[PATCH v5 0/4] hw/usb: Add ASPEED USB Device Controller (UDC)

Jamin Lin posted 4 patches 3 weeks, 3 days ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20260902021542.3194812-1-jamin._5Flin@aspeedtech.com
Maintainers: Paolo Bonzini <pbonzini@redhat.com>, Peter Maydell <peter.maydell@linaro.org>, "Cédric Le Goater" <clg@kaod.org>, Steven Lee <steven_lee@aspeedtech.com>, Troy Lee <leetroy@gmail.com>, Jamin Lin <jamin_lin@aspeedtech.com>, Kane Chen <kane_chen@aspeedtech.com>, Andrew Jeffery <andrew@codeconstruct.com.au>, Joel Stanley <joel@jms.id.au>
include/hw/arm/aspeed_soc.h |    4 +
include/hw/usb/aspeed-udc.h |   85 +++
hw/arm/aspeed_ast2600.c     |   37 +-
hw/usb/aspeed-udc.c         | 1058 +++++++++++++++++++++++++++++++++++
hw/arm/Kconfig              |    1 +
hw/usb/Kconfig              |    4 +
hw/usb/meson.build          |    1 +
hw/usb/trace-events         |   16 +
8 files changed, 1203 insertions(+), 3 deletions(-)
create mode 100644 include/hw/usb/aspeed-udc.h
create mode 100644 hw/usb/aspeed-udc.c
[PATCH v5 0/4] hw/usb: Add ASPEED USB Device Controller (UDC)
Posted by Jamin Lin 3 weeks, 3 days ago
This series adds a QEMU model for the ASPEED USB Device Controller (UDC),
driven by the Linux "aspeed_udc" gadget driver.

It is the first step of a larger plan to model USB device-side support on
ASPEED BMC/BIC SoCs, which has three goals:

1. Model the ASPEED UDC (AST2600 / AST1030). The AST2600 also has USB host
   (EHCI) controllers, so this series targets the AST2600 UDC: its gadget can
   be attached to the SoC's own EHCI bus, letting the guest enumerate its own
   gadget and exercise the UDC end-to-end.  [this series]

2. AST1030 UDC. The AST1030 has no USB host controller, so testing its UDC
   needs a second QEMU instance. The plan is to redirect the UDC gadget out
   of the guest using libusbredir and attach it to another QEMU that runs a
   USB host (a VMM, or an AST2600 / AST2700 guest).  [on-going]
   
3. ASPEED vHub, as a longer-term goal towards BMC KVM / Virtual Media support
   in QEMU.  [future]

This series implements goal 1 only.

Design
------
The UDC is modelled as two QOM objects, because a single object cannot be
both a SysBusDevice and a USBDevice:

  - "aspeed.udc": the sysbus device (MMIO register map, IRQ and DMA engine)
    that the guest gadget driver programs.

  - "aspeed.udc-gadget": a user-creatable USB device presented on a USB host
    controller's bus. It links back to its controller through the "udc"
    property.

The SoC creates the controller; the gadget is added on the command line, e.g.

  -device aspeed.udc-gadget,udc=/machine/soc/udc
     
Test result:
-----------
The default ASPEED SDK prebuilt image does not enable the UDC driver, so
build a kernel with CONFIG_USB_ASPEED_UDC=y first.

Start QEMU with the gadget attached to the on-SoC EHCI:

  qemu-system-arm -machine ast2600-evb -drive file=<image>,if=mtd,format=raw \
      -device aspeed.udc-gadget,udc=/machine/soc/udc -nographic

In the guest, bring up a mass-storage gadget and verify enumeration and I/O:

1. Before: only the host controllers are present
root@ast2600-default:~# lsusb
unable to initialize usb specBus 001 Device 001: ID 1d6b:0002 Linux 6.18.20-dirty-32e49fb4a22b-g32e49fb4a22b-dirty ehci_hcd EHCI Host Controller
Bus 002 Device 001: ID 1d6b:0001 Linux 6.18.20-dirty-32e49fb4a22b-g32e49fb4a22b-dirty uhci_hcd Generic UHCI Host Controller

