Unexpected ERROR_ABORTED from CyFx3BootUsbDmaXferData in USB2 mode

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
OlJo_4577026
Level 2
Level 2

Hi

I have a second stage bootloader that uses the FX3 boot firmware library; I'm testing using the FX3 superspeed explorer kit with a custom daughterboard attached.

The bootloader works correctly when connected via USB3. However, I get unexpected USB control transfer failures when connected by USB2 in specific circumstances.

When calling CyFx3BootUsbDmaXferData() to receive data for an OUT control transfer, sometimes it will return CY_FX3_BOOT_ERROR_ABORTED unexpectedly. Setup processing doesn't block (and there is no visible delay in debug output at the point of failure), and as far as I am aware there should be no second control transfer / setup packet being received; but the SUDAV interrupt bit is definitely set at the point of failure, which is why ERROR_ABORTED ends up being returned, and the transfer does fail on the host side.

This shows up both during USB enumeration, and when using vendor control transfers. It happens when directly connected to a USB2 port, or when connected to a USB3 port with a USB2 cable, or when connected to a USB3 port but with USB3 functionality disabled in the call to CyFx3BootUsbConnect().

It seems like it is a timing- or bus-state-related problem as:

1) it only happens when the FX3 is connected directly to the host. If there is a USB hub in between, everything works fine.

2) when USB enumeration fails due to the error, the host will do a USB reset and subsequent enumeration then works OK.

3) the specific transfer which it fails on varies depending on how much debug output I have enabled (debug output is going to the UART only)

I get this failure both when loading the second-stage bootloader from EEPROM, and when loading via USB using the ROM bootloader.

I do _not_ get a failure when my separate main firmware that uses the full FX3 library is used (same USB descriptors, different code).

Any ideas what is causing this / how to work around it?

Here is an example of an enumeration failure, with the FX3 directly connected to the host. After the ERROR_ABORTED, the host does a USB reset and re-enumerates successfully:

pv2boot: USB_RESET

pv2boot: setup: type=0x80 request=0x6 wIndex=0x0 wValue=0x100 wLength=64

pv2boot:  -> EP0 write 18 bytes to host

pv2boot:  -> done

pv2boot: USB_RESET

pv2boot: setup: type=0x80 request=0x6 wIndex=0x0 wValue=0x100 wLength=18

pv2boot:  -> EP0 write 18 bytes to host

pv2boot:  -> done

pv2boot: setup: type=0x80 request=0x6 wIndex=0x0 wValue=0xF00 wLength=5

pv2boot:  -> EP0 write 5 bytes to host

pv2boot:  -> done

pv2boot: setup: type=0x80 request=0x6 wIndex=0x0 wValue=0xF00 wLength=22

pv2boot:  -> EP0 write 22 bytes to host

pv2boot:  -> done

pv2boot: setup: type=0x80 request=0x6 wIndex=0x0 wValue=0x200 wLength=9

pv2boot:  -> EP0 write 9 bytes to host

pv2boot: xferdata (write) failed: ERROR_ABORTED

pv2boot:   SUDAV=64

pv2boot:   SUTOK=0

pv2boot:  -> done

pv2boot: setup: type=0x80 request=0x6 wIndex=0x0 wValue=0x100 wLength=64

pv2boot:  -> EP0 write 18 bytes to host

pv2boot:  -> done

pv2boot: USB_RESET

pv2boot: USB_RESET

pv2boot: setup: type=0x80 request=0x6 wIndex=0x0 wValue=0x100 wLength=18

pv2boot:  -> EP0 write 18 bytes to host

pv2boot:  -> done

pv2boot: setup: type=0x80 request=0x6 wIndex=0x0 wValue=0xF00 wLength=5

pv2boot:  -> EP0 write 5 bytes to host

pv2boot:  -> done

pv2boot: setup: type=0x80 request=0x6 wIndex=0x0 wValue=0xF00 wLength=22

pv2boot:  -> EP0 write 22 bytes to host

pv2boot:  -> done

pv2boot: setup: type=0x80 request=0x6 wIndex=0x0 wValue=0x200 wLength=9

pv2boot:  -> EP0 write 9 bytes to host

pv2boot:  -> done

pv2boot: setup: type=0x80 request=0x6 wIndex=0x0 wValue=0x200 wLength=41

pv2boot:  -> EP0 write 41 bytes to host

pv2boot:  -> done

pv2boot: setup: type=0x80 request=0x6 wIndex=0x0 wValue=0x300 wLength=255

pv2boot:  -> EP0 write 4 bytes to host

pv2boot:  -> done

pv2boot: setup: type=0x80 request=0x6 wIndex=0x409 wValue=0x302 wLength=255

pv2boot:  -> EP0 write 24 bytes to host

pv2boot:  -> done

pv2boot: setup: type=0x80 request=0x6 wIndex=0x409 wValue=0x301 wLength=255

pv2boot:  -> EP0 write 24 bytes to host

