Commit b72eb843 authored by YD Tseng's avatar YD Tseng Committed by Greg Kroah-Hartman

usb: xhci: Fix USB 3.1 supported protocol parsing

xHCI host controllers can have both USB 3.1 and 3.0 extended speed
protocol lists. If the USB3.1 speed is parsed first and 3.0 second then
the minor revision supported will be overwritten by the 3.0 speeds and
the USB3 roothub will only show support for USB 3.0 speeds.

This was the case with a xhci controller with the supported protocol
capability listed below.
In xhci-mem.c, the USB 3.1 speed is parsed first, the min_rev of usb3_rhub
is set as 0x10.  And then USB 3.0 is parsed.  However, the min_rev of
usb3_rhub will be changed to 0x00. If USB 3.1 device is connected behind
this host controller, the speed of USB 3.1 device just reports 5G speed
using lsusb.

     00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
  00 01 08 00 00 00 00 00 40 00 00 00 00 00 00 00 00
  10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  20 02 08 10 03 55 53 42 20 01 02 00 00 00 00 00 00     //USB 3.1
  30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  40 02 08 00 03 55 53 42 20 03 06 00 00 00 00 00 00     //USB 3.0
  50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  60 02 08 00 02 55 53 42 20 09 0E 19 00 00 00 00 00     //USB 2.0
  70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

This patch fixes the issue by only owerwriting the minor revision if
it is higher than the existing one.

[reword commit message -Mathias]
Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarYD Tseng <yd_tseng@asmedia.com.tw>
Signed-off-by: default avatarMathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 8ada5f3a
...@@ -2119,11 +2119,12 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, ...@@ -2119,11 +2119,12 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
{ {
u32 temp, port_offset, port_count; u32 temp, port_offset, port_count;
int i; int i;
u8 major_revision; u8 major_revision, minor_revision;
struct xhci_hub *rhub; struct xhci_hub *rhub;
temp = readl(addr); temp = readl(addr);
major_revision = XHCI_EXT_PORT_MAJOR(temp); major_revision = XHCI_EXT_PORT_MAJOR(temp);
minor_revision = XHCI_EXT_PORT_MINOR(temp);
if (major_revision == 0x03) { if (major_revision == 0x03) {
rhub = &xhci->usb3_rhub; rhub = &xhci->usb3_rhub;
...@@ -2137,7 +2138,9 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, ...@@ -2137,7 +2138,9 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
return; return;
} }
rhub->maj_rev = XHCI_EXT_PORT_MAJOR(temp); rhub->maj_rev = XHCI_EXT_PORT_MAJOR(temp);
rhub->min_rev = XHCI_EXT_PORT_MINOR(temp);
if (rhub->min_rev < minor_revision)
rhub->min_rev = minor_revision;
/* Port offset and count in the third dword, see section 7.2 */ /* Port offset and count in the third dword, see section 7.2 */
temp = readl(addr + 2); temp = readl(addr + 2);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment