Commit d6d8b110 authored by Stephen Hemminger's avatar Stephen Hemminger

[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.
parent 62dced02
...@@ -1516,7 +1516,9 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r) ...@@ -1516,7 +1516,9 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r)
return IRQ_NONE; return IRQ_NONE;
hcd->saw_irq = 1; 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) if (hcd->state != start && hcd->state == USB_STATE_HALT)
usb_hc_died (hcd); usb_hc_died (hcd);
return IRQ_HANDLED; return IRQ_HANDLED;
......
...@@ -163,7 +163,7 @@ struct hc_driver { ...@@ -163,7 +163,7 @@ struct hc_driver {
const char *description; /* "ehci-hcd" etc */ const char *description; /* "ehci-hcd" etc */
/* irq handler */ /* 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; int flags;
#define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */ #define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */
......
...@@ -680,7 +680,7 @@ static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs) ...@@ -680,7 +680,7 @@ static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
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); struct ehci_hcd *ehci = hcd_to_ehci (hcd);
u32 status; u32 status;
...@@ -690,6 +690,12 @@ static void ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs) ...@@ -690,6 +690,12 @@ static void ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
status = readl (&ehci->regs->status); status = readl (&ehci->regs->status);
/* shared irq */
if (status == 0) {
spin_unlock (&ehci->lock);
return IRQ_NONE;
}
/* e.g. cardbus physical eject */ /* e.g. cardbus physical eject */
if (status == ~(u32) 0) { if (status == ~(u32) 0) {
ehci_dbg (ehci, "device removed\n"); ehci_dbg (ehci, "device removed\n");
...@@ -743,6 +749,7 @@ static void ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs) ...@@ -743,6 +749,7 @@ static void ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
ehci_work (ehci, regs); ehci_work (ehci, regs);
done: done:
spin_unlock (&ehci->lock); spin_unlock (&ehci->lock);
return IRQ_HANDLED;
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
......
...@@ -545,7 +545,7 @@ static int hc_start (struct ohci_hcd *ohci) ...@@ -545,7 +545,7 @@ static int hc_start (struct ohci_hcd *ohci)
/* an interrupt happens */ /* 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_hcd *ohci = hcd_to_ohci (hcd);
struct ohci_regs *regs = ohci->regs; struct ohci_regs *regs = ohci->regs;
...@@ -560,11 +560,11 @@ static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) ...@@ -560,11 +560,11 @@ static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
} else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) { } else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
disable (ohci); disable (ohci);
ohci_dbg (ohci, "device removed!\n"); ohci_dbg (ohci, "device removed!\n");
return; return IRQ_HANDLED;
/* interrupt for some other device? */ /* interrupt for some other device? */
} else if ((ints &= readl (&regs->intrenable)) == 0) { } else if ((ints &= readl (&regs->intrenable)) == 0) {
return; return IRQ_NONE;
} }
if (ints & OHCI_INTR_UE) { if (ints & OHCI_INTR_UE) {
...@@ -604,6 +604,8 @@ static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) ...@@ -604,6 +604,8 @@ static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
// flush those pci writes // flush those pci writes
(void) readl (&ohci->regs->control); (void) readl (&ohci->regs->control);
} }
return IRQ_HANDLED;
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
......
...@@ -1909,7 +1909,7 @@ static void uhci_remove_pending_qhs(struct uhci_hcd *uhci) ...@@ -1909,7 +1909,7 @@ static void uhci_remove_pending_qhs(struct uhci_hcd *uhci)
spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags); 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); struct uhci_hcd *uhci = hcd_to_uhci(hcd);
unsigned int io_addr = uhci->io_addr; unsigned int io_addr = uhci->io_addr;
...@@ -1922,7 +1922,7 @@ static void uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) ...@@ -1922,7 +1922,7 @@ static void uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
*/ */
status = inw(io_addr + USBSTS); status = inw(io_addr + USBSTS);
if (!status) /* shared interrupt, not mine */ if (!status) /* shared interrupt, not mine */
return; return IRQ_NONE;
outw(status, io_addr + USBSTS); /* Clear it */ outw(status, io_addr + USBSTS); /* Clear it */
if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) { if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) {
...@@ -1963,6 +1963,7 @@ static void uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) ...@@ -1963,6 +1963,7 @@ static void uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
spin_unlock(&uhci->urb_list_lock); spin_unlock(&uhci->urb_list_lock);
uhci_finish_completion(hcd, regs); uhci_finish_completion(hcd, regs);
return IRQ_HANDLED;
} }
static void reset_hc(struct uhci_hcd *uhci) static void reset_hc(struct uhci_hcd *uhci)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment