xhci: Show ZHAOXIN xHCI root hub speed correctly
authorWeitao Wang <WeitaoWang-oc@zhaoxin.com>
Fri, 2 Jun 2023 14:40:08 +0000 (17:40 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 13 Jun 2023 09:34:50 +0000 (11:34 +0200)
Some ZHAOXIN xHCI controllers follow usb3.1 spec, but only support
gen1 speed 5Gbps. While in Linux kernel, if xHCI suspport usb3.1,
root hub speed will show on 10Gbps.
To fix this issue of ZHAOXIN xHCI platforms, read usb speed ID
supported by xHCI to determine root hub speed. And add a quirk
XHCI_ZHAOXIN_HOST for this issue.

[fix warning about uninitialized symbol -Mathias]

Suggested-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Cc: stable@vger.kernel.org
Signed-off-by: Weitao Wang <WeitaoWang-oc@zhaoxin.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Message-ID: <20230602144009.1225632-11-mathias.nyman@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci.h

index c4170421bc9c4f4085c4da538244d705aaec431e..19a402123de02f9589a526af60ffcbbf0a2297dc 100644 (file)
@@ -1961,7 +1961,7 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
 {
        u32 temp, port_offset, port_count;
        int i;
-       u8 major_revision, minor_revision;
+       u8 major_revision, minor_revision, tmp_minor_revision;
        struct xhci_hub *rhub;
        struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
        struct xhci_port_cap *port_cap;
@@ -1981,6 +1981,15 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
                 */
                if (minor_revision > 0x00 && minor_revision < 0x10)
                        minor_revision <<= 4;
+               /*
+                * Some zhaoxin's xHCI controller that follow usb3.1 spec
+                * but only support Gen1.
+                */
+               if (xhci->quirks & XHCI_ZHAOXIN_HOST) {
+                       tmp_minor_revision = minor_revision;
+                       minor_revision = 0;
+               }
+
        } else if (major_revision <= 0x02) {
                rhub = &xhci->usb2_rhub;
        } else {
@@ -1989,10 +1998,6 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
                /* Ignoring port protocol we can't understand. FIXME */
                return;
        }
-       rhub->maj_rev = XHCI_EXT_PORT_MAJOR(temp);
-
-       if (rhub->min_rev < minor_revision)
-               rhub->min_rev = minor_revision;
 
        /* Port offset and count in the third dword, see section 7.2 */
        temp = readl(addr + 2);
@@ -2010,8 +2015,6 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
        if (xhci->num_port_caps > max_caps)
                return;
 
-       port_cap->maj_rev = major_revision;
-       port_cap->min_rev = minor_revision;
        port_cap->psi_count = XHCI_EXT_PORT_PSIC(temp);
 
        if (port_cap->psi_count) {
@@ -2032,6 +2035,11 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
                                  XHCI_EXT_PORT_PSIV(port_cap->psi[i - 1])))
                                port_cap->psi_uid_count++;
 
+                       if (xhci->quirks & XHCI_ZHAOXIN_HOST &&
+                           major_revision == 0x03 &&
+                           XHCI_EXT_PORT_PSIV(port_cap->psi[i]) >= 5)
+                               minor_revision = tmp_minor_revision;
+
                        xhci_dbg(xhci, "PSIV:%d PSIE:%d PLT:%d PFD:%d LP:%d PSIM:%d\n",
                                  XHCI_EXT_PORT_PSIV(port_cap->psi[i]),
                                  XHCI_EXT_PORT_PSIE(port_cap->psi[i]),
@@ -2041,6 +2049,15 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
                                  XHCI_EXT_PORT_PSIM(port_cap->psi[i]));
                }
        }
+
+       rhub->maj_rev = major_revision;
+
+       if (rhub->min_rev < minor_revision)
+               rhub->min_rev = minor_revision;
+
+       port_cap->maj_rev = major_revision;
+       port_cap->min_rev = minor_revision;
+
        /* cache usb2 port capabilities */
        if (major_revision < 0x03 && xhci->num_ext_caps < max_caps)
                xhci->ext_caps[xhci->num_ext_caps++] = temp;
index 3aad946bab683a6117cee1bddb08399dc57ba930..88c16d91fb69c75b88b2814730fcf11f913632b9 100644 (file)
@@ -522,6 +522,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                xhci->quirks |= XHCI_NO_SOFT_RETRY;
 
        if (pdev->vendor == PCI_VENDOR_ID_ZHAOXIN) {
+               xhci->quirks |= XHCI_ZHAOXIN_HOST;
+
                if (pdev->device == 0x9202) {
                        xhci->quirks |= XHCI_RESET_ON_RESUME;
                        xhci->quirks |= XHCI_ZHAOXIN_TRB_FETCH;
index 5a495126c8ba781969da8b07b2e7479f3ff55a03..7e282b4522c0aa16c15398afefb933ecec2db7e5 100644 (file)
@@ -1905,6 +1905,7 @@ struct xhci_hcd {
 #define XHCI_SUSPEND_RESUME_CLKS       BIT_ULL(43)
 #define XHCI_RESET_TO_DEFAULT  BIT_ULL(44)
 #define XHCI_ZHAOXIN_TRB_FETCH BIT_ULL(45)
+#define XHCI_ZHAOXIN_HOST      BIT_ULL(46)
 
        unsigned int            num_active_eps;
        unsigned int            limit_active_eps;