XHCI: Address Device command fails for devices behind a hub

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
qookie
Member
Member
Posts: 73
Joined: Sun Apr 30, 2017 12:16 pm
Libera.chat IRC: qookie
Location: Poland

XHCI: Address Device command fails for devices behind a hub

Post by qookie »

Hi,

as stated in the title, I've a problem with the Address Device command failing with an USB transaction error for devices that are behind a hub. According to the XHCI spec this means that the SET_ADDRESS request has failed, but I can't think of a reason why.
I've tried a few of HS, FS and LS devices, and noticed that it only fails for HS devices. One thing also worth noting is that one device I tried is an USB 3 SSD, which is addressed correctly when plugged into an USB 3 root port, and yet fails when plugged into the USB 2 hub port.

I've observed this on a Raspberry Pi 4, which uses the VL805 XHCI controller, which has an integrated 4 port USB 2 hub (which is the main reason for implementing hub support right now), and I unfortunately don't have any other USB 2 HS hubs (only an FS one).

The code for the XHCI driver can be found here: https://github.com/qookei/managarm/tree ... s/xhci/src, and the USB hub driver code is here https://github.com/qookei/managarm/blob ... rc/hub.cpp.
One point of interest is the place the device is actually addressed: https://github.com/qookei/managarm/blob ... #L830-L902

For reference, here are the logs produced by this code:
Image
Working on managarm.
User avatar
BenLunt
Member
Member
Posts: 1039
Joined: Sat Nov 22, 2014 6:33 pm
Location: USA
Contact:

Re: XHCI: Address Device command fails for devices behind a

Post by BenLunt »

When you are setting the address of the device, you aren't actually sending the SET_ADDRESS request, correct? xHCI does not allow the SET_ADDRESS request to populate the bus.

You must send the Set Address command twice, once to set the address of the device (Block bit set), then a little bit later to let the xHCI send the SET_ADDRESS request (Block bit clear).

Also, since it is only happening on High-speed devices, it probably isn't with your "addressDevice()" code. It probably is something else pertaining to the way you set your CONTEXTs with high-speed devices.

Is the hub a high-speed hub? You say you only have a full-speed hub. Remember, a high-speed device plugged into a full-speed hub is now a full-speed device. You have to account for this.

Ben
User avatar
qookie
Member
Member
Posts: 73
Joined: Sun Apr 30, 2017 12:16 pm
Libera.chat IRC: qookie
Location: Poland

Re: XHCI: Address Device command fails for devices behind a

Post by qookie »

Hi Ben, thanks for responding.
BenLunt wrote:When you are setting the address of the device, you aren't actually sending the SET_ADDRESS request, correct? xHCI does not allow the SET_ADDRESS request to populate the bus.
Correct, I'm letting the controller do it via the Address Device command. I only mentioned it because the spec says that that error happens when the SET_ADDRESS request failed (stall or such).
BenLunt wrote:You must send the Set Address command twice, once to set the address of the device (Block bit set), then a little bit later to let the xHCI send the SET_ADDRESS request (Block bit clear).
Could you expand on what the correct order of commands to the controller would be? Currently my code does:
1. Enable Slot,
2. Address Device (with the slot and EP1 contexts set up in the input context) with BSR=0

And afterwards carries on with the device, it reads the device descriptor to get the class, vendor and product IDs etc, and finally at the request of a class/device-specific driver reads more descriptors, sets up other EPs as per the configuration descriptor (via the Configure Endpoint command), and sets the configuration via SET_CONFIGURATION request.

As mentioned this order of things works for one of the USB 3 devices I tried when plugged into an USB 3 root port instead of the HS hub, so it is probably indeed likely that this is not the problem in this case.
BenLunt wrote:Also, since it is only happening on High-speed devices, it probably isn't with your "addressDevice()" code. It probably is something else pertaining to the way you set your CONTEXTs with high-speed devices.
As far as I can tell the only difference is that LS/FS devices require the hub slot and port number fields filled out for split transactions, and for HS those fields should be 0, which is what I do in my code.
BenLunt wrote:Is the hub a high-speed hub? You say you only have a full-speed hub. Remember, a high-speed device plugged into a full-speed hub is now a full-speed device. You have to account for this.
The hub I was testing with is integrated into the XHCI controller chip, which has only one USB 2 root port, and an integrated 4 port hub (but 4 USB 3 root ports and no hub on those). The FS hub I mentioned is a standalone one, and I only mentioned it to say I can't test other HS hubs or on any other controller etc.
Working on managarm.
rdos
Member
Member
Posts: 3396
Joined: Wed Oct 01, 2008 1:55 pm

Re: XHCI: Address Device command fails for devices behind a

Post by rdos »

I'm more inclined to think that the hub is handled incorrectly. USB 2 hubs must be programmed correctly, which include the speed of the device connected to ports. The hub itself is running as an USB 2 device, but the hub ports either are directly connected or go through a transaction interface that converts to lower speed. This is not automatic. I think that is why certain device types works while other doesn't.
Gigasoft
Member
Member
Posts: 871
Joined: Sat Nov 21, 2009 5:11 pm

