]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.0-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 25 Oct 2012 23:49:02 +0000 (16:49 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 25 Oct 2012 23:49:02 +0000 (16:49 -0700)
added patches:
xhci-add-aborting-command-ring-function.patch
xhci-add-cmd_ring_state.patch
xhci-cancel-command-after-command-timeout.patch
xhci-handle-command-after-aborting-the-command-ring.patch

queue-3.0/series
queue-3.0/xhci-add-aborting-command-ring-function.patch [new file with mode: 0644]
queue-3.0/xhci-add-cmd_ring_state.patch [new file with mode: 0644]
queue-3.0/xhci-cancel-command-after-command-timeout.patch [new file with mode: 0644]
queue-3.0/xhci-handle-command-after-aborting-the-command-ring.patch [new file with mode: 0644]

index d5568adc37a3af1ef9f80e59a47eba549c8065b0..0dc88cad85beb664cd389f127d4fa417bf1aa0b8 100644 (file)
@@ -25,3 +25,7 @@ sparc64-like-x86-we-should-check-current-mm-during-perf-backtrace-generation.pat
 sparc64-fix-bit-twiddling-in-sparc_pmu_enable_event.patch
 sparc64-do-not-clobber-personality-flags-in-sys_sparc64_personality.patch
 sparc64-be-less-verbose-during-vmemmap-population.patch
+xhci-add-cmd_ring_state.patch
+xhci-add-aborting-command-ring-function.patch
+xhci-cancel-command-after-command-timeout.patch
+xhci-handle-command-after-aborting-the-command-ring.patch
diff --git a/queue-3.0/xhci-add-aborting-command-ring-function.patch b/queue-3.0/xhci-add-aborting-command-ring-function.patch
new file mode 100644 (file)
index 0000000..4441598
--- /dev/null
@@ -0,0 +1,241 @@
+From b92cc66c047ff7cf587b318fe377061a353c120f Mon Sep 17 00:00:00 2001
+From: Elric Fu <elricfu1@gmail.com>
+Date: Wed, 27 Jun 2012 16:31:12 +0800
+Subject: xHCI: add aborting command ring function
+
+From: Elric Fu <elricfu1@gmail.com>
+
+commit b92cc66c047ff7cf587b318fe377061a353c120f upstream.
+
+Software have to abort command ring and cancel command
+when a command is failed or hang. Otherwise, the command
+ring will hang up and can't handle the others. An example
+of a command that may hang is the Address Device Command,
+because waiting for a SET_ADDRESS request to be acknowledged
+by a USB device is outside of the xHC's ability to control.
+
+To cancel a command, software will initialize a command
+descriptor for the cancel command, and add it into a
+cancel_cmd_list of xhci.
+
+Sarah: Fixed missing newline on "Have the command ring been stopped?"
+debugging statement.
+
+This patch should be backported to kernels as old as 3.0, that contain
+the commit 7ed603ecf8b68ab81f4c83097d3063d43ec73bb8 "xhci: Add an
+assertion to check for virt_dev=0 bug." That commit papers over a NULL
+pointer dereference, and this patch fixes the underlying issue that
+caused the NULL pointer dereference.
+
+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-mem.c  |    7 ++
+ drivers/usb/host/xhci-ring.c |  108 +++++++++++++++++++++++++++++++++++++++++++
+ drivers/usb/host/xhci.c      |    2 
+ drivers/usb/host/xhci.h      |   12 ++++
+ 4 files changed, 128 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/host/xhci-mem.c
++++ b/drivers/usb/host/xhci-mem.c
+@@ -1505,6 +1505,7 @@ void xhci_free_command(struct xhci_hcd *
+ void xhci_mem_cleanup(struct xhci_hcd *xhci)
+ {
+       struct pci_dev  *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
++      struct xhci_cd  *cur_cd, *next_cd;
+       int size;
+       int i;
+@@ -1525,6 +1526,11 @@ void xhci_mem_cleanup(struct xhci_hcd *x
+               xhci_ring_free(xhci, xhci->cmd_ring);
+       xhci->cmd_ring = NULL;
+       xhci_dbg(xhci, "Freed command ring\n");
++      list_for_each_entry_safe(cur_cd, next_cd,
++                      &xhci->cancel_cmd_list, cancel_cmd_list) {
++              list_del(&cur_cd->cancel_cmd_list);
++              kfree(cur_cd);
++      }
+       for (i = 1; i < MAX_HC_SLOTS; ++i)
+               xhci_free_virt_device(xhci, i);
+@@ -2014,6 +2020,7 @@ int xhci_mem_init(struct xhci_hcd *xhci,
+       xhci->cmd_ring = xhci_ring_alloc(xhci, 1, true, false, flags);
+       if (!xhci->cmd_ring)
+               goto fail;
++      INIT_LIST_HEAD(&xhci->cancel_cmd_list);
+       xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring);
+       xhci_dbg(xhci, "First segment DMA is 0x%llx\n",
+                       (unsigned long long)xhci->cmd_ring->first_seg->dma);
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -320,6 +320,114 @@ void xhci_ring_cmd_db(struct xhci_hcd *x
+       xhci_readl(xhci, &xhci->dba->doorbell[0]);
+ }
++static int xhci_abort_cmd_ring(struct xhci_hcd *xhci)
++{
++      u64 temp_64;
++      int ret;
++
++      xhci_dbg(xhci, "Abort command ring\n");
++
++      if (!(xhci->cmd_ring_state & CMD_RING_STATE_RUNNING)) {
++              xhci_dbg(xhci, "The command ring isn't running, "
++                              "Have the command ring been stopped?\n");
++              return 0;
++      }
++
++      temp_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
++      if (!(temp_64 & CMD_RING_RUNNING)) {
++              xhci_dbg(xhci, "Command ring had been stopped\n");
++              return 0;
++      }
++      xhci->cmd_ring_state = CMD_RING_STATE_ABORTED;
++      xhci_write_64(xhci, temp_64 | CMD_RING_ABORT,
++                      &xhci->op_regs->cmd_ring);
++
++      /* Section 4.6.1.2 of xHCI 1.0 spec says software should
++       * time the completion od all xHCI commands, including
++       * the Command Abort operation. If software doesn't see
++       * CRR negated in a timely manner (e.g. longer than 5
++       * seconds), then it should assume that the there are
++       * larger problems with the xHC and assert HCRST.
++       */
++      ret = handshake(xhci, &xhci->op_regs->cmd_ring,
++                      CMD_RING_RUNNING, 0, 5 * 1000 * 1000);
++      if (ret < 0) {
++              xhci_err(xhci, "Stopped the command ring failed, "
++                              "maybe the host is dead\n");
++              xhci->xhc_state |= XHCI_STATE_DYING;
++              xhci_quiesce(xhci);
++              xhci_halt(xhci);
++              return -ESHUTDOWN;
++      }
++
++      return 0;
++}
++
++static int xhci_queue_cd(struct xhci_hcd *xhci,
++              struct xhci_command *command,
++              union xhci_trb *cmd_trb)
++{
++      struct xhci_cd *cd;
++      cd = kzalloc(sizeof(struct xhci_cd), GFP_ATOMIC);
++      if (!cd)
++              return -ENOMEM;
++      INIT_LIST_HEAD(&cd->cancel_cmd_list);
++
++      cd->command = command;
++      cd->cmd_trb = cmd_trb;
++      list_add_tail(&cd->cancel_cmd_list, &xhci->cancel_cmd_list);
++
++      return 0;
++}
++
++/*
++ * Cancel the command which has issue.
++ *
++ * Some commands may hang due to waiting for acknowledgement from
++ * usb device. It is outside of the xHC's ability to control and
++ * will cause the command ring is blocked. When it occurs software
++ * should intervene to recover the command ring.
++ * See Section 4.6.1.1 and 4.6.1.2
++ */
++int xhci_cancel_cmd(struct xhci_hcd *xhci, struct xhci_command *command,
++              union xhci_trb *cmd_trb)
++{
++      int retval = 0;
++      unsigned long flags;
++
++      spin_lock_irqsave(&xhci->lock, flags);
++
++      if (xhci->xhc_state & XHCI_STATE_DYING) {
++              xhci_warn(xhci, "Abort the command ring,"
++                              " but the xHCI is dead.\n");
++              retval = -ESHUTDOWN;
++              goto fail;
++      }
++
++      /* queue the cmd desriptor to cancel_cmd_list */
++      retval = xhci_queue_cd(xhci, command, cmd_trb);
++      if (retval) {
++              xhci_warn(xhci, "Queuing command descriptor failed.\n");
++              goto fail;
++      }
++
++      /* abort command ring */
++      retval = xhci_abort_cmd_ring(xhci);
++      if (retval) {
++              xhci_err(xhci, "Abort command ring failed\n");
++              if (unlikely(retval == -ESHUTDOWN)) {
++                      spin_unlock_irqrestore(&xhci->lock, flags);
++                      usb_hc_died(xhci_to_hcd(xhci)->primary_hcd);
++                      xhci_dbg(xhci, "xHCI host controller is dead.\n");
++                      return retval;
++              }
++      }
++
++fail:
++      spin_unlock_irqrestore(&xhci->lock, flags);
++      return retval;
++}
++
+ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci,
+               unsigned int slot_id,
+               unsigned int ep_index,
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -51,7 +51,7 @@ MODULE_PARM_DESC(link_quirk, "Don't clea
+  * handshake done).  There are two failure modes:  "usec" have passed (major
+  * hardware flakeout), or the register reads as all-ones (hardware removed).
+  */
+-static int handshake(struct xhci_hcd *xhci, void __iomem *ptr,
++int handshake(struct xhci_hcd *xhci, void __iomem *ptr,
+                     u32 mask, u32 done, int usec)
+ {
+       u32     result;
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1111,6 +1111,13 @@ struct xhci_td {
+       union xhci_trb          *last_trb;
+ };
++/* command descriptor */
++struct xhci_cd {
++      struct list_head        cancel_cmd_list;
++      struct xhci_command     *command;
++      union xhci_trb          *cmd_trb;
++};
++
+ struct xhci_dequeue_state {
+       struct xhci_segment *new_deq_seg;
+       union xhci_trb *new_deq_ptr;
+@@ -1256,6 +1263,7 @@ struct xhci_hcd {
+ #define CMD_RING_STATE_RUNNING         (1 << 0)
+ #define CMD_RING_STATE_ABORTED         (1 << 1)
+ #define CMD_RING_STATE_STOPPED         (1 << 2)
++      struct list_head        cancel_cmd_list;
+       unsigned int            cmd_ring_reserved_trbs;
+       struct xhci_ring        *event_ring;
+       struct xhci_erst        erst;
+@@ -1490,6 +1498,8 @@ void xhci_unregister_pci(void);
+ #endif
+ /* xHCI host controller glue */
++int handshake(struct xhci_hcd *xhci, void __iomem *ptr,
++              u32 mask, u32 done, int usec);
+ void xhci_quiesce(struct xhci_hcd *xhci);
+ int xhci_halt(struct xhci_hcd *xhci);
+ int xhci_reset(struct xhci_hcd *xhci);
+@@ -1572,6 +1582,8 @@ void xhci_queue_config_ep_quirk(struct x
+               unsigned int slot_id, unsigned int ep_index,
+               struct xhci_dequeue_state *deq_state);
+ void xhci_stop_endpoint_command_watchdog(unsigned long arg);
++int xhci_cancel_cmd(struct xhci_hcd *xhci, struct xhci_command *command,
++              union xhci_trb *cmd_trb);
+ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
+               unsigned int ep_index, unsigned int stream_id);
diff --git a/queue-3.0/xhci-add-cmd_ring_state.patch b/queue-3.0/xhci-add-cmd_ring_state.patch
new file mode 100644 (file)
index 0000000..e13cec4
--- /dev/null
@@ -0,0 +1,79 @@
+From c181bc5b5d5c79b71203cd10cef97f802fb6f9c1 Mon Sep 17 00:00:00 2001
+From: Elric Fu <elricfu1@gmail.com>
+Date: Wed, 27 Jun 2012 16:30:57 +0800
+Subject: xHCI: add cmd_ring_state
+
+From: Elric Fu <elricfu1@gmail.com>
+
+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 |    3 +++
+ drivers/usb/host/xhci.c      |    5 ++++-
+ drivers/usb/host/xhci.h      |    4 ++++
+ 3 files changed, 11 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -311,6 +311,9 @@ static int room_on_ring(struct xhci_hcd
+ /* 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 */
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -104,8 +104,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;
++              xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
++      }
+       return ret;
+ }
+@@ -390,6 +392,7 @@ static int xhci_run_finished(struct 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);
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1252,6 +1252,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;
diff --git a/queue-3.0/xhci-cancel-command-after-command-timeout.patch b/queue-3.0/xhci-cancel-command-after-command-timeout.patch
new file mode 100644 (file)
index 0000000..e024bc7
--- /dev/null
@@ -0,0 +1,142 @@
+From 6e4468b9a0793dfb53eb80d9fe52c739b13b27fd Mon Sep 17 00:00:00 2001
+From: Elric Fu <elricfu1@gmail.com>
+Date: Wed, 27 Jun 2012 16:31:52 +0800
+Subject: xHCI: cancel command after command timeout
+
+From: Elric Fu <elricfu1@gmail.com>
+
+commit 6e4468b9a0793dfb53eb80d9fe52c739b13b27fd upstream.
+
+The patch is used to cancel command when the command isn't
+acknowledged and a timeout occurs.
+
+This patch should be backported to kernels as old as 3.0, that contain
+the commit 7ed603ecf8b68ab81f4c83097d3063d43ec73bb8 "xhci: Add an
+assertion to check for virt_dev=0 bug." That commit papers over a NULL
+pointer dereference, and this patch fixes the underlying issue that
+caused the NULL pointer dereference.
+
+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.c |   26 +++++++++++++++++++-------
+ drivers/usb/host/xhci.h |    3 +++
+ 2 files changed, 22 insertions(+), 7 deletions(-)
+
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -1778,6 +1778,7 @@ static int xhci_configure_endpoint(struc
+       struct completion *cmd_completion;
+       u32 *cmd_status;
+       struct xhci_virt_device *virt_dev;
++      union xhci_trb *cmd_trb;
+       spin_lock_irqsave(&xhci->lock, flags);
+       virt_dev = xhci->devs[udev->slot_id];
+@@ -1820,6 +1821,7 @@ static int xhci_configure_endpoint(struc
+       }
+       init_completion(cmd_completion);
++      cmd_trb = xhci->cmd_ring->dequeue;
+       if (!ctx_change)
+               ret = xhci_queue_configure_endpoint(xhci, in_ctx->dma,
+                               udev->slot_id, must_succeed);
+@@ -1841,14 +1843,17 @@ static int xhci_configure_endpoint(struc
+       /* Wait for the configure endpoint command to complete */
+       timeleft = wait_for_completion_interruptible_timeout(
+                       cmd_completion,
+-                      USB_CTRL_SET_TIMEOUT);
++                      XHCI_CMD_DEFAULT_TIMEOUT);
+       if (timeleft <= 0) {
+               xhci_warn(xhci, "%s while waiting for %s command\n",
+                               timeleft == 0 ? "Timeout" : "Signal",
+                               ctx_change == 0 ?
+                                       "configure endpoint" :
+                                       "evaluate context");
+-              /* FIXME cancel the configure endpoint command */
++              /* cancel the configure endpoint command */
++              ret = xhci_cancel_cmd(xhci, command, cmd_trb);
++              if (ret < 0)
++                      return ret;
+               return -ETIME;
+       }
+@@ -2781,8 +2786,10 @@ int xhci_alloc_dev(struct usb_hcd *hcd,
+       unsigned long flags;
+       int timeleft;
+       int ret;
++      union xhci_trb *cmd_trb;
+       spin_lock_irqsave(&xhci->lock, flags);
++      cmd_trb = xhci->cmd_ring->dequeue;
+       ret = xhci_queue_slot_control(xhci, TRB_ENABLE_SLOT, 0);
+       if (ret) {
+               spin_unlock_irqrestore(&xhci->lock, flags);
+@@ -2794,12 +2801,12 @@ int xhci_alloc_dev(struct usb_hcd *hcd,
+       /* XXX: how much time for xHC slot assignment? */
+       timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev,
+-                      USB_CTRL_SET_TIMEOUT);
++                      XHCI_CMD_DEFAULT_TIMEOUT);
+       if (timeleft <= 0) {
+               xhci_warn(xhci, "%s while waiting for a slot\n",
+                               timeleft == 0 ? "Timeout" : "Signal");
+-              /* FIXME cancel the enable slot request */
+-              return 0;
++              /* cancel the enable slot request */
++              return xhci_cancel_cmd(xhci, NULL, cmd_trb);
+       }
+       if (!xhci->slot_id) {
+@@ -2860,6 +2867,7 @@ int xhci_address_device(struct usb_hcd *
+       struct xhci_slot_ctx *slot_ctx;
+       struct xhci_input_control_ctx *ctrl_ctx;
+       u64 temp_64;
++      union xhci_trb *cmd_trb;
+       if (!udev->slot_id) {
+               xhci_dbg(xhci, "Bad Slot ID %d\n", udev->slot_id);
+@@ -2898,6 +2906,7 @@ int xhci_address_device(struct usb_hcd *
+       xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2);
+       spin_lock_irqsave(&xhci->lock, flags);
++      cmd_trb = xhci->cmd_ring->dequeue;
+       ret = xhci_queue_address_device(xhci, virt_dev->in_ctx->dma,
+                                       udev->slot_id);
+       if (ret) {
+@@ -2910,7 +2919,7 @@ int xhci_address_device(struct usb_hcd *
+       /* ctrl tx can take up to 5 sec; XXX: need more time for xHC? */
+       timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev,
+-                      USB_CTRL_SET_TIMEOUT);
++                      XHCI_CMD_DEFAULT_TIMEOUT);
+       /* FIXME: From section 4.3.4: "Software shall be responsible for timing
+        * the SetAddress() "recovery interval" required by USB and aborting the
+        * command on a timeout.
+@@ -2918,7 +2927,10 @@ int xhci_address_device(struct usb_hcd *
+       if (timeleft <= 0) {
+               xhci_warn(xhci, "%s while waiting for a slot\n",
+                               timeleft == 0 ? "Timeout" : "Signal");
+-              /* FIXME cancel the address device command */
++              /* cancel the address device command */
++              ret = xhci_cancel_cmd(xhci, NULL, cmd_trb);
++              if (ret < 0)
++                      return ret;
+               return -ETIME;
+       }
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1111,6 +1111,9 @@ struct xhci_td {
+       union xhci_trb          *last_trb;
+ };
++/* xHCI command default timeout value */
++#define XHCI_CMD_DEFAULT_TIMEOUT       (5 * HZ)
++
+ /* command descriptor */
+ struct xhci_cd {
+       struct list_head        cancel_cmd_list;
diff --git a/queue-3.0/xhci-handle-command-after-aborting-the-command-ring.patch b/queue-3.0/xhci-handle-command-after-aborting-the-command-ring.patch
new file mode 100644 (file)
index 0000000..2001756
--- /dev/null
@@ -0,0 +1,255 @@
+From b63f4053cc8aa22a98e3f9a97845afe6c15d0a0d Mon Sep 17 00:00:00 2001
+From: Elric Fu <elricfu1@gmail.com>
+Date: Wed, 27 Jun 2012 16:55:43 +0800
+Subject: xHCI: handle command after aborting the command ring
+
+From: Elric Fu <elricfu1@gmail.com>
+
+commit b63f4053cc8aa22a98e3f9a97845afe6c15d0a0d upstream.
+
+According to xHCI spec section 4.6.1.1 and section 4.6.1.2,
+after aborting a command on the command ring, xHC will
+generate a command completion event with its completion
+code set to Command Ring Stopped at least. If a command is
+currently executing at the time of aborting a command, xHC
+also generate a command completion event with its completion
+code set to Command Abort. When the command ring is stopped,
+software may remove, add, or rearrage Command Descriptors.
+
+To cancel a command, software will initialize a command
+descriptor for the cancel command, and add it into a
+cancel_cmd_list of xhci. When the command ring is stopped,
+software will find the command trbs described by command
+descriptors in cancel_cmd_list and modify it to No Op
+command. If software can't find the matched trbs, we can
+think it had been finished.
+
+This patch should be backported to kernels as old as 3.0, that contain
+the commit 7ed603ecf8b68ab81f4c83097d3063d43ec73bb8 "xhci: Add an
+assertion to check for virt_dev=0 bug." That commit papers over a NULL
+pointer dereference, and this patch fixes the underlying issue that
+caused the NULL pointer dereference.
+
+Note from Sarah: The TRB_TYPE_LINK_LE32 macro is not in the 3.0 stable
+kernel, so I added it to this patch.
+
+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 |  171 +++++++++++++++++++++++++++++++++++++++++--
+ drivers/usb/host/xhci.h      |    3 
+ 2 files changed, 168 insertions(+), 6 deletions(-)
+
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -1157,6 +1157,20 @@ static void handle_reset_ep_completion(s
+       }
+ }
++/* Complete the command and detele it from the devcie's command queue.
++ */
++static void xhci_complete_cmd_in_cmd_wait_list(struct xhci_hcd *xhci,
++              struct xhci_command *command, u32 status)
++{
++      command->status = status;
++      list_del(&command->cmd_list);
++      if (command->completion)
++              complete(command->completion);
++      else
++              xhci_free_command(xhci, command);
++}
++
++
+ /* Check to see if a command in the device's command queue matches this one.
+  * Signal the completion or free the command, and return 1.  Return 0 if the
+  * completed command isn't at the head of the command list.
+@@ -1175,15 +1189,144 @@ static int handle_cmd_in_cmd_wait_list(s
+       if (xhci->cmd_ring->dequeue != command->command_trb)
+               return 0;
+-      command->status = GET_COMP_CODE(le32_to_cpu(event->status));
+-      list_del(&command->cmd_list);
+-      if (command->completion)
+-              complete(command->completion);
+-      else
+-              xhci_free_command(xhci, command);
++      xhci_complete_cmd_in_cmd_wait_list(xhci, command,
++                      GET_COMP_CODE(le32_to_cpu(event->status)));
+       return 1;
+ }
++/*
++ * Finding the command trb need to be cancelled and modifying it to
++ * NO OP command. And if the command is in device's command wait
++ * list, finishing and freeing it.
++ *
++ * If we can't find the command trb, we think it had already been
++ * executed.
++ */
++static void xhci_cmd_to_noop(struct xhci_hcd *xhci, struct xhci_cd *cur_cd)
++{
++      struct xhci_segment *cur_seg;
++      union xhci_trb *cmd_trb;
++      u32 cycle_state;
++
++      if (xhci->cmd_ring->dequeue == xhci->cmd_ring->enqueue)
++              return;
++
++      /* find the current segment of command ring */
++      cur_seg = find_trb_seg(xhci->cmd_ring->first_seg,
++                      xhci->cmd_ring->dequeue, &cycle_state);
++
++      /* find the command trb matched by cd from command ring */
++      for (cmd_trb = xhci->cmd_ring->dequeue;
++                      cmd_trb != xhci->cmd_ring->enqueue;
++                      next_trb(xhci, xhci->cmd_ring, &cur_seg, &cmd_trb)) {
++              /* If the trb is link trb, continue */
++              if (TRB_TYPE_LINK_LE32(cmd_trb->generic.field[3]))
++                      continue;
++
++              if (cur_cd->cmd_trb == cmd_trb) {
++
++                      /* If the command in device's command list, we should
++                       * finish it and free the command structure.
++                       */
++                      if (cur_cd->command)
++                              xhci_complete_cmd_in_cmd_wait_list(xhci,
++                                      cur_cd->command, COMP_CMD_STOP);
++
++                      /* get cycle state from the origin command trb */
++                      cycle_state = le32_to_cpu(cmd_trb->generic.field[3])
++                              & TRB_CYCLE;
++
++                      /* modify the command trb to NO OP command */
++                      cmd_trb->generic.field[0] = 0;
++                      cmd_trb->generic.field[1] = 0;
++                      cmd_trb->generic.field[2] = 0;
++                      cmd_trb->generic.field[3] = cpu_to_le32(
++                                      TRB_TYPE(TRB_CMD_NOOP) | cycle_state);
++                      break;
++              }
++      }
++}
++
++static void xhci_cancel_cmd_in_cd_list(struct xhci_hcd *xhci)
++{
++      struct xhci_cd *cur_cd, *next_cd;
++
++      if (list_empty(&xhci->cancel_cmd_list))
++              return;
++
++      list_for_each_entry_safe(cur_cd, next_cd,
++                      &xhci->cancel_cmd_list, cancel_cmd_list) {
++              xhci_cmd_to_noop(xhci, cur_cd);
++              list_del(&cur_cd->cancel_cmd_list);
++              kfree(cur_cd);
++      }
++}
++
++/*
++ * traversing the cancel_cmd_list. If the command descriptor according
++ * to cmd_trb is found, the function free it and return 1, otherwise
++ * return 0.
++ */
++static int xhci_search_cmd_trb_in_cd_list(struct xhci_hcd *xhci,
++              union xhci_trb *cmd_trb)
++{
++      struct xhci_cd *cur_cd, *next_cd;
++
++      if (list_empty(&xhci->cancel_cmd_list))
++              return 0;
++
++      list_for_each_entry_safe(cur_cd, next_cd,
++                      &xhci->cancel_cmd_list, cancel_cmd_list) {
++              if (cur_cd->cmd_trb == cmd_trb) {
++                      if (cur_cd->command)
++                              xhci_complete_cmd_in_cmd_wait_list(xhci,
++                                      cur_cd->command, COMP_CMD_STOP);
++                      list_del(&cur_cd->cancel_cmd_list);
++                      kfree(cur_cd);
++                      return 1;
++              }
++      }
++
++      return 0;
++}
++
++/*
++ * If the cmd_trb_comp_code is COMP_CMD_ABORT, we just check whether the
++ * trb pointed by the command ring dequeue pointer is the trb we want to
++ * cancel or not. And if the cmd_trb_comp_code is COMP_CMD_STOP, we will
++ * traverse the cancel_cmd_list to trun the all of the commands according
++ * to command descriptor to NO-OP trb.
++ */
++static int handle_stopped_cmd_ring(struct xhci_hcd *xhci,
++              int cmd_trb_comp_code)
++{
++      int cur_trb_is_good = 0;
++
++      /* Searching the cmd trb pointed by the command ring dequeue
++       * pointer in command descriptor list. If it is found, free it.
++       */
++      cur_trb_is_good = xhci_search_cmd_trb_in_cd_list(xhci,
++                      xhci->cmd_ring->dequeue);
++
++      if (cmd_trb_comp_code == COMP_CMD_ABORT)
++              xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
++      else if (cmd_trb_comp_code == COMP_CMD_STOP) {
++              /* traversing the cancel_cmd_list and canceling
++               * the command according to command descriptor
++               */
++              xhci_cancel_cmd_in_cd_list(xhci);
++
++              xhci->cmd_ring_state = CMD_RING_STATE_RUNNING;
++              /*
++               * ring command ring doorbell again to restart the
++               * command ring
++               */
++              if (xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue)
++                      xhci_ring_cmd_db(xhci);
++      }
++      return cur_trb_is_good;
++}
++
+ static void handle_cmd_completion(struct xhci_hcd *xhci,
+               struct xhci_event_cmd *event)
+ {
+@@ -1209,6 +1352,22 @@ static void handle_cmd_completion(struct
+               xhci->error_bitmask |= 1 << 5;
+               return;
+       }
++
++      if ((GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_ABORT) ||
++              (GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_STOP)) {
++              /* If the return value is 0, we think the trb pointed by
++               * command ring dequeue pointer is a good trb. The good
++               * trb means we don't want to cancel the trb, but it have
++               * been stopped by host. So we should handle it normally.
++               * Otherwise, driver should invoke inc_deq() and return.
++               */
++              if (handle_stopped_cmd_ring(xhci,
++                              GET_COMP_CODE(le32_to_cpu(event->status)))) {
++                      inc_deq(xhci, xhci->cmd_ring, false);
++                      return;
++              }
++      }
++
+       switch (le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3])
+               & TRB_TYPE_BITMASK) {
+       case TRB_TYPE(TRB_ENABLE_SLOT):
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1070,6 +1070,9 @@ union xhci_trb {
+ #define TRB_MFINDEX_WRAP      39
+ /* TRB IDs 40-47 reserved, 48-63 is vendor-defined */
++#define TRB_TYPE_LINK_LE32(x)   (((x) & cpu_to_le32(TRB_TYPE_BITMASK)) == \
++              cpu_to_le32(TRB_TYPE(TRB_LINK)))
++
+ /* Nec vendor-specific command completion event. */
+ #define       TRB_NEC_CMD_COMP        48
+ /* Get NEC firmware revision. */