Re: [PATCH v9 06/15] usb: hub: Associate port@ fwnode with USB port device

From: Chen-Yu Tsai

Date: Thu Oct 01 2026 - 06:56:42 EST


On Wed, Sep 16, 2026 at 3:58 PM Chen-Yu Tsai <wenst@xxxxxxxxxxxx> wrote:
>
> When a USB hub port is connected to a connector in a firmware node
> graph, the port itself has a node in the graph.
>
> Associate the port's firmware node with the USB port's device,
> usb_port::dev. This is used in later changes for the M.2 slot power
> sequencing provider to match against the requesting port.
>
> To avoid potential conflicts with ACPI firmware nodes and then causing
> power management issues, only assign the firmware node if the hub's
> firmware node is not an ACPI firmware node.
>
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx>
> Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@xxxxxxxxxxxxxxxx>
> Signed-off-by: Chen-Yu Tsai <wenst@xxxxxxxxxxxx>
> ---
> Changes since v5:
> - Added extra |struct fwnode_handle *| local variables to shorten lines
> (Andy)
> - Added comment about passing fwnode_graph_get_port_by_id() return value
> directly to device_set_node() (Andy)
>
> Changes since v4:
> - Dropped unused |hdev| variable
> - Added flags for fwnode_graph_get_port_by_id() with
> FWNODE_GRAPH_DEVICE_DISABLED so that even incomplete
> ports can be connected
>
> Changes since v3:
> - Added missing fwnode_handle_put()
>
> Changes since v2:
> - Skip assignment if hub firmware node is ACPI node
> ---
> drivers/usb/core/port.c | 25 +++++++++++++++++++++++++
> 1 file changed, 25 insertions(+)
>
> diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
> index b4452b665f59..c0a51d9b06a6 100644
> --- a/drivers/usb/core/port.c
> +++ b/drivers/usb/core/port.c
> @@ -7,6 +7,7 @@
> * Author: Lan Tianyu <tianyu.lan@xxxxxxxxx>
> */
>
> +#include <linux/acpi.h>
> #include <linux/kstrtox.h>
> #include <linux/slab.h>
> #include <linux/string_choices.h>
> @@ -358,6 +359,11 @@ static void usb_port_device_release(struct device *dev)
> {
> struct usb_port *port_dev = to_usb_port(dev);
>
> + /*
> + * At this point ACPI nodes and swnodes have been removed by
> + * device_platform_notify_remove() in device_del().
> + */
> + fwnode_handle_put(dev_fwnode(dev));
> kfree(port_dev->req);
> kfree(port_dev);
> }
> @@ -754,6 +760,7 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1)
> {
> struct usb_port *port_dev;
> struct usb_device *hdev = hub->hdev;
> + struct fwnode_handle *fwnode = dev_fwnode(&hdev->dev);
> int retval;
>
> port_dev = kzalloc_obj(*port_dev);
> @@ -782,6 +789,24 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1)
> port_dev->dev.driver = &usb_port_driver;
> dev_set_name(&port_dev->dev, "%s-port%d", dev_name(&hub->hdev->dev),
> port1);
> +
> + /*
> + * ACPI FW nodes are associated later when device_register() happens.
> + * Skip assigning one here to avoid potential conflicts.
> + */
> + if (!is_acpi_node(fwnode)) {
> + struct fwnode_handle *port;
> +
> + /*
> + * fwnode_graph_get_port_by_id() returns either a valid fwnode handle
> + * or NULL. Passing NULL to device_set_node() clears any associated
> + * fwnode. It is effectively a no-op here, since no fwnode has been
> + * assigned to the newly created device yet.
> + */
> + port = fwnode_graph_get_port_by_id(fwnode, port1, FWNODE_GRAPH_DEVICE_DISABLED);

After AI hinted, I found some dwc3 hardware to test this on.

"port1" needs to be remapped using usb_hcd_find_raw_port_number() when the
hub is the root hub. Otherwise both HS and SS ports end up getting the
same port node, which is incorrect.

Same needs to be done for "usb_of_get_connect_type(hdev, port1)" some
lines above the diff context.

This mapping is currently only done in usb_acpi_get_companion_for_port()
and usb_alloc_dev().


> + device_set_node(&port_dev->dev, port);
> + }
> +
> mutex_init(&port_dev->status_lock);
> retval = device_register(&port_dev->dev);
> if (retval) {
> --
> 2.55.0.1032.g73a4cd73de-goog
>