diff options
author | Kevin O'Connor <kevin@koconnor.net> | 2010-02-14 18:59:48 -0500 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2010-02-14 18:59:48 -0500 |
commit | 49a0aa61a581991526926a875c30870bfd7ec6e9 (patch) | |
tree | 5f8635d35482501f6f3cf7794bc1aef8592bb5d3 | |
parent | cfdc13f37f3fa3c7d8c11848f58cfc18a98e37a4 (diff) | |
download | seabios-hppa-49a0aa61a581991526926a875c30870bfd7ec6e9.zip seabios-hppa-49a0aa61a581991526926a875c30870bfd7ec6e9.tar.gz seabios-hppa-49a0aa61a581991526926a875c30870bfd7ec6e9.tar.bz2 |
Don't parallelize USB OHCI root port reset.
If multiple ports are reset simultaneously, they could both respond to
the default address. So, only reset one at a time.
-rw-r--r-- | src/usb-ohci.c | 53 |
1 files changed, 32 insertions, 21 deletions
diff --git a/src/usb-ohci.c b/src/usb-ohci.c index 421c19b..4ce75a6 100644 --- a/src/usb-ohci.c +++ b/src/usb-ohci.c @@ -82,38 +82,49 @@ check_ohci_ports(struct usb_s *cntl) writel(&cntl->ohci.regs->roothub_status, RH_HS_LPSC); writel(&cntl->ohci.regs->roothub_b, RH_B_PPCM); msleep((rha >> 24) * 2); + // XXX - need to sleep for USB_TIME_SIGATT if just powered up? // Count and reset connected devices int ports = rha & RH_A_NDP; int totalcount = 0; int i; - for (i=0; i<ports; i++) - if (readl(&cntl->ohci.regs->roothub_portstatus[i]) & RH_PS_CCS) { - writel(&cntl->ohci.regs->roothub_portstatus[i], RH_PS_PRS); - totalcount++; - } - if (!totalcount) - // No devices connected - goto shutdown; - - // XXX - should poll instead of using timer. - msleep(USB_TIME_DRSTR + USB_TIME_RSTRCY); - - totalcount = 0; for (i=0; i<ports; i++) { u32 sts = readl(&cntl->ohci.regs->roothub_portstatus[i]); - if ((sts & (RH_PS_CCS|RH_PS_PES)) == (RH_PS_CCS|RH_PS_PES)) { - int count = configure_usb_device(cntl, !!(sts & RH_PS_LSDA)); - if (! count) - // Shutdown port - writel(&cntl->ohci.regs->roothub_portstatus[i] - , RH_PS_CCS|RH_PS_LSDA); - totalcount += count; + if (!(sts & RH_PS_CCS)) + continue; + // XXX - need to wait for USB_TIME_ATTDB if just powered up? + writel(&cntl->ohci.regs->roothub_portstatus[i], RH_PS_PRS); + u64 end = calc_future_tsc(USB_TIME_DRSTR * 2); + for (;;) { + sts = readl(&cntl->ohci.regs->roothub_portstatus[i]); + if (!(sts & RH_PS_PRS)) + // XXX - need to ensure USB_TIME_DRSTR time in reset? + break; + if (check_time(end)) { + // Timeout. + warn_timeout(); + goto shutdown; + } + yield(); } + + if ((sts & (RH_PS_CCS|RH_PS_PES)) != (RH_PS_CCS|RH_PS_PES)) + // Device no longer present + continue; + + msleep(USB_TIME_RSTRCY); + + // XXX - should try to parallelize configuration. + int count = configure_usb_device(cntl, !!(sts & RH_PS_LSDA)); + if (! count) + // Shutdown port + writel(&cntl->ohci.regs->roothub_portstatus[i] + , RH_PS_CCS|RH_PS_LSDA); + totalcount += count; } if (!totalcount) + // No devices connected goto shutdown; - return totalcount; shutdown: |