[Jetson T5000 Custom Carrier Board] USB Type-C port stuck at High Speed after SuperSpeed+ device disconnect/reconnect, until reboot or ELPG triggered

Hi,

Just to clarify that I don’t want to dig into any driver or workaround things yet. This might bring us into wrong direction. I had seen lots of that case before.

What is the exact meaning here?

→ 3. Switch the OTG port’s role to “none” and back to “host” (through the normal ID/role-switch path, tegra_xhci_id_work()).

Are you trying to say you change the role manually or something else?

And bus trace is still the most quick way here… This could save lots of time discussing about those drivers and workaround things.

Hi @WayneWWW,

If you’re familiar with SuperSpeedPlus (Gen2, 10Gbps), it’s only supported over the Type-C connector, so in most real-world usage, plugging or unplugging a SuperSpeedPlus (Gen2, 10Gbps) device on this port simultaneously triggers the OTG role switch (since Type-C role detection is tied to the physical connect/disconnect event via ID/VBUS).

We have a special test fixture on hand that lets us keep the Type-C device physically connected while issuing a software command to disconnect it logically – without ever triggering a role switch. Under that condition, repeatedly disconnecting and reconnecting the device is always recognized correctly, with no issue at all.

Also, as mentioned in our earlier testing: if we configure the Type-C port as host-only (instead of OTG), repeatedly plugging and unplugging various USB devices causes no problem either – even on the exact same physical port that had previously shown the failure.

Given we don’t have a USB analyzer on hand that supports SuperSpeedPlus (Gen2, 10Gbps) capture, and this issue is quite easy to reproduce, would it be possible for the NVIDIA team to run the bus trace analysis directly?

sorry. 我請問一下如果直接用中文討論方便嗎?

可以的,用中文ok

我這裡想問的是你們為什麼要刻意提到你要把role從none切回host. 照理當你在第四步接回你們的SS device的時候就會自己切回去了

是要刻意做出這個手法才能複製問題嗎?

不用刻意的手法,我只是要描述Role必須要切成None才會發生。所以Host only的port就不會發生問題。這個問題只發生在otg(dual role) port

我這邊重述一次你的複製手法

  1. 什麼都不接開機 (避免UEFI影響) (role = none)

  2. 進kernel之後plug in USB 3.2 device → SS speed (role =host)

  3. 拔掉device (role = none)

  4. 再次接上USB 3.2 device → HS speed (role =host) 複製問題

請問我的理解正確嗎? 還是說如果進kernel才接入也會中?

是的沒錯,理解正確,即使再次接上的是其它usb3.0裝置也都只有HS speed

這裡有一點補充

  1. 進kernel之後plug in USB 3.2 device → SS+ speed (role =host)

由於AGX Thor devkit上面的type C有一些其他的known issue (跟這條無關, 只有devkit會碰上) 所以我們平常OTG是沒有開著的狀態.

我這邊會再找方法複製問題看看.

好的,非常感謝協助

Hi Wayne,

請問有測試過了嗎?

not yet reproduced the issue due to other issues. will update once we have done the test.

Hi Wayne,

請問有空可以幫忙測試看看嗎? 這個issue目前影響到我們產品生產時程

we are still looking into this.

I built usbmon.ko earlier today to take a look at it. While testing it I thought of your problem and following is a method for capturing a USB bus trace on Thor. Linux_for_Tegra/source/kernel/kernel-noble/Documentation/usb/usbmon.rst

usbmon is a software tap in the Linux USB host stack. It records URBs submitted to and completed by the host-controller driver. It is useful for determining how far enumeration progressed and whether a device reappeared on the USB2 or USB3 root hub.

It is not equivalent to a hardware USB protocol analyzer. It does not capture Type-C CC/PD signaling, LFPS, electrical/link-training behavior, or the individual USB packets on the wire.

For your case, it can show:

  1. The root-hub bus the device enumerated on. On my Thor Bus 2 is the SuperSpeed root hub and Bus 1 is the USB2 high-speed root hub. This makes an SS/SS+ → HS fallback immediately visible.
  2. The complete host-side control-transfer sequence during enumeration.
  3. Device, configuration, string, and BOS descriptor requests/responses, if enumeration progresses far enough to retrieve them.
  4. SuperSpeed/SuperSpeedPlus capability descriptors returned in the BOS descriptor.
  5. URB completion status, including stalls, timeouts, disconnects, and other errors reported by the host stack.
  6. The exact sequence of retries and enumeration attempts.

On my JetPack 7.2.1 kernel CONFIG_USB_MON is not set. For a diagnostic kernel, I started with the running kernel configuration and changed only CONFIG_USB_MON to a module.

Native build on Thor using GCC 13.2.0:

cd Linux_for_Tegra/source

