diff options
author | Peter Chen <peter.chen@freescale.com> | 2011-08-10 19:37:16 +0800 |
---|---|---|
committer | Jason Liu <r64343@freescale.com> | 2012-01-09 20:21:58 +0800 |
commit | abf9e53fe39967d40fdd8cf2b47523b5d5a7e3ab (patch) | |
tree | 9e97d68747533619380ef050259ef81ca619be9a /drivers/usb | |
parent | 59d3d7903895e7f3aa8c650b9af9c7cbdbf82ec7 (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>
Diffstat (limited to 'drivers/usb')
-rwxr-xr-x | 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 23d02aac2b91..95dd31ec7936 100755 --- a/drivers/usb/gadget/arcotg_udc.c +++ b/drivers/usb/gadget/arcotg_udc.c @@ -1103,6 +1103,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; @@ -2010,7 +2011,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; @@ -2028,6 +2029,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) @@ -2097,13 +2100,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) @@ -2151,16 +2162,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; } } |