summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Chen <peter.chen@freescale.com>2011-08-10 19:37:16 +0800
committerPeter Chen <peter.chen@freescale.com>2011-08-19 10:02:22 +0800
commitb97ac3cd36229c4e02eb16de2dac3bee5e3e5a56 (patch)
treeaac100154149aaf0f77cb50ef9669c4582825411
parent29c4a238b447957ebe2a40082f00ef36897f36a6 (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.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 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;
}
}