usb: dwc2: host: allocate qtd before atomic enqueue
authorMian Yousaf Kaukab <yousaf.kaukab@intel.com>
Mon, 29 Jun 2015 09:05:29 +0000 (11:05 +0200)
committerFelipe Balbi <balbi@ti.com>
Mon, 6 Jul 2015 17:34:08 +0000 (12:34 -0500)
To avoid sleep while atomic bugs, allocate qtd before calling
dwc2_hcd_urb_enqueue. No need to pass mem_flags to
dwc2_hcd_urb_enqueue any more as no memory allocations are done in it.

Acked-by: John Youn <johnyoun@synopsys.com>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Doug Anderson <dianders@chromium.org>
Signed-off-by: Mian Yousaf Kaukab <yousaf.kaukab@intel.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/dwc2/hcd.c

index 80bce711bc14b083b7e90956c8745e03630b8d8c..f845c41fe9e5e8c788c35d0fd7711b54debbe97e 100644 (file)
@@ -360,9 +360,8 @@ void dwc2_hcd_stop(struct dwc2_hsotg *hsotg)
 /* Caller must hold driver lock */
 static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
                                struct dwc2_hcd_urb *urb, struct dwc2_qh *qh,
-                               gfp_t mem_flags)
+                               struct dwc2_qtd *qtd)
 {
-       struct dwc2_qtd *qtd;
        u32 intr_mask;
        int retval;
        int dev_speed;
@@ -386,9 +385,8 @@ static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
                        return -ENODEV;
        }
 
-       qtd = kzalloc(sizeof(*qtd), mem_flags);
        if (!qtd)
-               return -ENOMEM;
+               return -EINVAL;
 
        dwc2_hcd_qtd_init(qtd, urb);
        retval = dwc2_hcd_qtd_add(hsotg, qtd, qh);
@@ -396,7 +394,6 @@ static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
                dev_err(hsotg->dev,
                        "DWC OTG HCD URB Enqueue failed adding QTD. Error status %d\n",
                        retval);
-               kfree(qtd);
                return retval;
        }
 
@@ -2446,6 +2443,7 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
        unsigned long flags;
        struct dwc2_qh *qh;
        bool qh_allocated = false;
+       struct dwc2_qtd *qtd;
 
        if (dbg_urb(urb)) {
                dev_vdbg(hsotg->dev, "DWC OTG HCD URB Enqueue\n");
@@ -2536,14 +2534,20 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
                qh_allocated = true;
        }
 
+       qtd = kzalloc(sizeof(*qtd), mem_flags);
+       if (!qtd) {
+               retval = -ENOMEM;
+               goto fail1;
+       }
+
        spin_lock_irqsave(&hsotg->lock, flags);
        retval = usb_hcd_link_urb_to_ep(hcd, urb);
        if (retval)
-               goto fail1;
+               goto fail2;
 
-       retval = dwc2_hcd_urb_enqueue(hsotg, dwc2_urb, qh, mem_flags);
+       retval = dwc2_hcd_urb_enqueue(hsotg, dwc2_urb, qh, qtd);
        if (retval)
-               goto fail2;
+               goto fail3;
 
        if (alloc_bandwidth) {
                dwc2_allocate_bus_bandwidth(hcd,
@@ -2555,12 +2559,14 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
 
        return 0;
 
-fail2:
+fail3:
        dwc2_urb->priv = NULL;
        usb_hcd_unlink_urb_from_ep(hcd, urb);
-fail1:
+fail2:
        spin_unlock_irqrestore(&hsotg->lock, flags);
        urb->hcpriv = NULL;
+       kfree(qtd);
+fail1:
        if (qh_allocated) {
                struct dwc2_qtd *qtd2, *qtd2_tmp;