]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
xHCI: add cmd_ring_state
authorElric Fu <elricfu1@gmail.com>
Wed, 27 Jun 2012 08:30:57 +0000 (16:30 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 7 Oct 2012 15:39:33 +0000 (08:39 -0700)
commit c181bc5b5d5c79b71203cd10cef97f802fb6f9c1 upstream.

Adding cmd_ring_state for command ring. It helps to verify
the current command ring state for controlling the command
ring operations.

This patch should be backported to kernels as old as 3.0.  The commit
7ed603ecf8b68ab81f4c83097d3063d43ec73bb8 "xhci: Add an assertion to
check for virt_dev=0 bug." papers over the NULL pointer dereference that
I now believe is related to a timed out Set Address command.  This (and
the four patches that follow it) contain the real fix that also allows
VIA USB 3.0 hubs to consistently re-enumerate during the plug/unplug
stress tests.

Signed-off-by: Elric Fu <elricfu1@gmail.com>
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Tested-by: Miroslav Sabljic <miroslav.sabljic@avl.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h

index c1df87b1c9daeb8003f93a4a3a470bf520512d50..855a462f1c87ad740acb6dd460a70f598b09ef39 100644 (file)
@@ -280,6 +280,9 @@ static inline int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring,
 /* Ring the host controller doorbell after placing a command on the ring */
 void xhci_ring_cmd_db(struct xhci_hcd *xhci)
 {
+       if (!(xhci->cmd_ring_state & CMD_RING_STATE_RUNNING))
+               return;
+
        xhci_dbg(xhci, "// Ding dong!\n");
        xhci_writel(xhci, DB_VALUE_HOST, &xhci->dba->doorbell[0]);
        /* Flush PCI posted writes */
index 8e80cfd125249d9510de5cf83e337db3ba3e7382..de57002f43fe8f07c02922a2cd2a9d5651c0ebf8 100644 (file)
@@ -105,9 +105,10 @@ int xhci_halt(struct xhci_hcd *xhci)
 
        ret = handshake(xhci, &xhci->op_regs->status,
                        STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC);
-       if (!ret)
+       if (!ret) {
                xhci->xhc_state |= XHCI_STATE_HALTED;
-       else
+               xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
+       } else
                xhci_warn(xhci, "Host not halted after %u microseconds.\n",
                                XHCI_MAX_HALT_USEC);
        return ret;
@@ -583,6 +584,7 @@ static int xhci_run_finished(struct xhci_hcd *xhci)
                return -ENODEV;
        }
        xhci->shared_hcd->state = HC_STATE_RUNNING;
+       xhci->cmd_ring_state = CMD_RING_STATE_RUNNING;
 
        if (xhci->quirks & XHCI_NEC_HOST)
                xhci_ring_cmd_db(xhci);
index e41557901e93e7546a4feb0a4504b770cf4de24f..d5d40ae7441f79193c65d6bd11975caf7379d5f7 100644 (file)
@@ -1421,6 +1421,10 @@ struct xhci_hcd {
        /* data structures */
        struct xhci_device_context_array *dcbaa;
        struct xhci_ring        *cmd_ring;
+       unsigned int            cmd_ring_state;
+#define CMD_RING_STATE_RUNNING         (1 << 0)
+#define CMD_RING_STATE_ABORTED         (1 << 1)
+#define CMD_RING_STATE_STOPPED         (1 << 2)
        unsigned int            cmd_ring_reserved_trbs;
        struct xhci_ring        *event_ring;
        struct xhci_erst        erst;