Re: XHCI: Address Device command fails for devices behind a

Post by Gigasoft »

You must send the Set Address command twice, once to set the address of the device (Block bit set), then a little bit later to let the xHCI send the SET_ADDRESS request (Block bit clear).
This is usually not required. The BSR bit exists only as a workaround for some broken device or devices which the specification does not name, which require a nonstandard initialization sequence.
User avatar
BenLunt
Member
Member
Posts: 1039
Joined: Sat Nov 22, 2014 6:33 pm
Location: USA
Contact:

Re: XHCI: Address Device command fails for devices behind a

Post by BenLunt »

Gigasoft wrote:
You must send the Set Address command twice, once to set the address of the device (Block bit set), then a little bit later to let the xHCI send the SET_ADDRESS request (Block bit clear).
This is usually not required. The BSR bit exists only as a workaround for some broken device or devices which the specification does not name, which require a nonstandard initialization sequence.
And you are absolutely correct. However, how do you know that the user hasn't plugged one of these broken devices into the port? This is the reason for the multiple calls. :-)
Sending the address command once, works on most devices, while sending it twice (as I suggest) works on most devices "plus" those broken devices. I have witnessed this personally.

Cheers,
Ben
User avatar
qookie
Member
Member
Posts: 73
Joined: Sun Apr 30, 2017 12:16 pm
Libera.chat IRC: qookie
Location: Poland

Re: XHCI: Address Device command fails for devices behind a hub

Post by qookie »

Hi. It's been a very long time, but I recently came across my own post when looking for something else, so I figured I'd post an update.

I've recently managed to solve the OP issue and some other hub-related issues. The problem in the OP was actually caused by broken computation of the route string and root port number in the slot contexts for devices behind hubs. Another two issues I ran into right after were filling out the parent hub port and slot numbers for devices that don't need to go through a TT (e.g. for an FS device plugged into an FS hub plugged into a HS hub), and the fact that the port speed bits from GET_PORT_STATUS are only valid once the device is in the enabled state (which caused the logic to treat HS devices as FS instead).

For both of these issues I've used a USB protocol analyzer (https://github.com/ataradov/usb-sniffer, preassembled units can be found on AliExpress for relatively cheap). For the former the clue was the fact no traffic was making it to the hub despite the USB transaction error, for the latter it was seeing SPLIT token packets making their way to a HS device. As far as I remember, no emulator has caught these issues, which is unfortunate.

In case anyone finds it useful, the changes can be found here: https://github.com/managarm/managarm/pull/1242 (do note the driver also underwent some refactoring compared to the branch in the OP).

I do agree it'd still be a good idea to implement getting the device descriptor before SET_ADDRESS just to be sure we cover everything (and I should even have a WIP impl somewhere in my git stash...), but so far I haven't ran into any device that needs it.
Working on managarm.
User avatar
BenLunt
Member
Member
Posts: 1039
Joined: Sat Nov 22, 2014 6:33 pm
Location: USA
Contact:

Re: XHCI: Address Device command fails for devices behind a hub

Post by BenLunt »

qookie wrote: ↑Sat Apr 11, 2026 2:53 am I've recently managed to solve the OP issue and some other hub-related issues.
Glad to hear it.
qookie wrote: ↑Sat Apr 11, 2026 2:53 am The problem in the OP was actually caused by broken computation of the route string and root port number in the slot contexts for devices behind hubs. Another two issues I ran into right after were filling out the parent hub port and slot numbers for devices that don't need to go through a TT (e.g. for an FS device plugged into an FS hub plugged into a HS hub), and the fact that the port speed bits from GET_PORT_STATUS are only valid once the device is in the enabled state (which caused the logic to treat HS devices as FS instead).
...
As far as I remember, no emulator has caught these issues, which is unfortunate.
(Just to clarify, the specification states that the speed bits are only valid after a reset. Granted after a reset, a connection should then move to the enabled state. Therefore, in all intents and purposes, the bits are really only valid after an enable, which is as you state here. I just wanted to clarify)

Bochs does implement the speed bits correctly, *but* does not give a warning if the port register is read while not in the enabled state. Since it is common to read the port register while not enabled, it would be difficult to not flood the log with a warning as such. Let me think about it.

As for the other checks you mention, they are valid requests and I may be able to implement something to place warnings in the Bochs' log file when these issues occur. When I get a chance, I will take a look.
qookie wrote: ↑Sat Apr 11, 2026 2:53 am I do agree it'd still be a good idea to implement getting the device descriptor before SET_ADDRESS just to be sure we cover everything (and I should even have a WIP impl somewhere in my git stash...), but so far I haven't ran into any device that needs it.
It has been quite a few years since I have found a device that requires it as well.

Thank you for following up with your results. It is appreciated.

Ben
- https://www.fysnet.net/the_universal_serial_bus.htm
Post Reply