aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/host/xhci-mem.c
diff options
context:
space:
mode:
authorElric Fu <elricfu1@gmail.com>2012-06-27 16:31:12 +0800
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2012-09-13 15:49:28 -0700
commitb92cc66c047ff7cf587b318fe377061a353c120f (patch)
treec4c7e2f695ed5c796b2b7fcb88ddaaa5480f1d59 /drivers/usb/host/xhci-mem.c
parentc181bc5b5d5c79b71203cd10cef97f802fb6f9c1 (diff)
xHCI: add aborting command ring function
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> Cc: stable@vger.kernel.org
Diffstat (limited to 'drivers/usb/host/xhci-mem.c')
-rw-r--r--drivers/usb/host/xhci-mem.c7
1 files changed, 7 insertions, 0 deletions
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 77689bd64ca..487bc083dea 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1772,6 +1772,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
{
struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
struct dev_info *dev_info, *next;
+ struct xhci_cd *cur_cd, *next_cd;
unsigned long flags;
int size;
int i, j, num_ports;
@@ -1795,6 +1796,11 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
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);
@@ -2340,6 +2346,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, 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);