pv2boot:  -> done

pv2boot: setup: type=0x80 request=0x6 wIndex=0x409 wValue=0x303 wLength=255

pv2boot:  -> EP0 write 18 bytes to host

pv2boot:  -> done

pv2boot: setup: type=0x0 request=0x9 wIndex=0x0 wValue=0x1 wLength=0

pv2boot:  -> ACK

pv2boot: setup: type=0x80 request=0x6 wIndex=0x0 wValue=0xF00 wLength=5

pv2boot:  -> EP0 write 5 bytes to host

pv2boot:  -> done

pv2boot: setup: type=0x80 request=0x6 wIndex=0x0 wValue=0xF00 wLength=22

pv2boot:  -> EP0 write 22 bytes to host

pv2boot:  -> done

(I suspect the first of two USB resets and the setup request immediately following the error may actually have occurred in the other order)

The host reported this enumeration failure (and successful retry):

[696630.259280] usb 1-6: new high-speed USB device number 29 using xhci_hcd

[696630.463468] usb 1-6: unable to read config index 0 descriptor/start: -71

[696630.463487] usb 1-6: can't read configurations, error -71

[696630.799003] usb 1-6: new high-speed USB device number 30 using xhci_hcd

[696631.106032] usb 1-6: New USB device found, idVendor=04b4, idProduct=fafb

Also on the host side, a wireshark capture of USB activity shows the GetDescriptor control transfer failing with -EPROTO ("protocol error", which is unfortunately a catchall for a lot of different unexpected-device-behaviour errors)

Here is an example of the same USB2 enumeration working correctly, with a hub between the FX3 and the host. The requests appear to be identical to the failing case:

pv2boot: USB_RESET

pv2boot: setup: type=0x80 request=0x6 wIndex=0x0 wValue=0x100 wLength=64

pv2boot:  -> EP0 write 18 bytes to host

pv2boot:  -> done

pv2boot: USB_RESET

pv2boot: setup: type=0x80 request=0x6 wIndex=0x0 wValue=0x100 wLength=18

pv2boot:  -> EP0 write 18 bytes to host

pv2boot:  -> done

pv2boot: setup: type=0x80 request=0x6 wIndex=0x0 wValue=0xF00 wLength=5

pv2boot:  -> EP0 write 5 bytes to host

pv2boot:  -> done

pv2boot: setup: type=0x80 request=0x6 wIndex=0x0 wValue=0xF00 wLength=22

pv2boot:  -> EP0 write 22 bytes to host

pv2boot:  -> done

pv2boot: setup: type=0x80 request=0x6 wIndex=0x0 wValue=0x200 wLength=9

pv2boot:  -> EP0 write 9 bytes to host

pv2boot:  -> done

pv2boot: setup: type=0x80 request=0x6 wIndex=0x0 wValue=0x200 wLength=41

pv2boot:  -> EP0 write 41 bytes to host

pv2boot:  -> done

pv2boot: setup: type=0x80 request=0x6 wIndex=0x0 wValue=0x300 wLength=255

pv2boot:  -> EP0 write 4 bytes to host

pv2boot:  -> done

pv2boot: setup: type=0x80 request=0x6 wIndex=0x409 wValue=0x302 wLength=255

pv2boot:  -> EP0 write 24 bytes to host

pv2boot:  -> done

pv2boot: setup: type=0x80 request=0x6 wIndex=0x409 wValue=0x301 wLength=255

pv2boot:  -> EP0 write 24 bytes to host

pv2boot:  -> done

pv2boot: setup: type=0x80 request=0x6 wIndex=0x409 wValue=0x303 wLength=255

pv2boot:  -> EP0 write 18 bytes to host

pv2boot:  -> done

pv2boot: setup: type=0x0 request=0x9 wIndex=0x0 wValue=0x1 wLength=0

pv2boot:  -> ACK

pv2boot: setup: type=0x80 request=0x6 wIndex=0x0 wValue=0xF00 wLength=5

pv2boot:  -> EP0 write 5 bytes to host

pv2boot:  -> done

pv2boot: setup: type=0x80 request=0x6 wIndex=0x0 wValue=0xF00 wLength=22

pv2boot:  -> EP0 write 22 bytes to host

pv2boot:  -> done

0 Likes
1 Solution
OlJo_4577026
Level 2
Level 2

A quick update on this for the benefit of anyone searching. This is a link power management problem. The sequence of events is:

* as part of enumeration, the host successfully fetches the BOS descriptor. The BOS descriptor indicates that the device supports LPM.

* during a subsequent GetDescriptor request, while waiting for a response, the host issues a LPM L1 transaction. This is the timing-sensitive part; if the device responds fast enough to the request, the LPM transaction doesn't happen.

* the FX3 device sends an ACK in response to the LPM transaction, and the link moves to L1

* when a response is ready, the FX3 bootloader library never brings the link out of L1, so the response is never sent and the bootloader blocks waiting for CyFx3BootUsbDmaXferData to complete.

