ChangeSet 1.1500.8.11, 2004/02/02 13:43:56-08:00, shemminger@osdl.org [PATCH] USB: fix usb hc and shared irq handling Here is a revised version of the irqreturn_t propagation patch. The only difference is now ohci-hcd returns IRQ_HANDLED in the remove case. drivers/usb/core/hcd.c | 4 +++- drivers/usb/core/hcd.h | 2 +- drivers/usb/host/ehci-hcd.c | 9 ++++++++- drivers/usb/host/ohci-hcd.c | 8 +++++--- drivers/usb/host/uhci-hcd.c | 5 +++-- 5 files changed, 20 insertions(+), 8 deletions(-) diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c --- a/drivers/usb/core/hcd.c Mon Feb 9 14:41:01 2004 +++ b/drivers/usb/core/hcd.c Mon Feb 9 14:41:01 2004 @@ -1516,7 +1516,9 @@ return IRQ_NONE; hcd->saw_irq = 1; - hcd->driver->irq (hcd, r); + if (hcd->driver->irq (hcd, r) == IRQ_NONE) + return IRQ_NONE; + if (hcd->state != start && hcd->state == USB_STATE_HALT) usb_hc_died (hcd); return IRQ_HANDLED; diff -Nru a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h --- a/drivers/usb/core/hcd.h Mon Feb 9 14:41:01 2004 +++ b/drivers/usb/core/hcd.h Mon Feb 9 14:41:01 2004 @@ -163,7 +163,7 @@ const char *description; /* "ehci-hcd" etc */ /* irq handler */ - void (*irq) (struct usb_hcd *hcd, struct pt_regs *regs); + irqreturn_t (*irq) (struct usb_hcd *hcd, struct pt_regs *regs); int flags; #define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */ diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c --- a/drivers/usb/host/ehci-hcd.c Mon Feb 9 14:41:01 2004 +++ b/drivers/usb/host/ehci-hcd.c Mon Feb 9 14:41:01 2004 @@ -680,7 +680,7 @@ /*-------------------------------------------------------------------------*/ -static void ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs) +static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); u32 status; @@ -690,6 +690,12 @@ status = readl (&ehci->regs->status); + /* shared irq */ + if (status == 0) { + spin_unlock (&ehci->lock); + return IRQ_NONE; + } + /* e.g. cardbus physical eject */ if (status == ~(u32) 0) { ehci_dbg (ehci, "device removed\n"); @@ -743,6 +749,7 @@ ehci_work (ehci, regs); done: spin_unlock (&ehci->lock); + return IRQ_HANDLED; } /*-------------------------------------------------------------------------*/ diff -Nru a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c --- a/drivers/usb/host/ohci-hcd.c Mon Feb 9 14:41:01 2004 +++ b/drivers/usb/host/ohci-hcd.c Mon Feb 9 14:41:01 2004 @@ -545,7 +545,7 @@ /* an interrupt happens */ -static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) +static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_regs *regs = ohci->regs; @@ -560,11 +560,11 @@ } else if ((ints = readl (®s->intrstatus)) == ~(u32)0) { disable (ohci); ohci_dbg (ohci, "device removed!\n"); - return; + return IRQ_HANDLED; /* interrupt for some other device? */ } else if ((ints &= readl (®s->intrenable)) == 0) { - return; + return IRQ_NONE; } if (ints & OHCI_INTR_UE) { @@ -604,6 +604,8 @@ // flush those pci writes (void) readl (&ohci->regs->control); } + + return IRQ_HANDLED; } /*-------------------------------------------------------------------------*/ diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c --- a/drivers/usb/host/uhci-hcd.c Mon Feb 9 14:41:01 2004 +++ b/drivers/usb/host/uhci-hcd.c Mon Feb 9 14:41:01 2004 @@ -1909,7 +1909,7 @@ spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags); } -static void uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) +static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); unsigned int io_addr = uhci->io_addr; @@ -1922,7 +1922,7 @@ */ status = inw(io_addr + USBSTS); if (!status) /* shared interrupt, not mine */ - return; + return IRQ_NONE; outw(status, io_addr + USBSTS); /* Clear it */ if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) { @@ -1963,6 +1963,7 @@ spin_unlock(&uhci->urb_list_lock); uhci_finish_completion(hcd, regs); + return IRQ_HANDLED; } static void reset_hc(struct uhci_hcd *uhci)