Commit d1dc908a authored by Sarah Sharp's avatar Sarah Sharp Committed by Greg Kroah-Hartman

USB: xHCI: Fix another bug in link TRB activation change.

Commit 6c12db90 also seems to have
introduced a bug that is triggered when the command ring is about to wrap.
The inc_enq() function will not have moved the enqueue pointer past the
link TRB.  It is supposed to be moved past the link TRB in prepare_ring(),
which should be called before a TD is enqueued.  However, the
queue_command() function never calls the prepare_ring() function because
prepare_ring() is only supposed to be used for endpoint rings.  That means
the enqueue pointer will not be moved past the link TRB, and will get
overwritten.

The fix is to make queue_command() call prepare_ring() with a fake
endpoint status (set to running).  Then the enqueue pointer will get moved
past the link TRB.
Signed-off-by: default avatarSarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 7595931c
...@@ -2380,16 +2380,19 @@ static int queue_command(struct xhci_hcd *xhci, u32 field1, u32 field2, ...@@ -2380,16 +2380,19 @@ static int queue_command(struct xhci_hcd *xhci, u32 field1, u32 field2,
u32 field3, u32 field4, bool command_must_succeed) u32 field3, u32 field4, bool command_must_succeed)
{ {
int reserved_trbs = xhci->cmd_ring_reserved_trbs; int reserved_trbs = xhci->cmd_ring_reserved_trbs;
int ret;
if (!command_must_succeed) if (!command_must_succeed)
reserved_trbs++; reserved_trbs++;
if (!room_on_ring(xhci, xhci->cmd_ring, reserved_trbs)) { ret = prepare_ring(xhci, xhci->cmd_ring, EP_STATE_RUNNING,
if (!in_interrupt()) reserved_trbs, GFP_ATOMIC);
if (ret < 0) {
xhci_err(xhci, "ERR: No room for command on command ring\n"); xhci_err(xhci, "ERR: No room for command on command ring\n");
if (command_must_succeed) if (command_must_succeed)
xhci_err(xhci, "ERR: Reserved TRB counting for " xhci_err(xhci, "ERR: Reserved TRB counting for "
"unfailable commands failed.\n"); "unfailable commands failed.\n");
return -ENOMEM; return ret;
} }
queue_trb(xhci, xhci->cmd_ring, false, false, field1, field2, field3, queue_trb(xhci, xhci->cmd_ring, false, false, field1, field2, field3,
field4 | xhci->cmd_ring->cycle_state); field4 | xhci->cmd_ring->cycle_state);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment