[06/11] usb: dwc3: core: allocate scratch buffers

Message ID 20140305154932.GH16430@saruman.home
State Accepted
Commit 0ffcaf3798bfd83aed0a650cddb9d1ee825ff2bb
Headers show

Commit Message

Felipe Balbi March 5, 2014, 3:49 p.m.
On Wed, Mar 05, 2014 at 04:47:31PM +0530, George Cherian wrote:
> On 2/26/2014 1:10 AM, Felipe Balbi wrote:
> >We must read HWPARAMS4 register to figure out
> >how many scratch buffers we should allocate.
> >
> >Later patch will use "Set Scratchpad Buffer
> >Array" command to pass the pointer to the
> >IP so it can be used during hibernation.
> >
> >Signed-off-by: Felipe Balbi <balbi@ti.com>
> >---
> >  drivers/usb/dwc3/core.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++
> >  drivers/usb/dwc3/core.h |  6 ++++
> >  2 files changed, 101 insertions(+)
> >
> >diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
> >index a49217a..2864aad 100644
> >--- a/drivers/usb/dwc3/core.c
> >+++ b/drivers/usb/dwc3/core.c
> >@@ -242,6 +242,80 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
> >  	}
> >  }
> >+static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc)
> >+{
> >+	if (!dwc->has_hibernation)
> >+		return 0;
> >+
> >+	if (!dwc->nr_scratch)
> >+		return 0;
> >+
> >+	dwc->scratchbuf = kmalloc_array(dwc->nr_scratch,
> >+			DWC3_SCRATCHBUF_SIZE, GFP_KERNEL);
> >+	if (!dwc->scratchbuf)
> >+		return -ENOMEM;
> >+
> >+	return 0;
> >+}
> >+
> >+static int dwc3_setup_scratch_buffers(struct dwc3 *dwc)
> >+{
> >+	dma_addr_t scratch_addr;
> >+	u32 param;
> >+	int ret;
> >+
> 
> Shouldn't there be check for  dwc->scratchbuf and dwc->nr_scratch
> before calling dma_map_single?

fixed, thanks:

commit ae53c955b61a6270b65f384665e5e856109a9c9f
Author: Felipe Balbi <balbi@ti.com>
Date:   Thu Dec 19 13:04:28 2013 -0600

    usb: dwc3: core: allocate scratch buffers
    
    We must read HWPARAMS4 register to figure out
    how many scratch buffers we should allocate.
    
    Later patch will use "Set Scratchpad Buffer
    Array" command to pass the pointer to the
    IP so it can be used during hibernation.
    
    Signed-off-by: Felipe Balbi <balbi@ti.com>

Patch

diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 785feee..e3f8fd5 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -242,6 +242,90 @@  static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
 	}
 }
 
