summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorPeter Chen <peter.chen@freescale.com>2011-08-10 19:37:16 +0800
committerJason Liu <r64343@freescale.com>2012-01-09 20:21:58 +0800
commitabf9e53fe39967d40fdd8cf2b47523b5d5a7e3ab (patch)
tree9e97d68747533619380ef050259ef81ca619be9a /drivers/usb
parent59d3d7903895e7f3aa8c650b9af9c7cbdbf82ec7 (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-xdrivers/usb/gadget/arcotg_udc.c21
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;
}
}