diff options
author | 2013-04-11 17:52:41 +0200 | |
---|---|---|
committer | 2013-04-11 12:58:39 -0700 | |
commit | 6706c721b22aadffbffec7550b81efedddd05cfb (patch) | |
tree | e763faf21c606750ae874fcd45258744f6fd1116 /drivers/staging/dwc2/hcd.c | |
parent | staging: dwc2: don't pass IRQ_LEVEL to devm_request_irq (diff) | |
download | linux-dev-6706c721b22aadffbffec7550b81efedddd05cfb.tar.xz linux-dev-6706c721b22aadffbffec7550b81efedddd05cfb.zip |
staging: dwc2: register common irq handler in dwc2_core_init
Before, this was initialized in pci.c, after the dwc2_hcd_init was
called and the interrupts were enabled. This opened up a small time
window where common interrupts could be triggered, but there was no
handler for them, causing them to keep triggering infinitely and locking
up the machine.
On my RT3052 board this bug could be easily reproduced by hardcoding
the console log level to 8, so that a bunch of debug output from the dwc2
driver was generated inside this time window. This caused the interrupt
lockup to occur almost every time.
By requesting the irq inside dwc2_core_init and by disabling interrupts
before calling dwc2_core_init instead of after, we can be sure the
handler is registered before the interrupts are enabled, which should
close this window.
Reported-by: Stephen Warren <swarren@wwwdotorg.org>
Signed-off-by: Matthijs Kooijman <matthijs@stdin.nl>
Acked-by: Paul Zimmerman <paulz@synopsys.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/dwc2/hcd.c')
-rw-r--r-- | drivers/staging/dwc2/hcd.c | 14 |
1 files changed, 7 insertions, 7 deletions
diff --git a/drivers/staging/dwc2/hcd.c b/drivers/staging/dwc2/hcd.c index 1ea1222e9b6b..f68d8cc408fa 100644 --- a/drivers/staging/dwc2/hcd.c +++ b/drivers/staging/dwc2/hcd.c @@ -1313,7 +1313,7 @@ static void dwc2_conn_id_status_change(struct work_struct *work) dev_err(hsotg->dev, "Connection id status change timed out"); hsotg->op_state = OTG_STATE_B_PERIPHERAL; - dwc2_core_init(hsotg, false); + dwc2_core_init(hsotg, false, -1); dwc2_enable_global_interrupts(hsotg); } else { /* A-Device connector (Host Mode) */ @@ -1332,7 +1332,7 @@ static void dwc2_conn_id_status_change(struct work_struct *work) hsotg->op_state = OTG_STATE_A_HOST; /* Initialize the Core for Host mode */ - dwc2_core_init(hsotg, false); + dwc2_core_init(hsotg, false, -1); dwc2_enable_global_interrupts(hsotg); dwc2_hcd_start(hsotg); } @@ -2818,17 +2818,17 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq, ((struct wrapper_priv_data *) &hcd->hcd_priv)->hsotg = hsotg; hsotg->priv = hcd; - /* Initialize the DWC_otg core, and select the Phy type */ - retval = dwc2_core_init(hsotg, true); - if (retval) - goto error2; - /* * Disable the global interrupt until all the interrupt handlers are * installed */ dwc2_disable_global_interrupts(hsotg); + /* Initialize the DWC_otg core, and select the Phy type */ + retval = dwc2_core_init(hsotg, true, irq); + if (retval) + goto error2; + /* Create new workqueue and init work */ hsotg->wq_otg = create_singlethread_workqueue("dwc_otg"); if (!hsotg->wq_otg) { |