aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2011-05-17 17:27:12 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-05-19 19:34:04 -0400
commit69fff59de4d844f8b4c2454c3c23d32b69dcbfd7 (patch)
tree3d88efbce85e3a8c25651d07f9c9ddafbda86ae5 /drivers/usb
parentd23894402b33338c51f1863d7f866fdc6f073a02 (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.c5
-rw-r--r--drivers/usb/host/ehci-hcd.c4
-rw-r--r--drivers/usb/host/ehci-sched.c8
-rw-r--r--drivers/usb/host/isp116x-hcd.c1
-rw-r--r--drivers/usb/host/ohci-hcd.c4
-rw-r--r--drivers/usb/host/oxu210hp-hcd.c6
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)
873dead: 874dead:
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, &regs->intrenable); 772 ints &= ohci_readl(ohci, &regs->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)
2516dead: 2519dead:
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 */