diff options
author | Mathias Nyman <mathias.nyman@linux.intel.com> | 2022-02-16 11:51:50 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2022-02-17 16:20:45 +0100 |
commit | 5c2a380a5aa8c15985359904b6d47466528d2993 (patch) | |
tree | f156ab04f51cd44f6090e9a724fbec8d14e0b02d /drivers/usb/host | |
parent | e1ec140f273e1e30cea7e6d5f50934d877232121 (diff) | |
download | linux-stable-5c2a380a5aa8c15985359904b6d47466528d2993.tar.gz linux-stable-5c2a380a5aa8c15985359904b6d47466528d2993.tar.bz2 linux-stable-5c2a380a5aa8c15985359904b6d47466528d2993.zip |
xhci: Allocate separate command structures for each LPM command
Every lpm commmand, both for USB 2 and USB 3 devies used the same
xhci->lpm_command structure to change max exit latency.
xhci->lpm_command is only protected by a hcd->bandwidth mutex, which is
not enoungh as USB 2 and USB 3 devices are behind separate HCDs.
Simplify code and avoid unnecessary locking risks by allocating
separate command structures for each lpm command, just like with
all other commands.
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20220216095153.1303105-7-mathias.nyman@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/xhci-mem.c | 7 | ||||
-rw-r--r-- | drivers/usb/host/xhci.c | 21 | ||||
-rw-r--r-- | drivers/usb/host/xhci.h | 2 |
3 files changed, 8 insertions, 22 deletions
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 0e312066c5c6..7a2dce730e9a 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1846,9 +1846,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci->event_ring = NULL; xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed event ring"); - if (xhci->lpm_command) - xhci_free_command(xhci, xhci->lpm_command); - xhci->lpm_command = NULL; if (xhci->cmd_ring) xhci_ring_free(xhci, xhci->cmd_ring); xhci->cmd_ring = NULL; @@ -2488,10 +2485,6 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) "// Setting command ring address to 0x%016llx", val_64); xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring); - xhci->lpm_command = xhci_alloc_command_with_ctx(xhci, 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. diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 17a561abfab7..2a58677d9b7a 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -4344,6 +4344,10 @@ static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci, unsigned long flags; int ret; + command = xhci_alloc_command_with_ctx(xhci, true, GFP_KERNEL); + if (!command) + return -ENOMEM; + spin_lock_irqsave(&xhci->lock, flags); virt_dev = xhci->devs[udev->slot_id]; @@ -4360,10 +4364,10 @@ static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci, } /* Attempt to issue an Evaluate Context command to change the MEL. */ - command = xhci->lpm_command; ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx); if (!ctrl_ctx) { spin_unlock_irqrestore(&xhci->lock, flags); + xhci_free_command(xhci, command); xhci_warn(xhci, "%s: Could not get input context, bad type.\n", __func__); return -ENOMEM; @@ -4390,6 +4394,9 @@ static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci, virt_dev->current_mel = max_exit_latency; spin_unlock_irqrestore(&xhci->lock, flags); } + + xhci_free_command(xhci, command); + return ret; } @@ -4510,18 +4517,8 @@ static int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, exit_latency = xhci_besl_encoding[hird]; spin_unlock_irqrestore(&xhci->lock, flags); - /* USB 3.0 code dedicate one xhci->lpm_command->in_ctx - * input context for link powermanagement evaluate - * context commands. It is protected by hcd->bandwidth - * mutex and is shared by all devices. We need to set - * the max ext latency in USB 2 BESL LPM as well, so - * use the same mutex and xhci_change_max_exit_latency() - */ - mutex_lock(hcd->bandwidth_mutex); ret = xhci_change_max_exit_latency(xhci, udev, exit_latency); - mutex_unlock(hcd->bandwidth_mutex); - if (ret < 0) return ret; spin_lock_irqsave(&xhci->lock, flags); @@ -4549,9 +4546,7 @@ static int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, readl(pm_addr); if (udev->usb2_hw_lpm_besl_capable) { spin_unlock_irqrestore(&xhci->lock, flags); - mutex_lock(hcd->bandwidth_mutex); xhci_change_max_exit_latency(xhci, udev, 0); - mutex_unlock(hcd->bandwidth_mutex); readl_poll_timeout(ports[port_num]->addr, pm_val, (pm_val & PORT_PLS_MASK) == XDEV_U0, 100, 10000); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 5a75fe563123..8a0026ee9524 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1812,8 +1812,6 @@ struct xhci_hcd { /* slot enabling and address device helpers */ /* these are not thread safe so use mutex */ struct mutex mutex; - /* 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. */ |