From: David Miller <davem@davemloft.net> Date: Sun, 07 Oct 2007 00:51:56 -0700 (PDT)To add some more information here, I think the EHCI idea might hold some water. What I have here are two NEC OHCI USB interfaces and one NEC EHCI USB interface on PCI. Aparently they all go through a shared USB hub, mapped like this: HUB Port 1: OHCI #1, EHCI HUB Port 2: OHCI #2, EHCI HUB Port 3: OHCI #1, EHCI HUB Port 4: OHCI #2, EHCI HUB Port 5: OHCI #1, EHCI The OHCI ports go out to external USB connectors on the back panel of the machine, whereas the EHCI is connected up to an internal USB storage CDROM device and what appears to be another USB hub. The problem seems to be very strongly tied to timing. For example simply adding "ignore_loglevel" to the kernel boot command line can make the problem go away. This got me thinking about your EHCI comment. If these controllers are going through the same HUB, things might go south if OHCI initialized first, then khubd et al. are asynchronously accessing the segments behind OHCI at the same time that the EHCI driver is initializing. Perhaps, this is the kind of sequence of events which makes one of the root ports reset in such a way that the the reset bit never clears. Given that this machine has 64 cpus, the likelyhood for such parallel accesses is very likely :-) Does this make any sense? Regardless, here is a patch that hardens the OHCI reset handling loops so that they break out instead of hanging the entire system should this condition occur. It's at least better than what the code does to a user right now which is hang the box completely: [USB] ohci: Do not hang the system if port reset does not complete. Signed-off-by: David S. Miller <davem@davemloft.net> diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index bb9cc59..77ae5b4 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -563,14 +563,19 @@ static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port) u32 temp; u16 now = ohci_readl(ohci, &ohci->regs->fmnumber); u16 reset_done = now + PORT_RESET_MSEC; + int limit_1; /* build a "continuous enough" reset signal, with up to * 3msec gap between pulses. scheduler HZ==100 must work; * this might need to be deadline-scheduled. */ - do { + limit_1 = 100; + while (--limit_1 >= 0) { + int limit_2; + /* spin until any current reset finishes */ - for (;;) { + limit_2 = PORT_RESET_MSEC * 2; + while (--limit_2 >= 0) { temp = ohci_readl (ohci, portstat); /* handle e.g. CardBus eject */ if (temp == ~(u32)0) @@ -579,6 +584,10 @@ static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port) break; udelay (500); } + if (limit_2 < 0) { + ohci_warn(ohci, "Root port inner-loop reset timeout, " + "portstat[%08x]\n", temp); + } if (!(temp & RH_PS_CCS)) break; @@ -589,7 +598,14 @@ static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port) ohci_writel (ohci, RH_PS_PRS, portstat); msleep(PORT_RESET_HW_MSEC); now = ohci_readl(ohci, &ohci->regs->fmnumber); - } while (tick_before(now, reset_done)); + if (!tick_before(now, reset_done)) + break; + } + if (limit_1 < 0) { + ohci_warn(ohci, "Root port outer-loop reset timeout, " + "now[%04x] reset_done[%04x]\n", + now, reset_done); + } /* caller synchronizes using PRSC */ return 0; -
| Tarkan Erimer | Re: Dual-Licensing Linux Kernel with GPL V2 and GPL V3 |
| Greg Kroah-Hartman | [PATCH 001/196] Chinese: Add the known_regression URI to the HOWTO |
| Benjamin Herrenschmidt | Re: [PATCH] Remove process freezer from suspend to RAM pathway |
| Bart Van Assche | Re: Integration of SCST in the mainstream Linux kernel |
git: | |
| Jarek Poplawski | [PATCH] pkt_sched: Destroy gen estimators under rtnl_lock(). |
| Arjan van de Ven | Re: [GIT]: Networking |
| Gerrit Renker | [PATCH 27/37] dccp: Integration of dynamic feature activation - part 2 (server side) |
| Natalie Protasevich | [BUG] New Kernel Bugs |
