lkml.org 
[lkml]   [2007]   [Nov]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[patch 19/26] USB: mutual exclusion for EHCI init and port resets

    2.6.22-stable review patch. If anyone has any objections, please let us
    know.

    ------------------
    From: Alan Stern <stern@rowland.harvard.edu>

    patch 32fe01985aa2cb2562f6fc171e526e279abe10db in mainline.

    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 <stern@rowland.harvard.edu>
    Acked-by: David Brownell <david-b@pacbell.net>
    Cc: David Miller <davem@davemloft.net>
    Cc: Dely L Sy <dely.l.sy@intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
    ---
    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(-)

    --- 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.
    */
    @@ -464,5 +466,9 @@ static inline void usbmon_urb_complete(s
    : (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__ */
    --- a/drivers/usb/core/hub.c
    +++ b/drivers/usb/core/hub.c
    @@ -117,6 +117,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)
    {
    @@ -1513,6 +1519,11 @@ static int hub_port_reset(struct usb_hub
    {
    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,
    @@ -1543,7 +1554,7 @@ static int hub_port_reset(struct usb_hub
    usb_set_device_state(udev, status
    ? USB_STATE_NOTATTACHED
    : USB_STATE_DEFAULT);
    - return status;
    + goto done;
    }

    dev_dbg (hub->intfdev,
    @@ -1556,6 +1567,8 @@ static int hub_port_reset(struct usb_hub
    "Cannot enable port %i. Maybe the USB cable is bad?\n",
    port1);

    + done:
    + up_read(&ehci_cf_port_reset_rwsem);
    return status;
    }

    --- a/drivers/usb/host/ehci-hcd.c
    +++ b/drivers/usb/host/ehci-hcd.c
    @@ -566,10 +566,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 linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2007-11-19 19:33    [W:0.038 / U:0.880 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site