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>
This commit is contained in:
parent
e1ec140f27
commit
5c2a380a5a
3 changed files with 8 additions and 22 deletions
|
@ -1846,9 +1846,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
||||||
xhci->event_ring = NULL;
|
xhci->event_ring = NULL;
|
||||||
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed event ring");
|
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)
|
if (xhci->cmd_ring)
|
||||||
xhci_ring_free(xhci, xhci->cmd_ring);
|
xhci_ring_free(xhci, xhci->cmd_ring);
|
||||||
xhci->cmd_ring = NULL;
|
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);
|
"// Setting command ring address to 0x%016llx", val_64);
|
||||||
xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
|
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.
|
/* Reserve one command ring TRB for disabling LPM.
|
||||||
* Since the USB core grabs the shared usb_bus bandwidth mutex before
|
* Since the USB core grabs the shared usb_bus bandwidth mutex before
|
||||||
* disabling LPM, we only need to reserve one TRB for all devices.
|
* disabling LPM, we only need to reserve one TRB for all devices.
|
||||||
|
|
|
@ -4344,6 +4344,10 @@ static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci,
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
command = xhci_alloc_command_with_ctx(xhci, true, GFP_KERNEL);
|
||||||
|
if (!command)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
spin_lock_irqsave(&xhci->lock, flags);
|
spin_lock_irqsave(&xhci->lock, flags);
|
||||||
|
|
||||||
virt_dev = xhci->devs[udev->slot_id];
|
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. */
|
/* 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);
|
ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx);
|
||||||
if (!ctrl_ctx) {
|
if (!ctrl_ctx) {
|
||||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||||
|
xhci_free_command(xhci, command);
|
||||||
xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
|
xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
|
||||||
__func__);
|
__func__);
|
||||||
return -ENOMEM;
|
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;
|
virt_dev->current_mel = max_exit_latency;
|
||||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xhci_free_command(xhci, command);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4510,18 +4517,8 @@ static int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
|
||||||
exit_latency = xhci_besl_encoding[hird];
|
exit_latency = xhci_besl_encoding[hird];
|
||||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
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,
|
ret = xhci_change_max_exit_latency(xhci, udev,
|
||||||
exit_latency);
|
exit_latency);
|
||||||
mutex_unlock(hcd->bandwidth_mutex);
|
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
spin_lock_irqsave(&xhci->lock, flags);
|
spin_lock_irqsave(&xhci->lock, flags);
|
||||||
|
@ -4549,9 +4546,7 @@ static int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
|
||||||
readl(pm_addr);
|
readl(pm_addr);
|
||||||
if (udev->usb2_hw_lpm_besl_capable) {
|
if (udev->usb2_hw_lpm_besl_capable) {
|
||||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||||
mutex_lock(hcd->bandwidth_mutex);
|
|
||||||
xhci_change_max_exit_latency(xhci, udev, 0);
|
xhci_change_max_exit_latency(xhci, udev, 0);
|
||||||
mutex_unlock(hcd->bandwidth_mutex);
|
|
||||||
readl_poll_timeout(ports[port_num]->addr, pm_val,
|
readl_poll_timeout(ports[port_num]->addr, pm_val,
|
||||||
(pm_val & PORT_PLS_MASK) == XDEV_U0,
|
(pm_val & PORT_PLS_MASK) == XDEV_U0,
|
||||||
100, 10000);
|
100, 10000);
|
||||||
|
|
|
@ -1812,8 +1812,6 @@ struct xhci_hcd {
|
||||||
/* slot enabling and address device helpers */
|
/* slot enabling and address device helpers */
|
||||||
/* these are not thread safe so use mutex */
|
/* these are not thread safe so use mutex */
|
||||||
struct mutex mutex;
|
struct mutex mutex;
|
||||||
/* For USB 3.0 LPM enable/disable. */
|
|
||||||
struct xhci_command *lpm_command;
|
|
||||||
/* Internal mirror of the HW's dcbaa */
|
/* Internal mirror of the HW's dcbaa */
|
||||||
struct xhci_virt_device *devs[MAX_HC_SLOTS];
|
struct xhci_virt_device *devs[MAX_HC_SLOTS];
|
||||||
/* For keeping track of bandwidth domains per roothub. */
|
/* For keeping track of bandwidth domains per roothub. */
|
||||||
|
|
Loading…
Add table
Reference in a new issue