diff options
author | Peter Chen <peter.chen@freescale.com> | 2011-08-10 19:37:16 +0800 |
---|---|---|
committer | Peter Chen <peter.chen@freescale.com> | 2011-08-19 10:02:22 +0800 |
commit | b97ac3cd36229c4e02eb16de2dac3bee5e3e5a56 (patch) | |
tree | aac100154149aaf0f77cb50ef9669c4582825411 | |
parent | 29c4a238b447957ebe2a40082f00ef36897f36a6 (diff) |
ENGR00154703 usb-gadget: fix spin_lock recursion problem at SMP platform
- The spin_lock is at interrupt handler, so all code routines
using at interrupt handler are forbidden to hold spin_lock again
- Move the code which needs to be protected by spin_lock to workqueue,
and it will be called when workqueue is scheduled.
Signed-off-by: Peter Chen <peter.chen@freescale.com>
-rw-r--r-- | drivers/usb/gadget/arcotg_udc.c | 21 |
1 files changed, 12 insertions, 9 deletions
diff --git a/drivers/usb/gadget/arcotg_udc.c b/drivers/usb/gadget/arcotg_udc.c index fb5e8a83a8bd..9711b7f7c643 100644 --- a/drivers/usb/gadget/arcotg_udc.c +++ b/drivers/usb/gadget/arcotg_udc.c @@ -1101,6 +1101,7 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) /* irq handler advances the queue */ if (req != NULL) list_add_tail(&req->queue, &ep->queue); + spin_unlock_irqrestore(&udc->lock, flags); return 0; @@ -2008,7 +2009,7 @@ static void suspend_irq(struct fsl_udc *udc) { u32 otgsc = 0; - pr_debug("%s\n", __func__); + pr_debug("%s begins\n", __func__); udc->resume_state = udc->usb_state; udc->usb_state = USB_STATE_SUSPENDED; @@ -2026,6 +2027,8 @@ static void suspend_irq(struct fsl_udc *udc) /* report suspend to the driver, serial.c does not support this */ if (udc->driver->suspend) udc->driver->suspend(&udc->gadget); + + pr_debug("%s ends\n", __func__); } static void bus_resume(struct fsl_udc *udc) @@ -2095,13 +2098,21 @@ static void fsl_gadget_event(struct work_struct *work) struct fsl_udc *udc = udc_controller; unsigned long flags; + if (udc->driver) + udc->driver->disconnect(&udc->gadget); spin_lock_irqsave(&udc->lock, flags); /* update port status */ fsl_udc_speed_update(udc); spin_unlock_irqrestore(&udc->lock, flags); + udc->stopped = 1; + /* enable wake up */ + dr_wake_up_enable(udc, true); + /* close USB PHY clock */ + dr_phy_low_power_mode(udc, true); /* close dr controller clock */ dr_clk_gate(false); + printk(KERN_DEBUG "%s: udc enter low power mode\n", __func__); } static void fsl_gadget_delay_event(struct work_struct *work) @@ -2148,16 +2159,8 @@ bool try_wake_up_udc(struct fsl_udc *udc) fsl_writel(tmp | USB_CMD_RUN_STOP, &dr_regs->usbcmd); printk(KERN_DEBUG "%s: udc out low power mode\n", __func__); } else { - if (udc->driver) - udc->driver->disconnect(&udc->gadget); fsl_writel(tmp & ~USB_CMD_RUN_STOP, &dr_regs->usbcmd); - udc->stopped = 1; - /* enable wake up */ - dr_wake_up_enable(udc, true); - /* close USB PHY clock */ - dr_phy_low_power_mode(udc, true); schedule_work(&udc->gadget_work); - printk(KERN_DEBUG "%s: udc enter low power mode\n", __func__); return false; } } |