| From 7879a8a1911d4c1e37a8270363c1a5ddcc6e0df6 Mon Sep 17 00:00:00 2001 |
| From: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> |
| Date: Tue, 3 Jan 2017 18:28:51 +0200 |
| Subject: [PATCH 294/299] xhci: Fix race related to abort operation |
| |
| Current abort operation has race. |
| |
| xhci_handle_command_timeout() |
| xhci_abort_cmd_ring() |
| xhci_write_64(CMD_RING_ABORT) |
| xhci_handshake(5s) |
| do { |
| check CMD_RING_RUNNING |
| udelay(1) |
| ... |
| COMP_CMD_ABORT event |
| COMP_CMD_STOP event |
| xhci_handle_stopped_cmd_ring() |
| restart cmd_ring |
| CMD_RING_RUNNING become 1 again |
| } while () |
| return -ETIMEDOUT |
| xhci_write_64(CMD_RING_ABORT) |
| /* can abort random command */ |
| |
| To do abort operation correctly, we have to wait both of COMP_CMD_STOP |
| event and negation of CMD_RING_RUNNING. |
| |
| But like above, while timeout handler is waiting negation of |
| CMD_RING_RUNNING, event handler can restart cmd_ring. So timeout |
| handler never be notice negation of CMD_RING_RUNNING, and retry of |
| CMD_RING_ABORT can abort random command (BTW, I guess retry of |
| CMD_RING_ABORT was workaround of this race). |
| |
| To fix this race, this moves xhci_handle_stopped_cmd_ring() to |
| xhci_abort_cmd_ring(). And timeout handler waits COMP_CMD_STOP event. |
| |
| At this point, timeout handler is owner of cmd_ring, and safely |
| restart cmd_ring by using xhci_handle_stopped_cmd_ring(). |
| |
| [FWIW, as bonus, this way would be easily extend to add CMD_RING_PAUSE |
| operation] |
| |
| [locks edited as patch is rebased on other locking fixes -Mathias] |
| Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> |
| Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| (cherry picked from commit 1c111b6c3844a142e03bcfc2fa17bfbdea08e9dc) |
| Signed-off-by: Simon Horman <horms+renesas@verge.net.au> |
| --- |
| drivers/usb/host/xhci-ring.c | 1 - |
| 1 file changed, 1 deletion(-) |
| |
| --- a/drivers/usb/host/xhci-ring.c |
| +++ b/drivers/usb/host/xhci-ring.c |
| @@ -392,7 +392,6 @@ static int xhci_abort_cmd_ring(struct xh |
| } else { |
| xhci_handle_stopped_cmd_ring(xhci, xhci_next_queued_cmd(xhci)); |
| } |
| - |
| return 0; |
| } |
| |