Message ID | 1393357243-2958-7-git-send-email-balbi@ti.com |
---|---|
State | Superseded |
Headers | show |
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? This fails in AM437x since both these are zero and leads to following crash [ 57.914762] Unable to handle kernel NULL pointer dereference at virtual address 00000000 [ 57.926272] pgd = ed43c000 [ 57.930222] [00000000] *pgd=ac05a831, *pte=00000000, *ppte=00000000 [ 57.939425] Internal error: Oops: 817 [#1] SMP ARM [ 57.945964] Modules linked in: dwc3(+) snd_soc_omap snd_pcm_dmaengine snd_soc_core snd_compress regmap_spi snd_pcm snd_timer snd soundcore dwc3_omap matrix_keypad [ 57.965884] CPU: 0 PID: 1126 Comm: insmod Tainted: G W 3.14.0-rc5-00151-gc02b641-dirty #2 [ 57.978198] task: ed1e2ac0 ti: ed456000 task.ti: ed456000 [ 57.985570] PC is at v7_dma_clean_range+0x1c/0x34 [ 57.992001] LR is at dma_cache_maint_page+0x90/0x120 [ 57.998765] pc : [<c001d710>] lr : [<c001963c>] psr: 000f0113 [ 57.998765] sp : ed457d18 ip : edff2000 fp : c07f0924 [ 58.014383] r10: c0888940 r9 : 00000000 r8 : c07f39c4 [ 58.021495] r7 : 00080000 r6 : 00000000 r5 : 000c0000 r4 : c001d75c [ 58.030374] r3 : 0000001f r2 : 00000020 r1 : 00000000 r0 : 00000000 [ 58.039258] Flags: nzcv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user [ 58.048971] Control: 10c53c7d Table: ad43c059 DAC: 00000015 [ 58.056793] Process insmod (pid: 1126, stack limit = 0xed456248) [ 58.064967] Stack: (0xed457d18 to 0xed458000) [ 58.070899] 7d00: 00000000 ed456000 [ 58.082031] 7d20: 00000000 00000000 ee7f2000 00000000 00000000 48a22004 25803004 ed5ffc10 [ 58.093164] 7d40: 000c0002 c00196f4 c001d75c c053205c bf0b1098 00000000 ee7f2000 ed474810 [ 58.104298] 7d60: c07f08c0 c0019810 00000000 00000000 c0000000 bf0ab0e0 00000000 00000000 [ 58.115425] 7d80: 00000000 ed5ffc10 bf0b2b70 00000000 00000000 bf0b2b70 ed456000 00000001 [ 58.126553] 7da0: 00000000 c0352de8 c0352dd0 c0de004c ed5ffc10 c0351a30 ed5ffc10 bf0b2b70 [ 58.137682] 7dc0: ed5ffc44 00000000 bf0b6000 c0351be0 00000000 bf0b2b70 c0351b4c c03501c4 [ 58.148810] 7de0: ed02f0a8 ed4fded0 bf0b2b70 ed2d7180 c0863090 c03511c4 bf0b10b8 bf0b2b70 [ 58.159937] 7e00: bf0b2bd8 bf0b2b70 bf0b2bd8 bf0b2bcc 00000001 c0352210 00000000 ed457f58 [ 58.171064] 7e20: bf0b2bd8 c0008908 ed1e2ac0 c0539790 00000001 ed07de40 c0d9fe2c 00000001 [ 58.182194] 7e40: ed456000 c008565c 60000013 c0846f60 bf0b2bcc 00000001 ed07de40 c0539790 [ 58.193325] 7e60: c0846f80 c0846f5c 00000000 c00627d4 00000000 ed5f9f80 ed000080 ed457f58 [ 58.204453] 7e80: bf0b2bd8 bf0b2bcc 00000001 ed07de40 c0d9fe2c 00000001 ed456000 c00ac1a4 [ 58.215582] 7ea0: bf0b2bd8 00007fff c00a9cd4 ed456000 c00a99a4 c0d9fe24 ed456000 bf0b2c14 [ 58.226713] 7ec0: bf0b2d44 c07f0940 ed457ef4 00000000 bf0b2bd8 ed456000 ffffffff c0733ccc [ 58.237842] 7ee0: 73646e65 c0539cf0 f08c0000 b6f5a000 0000071e 00000000 00000000 00000000 [ 58.248971] 7f00: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 58.260099] 7f20: 00000000 00000000 00000000 00000000 000000d2 000c479e b6e96000 b6f6d150 [ 58.271227] 7f40: 00000080 c000e6e4 ed456000 00000000 00000000 c00aca2c f07fc000 000c479e [ 58.282357] 7f60: f089166c f089147e f08bf834 00008d44 00009e54 00000000 00000000 00000000 [ 58.293484] 7f80: 00000030 00000031 00000017 0000001b 00000011 00000000 4e9c8ef8 00000000 [ 58.304612] 7fa0: 000210a0 c000e520 4e9c8ef8 00000000 b6e96000 000c479e b6f6d150 00000002 [ 58.315742] 7fc0: 4e9c8ef8 00000000 000210a0 00000080 00021088 000c479e b6f6d150 00000000 [ 58.326875] 7fe0: 4e978990 bec5bc08 b6f65aa8 4e9789a0 80000010 b6e96000 c8c0c094 4ac84040 [ 58.338044] [<c001d710>] (v7_dma_clean_range) from [<c001963c>] (dma_cache_maint_page+0x90/0x120) [ 58.350141] [<c001963c>] (dma_cache_maint_page) from [<c00196f4>] (__dma_page_cpu_to_dev+0x28/0xa0) [ 58.362471] [<c00196f4>] (__dma_page_cpu_to_dev) from [<c0019810>] (arm_dma_map_page+0x64/0x70) [ 58.374388] [<c0019810>] (arm_dma_map_page) from [<bf0ab0e0>] (dwc3_probe+0xa14/0xcc4 [dwc3]) [ 58.386063] [<bf0ab0e0>] (dwc3_probe [dwc3]) from [<c0352de8>] (platform_drv_probe+0x18/0x48) [ 58.397690] [<c0352de8>] (platform_drv_probe) from [<c0351a30>] (driver_probe_device+0x110/0x22c) [ 58.409774] [<c0351a30>] (driver_probe_device) from [<c0351be0>] (__driver_attach+0x94/0x98) [ 58.421280] [<c0351be0>] (__driver_attach) from [<c03501c4>] (bus_for_each_dev+0x54/0x88) [ 58.432430] [<c03501c4>] (bus_for_each_dev) from [<c03511c4>] (bus_add_driver+0xd8/0x1d8) [ 58.443570] [<c03511c4>] (bus_add_driver) from [<c0352210>] (driver_register+0x78/0xf4) [ 58.454474] [<c0352210>] (driver_register) from [<c0008908>] (do_one_initcall+0xe4/0x144) [ 58.465625] [<c0008908>] (do_one_initcall) from [<c00ac1a4>] (load_module+0x1788/0x1f68) [ 58.476645] [<c00ac1a4>] (load_module) from [<c00aca2c>] (SyS_init_module+0xa8/0xec) [ 58.487201] [<c00aca2c>] (SyS_init_module) from [<c000e520>] (ret_fast_syscall+0x0/0x48) [ 58.498220] Code: e3a02004 e1a02312 e2423001 e1c00003 (ee070f3a) [ 58.508114] ---[ end trace d26e7c6505b06264 ]--- > + 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; >
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; + + 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 +351,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; @@ -316,6 +391,10 @@ static int dwc3_core_init(struct dwc3 *dwc) case DWC3_GHWPARAMS1_EN_PWROPT_CLK: 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"); } @@ -333,14 +412,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 43fe290..deab3c5 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) @@ -600,6 +601,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 @@ -608,6 +610,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) @@ -650,10 +653,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 */ @@ -682,6 +687,7 @@ struct dwc3 { u32 dcfg; u32 gctl; + u32 nr_scratch; u32 num_event_buffers; u32 u1u2; u32 maximum_speed;
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(+)