# Sync the kernel source to the exact JetPack/L4T release being tested.
./source_sync.sh -k -t # jetson_39.2.1, jetson_39.2_GA, or jetson_38.4

export ARCH=arm64

# Adjust this path for your GCC 13 13.2.0 installation.
export TCBIN="/path/to/gcc-13/bin"
export PATH="$TCBIN:$PATH"

unset CROSS_COMPILE
export CC="$TCBIN/gcc-13"
export HOSTCC="$TCBIN/gcc-13"
export CXX="$TCBIN/g++-13"
export HOSTCXX="$TCBIN/g++-13"

KERNEL_SRC="$PWD/kernel/kernel-noble"

# Start with the configuration of the running JetPack kernel.
zcat /proc/config.gz > "$KERNEL_SRC/.config"
make -C "$KERNEL_SRC" ARCH=arm64 olddefconfig

# Enable CONFIG_USB_MON=m.
"$KERNEL_SRC/scripts/config" \
    --file "$KERNEL_SRC/.config" \
    --module USB_MON

make -C "$KERNEL_SRC" ARCH=arm64 olddefconfig

grep CONFIG_USB_MON "$KERNEL_SRC/.config"

# Build the kernel and in-tree modules.
make -C kernel -j"$(nproc)"

Install the new usbmon module and test kernel Image:

sudo install -D -m 0644 \
    "$KERNEL_SRC/drivers/usb/mon/usbmon.ko" \
    "/lib/modules/$RUNREL/updates/drivers/usb/mon/usbmon.ko"

sudo install -m 0644 "$KERNEL_SRC/arch/arm64/boot/Image" /boot/Image-usbmon

sudo depmod -a

Add an extlinux.conf test entry

cat /boot/extlinux/extlinux.conf.
copy the existing primary boot entry

sudo nano /boot/extlinux/extlinux.conf

Paste copied text. Change the label/menu name and kernel Image, for example:

LABEL usbmon
      MENU LABEL USBMON test kernel
      LINUX /boot/Image-usbmon
      INITRD /boot/initrd
      APPEND <copy the complete APPEND line from the primary entry>

Reboot and select USBMON test kernel from the extlinux boot menu.

Once booted:

sudo modprobe usbmon

Then:
sudo ls /sys/kernel/debug/usb/usbmon

If needed identify the buses

Linux_for_Tegra/source/kernel/kernel-noble/Documentation/usb/usbmon.rst

usbmon2 records SuperSpeed.
usbmon1 records USB2.
usbmon0 records all usb devices.

Capture the problem. Start the kernel log and leave it running in another terminal:

sudo dmesg -wT | tee usbdmesg.txt

Start the USB capture:

sudo tcpdump \
    -i usbmon0 \
    -s 0 \
    -U \
    -w typec_fallback_diagnostic.pcap

While the captures are running, run your USB problem creation sequence.

After the failure has occurred stop tcpdump and the dmesg capture.

Analysis in Wireshark

wireshark typec_fallback_diagnostic.pcap &

A display filter that shows control transfers, including the enumeration sequence:

usb.transfer_type == 2

To show descriptor requests use:

usb.setup.bRequest == 6

usb.transfer_type == 2 || (usb.urb_type == 0x43 && usb.urb_status < 0)

For Nvidia @WayneWWW you could attach:

typec_fallback_diagnostic.pcap
usbdmesg.txt

Hi,

Could you help revert this patch from your usb device mode script and see if the issue is still ?

diff --git a/rfs/opt/nvidia/l4t-usb-device-mode/nv-l4t-usb-device-mode-start.sh b/rfs/opt/nvidia/l4t-usb-device-mode/nv-l4t-usb-device-mode-start.sh
index 17c31a2..a9b4a91 100755
--- a/rfs/opt/nvidia/l4t-usb-device-mode/nv-l4t-usb-device-mode-start.sh
+++ b/rfs/opt/nvidia/l4t-usb-device-mode/nv-l4t-usb-device-mode-start.sh
@@ -62,18 +62,6 @@
     exit 1
 fi
 
-# Orin Nano upstream builds lack the fusb301.ko driver, causing the USB
-# role to be "none" instead of "device". This prevents USB device mode from
-# working. If the role is "none", set it to "device" manually.
-usb_role_switch="/sys/class/usb_role/usb2-0-role-switch/role"
-if [ -f "${usb_role_switch}" ]; then
-    current_role="$(cat "${usb_role_switch}" 2>/dev/null)"
-    if [ "${current_role}" = "none" ]; then
-        echo "USB role is 'none', setting to 'device' mode" | systemd-cat -t usb-device-mode -p info
-        echo device > "${usb_role_switch}" 2>/dev/null
-    fi
-fi
-
 macs_file="${script_dir}/mac-addresses"
 if [ -f "${macs_file}" ]; then
     . "${macs_file}"