diff options
author | Elric Fu <elricfu1@gmail.com> | 2012-06-27 04:31:12 -0400 |
---|---|---|
committer | Sarah Sharp <sarah.a.sharp@linux.intel.com> | 2012-09-13 18:49:28 -0400 |
commit | b92cc66c047ff7cf587b318fe377061a353c120f (patch) | |
tree | c4c7e2f695ed5c796b2b7fcb88ddaaa5480f1d59 /drivers/usb/host/xhci-mem.c | |
parent | c181bc5b5d5c79b71203cd10cef97f802fb6f9c1 (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.c | 7 |
1 files changed, 7 insertions, 0 deletions
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 77689bd64cac..487bc083dead 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) | |||
1772 | { | 1772 | { |
1773 | struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); | 1773 | struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); |
1774 | struct dev_info *dev_info, *next; | 1774 | struct dev_info *dev_info, *next; |
1775 | struct xhci_cd *cur_cd, *next_cd; | ||
1775 | unsigned long flags; | 1776 | unsigned long flags; |
1776 | int size; | 1777 | int size; |
1777 | int i, j, num_ports; | 1778 | int i, j, num_ports; |
@@ -1795,6 +1796,11 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) | |||
1795 | xhci_ring_free(xhci, xhci->cmd_ring); | 1796 | xhci_ring_free(xhci, xhci->cmd_ring); |
1796 | xhci->cmd_ring = NULL; | 1797 | xhci->cmd_ring = NULL; |
1797 | xhci_dbg(xhci, "Freed command ring\n"); | 1798 | xhci_dbg(xhci, "Freed command ring\n"); |
1799 | list_for_each_entry_safe(cur_cd, next_cd, | ||
1800 | &xhci->cancel_cmd_list, cancel_cmd_list) { | ||
1801 | list_del(&cur_cd->cancel_cmd_list); | ||
1802 | kfree(cur_cd); | ||
1803 | } | ||
1798 | 1804 | ||
1799 | for (i = 1; i < MAX_HC_SLOTS; ++i) | 1805 | for (i = 1; i < MAX_HC_SLOTS; ++i) |
1800 | xhci_free_virt_device(xhci, i); | 1806 | xhci_free_virt_device(xhci, i); |
@@ -2340,6 +2346,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) | |||
2340 | xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, flags); | 2346 | xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, flags); |
2341 | if (!xhci->cmd_ring) | 2347 | if (!xhci->cmd_ring) |
2342 | goto fail; | 2348 | goto fail; |
2349 | INIT_LIST_HEAD(&xhci->cancel_cmd_list); | ||
2343 | xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring); | 2350 | xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring); |
2344 | xhci_dbg(xhci, "First segment DMA is 0x%llx\n", | 2351 | xhci_dbg(xhci, "First segment DMA is 0x%llx\n", |
2345 | (unsigned long long)xhci->cmd_ring->first_seg->dma); | 2352 | (unsigned long long)xhci->cmd_ring->first_seg->dma); |