xhci: Add ZHAOXIN xHCI host U1/U2 feature support
authorWeitao Wang <WeitaoWang-oc@zhaoxin.com>
Fri, 2 Jun 2023 14:40:09 +0000 (17:40 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 13 Jun 2023 09:34:50 +0000 (11:34 +0200)
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: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Weitao Wang <WeitaoWang-oc@zhaoxin.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Message-ID: <20230602144009.1225632-12-mathias.nyman@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci.c

index 88c16d9..c6742ba 100644 (file)
@@ -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;
index 176969b..5b73a7d 100644 (file)
@@ -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,37 +4741,30 @@ 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++;
+       while (parent) {
+               parent = parent->parent;
+               tier++;
+       }
 
-       if (num_hubs < 2)
-               return 0;
+       if (xhci->quirks & XHCI_INTEL_HOST && tier > 3)
+               goto fail;
+       if (xhci->quirks & XHCI_ZHAOXIN_HOST && tier > 2)
+               goto fail;
 
-       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 0;
+fail:
+       dev_dbg(&udev->dev, "Tier policy prevents U1/U2 LPM states for devices at tier %d\n",
+                       tier);
        return -E2BIG;
 }
 
-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
-               return 0;
-}
-
 /* Returns the U1 or U2 timeout that should be enabled.
  * If the tier check or timeout setting functions return with a non-zero exit
  * code, that means the timeout value has been finalized and we shouldn't look