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)
committerFelipe Balbi <balbi@ti.com>
Tue, 15 Dec 2015 15:12:41 +0000 (09:12 -0600)
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.

Acked-by: John Youn <johnyoun@synopsys.com>
Signed-off-by: Gregory Herrero <gregory.herrero@intel.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/dwc2/core.h
drivers/usb/dwc2/hcd.c
drivers/usb/dwc2/hcd_ddma.c

index e7cc54268f2f537078c19ab68098f3f34543b7b9..baee2bc1e8a881bcab0be9a449cb75b778503ae1 100644 (file)
@@ -686,6 +686,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:
  *
@@ -806,6 +808,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 7fd4f41e12a793cd41862c2f95aca7ddf36927bc..b2afe913d559324f1679e092ad4ff6621711f6b3 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;
        }