UPSTREAM: usb: dwc2: host: use kmem cache to allocate descriptors
authorGregory Herrero <gregory.herrero@intel.com>
Fri, 20 Nov 2015 10:49:31 +0000 (11:49 +0100)
committerHuang, Tao <huangtao@rock-chips.com>
Tue, 3 Jan 2017 09:50:42 +0000 (17:50 +0800)
Kmem caches help to get correct boundary for descriptor buffers
which need to be 512 bytes aligned for dwc2 controller.
Two kmem caches are needed for generic descriptors and for
hs isochronous descriptors which doesn't have same size.

Change-Id: Ic5af8b3871a32d51942aad35e0968ddbd803a73e
Acked-by: John Youn <johnyoun@synopsys.com>
Signed-off-by: Gregory Herrero <gregory.herrero@intel.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Signed-off-by: Huang, Tao <huangtao@rock-chips.com>
(cherry picked from commit 3b5fcc9ac2f4453a5609cc89ac7618b1b27ccb01)

drivers/usb/dwc2/core.h
drivers/usb/dwc2/hcd.c
drivers/usb/dwc2/hcd_ddma.c

index 3e641b9358ff854cd6314f7537ac710889b76762..ebd973ebc0c28df6d1f676af1634fad01fc412cd 100644 (file)
@@ -713,6 +713,8 @@ struct dwc2_hregs_backup {
  * @frame_list:         Frame list
  * @frame_list_dma:     Frame list DMA address
  * @frame_list_sz:      Frame list size
+ * @desc_gen_cache:     Kmem cache for generic descriptors
+ * @desc_hsisoc_cache:  Kmem cache for hs isochronous descriptors
  *
  * These are for peripheral mode:
  *
@@ -834,6 +836,8 @@ struct dwc2_hsotg {
        u32 *frame_list;
        dma_addr_t frame_list_dma;
        u32 frame_list_sz;
+       struct kmem_cache *desc_gen_cache;
+       struct kmem_cache *desc_hsisoc_cache;
 
 #ifdef DEBUG
        u32 frrem_samples;
index f638f34eb27227dce93ce8ba4cbda71c6caca204..f0b0d9161724853f41407c4b37fbab8411479cd3 100644 (file)
@@ -3146,6 +3146,47 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq)
        if (!hsotg->status_buf)
                goto error3;
 
+       /*
+        * Create kmem caches to handle descriptor buffers in descriptor
+        * DMA mode.
+        * Alignment must be set to 512 bytes.
+        */
+       if (hsotg->core_params->dma_desc_enable ||
+           hsotg->core_params->dma_desc_fs_enable) {
+               hsotg->desc_gen_cache = kmem_cache_create("dwc2-gen-desc",
+                               sizeof(struct dwc2_hcd_dma_desc) *
+                               MAX_DMA_DESC_NUM_GENERIC, 512, SLAB_CACHE_DMA,
+                               NULL);
+               if (!hsotg->desc_gen_cache) {
+                       dev_err(hsotg->dev,
+                               "unable to create dwc2 generic desc cache\n");
+
+                       /*
+                        * Disable descriptor dma mode since it will not be
+                        * usable.
+                        */
+                       hsotg->core_params->dma_desc_enable = 0;
+                       hsotg->core_params->dma_desc_fs_enable = 0;
+               }
+
+               hsotg->desc_hsisoc_cache = kmem_cache_create("dwc2-hsisoc-desc",
+                               sizeof(struct dwc2_hcd_dma_desc) *
+                               MAX_DMA_DESC_NUM_HS_ISOC, 512, 0, NULL);
+               if (!hsotg->desc_hsisoc_cache) {
+                       dev_err(hsotg->dev,
+                               "unable to create dwc2 hs isoc desc cache\n");
+
+                       kmem_cache_destroy(hsotg->desc_gen_cache);
+
+                       /*
+                        * Disable descriptor dma mode since it will not be
+                        * usable.
+                        */
+                       hsotg->core_params->dma_desc_enable = 0;
+                       hsotg->core_params->dma_desc_fs_enable = 0;
+               }
+       }
+
        hsotg->otg_port = 1;
        hsotg->frame_list = NULL;
        hsotg->frame_list_dma = 0;
@@ -3169,7 +3210,7 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq)
         */
        retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
        if (retval < 0)
-               goto error3;
+               goto error4;
 
        device_wakeup_enable(hcd->self.controller);
 
@@ -3179,6 +3220,9 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq)
 
        return 0;
 
+error4:
+       kmem_cache_destroy(hsotg->desc_gen_cache);
+       kmem_cache_destroy(hsotg->desc_hsisoc_cache);
 error3:
        dwc2_hcd_release(hsotg);
 error2:
@@ -3219,6 +3263,10 @@ void dwc2_hcd_remove(struct dwc2_hsotg *hsotg)
 
        usb_remove_hcd(hcd);
        hsotg->priv = NULL;
+
+       kmem_cache_destroy(hsotg->desc_gen_cache);
+       kmem_cache_destroy(hsotg->desc_hsisoc_cache);
+
        dwc2_hcd_release(hsotg);
        usb_put_hcd(hcd);
 
index 85d7816d29f1d71c5cfdceb18f3401e4690a1af5..36606fc33c0d31f0ed52d85bc626f3fe29e36099 100644 (file)
@@ -87,10 +87,18 @@ static u16 dwc2_frame_incr_val(struct dwc2_qh *qh)
 static int dwc2_desc_list_alloc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
                                gfp_t flags)
 {
+       struct kmem_cache *desc_cache;
+
+       if (qh->ep_type == USB_ENDPOINT_XFER_ISOC
+           && qh->dev_speed == USB_SPEED_HIGH)
+               desc_cache = hsotg->desc_hsisoc_cache;
+       else
+               desc_cache = hsotg->desc_gen_cache;
+
        qh->desc_list_sz = sizeof(struct dwc2_hcd_dma_desc) *
                                                dwc2_max_desc_num(qh);
 
-       qh->desc_list = kzalloc(qh->desc_list_sz, flags | GFP_DMA);
+       qh->desc_list = kmem_cache_zalloc(desc_cache, flags | GFP_DMA);
        if (!qh->desc_list)
                return -ENOMEM;
 
@@ -113,10 +121,18 @@ static int dwc2_desc_list_alloc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
 
 static void dwc2_desc_list_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
 {
+       struct kmem_cache *desc_cache;
+
+       if (qh->ep_type == USB_ENDPOINT_XFER_ISOC
+           && qh->dev_speed == USB_SPEED_HIGH)
+               desc_cache = hsotg->desc_hsisoc_cache;
+       else
+               desc_cache = hsotg->desc_gen_cache;
+
        if (qh->desc_list) {
                dma_unmap_single(hsotg->dev, qh->desc_list_dma,
                                 qh->desc_list_sz, DMA_FROM_DEVICE);
-               kfree(qh->desc_list);
+               kmem_cache_free(desc_cache, qh->desc_list);
                qh->desc_list = NULL;
        }