aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2010-02-14 18:59:48 -0500
committerKevin O'Connor <kevin@koconnor.net>2010-02-14 18:59:48 -0500
commit49a0aa61a581991526926a875c30870bfd7ec6e9 (patch)
tree5f8635d35482501f6f3cf7794bc1aef8592bb5d3
parentcfdc13f37f3fa3c7d8c11848f58cfc18a98e37a4 (diff)
downloadseabios-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.c53
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: