Linux USB
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Arun Iyengar" <aiyengar1990@gmail.com>
Cc: linux-usb@vger.kernel.org
Subject: Re: [PATCH v4 1/2] usb: core: Pair ports of different hubs through their connector
Date: Sun, 15 Nov 2026 09:50:30 +0000	[thread overview]
Message-ID: <sashiko-outbox-215380@kernel.org> (raw)
In-Reply-To: <20261115-usb-port-pairing-v4-1-25d3c9adcc21@gmail.com>

Thank you for your contribution! Sashiko AI review found 3 potential
issues to consider:
- [High] usb: core: OF graph port numbering mismatch in
  usb_port_graph_id()
- [Medium] usb: core: raw port number not passed to
  usb_of_get_connect_type()
- [Medium] usb: core: update connect_type and connector_peer after
  device_register()
--

commit a8c7879971bee16d5ebf91273578d78c7dde5445
Author: Arun Iyengar <aiyengar1990@gmail.com>

usb: core: Pair ports of different hubs through their connector

This commit pairs USB 2.0 and SuperSpeed ports across different hubs or
host controllers when they are linked to the same usb-connector node in
the OF graph.

> diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
> index b4452b665f591..5b2041d891eca 100644
> --- a/drivers/usb/core/port.c
> +++ b/drivers/usb/core/port.c
> @@ -649,10 +649,49 @@ static int match_location(struct usb_device *peer_hdev, void *p)
>  	return 0;
>  }
>  
> +static u32 usb_port_graph_id(struct usb_device *hdev, int port1)
> +{
> +	if (hdev->parent)
> +		return port1;
> +	return usb_hcd_find_raw_port_number(bus_to_hcd(hdev->bus), port1);
> +}
> +
> +struct usb_connector_peer {
> +	struct usb_port *port_dev;
> +	struct device_node *np;
> +	u32 port;
> +};
> +
> +static int match_connector_peer(struct usb_device *peer_hdev, void *p)
> +{
> +	struct usb_connector_peer *cp = p;
> +	struct usb_hub *peer_hub = usb_hub_to_struct_hub(peer_hdev);
> +	struct usb_port *peer;
> +	int port1;
> +
> +	if (!peer_hub || peer_hdev->dev.of_node != cp->np ||
> +	    hub_is_superspeed(peer_hdev) == cp->port_dev->is_superspeed)
> +		return 0;
> +
> +	for (port1 = 1; port1 <= peer_hdev->maxchild; port1++) {
> +		if (usb_port_graph_id(peer_hdev, port1) == cp->port)
> +			break;
> +	}

[Severity: High]
Does usb_port_graph_id() match the OF graph port numbering used by USB
controller bindings, and does usb_of_get_connector_peer() leave USB 2.0
ports unpeered when the peer controller uses dwc3 graph numbering?

On dwc3 xHCI controllers, xhci_find_raw_port_number() returns 1 for the
High-Speed root hub port and 2 for the SuperSpeed root hub port, whereas
USB controller DT bindings (such as snps,dwc3-common.yaml and
rockchip,dwc3.yaml) define port@0 as High-Speed and port@1 as SuperSpeed.

When find_and_link_peer() runs for a USB 2.0 hub port whose connector
port@1 points to a dwc3 controller's port@1 (as on
rk3576-lckfb-tspi-3m.dts), usb_of_get_connector_peer() checks !*peer_port,
which rejects port@0 when starting from a SuperSpeed port but accepts
*peer_port == 1 when starting from a USB 2.0 port.  find_and_link_peer()
then sets port_dev->connector_peer = 1 and returns early, while
match_connector_peer() compares usb_port_graph_id() (2) against cp->port
(1) and fails to link the ports.  Meanwhile, when the dwc3 SuperSpeed root
hub port runs find_and_link_peer(), usb_port_graph_id() returns 2, which
misses port@1 on the controller node and falls through to default peering
with the wrong port (or is blocked by !peer->connector_peer when the
default peer was already marked).

> @@ -671,7 +711,21 @@ static void find_and_link_peer(struct usb_hub *hub, int port1)
>  		/* we link the peer in match_location() if found */
>  		usb_for_each_dev(port_dev, match_location);
>  		return;
> -	} else if (!hdev->parent) {
> +	}
> +
> +	cp.np = usb_of_get_connector_peer(hdev, usb_port_graph_id(hdev, port1),
> +					  port_dev->is_superspeed, &cp.port);
> +	if (cp.np) {
> +		cp.port_dev = port_dev;
> +		port_dev->connector_peer = 1;

[Severity: Medium]
Does setting port_dev->connector_peer and port_dev->connect_type in
find_and_link_peer() happen too late, after device_register() has already
exposed the port to sysfs?

In usb_hub_create_port_device(), device_register(&port_dev->dev) publishes
the sysfs attributes and emits KOBJ_ADD before find_and_link_peer() runs.
Userspace handlers reacting to KOBJ_ADD can read the stale connect_type,
and the unlocked bitfield write to connector_peer can race with sysfs
writes to sibling bitfields in struct usb_port (early_stop_store() and
usb3_lpm_permit_store()):

CPU0                                  CPU1
usb_hub_create_port_device()
  device_register(&port_dev->dev)
                                      early_stop_store()
                                        port_dev->early_stop = ...
  find_and_link_peer()
    port_dev->connector_peer = 1;
    <-- bitfield RMW clobbers early_stop

> +		/* usb_of_get_connect_type() misses graph ports */
> +		port_dev->connect_type = USB_PORT_CONNECT_TYPE_HOT_PLUG;

[Severity: Medium]
Why does find_and_link_peer() override port_dev->connect_type here instead
of usb_hub_create_port_device() passing usb_port_graph_id(hdev, port1) to
usb_of_get_connect_type()?

usb_of_get_connect_type() already checks OF graph endpoints via
of_graph_get_endpoint_by_regs(), but usb_hub_create_port_device() passes
the HCD-relative port1 index instead of the controller's raw port number:

drivers/usb/core/port.c:usb_hub_create_port_device() {
    ...
	port_dev->connect_type = usb_of_get_connect_type(hdev, port1);
    ...
}

On a split-roothub controller where usb_port_graph_id(hdev, port1) !=
port1, usb_of_get_connect_type() inspects the wrong port number on the
controller DT node.  Whenever usb_of_get_connector_peer() returns NULL
(for example, when both ports of the connector belong to the same
controller node, or for a hardwired child device node), connect_type is
never fixed up and remains wrong (such as USB_PORT_NOT_USED), causing
set_usb_port_removable() to misclassify hotplugged devices as fixed.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261115-usb-port-pairing-v4-0-25d3c9adcc21@gmail.com?part=1

  reply	other threads:[~2026-11-15  9:50 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-15  8:57 [PATCH v4 0/2] usb: core: Pair ports of different host controllers through their connector Arun Iyengar via B4 Relay
2026-11-15  8:57 ` [PATCH v4 1/2] usb: core: Pair ports of different hubs " Arun Iyengar via B4 Relay
2026-11-15  9:50   ` sashiko-bot [this message]
2026-11-15  8:57 ` [PATCH v4 2/2] usb: hub: Retry SuperSpeed for a device stuck on its USB 2.0 peer Arun Iyengar via B4 Relay
2026-11-15  9:27   ` sashiko-bot

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=sashiko-outbox-215380@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=aiyengar1990@gmail.com \
    --cc=linux-usb@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /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