aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ohci-hub.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/ohci-hub.c')
-rw-r--r--drivers/usb/host/ohci-hub.c24
1 files changed, 21 insertions, 3 deletions
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 48e4b11f4d3e..c638e6b33c43 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -564,14 +564,18 @@ static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port)
564 u32 temp; 564 u32 temp;
565 u16 now = ohci_readl(ohci, &ohci->regs->fmnumber); 565 u16 now = ohci_readl(ohci, &ohci->regs->fmnumber);
566 u16 reset_done = now + PORT_RESET_MSEC; 566 u16 reset_done = now + PORT_RESET_MSEC;
567 int limit_1 = DIV_ROUND_UP(PORT_RESET_MSEC, PORT_RESET_HW_MSEC);
567 568
568 /* build a "continuous enough" reset signal, with up to 569 /* build a "continuous enough" reset signal, with up to
569 * 3msec gap between pulses. scheduler HZ==100 must work; 570 * 3msec gap between pulses. scheduler HZ==100 must work;
570 * this might need to be deadline-scheduled. 571 * this might need to be deadline-scheduled.
571 */ 572 */
572 do { 573 do {
574 int limit_2;
575
573 /* spin until any current reset finishes */ 576 /* spin until any current reset finishes */
574 for (;;) { 577 limit_2 = PORT_RESET_HW_MSEC * 2;
578 while (--limit_2 >= 0) {
575 temp = ohci_readl (ohci, portstat); 579 temp = ohci_readl (ohci, portstat);
576 /* handle e.g. CardBus eject */ 580 /* handle e.g. CardBus eject */
577 if (temp == ~(u32)0) 581 if (temp == ~(u32)0)
@@ -581,6 +585,17 @@ static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port)
581 udelay (500); 585 udelay (500);
582 } 586 }
583 587
588 /* timeout (a hardware error) has been observed when
589 * EHCI sets CF while this driver is resetting a port;
590 * presumably other disconnect paths might do it too.
591 */
592 if (limit_2 < 0) {
593 ohci_dbg(ohci,
594 "port[%d] reset timeout, stat %08x\n",
595 port, temp);
596 break;
597 }
598
584 if (!(temp & RH_PS_CCS)) 599 if (!(temp & RH_PS_CCS))
585 break; 600 break;
586 if (temp & RH_PS_PRSC) 601 if (temp & RH_PS_PRSC)
@@ -590,8 +605,11 @@ static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port)
590 ohci_writel (ohci, RH_PS_PRS, portstat); 605 ohci_writel (ohci, RH_PS_PRS, portstat);
591 msleep(PORT_RESET_HW_MSEC); 606 msleep(PORT_RESET_HW_MSEC);
592 now = ohci_readl(ohci, &ohci->regs->fmnumber); 607 now = ohci_readl(ohci, &ohci->regs->fmnumber);
593 } while (tick_before(now, reset_done)); 608 } while (tick_before(now, reset_done) && --limit_1 >= 0);
594 /* caller synchronizes using PRSC */ 609
610 /* caller synchronizes using PRSC ... and handles PRS
611 * still being set when this returns.
612 */
595 613
596 return 0; 614 return 0;
597} 615}