[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <CACF_Uwo2jZ2duXm_B6GdcLd3yPr0+CJ0sCBTDRqwkuX_KF81Ug@mail.gmail.com>
Date: Tue, 22 Jul 2025 23:59:40 +0200
From: Marco Tormento <mtormento80@...il.com>
To: Alan Stern <stern@...land.harvard.edu>
Cc: gregkh@...uxfoundation.org, linux-usb@...r.kernel.org,
linux-kernel@...r.kernel.org
Subject: Re: [PATCH] USB: hub: Move typec deattach before children
disconnections in usb_disconnect()
On Tue, 22 Jul 2025 at 05:05, Alan Stern <stern@...land.harvard.edu> wrote:
>
> On Tue, Jul 22, 2025 at 01:18:25AM +0200, Marco Tormento wrote:
> > On Mon, 21 Jul 2025 at 03:21, Alan Stern <stern@...land.harvard.edu> wrote:
> > > I'm not a typec expert; in fact I know practically nothing about it.
> > > Nevertheless, this sounds strange. The recursive usb_disconnect() calls
> > > should affect the connectors to the monitor's children and the monitor's
> > > own ports, not the connector or port on the monitor's parent hub.
> >
> > What you wrote makes total sense, let me add some detail though.
> > When I plug the monitor to the thunderbolt port, 3 usb hubs pop up, but only 2
> > are backed by XHCI Host Controllers: usb3 and usb4.
>
> I don't know what you mean when you say "backed by". usb3 and usb4 are
> the two root hubs of the xHCI host controller. usb3-1 is an internal
> hub (presumably built into the monitor) attached to the usb3 root hub.
Mine was a failed attempt at expressing what you wrote :-).
My understanding is that usb3 and usb4 root hubs are somehow part of the
thunderbolt controller, because they are not brought up if I plug the monitor
into the other typec port.
> > typec port0: bound usb3-port1 (ops connector_ops [usbcore])
> > typec port0: bound usb4-port1 (ops connector_ops [usbcore])
> > typec port1: bound usb3-port2 (ops connector_ops [usbcore])
> > typec port1: bound usb4-port2 (ops connector_ops [usbcore])
>
> Why are the usb3 port connectors getting bound at this point rather than
> when usb3 was registered?
Not sure, but maybe this is a consequence of the fact usb4 is on a shared hcd of
usb3 pci device? See the stack traces below.
> > When I unplug the monitor though, usb 3-1 is not processed as part of
> > hub_disconnect_children() of usb3 hub, as I would expect.
>
> Are you sure about this? How did you reach that conclusion?
I checked the stack traces of usb_disconnect().
usb 3-1 is triggered by hub_event():
usb 3-1: [usb_disconnect] debugging()
...cut...
Workqueue: usb_hub_wq hub_event [usbcore]
Call Trace:
<TASK>
dump_stack_lvl+0x5d/0x80
usb_disconnect+0x38/0x2f4 [usbcore d46dddc5902949f0a284aff7ecf8d6e861774323]
hub_event.cold+0x73e/0xc50 [usbcore d46dddc5902949f0a284aff7ecf8d6e861774323]
...cut
usb4 is not:
usb usb4: [usb_disconnect] debugging()
...cut...
Workqueue: kacpi_hotplug acpi_hotplug_work_fn
Call Trace:
<TASK>
dump_stack_lvl+0x5d/0x80
usb_disconnect+0x38/0x2f4 [usbcore d46dddc5902949f0a284aff7ecf8d6e861774323]
usb_remove_hcd.cold+0xc6/0x1bb [usbcore
d46dddc5902949f0a284aff7ecf8d6e861774323]
xhci_pci_remove+0x6a/0xd0 [xhci_pci 89d1427fd34e7648221e69cd90b20ad6e1fd2fd6]
pci_device_remove+0x47/0xc0
...cut
usb3 is a little bit different compared to usb4, it has a call to
usb_hcd_pci_remove():
usb usb3: [usb_disconnect] debugging()
...cut...
Workqueue: kacpi_hotplug acpi_hotplug_work_fn
Call Trace:
<TASK>
dump_stack_lvl+0x5d/0x80
usb_disconnect+0x38/0x2f4 [usbcore d46dddc5902949f0a284aff7ecf8d6e861774323]
usb_remove_hcd.cold+0xc6/0x1bb [usbcore
d46dddc5902949f0a284aff7ecf8d6e861774323]
usb_hcd_pci_remove+0x7a/0x110 [usbcore
d46dddc5902949f0a284aff7ecf8d6e861774323]
xhci_pci_remove+0x89/0xd0 [xhci_pci 89d1427fd34e7648221e69cd90b20ad6e1fd2fd6]
pci_device_remove+0x47/0xc0
...cut
There's a branch in xhci_pci_remove() on xhci->shared_hcd being valid.
So it seems:
- xhci_pci_remove() is called
- xhci->shared_hcd is valid so usb_remove_hcd() is called which triggers usb4
usb_disconnect()
- usb_hcd_pci_remove() is then called which does a lot of stuff + calls
usb_remove_hcd() which triggers usb3 usb_disconnect()
No idea what this shared hcd implies, by the way.
I also got this stack trace of the port unbinding, which happens
in typec_aggregate_unbind() in the usb4 usb_disconnect() trace:
usb usb4: [hub_disconnect] debugging
usb usb4-port2: [usb_hub_remove_port_device] debugging: port 1
...cut...
Workqueue: kacpi_hotplug acpi_hotplug_work_fn
Call Trace:
<TASK>
dump_stack_lvl+0x5d/0x80
typec_aggregate_unbind+0x12/0x30 [typec
6de6f75aa8c9f6a0a8c73a05ed9c668a2b7634cf]
component_del+0xb8/0x150
usb_hub_remove_port_device+0xf8/0x115 [usbcore
d46dddc5902949f0a284aff7ecf8d6e861774323]
hub_disconnect+0x95/0x160 [usbcore d46dddc5902949f0a284aff7ecf8d6e861774323]
usb_unbind_interface+0xb6/0x1ef [usbcore
d46dddc5902949f0a284aff7ecf8d6e861774323]
? kernfs_remove_by_name_ns+0xbe/0xe0
device_release_driver_internal+0x19e/0x200
bus_remove_device+0xc2/0x130
device_del+0x160/0x3d0
? kobject_put+0xa2/0x200
usb_disable_device+0xf4/0x220 [usbcore
d46dddc5902949f0a284aff7ecf8d6e861774323]
usb_disconnect+0x117/0x2f4 [usbcore d46dddc5902949f0a284aff7ecf8d6e861774323]
usb_remove_hcd.cold+0xc6/0x1bb [usbcore
d46dddc5902949f0a284aff7ecf8d6e861774323]
xhci_pci_remove+0x6a/0xd0 [xhci_pci 89d1427fd34e7648221e69cd90b20ad6e1fd2fd6]
pci_device_remove+0x47/0xc0
...cut...
</TASK>
typec port1: [connector_unbind] unbinding connector from usb4-port2
typec port1: [connector_unbind] unbinding connector from usb3-port2
> > Maybe usb 3-1 should be disconnected as a child of usb3, but even in that case
> > we would still end up in the same situation because it's usb4 disconnection that
> > is doing the unbinding.
> > Since there's no dependency between usb3 and usb4 they can be
> > disconnected in any order and it's just a matter of luck as it is right now.
>
> That last sentence is totally wrong. usb3 and usb4 are closely
> connected, since they represent logical components of the same xHCI
> controller, and they will always be unregistered in the same order.
> usb3 is the USB-2 root hub (the one connected to the physical wires
> carrying the USB-2 low/full/high-speed signals), and usb4 is the USB-3
> root hub (the one connected to the physical wires carrying the USB-3
> SuperSpeed and SuperSpeedPlus signals).
That makes a lot of sense.
Unfortunately I realized this could be the order half an hour after having
pressed "send"...
Thank you for the explanation!
> This still leaves the puzzle about why the typec things are handled this
> way. In particular, if connector_unbind undoes the binding of the typec
> ports that happened when usb4 was registered, then what action is
> typec_unregister_partner supposed to undo, and when was it supposed to
> happen? As a general rule, disconnection and unregistration actions
> take place in the reverse order of the corresponding connection and
> registration actions.
>
> Questions like this are best directed at the maintainers of the
> USB-4/Thunderbolt and typec subsystems.
Should I just cc them here or should I open a new thread with them?
Marco Tormento
Powered by blists - more mailing lists