lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250414185458.7767aabc@booty>
Date: Mon, 14 Apr 2025 18:54:58 +0200
From: Luca Ceresoli <luca.ceresoli@...tlin.com>
To: Minas Harutyunyan <hminas@...opsys.com>, linux-usb@...r.kernel.org,
 Kever Yang <kever.yang@...k-chips.com>
Cc: Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
 linux-kernel@...r.kernel.org, Hervé Codina
 <herve.codina@...tlin.com>, Thomas Petazzoni
 <thomas.petazzoni@...tlin.com>, Stefan Wahren <wahrenst@....net>, Fabrice
 Gasnier <fabrice.gasnier@...s.st.com>
Subject: DWC2 gadget: unexpected device reenumeration on Rockchip RK3308

Hello Minas, Kever, linux-usb, recent dwc2 driver contributors,

I am facing an unexpected behavior (apparently a bug) with a dwc2
controller in gadget mode, using a mainline kernel: the gadget device is
enumerated normally but then disappears and gets re-enumerated about 6
seconds after the initial enumeration, for no apparent reason. Here are
the details.

Testing setup:

SoC:             Rockchip RK3308
Board:           Rock Pi S [1]
USB controller:  rockchip,rk3308-usb, snps,dwc2 [2]
Controller mode: device only (dr_mode = "peripheral") [3]
Tested kernels:
 - v6.15-rc2
 - v6.14.1
 - v6.12.20
 - v6.6.87
 - v6.1.134
 - v5.15.180
Device tree:     upstream Rock Pi S dts [4]
Kernel config:   ARM64 defconfig

Hardware setup: USB A-C cable connected from PC A port to the C
connector on the Rock Pi S board. This cable provides board power as
well as the connection between the host and the gadget.

Behavior:
 1. boot board normally
 2. optionally wait some time
 3. run script to start a CDC serial gadget [5]
 4. after about 0.6 seconds the ttyGS0 serial device is present and
    working, and so is ttyACM0 on the host: so far all good
 5. after about 6 seconds the dwc2 controller receives some
    interrupts and starts a new enumeration sequence

This is what the kernel logs:

[   20.105688] dwc2 ff400000.usb: bound driver configfs-gadget.g1
[   20.285431] dwc2 ff400000.usb: new device is high-speed
[   20.373455] dwc2 ff400000.usb: new device is high-speed
[   20.426496] dwc2 ff400000.usb: new address 28
[   26.688388] dwc2 ff400000.usb: new device is high-speed
[   26.775363] dwc2 ff400000.usb: new device is high-speed
[   26.836880] dwc2 ff400000.usb: new address 29