2. Enable the gadget
root@ast2600-default:~# ./usb-storage.sh
Using UDC: 1e6a2000.usb
[  598.582205] Mass Storage Function, version: 2009/09/11
[  598.582635] LUN: removable file: (no medium)
USB Mass Storage gadget is enabled.
Backing file: /home/root/jamin
root@ast2600-default:~# [  598.876395] usb 1-1: new high-speed USB device number 2 using ehci-platform
[  599.070035] usb 1-1: New USB device found, idVendor=1d6b, idProduct=0104, bcdDevice= 1.00
[  599.070821] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  599.071448] usb 1-1: Product: ASPEED USB Storage
[  599.072687] usb 1-1: Manufacturer: ASPEED
[  599.073384] usb 1-1: SerialNumber: 1234567890
[  599.103625] usb-storage 1-1:1.0: USB Mass Storage device detected
[  599.136326] scsi host0: usb-storage 1-1:1.0
[  600.230921] scsi 0:0:0:0: Direct-Access     Linux    File-Stor Gadget 0618 PQ: 0 ANSI: 2
[  600.243758] sd 0:0:0:0: Attached scsi generic sg0 type 0
[  600.263452] sd 0:0:0:0: Power-on or device reset occurred
[  600.289381] sd 0:0:0:0: [sda] 2048 512-byte logical blocks: (1.05 MB/1.00 MiB)
[  600.297896] sd 0:0:0:0: [sda] Write Protect is off
[  600.306379] sd 0:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  600.424608]  sda:
[  600.425526] sd 0:0:0:0: [sda] Attached SCSI removable disk

3. After: the gadget enumerates on the EHCI bus
root@ast2600-default:~# lsusb
unable to initialize usb specBus 001 Device 001: ID 1d6b:0002 Linux 6.18.20-dirty-32e49fb4a22b-g32e49fb4a22b-dirty ehci_hcd EHCI Host Controller
Bus 001 Device 002: ID 1d6b:0104 ASPEED ASPEED USB Storage
Bus 002 Device 001: ID 1d6b:0001 Linux 6.18.20-dirty-32e49fb4a22b-g32e49fb4a22b-dirty uhci_hcd Generic UHCI Host Controller

4. Mount and verify data
root@ast2600-default:~# mount /dev/sda /mnt/
root@ast2600-default:~# sha256sum /mnt/testfile
3308890a1289f6a327c014537523e8ebd0833301af3d25a7c5893dc7050d2c70  /mnt/testfile
root@ast2600-default:~# umount /mnt

5. Stop the gadget -> clean disconnect
root@ast2600-default:~# ./usb-storage.sh stop
Stopping USB gadget...
[  669.866439] usb 1-1: USB disconnect, device number 2
Stopped.
root@ast2600-default:~# [  669.968156] sd 0:0:0:0: [sda] Synchronizing SCSI cache
[  669.969307] sd 0:0:0:0: [sda] Synchronize Cache(10) failed: Result: hostbyte=0x01 driverbyte=DRIVER_OK

root@ast2600-default:~# lsusb
unable to initialize usb specBus 001 Device 001: ID 1d6b:0002 Linux 6.18.20-dirty-32e49fb4a22b-g32e49fb4a22b-dirty ehci_hcd EHCI Host Controller
Bus 002 Device 001: ID 1d6b:0001 Linux 6.18.20-dirty-32e49fb4a22b-g32e49fb4a22b-dirty uhci_hcd Generic UHCI Host Controller


The contents of this scripts
---------------------------
root@ast2600-default:~# cat  usb-storage.sh
#!/bin/sh
set -e

G=/sys/kernel/config/usb_gadget/g1
IMG=/home/root/jamin
SIZE_MB=64

mount_configfs()
{
    mountpoint -q /sys/kernel/config || mount -t configfs none /sys/kernel/config
}

get_udc()
{
    ls /sys/class/udc | head -n 1
}

stop_gadget()
{
    if [ ! -d "$G" ]; then
        return
    fi

    echo "Stopping USB gadget..."

    # Unbind UDC first
    if [ -f "$G/UDC" ]; then
        echo "" > "$G/UDC" 2>/dev/null || true
    fi

    # Clear backing file to release image
    if [ -f "$G/functions/mass_storage.0/lun.0/file" ]; then
        echo "" > "$G/functions/mass_storage.0/lun.0/file" 2>/dev/null || true
    fi

    # Remove function link from config
    rm -f "$G/configs/c.1/mass_storage.0" 2>/dev/null || true

    echo "Stopped."
}

