aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2007-12-06 16:28:25 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2007-12-17 13:47:15 -0500
commit565227c08226e458da191518251dbff6831624c2 (patch)
tree95571e1e6aa150aa4f7792118532f5ad89edd03e
parent08cbc706acd2dd601b0663e28fa97ffb0564e105 (diff)
usb: Remove broken optimisation in OHCI IRQ handler
The OHCI IRQ handler has an optimisation that avoids reading some chip registers when the controller reports that the interrupt was triggered *only* because completed requests were written into the controller's "done list" and handed to the host. This mechanism can't be used on some controllers. Among others, it fails for the SA1111 and the AMCC 440EP PowerPC processor. This patch removes the optimisation and makes the code clearer. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/host/ohci-hcd.c23
1 files changed, 13 insertions, 10 deletions
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 704f33fdd2f1..ecfe800fd720 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -732,24 +732,27 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
732 struct ohci_regs __iomem *regs = ohci->regs; 732 struct ohci_regs __iomem *regs = ohci->regs;
733 int ints; 733 int ints;
734 734
735 /* we can eliminate a (slow) ohci_readl() 735 /* Read interrupt status (and flush pending writes). We ignore the
736 * if _only_ WDH caused this irq 736 * optimization of checking the LSB of hcca->done_head; it doesn't
737 * work on all systems (edge triggering for OHCI can be a factor).
737 */ 738 */
738 if ((ohci->hcca->done_head != 0) 739 ints = ohci_readl(ohci, &regs->intrstatus);
739 && ! (hc32_to_cpup (ohci, &ohci->hcca->done_head)
740 & 0x01)) {
741 ints = OHCI_INTR_WDH;
742 740
743 /* cardbus/... hardware gone before remove() */ 741 /* Check for an all 1's result which is a typical consequence
744 } else if ((ints = ohci_readl (ohci, &regs->intrstatus)) == ~(u32)0) { 742 * of dead, unclocked, or unplugged (CardBus...) devices
743 */
744 if (ints == ~(u32)0) {
745 disable (ohci); 745 disable (ohci);
746 ohci_dbg (ohci, "device removed!\n"); 746 ohci_dbg (ohci, "device removed!\n");
747 return IRQ_HANDLED; 747 return IRQ_HANDLED;
748 }
749
750 /* We only care about interrupts that are enabled */
751 ints &= ohci_readl(ohci, &regs->intrenable);
748 752
749 /* interrupt for some other device? */ 753 /* interrupt for some other device? */
750 } else if ((ints &= ohci_readl (ohci, &regs->intrenable)) == 0) { 754 if (ints == 0)
751 return IRQ_NOTMINE; 755 return IRQ_NOTMINE;
752 }
753 756
754 if (ints & OHCI_INTR_UE) { 757 if (ints & OHCI_INTR_UE) {
755 // e.g. due to PCI Master/Target Abort 758 // e.g. due to PCI Master/Target Abort