diff options
author | Sarah Sharp <sarah.a.sharp@linux.intel.com> | 2009-12-09 15:59:13 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-03-02 14:53:12 -0800 |
commit | 2a8f82c4ceaffcfd64531dbdee1d1bc227387882 (patch) | |
tree | b70b68e35d8a9e7264263848ce48a9863b387c55 /drivers/usb/host/xhci-ring.c | |
parent | 6219c047d3fe18dee4916d6898fc94f5a7ffd156 (diff) |
USB: xhci: Notify the xHC when a device is reset.
When a USB device is reset, the xHCI hardware must know, in order to match
the device state and disable all endpoints except control endpoint 0.
Issue a Reset Device command after a USB device is successfully reset.
Wait on the command to finish, and then cache or free the disabled
endpoint rings.
There are four different USB device states that the xHCI hardware tracks:
- disabled/enabled - device connection has just been detected,
- default - the device has been reset and has an address of 0,
- addressed - the device has a non-zero address but no configuration has
been set,
- configured - a set configuration succeeded.
The USB core may issue a port reset when a device is in any state, but the
Reset Device command will fail for a 0.96 xHC if the device is not in the
addressed or configured state. Don't consider this failure as an error,
but don't free any endpoint rings if this command fails.
A storage driver may request that the USB device be reset during error
handling, so use GPF_NOIO instead of GPF_KERNEL while allocating memory
for the Reset Device command.
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/xhci-ring.c')
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index f43e073dee9..6ba841bca4a 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -953,6 +953,17 @@ bandwidth_change: case TRB_TYPE(TRB_RESET_EP): handle_reset_ep_completion(xhci, event, xhci->cmd_ring->dequeue); break; + case TRB_TYPE(TRB_RESET_DEV): + xhci_dbg(xhci, "Completed reset device command.\n"); + slot_id = TRB_TO_SLOT_ID( + xhci->cmd_ring->dequeue->generic.field[3]); + virt_dev = xhci->devs[slot_id]; + if (virt_dev) + handle_cmd_in_cmd_wait_list(xhci, virt_dev, event); + else + xhci_warn(xhci, "Reset device command completion " + "for disabled slot %u\n", slot_id); + break; default: /* Skip over unknown commands on the event ring */ xhci->error_bitmask |= 1 << 6; @@ -2189,6 +2200,14 @@ int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, false); } +/* Queue a reset device command TRB */ +int xhci_queue_reset_device(struct xhci_hcd *xhci, u32 slot_id) +{ + return queue_command(xhci, 0, 0, 0, + TRB_TYPE(TRB_RESET_DEV) | SLOT_ID_FOR_TRB(slot_id), + false); +} + /* Queue a configure endpoint command TRB */ int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, u32 slot_id, bool command_must_succeed) |