+static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc)
+{
+	if (!dwc->has_hibernation)
+		return 0;
+
+	if (!dwc->nr_scratch)
+		return 0;
+
+	dwc->scratchbuf = kmalloc_array(dwc->nr_scratch,
+			DWC3_SCRATCHBUF_SIZE, GFP_KERNEL);
+	if (!dwc->scratchbuf)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int dwc3_setup_scratch_buffers(struct dwc3 *dwc)
+{
+	dma_addr_t scratch_addr;
+	u32 param;
+	int ret;
+
+	if (!dwc->has_hibernation)
+		return 0;
+
+	if (!dwc->nr_scratch)
+		return 0;
+
+	 /* should never fall here */
+	if (!WARN_ON(dwc->scratchbuf))
+		return;
+
+	scratch_addr = dma_map_single(dwc->dev, dwc->scratchbuf,
+			dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE,
+			DMA_BIDIRECTIONAL);
+	if (dma_mapping_error(dwc->dev, scratch_addr)) {
+		dev_err(dwc->dev, "failed to map scratch buffer\n");
+		ret = -EFAULT;
+		goto err0;
+	}
+
+	dwc->scratch_addr = scratch_addr;
+
+	param = lower_32_bits(scratch_addr);
+
+	ret = dwc3_send_gadget_generic_command(dwc,
+			DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO, param);
+	if (ret < 0)
+		goto err1;
+
+	param = upper_32_bits(scratch_addr);
+
+	ret = dwc3_send_gadget_generic_command(dwc,
+			DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI, param);
+	if (ret < 0)
+		goto err1;
+
+	return 0;
+
+err1:
+	dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch *
+			DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
+
+err0:
+	return ret;
+}
+
+static void dwc3_free_scratch_buffers(struct dwc3 *dwc)
+{
+	if (!dwc->has_hibernation)
+		return;
+
+	if (!dwc->nr_scratch)
+		return;
+
+	 /* should never fall here */
+	if (!WARN_ON(dwc->scratchbuf))
+		return;
+
+	dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch *
+			DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
+	kfree(dwc->scratchbuf);
+}
+
 static void dwc3_core_num_eps(struct dwc3 *dwc)
 {
 	struct dwc3_hwparams	*parms = &dwc->hwparams;
@@ -277,6 +361,7 @@  static void dwc3_cache_hwparams(struct dwc3 *dwc)
 static int dwc3_core_init(struct dwc3 *dwc)
 {
 	unsigned long		timeout;
+	u32			hwparams4 = dwc->hwparams.hwparams4;
 	u32			reg;
 	int			ret;
 
@@ -334,6 +419,10 @@  static int dwc3_core_init(struct dwc3 *dwc)
 		else
 			reg &= ~DWC3_GCTL_DSBLCLKGTNG;
 		break;
+	case DWC3_GHWPARAMS1_EN_PWROPT_HIB:
+		/* enable hibernation here */
+		dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4);
+		break;
 	default:
 		dev_dbg(dwc->dev, "No power optimization available\n");
 	}
@@ -351,14 +440,30 @@  static int dwc3_core_init(struct dwc3 *dwc)
 
 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
 
+	ret = dwc3_alloc_scratch_buffers(dwc);
+	if (ret)
+		goto err1;
+
+	ret = dwc3_setup_scratch_buffers(dwc);
+	if (ret)
+		goto err2;
+
 	return 0;
 
+err2:
+	dwc3_free_scratch_buffers(dwc);
+
+err1:
+	usb_phy_shutdown(dwc->usb2_phy);
+	usb_phy_shutdown(dwc->usb3_phy);
+
 err0:
 	return ret;
 }
 
 static void dwc3_core_exit(struct dwc3 *dwc)
 {
+	dwc3_free_scratch_buffers(dwc);
 	usb_phy_shutdown(dwc->usb2_phy);
 	usb_phy_shutdown(dwc->usb3_phy);
 }
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 4c14796..bbb5b78e 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -36,6 +36,7 @@ 
 #define DWC3_ENDPOINTS_NUM	32
 #define DWC3_XHCI_RESOURCES_NUM	2
 
+#define DWC3_SCRATCHBUF_SIZE	4096	/* each buffer is assumed to be 4KiB */
 #define DWC3_EVENT_SIZE		4	/* bytes */
 #define DWC3_EVENT_MAX_NUM	64	/* 2 events/endpoint */
 #define DWC3_EVENT_BUFFERS_SIZE	(DWC3_EVENT_SIZE * DWC3_EVENT_MAX_NUM)
@@ -601,6 +602,7 @@  struct dwc3_scratchpad_array {
  * @ep0_trb: dma address of ep0_trb
  * @ep0_usb_req: dummy req used while handling STD USB requests
  * @ep0_bounce_addr: dma address of ep0_bounce
+ * @scratch_addr: dma address of scratchbuf
  * @lock: for synchronizing
  * @dev: pointer to our struct device
  * @xhci: pointer to our xHCI child
@@ -609,6 +611,7 @@  struct dwc3_scratchpad_array {
  * @gadget_driver: pointer to the gadget driver
  * @regs: base address for our registers
  * @regs_size: address space size
+ * @nr_scratch: number of scratch buffers
  * @num_event_buffers: calculated number of event buffers
  * @u1u2: only used on revisions <1.83a for workaround
  * @maximum_speed: maximum speed requested (mainly for testing purposes)
@@ -651,10 +654,12 @@  struct dwc3 {
 	struct usb_ctrlrequest	*ctrl_req;
 	struct dwc3_trb		*ep0_trb;
 	void			*ep0_bounce;
+	void			*scratchbuf;
 	u8			*setup_buf;
 	dma_addr_t		ctrl_req_addr;
 	dma_addr_t		ep0_trb_addr;
 	dma_addr_t		ep0_bounce_addr;
+	dma_addr_t		scratch_addr;
 	struct dwc3_request	ep0_usb_req;
 
 	/* device lock */
@@ -683,6 +688,7 @@  struct dwc3 {
 	u32			dcfg;
 	u32			gctl;
 
+	u32			nr_scratch;
 	u32			num_event_buffers;
 	u32			u1u2;
 	u32			maximum_speed;