xhci: Fix race related to abort operation
authorOGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Tue, 3 Jan 2017 16:28:51 +0000 (18:28 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 3 Jan 2017 16:37:32 +0000 (17:37 +0100)
commit1c111b6c3844a142e03bcfc2fa17bfbdea08e9dc
treeb612579aa5707c9fc8c0a3082c0f132da1cc78eb
parentcb4d5ce588c5ff68e0fdd30370a0e6bc2c0a736b
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>
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.h