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.


Reply via email to