Commit d5e234ff authored by Weitao Wang's avatar Weitao Wang Committed by Greg Kroah-Hartman
Browse files

xhci: Add ZHAOXIN xHCI host U1/U2 feature support



Add U1/U2 feature support of xHCI for ZHAOXIN.
Since both INTEL and ZHAOXIN need to check the tier where the device is
located to determine whether to enabled U1/U2, remove the previous INTEL
U1/U2 tier policy and add common policy in xhci_check_tier_policy.
If vendor has specific U1/U2 enable policy,quirks can be add to declare.

Suggested-by: default avatarMathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: default avatarWeitao Wang <WeitaoWang-oc@zhaoxin.com>
Signed-off-by: default avatarMathias Nyman <mathias.nyman@linux.intel.com>
Message-ID: <20230602144009.1225632-12-mathias.nyman@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent d9b0328d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -523,6 +523,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)

	if (pdev->vendor == PCI_VENDOR_ID_ZHAOXIN) {
		xhci->quirks |= XHCI_ZHAOXIN_HOST;
		xhci->quirks |= XHCI_LPM_SUPPORT;

		if (pdev->device == 0x9202) {
			xhci->quirks |= XHCI_RESET_ON_RESUME;
+18 −25
Original line number Diff line number Diff line
@@ -4605,7 +4605,7 @@ static u16 xhci_calculate_u1_timeout(struct xhci_hcd *xhci,
		}
	}

	if (xhci->quirks & XHCI_INTEL_HOST)
	if (xhci->quirks & (XHCI_INTEL_HOST | XHCI_ZHAOXIN_HOST))
		timeout_ns = xhci_calculate_intel_u1_timeout(udev, desc);
	else
		timeout_ns = udev->u1_params.sel;
@@ -4669,7 +4669,7 @@ static u16 xhci_calculate_u2_timeout(struct xhci_hcd *xhci,
		}
	}

	if (xhci->quirks & XHCI_INTEL_HOST)
	if (xhci->quirks & (XHCI_INTEL_HOST | XHCI_ZHAOXIN_HOST))
		timeout_ns = xhci_calculate_intel_u2_timeout(udev, desc);
	else
		timeout_ns = udev->u2_params.sel;
@@ -4741,35 +4741,28 @@ static int xhci_update_timeout_for_interface(struct xhci_hcd *xhci,
	return 0;
}

static int xhci_check_intel_tier_policy(struct usb_device *udev,
static int xhci_check_tier_policy(struct xhci_hcd *xhci,
		struct usb_device *udev,
		enum usb3_link_state state)
{
	struct usb_device *parent;
	unsigned int num_hubs;
	struct usb_device *parent = udev->parent;
	int tier = 1; /* roothub is tier1 */

	/* 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)
		num_hubs++;

	if (num_hubs < 2)
		return 0;

	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");
	return -E2BIG;
	while (parent) {
		parent = parent->parent;
		tier++;
	}

static int xhci_check_tier_policy(struct xhci_hcd *xhci,
		struct usb_device *udev,
		enum usb3_link_state state)
{
	if (xhci->quirks & XHCI_INTEL_HOST)
		return xhci_check_intel_tier_policy(udev, state);
	else
	if (xhci->quirks & XHCI_INTEL_HOST && tier > 3)
		goto fail;
	if (xhci->quirks & XHCI_ZHAOXIN_HOST && tier > 2)
		goto fail;

	return 0;
fail:
	dev_dbg(&udev->dev, "Tier policy prevents U1/U2 LPM states for devices at tier %d\n",
			tier);
	return -E2BIG;
}

/* Returns the U1 or U2 timeout that should be enabled.