xhci: Allocate separate command structures for each LPM command
authorMathias Nyman <mathias.nyman@linux.intel.com>
Wed, 16 Feb 2022 09:51:50 +0000 (11:51 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 17 Feb 2022 15:20:45 +0000 (16:20 +0100)
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>
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h

index 0e31206..7a2dce7 100644 (file)
@@ -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.
index 17a561a..2a58677 100644 (file)
@@ -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);
index 5a75fe5..8a0026e 100644 (file)
@@ -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. */