Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=32fe01985aa2cb2562f6fc171e526e279abe10db
Commit:     32fe01985aa2cb2562f6fc171e526e279abe10db
Parent:     17f060224fb9f435c6f9306b7b61419d038def13
Author:     Alan Stern <[EMAIL PROTECTED]>
AuthorDate: Wed Oct 10 16:27:07 2007 -0400
Committer:  Greg Kroah-Hartman <[EMAIL PROTECTED]>
CommitDate: Fri Oct 12 14:55:34 2007 -0700

    USB: mutual exclusion for EHCI init and port resets
    
    This patch (as999) fixes a problem that sometimes shows up when host
    controller driver modules are loaded in the wrong order.  If ehci-hcd
    happens to initialize an EHCI controller while the companion OHCI or
    UHCI controller is in the middle of a port reset, the reset can fail
    and the companion may get very confused.  The patch adds an
    rw-semaphore and uses it to keep EHCI initialization and port resets
    mutually exclusive.
    
    Signed-off-by: Alan Stern <[EMAIL PROTECTED]>
    Acked-by: David Brownell <[EMAIL PROTECTED]>
    Cc: David Miller <[EMAIL PROTECTED]>
    Cc: Dely L Sy <[EMAIL PROTECTED]>
    Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>
---
 drivers/usb/core/hcd.h      |    8 +++++++-
 drivers/usb/core/hub.c      |   15 ++++++++++++++-
 drivers/usb/host/ehci-hcd.c |    8 ++++++++
 3 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 1396141..98e2419 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -19,6 +19,8 @@
 
 #ifdef __KERNEL__
 
+#include <linux/rwsem.h>
+
 /* This file contains declarations of usbcore internals that are mostly
  * used or exposed by Host Controller Drivers.
  */
@@ -470,5 +472,9 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, 
struct urb *urb,
                : (in_interrupt () ? "in_interrupt" : "can sleep"))
 
 
-#endif /* __KERNEL__ */
+/* This rwsem is for use only by the hub driver and ehci-hcd.
+ * Nobody else should touch it.
+ */
+extern struct rw_semaphore ehci_cf_port_reset_rwsem;
 
+#endif /* __KERNEL__ */
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 481dca6..d20cb54 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -125,6 +125,12 @@ MODULE_PARM_DESC(use_both_schemes,
                "try the other device initialization scheme if the "
                "first one fails");
 
+/* Mutual exclusion for EHCI CF initialization.  This interferes with
+ * port reset on some companion controllers.
+ */
+DECLARE_RWSEM(ehci_cf_port_reset_rwsem);
+EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem);
+
 
 static inline char *portspeed(int portstatus)
 {
@@ -1581,6 +1587,11 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
 {
        int i, status;
 
+       /* Block EHCI CF initialization during the port reset.
+        * Some companion controllers don't like it when they mix.
+        */
+       down_read(&ehci_cf_port_reset_rwsem);
+
        /* Reset the port */
        for (i = 0; i < PORT_RESET_TRIES; i++) {
                status = set_port_feature(hub->hdev,
@@ -1612,7 +1623,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
                        usb_set_device_state(udev, status
                                        ? USB_STATE_NOTATTACHED
                                        : USB_STATE_DEFAULT);
-                       return status;
+                       goto done;
                }
 
                dev_dbg (hub->intfdev,
@@ -1625,6 +1636,8 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
                "Cannot enable port %i.  Maybe the USB cable is bad?\n",
                port1);
 
+ done:
+       up_read(&ehci_cf_port_reset_rwsem);
        return status;
 }
 
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index db00492..c151444 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -570,10 +570,18 @@ static int ehci_run (struct usb_hcd *hcd)
         * are explicitly handed to companion controller(s), so no TT is
         * involved with the root hub.  (Except where one is integrated,
         * and there's no companion controller unless maybe for USB OTG.)
+        *
+        * Turning on the CF flag will transfer ownership of all ports
+        * from the companions to the EHCI controller.  If any of the
+        * companions are in the middle of a port reset at the time, it
+        * could cause trouble.  Write-locking ehci_cf_port_reset_rwsem
+        * guarantees that no resets are in progress.
         */
+       down_write(&ehci_cf_port_reset_rwsem);
        hcd->state = HC_STATE_RUNNING;
        ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
        ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
+       up_write(&ehci_cf_port_reset_rwsem);
 
        temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
        ehci_info (ehci,
-
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