Here is a side-by-side log of host and device, synced manually using
a video capture (sorry about the long lines, can't do without):

    *** HOST ***                                                                                      *** DEVICE ***
                                                                                                 <<< Last line of the script: 'echo ff400000.usb > UDC' >>>
                                                                                                 [   14.281350] dwc2 ff400000.usb: bound driver configfs-gadget.g1
                                                                                                 [   14.482332] dwc2 ff400000.usb: new device is high-speed
[108204.084049] usb 3-2: new high-speed USB device number 39 using xhci_hcd
                                                                                                 [   14.675692] dwc2 ff400000.usb: new device is high-speed
[108204.274639] usb 3-2: New USB device found, idVendor=1209, idProduct=0001, bcdDevice= 1.00    [   14.737395] dwc2 ff400000.usb: new address 44
[108204.274652] usb 3-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[108204.274656] usb 3-2: Product: ...
[108204.274659] usb 3-2: Manufacturer: ...
[108204.274662] usb 3-2: SerialNumber: 12345678
[108204.282555] cdc_acm 3-2:1.0: ttyACM0: USB ACM device
                                                            (...nothing happens for about 6 seconds...)
[108209.972180] usb 3-2: USB disconnect, device number 39
                                                                                                 [   20.766950] dwc2 ff400000.usb: new device is high-speed
[108210.339297] usb 3-2: new high-speed USB device number 40 using xhci_hcd
                                                                                                 [   20.960375] dwc2 ff400000.usb: new device is high-speed
[108210.739738] usb 3-2: New USB device found, idVendor=1209, idProduct=0001, bcdDevice= 1.00    [   21.200670] dwc2 ff400000.usb: new address 45
[108210.739750] usb 3-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[108210.739753] usb 3-2: Product: ...
[108210.739756] usb 3-2: Manufacturer: ...
[108210.739758] usb 3-2: SerialNumber: 12345678
[108210.747084] cdc_acm 3-2:1.0: ttyACM0: USB ACM device

Note: the device address is different on the host and the target. Is
this expected?

In the driver there are 2 interrupt handlers involved:
 - dwc2_handle_common_intr in core_intr.c for the common events
 - dwc2_hsotg_irq in gadget.c for gadget events

They share the same interrupt number, which AFAICU is because they
actually read different bits from the same GINTSTS register.

I enabled DEBUG in the dwc2 driver and captured the initial events
logged after the ~6 seconds pause, i.e. where the 2nd enumeration
starts. Here they are with some annotations:

 1. first interrupt after the ~6 s break:
    - dwc2_handle_common_intr finds no bits high
    - dwc2_hsotg_irq finds one (early suspend bit):
       [   46.203094] dwc2 ff400000.usb: dwc2_hsotg_irq: 04008428 00000400 (d88c3cc4) retry 8
       [   46.204060] dwc2 ff400000.usb: GINTSTS_ErlySusp

 2. second interrupt
    - dwc2_handle_common_intr finds one bits high (suspend):
       [   46.206807] dwc2 ff400000.usb: USB SUSPEND
       [   46.206824] dwc2 ff400000.usb: dwc2_handle_usb_suspend_intr: DSTS=0x502a01
       [   46.206842] dwc2 ff400000.usb: DSTS.Suspend Status=1 HWCFG4.Power Optimize=1 HWCFG4.Hibernation=0
       [   46.206872] dwc2 ff400000.usb: dwc2_hsotg_irq: 04008028 00000000 (d88c3cc4) retry 8      
    - dwc2_hsotg_irq finds no bits high

 3. third interrupt
    - dwc2_handle_common_intr finds no bits high
    - dwc2_hsotg_irq finds two (reset detected + USB reset):
       [   46.437109] dwc2 ff400000.usb: dwc2_hsotg_irq: 04809028 00801000 (d88c3cc4) retry 8
       [   46.437607] dwc2 ff400000.usb: dwc2_hsotg_irq: USBRstDet
       [   46.437630] dwc2 ff400000.usb: dwc2_hsotg_irq: USBRst
       [   46.437649] dwc2 ff400000.usb: GNPTXSTS=00080010
       [   46.437673] dwc2 ff400000.usb: complete: ep 00000000dab859c8 ep0, req 000000009cb97255, -108 => 00000000acdb2ee9
       [   46.437719] dwc2 ff400000.usb: dwc2_hsotg_complete_setup: failed -108
       [   46.437765] dwc2 ff400000.usb: dwc2_hsotg_ep_disable(ep 00000000cf8cf06f)
       [   46.437790] dwc2 ff400000.usb: dwc2_hsotg_ep_disable: DxEPCTL=0x08080200
       ...

From now on the log appears as a normal enumeration process.

I'm stuck at a dead end, trying to understand what may be triggering the
second enumeration.

Some more facts:

 * the 2nd enumeration happens always
 * there is never a 3rd enumeration
 * the ~6 seconds delay is always between 5 and 6.5 seconds
 * no relevant kernel activity is logged during the 6 seconds, except
   for some OPP changes; disabling CONFIG_CPU_IDLE and CONFIG_CPU_FREQ
   the OPP changes disappear but USB behaves like before
 * happens (with same delay) if after the 1st enumeration the USB
   serial is opened and kept in use
 * happens even if using a different device class (tried 0x8, 0x2)
 * happens even using g_mass_storage or g_zero instead of libcomposite
   (but with g_zero it happens when the g_zero module is loaded,
   without any configfs configuration)
 * tried different cables, no change
 * there is no evidence of power glitches
 * happens also on a custom hardware which is self-powered
 * happens with different hosts: two different PCs, one running Linux
   and one running Windows
 * to be double checked: does not happen if the host is an Android phone
   (but I haven't gone into the details of what happens with that setup)

So I'm looking for any hints or directions for further investigation.
Any input would be very appreciated.

Thanks in advance!

Luca

[1] https://wiki.radxa.com/RockpiS
[2]
https://elixir.bootlin.com/linux/v6.13.7/source/arch/arm64/boot/dts/rockchip/rk3308.dtsi#L696-L710
[3]
https://elixir.bootlin.com/linux/v6.13.7/source/arch/arm64/boot/dts/rockchip/rk3308-rock-pi-s.dts#L383 
[4]
https://elixir.bootlin.com/linux/v6.13.7/source/arch/arm64/boot/dts/rockchip/rk3308-rock-pi-s.dts

[5] Script used to configure the gadget serial:

------------------------8<------------------------

#!/bin/sh

set -eu

modprobe libcomposite

mount -t configfs none /sys/kernel/config

mkdir -p "/sys/kernel/config/usb_gadget/g1"
cd "/sys/kernel/config/usb_gadget/g1"

echo 0x0200 > bcdUSB
echo 0x0100 > bcdDevice
echo 0x1209 > idVendor
echo 0x0001 > idProduct
echo 0x02   > bDeviceClass 
echo 0x00   > bDeviceSubClass 
echo 0x00   > bDeviceProtocol 

mkdir -p strings/0x409
echo 12345678 > strings/0x409/serialnumber
echo "ACME"   > strings/0x409/manufacturer
echo "foobar" > strings/0x409/product

# create the configuration
mkdir -p configs/c.1
mkdir -p configs/c.1/strings/0x409
echo "foobar Config" > configs/c.1/strings/0x409/configuration
echo 500 > configs/c.1/MaxPower

# create the function
mkdir functions/acm.0

# associate the function with the configuration
ln -s functions/acm.0 configs/c.1

# enable the gadget using rock pi s UDC controller name (from /sys/class/udc/)
echo ff400000.usb > UDC

------------------------8<------------------------

-- 
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