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 7ed603ecf8 "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
This commit is contained in:
Elric Fu 2012-06-27 16:31:12 +08:00 committed by Sarah Sharp
parent c181bc5b5d
commit b92cc66c04
4 changed files with 128 additions and 1 deletions

View File

@ -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 pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
struct dev_info *dev_info, *next; struct dev_info *dev_info, *next;
struct xhci_cd *cur_cd, *next_cd;
unsigned long flags; unsigned long flags;
int size; int size;
int i, j, num_ports; 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_ring_free(xhci, xhci->cmd_ring);
xhci->cmd_ring = NULL; xhci->cmd_ring = NULL;
xhci_dbg(xhci, "Freed command ring\n"); 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) for (i = 1; i < MAX_HC_SLOTS; ++i)
xhci_free_virt_device(xhci, 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); xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, flags);
if (!xhci->cmd_ring) if (!xhci->cmd_ring)
goto fail; goto fail;
INIT_LIST_HEAD(&xhci->cancel_cmd_list);
xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring); xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring);
xhci_dbg(xhci, "First segment DMA is 0x%llx\n", xhci_dbg(xhci, "First segment DMA is 0x%llx\n",
(unsigned long long)xhci->cmd_ring->first_seg->dma); (unsigned long long)xhci->cmd_ring->first_seg->dma);

View File

@ -289,6 +289,114 @@ void xhci_ring_cmd_db(struct xhci_hcd *xhci)
xhci_readl(xhci, &xhci->dba->doorbell[0]); 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, void xhci_ring_ep_doorbell(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int slot_id,
unsigned int ep_index, unsigned int ep_index,

View File

@ -51,7 +51,7 @@ MODULE_PARM_DESC(link_quirk, "Don't clear the chain bit on a link TRB");
* handshake done). There are two failure modes: "usec" have passed (major * handshake done). There are two failure modes: "usec" have passed (major
* hardware flakeout), or the register reads as all-ones (hardware removed). * 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 mask, u32 done, int usec)
{ {
u32 result; u32 result;

View File

@ -1256,6 +1256,13 @@ struct xhci_td {
union xhci_trb *last_trb; 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_dequeue_state {
struct xhci_segment *new_deq_seg; struct xhci_segment *new_deq_seg;
union xhci_trb *new_deq_ptr; union xhci_trb *new_deq_ptr;
@ -1425,6 +1432,7 @@ struct xhci_hcd {
#define CMD_RING_STATE_RUNNING (1 << 0) #define CMD_RING_STATE_RUNNING (1 << 0)
#define CMD_RING_STATE_ABORTED (1 << 1) #define CMD_RING_STATE_ABORTED (1 << 1)
#define CMD_RING_STATE_STOPPED (1 << 2) #define CMD_RING_STATE_STOPPED (1 << 2)
struct list_head cancel_cmd_list;
unsigned int cmd_ring_reserved_trbs; unsigned int cmd_ring_reserved_trbs;
struct xhci_ring *event_ring; struct xhci_ring *event_ring;
struct xhci_erst erst; struct xhci_erst erst;
@ -1702,6 +1710,8 @@ static inline void xhci_unregister_plat(void)
/* xHCI host controller glue */ /* xHCI host controller glue */
typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *); typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *);
int handshake(struct xhci_hcd *xhci, void __iomem *ptr,
u32 mask, u32 done, int usec);
void xhci_quiesce(struct xhci_hcd *xhci); void xhci_quiesce(struct xhci_hcd *xhci);
int xhci_halt(struct xhci_hcd *xhci); int xhci_halt(struct xhci_hcd *xhci);
int xhci_reset(struct xhci_hcd *xhci); int xhci_reset(struct xhci_hcd *xhci);
@ -1792,6 +1802,8 @@ void xhci_queue_config_ep_quirk(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int ep_index, unsigned int slot_id, unsigned int ep_index,
struct xhci_dequeue_state *deq_state); struct xhci_dequeue_state *deq_state);
void xhci_stop_endpoint_command_watchdog(unsigned long arg); 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, void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
unsigned int ep_index, unsigned int stream_id); unsigned int ep_index, unsigned int stream_id);