diff options
author | Sarah Sharp <sarah.a.sharp@linux.intel.com> | 2012-05-08 07:32:03 -0700 |
---|---|---|
committer | Sarah Sharp <sarah.a.sharp@linux.intel.com> | 2012-05-18 15:42:01 -0700 |
commit | dbc33303e457bc9d9179d628951e6b7c7a3f6056 (patch) | |
tree | 4c0c1daf3895f65a65e7714a5f0e3e3ea7e12f81 | |
parent | 4b2665418c81c87e7a46df690a443b3d5ac5b088 (diff) | |
download | linux-dbc33303e457bc9d9179d628951e6b7c7a3f6056.tar.gz linux-dbc33303e457bc9d9179d628951e6b7c7a3f6056.tar.bz2 linux-dbc33303e457bc9d9179d628951e6b7c7a3f6056.zip |
xhci: Reserve one command for USB3 LPM disable.
We want to do everything we can to ensure that USB 3.0 Link Power
Management (LPM) can be disabled when it is enabled. If LPM can't be
disabled, we can't suspend USB 3.0 devices, or reset them. To make sure
we can submit the command to disable LPM, allocate a command in the
xhci_hcd structure, and reserve one TRB on the command ring.
We only need one command per xHCI driver instance, because LPM is only
disabled or enabled while the USB core is holding the bandwidth_mutex
that is shared between the xHCI USB 2.0 and USB 3.0 roothubs. The
bandwidth_mutex will be held until the command completes, or times out.
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
-rw-r--r-- | drivers/usb/host/xhci-mem.c | 12 | ||||
-rw-r--r-- | drivers/usb/host/xhci.h | 2 |
2 files changed, 14 insertions, 0 deletions
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 497ed7723e44..ec4338eec826 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1815,6 +1815,8 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci->event_ring = NULL; xhci_dbg(xhci, "Freed event ring\n"); + if (xhci->lpm_command) + xhci_free_command(xhci, xhci->lpm_command); xhci->cmd_ring_reserved_trbs = 0; if (xhci->cmd_ring) xhci_ring_free(xhci, xhci->cmd_ring); @@ -2377,6 +2379,16 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring); xhci_dbg_cmd_ptrs(xhci); + xhci->lpm_command = xhci_alloc_command(xhci, true, true, flags); + if (!xhci->lpm_command) + goto fail; + + /* Reserve one command ring TRB for disabling LPM. + * Since the USB core grabs the shared usb_bus bandwidth mutex before + * disabling LPM, we only need to reserve one TRB for all devices. + */ + xhci->cmd_ring_reserved_trbs++; + val = xhci_readl(xhci, &xhci->cap_regs->db_off); val &= DBOFF_MASK; xhci_dbg(xhci, "// Doorbell array is located at offset 0x%x" diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 59248449b254..f5cb7417f231 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1426,6 +1426,8 @@ struct xhci_hcd { /* slot enabling and address device helpers */ struct completion addr_dev; int slot_id; + /* For USB 3.0 LPM enable/disable. */ + struct xhci_command *lpm_command; /* Internal mirror of the HW's dcbaa */ struct xhci_virt_device *devs[MAX_HC_SLOTS]; /* For keeping track of bandwidth domains per roothub. */ |