diff mbox series

[v2,3/4] xhci: Show zhaoxin xHCI root hub speed correctly

Message ID 20230421203853.387210-4-WeitaoWang-oc@zhaoxin.com
State Superseded
Headers show
Series Fix some issues of xHCI for zhaoxin | expand

Commit Message

Weitao Wang April 21, 2023, 8:38 p.m. UTC
Some zhaoxin xHCI controllers follow usb3.1 spec,
but only support gen1 speed 5G. While in Linux kernel,
if xHCI suspport usb3.1,root hub speed will show on 10G.
To fix this issue of zhaoxin xHCI platforms, read usb speed ID
supported by xHCI to determine root hub speed.

Signed-off-by: Weitao Wang <WeitaoWang-oc@zhaoxin.com>
---
 drivers/usb/host/xhci.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

Comments

Mathias Nyman May 5, 2023, 10:52 a.m. UTC | #1
On 21.4.2023 23.38, Weitao Wang wrote:
> Some zhaoxin xHCI controllers follow usb3.1 spec,
> but only support gen1 speed 5G. While in Linux kernel,
> if xHCI suspport usb3.1,root hub speed will show on 10G.
> To fix this issue of zhaoxin xHCI platforms, read usb speed ID
> supported by xHCI to determine root hub speed.
> 
> Signed-off-by: Weitao Wang <WeitaoWang-oc@zhaoxin.com>
> ---
>   drivers/usb/host/xhci.c | 22 ++++++++++++++++++++++
>   1 file changed, 22 insertions(+)
> 
> diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
> index 6307bae9cddf..31d6ace9cace 100644
> --- a/drivers/usb/host/xhci.c
> +++ b/drivers/usb/host/xhci.c
> @@ -5294,6 +5294,7 @@ static void xhci_hcd_init_usb2_data(struct xhci_hcd *xhci, struct usb_hcd *hcd)
>   static void xhci_hcd_init_usb3_data(struct xhci_hcd *xhci, struct usb_hcd *hcd)
>   {
>   	unsigned int minor_rev;
> +	unsigned int i, j;
>   
>   	/*
>   	 * Early xHCI 1.1 spec did not mention USB 3.1 capable hosts
> @@ -5323,6 +5324,27 @@ static void xhci_hcd_init_usb3_data(struct xhci_hcd *xhci, struct usb_hcd *hcd)
>   		hcd->self.root_hub->ssp_rate = USB_SSP_GEN_2x1;
>   		break;
>   	}
> +
> +	/* Usb3.1 has gen1 and gen2, Some zhaoxin's xHCI controller
> +	 * that follow usb3.1 spec but only support gen1.
> +	 */
> +	if (xhci->quirks & XHCI_ZHAOXIN_HOST) {
> +		minor_rev = 0;
> +		for (j = 0; j < xhci->num_port_caps; j++) {
> +			for (i = 0; i < xhci->port_caps[j].psi_count; i++) {
> +				if (XHCI_EXT_PORT_PSIV(xhci->port_caps[j].psi[i]) >= 5) {
> +					minor_rev = 1;
> +					break;
> +				}
> +			}
> +			if (minor_rev)
> +				break;
> +		}
> +		if (minor_rev != 1) {
> +			hcd->speed = HCD_USB3;
> +			hcd->self.root_hub->speed = USB_SPEED_SUPER;
> +		}
> +	}
>   	xhci_info(xhci, "Host supports USB 3.%x %sSuperSpeed\n",
>   		  minor_rev, minor_rev ? "Enhanced " : "");
>   

How about checking if port support over 5Gbps (psiv >= 5) when we parse the protocol speed ID
entries the first time? This way we could avoid looping through all the port_cap psiv values.

Something like:

diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index c4170421bc9c..2e4c80eb4972 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -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,11 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
                  */
                 if (minor_revision > 0x00 && minor_revision < 0x10)
                         minor_revision <<= 4;
+               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 +1994,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 +2011,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 +2031,10 @@ 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 &&
+                           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 +2044,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;

Thanks
Mathias
Weitao Wang May 6, 2023, 11:38 a.m. UTC | #2
On 2023/5/5 18:52, Mathias Nyman wrote:
> On 21.4.2023 23.38, Weitao Wang wrote:
>> Some zhaoxin xHCI controllers follow usb3.1 spec,
>> but only support gen1 speed 5G. While in Linux kernel,
>> if xHCI suspport usb3.1,root hub speed will show on 10G.
>> To fix this issue of zhaoxin xHCI platforms, read usb speed ID
>> supported by xHCI to determine root hub speed.
>>
>> Signed-off-by: Weitao Wang <WeitaoWang-oc@zhaoxin.com>
>> ---
>>   drivers/usb/host/xhci.c | 22 ++++++++++++++++++++++
>>   1 file changed, 22 insertions(+)
>>
>> diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
>> index 6307bae9cddf..31d6ace9cace 100644
>> --- a/drivers/usb/host/xhci.c
>> +++ b/drivers/usb/host/xhci.c
>> @@ -5294,6 +5294,7 @@ static void xhci_hcd_init_usb2_data(struct xhci_hcd *xhci, struct 
>> usb_hcd *hcd)
>>   static void xhci_hcd_init_usb3_data(struct xhci_hcd *xhci, struct usb_hcd *hcd)
>>   {
>>       unsigned int minor_rev;
>> +    unsigned int i, j;
>>       /*
>>        * Early xHCI 1.1 spec did not mention USB 3.1 capable hosts
>> @@ -5323,6 +5324,27 @@ static void xhci_hcd_init_usb3_data(struct xhci_hcd *xhci, struct 
>> usb_hcd *hcd)
>>           hcd->self.root_hub->ssp_rate = USB_SSP_GEN_2x1;
>>           break;
>>       }
>> +
>> +    /* Usb3.1 has gen1 and gen2, Some zhaoxin's xHCI controller
>> +     * that follow usb3.1 spec but only support gen1.
>> +     */
>> +    if (xhci->quirks & XHCI_ZHAOXIN_HOST) {
>> +        minor_rev = 0;
>> +        for (j = 0; j < xhci->num_port_caps; j++) {
>> +            for (i = 0; i < xhci->port_caps[j].psi_count; i++) {
>> +                if (XHCI_EXT_PORT_PSIV(xhci->port_caps[j].psi[i]) >= 5) {
>> +                    minor_rev = 1;
>> +                    break;
>> +                }
>> +            }
>> +            if (minor_rev)
>> +                break;
>> +        }
>> +        if (minor_rev != 1) {
>> +            hcd->speed = HCD_USB3;
>> +            hcd->self.root_hub->speed = USB_SPEED_SUPER;
>> +        }
>> +    }
>>       xhci_info(xhci, "Host supports USB 3.%x %sSuperSpeed\n",
>>             minor_rev, minor_rev ? "Enhanced " : "");
> 
> How about checking if port support over 5Gbps (psiv >= 5) when we parse the protocol speed ID
> entries the first time? This way we could avoid looping through all the port_cap psiv values.
> 
> Something like:
> 
> diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
> index c4170421bc9c..2e4c80eb4972 100644
> --- a/drivers/usb/host/xhci-mem.c
> +++ b/drivers/usb/host/xhci-mem.c
> @@ -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,11 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int 
> num_ports,
>                   */
>                  if (minor_revision > 0x00 && minor_revision < 0x10)
>                          minor_revision <<= 4;
> +               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 +1994,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 +2011,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 +2031,10 @@ 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 &&
> +                           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 +2044,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;
> +

This patch solution is effective and concise. Thanks for your suggestion.
I'll adopt it in next patch version after other patches of this patch set
are reviewed or suggested.

Best Regards,
Weitao
>          /* cache usb2 port capabilities */
>          if (major_revision < 0x03 && xhci->num_ext_caps < max_caps)
>                  xhci->ext_caps[xhci->num_ext_caps++] = temp;
> 
> Thanks
> Mathias
> .
diff mbox series

Patch

diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 6307bae9cddf..31d6ace9cace 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -5294,6 +5294,7 @@  static void xhci_hcd_init_usb2_data(struct xhci_hcd *xhci, struct usb_hcd *hcd)
 static void xhci_hcd_init_usb3_data(struct xhci_hcd *xhci, struct usb_hcd *hcd)
 {
 	unsigned int minor_rev;
+	unsigned int i, j;
 
 	/*
 	 * Early xHCI 1.1 spec did not mention USB 3.1 capable hosts
@@ -5323,6 +5324,27 @@  static void xhci_hcd_init_usb3_data(struct xhci_hcd *xhci, struct usb_hcd *hcd)
 		hcd->self.root_hub->ssp_rate = USB_SSP_GEN_2x1;
 		break;
 	}
+
+	/* Usb3.1 has gen1 and gen2, Some zhaoxin's xHCI controller
+	 * that follow usb3.1 spec but only support gen1.
+	 */
+	if (xhci->quirks & XHCI_ZHAOXIN_HOST) {
+		minor_rev = 0;
+		for (j = 0; j < xhci->num_port_caps; j++) {
+			for (i = 0; i < xhci->port_caps[j].psi_count; i++) {
+				if (XHCI_EXT_PORT_PSIV(xhci->port_caps[j].psi[i]) >= 5) {
+					minor_rev = 1;
+					break;
+				}
+			}
+			if (minor_rev)
+				break;
+		}
+		if (minor_rev != 1) {
+			hcd->speed = HCD_USB3;
+			hcd->self.root_hub->speed = USB_SPEED_SUPER;
+		}
+	}
 	xhci_info(xhci, "Host supports USB 3.%x %sSuperSpeed\n",
 		  minor_rev, minor_rev ? "Enhanced " : "");