* eventually, the host times out, resets the port, and restarts enumeration

* the first setup token sent as part of the second enumeration attempt causes the blocked attempt to send a response to be aborted

When using the full firmware library, the initial sequence of events is the same, but the firmware library correctly brings the link out of L1 via a remote wakeup when a response is ready.

A workaround is to disable LPM support in the BOS descriptor so the host does not attempt to use LPM, but this is obviously not ideal.

View solution in original post

0 Likes
10 Replies
YatheeshD_36
Moderator
Moderator
Moderator
750 replies posted 500 replies posted 250 solutions authored

Hello,

Please let me know if my understanding is correct. The FX3 second stage boot loader in USB boot enumerates at 3.0 and fails to enumerate as 2.1 when directly connected to the host, as the CyFx3BootUsbDmaXferData API used to handle the setup command is failing.

Can you please try the BootGpifDemo present in the FX3 SDK firmware example on the super speed explorer kit and check if the device is enumerating as both super speed and high speed, when connected to the 2.0 and 3.0 ports.

You can also test the enumeration as 2.1 when the 2nd parameter in CyFx3BootUsbConnect() API under USBInit is set to CyFalse?

pastedImage_1.png

Thanks,

Yatheesh

0 Likes

Hi, thanks for taking a look at this.

For my second-stage bootloader:

USB3 enumeration works correctly with no errors in all cases.

USB2 enumeration (and other control transfers) sees the error from CyFxBootUsbDmaXferData in these situations:

a) the FX3 is directly connected to a host USB2 port; or

b) the FX3 is connected to a host USB3 port with a USB2 cable; or

c) the FX3 is directly connected to a host USB3 port and the second parameter to CyFx3BootUsbConnect is CyFalse (i.e. disable superspeed)

Often USB2 enumeration will succeed after the host does a USB reset and retries enumeration.

USB2 enumeration works correctly in cases (a)-(c) if the FX3 is connected via a separate USB3 hub, rather than directly to the host ports.

(Note that the error does not only affect USB enumeration, it just happens to be most obvious there. Sometimes, it'll enumerate over USB2 without error, but then I'll see the error when attempting to read EP0 data for a vendor control transfer, and it actually happens on every control transfer until a USB reset once it's in that state)

For BootGpifDemo, enumeration appears to work fine with no errors in all of the above cases.

0 Likes

Hello,

Please share your firmware with us. We will review it and suggest changes if necessary.

Thanks,

Yatheesh

0 Likes

Sure, where should I send that to?

0 Likes

Hello,

You can attach the project in your next response.

If you cannot find the attach option, use the advanced editor in the top right corner of the reply dialog box.

Thanks,

Yatheesh

0 Likes

I'll see if I can strip the bootloader code down to something that I can post in public then, it might take a few days.

0 Likes

Hello,

Can you please let me know if you are facing the issue on a specific PC and Host Controller?

Thanks,

Yatheesh

0 Likes

The host it fails on is a no-name x86 Skylake laptop with:

* Ubuntu 18.04.4 LTS with kernel: Linux 4.15.0-109-generic #110-Ubuntu SMP Tue Jun 23 02:39:32 UTC 2020

* USB controller: Intel Corporation Sunrise Point-LP USB 3.0 xHCI Controller (rev 21)

0 Likes

Update:

Enumeration fails when UART Debug logs are sent when handling Setup requests. Issue is resolved when the logs are removed.

Issue seen on:

Ubuntu 18.04.4 LTS with kernel: Linux 4.15.0-109-generic #110-Ubuntu

USB controller: Intel Corporation Sunrise Point-LP USB 3.0 xHCI Controller (rev 21)

Thanks,

Yatheesh

0 Likes
OlJo_4577026
Level 2
Level 2

A quick update on this for the benefit of anyone searching. This is a link power management problem. The sequence of events is:

* as part of enumeration, the host successfully fetches the BOS descriptor. The BOS descriptor indicates that the device supports LPM.

* during a subsequent GetDescriptor request, while waiting for a response, the host issues a LPM L1 transaction. This is the timing-sensitive part; if the device responds fast enough to the request, the LPM transaction doesn't happen.

* the FX3 device sends an ACK in response to the LPM transaction, and the link moves to L1

* when a response is ready, the FX3 bootloader library never brings the link out of L1, so the response is never sent and the bootloader blocks waiting for CyFx3BootUsbDmaXferData to complete.

* eventually, the host times out, resets the port, and restarts enumeration

* the first setup token sent as part of the second enumeration attempt causes the blocked attempt to send a response to be aborted

When using the full firmware library, the initial sequence of events is the same, but the firmware library correctly brings the link out of L1 via a remote wakeup when a response is ready.

A workaround is to disable LPM support in the BOS descriptor so the host does not attempt to use LPM, but this is obviously not ideal.

0 Likes