USB: chipidea: re-order irq handling to avoid unhandled irqs
authorRichard Zhao <richard.zhao@freescale.com>
Wed, 12 Sep 2012 11:58:11 +0000 (14:58 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 12 Sep 2012 18:20:38 +0000 (11:20 -0700)
- let role driver handle irq before ID change check; this gives the
  role driver a chance to handle disconnect;
- disable irq during switch role; no role driver to handle irq in
  the period.

Tested-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
Tested-by: Marc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: Richard Zhao <richard.zhao@freescale.com>
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/chipidea/core.c

index 19ef324..f69d029 100644 (file)
@@ -279,6 +279,7 @@ static void ci_role_work(struct work_struct *work)
 
                ci_role_stop(ci);
                ci_role_start(ci, role);
+               enable_irq(ci->irq);
        }
 }
 
@@ -318,18 +319,22 @@ static irqreturn_t ci_irq(int irq, void *data)
 {
        struct ci13xxx *ci = data;
        irqreturn_t ret = IRQ_NONE;
+       u32 otgsc = 0;
 
-       if (ci->is_otg) {
-               u32 sts = hw_read(ci, OP_OTGSC, ~0);
+       if (ci->is_otg)
+               otgsc = hw_read(ci, OP_OTGSC, ~0);
+
+       if (ci->role != CI_ROLE_END)
+               ret = ci_role(ci)->irq(ci);
 
-               if (sts & OTGSC_IDIS) {
-                       hw_write(ci, OP_OTGSC, OTGSC_IDIS, OTGSC_IDIS);
-                       queue_work(ci->wq, &ci->work);
-                       ret = IRQ_HANDLED;
-               }
+       if (ci->is_otg && (otgsc & OTGSC_IDIS)) {
+               hw_write(ci, OP_OTGSC, OTGSC_IDIS, OTGSC_IDIS);
+               disable_irq_nosync(ci->irq);
+               queue_work(ci->wq, &ci->work);
+               ret = IRQ_HANDLED;
        }
 
-       return ci->role == CI_ROLE_END ? ret : ci_role(ci)->irq(ci);
+       return ret;
 }
 
 static DEFINE_IDA(ci_ida);