summaryrefslogtreecommitdiff
path: root/drivers/usb/host/xhci.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2022-06-03 21:17:49 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2022-06-03 21:17:49 +0300
commit54c2cc79194c961a213c1d375fe3aa4165664cc4 (patch)
treea6f03d84b18dcab2a03c0d162327bba2f577cfb5 /drivers/usb/host/xhci.c
parent932c2989b59008e530ffcc7c7e6ef507a28b28ca (diff)
parent97fa5887cf283bb75ffff5f6b2c0e71794c02400 (diff)
downloadlinux-54c2cc79194c961a213c1d375fe3aa4165664cc4.tar.xz
Merge tag 'usb-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB / Thunderbolt updates from Greg KH: "Here is the "big" set of USB and Thunderbolt driver changes for 5.18-rc1. For the most part it's been a quiet development cycle for the USB core, but there are the usual "hot spots" of development activity. Included in here are: - Thunderbolt driver updates: - fixes for devices without displayport adapters - lane bonding support and improvements - other minor changes based on device testing - dwc3 gadget driver changes. It seems this driver will never be finished given that the IP core is showing up in zillions of new devices and each implementation decides to do something different with it... - uvc gadget driver updates as more devices start to use and rely on this hardware as well - usb_maxpacket() api changes to remove an unneeded and unused parameter. - usb-serial driver device id updates and small cleanups - typec cleanups and fixes based on device testing - device tree updates for usb properties - lots of other small fixes and driver updates. All of these have been in linux-next for weeks with no reported problems" * tag 'usb-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (154 commits) USB: new quirk for Dell Gen 2 devices usb: dwc3: core: Add error log when core soft reset failed usb: dwc3: gadget: Move null pinter check to proper place usb: hub: Simplify error and success path in port_over_current_notify usb: cdns3: allocate TX FIFO size according to composite EP number usb: dwc3: Fix ep0 handling when getting reset while doing control transfer usb: Probe EHCI, OHCI controllers asynchronously usb: isp1760: Fix out-of-bounds array access xhci: Don't defer primary roothub registration if there is only one roothub USB: serial: option: add Quectel BG95 modem USB: serial: pl2303: fix type detection for odd device xhci: Allow host runtime PM as default for Intel Alder Lake N xHCI xhci: Remove quirk for over 10 year old evaluation hardware xhci: prevent U2 link power state if Intel tier policy prevented U1 xhci: use generic command timer for stop endpoint commands. usb: host: xhci-plat: omit shared hcd if either root hub has no ports usb: host: xhci-plat: prepare operation w/o shared hcd usb: host: xhci-plat: create shared hcd after having added main hcd xhci: prepare for operation w/o shared hcd xhci: factor out parts of xhci_gen_setup() ...
Diffstat (limited to 'drivers/usb/host/xhci.c')
-rw-r--r--drivers/usb/host/xhci.c175
1 files changed, 94 insertions, 81 deletions
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 25b87e99b4dd..f0ab63138016 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -486,6 +486,10 @@ static void compliance_mode_recovery(struct timer_list *t)
xhci = from_timer(xhci, t, comp_mode_recovery_timer);
rhub = &xhci->usb3_rhub;
+ hcd = rhub->hcd;
+
+ if (!hcd)
+ return;
for (i = 0; i < rhub->num_ports; i++) {
temp = readl(rhub->ports[i]->addr);
@@ -499,7 +503,6 @@ static void compliance_mode_recovery(struct timer_list *t)
i + 1);
xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
"Attempting compliance mode recovery");
- hcd = xhci->shared_hcd;
if (hcd->state == HC_STATE_SUSPENDED)
usb_hcd_resume_root_hub(hcd);
@@ -612,14 +615,11 @@ static int xhci_run_finished(struct xhci_hcd *xhci)
xhci_halt(xhci);
return -ENODEV;
}
- xhci->shared_hcd->state = HC_STATE_RUNNING;
xhci->cmd_ring_state = CMD_RING_STATE_RUNNING;
if (xhci->quirks & XHCI_NEC_HOST)
xhci_ring_cmd_db(xhci);
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "Finished xhci_run for USB3 roothub");
return 0;
}
@@ -694,12 +694,17 @@ int xhci_run(struct usb_hcd *hcd)
xhci_free_command(xhci, command);
}
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "Finished xhci_run for USB2 roothub");
+ "Finished %s for main hcd", __func__);
xhci_create_dbc_dev(xhci);
xhci_debugfs_init(xhci);
+ if (xhci_has_one_roothub(xhci))
+ return xhci_run_finished(xhci);
+
+ set_bit(HCD_FLAG_DEFER_RH_REGISTER, &hcd->flags);
+
return 0;
}
EXPORT_SYMBOL_GPL(xhci_run);
@@ -992,7 +997,7 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
return 0;
if (hcd->state != HC_STATE_SUSPENDED ||
- xhci->shared_hcd->state != HC_STATE_SUSPENDED)
+ (xhci->shared_hcd && xhci->shared_hcd->state != HC_STATE_SUSPENDED))
return -EINVAL;
/* Clear root port wake on bits if wakeup not allowed. */
@@ -1009,15 +1014,18 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
__func__, hcd->self.busnum);
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
del_timer_sync(&hcd->rh_timer);
- clear_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
- del_timer_sync(&xhci->shared_hcd->rh_timer);
+ if (xhci->shared_hcd) {
+ clear_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
+ del_timer_sync(&xhci->shared_hcd->rh_timer);
+ }
if (xhci->quirks & XHCI_SUSPEND_DELAY)
usleep_range(1000, 1500);
spin_lock_irq(&xhci->lock);
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
- clear_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags);
+ if (xhci->shared_hcd)
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags);
/* step 1: stop endpoint */
/* skipped assuming that port suspend has done */
@@ -1117,7 +1125,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
msleep(100);
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
- set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags);
+ if (xhci->shared_hcd)
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags);
spin_lock_irq(&xhci->lock);
@@ -1177,7 +1186,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
/* Let the USB core know _both_ roothubs lost power. */
usb_root_hub_lost_power(xhci->main_hcd->self.root_hub);
- usb_root_hub_lost_power(xhci->shared_hcd->self.root_hub);
+ if (xhci->shared_hcd)
+ usb_root_hub_lost_power(xhci->shared_hcd->self.root_hub);
xhci_dbg(xhci, "Stop HCD\n");
xhci_halt(xhci);
@@ -1217,12 +1227,13 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
xhci_dbg(xhci, "Start the primary HCD\n");
retval = xhci_run(hcd->primary_hcd);
- if (!retval) {
+ if (!retval && secondary_hcd) {
xhci_dbg(xhci, "Start the secondary HCD\n");
retval = xhci_run(secondary_hcd);
}
hcd->state = HC_STATE_SUSPENDED;
- xhci->shared_hcd->state = HC_STATE_SUSPENDED;
+ if (xhci->shared_hcd)
+ xhci->shared_hcd->state = HC_STATE_SUSPENDED;
goto done;
}
@@ -1260,7 +1271,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
}
if (pending_portevent) {
- usb_hcd_resume_root_hub(xhci->shared_hcd);
+ if (xhci->shared_hcd)
+ usb_hcd_resume_root_hub(xhci->shared_hcd);
usb_hcd_resume_root_hub(hcd);
}
}
@@ -1279,8 +1291,10 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
/* Re-enable port polling. */
xhci_dbg(xhci, "%s: starting usb%d port polling.\n",
__func__, hcd->self.busnum);
- set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
- usb_hcd_poll_rh_status(xhci->shared_hcd);
+ if (xhci->shared_hcd) {
+ set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
+ usb_hcd_poll_rh_status(xhci->shared_hcd);
+ }
set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
usb_hcd_poll_rh_status(hcd);
@@ -1860,9 +1874,6 @@ static int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
goto done;
}
ep->ep_state |= EP_STOP_CMD_PENDING;
- ep->stop_cmd_timer.expires = jiffies +
- XHCI_STOP_EP_CMD_TIMEOUT * HZ;
- add_timer(&ep->stop_cmd_timer);
xhci_queue_stop_endpoint(xhci, command, urb->dev->slot_id,
ep_index, 0);
xhci_ring_cmd_db(xhci);
@@ -3972,10 +3983,8 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
trace_xhci_free_dev(slot_ctx);
/* Stop any wayward timer functions (which may grab the lock) */
- for (i = 0; i < 31; i++) {
+ for (i = 0; i < 31; i++)
virt_dev->eps[i].ep_state &= ~EP_STOP_CMD_PENDING;
- del_timer_sync(&virt_dev->eps[i].stop_cmd_timer);
- }
virt_dev->udev = NULL;
xhci_disable_slot(xhci, udev->slot_id);
xhci_free_virt_device(xhci, udev->slot_id);
@@ -4879,9 +4888,6 @@ static int xhci_check_intel_tier_policy(struct usb_device *udev,
struct usb_device *parent;
unsigned int num_hubs;
- if (state == USB3_LPM_U2)
- return 0;
-
/* Don't enable U1 if the device is on a 2nd tier hub or lower. */
for (parent = udev->parent, num_hubs = 0; parent->parent;
parent = parent->parent)
@@ -4890,7 +4896,7 @@ static int xhci_check_intel_tier_policy(struct usb_device *udev,
if (num_hubs < 2)
return 0;
- dev_dbg(&udev->dev, "Disabling U1 link state for device"
+ dev_dbg(&udev->dev, "Disabling U1/U2 link state for device"
" below second-tier hub.\n");
dev_dbg(&udev->dev, "Plug device into first-tier hub "
"to decrease power consumption.\n");
@@ -4931,9 +4937,6 @@ static u16 xhci_calculate_lpm_timeout(struct usb_hcd *hcd,
return timeout;
}
- if (xhci_check_tier_policy(xhci, udev, state) < 0)
- return timeout;
-
/* Gather some information about the currently installed configuration
* and alternate interface settings.
*/
@@ -5040,6 +5043,9 @@ static int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
!xhci->devs[udev->slot_id])
return USB3_LPM_DISABLED;
+ if (xhci_check_tier_policy(xhci, udev, state) < 0)
+ return USB3_LPM_DISABLED;
+
hub_encoded_timeout = xhci_calculate_lpm_timeout(hcd, udev, state);
mel = calculate_max_exit_latency(udev, state, hub_encoded_timeout);
if (mel < 0) {
@@ -5207,6 +5213,57 @@ static int xhci_get_frame(struct usb_hcd *hcd)
return readl(&xhci->run_regs->microframe_index) >> 3;
}
+static void xhci_hcd_init_usb2_data(struct xhci_hcd *xhci, struct usb_hcd *hcd)
+{
+ xhci->usb2_rhub.hcd = hcd;
+ hcd->speed = HCD_USB2;
+ hcd->self.root_hub->speed = USB_SPEED_HIGH;
+ /*
+ * USB 2.0 roothub under xHCI has an integrated TT,
+ * (rate matching hub) as opposed to having an OHCI/UHCI
+ * companion controller.
+ */
+ hcd->has_tt = 1;
+}
+
+static void xhci_hcd_init_usb3_data(struct xhci_hcd *xhci, struct usb_hcd *hcd)
+{
+ unsigned int minor_rev;
+
+ /*
+ * Early xHCI 1.1 spec did not mention USB 3.1 capable hosts
+ * should return 0x31 for sbrn, or that the minor revision
+ * is a two digit BCD containig minor and sub-minor numbers.
+ * This was later clarified in xHCI 1.2.
+ *
+ * Some USB 3.1 capable hosts therefore have sbrn 0x30, and
+ * minor revision set to 0x1 instead of 0x10.
+ */
+ if (xhci->usb3_rhub.min_rev == 0x1)
+ minor_rev = 1;
+ else
+ minor_rev = xhci->usb3_rhub.min_rev / 0x10;
+
+ switch (minor_rev) {
+ case 2:
+ hcd->speed = HCD_USB32;
+ hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS;
+ hcd->self.root_hub->rx_lanes = 2;
+ hcd->self.root_hub->tx_lanes = 2;
+ hcd->self.root_hub->ssp_rate = USB_SSP_GEN_2x2;
+ break;
+ case 1:
+ hcd->speed = HCD_USB31;
+ hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS;
+ hcd->self.root_hub->ssp_rate = USB_SSP_GEN_2x1;
+ break;
+ }
+ xhci_info(xhci, "Host supports USB 3.%x %sSuperSpeed\n",
+ minor_rev, minor_rev ? "Enhanced " : "");
+
+ xhci->usb3_rhub.hcd = hcd;
+}
+
int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
{
struct xhci_hcd *xhci;
@@ -5215,7 +5272,6 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
* quirks
*/
struct device *dev = hcd->self.sysdev;
- unsigned int minor_rev;
int retval;
/* Accept arbitrarily long scatter-gather lists */
@@ -5229,61 +5285,13 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
xhci = hcd_to_xhci(hcd);
- if (usb_hcd_is_primary_hcd(hcd)) {
- xhci->main_hcd = hcd;
- xhci->usb2_rhub.hcd = hcd;
- /* Mark the first roothub as being USB 2.0.
- * The xHCI driver will register the USB 3.0 roothub.
- */
- hcd->speed = HCD_USB2;
- hcd->self.root_hub->speed = USB_SPEED_HIGH;
- /*
- * USB 2.0 roothub under xHCI has an integrated TT,
- * (rate matching hub) as opposed to having an OHCI/UHCI
- * companion controller.
- */
- hcd->has_tt = 1;
- } else {
- /*
- * Early xHCI 1.1 spec did not mention USB 3.1 capable hosts
- * should return 0x31 for sbrn, or that the minor revision
- * is a two digit BCD containig minor and sub-minor numbers.
- * This was later clarified in xHCI 1.2.
- *
- * Some USB 3.1 capable hosts therefore have sbrn 0x30, and
- * minor revision set to 0x1 instead of 0x10.
- */
- if (xhci->usb3_rhub.min_rev == 0x1)
- minor_rev = 1;
- else
- minor_rev = xhci->usb3_rhub.min_rev / 0x10;
-
- switch (minor_rev) {
- case 2:
- hcd->speed = HCD_USB32;
- hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS;
- hcd->self.root_hub->rx_lanes = 2;
- hcd->self.root_hub->tx_lanes = 2;
- hcd->self.root_hub->ssp_rate = USB_SSP_GEN_2x2;
- break;
- case 1:
- hcd->speed = HCD_USB31;
- hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS;
- hcd->self.root_hub->ssp_rate = USB_SSP_GEN_2x1;
- break;
- }
- xhci_info(xhci, "Host supports USB 3.%x %sSuperSpeed\n",
- minor_rev,
- minor_rev ? "Enhanced " : "");
-
- xhci->usb3_rhub.hcd = hcd;
- /* xHCI private pointer was set in xhci_pci_probe for the second
- * registered roothub.
- */
+ if (!usb_hcd_is_primary_hcd(hcd)) {
+ xhci_hcd_init_usb3_data(xhci, hcd);
return 0;
}
mutex_init(&xhci->mutex);
+ xhci->main_hcd = hcd;
xhci->cap_regs = hcd->regs;
xhci->op_regs = hcd->regs +
HC_LENGTH(readl(&xhci->cap_regs->hc_capbase));
@@ -5358,6 +5366,11 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
return retval;
xhci_dbg(xhci, "Called HCD init\n");
+ if (xhci_hcd_is_usb3(hcd))
+ xhci_hcd_init_usb3_data(xhci, hcd);
+ else
+ xhci_hcd_init_usb2_data(xhci, hcd);
+
xhci_info(xhci, "hcc params 0x%08x hci version 0x%x quirks 0x%016llx\n",
xhci->hcc_params, xhci->hci_version, xhci->quirks);