diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2011-05-17 17:27:12 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-05-19 19:34:04 -0400 |
commit | 69fff59de4d844f8b4c2454c3c23d32b69dcbfd7 (patch) | |
tree | 3d88efbce85e3a8c25651d07f9c9ddafbda86ae5 /drivers/usb | |
parent | d23894402b33338c51f1863d7f866fdc6f073a02 (diff) |
USB: remove remaining usages of hcd->state from usbcore and fix regression
This patch (as1467) removes the last usages of hcd->state from
usbcore. We no longer check to see if an interrupt handler finds that
a controller has died; instead we rely on host controller drivers to
make an explicit call to usb_hc_died().
This fixes a regression introduced by commit
9b37596a2e860404503a3f2a6513db60c296bfdc (USB: move usbcore away from
hcd->state). It used to be that when a controller shared an IRQ with
another device and an interrupt arrived while hcd->state was set to
HC_STATE_HALT, the interrupt handler would be skipped. The commit
removed that test; as a result the current code doesn't skip calling
the handler and ends up believing the controller has died, even though
it's only temporarily stopped. The solution is to ignore HC_STATE_HALT
following the handler's return.
As a consequence of this change, several of the host controller
drivers need to be modified. They can no longer implicitly rely on
usbcore realizing that a controller has died because of hcd->state.
The patch adds calls to usb_hc_died() in the appropriate places.
The patch also changes a few of the interrupt handlers. They don't
expect to be called when hcd->state is equal to HC_STATE_HALT, even if
the controller is still alive. Early returns were added to avoid any
confusion.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Tested-by: Manuel Lauss <manuel.lauss@googlemail.com>
CC: Rodolfo Giometti <giometti@linux.it>
CC: Olav Kongas <ok@artecdesign.ee>
CC: <stable@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/core/hcd.c | 5 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 4 | ||||
-rw-r--r-- | drivers/usb/host/ehci-sched.c | 8 | ||||
-rw-r--r-- | drivers/usb/host/isp116x-hcd.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/ohci-hcd.c | 4 | ||||
-rw-r--r-- | drivers/usb/host/oxu210hp-hcd.c | 6 |
6 files changed, 19 insertions, 9 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 10936ba9c42b..ace9f8442e5d 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c | |||
@@ -986,7 +986,7 @@ static int register_root_hub(struct usb_hcd *hcd) | |||
986 | spin_unlock_irq (&hcd_root_hub_lock); | 986 | spin_unlock_irq (&hcd_root_hub_lock); |
987 | 987 | ||
988 | /* Did the HC die before the root hub was registered? */ | 988 | /* Did the HC die before the root hub was registered? */ |
989 | if (HCD_DEAD(hcd) || hcd->state == HC_STATE_HALT) | 989 | if (HCD_DEAD(hcd)) |
990 | usb_hc_died (hcd); /* This time clean up */ | 990 | usb_hc_died (hcd); /* This time clean up */ |
991 | } | 991 | } |
992 | 992 | ||
@@ -2128,9 +2128,6 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd) | |||
2128 | set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); | 2128 | set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); |
2129 | if (hcd->shared_hcd) | 2129 | if (hcd->shared_hcd) |
2130 | set_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags); | 2130 | set_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags); |
2131 | |||
2132 | if (unlikely(hcd->state == HC_STATE_HALT)) | ||
2133 | usb_hc_died(hcd); | ||
2134 | rc = IRQ_HANDLED; | 2131 | rc = IRQ_HANDLED; |
2135 | } | 2132 | } |
2136 | 2133 | ||
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index c5719cd258c3..b435ed67dd5c 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c | |||
@@ -777,8 +777,9 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) | |||
777 | goto dead; | 777 | goto dead; |
778 | } | 778 | } |
779 | 779 | ||
780 | /* Shared IRQ? */ | ||
780 | masked_status = status & INTR_MASK; | 781 | masked_status = status & INTR_MASK; |
781 | if (!masked_status) { /* irq sharing? */ | 782 | if (!masked_status || unlikely(hcd->state == HC_STATE_HALT)) { |
782 | spin_unlock(&ehci->lock); | 783 | spin_unlock(&ehci->lock); |
783 | return IRQ_NONE; | 784 | return IRQ_NONE; |
784 | } | 785 | } |
@@ -873,6 +874,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) | |||
873 | dead: | 874 | dead: |
874 | ehci_reset(ehci); | 875 | ehci_reset(ehci); |
875 | ehci_writel(ehci, 0, &ehci->regs->configured_flag); | 876 | ehci_writel(ehci, 0, &ehci->regs->configured_flag); |
877 | usb_hc_died(hcd); | ||
876 | /* generic layer kills/unlinks all urbs, then | 878 | /* generic layer kills/unlinks all urbs, then |
877 | * uses ehci_stop to clean up the rest | 879 | * uses ehci_stop to clean up the rest |
878 | */ | 880 | */ |
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index a7408d88fda0..6c9fbe352f73 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c | |||
@@ -471,8 +471,10 @@ static int enable_periodic (struct ehci_hcd *ehci) | |||
471 | */ | 471 | */ |
472 | status = handshake_on_error_set_halt(ehci, &ehci->regs->status, | 472 | status = handshake_on_error_set_halt(ehci, &ehci->regs->status, |
473 | STS_PSS, 0, 9 * 125); | 473 | STS_PSS, 0, 9 * 125); |
474 | if (status) | 474 | if (status) { |
475 | usb_hc_died(ehci_to_hcd(ehci)); | ||
475 | return status; | 476 | return status; |
477 | } | ||
476 | 478 | ||
477 | cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE; | 479 | cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE; |
478 | ehci_writel(ehci, cmd, &ehci->regs->command); | 480 | ehci_writel(ehci, cmd, &ehci->regs->command); |
@@ -510,8 +512,10 @@ static int disable_periodic (struct ehci_hcd *ehci) | |||
510 | */ | 512 | */ |
511 | status = handshake_on_error_set_halt(ehci, &ehci->regs->status, | 513 | status = handshake_on_error_set_halt(ehci, &ehci->regs->status, |
512 | STS_PSS, STS_PSS, 9 * 125); | 514 | STS_PSS, STS_PSS, 9 * 125); |
513 | if (status) | 515 | if (status) { |
516 | usb_hc_died(ehci_to_hcd(ehci)); | ||
514 | return status; | 517 | return status; |
518 | } | ||
515 | 519 | ||
516 | cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE; | 520 | cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE; |
517 | ehci_writel(ehci, cmd, &ehci->regs->command); | 521 | ehci_writel(ehci, cmd, &ehci->regs->command); |
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index c0e22f26da19..baae4ccd16ac 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c | |||
@@ -612,6 +612,7 @@ static irqreturn_t isp116x_irq(struct usb_hcd *hcd) | |||
612 | /* IRQ's are off, we do no DMA, | 612 | /* IRQ's are off, we do no DMA, |
613 | perfectly ready to die ... */ | 613 | perfectly ready to die ... */ |
614 | hcd->state = HC_STATE_HALT; | 614 | hcd->state = HC_STATE_HALT; |
615 | usb_hc_died(hcd); | ||
615 | ret = IRQ_HANDLED; | 616 | ret = IRQ_HANDLED; |
616 | goto done; | 617 | goto done; |
617 | } | 618 | } |
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 8c8dc6559ac7..9aa10bdf3918 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c | |||
@@ -764,6 +764,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) | |||
764 | if (ints == ~(u32)0) { | 764 | if (ints == ~(u32)0) { |
765 | disable (ohci); | 765 | disable (ohci); |
766 | ohci_dbg (ohci, "device removed!\n"); | 766 | ohci_dbg (ohci, "device removed!\n"); |
767 | usb_hc_died(hcd); | ||
767 | return IRQ_HANDLED; | 768 | return IRQ_HANDLED; |
768 | } | 769 | } |
769 | 770 | ||
@@ -771,7 +772,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) | |||
771 | ints &= ohci_readl(ohci, ®s->intrenable); | 772 | ints &= ohci_readl(ohci, ®s->intrenable); |
772 | 773 | ||
773 | /* interrupt for some other device? */ | 774 | /* interrupt for some other device? */ |
774 | if (ints == 0) | 775 | if (ints == 0 || unlikely(hcd->state == HC_STATE_HALT)) |
775 | return IRQ_NOTMINE; | 776 | return IRQ_NOTMINE; |
776 | 777 | ||
777 | if (ints & OHCI_INTR_UE) { | 778 | if (ints & OHCI_INTR_UE) { |
@@ -788,6 +789,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) | |||
788 | } else { | 789 | } else { |
789 | disable (ohci); | 790 | disable (ohci); |
790 | ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n"); | 791 | ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n"); |
792 | usb_hc_died(hcd); | ||
791 | } | 793 | } |
792 | 794 | ||
793 | ohci_dump (ohci, 1); | 795 | ohci_dump (ohci, 1); |
diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index 4a771f6cc822..5fbe997dc6df 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c | |||
@@ -1884,6 +1884,7 @@ static int enable_periodic(struct oxu_hcd *oxu) | |||
1884 | status = handshake(oxu, &oxu->regs->status, STS_PSS, 0, 9 * 125); | 1884 | status = handshake(oxu, &oxu->regs->status, STS_PSS, 0, 9 * 125); |
1885 | if (status != 0) { | 1885 | if (status != 0) { |
1886 | oxu_to_hcd(oxu)->state = HC_STATE_HALT; | 1886 | oxu_to_hcd(oxu)->state = HC_STATE_HALT; |
1887 | usb_hc_died(oxu_to_hcd(oxu)); | ||
1887 | return status; | 1888 | return status; |
1888 | } | 1889 | } |
1889 | 1890 | ||
@@ -1909,6 +1910,7 @@ static int disable_periodic(struct oxu_hcd *oxu) | |||
1909 | status = handshake(oxu, &oxu->regs->status, STS_PSS, STS_PSS, 9 * 125); | 1910 | status = handshake(oxu, &oxu->regs->status, STS_PSS, STS_PSS, 9 * 125); |
1910 | if (status != 0) { | 1911 | if (status != 0) { |
1911 | oxu_to_hcd(oxu)->state = HC_STATE_HALT; | 1912 | oxu_to_hcd(oxu)->state = HC_STATE_HALT; |
1913 | usb_hc_died(oxu_to_hcd(oxu)); | ||
1912 | return status; | 1914 | return status; |
1913 | } | 1915 | } |
1914 | 1916 | ||
@@ -2449,8 +2451,9 @@ static irqreturn_t oxu210_hcd_irq(struct usb_hcd *hcd) | |||
2449 | goto dead; | 2451 | goto dead; |
2450 | } | 2452 | } |
2451 | 2453 | ||
2454 | /* Shared IRQ? */ | ||
2452 | status &= INTR_MASK; | 2455 | status &= INTR_MASK; |
2453 | if (!status) { /* irq sharing? */ | 2456 | if (!status || unlikely(hcd->state == HC_STATE_HALT)) { |
2454 | spin_unlock(&oxu->lock); | 2457 | spin_unlock(&oxu->lock); |
2455 | return IRQ_NONE; | 2458 | return IRQ_NONE; |
2456 | } | 2459 | } |
@@ -2516,6 +2519,7 @@ static irqreturn_t oxu210_hcd_irq(struct usb_hcd *hcd) | |||
2516 | dead: | 2519 | dead: |
2517 | ehci_reset(oxu); | 2520 | ehci_reset(oxu); |
2518 | writel(0, &oxu->regs->configured_flag); | 2521 | writel(0, &oxu->regs->configured_flag); |
2522 | usb_hc_died(hcd); | ||
2519 | /* generic layer kills/unlinks all urbs, then | 2523 | /* generic layer kills/unlinks all urbs, then |
2520 | * uses oxu_stop to clean up the rest | 2524 | * uses oxu_stop to clean up the rest |
2521 | */ | 2525 | */ |