Commit 873f3236 authored by Heiner Kallweit's avatar Heiner Kallweit Committed by Greg Kroah-Hartman
Browse files

xhci: prepare for operation w/o shared hcd



This patch prepares xhci for the following scenario:
- If either of the root hubs has no ports, then omit shared hcd
- Main hcd can be USB3 if there are no USB2 ports

Signed-off-by: default avatarHeiner Kallweit <hkallweit1@gmail.com>
Signed-off-by: default avatarMathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20220511220450.85367-3-mathias.nyman@linux.intel.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 57f23cd0
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -707,6 +707,7 @@ static int xhci_enter_test_mode(struct xhci_hcd *xhci,
				u16 test_mode, u16 wIndex, unsigned long *flags)
	__must_hold(&xhci->lock)
{
	struct usb_hcd *usb3_hcd = xhci_get_usb3_hcd(xhci);
	int i, retval;

	/* Disable all Device Slots */
@@ -727,7 +728,7 @@ static int xhci_enter_test_mode(struct xhci_hcd *xhci,
	xhci_dbg(xhci, "Disable all port (PP = 0)\n");
	/* 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);
		xhci_set_port_power(xhci, usb3_hcd, i, false, flags);
	/* 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);
+6 −5
Original line number Diff line number Diff line
@@ -1072,7 +1072,7 @@ static u32 xhci_find_real_port_number(struct xhci_hcd *xhci,
	struct usb_hcd *hcd;

	if (udev->speed >= USB_SPEED_SUPER)
		hcd = xhci->shared_hcd;
		hcd = xhci_get_usb3_hcd(xhci);
	else
		hcd = xhci->main_hcd;

@@ -2362,10 +2362,11 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
		xhci->usb2_rhub.num_ports = USB_MAXCHILDREN;
	}

	/*
	 * Note we could have all USB 3.0 ports, or all USB 2.0 ports.
	 * Not sure how the USB core will handle a hub with no ports...
	 */
	if (!xhci->usb2_rhub.num_ports)
		xhci_info(xhci, "USB2 root hub has no ports\n");

	if (!xhci->usb3_rhub.num_ports)
		xhci_info(xhci, "USB3 root hub has no ports\n");

	xhci_create_rhub_port_array(xhci, &xhci->usb2_rhub, flags);
	xhci_create_rhub_port_array(xhci, &xhci->usb3_rhub, flags);
+34 −19
Original line number Diff line number Diff line
@@ -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,7 +694,7 @@ 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__);

	set_bit(HCD_FLAG_DEFER_RH_REGISTER, &hcd->flags);

@@ -702,6 +702,9 @@ int xhci_run(struct usb_hcd *hcd)

	xhci_debugfs_init(xhci);

	if (xhci_has_one_roothub(xhci))
		return xhci_run_finished(xhci);

	return 0;
}
EXPORT_SYMBOL_GPL(xhci_run);
@@ -994,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. */
@@ -1011,14 +1014,17 @@ 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);
	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);
	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 */
@@ -1119,6 +1125,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
		msleep(100);

	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
	if (xhci->shared_hcd)
		set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags);

	spin_lock_irq(&xhci->lock);
@@ -1179,6 +1186,7 @@ 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);
		if (xhci->shared_hcd)
			usb_root_hub_lost_power(xhci->shared_hcd->self.root_hub);

		xhci_dbg(xhci, "Stop HCD\n");
@@ -1219,11 +1227,12 @@ 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;
		if (xhci->shared_hcd)
			xhci->shared_hcd->state = HC_STATE_SUSPENDED;
		goto done;
	}
@@ -1262,6 +1271,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
		}

		if (pending_portevent) {
			if (xhci->shared_hcd)
				usb_hcd_resume_root_hub(xhci->shared_hcd);
			usb_hcd_resume_root_hub(hcd);
		}
@@ -1281,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);
	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);

@@ -5281,9 +5293,7 @@ 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_hcd_init_usb2_data(xhci, hcd);
	} else {
	if (!usb_hcd_is_primary_hcd(hcd)) {
		xhci_hcd_init_usb3_data(xhci, hcd);
		return 0;
	}
@@ -5364,6 +5374,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);

+26 −0
Original line number Diff line number Diff line
@@ -1911,6 +1911,8 @@ struct xhci_hcd {
	unsigned		hw_lpm_support:1;
	/* Broken Suspend flag for SNPS Suspend resume issue */
	unsigned		broken_suspend:1;
	/* Indicates that omitting hcd is supported if root hub has no ports */
	unsigned		allow_single_roothub:1;
	/* cached usb2 extened protocol capabilites */
	u32                     *ext_caps;
	unsigned int            num_ext_caps;
@@ -1966,6 +1968,30 @@ static inline struct usb_hcd *xhci_to_hcd(struct xhci_hcd *xhci)
	return xhci->main_hcd;
}

static inline struct usb_hcd *xhci_get_usb3_hcd(struct xhci_hcd *xhci)
{
	if (xhci->shared_hcd)
		return xhci->shared_hcd;

	if (!xhci->usb2_rhub.num_ports)
		return xhci->main_hcd;

	return NULL;
}

static inline bool xhci_hcd_is_usb3(struct usb_hcd *hcd)
{
	struct xhci_hcd *xhci = hcd_to_xhci(hcd);

	return hcd == xhci_get_usb3_hcd(xhci);
}

static inline bool xhci_has_one_roothub(struct xhci_hcd *xhci)
{
	return xhci->allow_single_roothub &&
	       (!xhci->usb2_rhub.num_ports || !xhci->usb3_rhub.num_ports);
}

#define xhci_dbg(xhci, fmt, args...) \
	dev_dbg(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
#define xhci_err(xhci, fmt, args...) \