Dear, All.
I have found a problem where the root_port_reset() goes into an infinite
loop and stall the kernel.
This happens when an hardware fault inside the machine occurs during a small
timing window. In case of USB device connection, if a USB device, responds to
hcd_submit_urb(), and later the machine fails before root_port_reset(),
root_port_reset() will loop infinitely because ohci_readl() will always
return "-1".
The probability of this problem is low, but it will increase if PnP
processing becomes frequent. The attached patch can solve this problem
and I believe that it is better to fix this problem.
[in the case of the USB device connection]
hub_events()
|
hub_port_connect_change()
|
<omission>
|
usb_submit_urb()
|
hcd_submit_urb() <---- If the H/W machine trouble has already occured,
| hcd_submit_urb() returns error code(ESHUTDOWN).
| And the functions after this are not called.
<omission>
|
| <------- If the H/W machine trouble occurs between hcd_submit_urb()
| and root_port_reset(),root_port_reset() will go into
| endless loop because ohci_readl() will always return "-1".
|
root_port_reset()
The patch that fixed this problem is as follows.
Signed-off-by:Takamasa Ohtake <[EMAIL PROTECTED]>
Index: linux-2.6.15.4/drivers/usb/host/ohci-hub.c
===================================================================
--- linux-2.6.15.4/drivers/usb/host/ohci-hub.c.orig 2006-02-28
14:05:22.716664344 +0900
+++ linux-2.6.15.4/drivers/usb/host/ohci-hub.c 2006-02-28 14:05:22.699666928
+0900
@@ -475,7 +475,7 @@ static void start_hnp(struct ohci_hcd *o
#define tick_before(t1,t2) ((s16)(((s16)(t1))-((s16)(t2))) < 0)
/* called from some task, normally khubd */
-static inline void root_port_reset (struct ohci_hcd *ohci, unsigned port)
+static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port)
{
__hc32 __iomem *portstat = &ohci->regs->roothub.portstatus [port];
u32 temp;
@@ -490,6 +490,8 @@ static inline void root_port_reset (stru
/* spin until any current reset finishes */
for (;;) {
temp = ohci_readl (ohci, portstat);
+ if (temp == ~(u32)0)
+ return -ESHUTDOWN;
if (!(temp & RH_PS_PRS))
break;
udelay (500);
@@ -506,6 +508,8 @@ static inline void root_port_reset (stru
now = ohci_readl(ohci, &ohci->regs->fmnumber);
} while (tick_before(now, reset_done));
/* caller synchronizes using PRSC */
+
+ return 0;
}
static int ohci_hub_control (
@@ -625,7 +629,7 @@ static int ohci_hub_control (
&ohci->regs->roothub.portstatus [wIndex]);
break;
case USB_PORT_FEAT_RESET:
- root_port_reset (ohci, wIndex);
+ retval = root_port_reset (ohci, wIndex);
break;
default:
goto error;
^---
--------------------------------------------------
Takamasa Ohtake | Servers Software Division
| NEC System Technologies, Ltd.
| [EMAIL PROTECTED]
--------------------------------------------------
-------------------------------------------------------
This SF.Net email is sponsored by xPML, a groundbreaking scripting language
that extends applications into web and mobile media. Attend the live webcast
and join the prime developer group breaking into this new coding territory!
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=110944&bid=241720&dat=121642
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel