]> git.karo-electronics.de Git - linux-beck.git/commitdiff
staging: dwc2: register common irq handler in dwc2_core_init
authorMatthijs Kooijman <matthijs@stdin.nl>
Thu, 11 Apr 2013 15:52:41 +0000 (17:52 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 11 Apr 2013 19:58:39 +0000 (12:58 -0700)
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>
drivers/staging/dwc2/core.c
drivers/staging/dwc2/core.h
drivers/staging/dwc2/hcd.c
drivers/staging/dwc2/pci.c

index 549cd3dd0bc2873f91f4cc99bedac018cccf2293..3177db2380bfca5943a38670efaaf8a3cf546e4a 100644 (file)
@@ -365,8 +365,9 @@ static void dwc2_gusbcfg_init(struct dwc2_hsotg *hsotg)
  *
  * @hsotg:      Programming view of the DWC_otg controller
  * @select_phy: If true then also set the Phy type
+ * @irq:        If >= 0, the irq to register
  */
-int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy)
+int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq)
 {
        u32 usbcfg, otgctl;
        int retval;
@@ -430,6 +431,16 @@ int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy)
        /* Clear the SRP success bit for FS-I2c */
        hsotg->srp_success = 0;
 
+       if (irq >= 0) {
+               dev_dbg(hsotg->dev, "registering common handler for irq%d\n",
+                       irq);
+               retval = devm_request_irq(hsotg->dev, irq,
+                                         dwc2_handle_common_intr, IRQF_SHARED,
+                                         dev_name(hsotg->dev), hsotg);
+               if (retval)
+                       return retval;
+       }
+
        /* Enable common interrupts */
        dwc2_enable_common_interrupts(hsotg);
 
index f8ee04b7cc00bc54c7766133d106e841d62bb2ad..320ed00b6ce7f4dfc6fd2db06bafd52a7814987c 100644 (file)
@@ -445,7 +445,7 @@ extern void dwc2_read_packet(struct dwc2_hsotg *hsotg, u8 *dest, u16 bytes);
 extern void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num);
 extern void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg);
 
-extern int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy);
+extern int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq);
 extern void dwc2_enable_global_interrupts(struct dwc2_hsotg *hcd);
 extern void dwc2_disable_global_interrupts(struct dwc2_hsotg *hcd);
 
index 1ea1222e9b6bcd5de5c8c0232ffdb3740cf6c99d..f68d8cc408faebf585190c1237994502b50f7a45 100644 (file)
@@ -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) {
index 80808d82aa74dd9cb7cdb11f46d9e025fe7f720f..8d9a9023c29a5a05fd93ad48fddb9e001677792b 100644 (file)
@@ -155,13 +155,6 @@ static int dwc2_driver_probe(struct pci_dev *dev,
        pci_set_drvdata(dev, hsotg);
        dev_dbg(&dev->dev, "hsotg=%p\n", hsotg);
 
-       dev_dbg(&dev->dev, "registering common handler for irq%d\n", dev->irq);
-       retval = devm_request_irq(&dev->dev, dev->irq, dwc2_handle_common_intr,
-                                 IRQF_SHARED, dev_name(&dev->dev),
-                                 hsotg);
-       if (retval)
-               dwc2_hcd_remove(hsotg);
-
        return retval;
 }