summaryrefslogtreecommitdiff
path: root/drivers/usb/host/xhci-pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/xhci-pci.c')
-rw-r--r--drivers/usb/host/xhci-pci.c108
1 files changed, 104 insertions, 4 deletions
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 7bccbe50bab1..fb988e4ea924 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -59,6 +59,7 @@
#define PCI_DEVICE_ID_INTEL_TIGER_LAKE_XHCI 0x9a13
#define PCI_DEVICE_ID_INTEL_MAPLE_RIDGE_XHCI 0x1138
#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_PCH_XHCI 0x51ed
+#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_N_PCH_XHCI 0x54ed
#define PCI_DEVICE_ID_AMD_RENOIR_XHCI 0x1639
#define PCI_DEVICE_ID_AMD_PROMONTORYA_4 0x43b9
@@ -77,9 +78,12 @@ static const char hcd_name[] = "xhci_hcd";
static struct hc_driver __read_mostly xhci_pci_hc_driver;
static int xhci_pci_setup(struct usb_hcd *hcd);
+static int xhci_pci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
+ struct usb_tt *tt, gfp_t mem_flags);
static const struct xhci_driver_overrides xhci_pci_overrides __initconst = {
.reset = xhci_pci_setup,
+ .update_hub_device = xhci_pci_update_hub_device,
};
/* called after powerup, by probe or system-pm "wakeup" */
@@ -246,7 +250,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
xhci->quirks |= XHCI_MISSING_CAS;
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
- 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_ALDER_LAKE_N_PCH_XHCI))
xhci->quirks |= XHCI_RESET_TO_DEFAULT;
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
@@ -350,8 +355,38 @@ static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev)
NULL);
ACPI_FREE(obj);
}
+
+static void xhci_find_lpm_incapable_ports(struct usb_hcd *hcd, struct usb_device *hdev)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ struct xhci_hub *rhub = &xhci->usb3_rhub;
+ int ret;
+ int i;
+
+ /* This is not the usb3 roothub we are looking for */
+ if (hcd != rhub->hcd)
+ return;
+
+ if (hdev->maxchild > rhub->num_ports) {
+ dev_err(&hdev->dev, "USB3 roothub port number mismatch\n");
+ return;
+ }
+
+ for (i = 0; i < hdev->maxchild; i++) {
+ ret = usb_acpi_port_lpm_incapable(hdev, i);
+
+ dev_dbg(&hdev->dev, "port-%d disable U1/U2 _DSM: %d\n", i + 1, ret);
+
+ if (ret >= 0) {
+ rhub->ports[i]->lpm_incapable = ret;
+ continue;
+ }
+ }
+}
+
#else
static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev) { }
+static void xhci_find_lpm_incapable_ports(struct usb_hcd *hcd, struct usb_device *hdev) { }
#endif /* CONFIG_ACPI */
/* called during probe() after chip reset completes */
@@ -384,6 +419,16 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
return xhci_pci_reinit(xhci, pdev);
}
+static int xhci_pci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
+ struct usb_tt *tt, gfp_t mem_flags)
+{
+ /* Check if acpi claims some USB3 roothub ports are lpm incapable */
+ if (!hdev->parent)
+ xhci_find_lpm_incapable_ports(hcd, hdev);
+
+ return xhci_update_hub_device(hcd, hdev, tt, mem_flags);
+}
+
/*
* We need to register our own PCI probe function (instead of the USB core's
* function) in order to create a second roothub under xHCI.
@@ -453,6 +498,8 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (xhci->quirks & XHCI_DEFAULT_PM_RUNTIME_ALLOW)
pm_runtime_allow(&dev->dev);
+ dma_set_max_seg_size(&dev->dev, UINT_MAX);
+
return 0;
put_usb3_hcd:
@@ -620,6 +667,57 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
return retval;
}
+static int xhci_pci_poweroff_late(struct usb_hcd *hcd, bool do_wakeup)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ struct xhci_port *port;
+ struct usb_device *udev;
+ unsigned int slot_id;
+ u32 portsc;
+ int i;
+
+ /*
+ * Systems with XHCI_RESET_TO_DEFAULT quirk have boot firmware that
+ * cause significant boot delay if usb ports are in suspended U3 state
+ * during boot. Some USB devices survive in U3 state over S4 hibernate
+ *
+ * Disable ports that are in U3 if remote wake is not enabled for either
+ * host controller or connected device
+ */
+
+ if (!(xhci->quirks & XHCI_RESET_TO_DEFAULT))
+ return 0;
+
+ for (i = 0; i < HCS_MAX_PORTS(xhci->hcs_params1); i++) {
+ port = &xhci->hw_ports[i];
+ portsc = readl(port->addr);
+
+ if ((portsc & PORT_PLS_MASK) != XDEV_U3)
+ continue;
+
+ slot_id = xhci_find_slot_id_by_port(port->rhub->hcd, xhci,
+ port->hcd_portnum + 1);
+ if (!slot_id || !xhci->devs[slot_id]) {
+ xhci_err(xhci, "No dev for slot_id %d for port %d-%d in U3\n",
+ slot_id, port->rhub->hcd->self.busnum, port->hcd_portnum + 1);
+ continue;
+ }
+
+ udev = xhci->devs[slot_id]->udev;
+
+ /* if wakeup is enabled then don't disable the port */
+ if (udev->do_remote_wakeup && do_wakeup)
+ continue;
+
+ xhci_dbg(xhci, "port %d-%d in U3 without wakeup, disable it\n",
+ port->rhub->hcd->self.busnum, port->hcd_portnum + 1);
+ portsc = xhci_port_state_to_neutral(portsc);
+ writel(portsc | PORT_PE, port->addr);
+ }
+
+ return 0;
+}
+
static void xhci_pci_shutdown(struct usb_hcd *hcd)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
@@ -673,11 +771,12 @@ static struct pci_driver xhci_pci_driver = {
/* suspend and resume implemented later */
.shutdown = usb_hcd_pci_shutdown,
-#ifdef CONFIG_PM
.driver = {
- .pm = &usb_hcd_pci_pm_ops
- },
+#ifdef CONFIG_PM
+ .pm = &usb_hcd_pci_pm_ops,
#endif
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ },
};
static int __init xhci_pci_init(void)
@@ -686,6 +785,7 @@ static int __init xhci_pci_init(void)
#ifdef CONFIG_PM
xhci_pci_hc_driver.pci_suspend = xhci_pci_suspend;
xhci_pci_hc_driver.pci_resume = xhci_pci_resume;
+ xhci_pci_hc_driver.pci_poweroff_late = xhci_pci_poweroff_late;
xhci_pci_hc_driver.shutdown = xhci_pci_shutdown;
#endif
return pci_register_driver(&xhci_pci_driver);