Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=23d10a9e376d6a9cd4afd4e27e5e403864f6729b
Commit:     23d10a9e376d6a9cd4afd4e27e5e403864f6729b
Parent:     ee269d98a9248fbb729c20ffda0f1b97e82c5c37
Author:     Takamasa Ohtake <[EMAIL PROTECTED]>
AuthorDate: Wed Dec 6 17:04:15 2006 -0800
Committer:  Greg Kroah-Hartman <[EMAIL PROTECTED]>
CommitDate: Wed Dec 20 10:14:27 2006 -0800

    USB: ohci handles hardware faults during root port resets
    
    I have found a problem where the root_port_reset() goes into an infinite
    loop and stalls the kernel.
    
    This happens when a 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 controller fails before root_port_reset(),
    root_port_reset() will loop infinitely because ohci_readl() will always
    return "-1".  Such a failure can include ejecting a CardBus OHCI controller.
    
    The probability of this problem is low, but it will increase if PnP type
    usage is frequent.  The attached patch can solve this problem and I believe
    that it is better to fix this problem.
    
    Signed-off-by: Takamasa Ohtake <[EMAIL PROTECTED]>
    Signed-off-by: David Brownell <[EMAIL PROTECTED]>
    Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>
---
 drivers/usb/host/ohci-hub.c |    9 +++++++--
 1 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index f9748b6..216c9c9 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -555,7 +555,7 @@ static void start_hnp(struct ohci_hcd *ohci);
 #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;
@@ -570,6 +570,9 @@ static inline void root_port_reset (struct ohci_hcd *ohci, 
unsigned port)
                /* spin until any current reset finishes */
                for (;;) {
                        temp = ohci_readl (ohci, portstat);
+                       /* handle e.g. CardBus eject */
+                       if (temp == ~(u32)0)
+                               return -ESHUTDOWN;
                        if (!(temp & RH_PS_PRS))
                                break;
                        udelay (500);
@@ -586,6 +589,8 @@ static inline void root_port_reset (struct ohci_hcd *ohci, 
unsigned port)
                now = ohci_readl(ohci, &ohci->regs->fmnumber);
        } while (tick_before(now, reset_done));
        /* caller synchronizes using PRSC */
+
+       return 0;
 }
 
 static int ohci_hub_control (
@@ -702,7 +707,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;
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to