]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 27 Jun 2022 08:23:44 +0000 (10:23 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 27 Jun 2022 08:23:44 +0000 (10:23 +0200)
added patches:
usb-gadget-fix-double-free-bug-in-raw_gadget-driver.patch
usb-gadget-fix-non-unique-driver-names-in-raw-gadget-driver.patch
xhci-pci-allow-host-runtime-pm-as-default-for-intel-meteor-lake-xhci.patch
xhci-pci-allow-host-runtime-pm-as-default-for-intel-raptor-lake-xhci.patch
xhci-turn-off-port-power-in-shutdown.patch

queue-5.10/series
queue-5.10/usb-gadget-fix-double-free-bug-in-raw_gadget-driver.patch [new file with mode: 0644]
queue-5.10/usb-gadget-fix-non-unique-driver-names-in-raw-gadget-driver.patch [new file with mode: 0644]
queue-5.10/xhci-pci-allow-host-runtime-pm-as-default-for-intel-meteor-lake-xhci.patch [new file with mode: 0644]
queue-5.10/xhci-pci-allow-host-runtime-pm-as-default-for-intel-raptor-lake-xhci.patch [new file with mode: 0644]
queue-5.10/xhci-turn-off-port-power-in-shutdown.patch [new file with mode: 0644]

index ea81f660d4b4b93ec2d4ed2c0bed26bbe9fe740b..bd0232c464c7658e603ef3ca692dd6a5f3152b7d 100644 (file)
@@ -63,3 +63,8 @@ s390-cpumf-handle-events-cycles-and-instructions-ide.patch
 iio-mma8452-fix-probe-fail-when-device-tree-compatib.patch
 iio-adc-vf610-fix-conversion-mode-sysfs-node-name.patch
 usb-typec-wcove-drop-wrong-dependency-to-intel_soc_p.patch
+xhci-turn-off-port-power-in-shutdown.patch
+xhci-pci-allow-host-runtime-pm-as-default-for-intel-raptor-lake-xhci.patch
+xhci-pci-allow-host-runtime-pm-as-default-for-intel-meteor-lake-xhci.patch
+usb-gadget-fix-non-unique-driver-names-in-raw-gadget-driver.patch
+usb-gadget-fix-double-free-bug-in-raw_gadget-driver.patch
diff --git a/queue-5.10/usb-gadget-fix-double-free-bug-in-raw_gadget-driver.patch b/queue-5.10/usb-gadget-fix-double-free-bug-in-raw_gadget-driver.patch
new file mode 100644 (file)
index 0000000..0e14b5f
--- /dev/null
@@ -0,0 +1,86 @@
+From 90bc2af24638659da56397ff835f3c95a948f991 Mon Sep 17 00:00:00 2001
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Wed, 22 Jun 2022 10:46:31 -0400
+Subject: USB: gadget: Fix double-free bug in raw_gadget driver
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+commit 90bc2af24638659da56397ff835f3c95a948f991 upstream.
+
+Re-reading a recently merged fix to the raw_gadget driver showed that
+it inadvertently introduced a double-free bug in a failure pathway.
+If raw_ioctl_init() encounters an error after the driver ID number has
+been allocated, it deallocates the ID number before returning.  But
+when dev_free() runs later on, it will then try to deallocate the ID
+number a second time.
+
+Closely related to this issue is another error in the recent fix: The
+ID number is stored in the raw_dev structure before the code checks to
+see whether the structure has already been initialized, in which case
+the new ID number would overwrite the earlier value.
+
+The solution to both bugs is to keep the new ID number in a local
+variable, and store it in the raw_dev structure only after the check
+for prior initialization.  No errors can occur after that point, so
+the double-free will never happen.
+
+Fixes: f2d8c2606825 ("usb: gadget: Fix non-unique driver names in raw-gadget driver")
+CC: Andrey Konovalov <andreyknvl@gmail.com>
+CC: <stable@vger.kernel.org>
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Link: https://lore.kernel.org/r/YrMrRw5AyIZghN0v@rowland.harvard.edu
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/legacy/raw_gadget.c |   13 +++++++------
+ 1 file changed, 7 insertions(+), 6 deletions(-)
+
+--- a/drivers/usb/gadget/legacy/raw_gadget.c
++++ b/drivers/usb/gadget/legacy/raw_gadget.c
+@@ -429,6 +429,7 @@ out_put:
+ static int raw_ioctl_init(struct raw_dev *dev, unsigned long value)
+ {
+       int ret = 0;
++      int driver_id_number;
+       struct usb_raw_init arg;
+       char *udc_driver_name;
+       char *udc_device_name;
+@@ -451,10 +452,9 @@ static int raw_ioctl_init(struct raw_dev
+               return -EINVAL;
+       }
+-      ret = ida_alloc(&driver_id_numbers, GFP_KERNEL);
+-      if (ret < 0)
+-              return ret;
+-      dev->driver_id_number = ret;
++      driver_id_number = ida_alloc(&driver_id_numbers, GFP_KERNEL);
++      if (driver_id_number < 0)
++              return driver_id_number;
+       driver_driver_name = kmalloc(DRIVER_DRIVER_NAME_LENGTH_MAX, GFP_KERNEL);
+       if (!driver_driver_name) {
+@@ -462,7 +462,7 @@ static int raw_ioctl_init(struct raw_dev
+               goto out_free_driver_id_number;
+       }
+       snprintf(driver_driver_name, DRIVER_DRIVER_NAME_LENGTH_MAX,
+-                              DRIVER_NAME ".%d", dev->driver_id_number);
++                              DRIVER_NAME ".%d", driver_id_number);
+       udc_driver_name = kmalloc(UDC_NAME_LENGTH_MAX, GFP_KERNEL);
+       if (!udc_driver_name) {
+@@ -506,6 +506,7 @@ static int raw_ioctl_init(struct raw_dev
+       dev->driver.driver.name = driver_driver_name;
+       dev->driver.udc_name = udc_device_name;
+       dev->driver.match_existing_only = 1;
++      dev->driver_id_number = driver_id_number;
+       dev->state = STATE_DEV_INITIALIZED;
+       spin_unlock_irqrestore(&dev->lock, flags);
+@@ -520,7 +521,7 @@ out_free_udc_driver_name:
+ out_free_driver_driver_name:
+       kfree(driver_driver_name);
+ out_free_driver_id_number:
+-      ida_free(&driver_id_numbers, dev->driver_id_number);
++      ida_free(&driver_id_numbers, driver_id_number);
+       return ret;
+ }
diff --git a/queue-5.10/usb-gadget-fix-non-unique-driver-names-in-raw-gadget-driver.patch b/queue-5.10/usb-gadget-fix-non-unique-driver-names-in-raw-gadget-driver.patch
new file mode 100644 (file)
index 0000000..56fa21b
--- /dev/null
@@ -0,0 +1,192 @@
+From f2d8c2606825317b77db1f9ba0fc26ef26160b30 Mon Sep 17 00:00:00 2001
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Mon, 13 Jun 2022 10:17:03 -0400
+Subject: usb: gadget: Fix non-unique driver names in raw-gadget driver
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+commit f2d8c2606825317b77db1f9ba0fc26ef26160b30 upstream.
+
+In a report for a separate bug (which has already been fixed by commit
+5f0b5f4d50fa "usb: gadget: fix race when gadget driver register via
+ioctl") in the raw-gadget driver, the syzbot console log included
+error messages caused by attempted registration of a new driver with
+the same name as an existing driver:
+
+> kobject_add_internal failed for raw-gadget with -EEXIST, don't try to register things with the same name in the same directory.
+> UDC core: USB Raw Gadget: driver registration failed: -17
+> misc raw-gadget: fail, usb_gadget_register_driver returned -17
+
+These errors arise because raw_gadget.c registers a separate UDC
+driver for each of the UDC instances it creates, but these drivers all
+have the same name: "raw-gadget".  Until recently this wasn't a
+problem, but when the "gadget" bus was added and UDC drivers were
+registered on this bus, it became possible for name conflicts to cause
+the registrations to fail.  The reason is simply that the bus code in
+the driver core uses the driver name as a sysfs directory name (e.g.,
+/sys/bus/gadget/drivers/raw-gadget/), and you can't create two
+directories with the same pathname.
+
+To fix this problem, the driver names used by raw-gadget are made
+distinct by appending a unique ID number: "raw-gadget.N", with a
+different value of N for each driver instance.  And to avoid the
+proliferation of error handling code in the raw_ioctl_init() routine,
+the error return paths are refactored into the common pattern (goto
+statements leading to cleanup code at the end of the routine).
+
+Link: https://lore.kernel.org/all/0000000000008c664105dffae2eb@google.com/
+Fixes: fc274c1e9973 "USB: gadget: Add a new bus for gadgets"
+CC: Andrey Konovalov <andreyknvl@gmail.com>
+CC: <stable@vger.kernel.org>
+Reported-and-tested-by: syzbot+02b16343704b3af1667e@syzkaller.appspotmail.com
+Reviewed-by: Andrey Konovalov <andreyknvl@gmail.com>
+Acked-by: Hillf Danton <hdanton@sina.com>
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Link: https://lore.kernel.org/r/YqdG32w+3h8c1s7z@rowland.harvard.edu
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/legacy/raw_gadget.c |   62 ++++++++++++++++++++++++---------
+ 1 file changed, 46 insertions(+), 16 deletions(-)
+
+--- a/drivers/usb/gadget/legacy/raw_gadget.c
++++ b/drivers/usb/gadget/legacy/raw_gadget.c
+@@ -10,6 +10,7 @@
+ #include <linux/ctype.h>
+ #include <linux/debugfs.h>
+ #include <linux/delay.h>
++#include <linux/idr.h>
+ #include <linux/kref.h>
+ #include <linux/miscdevice.h>
+ #include <linux/module.h>
+@@ -35,6 +36,9 @@ MODULE_LICENSE("GPL");
+ /*----------------------------------------------------------------------*/
++static DEFINE_IDA(driver_id_numbers);
++#define DRIVER_DRIVER_NAME_LENGTH_MAX 32
++
+ #define RAW_EVENT_QUEUE_SIZE  16
+ struct raw_event_queue {
+@@ -160,6 +164,9 @@ struct raw_dev {
+       /* Reference to misc device: */
+       struct device                   *dev;
++      /* Make driver names unique */
++      int                             driver_id_number;
++
+       /* Protected by lock: */
+       enum dev_state                  state;
+       bool                            gadget_registered;
+@@ -188,6 +195,7 @@ static struct raw_dev *dev_new(void)
+       spin_lock_init(&dev->lock);
+       init_completion(&dev->ep0_done);
+       raw_event_queue_init(&dev->queue);
++      dev->driver_id_number = -1;
+       return dev;
+ }
+@@ -198,6 +206,9 @@ static void dev_free(struct kref *kref)
+       kfree(dev->udc_name);
+       kfree(dev->driver.udc_name);
++      kfree(dev->driver.driver.name);
++      if (dev->driver_id_number >= 0)
++              ida_free(&driver_id_numbers, dev->driver_id_number);
+       if (dev->req) {
+               if (dev->ep0_urb_queued)
+                       usb_ep_dequeue(dev->gadget->ep0, dev->req);
+@@ -421,6 +432,7 @@ static int raw_ioctl_init(struct raw_dev
+       struct usb_raw_init arg;
+       char *udc_driver_name;
+       char *udc_device_name;
++      char *driver_driver_name;
+       unsigned long flags;
+       if (copy_from_user(&arg, (void __user *)value, sizeof(arg)))
+@@ -439,36 +451,44 @@ static int raw_ioctl_init(struct raw_dev
+               return -EINVAL;
+       }
++      ret = ida_alloc(&driver_id_numbers, GFP_KERNEL);
++      if (ret < 0)
++              return ret;
++      dev->driver_id_number = ret;
++
++      driver_driver_name = kmalloc(DRIVER_DRIVER_NAME_LENGTH_MAX, GFP_KERNEL);
++      if (!driver_driver_name) {
++              ret = -ENOMEM;
++              goto out_free_driver_id_number;
++      }
++      snprintf(driver_driver_name, DRIVER_DRIVER_NAME_LENGTH_MAX,
++                              DRIVER_NAME ".%d", dev->driver_id_number);
++
+       udc_driver_name = kmalloc(UDC_NAME_LENGTH_MAX, GFP_KERNEL);
+-      if (!udc_driver_name)
+-              return -ENOMEM;
++      if (!udc_driver_name) {
++              ret = -ENOMEM;
++              goto out_free_driver_driver_name;
++      }
+       ret = strscpy(udc_driver_name, &arg.driver_name[0],
+                               UDC_NAME_LENGTH_MAX);
+-      if (ret < 0) {
+-              kfree(udc_driver_name);
+-              return ret;
+-      }
++      if (ret < 0)
++              goto out_free_udc_driver_name;
+       ret = 0;
+       udc_device_name = kmalloc(UDC_NAME_LENGTH_MAX, GFP_KERNEL);
+       if (!udc_device_name) {
+-              kfree(udc_driver_name);
+-              return -ENOMEM;
++              ret = -ENOMEM;
++              goto out_free_udc_driver_name;
+       }
+       ret = strscpy(udc_device_name, &arg.device_name[0],
+                               UDC_NAME_LENGTH_MAX);
+-      if (ret < 0) {
+-              kfree(udc_driver_name);
+-              kfree(udc_device_name);
+-              return ret;
+-      }
++      if (ret < 0)
++              goto out_free_udc_device_name;
+       ret = 0;
+       spin_lock_irqsave(&dev->lock, flags);
+       if (dev->state != STATE_DEV_OPENED) {
+               dev_dbg(dev->dev, "fail, device is not opened\n");
+-              kfree(udc_driver_name);
+-              kfree(udc_device_name);
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+@@ -483,14 +503,24 @@ static int raw_ioctl_init(struct raw_dev
+       dev->driver.suspend = gadget_suspend;
+       dev->driver.resume = gadget_resume;
+       dev->driver.reset = gadget_reset;
+-      dev->driver.driver.name = DRIVER_NAME;
++      dev->driver.driver.name = driver_driver_name;
+       dev->driver.udc_name = udc_device_name;
+       dev->driver.match_existing_only = 1;
+       dev->state = STATE_DEV_INITIALIZED;
++      spin_unlock_irqrestore(&dev->lock, flags);
++      return ret;
+ out_unlock:
+       spin_unlock_irqrestore(&dev->lock, flags);
++out_free_udc_device_name:
++      kfree(udc_device_name);
++out_free_udc_driver_name:
++      kfree(udc_driver_name);
++out_free_driver_driver_name:
++      kfree(driver_driver_name);
++out_free_driver_id_number:
++      ida_free(&driver_id_numbers, dev->driver_id_number);
+       return ret;
+ }
diff --git a/queue-5.10/xhci-pci-allow-host-runtime-pm-as-default-for-intel-meteor-lake-xhci.patch b/queue-5.10/xhci-pci-allow-host-runtime-pm-as-default-for-intel-meteor-lake-xhci.patch
new file mode 100644 (file)
index 0000000..2eb3958
--- /dev/null
@@ -0,0 +1,42 @@
+From 8ffdc53a60049f3930afe161dc51c67959c8d83d Mon Sep 17 00:00:00 2001
+From: Utkarsh Patel <utkarsh.h.patel@intel.com>
+Date: Thu, 23 Jun 2022 14:19:45 +0300
+Subject: xhci-pci: Allow host runtime PM as default for Intel Meteor Lake xHCI
+
+From: Utkarsh Patel <utkarsh.h.patel@intel.com>
+
+commit 8ffdc53a60049f3930afe161dc51c67959c8d83d upstream.
+
+Meteor Lake TCSS(Type-C Subsystem) xHCI needs to be runtime suspended
+whenever possible to allow the TCSS hardware block to enter D3cold and
+thus save energy.
+
+Cc: stable@kernel.org
+Signed-off-by: Utkarsh Patel <utkarsh.h.patel@intel.com>
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20220623111945.1557702-5-mathias.nyman@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/host/xhci-pci.c |    4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/host/xhci-pci.c
++++ b/drivers/usb/host/xhci-pci.c
+@@ -62,6 +62,7 @@
+ #define PCI_DEVICE_ID_INTEL_ALDER_LAKE_N_XHCI         0x464e
+ #define PCI_DEVICE_ID_INTEL_ALDER_LAKE_PCH_XHCI       0x51ed
+ #define PCI_DEVICE_ID_INTEL_RAPTOR_LAKE_XHCI          0xa71e
++#define PCI_DEVICE_ID_INTEL_METEOR_LAKE_XHCI          0x7ec0
+ #define PCI_DEVICE_ID_AMD_PROMONTORYA_4                       0x43b9
+ #define PCI_DEVICE_ID_AMD_PROMONTORYA_3                       0x43ba
+@@ -267,7 +268,8 @@ static void xhci_pci_quirks(struct devic
+            pdev->device == PCI_DEVICE_ID_INTEL_ALDER_LAKE_XHCI ||
+            pdev->device == PCI_DEVICE_ID_INTEL_ALDER_LAKE_N_XHCI ||
+            pdev->device == PCI_DEVICE_ID_INTEL_ALDER_LAKE_PCH_XHCI ||
+-           pdev->device == PCI_DEVICE_ID_INTEL_RAPTOR_LAKE_XHCI))
++           pdev->device == PCI_DEVICE_ID_INTEL_RAPTOR_LAKE_XHCI ||
++           pdev->device == PCI_DEVICE_ID_INTEL_METEOR_LAKE_XHCI))
+               xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW;
+       if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
diff --git a/queue-5.10/xhci-pci-allow-host-runtime-pm-as-default-for-intel-raptor-lake-xhci.patch b/queue-5.10/xhci-pci-allow-host-runtime-pm-as-default-for-intel-raptor-lake-xhci.patch
new file mode 100644 (file)
index 0000000..cac3489
--- /dev/null
@@ -0,0 +1,42 @@
+From 7516da47a349e74de623243a27f9b8a91446bf4f Mon Sep 17 00:00:00 2001
+From: Tanveer Alam <tanveer1.alam@intel.com>
+Date: Thu, 23 Jun 2022 14:19:44 +0300
+Subject: xhci-pci: Allow host runtime PM as default for Intel Raptor Lake xHCI
+
+From: Tanveer Alam <tanveer1.alam@intel.com>
+
+commit 7516da47a349e74de623243a27f9b8a91446bf4f upstream.
+
+In the same way as Intel Alder Lake TCSS (Type-C Subsystem) the Raptor
+Lake TCSS xHCI needs to be runtime suspended whenever possible to
+allow the TCSS hardware block to enter D3cold and thus save energy.
+
+Cc: stable@kernel.org
+Signed-off-by: Tanveer Alam <tanveer1.alam@intel.com>
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20220623111945.1557702-4-mathias.nyman@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/host/xhci-pci.c |    4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/host/xhci-pci.c
++++ b/drivers/usb/host/xhci-pci.c
+@@ -61,6 +61,7 @@
+ #define PCI_DEVICE_ID_INTEL_ALDER_LAKE_XHCI           0x461e
+ #define PCI_DEVICE_ID_INTEL_ALDER_LAKE_N_XHCI         0x464e
+ #define PCI_DEVICE_ID_INTEL_ALDER_LAKE_PCH_XHCI       0x51ed
++#define PCI_DEVICE_ID_INTEL_RAPTOR_LAKE_XHCI          0xa71e
+ #define PCI_DEVICE_ID_AMD_PROMONTORYA_4                       0x43b9
+ #define PCI_DEVICE_ID_AMD_PROMONTORYA_3                       0x43ba
+@@ -265,7 +266,8 @@ static void xhci_pci_quirks(struct devic
+            pdev->device == PCI_DEVICE_ID_INTEL_MAPLE_RIDGE_XHCI ||
+            pdev->device == PCI_DEVICE_ID_INTEL_ALDER_LAKE_XHCI ||
+            pdev->device == PCI_DEVICE_ID_INTEL_ALDER_LAKE_N_XHCI ||
+-           pdev->device == PCI_DEVICE_ID_INTEL_ALDER_LAKE_PCH_XHCI))
++           pdev->device == PCI_DEVICE_ID_INTEL_ALDER_LAKE_PCH_XHCI ||
++           pdev->device == PCI_DEVICE_ID_INTEL_RAPTOR_LAKE_XHCI))
+               xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW;
+       if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
diff --git a/queue-5.10/xhci-turn-off-port-power-in-shutdown.patch b/queue-5.10/xhci-turn-off-port-power-in-shutdown.patch
new file mode 100644 (file)
index 0000000..117cd6a
--- /dev/null
@@ -0,0 +1,86 @@
+From 83810f84ecf11dfc5a9414a8b762c3501b328185 Mon Sep 17 00:00:00 2001
+From: Mathias Nyman <mathias.nyman@linux.intel.com>
+Date: Thu, 23 Jun 2022 14:19:43 +0300
+Subject: xhci: turn off port power in shutdown
+
+From: Mathias Nyman <mathias.nyman@linux.intel.com>
+
+commit 83810f84ecf11dfc5a9414a8b762c3501b328185 upstream.
+
+If ports are not turned off in shutdown then runtime suspended
+self-powered USB devices may survive in U3 link state over S5.
+
+During subsequent boot, if firmware sends an IPC command to program
+the port in DISCONNECT state, it will time out, causing significant
+delay in the boot time.
+
+Turning off roothub port power is also recommended in xhci
+specification 4.19.4 "Port Power" in the additional note.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20220623111945.1557702-3-mathias.nyman@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/host/xhci-hub.c |    2 +-
+ drivers/usb/host/xhci.c     |   15 +++++++++++++--
+ drivers/usb/host/xhci.h     |    2 ++
+ 3 files changed, 16 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/host/xhci-hub.c
++++ b/drivers/usb/host/xhci-hub.c
+@@ -566,7 +566,7 @@ struct xhci_hub *xhci_get_rhub(struct us
+  * It will release and re-aquire the lock while calling ACPI
+  * method.
+  */
+-static void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd,
++void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd,
+                               u16 index, bool on, unsigned long *flags)
+       __must_hold(&xhci->lock)
+ {
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -775,6 +775,8 @@ static void xhci_stop(struct usb_hcd *hc
+ void xhci_shutdown(struct usb_hcd *hcd)
+ {
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
++      unsigned long flags;
++      int i;
+       if (xhci->quirks & XHCI_SPURIOUS_REBOOT)
+               usb_disable_xhci_ports(to_pci_dev(hcd->self.sysdev));
+@@ -790,12 +792,21 @@ void xhci_shutdown(struct usb_hcd *hcd)
+               del_timer_sync(&xhci->shared_hcd->rh_timer);
+       }
+-      spin_lock_irq(&xhci->lock);
++      spin_lock_irqsave(&xhci->lock, flags);
+       xhci_halt(xhci);
++
++      /* Power off USB2 ports*/
++      for (i = 0; i < xhci->usb2_rhub.num_ports; i++)
++              xhci_set_port_power(xhci, xhci->main_hcd, i, false, &flags);
++
++      /* Power off USB3 ports*/
++      for (i = 0; i < xhci->usb3_rhub.num_ports; i++)
++              xhci_set_port_power(xhci, xhci->shared_hcd, i, false, &flags);
++
+       /* Workaround for spurious wakeups at shutdown with HSW */
+       if (xhci->quirks & XHCI_SPURIOUS_WAKEUP)
+               xhci_reset(xhci, XHCI_RESET_SHORT_USEC);
+-      spin_unlock_irq(&xhci->lock);
++      spin_unlock_irqrestore(&xhci->lock, flags);
+       xhci_cleanup_msix(xhci);
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -2162,6 +2162,8 @@ int xhci_hub_control(struct usb_hcd *hcd
+ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf);
+ int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1);
+ struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd);
++void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd, u16 index,
++                       bool on, unsigned long *flags);
+ void xhci_hc_died(struct xhci_hcd *xhci);