start_gadget()
{
    mount_configfs

    UDC="$(get_udc)"
    if [ -z "$UDC" ]; then
        echo "ERROR: No UDC found in /sys/class/udc"
        exit 1
    fi

    stop_gadget

    echo "Using UDC: $UDC"

    modprobe libcomposite 2>/dev/null || true

    mkdir -p "$G"
    cd "$G"

    echo 0x1d6b > idVendor
    echo 0x0104 > idProduct
    echo 0x0200 > bcdUSB
    echo 0x0100 > bcdDevice

    mkdir -p strings/0x409
    echo "1234567890" > strings/0x409/serialnumber
    echo "ASPEED" > strings/0x409/manufacturer
    echo "ASPEED USB Storage" > strings/0x409/product

    mkdir -p configs/c.1/strings/0x409
    echo "Mass Storage" > configs/c.1/strings/0x409/configuration
    echo 120 > configs/c.1/MaxPower

    if [ ! -f "$IMG" ]; then
        echo "Creating backing image: $IMG"
        dd if=/dev/zero of="$IMG" bs=1M count="$SIZE_MB"
        mkfs.vfat "$IMG"
    fi

    mkdir -p functions/mass_storage.0

    # Make sure old LUN is detached before changing attributes
    echo "" > functions/mass_storage.0/lun.0/file 2>/dev/null || true

    echo 0 > functions/mass_storage.0/stall
    echo 0 > functions/mass_storage.0/lun.0/cdrom
    echo 0 > functions/mass_storage.0/lun.0/ro
    echo 1 > functions/mass_storage.0/lun.0/removable
    echo "$IMG" > functions/mass_storage.0/lun.0/file

    ln -sf functions/mass_storage.0 configs/c.1/mass_storage.0

    echo "$UDC" > UDC

    echo "USB Mass Storage gadget is enabled."
    echo "Backing file: $IMG"
}

case "$1" in
    start|"")
        start_gadget
        ;;
    stop)
        stop_gadget
        ;;
    restart)
        stop_gadget
        sleep 1
        start_gadget
        ;;
    *)
        echo "Usage: $0 {start|stop|restart}"
        exit 1
        ;;
esac


v1:
  1. Add ASPEED UDC device controller
  2. Add ASPEED UDC gadget USB device

v2:
  1. Replace dynamic memory allocation with fixed-size arrays.
  2. Use an OR gate to route the interrupt signals from the UDC and EHCI2.
  3. Split the "Add ASPEED UDC gadget USB device" patch into two patches:
    a. Add ASPEED UDC gadget USB device
      Implement EP0 control transfers.
    b. Add programmable endpoint DMA transfers
      Implement DMA transfers for programmable endpoints.
  4. Remove unused macros.
  
v3:
  1. Remove unused macros.
  2. Bind the gadget to the controller via a QOM link property
   ("usbgadget", weak) instead of writing the back-pointer directly

v4:
  1. Move the "select USB" dependency to the appropriate patch.

v5:
  1. Dynamically allocate the buffer in aspeed_udc_ep_xfer_out() to reduce stack usage.

Jamin Lin (4):
  hw/usb/aspeed-udc: Add ASPEED UDC device controller
  hw/usb/aspeed-udc: Add ASPEED UDC gadget USB device
  hw/usb/aspeed-udc: Add programmable endpoint DMA transfers
  hw/arm/aspeed_ast2600: Wire up the UDC

 include/hw/arm/aspeed_soc.h |    4 +
 include/hw/usb/aspeed-udc.h |   85 +++
 hw/arm/aspeed_ast2600.c     |   37 +-
 hw/usb/aspeed-udc.c         | 1058 +++++++++++++++++++++++++++++++++++
 hw/arm/Kconfig              |    1 +
 hw/usb/Kconfig              |    4 +
 hw/usb/meson.build          |    1 +
 hw/usb/trace-events         |   16 +
 8 files changed, 1203 insertions(+), 3 deletions(-)
 create mode 100644 include/hw/usb/aspeed-udc.h
 create mode 100644 hw/usb/aspeed-udc.c

