usb: dwc2: host: allocate qtd before atomic enqueue
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>
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 80bce71..f845c41 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -360,9 +360,8 @@
/* 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 @@
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 @@
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 @@
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,15 +2534,21 @@
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;
-
- retval = dwc2_hcd_urb_enqueue(hsotg, dwc2_urb, qh, mem_flags);
- if (retval)
goto fail2;
+ retval = dwc2_hcd_urb_enqueue(hsotg, dwc2_urb, qh, qtd);
+ if (retval)
+ goto fail3;
+
if (alloc_bandwidth) {
dwc2_allocate_bus_bandwidth(hcd,
dwc2_hcd_get_ep_bandwidth(hsotg, ep),
@@ -2555,12 +2559,14 @@
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;