mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Kean Ren <rh_king@163.com>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Mathias Nyman <mathias.nyman@intel.com>
Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org,
	Alan Stern <stern@rowland.harvard.edu>,
	Griffin Kroah-Hartman <griffin@kroah.com>,
	Kuen-Han Tsai <khtsai@google.com>, Kees Cook <kees@kernel.org>,
	Nikhil Solanke <nikhilsolanke5@gmail.com>,
	Thorsten Blum <blum@kernel.org>, Kean Ren <rh_king@163.com>
Subject: [PATCH 2/2] xhci: fix ASM3242 port speed report for Gen 2x2 links after cold boot
Date: Sun, 20 Sep 2026 10:52:43 +0800	[thread overview]
Message-ID: <20260920025308.2358862-3-rh_king@163.com> (raw)
In-Reply-To: <20260920025308.2358862-1-rh_king@163.com>

The ASMedia ASM3242 (1b21:3242) reports the SuperSpeed speed ID (4) in
PORTSC[13:10], together with two active lanes, for a link that is
actually running at Gen 2x2 after a cold boot.
xhci_get_ext_port_status() copies that ID into dwExtPortStatus, so the
USB core matches SSID 4 (whose LP is SuperSpeed, not SuperSpeedPlus),
returns USB_SSP_GEN_UNKNOWN and falls back to USB_SPEED_SUPER:

  $ lsusb -t
      |__ Port 001: Dev 002, If 0, Class=Mass Storage, Driver=uas, 5000M/x2
  $ cat /sys/bus/usb/devices/2-1/speed
  5000

while the link really runs at 20 Gbps:

  GetPortStatus(HUB_EXT_PORT_STATUS) -> dwExtPortStatus = 0x00001144
      (RX/TX speed id 4, RX/TX lanes 2)     after a cold boot
  GetPortStatus(HUB_EXT_PORT_STATUS) -> dwExtPortStatus = 0x00001177
      (RX/TX speed id 7, RX/TX lanes 2)     after an S3 resume

  O_DIRECT throughput, cross-checked with /proc/diskstats:
      1.49 - 1.60 GB/s (11.9 - 12.8 Gbps)  in the "5000M" state
      1.63 - 1.83 GB/s (13.0 - 14.7 Gbps)  in the "20000M" state

Both exceed the physical ceiling of a 10 Gbps link (~1.25 GB/s), so the
link is Gen 2x2 in both states and only the controller's report is
wrong.  Only an S3 suspend/resume makes the controller report speed ID
7; a device re-plug, a port disable/enable, an xhci_hcd unbind/bind, a
PCI function reset and a PCI remove+rescan all leave the wrong value in
place.

Add XHCI_ASM3242_SPEED_QUIRK and, when it is set, report the Gen 2x2
speed ID when the controller reports SuperSpeed with two active lanes.

Reported-by: Kean Ren <rh_king@163.com>
Link: https://lore.kernel.org/linux-usb/<your-report-message-id>/
Signed-off-by: Kean Ren <rh_king@163.com>
---
 drivers/usb/host/xhci-hub.c | 17 +++++++++++++++--
 drivers/usb/host/xhci-pci.c |  4 ++++
 drivers/usb/host/xhci.h     |  1 +
 3 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 470bafe1802b..ef2b35b31492 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -1001,13 +1001,26 @@ static int xhci_handle_usb2_port_link_resume(struct xhci_port *port,
 	return 0;
 }
 
-static u32 xhci_get_ext_port_status(u32 portsc, u32 port_li)
+static u32 xhci_get_ext_port_status(struct xhci_hcd *xhci, u32 portsc,
+				    u32 port_li)
 {
 	u32 ext_stat = 0;
 	int speed_id;
 
 	/* only support rx and tx lane counts of 1 in usb3.1 spec */
 	speed_id = DEV_PORT_SPEED(portsc);
+
+	/*
+	 * The ASM3242 reports the SuperSpeed speed ID (4) together with two
+	 * active lanes for a link that is actually running at Gen 2x2 after a
+	 * cold boot.  Reporting that ID makes the USB core fall back to
+	 * USB_SPEED_SUPER (5000 Mbps) although the link runs at 20 Gbps, so
+	 * report the Gen 2x2 speed ID (7) instead.
+	 */
+	if ((xhci->quirks & XHCI_ASM3242_SPEED_QUIRK) && speed_id == 4 &&
+	    PORT_RX_LANES(port_li) && PORT_TX_LANES(port_li))
+		speed_id = 7;
+
 	ext_stat |= speed_id;		/* bits 3:0, RX speed id */
 	ext_stat |= speed_id << 4;	/* bits 7:4, TX speed id */
 
@@ -1265,7 +1278,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
 				break;
 			}
 			port_li = readl(&port->port_reg->portli);
-			status = xhci_get_ext_port_status(portsc, port_li);
+			status = xhci_get_ext_port_status(xhci, portsc, port_li);
 			put_unaligned_le32(status, &buf[4]);
 		}
 		break;
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index a8889081ae82..6219151d9eb0 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -471,6 +471,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
 	     pdev->device == PCI_DEVICE_ID_ASMEDIA_3242_XHCI))
 		xhci->quirks |= XHCI_NO_64BIT_SUPPORT;
 
+	if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
+	    pdev->device == PCI_DEVICE_ID_ASMEDIA_3242_XHCI)
+		xhci->quirks |= XHCI_ASM3242_SPEED_QUIRK;
+
 	if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
 		pdev->device == PCI_DEVICE_ID_ASMEDIA_1042A_XHCI)
 		xhci->quirks |= XHCI_ASMEDIA_MODIFY_FLOWCONTROL;
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index c7bfa7f028d3..77fab2f29693 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1647,6 +1647,7 @@ struct xhci_hcd {
 #define XHCI_CDNS_SCTX_QUIRK	BIT_ULL(48)
 #define XHCI_ETRON_HOST	BIT_ULL(49)
 #define XHCI_LIMIT_ENDPOINT_INTERVAL_9 BIT_ULL(50)
+#define XHCI_ASM3242_SPEED_QUIRK	BIT_ULL(51)
 
 	unsigned int		num_active_eps;
 	unsigned int		limit_active_eps;


      parent reply	other threads:[~2026-09-20  2:54 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-20  2:52 [PATCH 0/2] usb: fix ASM3242 reporting SuperSpeed for a Gen 2x2 link Kean Ren
2026-09-20  2:52 ` [PATCH 1/2] usb: core: hub: recognise two-lane SuperSpeed sublinks as Gen 1x2 Kean Ren
2026-09-20  2:52 ` Kean Ren [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260920025308.2358862-3-rh_king@163.com \
    --to=rh_king@163.com \
    --cc=blum@kernel.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=griffin@kroah.com \
    --cc=kees@kernel.org \
    --cc=khtsai@google.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=mathias.nyman@intel.com \
    --cc=nikhilsolanke5@gmail.com \
    --cc=stern@rowland.harvard.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®