-- 
2.53.0
Re: [PATCH v5 0/4] hw/usb: Add ASPEED USB Device Controller (UDC)
Posted by Cédric Le Goater 3 weeks, 3 days ago
On 9/2/26 04:15, Jamin Lin wrote:
> This series adds a QEMU model for the ASPEED USB Device Controller (UDC),
> driven by the Linux "aspeed_udc" gadget driver.
> 
> It is the first step of a larger plan to model USB device-side support on
> ASPEED BMC/BIC SoCs, which has three goals:
> 
> 1. Model the ASPEED UDC (AST2600 / AST1030). The AST2600 also has USB host
>     (EHCI) controllers, so this series targets the AST2600 UDC: its gadget can
>     be attached to the SoC's own EHCI bus, letting the guest enumerate its own
>     gadget and exercise the UDC end-to-end.  [this series]
> 
> 2. AST1030 UDC. The AST1030 has no USB host controller, so testing its UDC
>     needs a second QEMU instance. The plan is to redirect the UDC gadget out
>     of the guest using libusbredir and attach it to another QEMU that runs a
>     USB host (a VMM, or an AST2600 / AST2700 guest).  [on-going]
>     
> 3. ASPEED vHub, as a longer-term goal towards BMC KVM / Virtual Media support
>     in QEMU.  [future]
> 
> This series implements goal 1 only.
> 
> Design
> ------
> The UDC is modelled as two QOM objects, because a single object cannot be
> both a SysBusDevice and a USBDevice:
> 
>    - "aspeed.udc": the sysbus device (MMIO register map, IRQ and DMA engine)
>      that the guest gadget driver programs.
> 
>    - "aspeed.udc-gadget": a user-creatable USB device presented on a USB host
>      controller's bus. It links back to its controller through the "udc"
>      property.
> 
> The SoC creates the controller; the gadget is added on the command line, e.g.
> 
>    -device aspeed.udc-gadget,udc=/machine/soc/udc
>       
> Test result:
> -----------
> The default ASPEED SDK prebuilt image does not enable the UDC driver, so
> build a kernel with CONFIG_USB_ASPEED_UDC=y first.
> 
> Start QEMU with the gadget attached to the on-SoC EHCI:
> 
>    qemu-system-arm -machine ast2600-evb -drive file=<image>,if=mtd,format=raw \
>        -device aspeed.udc-gadget,udc=/machine/soc/udc -nographic
> 
> In the guest, bring up a mass-storage gadget and verify enumeration and I/O:
> 
> 1. Before: only the host controllers are present
> root@ast2600-default:~# lsusb
> unable to initialize usb specBus 001 Device 001: ID 1d6b:0002 Linux 6.18.20-dirty-32e49fb4a22b-g32e49fb4a22b-dirty ehci_hcd EHCI Host Controller
> Bus 002 Device 001: ID 1d6b:0001 Linux 6.18.20-dirty-32e49fb4a22b-g32e49fb4a22b-dirty uhci_hcd Generic UHCI Host Controller
> 
> 2. Enable the gadget
> root@ast2600-default:~# ./usb-storage.sh
> Using UDC: 1e6a2000.usb
> [  598.582205] Mass Storage Function, version: 2009/09/11
> [  598.582635] LUN: removable file: (no medium)
> USB Mass Storage gadget is enabled.
> Backing file: /home/root/jamin
> root@ast2600-default:~# [  598.876395] usb 1-1: new high-speed USB device number 2 using ehci-platform
> [  599.070035] usb 1-1: New USB device found, idVendor=1d6b, idProduct=0104, bcdDevice= 1.00
> [  599.070821] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
> [  599.071448] usb 1-1: Product: ASPEED USB Storage
> [  599.072687] usb 1-1: Manufacturer: ASPEED
> [  599.073384] usb 1-1: SerialNumber: 1234567890
> [  599.103625] usb-storage 1-1:1.0: USB Mass Storage device detected
> [  599.136326] scsi host0: usb-storage 1-1:1.0
> [  600.230921] scsi 0:0:0:0: Direct-Access     Linux    File-Stor Gadget 0618 PQ: 0 ANSI: 2
> [  600.243758] sd 0:0:0:0: Attached scsi generic sg0 type 0
> [  600.263452] sd 0:0:0:0: Power-on or device reset occurred
> [  600.289381] sd 0:0:0:0: [sda] 2048 512-byte logical blocks: (1.05 MB/1.00 MiB)
> [  600.297896] sd 0:0:0:0: [sda] Write Protect is off
> [  600.306379] sd 0:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
> [  600.424608]  sda:
> [  600.425526] sd 0:0:0:0: [sda] Attached SCSI removable disk
> 
> 3. After: the gadget enumerates on the EHCI bus
> root@ast2600-default:~# lsusb
> unable to initialize usb specBus 001 Device 001: ID 1d6b:0002 Linux 6.18.20-dirty-32e49fb4a22b-g32e49fb4a22b-dirty ehci_hcd EHCI Host Controller
> Bus 001 Device 002: ID 1d6b:0104 ASPEED ASPEED USB Storage
> Bus 002 Device 001: ID 1d6b:0001 Linux 6.18.20-dirty-32e49fb4a22b-g32e49fb4a22b-dirty uhci_hcd Generic UHCI Host Controller
> 
> 4. Mount and verify data
> root@ast2600-default:~# mount /dev/sda /mnt/
> root@ast2600-default:~# sha256sum /mnt/testfile
> 3308890a1289f6a327c014537523e8ebd0833301af3d25a7c5893dc7050d2c70  /mnt/testfile
> root@ast2600-default:~# umount /mnt
> 
> 5. Stop the gadget -> clean disconnect
> root@ast2600-default:~# ./usb-storage.sh stop
> Stopping USB gadget...
> [  669.866439] usb 1-1: USB disconnect, device number 2
> Stopped.
> root@ast2600-default:~# [  669.968156] sd 0:0:0:0: [sda] Synchronizing SCSI cache
> [  669.969307] sd 0:0:0:0: [sda] Synchronize Cache(10) failed: Result: hostbyte=0x01 driverbyte=DRIVER_OK
> 
> root@ast2600-default:~# lsusb
> unable to initialize usb specBus 001 Device 001: ID 1d6b:0002 Linux 6.18.20-dirty-32e49fb4a22b-g32e49fb4a22b-dirty ehci_hcd EHCI Host Controller
> Bus 002 Device 001: ID 1d6b:0001 Linux 6.18.20-dirty-32e49fb4a22b-g32e49fb4a22b-dirty uhci_hcd Generic UHCI Host Controller
> 
> 
> The contents of this scripts
> ---------------------------
> root@ast2600-default:~# cat  usb-storage.sh
> #!/bin/sh
> set -e
> 
> G=/sys/kernel/config/usb_gadget/g1
> IMG=/home/root/jamin
> SIZE_MB=64
> 
> mount_configfs()
> {
>      mountpoint -q /sys/kernel/config || mount -t configfs none /sys/kernel/config
> }
> 
> get_udc()
> {
>      ls /sys/class/udc | head -n 1
> }
> 
> stop_gadget()
> {
>      if [ ! -d "$G" ]; then
>          return
>      fi
> 
>      echo "Stopping USB gadget..."
> 
>      # Unbind UDC first
>      if [ -f "$G/UDC" ]; then
>          echo "" > "$G/UDC" 2>/dev/null || true
>      fi
> 
>      # Clear backing file to release image
>      if [ -f "$G/functions/mass_storage.0/lun.0/file" ]; then
>          echo "" > "$G/functions/mass_storage.0/lun.0/file" 2>/dev/null || true
>      fi
> 
>      # Remove function link from config
>      rm -f "$G/configs/c.1/mass_storage.0" 2>/dev/null || true
> 
>      echo "Stopped."
> }
> 
> start_gadget()
> {
>      mount_configfs
> 
>      UDC="$(get_udc)"
>      if [ -z "$UDC" ]; then
>          echo "ERROR: No UDC found in /sys/class/udc"
>          exit 1
>      fi
> 
>      stop_gadget
> 
>      echo "Using UDC: $UDC"
> 
>      modprobe libcomposite 2>/dev/null || true
> 
>      mkdir -p "$G"
>      cd "$G"
> 
>      echo 0x1d6b > idVendor
>      echo 0x0104 > idProduct
>      echo 0x0200 > bcdUSB
>      echo 0x0100 > bcdDevice
> 
>      mkdir -p strings/0x409
>      echo "1234567890" > strings/0x409/serialnumber
>      echo "ASPEED" > strings/0x409/manufacturer
>      echo "ASPEED USB Storage" > strings/0x409/product
> 
>      mkdir -p configs/c.1/strings/0x409
>      echo "Mass Storage" > configs/c.1/strings/0x409/configuration
>      echo 120 > configs/c.1/MaxPower
> 
>      if [ ! -f "$IMG" ]; then
>          echo "Creating backing image: $IMG"
>          dd if=/dev/zero of="$IMG" bs=1M count="$SIZE_MB"
>          mkfs.vfat "$IMG"
>      fi
> 
>      mkdir -p functions/mass_storage.0
> 
>      # Make sure old LUN is detached before changing attributes
>      echo "" > functions/mass_storage.0/lun.0/file 2>/dev/null || true
> 
>      echo 0 > functions/mass_storage.0/stall
>      echo 0 > functions/mass_storage.0/lun.0/cdrom
>      echo 0 > functions/mass_storage.0/lun.0/ro
>      echo 1 > functions/mass_storage.0/lun.0/removable
>      echo "$IMG" > functions/mass_storage.0/lun.0/file
> 
>      ln -sf functions/mass_storage.0 configs/c.1/mass_storage.0
> 
>      echo "$UDC" > UDC
> 
>      echo "USB Mass Storage gadget is enabled."
>      echo "Backing file: $IMG"
> }
> 
> case "$1" in
>      start|"")
>          start_gadget
>          ;;
>      stop)
>          stop_gadget
>          ;;
>      restart)
>          stop_gadget
>          sleep 1
>          start_gadget
>          ;;
>      *)
>          echo "Usage: $0 {start|stop|restart}"
>          exit 1
>          ;;
> esac
> 
> 
> v1:
>    1. Add ASPEED UDC device controller
>    2. Add ASPEED UDC gadget USB device
> 
> v2:
>    1. Replace dynamic memory allocation with fixed-size arrays.
>    2. Use an OR gate to route the interrupt signals from the UDC and EHCI2.
>    3. Split the "Add ASPEED UDC gadget USB device" patch into two patches:
>      a. Add ASPEED UDC gadget USB device
>        Implement EP0 control transfers.
>      b. Add programmable endpoint DMA transfers
>        Implement DMA transfers for programmable endpoints.
>    4. Remove unused macros.
>    
> v3:
>    1. Remove unused macros.
>    2. Bind the gadget to the controller via a QOM link property
>     ("usbgadget", weak) instead of writing the back-pointer directly
> 
> v4:
>    1. Move the "select USB" dependency to the appropriate patch.
> 
> v5:
>    1. Dynamically allocate the buffer in aspeed_udc_ep_xfer_out() to reduce stack usage.
> 
> Jamin Lin (4):
>    hw/usb/aspeed-udc: Add ASPEED UDC device controller
>    hw/usb/aspeed-udc: Add ASPEED UDC gadget USB device
>    hw/usb/aspeed-udc: Add programmable endpoint DMA transfers
>    hw/arm/aspeed_ast2600: Wire up the UDC
> 
>   include/hw/arm/aspeed_soc.h |    4 +
>   include/hw/usb/aspeed-udc.h |   85 +++
>   hw/arm/aspeed_ast2600.c     |   37 +-
>   hw/usb/aspeed-udc.c         | 1058 +++++++++++++++++++++++++++++++++++
>   hw/arm/Kconfig              |    1 +
>   hw/usb/Kconfig              |    4 +
>   hw/usb/meson.build          |    1 +
>   hw/usb/trace-events         |   16 +
>   8 files changed, 1203 insertions(+), 3 deletions(-)
>   create mode 100644 include/hw/usb/aspeed-udc.h
>   create mode 100644 hw/usb/aspeed-udc.c
> 

Applied to

     https://github.com/legoater/qemu aspeed-next

Thanks,

C.