* [PATCH v3 00/17] hw/usb/ehci: Add 64-bit descriptor addressing support
@ 2026-04-16 1:49 Jamin Lin
2026-04-16 1:49 ` [PATCH v3 01/17] hw/usb/hcd-ehci: Remove unused EHCIfstn structure and dead code Jamin Lin
` (17 more replies)
0 siblings, 18 replies; 69+ messages in thread
From: Jamin Lin @ 2026-04-16 1:49 UTC (permalink / raw)
To: philmd@linaro.org, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Jamin Lin, Troy Lee, flwu@google.com, nabihestefan@google.com
EHCI supports 64-bit addressing through the CTRLDSSEGMENT register,
which provides the upper 32 bits of descriptor addresses when the
controller advertises 64-bit capability.
Currently QEMU EHCI model only partially supports this functionality and
descriptor addresses are effectively treated as 32-bit. This becomes
problematic on systems where system memory is located above the 4GB
boundary.
The Linux EHCI driver enables 64-bit addressing if the controller
advertises the capability. During initialization it programs the
segment register to zero:
https://github.com/torvalds/linux/blob/master/drivers/usb/host/ehci-hcd.c#L600
The driver also notes that descriptor structures allocated from the
DMA pool use segment zero semantics. Descriptor memory is allocated
using the DMA API and platforms may configure a 64-bit DMA mask,
allowing descriptor memory to be placed above 4GB.
On AST2700 platforms, system DRAM is mapped at 0x400000000. As a
result, descriptor addresses constructed directly from the EHCI
registers do not match the actual system addresses used by the
controller when accessing queue heads (QH) and queue element transfer
descriptors (qTD).
This patch series implements full 64-bit descriptor addressing support
in the EHCI emulation. Descriptor address handling is updated to use
64-bit values and the descriptor structures (QH, qTD, iTD and siTD)
are extended to support the upper address bits provided by the segment
register.
In addition, a descriptor-addr-offset property is introduced so
platforms can apply an address translation when descriptor memory
resides above the 4GB boundary.
The AST2700 machine uses this property to account for its DRAM mapping
at 0x400000000 and enables 64-bit EHCI DMA addressing.
Test Result:
1. EHCI 32bits with ast2600-evb machine
Command line:
./build/qemu-system-arm \
-machine ast2600-evb \
-m 1G \
-drive file=image-bmc,if=mtd,format=raw \
-nographic \
-device usb-kbd,bus=usb-bus.1,id=mykbd \
-drive id=usbdisk,if=none,file=image0.ext4,format=raw \
-device usb-storage,bus=usb-bus.1,id=mystorage,drive=usbdisk
-snapshot \
-nographic
Result:
unable to initialize usb specBus 001 Device 001: ID 1d6b:0002 Linux 6.18.3-v00.08.01-g172b7e27a30d ehci_hcd EHCI Host Controller
Bus 001 Device 002: ID 0627:0001 QEMU QEMU USB Keyboard
Bus 001 Device 003: ID 46f4:0001 QEMU QEMU USB HARDDRIVE
Bus 002 Device 001: ID 1d6b:0001 Linux 6.18.3-v00.08.01-g172b7e27a30d uhci_hcd Generic UHCI Host Controller
2. EHCI 64bits with ast2700a2-evb machine
Command line:
./build/qemu-system-aarch64 -M ast2700a2-evb -nographic\
-bios ast27x0_bootrom.bin \
-drive file=image-bmc,format=raw,if=mtd \
-snapshot \
-device usb-kbd,bus=usb-bus.3,id=mykbd \
-drive id=usbdisk,if=none,file=image0.ext4,format=raw \
-device usb-storage,bus=usb-bus.3,id=mystorage,drive=usbdisk
Result:
root@ast2700-default:~# lsusb
unable to initialize usb specBus 001 Device 001: ID 1d6b:0001 Linux 6.18.3-v00.08.01-g172b7e27a30d uhci_hcd Generic UHCI Host Controller
Bus 002 Device 001: ID 1d6b:0002 Linux 6.18.3-v00.08.01-g172b7e27a30d ehci_hcd EHCI Host Controller
Bus 002 Device 002: ID 0627:0001 QEMU QEMU USB Keyboard
Bus 002 Device 003: ID 46f4:0001 QEMU QEMU USB HARDDRIVE
v1
1. Fix checkpatch coding style issues
2. Implement 64-bit addressing for QH/qTD/iTD/siTD descriptors
3. Add descriptor address offset property
4. Enable 64-bit EHCI DMA addressing on AST2700
5. Configure descriptor address offset for AST2700
v2
1. Remove unused EHCIfstn structure and dead code
2. Replace fprintf(stderr, ...) with qemu_log_mask(LOG_GUEST_ERROR)
3. Replace DPRINTF debug logs with trace events
4. Add functional tests for USB EHCI on AST2600 and AST2700 A1/A2
5. Fix review issue
v3:
1. Add Migration version test function
2. Add EHCI 64-bit buffer pointer fields description in commit log
Jamin Lin (17):
hw/usb/hcd-ehci: Remove unused EHCIfstn structure and dead code
hw/usb/hcd-ehci.h: Fix coding style issues reported by checkpatch
hw/usb/hcd-ehci.c: Fix coding style issues reported by checkpatch
hw/usb/hcd-ehci.c: Replace fprintf(stderr, ...) with
qemu_log_mask(LOG_GUEST_ERROR)
hw/usb/hcd-ehci: Replace DPRINTF debug logs with trace events
hw/usb/hcd-ehci: Change descriptor addresses to 64-bit
hw/usb/hcd-ehci: Add property to advertise 64-bit addressing
capability
hw/usb/hcd-ehci: Reject CTRLDSSEGMENT writes without 64-bit capability
hw/usb/hcd-ehci: Implement 64-bit QH descriptor addressing
hw/usb/hcd-ehci: Implement 64-bit qTD descriptor addressing
hw/usb/hcd-ehci: Implement 64-bit iTD descriptor addressing
hw/usb/hcd-ehci: Implement 64-bit siTD descriptor addressing
hw/usb/hcd-ehci: Add descriptor address offset property
hw/arm/aspeed_ast27x0: Enable 64-bit EHCI DMA addressing
hw/arm/aspeed_ast27x0: Set EHCI descriptor address offset
tests/functional/arm/test_aspeed_ast2600_sdk: Add USB EHCI test for
AST2600 SDK
tests/functional/aarch64/test_aspeed_ast2700: Add USB EHCI test for
AST2700 A1/A2
hw/usb/hcd-ehci.h | 55 ++-
hw/arm/aspeed_ast27x0.c | 5 +
hw/usb/hcd-ehci-pci.c | 4 +
hw/usb/hcd-ehci-sysbus.c | 4 +
hw/usb/hcd-ehci.c | 378 +++++++++++-------
hw/usb/trace-events | 25 +-
.../aarch64/test_aspeed_ast2700a1.py | 7 +
.../aarch64/test_aspeed_ast2700a2.py | 7 +
.../functional/arm/test_aspeed_ast2600_sdk.py | 7 +
9 files changed, 301 insertions(+), 191 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 69+ messages in thread
* [PATCH v3 01/17] hw/usb/hcd-ehci: Remove unused EHCIfstn structure and dead code
2026-04-16 1:49 [PATCH v3 00/17] hw/usb/ehci: Add 64-bit descriptor addressing support Jamin Lin
@ 2026-04-16 1:49 ` Jamin Lin
2026-04-16 12:09 ` BALATON Zoltan
2026-04-17 6:30 ` Cédric Le Goater
2026-04-16 1:49 ` [PATCH v3 02/17] hw/usb/hcd-ehci.h: Fix coding style issues reported by checkpatch Jamin Lin
` (16 subsequent siblings)
17 siblings, 2 replies; 69+ messages in thread
From: Jamin Lin @ 2026-04-16 1:49 UTC (permalink / raw)
To: philmd@linaro.org, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Jamin Lin, Troy Lee, flwu@google.com, nabihestefan@google.com
The EHCIfstn structure, defined according to EHCI spec section 3.7,
is currently unused in the EHCI implementation. Remove it to reduce
unused code and improve maintainability.
Additionally, drop a block of disabled (#if 0) code in
ehci_state_advqueue() that was never implemented. This code path
is incomplete and has no functional impact.
No functional change.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
hw/usb/hcd-ehci.h | 7 -------
hw/usb/hcd-ehci.c | 11 -----------
2 files changed, 18 deletions(-)
diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
index 0ae8c06331..3aec0e047c 100644
--- a/hw/usb/hcd-ehci.h
+++ b/hw/usb/hcd-ehci.h
@@ -202,13 +202,6 @@ typedef struct EHCIqh {
#define BUFPTR_SBYTES_SH 5
} EHCIqh;
-/* EHCI spec version 1.0 Section 3.7
- */
-typedef struct EHCIfstn {
- uint32_t next; /* Standard next link pointer */
- uint32_t backptr; /* Standard next link pointer */
-} EHCIfstn;
-
enum async_state {
EHCI_ASYNC_NONE = 0,
EHCI_ASYNC_INITIALIZED,
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 57f930b099..5ea8461f70 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -1756,17 +1756,6 @@ static int ehci_state_fetchsitd(EHCIState *ehci, int async)
/* Section 4.10.2 - paragraph 3 */
static int ehci_state_advqueue(EHCIQueue *q)
{
-#if 0
- /* TO-DO: 4.10.2 - paragraph 2
- * if I-bit is set to 1 and QH is not active
- * go to horizontal QH
- */
- if (I-bit set) {
- ehci_set_state(ehci, async, EST_HORIZONTALQH);
- goto out;
- }
-#endif
-
/*
* want data and alt-next qTD is valid
*/
--
2.43.0
^ permalink raw reply related [flat|nested] 69+ messages in thread
* [PATCH v3 02/17] hw/usb/hcd-ehci.h: Fix coding style issues reported by checkpatch
2026-04-16 1:49 [PATCH v3 00/17] hw/usb/ehci: Add 64-bit descriptor addressing support Jamin Lin
2026-04-16 1:49 ` [PATCH v3 01/17] hw/usb/hcd-ehci: Remove unused EHCIfstn structure and dead code Jamin Lin
@ 2026-04-16 1:49 ` Jamin Lin
2026-04-17 6:32 ` Philippe Mathieu-Daudé
2026-04-16 1:49 ` [PATCH v3 03/17] hw/usb/hcd-ehci.c: " Jamin Lin
` (15 subsequent siblings)
17 siblings, 1 reply; 69+ messages in thread
From: Jamin Lin @ 2026-04-16 1:49 UTC (permalink / raw)
To: philmd@linaro.org, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Jamin Lin, Troy Lee, flwu@google.com, nabihestefan@google.com,
Cédric Le Goater
No functional change.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
---
hw/usb/hcd-ehci.h | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
index 3aec0e047c..736407fd52 100644
--- a/hw/usb/hcd-ehci.h
+++ b/hw/usb/hcd-ehci.h
@@ -43,7 +43,8 @@ typedef struct EHCIPacket EHCIPacket;
typedef struct EHCIQueue EHCIQueue;
typedef struct EHCIState EHCIState;
-/* EHCI spec version 1.0 Section 3.3
+/*
+ * EHCI spec version 1.0 Section 3.3
*/
typedef struct EHCIitd {
uint32_t next;
@@ -74,7 +75,8 @@ typedef struct EHCIitd {
#define ITD_BUFPTR_MULT_SH 0
} EHCIitd;
-/* EHCI spec version 1.0 Section 3.4
+/*
+ * EHCI spec version 1.0 Section 3.4
*/
typedef struct EHCIsitd {
uint32_t next; /* Standard next link pointer */
@@ -118,7 +120,8 @@ typedef struct EHCIsitd {
uint32_t backptr; /* Standard next link pointer */
} EHCIsitd;
-/* EHCI spec version 1.0 Section 3.5
+/*
+ * EHCI spec version 1.0 Section 3.5
*/
typedef struct EHCIqtd {
uint32_t next; /* Standard next link pointer */
@@ -148,7 +151,8 @@ typedef struct EHCIqtd {
#define QTD_BUFPTR_SH 12
} EHCIqtd;
-/* EHCI spec version 1.0 Section 3.6
+/*
+ * EHCI spec version 1.0 Section 3.6
*/
typedef struct EHCIqh {
uint32_t next; /* Standard next link pointer */
@@ -230,7 +234,8 @@ struct EHCIQueue {
int async;
int transact_ctr;
- /* cached data from guest - needs to be flushed
+ /*
+ * cached data from guest - needs to be flushed
* when guest removes an entry (doorbell, handshake sequence)
*/
EHCIqh qh; /* copy of current QH (being worked on) */
@@ -268,7 +273,7 @@ struct EHCIState {
*/
uint8_t caps[CAPA_SIZE];
union {
- uint32_t opreg[0x44/sizeof(uint32_t)];
+ uint32_t opreg[0x44 / sizeof(uint32_t)];
struct {
uint32_t usbcmd;
uint32_t usbsts;
--
2.43.0
^ permalink raw reply related [flat|nested] 69+ messages in thread
* [PATCH v3 03/17] hw/usb/hcd-ehci.c: Fix coding style issues reported by checkpatch
2026-04-16 1:49 [PATCH v3 00/17] hw/usb/ehci: Add 64-bit descriptor addressing support Jamin Lin
2026-04-16 1:49 ` [PATCH v3 01/17] hw/usb/hcd-ehci: Remove unused EHCIfstn structure and dead code Jamin Lin
2026-04-16 1:49 ` [PATCH v3 02/17] hw/usb/hcd-ehci.h: Fix coding style issues reported by checkpatch Jamin Lin
@ 2026-04-16 1:49 ` Jamin Lin
2026-04-17 6:31 ` Cédric Le Goater
2026-04-17 6:32 ` Philippe Mathieu-Daudé
2026-04-16 1:49 ` [PATCH v3 04/17] hw/usb/hcd-ehci.c: Replace fprintf(stderr, ...) with qemu_log_mask(LOG_GUEST_ERROR) Jamin Lin
` (14 subsequent siblings)
17 siblings, 2 replies; 69+ messages in thread
From: Jamin Lin @ 2026-04-16 1:49 UTC (permalink / raw)
To: philmd@linaro.org, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Jamin Lin, Troy Lee, flwu@google.com, nabihestefan@google.com
No functional change.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
hw/usb/hcd-ehci.c | 126 +++++++++++++++++++++++++---------------------
1 file changed, 69 insertions(+), 57 deletions(-)
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 5ea8461f70..9b92384bac 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -41,21 +41,23 @@
#define FRAME_TIMER_NS (NANOSECONDS_PER_SECOND / FRAME_TIMER_FREQ)
#define UFRAME_TIMER_NS (FRAME_TIMER_NS / 8)
-#define NB_MAXINTRATE 8 // Max rate at which controller issues ints
-#define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction
-#define MAX_QH 100 // Max allowable queue heads in a chain
+#define NB_MAXINTRATE 8 /* Max rate at which controller issues ints */
+#define BUFF_SIZE (5 * 4096) /* Max bytes to transfer per transaction */
+#define MAX_QH 100 /* Max allowable queue heads in a chain */
#define MIN_UFR_PER_TICK 24 /* Min frames to process when catching up */
#define PERIODIC_ACTIVE 512 /* Micro-frames */
-/* Internal periodic / asynchronous schedule state machine states
+/*
+ * Internal periodic / asynchronous schedule state machine states
*/
typedef enum {
EST_INACTIVE = 1000,
EST_ACTIVE,
EST_EXECUTING,
EST_SLEEPING,
- /* The following states are internal to the state machine function
- */
+ /*
+ * The following states are internal to the state machine function
+ */
EST_WAITLISTHEAD,
EST_FETCHENTRY,
EST_FETCHQH,
@@ -71,13 +73,13 @@ typedef enum {
/* macros for accessing fields within next link pointer entry */
#define NLPTR_GET(x) ((x) & 0xffffffe0)
#define NLPTR_TYPE_GET(x) (((x) >> 1) & 3)
-#define NLPTR_TBIT(x) ((x) & 1) // 1=invalid, 0=valid
+#define NLPTR_TBIT(x) ((x) & 1) /* 1=invalid, 0=valid */
/* link pointer types */
-#define NLPTR_TYPE_ITD 0 // isoc xfer descriptor
-#define NLPTR_TYPE_QH 1 // queue head
-#define NLPTR_TYPE_STITD 2 // split xaction, isoc xfer descriptor
-#define NLPTR_TYPE_FSTN 3 // frame span traversal node
+#define NLPTR_TYPE_ITD 0 /* isoc xfer descriptor */
+#define NLPTR_TYPE_QH 1 /* queue head */
+#define NLPTR_TYPE_STITD 2 /* split xaction, isoc xfer descriptor */
+#define NLPTR_TYPE_FSTN 3 /* frame span traversal node */
#define SET_LAST_RUN_CLOCK(s) \
(s)->last_run_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
@@ -88,10 +90,10 @@ typedef enum {
#define set_field(data, newval, field) do { \
uint32_t val = *data; \
- val &= ~ field##_MASK; \
+ val &= ~field##_MASK; \
val |= ((newval) << field##_SH) & field##_MASK; \
*data = val; \
- } while(0)
+ } while (0)
static const char *ehci_state_names[] = {
[EST_INACTIVE] = "INACTIVE",
@@ -472,8 +474,10 @@ static bool ehci_verify_pid(EHCIQueue *q, EHCIqtd *qtd)
}
}
-/* Finish executing and writeback a packet outside of the regular
- fetchqh -> fetchqtd -> execute -> writeback cycle */
+/*
+ * Finish executing and writeback a packet outside of the regular
+ * fetchqh -> fetchqtd -> execute -> writeback cycle
+ */
static void ehci_writeback_async_complete_packet(EHCIPacket *p)
{
EHCIQueue *q = p->queue;
@@ -733,7 +737,7 @@ static void ehci_detach(USBPort *port)
ehci_queues_rip_device(s, port->dev, 0);
ehci_queues_rip_device(s, port->dev, 1);
- *portsc &= ~(PORTSC_CONNECT|PORTSC_PED|PORTSC_SUSPEND);
+ *portsc &= ~(PORTSC_CONNECT | PORTSC_PED | PORTSC_SUSPEND);
*portsc |= PORTSC_CSC;
ehci_raise_irq(s, USBSTS_PCD);
@@ -858,7 +862,7 @@ void ehci_reset(void *opaque)
* Do the detach before touching portsc, so that it correctly gets send to
* us or to our companion based on PORTSC_POWNER before the reset.
*/
- for(i = 0; i < EHCI_PORTS; i++) {
+ for (i = 0; i < EHCI_PORTS; i++) {
devs[i] = s->ports[i].dev;
if (devs[i] && devs[i]->attached) {
usb_detach(&s->ports[i]);
@@ -877,7 +881,7 @@ void ehci_reset(void *opaque)
s->astate = EST_INACTIVE;
s->pstate = EST_INACTIVE;
- for(i = 0; i < EHCI_PORTS; i++) {
+ for (i = 0; i < EHCI_PORTS; i++) {
if (s->companion_ports[i]) {
s->portsc[i] = PORTSC_POWNER | PORTSC_PPOWER;
} else {
@@ -942,8 +946,9 @@ static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner)
uint32_t *portsc = &s->portsc[port];
uint32_t orig;
- if (s->companion_ports[port] == NULL)
+ if (s->companion_ports[port] == NULL) {
return;
+ }
owner = owner & PORTSC_POWNER;
orig = *portsc & PORTSC_POWNER;
@@ -988,7 +993,7 @@ static void ehci_port_write(void *ptr, hwaddr addr,
trace_usb_ehci_port_reset(port, 1);
}
- if (!(val & PORTSC_PRESET) &&(*portsc & PORTSC_PRESET)) {
+ if (!(val & PORTSC_PRESET) && (*portsc & PORTSC_PRESET)) {
trace_usb_ehci_port_reset(port, 0);
if (dev && dev->attached) {
usb_port_reset(&s->ports[port]);
@@ -1065,8 +1070,10 @@ static void ehci_opreg_write(void *ptr, hwaddr addr,
break;
case USBSTS:
- val &= USBSTS_RO_MASK; // bits 6 through 31 are RO
- ehci_clear_usbsts(s, val); // bits 0 through 5 are R/WC
+ /* bits 6 through 31 are RO */
+ val &= USBSTS_RO_MASK;
+ /* bits 0 through 5 are R/WC */
+ ehci_clear_usbsts(s, val);
val = s->usbsts;
ehci_update_irq(s);
break;
@@ -1131,8 +1138,7 @@ static void ehci_flush_qh(EHCIQueue *q)
put_dwords(q->ehci, addr + 3 * sizeof(uint32_t), qh + 3, dwords - 3);
}
-// 4.10.2
-
+/* 4.10.2 */
static int ehci_qh_do_overlay(EHCIQueue *q)
{
EHCIPacket *p = QTAILQ_FIRST(&q->packets);
@@ -1145,8 +1151,7 @@ static int ehci_qh_do_overlay(EHCIQueue *q)
assert(p != NULL);
assert(p->qtdaddr == q->qtdaddr);
- // remember values in fields to preserve in qh after overlay
-
+ /* remember values in fields to preserve in qh after overlay */
dtoggle = q->qh.token & QTD_TOKEN_DTOGGLE;
ping = q->qh.token & QTD_TOKEN_PING;
@@ -1170,7 +1175,7 @@ static int ehci_qh_do_overlay(EHCIQueue *q)
}
if (!(q->qh.epchar & QH_EPCHAR_DTC)) {
- // preserve QH DT bit
+ /* preserve QH DT bit */
q->qh.token &= ~QTD_TOKEN_DTOGGLE;
q->qh.token |= dtoggle;
}
@@ -1397,9 +1402,7 @@ static int ehci_execute(EHCIPacket *p, const char *action)
return 1;
}
-/* 4.7.2
- */
-
+/* 4.7.2 */
static int ehci_process_itd(EHCIState *ehci,
EHCIitd *itd,
uint32_t addr)
@@ -1411,13 +1414,13 @@ static int ehci_process_itd(EHCIState *ehci,
ehci->periodic_sched_active = PERIODIC_ACTIVE;
- dir =(itd->bufptr[1] & ITD_BUFPTR_DIRECTION);
+ dir = (itd->bufptr[1] & ITD_BUFPTR_DIRECTION);
devaddr = get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR);
endp = get_field(itd->bufptr[0], ITD_BUFPTR_EP);
max = get_field(itd->bufptr[1], ITD_BUFPTR_MAXPKT);
mult = get_field(itd->bufptr[2], ITD_BUFPTR_MULT);
- for(i = 0; i < 8; i++) {
+ for (i = 0; i < 8; i++) {
if (itd->transact[i] & ITD_XACT_ACTIVE) {
pg = get_field(itd->transact[i], ITD_XACT_PGSEL);
off = itd->transact[i] & ITD_XACT_OFFSET_MASK;
@@ -1513,8 +1516,9 @@ static int ehci_process_itd(EHCIState *ehci,
}
-/* This state is the entry point for asynchronous schedule
- * processing. Entry here constitutes a EHCI start event state (4.8.5)
+/*
+ * This state is the entry point for asynchronous schedule
+ * processing. Entry here constitutes a EHCI start event state (4.8.5)
*/
static int ehci_state_waitlisthead(EHCIState *ehci, int async)
{
@@ -1531,7 +1535,7 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async)
ehci_queues_rip_unused(ehci, async);
/* Find the head of the list (4.9.1.1) */
- for(i = 0; i < MAX_QH; i++) {
+ for (i = 0; i < MAX_QH; i++) {
if (get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &qh,
sizeof(EHCIqh) >> 2) < 0) {
return 0;
@@ -1564,8 +1568,9 @@ out:
}
-/* This state is the entry point for periodic schedule processing as
- * well as being a continuation state for async processing.
+/*
+ * This state is the entry point for periodic schedule processing as
+ * well as being a continuation state for async processing.
*/
static int ehci_state_fetchentry(EHCIState *ehci, int async)
{
@@ -1674,7 +1679,7 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
#if EHCI_DEBUG
if (q->qhaddr != q->qh.next) {
- DPRINTF("FETCHQH: QH 0x%08x (h %x halt %x active %x) next 0x%08x\n",
+ DPRINTF("FETCHQH: QH 0x%08x (h %x halt %x active %x) next 0x%08x\n",
q->qhaddr,
q->qh.epchar & QH_EPCHAR_H,
q->qh.token & QTD_TOKEN_HALT,
@@ -1924,8 +1929,10 @@ static int ehci_state_execute(EHCIQueue *q)
return -1;
}
- // TODO verify enough time remains in the uframe as in 4.4.1.1
- // TODO write back ptr to async list when done or out of time
+ /*
+ * TODO verify enough time remains in the uframe as in 4.4.1.1
+ * TODO write back ptr to async list when done or out of time
+ */
/* 4.10.3, bottom of page 82, go horizontal on transaction counter == 0 */
if (!q->async && q->transact_ctr == 0) {
@@ -2036,7 +2043,7 @@ static void ehci_advance_state(EHCIState *ehci, int async)
int again;
do {
- switch(ehci_get_state(ehci, async)) {
+ switch (ehci_get_state(ehci, async)) {
case EST_WAITLISTHEAD:
again = ehci_state_waitlisthead(ehci, async);
break;
@@ -2115,21 +2122,20 @@ static void ehci_advance_state(EHCIState *ehci, int async)
ehci_reset(ehci);
again = 0;
}
- }
- while (again);
+ } while (again);
}
static void ehci_advance_async_state(EHCIState *ehci)
{
const int async = 1;
- switch(ehci_get_state(ehci, async)) {
+ switch (ehci_get_state(ehci, async)) {
case EST_INACTIVE:
if (!ehci_async_enabled(ehci)) {
break;
}
ehci_set_state(ehci, async, EST_ACTIVE);
- // No break, fall through to ACTIVE
+ /* No break, fall through to ACTIVE */
case EST_ACTIVE:
if (!ehci_async_enabled(ehci)) {
@@ -2153,7 +2159,8 @@ static void ehci_advance_async_state(EHCIState *ehci)
ehci_set_state(ehci, async, EST_WAITLISTHEAD);
ehci_advance_state(ehci, async);
- /* If the doorbell is set, the guest wants to make a change to the
+ /*
+ * If the doorbell is set, the guest wants to make a change to the
* schedule. The host controller needs to release cached data.
* (section 4.8.2)
*/
@@ -2180,13 +2187,13 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
uint32_t list;
const int async = 0;
- // 4.6
+ /* 4.6 */
- switch(ehci_get_state(ehci, async)) {
+ switch (ehci_get_state(ehci, async)) {
case EST_INACTIVE:
if (!(ehci->frindex & 7) && ehci_periodic_enabled(ehci)) {
ehci_set_state(ehci, async, EST_ACTIVE);
- // No break, fall through to ACTIVE
+ /* No break, fall through to ACTIVE */
} else
break;
@@ -2210,7 +2217,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
DPRINTF("PERIODIC state adv fr=%d. [%08X] -> %08X\n",
ehci->frindex / 8, list, entry);
- ehci_set_fetch_addr(ehci, async,entry);
+ ehci_set_fetch_addr(ehci, async, entry);
ehci_set_state(ehci, async, EST_FETCHENTRY);
ehci_advance_state(ehci, async);
ehci_queues_rip_unused(ehci, async);
@@ -2235,7 +2242,8 @@ static void ehci_update_frindex(EHCIState *ehci, int uframes)
ehci_raise_irq(ehci, USBSTS_FLR);
}
- /* How many times will frindex roll over 0x4000 with this frame count?
+ /*
+ * How many times will frindex roll over 0x4000 with this frame count?
* usbsts_frindex is decremented by 0x4000 on rollover until it reaches 0
*/
int rollovers = (ehci->frindex + uframes) / 0x4000;
@@ -2315,8 +2323,9 @@ static void ehci_work_bh(void *opaque)
ehci->async_stepdown++;
}
- /* Async is not inside loop since it executes everything it can once
- * called
+ /*
+ * Async is not inside loop since it executes everything it can once
+ * called
*/
if (ehci_async_enabled(ehci) || ehci->astate != EST_INACTIVE) {
need_timer++;
@@ -2334,15 +2343,18 @@ static void ehci_work_bh(void *opaque)
}
if (need_timer) {
- /* If we've raised int, we speed up the timer, so that we quickly
- * notice any new packets queued up in response */
+ /*
+ * If we've raised int, we speed up the timer, so that we quickly
+ * notice any new packets queued up in response
+ */
if (ehci->int_req_by_async && (ehci->usbsts & USBSTS_INT)) {
expire_time = t_now +
NANOSECONDS_PER_SECOND / (FRAME_TIMER_FREQ * 4);
ehci->int_req_by_async = false;
} else {
- expire_time = t_now + (NANOSECONDS_PER_SECOND
- * (ehci->async_stepdown+1) / FRAME_TIMER_FREQ);
+ expire_time = t_now
+ + (NANOSECONDS_PER_SECOND * (ehci->async_stepdown + 1) /
+ FRAME_TIMER_FREQ);
}
timer_mod(ehci->frame_timer, expire_time);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 69+ messages in thread
* [PATCH v3 04/17] hw/usb/hcd-ehci.c: Replace fprintf(stderr, ...) with qemu_log_mask(LOG_GUEST_ERROR)
2026-04-16 1:49 [PATCH v3 00/17] hw/usb/ehci: Add 64-bit descriptor addressing support Jamin Lin
` (2 preceding siblings ...)
2026-04-16 1:49 ` [PATCH v3 03/17] hw/usb/hcd-ehci.c: " Jamin Lin
@ 2026-04-16 1:49 ` Jamin Lin
2026-04-17 6:31 ` Philippe Mathieu-Daudé
2026-04-16 1:49 ` [PATCH v3 05/17] hw/usb/hcd-ehci: Replace DPRINTF debug logs with trace events Jamin Lin
` (13 subsequent siblings)
17 siblings, 1 reply; 69+ messages in thread
From: Jamin Lin @ 2026-04-16 1:49 UTC (permalink / raw)
To: philmd@linaro.org, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Jamin Lin, Troy Lee, flwu@google.com, nabihestefan@google.com
Replace direct fprintf(stderr, ...) calls with qemu_log_mask()
using LOG_GUEST_ERROR in the EHCI controller implementation.
Direct writes to stderr are discouraged in QEMU as they bypass
the logging framework and cannot be filtered or controlled at
runtime. Using qemu_log_mask() ensures that guest-visible errors
are properly categorized and can be managed via QEMU logging
options.
All affected messages correspond to guest-triggerable error
conditions, so LOG_GUEST_ERROR is used consistently.
This change improves integration with QEMU's logging infrastructure
and aligns with upstream coding guidelines.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
hw/usb/hcd-ehci.c | 43 +++++++++++++++++++++++++------------------
1 file changed, 25 insertions(+), 18 deletions(-)
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 9b92384bac..bebd137f94 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -36,6 +36,7 @@
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "system/runstate.h"
+#include "qemu/log.h"
#define FRAME_TIMER_FREQ 1000
#define FRAME_TIMER_NS (NANOSECONDS_PER_SECOND / FRAME_TIMER_FREQ)
@@ -425,7 +426,7 @@ static int ehci_get_pid(EHCIqtd *qtd)
case 2:
return USB_TOKEN_SETUP;
default:
- fprintf(stderr, "bad token\n");
+ qemu_log_mask(LOG_GUEST_ERROR, "bad token\n");
return 0;
}
}
@@ -532,7 +533,7 @@ static void ehci_free_packet(EHCIPacket *p)
}
if (p->async == EHCI_ASYNC_FINISHED &&
p->packet.status == USB_RET_SUCCESS) {
- fprintf(stderr,
+ qemu_log_mask(LOG_GUEST_ERROR,
"EHCI: Dropping completed packet from halted %s ep %02X\n",
(p->pid == USB_TOKEN_IN) ? "in" : "out",
get_field(p->queue->qh.epchar, QH_EPCHAR_EP));
@@ -1042,8 +1043,9 @@ static void ehci_opreg_write(void *ptr, hwaddr addr,
/* not supporting dynamic frame list size at the moment */
if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) {
- fprintf(stderr, "attempt to set frame list size -- value %d\n",
- (int)val & USBCMD_FLS);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "attempt to set frame list size -- value %d\n",
+ (int)val & USBCMD_FLS);
val &= ~USBCMD_FLS;
}
@@ -1101,7 +1103,7 @@ static void ehci_opreg_write(void *ptr, hwaddr addr,
case PERIODICLISTBASE:
if (ehci_periodic_enabled(s)) {
- fprintf(stderr,
+ qemu_log_mask(LOG_GUEST_ERROR,
"ehci: PERIODIC list base register set while periodic schedule\n"
" is enabled and HC is enabled\n");
}
@@ -1109,7 +1111,7 @@ static void ehci_opreg_write(void *ptr, hwaddr addr,
case ASYNCLISTADDR:
if (ehci_async_enabled(s)) {
- fprintf(stderr,
+ qemu_log_mask(LOG_GUEST_ERROR,
"ehci: ASYNC list address register set while async schedule\n"
" is enabled and HC is enabled\n");
}
@@ -1200,7 +1202,7 @@ static int ehci_init_transfer(EHCIPacket *p)
while (bytes > 0) {
if (cpage > 4) {
- fprintf(stderr, "cpage out of range (%u)\n", cpage);
+ qemu_log_mask(LOG_GUEST_ERROR, "cpage out of range (%u)\n", cpage);
qemu_sglist_destroy(&p->sgl);
return -1;
}
@@ -1306,7 +1308,8 @@ static void ehci_execute_complete(EHCIQueue *q)
break;
default:
/* should not be triggerable */
- fprintf(stderr, "USB invalid response %d\n", p->packet.status);
+ qemu_log_mask(LOG_GUEST_ERROR, "USB invalid response %d\n",
+ p->packet.status);
g_assert_not_reached();
}
@@ -1354,7 +1357,7 @@ static int ehci_execute(EHCIPacket *p, const char *action)
p->async == EHCI_ASYNC_INITIALIZED);
if (!(p->qtd.token & QTD_TOKEN_ACTIVE)) {
- fprintf(stderr, "Attempting to execute inactive qtd\n");
+ qemu_log_mask(LOG_GUEST_ERROR, "Attempting to execute inactive qtd\n");
return -1;
}
@@ -1395,7 +1398,8 @@ static int ehci_execute(EHCIPacket *p, const char *action)
p->packet.actual_length);
if (p->packet.actual_length > BUFF_SIZE) {
- fprintf(stderr, "ret from usb_handle_packet > BUFF_SIZE\n");
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ret from usb_handle_packet > BUFF_SIZE\n");
return -1;
}
@@ -1479,8 +1483,9 @@ static int ehci_process_itd(EHCIState *ehci,
case USB_RET_SUCCESS:
break;
default:
- fprintf(stderr, "Unexpected iso usb result: %d\n",
- ehci->ipacket.status);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "Unexpected iso usb result: %d\n",
+ ehci->ipacket.status);
/* Fall through */
case USB_RET_IOERROR:
case USB_RET_NODEV:
@@ -1584,7 +1589,8 @@ static int ehci_state_fetchentry(EHCIState *ehci, int async)
/* section 4.8, only QH in async schedule */
if (async && (NLPTR_TYPE_GET(entry) != NLPTR_TYPE_QH)) {
- fprintf(stderr, "non queue head request in async schedule\n");
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "non queue head request in async schedule\n");
return -1;
}
@@ -1606,7 +1612,7 @@ static int ehci_state_fetchentry(EHCIState *ehci, int async)
default:
/* TODO: handle FSTN type */
- fprintf(stderr, "FETCHENTRY: entry at %X is of type %u "
+ qemu_log_mask(LOG_GUEST_ERROR, "FETCHENTRY: entry at %X is of type %u "
"which is not supported yet\n", entry, NLPTR_TYPE_GET(entry));
return -1;
}
@@ -2112,13 +2118,14 @@ static void ehci_advance_state(EHCIState *ehci, int async)
break;
default:
- fprintf(stderr, "Bad state!\n");
+ qemu_log_mask(LOG_GUEST_ERROR, "Bad state!\n");
g_assert_not_reached();
}
if (again < 0 || itd_count > 16) {
/* TODO: notify guest (raise HSE irq?) */
- fprintf(stderr, "processing error - resetting ehci HC\n");
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "processing error - resetting ehci HC\n");
ehci_reset(ehci);
again = 0;
}
@@ -2175,7 +2182,7 @@ static void ehci_advance_async_state(EHCIState *ehci)
default:
/* this should only be due to a developer mistake */
- fprintf(stderr, "ehci: Bad asynchronous state %d. "
+ qemu_log_mask(LOG_GUEST_ERROR, "ehci: Bad asynchronous state %d. "
"Resetting to active\n", ehci->astate);
g_assert_not_reached();
}
@@ -2225,7 +2232,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
default:
/* this should only be due to a developer mistake */
- fprintf(stderr, "ehci: Bad periodic state %d. "
+ qemu_log_mask(LOG_GUEST_ERROR, "ehci: Bad periodic state %d. "
"Resetting to active\n", ehci->pstate);
g_assert_not_reached();
}
--
2.43.0
^ permalink raw reply related [flat|nested] 69+ messages in thread
* [PATCH v3 05/17] hw/usb/hcd-ehci: Replace DPRINTF debug logs with trace events
2026-04-16 1:49 [PATCH v3 00/17] hw/usb/ehci: Add 64-bit descriptor addressing support Jamin Lin
` (3 preceding siblings ...)
2026-04-16 1:49 ` [PATCH v3 04/17] hw/usb/hcd-ehci.c: Replace fprintf(stderr, ...) with qemu_log_mask(LOG_GUEST_ERROR) Jamin Lin
@ 2026-04-16 1:49 ` Jamin Lin
2026-04-17 5:04 ` Philippe Mathieu-Daudé
2026-04-16 1:49 ` [PATCH v3 06/17] hw/usb/hcd-ehci: Change descriptor addresses to 64-bit Jamin Lin
` (12 subsequent siblings)
17 siblings, 1 reply; 69+ messages in thread
From: Jamin Lin @ 2026-04-16 1:49 UTC (permalink / raw)
To: philmd@linaro.org, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Jamin Lin, Troy Lee, flwu@google.com, nabihestefan@google.com
Replace legacy DPRINTF() debug logging in the EHCI host controller
implementation with QEMU trace events.
The EHCI_DEBUG macro and associated DPRINTF() definitions are
removed as they are no longer needed.
Trace events are added for:
- packet submission and completion
- queue head execution state
- periodic schedule advancement
- ITD error conditions
- port state handling
- skipped microframes
No functional change.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
hw/usb/hcd-ehci.h | 10 ---------
hw/usb/hcd-ehci.c | 49 +++++++++++++++++++--------------------------
hw/usb/trace-events | 9 +++++++++
3 files changed, 30 insertions(+), 38 deletions(-)
diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
index 736407fd52..4234591cb4 100644
--- a/hw/usb/hcd-ehci.h
+++ b/hw/usb/hcd-ehci.h
@@ -24,16 +24,6 @@
#include "hw/pci/pci_device.h"
#include "hw/core/sysbus.h"
-#ifndef EHCI_DEBUG
-#define EHCI_DEBUG 0
-#endif
-
-#if EHCI_DEBUG
-#define DPRINTF printf
-#else
-#define DPRINTF(...)
-#endif
-
#define MMIO_SIZE 0x1000
#define CAPA_SIZE 0x10
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index bebd137f94..d0ea4949f9 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -839,7 +839,7 @@ static USBDevice *ehci_find_device(EHCIState *ehci, uint8_t addr)
for (i = 0; i < EHCI_PORTS; i++) {
port = &ehci->ports[i];
if (!(ehci->portsc[i] & PORTSC_PED)) {
- DPRINTF("Port %d not enabled\n", i);
+ trace_usb_ehci_port_disable(i);
continue;
}
dev = usb_find_device(port, addr);
@@ -1281,10 +1281,8 @@ static void ehci_execute_complete(EHCIQueue *q)
assert(p->async == EHCI_ASYNC_INITIALIZED ||
p->async == EHCI_ASYNC_FINISHED);
- DPRINTF("execute_complete: qhaddr 0x%x, next 0x%x, qtdaddr 0x%x, "
- "status %d, actual_length %d\n",
- q->qhaddr, q->qh.next, q->qtdaddr,
- p->packet.status, p->packet.actual_length);
+ trace_usb_ehci_execute_complete(q->qhaddr, q->qh.next, q->qtdaddr,
+ p->packet.status, p->packet.actual_length);
switch (p->packet.status) {
case USB_RET_SUCCESS:
@@ -1327,7 +1325,7 @@ static void ehci_execute_complete(EHCIQueue *q)
} else {
tbytes = 0;
}
- DPRINTF("updating tbytes to %d\n", tbytes);
+ trace_usb_ehci_qh_tbytes(tbytes);
set_field(&q->qh.token, tbytes, QTD_TOKEN_TBYTES);
ehci_finish_transfer(q, p->packet.actual_length);
@@ -1392,10 +1390,9 @@ static int ehci_execute(EHCIPacket *p, const char *action)
trace_usb_ehci_packet_action(p->queue, p, action);
usb_handle_packet(p->queue->dev, &p->packet);
- DPRINTF("submit: qh 0x%x next 0x%x qtd 0x%x pid 0x%x len %zd endp 0x%x "
- "status %d actual_length %d\n", p->queue->qhaddr, p->qtd.next,
- p->qtdaddr, p->pid, p->packet.iov.size, endp, p->packet.status,
- p->packet.actual_length);
+ trace_usb_ehci_packet_submit(p->queue->qhaddr, p->qtd.next, p->qtdaddr,
+ p->pid, p->packet.iov.size, endp,
+ p->packet.status, p->packet.actual_length);
if (p->packet.actual_length > BUFF_SIZE) {
qemu_log_mask(LOG_GUEST_ERROR,
@@ -1472,7 +1469,8 @@ static int ehci_process_itd(EHCIState *ehci,
usb_handle_packet(dev, &ehci->ipacket);
usb_packet_unmap(&ehci->ipacket, &ehci->isgl);
} else {
- DPRINTF("ISOCH: attempt to address non-iso endpoint\n");
+ trace_usb_ehci_log("ISOCH: "
+ "attempt to address non-iso endpoint");
ehci->ipacket.status = USB_RET_NAK;
ehci->ipacket.actual_length = 0;
}
@@ -1675,24 +1673,22 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
if (ehci->usbsts & USBSTS_REC) {
ehci_clear_usbsts(ehci, USBSTS_REC);
} else {
- DPRINTF("FETCHQH: QH 0x%08x. H-bit set, reclamation status reset"
- " - done processing\n", q->qhaddr);
+ trace_usb_ehci_fetchqh_reclaim_done(q->qhaddr);
ehci_set_state(ehci, async, EST_ACTIVE);
q = NULL;
goto out;
}
}
-#if EHCI_DEBUG
- if (q->qhaddr != q->qh.next) {
- DPRINTF("FETCHQH: QH 0x%08x (h %x halt %x active %x) next 0x%08x\n",
- q->qhaddr,
- q->qh.epchar & QH_EPCHAR_H,
- q->qh.token & QTD_TOKEN_HALT,
- q->qh.token & QTD_TOKEN_ACTIVE,
- q->qh.next);
+ if (trace_event_get_state_backends(TRACE_USB_EHCI_FETCHQH_DBG)) {
+ if (q->qhaddr != q->qh.next) {
+ trace_usb_ehci_fetchqh_dbg(q->qhaddr,
+ q->qh.epchar & QH_EPCHAR_H,
+ q->qh.token & QTD_TOKEN_HALT,
+ q->qh.token & QTD_TOKEN_ACTIVE,
+ q->qh.next);
+ }
}
-#endif
if (q->qh.token & QTD_TOKEN_HALT) {
ehci_set_state(ehci, async, EST_HORIZONTALQH);
@@ -2154,7 +2150,7 @@ static void ehci_advance_async_state(EHCIState *ehci)
/* make sure guest has acknowledged the doorbell interrupt */
/* TO-DO: is this really needed? */
if (ehci->usbsts & USBSTS_IAA) {
- DPRINTF("IAA status bit still set.\n");
+ trace_usb_ehci_log("IAA status bit still set.");
break;
}
@@ -2221,9 +2217,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
if (get_dwords(ehci, list, &entry, 1) < 0) {
break;
}
-
- DPRINTF("PERIODIC state adv fr=%d. [%08X] -> %08X\n",
- ehci->frindex / 8, list, entry);
+ trace_usb_ehci_periodic_state_advance(ehci->frindex / 8, list, entry);
ehci_set_fetch_addr(ehci, async, entry);
ehci_set_state(ehci, async, EST_FETCHENTRY);
ehci_advance_state(ehci, async);
@@ -2291,8 +2285,7 @@ static void ehci_work_bh(void *opaque)
ehci_update_frindex(ehci, skipped_uframes);
ehci->last_run_ns += UFRAME_TIMER_NS * skipped_uframes;
uframes -= skipped_uframes;
- DPRINTF("WARNING - EHCI skipped %"PRIu64" uframes\n",
- skipped_uframes);
+ trace_usb_ehci_skipped_uframes(skipped_uframes);
}
for (i = 0; i < uframes; i++) {
diff --git a/hw/usb/trace-events b/hw/usb/trace-events
index dd04f14add..0d4318dcf1 100644
--- a/hw/usb/trace-events
+++ b/hw/usb/trace-events
@@ -89,6 +89,7 @@ usb_ehci_state(const char *schedule, const char *state) "%s schedule %s"
usb_ehci_qh_ptrs(void *q, uint32_t addr, uint32_t nxt, uint32_t c_qtd, uint32_t n_qtd, uint32_t a_qtd) "q %p - QH @ 0x%08x: next 0x%08x qtds 0x%08x,0x%08x,0x%08x"
usb_ehci_qh_fields(uint32_t addr, int rl, int mplen, int eps, int ep, int devaddr) "QH @ 0x%08x - rl %d, mplen %d, eps %d, ep %d, dev %d"
usb_ehci_qh_bits(uint32_t addr, int c, int h, int dtc, int i) "QH @ 0x%08x - c %d, h %d, dtc %d, i %d"
+usb_ehci_qh_tbytes(uint32_t tbytes) "updating tbytes to %d"
usb_ehci_qtd_ptrs(void *q, uint32_t addr, uint32_t nxt, uint32_t altnext) "q %p - QTD @ 0x%08x: next 0x%08x altnext 0x%08x"
usb_ehci_qtd_fields(uint32_t addr, int tbytes, int cpage, int cerr, int pid) "QTD @ 0x%08x - tbytes %d, cpage %d, cerr %d, pid %d"
usb_ehci_qtd_bits(uint32_t addr, int ioc, int active, int halt, int babble, int xacterr) "QTD @ 0x%08x - ioc %d, active %d, halt %d, babble %d, xacterr %d"
@@ -100,13 +101,21 @@ usb_ehci_port_reset(uint32_t port, int enable) "reset port #%d - %d"
usb_ehci_port_suspend(uint32_t port) "port #%d"
usb_ehci_port_wakeup(uint32_t port) "port #%d"
usb_ehci_port_resume(uint32_t port) "port #%d"
+usb_ehci_port_disable(uint32_t port) "port #%d"
usb_ehci_queue_action(void *q, const char *action) "q %p: %s"
usb_ehci_packet_action(void *q, void *p, const char *action) "q %p p %p: %s"
+usb_ehci_packet_submit(uint32_t qhaddr, uint32_t next, uint32_t qtdaddr, int pid, size_t len, int endp, int status, int actual_length) "qh=0x%x, next=0x%x, qtd=0x%x, pid=0x%x, len=%zd, endp=0x%x, status=%d, actual_length=%d"
usb_ehci_irq(uint32_t level, uint32_t frindex, uint32_t sts, uint32_t mask) "level %d, frindex 0x%04x, sts 0x%x, mask 0x%x"
usb_ehci_guest_bug(const char *reason) "%s"
usb_ehci_doorbell_ring(void) ""
usb_ehci_doorbell_ack(void) ""
usb_ehci_dma_error(void) ""
+usb_ehci_execute_complete(uint32_t qhaddr, uint32_t next, uint32_t qtdaddr, int status, int actual_length) "qhaddr=0x%x, next=0x%x, qtdaddr=0x%x, status=%d, actual_length=%d"
+usb_ehci_fetchqh_reclaim_done(uint32_t qhaddr) "QH 0x%08x H-bit set, reclamation status reset - done processing"
+usb_ehci_fetchqh_dbg(uint32_t qhaddr, uint32_t h, uint32_t halt, uint32_t active, uint32_t next) "QH 0x%08x (h 0x%x halt 0x%x active 0x%x) next 0x%08x"
+usb_ehci_periodic_state_advance(uint32_t frame, uint32_t list, uint32_t entry) "frame=%d, list=0x%x, entry=0x%x"
+usb_ehci_skipped_uframes(uint64_t skipped_uframes) "skipped %" PRIu64 " uframes"
+usb_ehci_log(const char *msg) "%s"
# hcd-uhci.c
usb_uhci_reset(void) "=== RESET ==="
--
2.43.0
^ permalink raw reply related [flat|nested] 69+ messages in thread
* [PATCH v3 06/17] hw/usb/hcd-ehci: Change descriptor addresses to 64-bit
2026-04-16 1:49 [PATCH v3 00/17] hw/usb/ehci: Add 64-bit descriptor addressing support Jamin Lin
` (4 preceding siblings ...)
2026-04-16 1:49 ` [PATCH v3 05/17] hw/usb/hcd-ehci: Replace DPRINTF debug logs with trace events Jamin Lin
@ 2026-04-16 1:49 ` Jamin Lin
2026-04-17 4:54 ` Philippe Mathieu-Daudé
2026-04-17 7:01 ` Cédric Le Goater
2026-04-16 1:49 ` [PATCH v3 07/17] hw/usb/hcd-ehci: Add property to advertise 64-bit addressing capability Jamin Lin
` (11 subsequent siblings)
17 siblings, 2 replies; 69+ messages in thread
From: Jamin Lin @ 2026-04-16 1:49 UTC (permalink / raw)
To: philmd@linaro.org, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Jamin Lin, Troy Lee, flwu@google.com, nabihestefan@google.com
Change internal EHCI descriptor addresses from uint32_t to uint64_t.
The following fields are updated:
- EHCIPacket::qtdaddr
- EHCIQueue::{qhaddr, qtdaddr}
- EHCIState::{a_fetch_addr, p_fetch_addr}
Update get_dwords() and put_dwords() to take 64-bit addresses and
propagate the type change through the descriptor traversal paths.
Adjust NLPTR_GET() to operate on 64-bit values:
#define NLPTR_GET(x) ((x) & ~0x1fULL)
so that link pointer masking works correctly when descriptor
addresses exceed 32-bit space. The previous mask (0xffffffe0)
implicitly truncated addresses to 32 bits.
This patch does not change the on-wire descriptor layout yet.
It only removes the internal 32-bit address limit and prepares
for later patches that will add full 64-bit QH/qTD/iTD/siTD support.
Update the EHCI trace-events prototypes for QH, qTD, iTD, and siTD to
use uint64_t for the address argument and print it with PRIx64. This
ensures full 64-bit addresses are shown in trace output and improves
debugging of queue heads and transfer descriptors.
Migration compatibility:
The fetch address fields in EHCIState are extended from 32-bit to
64-bit, requiring a VMState version bump (v2 -> v3).
Backward compatibility is preserved by keeping the legacy 32-bit
fields (a_fetch_addr_pre_v3, p_fetch_addr_pre_v3) for pre-v3
migration streams via VMSTATE_UINT32_TEST(), and introducing new
64-bit fields for v3+.
In post_load, pre-v3 state is promoted to the 64-bit fields.
No functional change.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
hw/usb/hcd-ehci.h | 12 +++++----
hw/usb/hcd-ehci.c | 64 +++++++++++++++++++++++++++++----------------
hw/usb/trace-events | 24 ++++++++---------
3 files changed, 60 insertions(+), 40 deletions(-)
diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
index 4234591cb4..24eea9d23b 100644
--- a/hw/usb/hcd-ehci.h
+++ b/hw/usb/hcd-ehci.h
@@ -208,7 +208,7 @@ struct EHCIPacket {
QTAILQ_ENTRY(EHCIPacket) next;
EHCIqtd qtd; /* copy of current QTD (being worked on) */
- uint32_t qtdaddr; /* address QTD read from */
+ uint64_t qtdaddr; /* address QTD read from */
USBPacket packet;
QEMUSGList sgl;
@@ -229,8 +229,8 @@ struct EHCIQueue {
* when guest removes an entry (doorbell, handshake sequence)
*/
EHCIqh qh; /* copy of current QH (being worked on) */
- uint32_t qhaddr; /* address QH read from */
- uint32_t qtdaddr; /* address QTD read from */
+ uint64_t qhaddr; /* address QH read from */
+ uint64_t qtdaddr; /* address QTD read from */
int last_pid; /* pid of last packet executed */
USBDevice *dev;
QTAILQ_HEAD(, EHCIPacket) packets;
@@ -294,8 +294,10 @@ struct EHCIState {
EHCIQueueHead pqueues;
/* which address to look at next */
- uint32_t a_fetch_addr;
- uint32_t p_fetch_addr;
+ uint32_t a_fetch_addr_pre_v3;
+ uint32_t p_fetch_addr_pre_v3;
+ uint64_t a_fetch_addr;
+ uint64_t p_fetch_addr;
USBPacket ipacket;
QEMUSGList isgl;
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index d0ea4949f9..35173d27b4 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -72,7 +72,7 @@ typedef enum {
} EHCI_STATES;
/* macros for accessing fields within next link pointer entry */
-#define NLPTR_GET(x) ((x) & 0xffffffe0)
+#define NLPTR_GET(x) ((x) & ~0x1fULL)
#define NLPTR_TYPE_GET(x) (((x) >> 1) & 3)
#define NLPTR_TBIT(x) ((x) & 1) /* 1=invalid, 0=valid */
@@ -287,7 +287,7 @@ static int ehci_get_state(EHCIState *s, int async)
return async ? s->astate : s->pstate;
}
-static void ehci_set_fetch_addr(EHCIState *s, int async, uint32_t addr)
+static void ehci_set_fetch_addr(EHCIState *s, int async, uint64_t addr)
{
if (async) {
s->a_fetch_addr = addr;
@@ -296,7 +296,7 @@ static void ehci_set_fetch_addr(EHCIState *s, int async, uint32_t addr)
}
}
-static int ehci_get_fetch_addr(EHCIState *s, int async)
+static uint64_t ehci_get_fetch_addr(EHCIState *s, int async)
{
return async ? s->a_fetch_addr : s->p_fetch_addr;
}
@@ -373,7 +373,7 @@ static inline bool ehci_periodic_enabled(EHCIState *s)
}
/* Get an array of dwords from main memory */
-static inline int get_dwords(EHCIState *ehci, uint32_t addr,
+static inline int get_dwords(EHCIState *ehci, uint64_t addr,
uint32_t *buf, int num)
{
int i;
@@ -395,7 +395,7 @@ static inline int get_dwords(EHCIState *ehci, uint32_t addr,
}
/* Put an array of dwords in to main memory */
-static inline int put_dwords(EHCIState *ehci, uint32_t addr,
+static inline int put_dwords(EHCIState *ehci, uint64_t addr,
uint32_t *buf, int num)
{
int i;
@@ -549,7 +549,7 @@ static void ehci_free_packet(EHCIPacket *p)
/* queue management */
-static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, uint32_t addr, int async)
+static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, uint64_t addr, int async)
{
EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
EHCIQueue *q;
@@ -622,7 +622,7 @@ static void ehci_free_queue(EHCIQueue *q, const char *warn)
g_free(q);
}
-static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr,
+static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint64_t addr,
int async)
{
EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
@@ -1135,7 +1135,7 @@ static void ehci_flush_qh(EHCIQueue *q)
{
uint32_t *qh = (uint32_t *) &q->qh;
uint32_t dwords = sizeof(EHCIqh) >> 2;
- uint32_t addr = NLPTR_GET(q->qhaddr);
+ uint64_t addr = NLPTR_GET(q->qhaddr);
put_dwords(q->ehci, addr + 3 * sizeof(uint32_t), qh + 3, dwords - 3);
}
@@ -1406,12 +1406,13 @@ static int ehci_execute(EHCIPacket *p, const char *action)
/* 4.7.2 */
static int ehci_process_itd(EHCIState *ehci,
EHCIitd *itd,
- uint32_t addr)
+ uint64_t addr)
{
USBDevice *dev;
USBEndpoint *ep;
uint32_t i, len, pid, dir, devaddr, endp;
- uint32_t pg, off, ptr1, ptr2, max, mult;
+ uint32_t pg, off, max, mult;
+ uint64_t ptr1, ptr2;
ehci->periodic_sched_active = PERIODIC_ACTIVE;
@@ -1528,7 +1529,7 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async)
EHCIqh qh;
int i = 0;
int again = 0;
- uint32_t entry = ehci->asynclistaddr;
+ uint64_t entry = ehci->asynclistaddr;
/* set reclamation flag at start event (4.8.6) */
if (async) {
@@ -1578,7 +1579,7 @@ out:
static int ehci_state_fetchentry(EHCIState *ehci, int async)
{
int again = 0;
- uint32_t entry = ehci_get_fetch_addr(ehci, async);
+ uint64_t entry = ehci_get_fetch_addr(ehci, async);
if (NLPTR_TBIT(entry)) {
ehci_set_state(ehci, async, EST_ACTIVE);
@@ -1610,8 +1611,10 @@ static int ehci_state_fetchentry(EHCIState *ehci, int async)
default:
/* TODO: handle FSTN type */
- qemu_log_mask(LOG_GUEST_ERROR, "FETCHENTRY: entry at %X is of type %u "
- "which is not supported yet\n", entry, NLPTR_TYPE_GET(entry));
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "FETCHENTRY: entry at %" PRIx64 "is of type %" PRIu64
+ "which is not supported yet\n",
+ entry, NLPTR_TYPE_GET(entry));
return -1;
}
@@ -1621,7 +1624,7 @@ out:
static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
{
- uint32_t entry;
+ uint64_t entry;
EHCIQueue *q;
EHCIqh qh;
@@ -1710,7 +1713,7 @@ out:
static int ehci_state_fetchitd(EHCIState *ehci, int async)
{
- uint32_t entry;
+ uint64_t entry;
EHCIitd itd;
assert(!async);
@@ -1736,7 +1739,7 @@ static int ehci_state_fetchitd(EHCIState *ehci, int async)
static int ehci_state_fetchsitd(EHCIState *ehci, int async)
{
- uint32_t entry;
+ uint64_t entry;
EHCIsitd sitd;
assert(!async);
@@ -1794,7 +1797,7 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
EHCIqtd qtd;
EHCIPacket *p;
int again = 1;
- uint32_t addr;
+ uint64_t addr;
addr = NLPTR_GET(q->qtdaddr);
if (get_dwords(q->ehci, addr + 8, &qtd.token, 1) < 0) {
@@ -1877,7 +1880,7 @@ static int ehci_fill_queue(EHCIPacket *p)
USBEndpoint *ep = p->packet.ep;
EHCIQueue *q = p->queue;
EHCIqtd qtd = p->qtd;
- uint32_t qtdaddr;
+ uint64_t qtdaddr;
for (;;) {
if (NLPTR_TBIT(qtd.next) != 0) {
@@ -2000,7 +2003,8 @@ static int ehci_state_executing(EHCIQueue *q)
static int ehci_state_writeback(EHCIQueue *q)
{
EHCIPacket *p = QTAILQ_FIRST(&q->packets);
- uint32_t *qtd, addr;
+ uint32_t *qtd;
+ uint64_t addr;
int again = 0;
/* Write back the QTD from the QH area */
@@ -2441,6 +2445,11 @@ static int usb_ehci_post_load(void *opaque, int version_id)
}
}
+ if (version_id < 3) {
+ s->a_fetch_addr = s->a_fetch_addr_pre_v3;
+ s->p_fetch_addr = s->p_fetch_addr_pre_v3;
+ }
+
return 0;
}
@@ -2470,9 +2479,14 @@ static void usb_ehci_vm_state_change(void *opaque, bool running, RunState state)
}
}
+static bool ehci_core_is_before_version_3(void *opaque, int version_id)
+{
+ return version_id < 3;
+}
+
const VMStateDescription vmstate_ehci = {
.name = "ehci-core",
- .version_id = 2,
+ .version_id = 3,
.minimum_version_id = 1,
.pre_save = usb_ehci_pre_save,
.post_load = usb_ehci_post_load,
@@ -2501,8 +2515,12 @@ const VMStateDescription vmstate_ehci = {
/* schedule state */
VMSTATE_UINT32(astate, EHCIState),
VMSTATE_UINT32(pstate, EHCIState),
- VMSTATE_UINT32(a_fetch_addr, EHCIState),
- VMSTATE_UINT32(p_fetch_addr, EHCIState),
+ VMSTATE_UINT32_TEST(a_fetch_addr_pre_v3, EHCIState,
+ ehci_core_is_before_version_3),
+ VMSTATE_UINT32_TEST(p_fetch_addr_pre_v3, EHCIState,
+ ehci_core_is_before_version_3),
+ VMSTATE_UINT64_V(a_fetch_addr, EHCIState, 3),
+ VMSTATE_UINT64_V(p_fetch_addr, EHCIState, 3),
VMSTATE_END_OF_LIST()
}
};
diff --git a/hw/usb/trace-events b/hw/usb/trace-events
index 0d4318dcf1..8c90688bb3 100644
--- a/hw/usb/trace-events
+++ b/hw/usb/trace-events
@@ -86,15 +86,15 @@ usb_ehci_portsc_write(uint32_t addr, uint32_t port, uint32_t val) "wr mmio 0x%04
usb_ehci_portsc_change(uint32_t addr, uint32_t port, uint32_t new, uint32_t old) "ch mmio 0x%04x [port %d] = 0x%x (old: 0x%x)"
usb_ehci_usbsts(const char *sts, int state) "usbsts %s %d"
usb_ehci_state(const char *schedule, const char *state) "%s schedule %s"
-usb_ehci_qh_ptrs(void *q, uint32_t addr, uint32_t nxt, uint32_t c_qtd, uint32_t n_qtd, uint32_t a_qtd) "q %p - QH @ 0x%08x: next 0x%08x qtds 0x%08x,0x%08x,0x%08x"
-usb_ehci_qh_fields(uint32_t addr, int rl, int mplen, int eps, int ep, int devaddr) "QH @ 0x%08x - rl %d, mplen %d, eps %d, ep %d, dev %d"
-usb_ehci_qh_bits(uint32_t addr, int c, int h, int dtc, int i) "QH @ 0x%08x - c %d, h %d, dtc %d, i %d"
+usb_ehci_qh_ptrs(void *q, uint64_t addr, uint32_t nxt, uint32_t c_qtd, uint32_t n_qtd, uint32_t a_qtd) "q %p - QH @ 0x%" PRIx64 ": next 0x%08x qtds 0x%08x,0x%08x,0x%08x"
+usb_ehci_qh_fields(uint64_t addr, int rl, int mplen, int eps, int ep, int devaddr) "QH @ 0x%" PRIx64 " - rl %d, mplen %d, eps %d, ep %d, dev %d"
+usb_ehci_qh_bits(uint64_t addr, int c, int h, int dtc, int i) "QH @ 0x%" PRIx64 " - c %d, h %d, dtc %d, i %d"
usb_ehci_qh_tbytes(uint32_t tbytes) "updating tbytes to %d"
-usb_ehci_qtd_ptrs(void *q, uint32_t addr, uint32_t nxt, uint32_t altnext) "q %p - QTD @ 0x%08x: next 0x%08x altnext 0x%08x"
-usb_ehci_qtd_fields(uint32_t addr, int tbytes, int cpage, int cerr, int pid) "QTD @ 0x%08x - tbytes %d, cpage %d, cerr %d, pid %d"
-usb_ehci_qtd_bits(uint32_t addr, int ioc, int active, int halt, int babble, int xacterr) "QTD @ 0x%08x - ioc %d, active %d, halt %d, babble %d, xacterr %d"
-usb_ehci_itd(uint32_t addr, uint32_t nxt, uint32_t mplen, uint32_t mult, uint32_t ep, uint32_t devaddr) "ITD @ 0x%08x: next 0x%08x - mplen %d, mult %d, ep %d, dev %d"
-usb_ehci_sitd(uint32_t addr, uint32_t nxt, uint32_t active) "ITD @ 0x%08x: next 0x%08x - active %d"
+usb_ehci_qtd_ptrs(void *q, uint64_t addr, uint32_t nxt, uint32_t altnext) "q %p - QTD @ 0x%" PRIx64 ": next 0x%08x altnext 0x%08x"
+usb_ehci_qtd_fields(uint64_t addr, int tbytes, int cpage, int cerr, int pid) "QTD @ 0x%" PRIx64 " - tbytes %d, cpage %d, cerr %d, pid %d"
+usb_ehci_qtd_bits(uint64_t addr, int ioc, int active, int halt, int babble, int xacterr) "QTD @ 0x%" PRIx64 " - ioc %d, active %d, halt %d, babble %d, xacterr %d"
+usb_ehci_itd(uint64_t addr, uint32_t nxt, uint32_t mplen, uint32_t mult, uint32_t ep, uint32_t devaddr) "ITD @ 0x%" PRIx64 ": next 0x%08x - mplen %d, mult %d, ep %d, dev %d"
+usb_ehci_sitd(uint64_t addr, uint32_t nxt, uint32_t active) "SITD @ 0x%" PRIx64 ": next 0x%08x - active %d"
usb_ehci_port_attach(uint32_t port, const char *owner, const char *device) "attach port #%d, owner %s, device %s"
usb_ehci_port_detach(uint32_t port, const char *owner) "detach port #%d, owner %s"
usb_ehci_port_reset(uint32_t port, int enable) "reset port #%d - %d"
@@ -104,15 +104,15 @@ usb_ehci_port_resume(uint32_t port) "port #%d"
usb_ehci_port_disable(uint32_t port) "port #%d"
usb_ehci_queue_action(void *q, const char *action) "q %p: %s"
usb_ehci_packet_action(void *q, void *p, const char *action) "q %p p %p: %s"
-usb_ehci_packet_submit(uint32_t qhaddr, uint32_t next, uint32_t qtdaddr, int pid, size_t len, int endp, int status, int actual_length) "qh=0x%x, next=0x%x, qtd=0x%x, pid=0x%x, len=%zd, endp=0x%x, status=%d, actual_length=%d"
+usb_ehci_packet_submit(uint64_t qhaddr, uint32_t next, uint64_t qtdaddr, int pid, size_t len, int endp, int status, int actual_length) "qh=0x%" PRIx64 ", next=0x%x, qtd=0x%" PRIx64 ", pid=0x%x, len=%zd, endp=0x%x, status=%d, actual_length=%d"
usb_ehci_irq(uint32_t level, uint32_t frindex, uint32_t sts, uint32_t mask) "level %d, frindex 0x%04x, sts 0x%x, mask 0x%x"
usb_ehci_guest_bug(const char *reason) "%s"
usb_ehci_doorbell_ring(void) ""
usb_ehci_doorbell_ack(void) ""
usb_ehci_dma_error(void) ""
-usb_ehci_execute_complete(uint32_t qhaddr, uint32_t next, uint32_t qtdaddr, int status, int actual_length) "qhaddr=0x%x, next=0x%x, qtdaddr=0x%x, status=%d, actual_length=%d"
-usb_ehci_fetchqh_reclaim_done(uint32_t qhaddr) "QH 0x%08x H-bit set, reclamation status reset - done processing"
-usb_ehci_fetchqh_dbg(uint32_t qhaddr, uint32_t h, uint32_t halt, uint32_t active, uint32_t next) "QH 0x%08x (h 0x%x halt 0x%x active 0x%x) next 0x%08x"
+usb_ehci_execute_complete(uint64_t qhaddr, uint32_t next, uint64_t qtdaddr, int status, int actual_length) "qhaddr=0x%" PRIx64 ", next=0x%x, qtdaddr=0x%" PRIx64 ", status=%d, actual_length=%d"
+usb_ehci_fetchqh_reclaim_done(uint64_t qhaddr) "QH 0x%" PRIx64 " H-bit set, reclamation status reset - done processing"
+usb_ehci_fetchqh_dbg(uint64_t qhaddr, uint32_t h, uint32_t halt, uint32_t active, uint32_t next) "QH 0x%" PRIx64 " (h 0x%x halt 0x%x active 0x%x) next 0x%08x"
usb_ehci_periodic_state_advance(uint32_t frame, uint32_t list, uint32_t entry) "frame=%d, list=0x%x, entry=0x%x"
usb_ehci_skipped_uframes(uint64_t skipped_uframes) "skipped %" PRIu64 " uframes"
usb_ehci_log(const char *msg) "%s"
--
2.43.0
^ permalink raw reply related [flat|nested] 69+ messages in thread
* [PATCH v3 07/17] hw/usb/hcd-ehci: Add property to advertise 64-bit addressing capability
2026-04-16 1:49 [PATCH v3 00/17] hw/usb/ehci: Add 64-bit descriptor addressing support Jamin Lin
` (5 preceding siblings ...)
2026-04-16 1:49 ` [PATCH v3 06/17] hw/usb/hcd-ehci: Change descriptor addresses to 64-bit Jamin Lin
@ 2026-04-16 1:49 ` Jamin Lin
2026-04-17 4:55 ` Philippe Mathieu-Daudé
2026-04-16 1:49 ` [PATCH v3 08/17] hw/usb/hcd-ehci: Reject CTRLDSSEGMENT writes without 64-bit capability Jamin Lin
` (10 subsequent siblings)
17 siblings, 1 reply; 69+ messages in thread
From: Jamin Lin @ 2026-04-16 1:49 UTC (permalink / raw)
To: philmd@linaro.org, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Jamin Lin, Troy Lee, flwu@google.com, nabihestefan@google.com,
Cédric Le Goater
Introduce a new boolean property, "caps-64bit-addr", to control
HCCPARAMS[0] (64-bit Addressing Capability).
When enabled, the EHCI controller advertises support for 64-bit
address memory pointers as defined in the EHCI specification
(Table 2-7, HCCPARAMS). This allows software to use the 64-bit
data structure formats described in Appendix B.
When disabled (default), the controller reports 32-bit addressing
capability and uses the standard 32-bit data structures.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
---
hw/usb/hcd-ehci.h | 1 +
hw/usb/hcd-ehci-pci.c | 2 ++
hw/usb/hcd-ehci-sysbus.c | 2 ++
hw/usb/hcd-ehci.c | 5 ++++-
4 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
index 24eea9d23b..fe4c508c32 100644
--- a/hw/usb/hcd-ehci.h
+++ b/hw/usb/hcd-ehci.h
@@ -256,6 +256,7 @@ struct EHCIState {
/* properties */
uint32_t maxframes;
+ bool caps_64bit_addr;
/*
* EHCI spec version 1.0 Section 2.3
diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c
index 9febcc1031..2ea8549db9 100644
--- a/hw/usb/hcd-ehci-pci.c
+++ b/hw/usb/hcd-ehci-pci.c
@@ -137,6 +137,8 @@ static void usb_ehci_pci_write_config(PCIDevice *dev, uint32_t addr,
static const Property ehci_pci_properties[] = {
DEFINE_PROP_UINT32("maxframes", EHCIPCIState, ehci.maxframes, 128),
+ DEFINE_PROP_BOOL("caps-64bit-addr", EHCIPCIState, ehci.caps_64bit_addr,
+ false),
};
static const VMStateDescription vmstate_ehci_pci = {
diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c
index b31032bbf3..61215e9f3d 100644
--- a/hw/usb/hcd-ehci-sysbus.c
+++ b/hw/usb/hcd-ehci-sysbus.c
@@ -34,6 +34,8 @@ static const Property ehci_sysbus_properties[] = {
DEFINE_PROP_UINT32("maxframes", EHCISysBusState, ehci.maxframes, 128),
DEFINE_PROP_BOOL("companion-enable", EHCISysBusState, ehci.companion_enable,
false),
+ DEFINE_PROP_BOOL("caps-64bit-addr", EHCISysBusState, ehci.caps_64bit_addr,
+ false),
};
static void usb_ehci_sysbus_realize(DeviceState *dev, Error **errp)
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 35173d27b4..6409457186 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -2539,6 +2539,9 @@ void usb_ehci_realize(EHCIState *s, DeviceState *dev, Error **errp)
s->maxframes);
return;
}
+ if (s->caps_64bit_addr) {
+ s->caps[0x08] |= BIT(0);
+ }
memory_region_add_subregion(&s->mem, s->capsbase, &s->mem_caps);
memory_region_add_subregion(&s->mem, s->opregbase, &s->mem_opreg);
@@ -2598,7 +2601,7 @@ void usb_ehci_init(EHCIState *s, DeviceState *dev)
s->caps[0x05] = 0x00; /* No companion ports at present */
s->caps[0x06] = 0x00;
s->caps[0x07] = 0x00;
- s->caps[0x08] = 0x80; /* We can cache whole frame, no 64-bit */
+ s->caps[0x08] = 0x80; /* We can cache whole frame */
s->caps[0x0a] = 0x00;
s->caps[0x0b] = 0x00;
--
2.43.0
^ permalink raw reply related [flat|nested] 69+ messages in thread
* [PATCH v3 08/17] hw/usb/hcd-ehci: Reject CTRLDSSEGMENT writes without 64-bit capability
2026-04-16 1:49 [PATCH v3 00/17] hw/usb/ehci: Add 64-bit descriptor addressing support Jamin Lin
` (6 preceding siblings ...)
2026-04-16 1:49 ` [PATCH v3 07/17] hw/usb/hcd-ehci: Add property to advertise 64-bit addressing capability Jamin Lin
@ 2026-04-16 1:49 ` Jamin Lin
2026-04-17 6:33 ` Philippe Mathieu-Daudé
2026-04-16 1:49 ` [PATCH v3 09/17] hw/usb/hcd-ehci: Implement 64-bit QH descriptor addressing Jamin Lin
` (9 subsequent siblings)
17 siblings, 1 reply; 69+ messages in thread
From: Jamin Lin @ 2026-04-16 1:49 UTC (permalink / raw)
To: philmd@linaro.org, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Jamin Lin, Troy Lee, flwu@google.com, nabihestefan@google.com
The EHCI CTRLDSSEGMENT register provides the upper 32 bits [63:32] used to
form 64-bit addresses for EHCI control data structures. Per EHCI 1.0
spec section 2.3.5, when the HCCPARAMS 64-bit Addressing Capability bit
is zero, CTRLDSSEGMENT is not used: software cannot write it and reads
must return zero.
Add a capability check in the operational register write handler and
reject guest writes to CTRLDSSEGMENT when 64-bit addressing is
not enabled.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
hw/usb/hcd-ehci.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 6409457186..b9e4251d62 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -1108,7 +1108,14 @@ static void ehci_opreg_write(void *ptr, hwaddr addr,
" is enabled and HC is enabled\n");
}
break;
-
+ case CTRLDSSEGMENT:
+ if (!s->caps_64bit_addr) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ehci: write to CTRLDSSEGMENT while "
+ " 64-bit addressing capability is disabled\n");
+ return;
+ }
+ break;
case ASYNCLISTADDR:
if (ehci_async_enabled(s)) {
qemu_log_mask(LOG_GUEST_ERROR,
--
2.43.0
^ permalink raw reply related [flat|nested] 69+ messages in thread
* [PATCH v3 09/17] hw/usb/hcd-ehci: Implement 64-bit QH descriptor addressing
2026-04-16 1:49 [PATCH v3 00/17] hw/usb/ehci: Add 64-bit descriptor addressing support Jamin Lin
` (7 preceding siblings ...)
2026-04-16 1:49 ` [PATCH v3 08/17] hw/usb/hcd-ehci: Reject CTRLDSSEGMENT writes without 64-bit capability Jamin Lin
@ 2026-04-16 1:49 ` Jamin Lin
2026-04-17 5:03 ` Philippe Mathieu-Daudé
2026-04-16 1:49 ` [PATCH v3 10/17] hw/usb/hcd-ehci: Implement 64-bit qTD " Jamin Lin
` (8 subsequent siblings)
17 siblings, 1 reply; 69+ messages in thread
From: Jamin Lin @ 2026-04-16 1:49 UTC (permalink / raw)
To: philmd@linaro.org, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Jamin Lin, Troy Lee, flwu@google.com, nabihestefan@google.com
EHCI supports 64-bit control data structure addressing when the
64-bit Addressing Capability bit in HCCPARAMS is set. In that mode,
the CTRLDSSEGMENT register supplies the upper 32 bits which are
concatenated with 32-bit link pointer fields to form full 64-bit
descriptor addresses (EHCI 1.0, section 2.3.5 and Appendix B).
The current implementation assumes 32-bit QH descriptor addresses
and directly uses link pointer values without applying the
CTRLDSSEGMENT upper dword.
Introduce a helper, ehci_get_desc_addr(), to construct full 64-bit
descriptor addresses when 64-bit capability is enabled. Update QH
traversal paths (async list walk, horizontal QH link, and periodic
schedule entry handling) to use the translated 64-bit addresses.
EHCI 64-bit buffer pointer fields are defined in Appendix B as
split 32-bit low/high parts located at separate offsets, rather
than a single contiguous 64-bit field. Therefore, the buffer
pointers cannot be represented as uint64_t bufptr[5] without
violating the descriptor layout defined by the specification.
Introduce ehci_get_buf_addr() to construct full 64-bit buffer
addresses from bufptr[] and bufptr_hi[] fields. Use this helper
when calculating transfer buffer addresses so that data buffers
above 4GB are correctly handled.
Also add bufptr_hi[5] to EHCIqh to support 64-bit buffer pointer
fields as defined in Appendix B.
When 64-bit capability is disabled, descriptor addresses remain
32-bit and existing behaviour is unchanged.
Note: Similar split 64-bit buffer pointer handling is required for
qTD, iTD and siTD descriptors, which will be addressed in follow-up
changes.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
hw/usb/hcd-ehci.h | 4 ++++
hw/usb/hcd-ehci.c | 48 ++++++++++++++++++++++++++++++++++-----------
hw/usb/trace-events | 2 +-
3 files changed, 42 insertions(+), 12 deletions(-)
diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
index fe4c508c32..773f376834 100644
--- a/hw/usb/hcd-ehci.h
+++ b/hw/usb/hcd-ehci.h
@@ -141,6 +141,9 @@ typedef struct EHCIqtd {
#define QTD_BUFPTR_SH 12
} EHCIqtd;
+/* QH overlay: altnext_qtd, token, bufptr[5], bufptr_hi[5] */
+#define EHCI_QH_OVERLAY_COUNT 12
+
/*
* EHCI spec version 1.0 Section 3.6
*/
@@ -194,6 +197,7 @@ typedef struct EHCIqh {
#define BUFPTR_FRAMETAG_MASK 0x0000001f
#define BUFPTR_SBYTES_MASK 0x00000fe0
#define BUFPTR_SBYTES_SH 5
+ uint32_t bufptr_hi[5];
} EHCIqh;
enum async_state {
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index b9e4251d62..37ae637e08 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -147,6 +147,24 @@ static const char *addr2str(hwaddr addr)
return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), addr);
}
+static uint64_t ehci_get_buf_addr(EHCIState *s, uint32_t hi, uint32_t low,
+ uint32_t mask)
+{
+ uint64_t addr;
+
+ addr = (uint64_t)(low & mask);
+ if (s->caps_64bit_addr) {
+ addr |= (uint64_t)hi << 32;
+ }
+
+ return addr;
+}
+
+static uint64_t ehci_get_desc_addr(EHCIState *s, uint32_t low)
+{
+ return ehci_get_buf_addr(s, s->ctrldssegment, low, UINT32_MAX);
+}
+
static void ehci_trace_usbsts(uint32_t mask, int state)
{
/* interrupts */
@@ -440,7 +458,7 @@ static bool ehci_verify_qh(EHCIQueue *q, EHCIqh *qh)
(qh->current_qtd != q->qh.current_qtd) ||
(q->async && qh->next_qtd != q->qh.next_qtd) ||
(memcmp(&qh->altnext_qtd, &q->qh.altnext_qtd,
- 7 * sizeof(uint32_t)) != 0) ||
+ EHCI_QH_OVERLAY_COUNT * sizeof(uint32_t)) != 0) ||
(q->dev != NULL && q->dev->addr != devaddr)) {
return false;
} else {
@@ -1536,7 +1554,9 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async)
EHCIqh qh;
int i = 0;
int again = 0;
- uint64_t entry = ehci->asynclistaddr;
+ uint64_t entry = 0;
+
+ entry = ehci_get_desc_addr(ehci, ehci->asynclistaddr);
/* set reclamation flag at start event (4.8.6) */
if (async) {
@@ -1564,8 +1584,8 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async)
goto out;
}
- entry = qh.next;
- if (entry == ehci->asynclistaddr) {
+ entry = ehci_get_desc_addr(ehci, qh.next);
+ if (entry == ehci_get_desc_addr(ehci, ehci->asynclistaddr)) {
break;
}
}
@@ -1691,7 +1711,7 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
}
if (trace_event_get_state_backends(TRACE_USB_EHCI_FETCHQH_DBG)) {
- if (q->qhaddr != q->qh.next) {
+ if (q->qhaddr != ehci_get_desc_addr(ehci, q->qh.next)) {
trace_usb_ehci_fetchqh_dbg(q->qhaddr,
q->qh.epchar & QH_EPCHAR_H,
q->qh.token & QTD_TOKEN_HALT,
@@ -1868,10 +1888,12 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
static int ehci_state_horizqh(EHCIQueue *q)
{
+ uint64_t addr;
int again = 0;
- if (ehci_get_fetch_addr(q->ehci, q->async) != q->qh.next) {
- ehci_set_fetch_addr(q->ehci, q->async, q->qh.next);
+ addr = ehci_get_desc_addr(q->ehci, q->qh.next);
+ if (ehci_get_fetch_addr(q->ehci, q->async) != addr) {
+ ehci_set_fetch_addr(q->ehci, q->async, addr);
ehci_set_state(q->ehci, q->async, EST_FETCHENTRY);
again = 1;
} else {
@@ -2200,6 +2222,8 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
uint32_t entry;
uint32_t list;
const int async = 0;
+ uint64_t entry64;
+ uint64_t list64;
/* 4.6 */
@@ -2224,12 +2248,14 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
break;
}
list |= ((ehci->frindex & 0x1ff8) >> 1);
-
- if (get_dwords(ehci, list, &entry, 1) < 0) {
+ list64 = ehci_get_desc_addr(ehci, list);
+ if (get_dwords(ehci, list64, &entry, 1) < 0) {
break;
}
- trace_usb_ehci_periodic_state_advance(ehci->frindex / 8, list, entry);
- ehci_set_fetch_addr(ehci, async, entry);
+ entry64 = ehci_get_desc_addr(ehci, entry);
+ trace_usb_ehci_periodic_state_advance(ehci->frindex / 8,
+ list64, entry64);
+ ehci_set_fetch_addr(ehci, async, entry64);
ehci_set_state(ehci, async, EST_FETCHENTRY);
ehci_advance_state(ehci, async);
ehci_queues_rip_unused(ehci, async);
diff --git a/hw/usb/trace-events b/hw/usb/trace-events
index 8c90688bb3..67249d69c2 100644
--- a/hw/usb/trace-events
+++ b/hw/usb/trace-events
@@ -113,7 +113,7 @@ usb_ehci_dma_error(void) ""
usb_ehci_execute_complete(uint64_t qhaddr, uint32_t next, uint64_t qtdaddr, int status, int actual_length) "qhaddr=0x%" PRIx64 ", next=0x%x, qtdaddr=0x%" PRIx64 ", status=%d, actual_length=%d"
usb_ehci_fetchqh_reclaim_done(uint64_t qhaddr) "QH 0x%" PRIx64 " H-bit set, reclamation status reset - done processing"
usb_ehci_fetchqh_dbg(uint64_t qhaddr, uint32_t h, uint32_t halt, uint32_t active, uint32_t next) "QH 0x%" PRIx64 " (h 0x%x halt 0x%x active 0x%x) next 0x%08x"
-usb_ehci_periodic_state_advance(uint32_t frame, uint32_t list, uint32_t entry) "frame=%d, list=0x%x, entry=0x%x"
+usb_ehci_periodic_state_advance(uint32_t frame, uint64_t list, uint64_t entry) "frame=%d, list=0x%" PRIx64 ", entry=0x%" PRIx64
usb_ehci_skipped_uframes(uint64_t skipped_uframes) "skipped %" PRIu64 " uframes"
usb_ehci_log(const char *msg) "%s"
--
2.43.0
^ permalink raw reply related [flat|nested] 69+ messages in thread
* [PATCH v3 10/17] hw/usb/hcd-ehci: Implement 64-bit qTD descriptor addressing
2026-04-16 1:49 [PATCH v3 00/17] hw/usb/ehci: Add 64-bit descriptor addressing support Jamin Lin
` (8 preceding siblings ...)
2026-04-16 1:49 ` [PATCH v3 09/17] hw/usb/hcd-ehci: Implement 64-bit QH descriptor addressing Jamin Lin
@ 2026-04-16 1:49 ` Jamin Lin
2026-04-17 6:14 ` Philippe Mathieu-Daudé
2026-04-16 1:49 ` [PATCH v3 11/17] hw/usb/hcd-ehci: Implement 64-bit iTD " Jamin Lin
` (7 subsequent siblings)
17 siblings, 1 reply; 69+ messages in thread
From: Jamin Lin @ 2026-04-16 1:49 UTC (permalink / raw)
To: philmd@linaro.org, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Jamin Lin, Troy Lee, flwu@google.com, nabihestefan@google.com
EHCI supports 64-bit addressing when the 64-bit Addressing Capability
bit in HCCPARAMS is set. In that mode, the CTRLDSSEGMENT register
provides the upper 32 bits that are concatenated with 32-bit link
pointer values to form 64-bit control data structure addresses
(EHCI 1.0, section 2.3.5 and Appendix B).
qTD link pointers (current_qtd/next_qtd/altnext_qtd and qTD.next)
are stored as 32-bit values in the data structures and must be
expanded to full 64-bit descriptor addresses when 64-bit mode is
enabled. Update the qTD traversal paths to use ehci_get_desc_addr()
when following link pointers.
Appendix B also defines high dword fields for qTD buffer pointers.
Add bufptr_hi[5] to EHCIqtd and extend qTD fetch and QH overlay
handling to load and propagate the high buffer pointer fields.
When 64-bit capability is disabled, descriptor and buffer addresses
remain 32-bit and existing behaviour is unchanged.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
hw/usb/hcd-ehci.h | 1 +
hw/usb/hcd-ehci.c | 19 ++++++++++++-------
2 files changed, 13 insertions(+), 7 deletions(-)
diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
index 773f376834..712de9d50e 100644
--- a/hw/usb/hcd-ehci.h
+++ b/hw/usb/hcd-ehci.h
@@ -139,6 +139,7 @@ typedef struct EHCIqtd {
uint32_t bufptr[5]; /* Standard buffer pointer */
#define QTD_BUFPTR_MASK 0xfffff000
#define QTD_BUFPTR_SH 12
+ uint32_t bufptr_hi[5];
} EHCIqtd;
/* QH overlay: altnext_qtd, token, bufptr[5], bufptr_hi[5] */
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 37ae637e08..d93d227e6f 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -473,7 +473,8 @@ static bool ehci_verify_qtd(EHCIPacket *p, EHCIqtd *qtd)
(p->qtd.next != qtd->next)) ||
(!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd->altnext)) ||
p->qtd.token != qtd->token ||
- p->qtd.bufptr[0] != qtd->bufptr[0]) {
+ p->qtd.bufptr[0] != qtd->bufptr[0] ||
+ p->qtd.bufptr_hi[0] != qtd->bufptr_hi[0]) {
return false;
} else {
return true;
@@ -1199,6 +1200,7 @@ static int ehci_qh_do_overlay(EHCIQueue *q)
for (i = 0; i < 5; i++) {
q->qh.bufptr[i] = p->qtd.bufptr[i];
+ q->qh.bufptr_hi[i] = p->qtd.bufptr_hi[i];
}
if (!(q->qh.epchar & QH_EPCHAR_DTC)) {
@@ -1232,7 +1234,8 @@ static int ehci_init_transfer(EHCIPacket *p)
return -1;
}
- page = p->qtd.bufptr[cpage] & QTD_BUFPTR_MASK;
+ page = ehci_get_buf_addr(p->queue->ehci, p->qtd.bufptr_hi[cpage],
+ p->qtd.bufptr[cpage], QTD_BUFPTR_MASK);
page += offset;
plen = bytes;
if (plen > 4096 - offset) {
@@ -1726,7 +1729,7 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
} else if ((q->qh.token & QTD_TOKEN_ACTIVE) &&
(NLPTR_TBIT(q->qh.current_qtd) == 0) &&
(q->qh.current_qtd != 0)) {
- q->qtdaddr = q->qh.current_qtd;
+ q->qtdaddr = ehci_get_desc_addr(ehci, q->qh.current_qtd);
ehci_set_state(ehci, async, EST_FETCHQTD);
} else {
@@ -1798,14 +1801,14 @@ static int ehci_state_advqueue(EHCIQueue *q)
*/
if (((q->qh.token & QTD_TOKEN_TBYTES_MASK) != 0) &&
(NLPTR_TBIT(q->qh.altnext_qtd) == 0)) {
- q->qtdaddr = q->qh.altnext_qtd;
+ q->qtdaddr = ehci_get_desc_addr(q->ehci, q->qh.altnext_qtd);
ehci_set_state(q->ehci, q->async, EST_FETCHQTD);
/*
* next qTD is valid
*/
} else if (NLPTR_TBIT(q->qh.next_qtd) == 0) {
- q->qtdaddr = q->qh.next_qtd;
+ q->qtdaddr = ehci_get_desc_addr(q->ehci, q->qh.next_qtd);
ehci_set_state(q->ehci, q->async, EST_FETCHQTD);
/*
@@ -1834,7 +1837,9 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
if (get_dwords(q->ehci, addr + 0, &qtd.next, 1) < 0 ||
get_dwords(q->ehci, addr + 4, &qtd.altnext, 1) < 0 ||
get_dwords(q->ehci, addr + 12, qtd.bufptr,
- ARRAY_SIZE(qtd.bufptr)) < 0) {
+ ARRAY_SIZE(qtd.bufptr)) < 0 ||
+ get_dwords(q->ehci, addr + 32, qtd.bufptr_hi,
+ ARRAY_SIZE(qtd.bufptr_hi)) < 0) {
return 0;
}
ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), &qtd);
@@ -1915,7 +1920,7 @@ static int ehci_fill_queue(EHCIPacket *p)
if (NLPTR_TBIT(qtd.next) != 0) {
break;
}
- qtdaddr = qtd.next;
+ qtdaddr = ehci_get_desc_addr(q->ehci, qtd.next);
/*
* Detect circular td lists, Windows creates these, counting on the
* active bit going low after execution to make the queue stop.
--
2.43.0
^ permalink raw reply related [flat|nested] 69+ messages in thread
* [PATCH v3 11/17] hw/usb/hcd-ehci: Implement 64-bit iTD descriptor addressing
2026-04-16 1:49 [PATCH v3 00/17] hw/usb/ehci: Add 64-bit descriptor addressing support Jamin Lin
` (9 preceding siblings ...)
2026-04-16 1:49 ` [PATCH v3 10/17] hw/usb/hcd-ehci: Implement 64-bit qTD " Jamin Lin
@ 2026-04-16 1:49 ` Jamin Lin
2026-04-17 6:15 ` Philippe Mathieu-Daudé
2026-04-16 1:49 ` [PATCH v3 12/17] hw/usb/hcd-ehci: Implement 64-bit siTD " Jamin Lin
` (6 subsequent siblings)
17 siblings, 1 reply; 69+ messages in thread
From: Jamin Lin @ 2026-04-16 1:49 UTC (permalink / raw)
To: philmd@linaro.org, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Jamin Lin, Troy Lee, flwu@google.com, nabihestefan@google.com
EHCI supports 64-bit control data structure addressing when the
64-bit Addressing Capability bit in HCCPARAMS is set. In that mode,
the CTRLDSSEGMENT register provides the upper 32 bits that are
concatenated with 32-bit link pointer values to form full 64-bit
descriptor addresses (EHCI 1.0, section 2.3.5 and Appendix B).
iTD link pointers are stored as 32-bit values and must be expanded
to full 64-bit descriptor addresses when 64-bit mode is enabled.
Update the iTD traversal path to use ehci_get_desc_addr() when
following link pointers.
Appendix B also defines high dword fields for iTD buffer pointers.
Add bufptr_hi[7] to EHCIitd and use ehci_get_buf_addr() to construct
full 64-bit buffer addresses from bufptr[] and bufptr_hi[] fields
when processing isochronous transfers. This allows buffers above
4GB to be handled correctly.
When 64-bit capability is disabled, descriptor and buffer addresses
remain 32-bit and existing behaviour is unchanged.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
hw/usb/hcd-ehci.h | 1 +
hw/usb/hcd-ehci.c | 9 ++++++---
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
index 712de9d50e..af8c080c60 100644
--- a/hw/usb/hcd-ehci.h
+++ b/hw/usb/hcd-ehci.h
@@ -63,6 +63,7 @@ typedef struct EHCIitd {
#define ITD_BUFPTR_MAXPKT_SH 0
#define ITD_BUFPTR_MULT_MASK 0x00000003
#define ITD_BUFPTR_MULT_SH 0
+ uint32_t bufptr_hi[7];
} EHCIitd;
/*
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index d93d227e6f..3db1c25e4d 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -1463,7 +1463,8 @@ static int ehci_process_itd(EHCIState *ehci,
return -1;
}
- ptr1 = (itd->bufptr[pg] & ITD_BUFPTR_MASK);
+ ptr1 = ehci_get_buf_addr(ehci, itd->bufptr_hi[pg],
+ itd->bufptr[pg], ITD_BUFPTR_MASK);
qemu_sglist_init(&ehci->isgl, ehci->device, 2, ehci->as);
if (off + len > 4096) {
/* transfer crosses page border */
@@ -1471,7 +1472,9 @@ static int ehci_process_itd(EHCIState *ehci,
qemu_sglist_destroy(&ehci->isgl);
return -1; /* avoid page pg + 1 */
}
- ptr2 = (itd->bufptr[pg + 1] & ITD_BUFPTR_MASK);
+ ptr2 = ehci_get_buf_addr(ehci, itd->bufptr_hi[pg + 1],
+ itd->bufptr[pg + 1],
+ ITD_BUFPTR_MASK);
uint32_t len2 = off + len - 4096;
uint32_t len1 = len - len2;
qemu_sglist_add(&ehci->isgl, ptr1 + off, len1);
@@ -1761,7 +1764,7 @@ static int ehci_state_fetchitd(EHCIState *ehci, int async)
put_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &itd,
sizeof(EHCIitd) >> 2);
- ehci_set_fetch_addr(ehci, async, itd.next);
+ ehci_set_fetch_addr(ehci, async, ehci_get_desc_addr(ehci, itd.next));
ehci_set_state(ehci, async, EST_FETCHENTRY);
return 1;
--
2.43.0
^ permalink raw reply related [flat|nested] 69+ messages in thread
* [PATCH v3 12/17] hw/usb/hcd-ehci: Implement 64-bit siTD descriptor addressing
2026-04-16 1:49 [PATCH v3 00/17] hw/usb/ehci: Add 64-bit descriptor addressing support Jamin Lin
` (10 preceding siblings ...)
2026-04-16 1:49 ` [PATCH v3 11/17] hw/usb/hcd-ehci: Implement 64-bit iTD " Jamin Lin
@ 2026-04-16 1:49 ` Jamin Lin
2026-04-17 6:27 ` Philippe Mathieu-Daudé
2026-04-16 1:49 ` [PATCH v3 13/17] hw/usb/hcd-ehci: Add descriptor address offset property Jamin Lin
` (5 subsequent siblings)
17 siblings, 1 reply; 69+ messages in thread
From: Jamin Lin @ 2026-04-16 1:49 UTC (permalink / raw)
To: philmd@linaro.org, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Jamin Lin, Troy Lee, flwu@google.com, nabihestefan@google.com
EHCI supports 64-bit control data structure addressing when the
64-bit Addressing Capability bit in HCCPARAMS is set. In that mode,
the CTRLDSSEGMENT register provides the upper 32 bits that are
concatenated with 32-bit link pointer values to form full 64-bit
descriptor addresses (EHCI 1.0, section 2.3.5 and Appendix B).
siTD link pointers are stored as 32-bit values and must be expanded
to full 64-bit descriptor addresses when 64-bit mode is enabled.
Update the siTD traversal path to use ehci_get_desc_addr() when
following link pointers.
Appendix B also defines high dword fields for siTD buffer pointers.
Add bufptr_hi[] fields to EHCIsitd and use ehci_get_buf_addr() to
construct full 64-bit buffer addresses from bufptr[] and bufptr_hi[]
when processing split isochronous transfers. This allows buffers
above 4GB to be handled correctly.
When 64-bit capability is disabled, descriptor and buffer addresses
remain 32-bit and existing behaviour is unchanged.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
hw/usb/hcd-ehci.h | 1 +
hw/usb/hcd-ehci.c | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
index af8c080c60..6406f536e8 100644
--- a/hw/usb/hcd-ehci.h
+++ b/hw/usb/hcd-ehci.h
@@ -109,6 +109,7 @@ typedef struct EHCIsitd {
#define SITD_BUFPTR_TCNT_MASK 0x00000007
uint32_t backptr; /* Standard next link pointer */
+ uint32_t bufptr_hi[2];
} EHCIsitd;
/*
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 3db1c25e4d..e1d5ecbad7 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -1791,7 +1791,7 @@ static int ehci_state_fetchsitd(EHCIState *ehci, int async)
warn_report("Skipping active siTD");
}
- ehci_set_fetch_addr(ehci, async, sitd.next);
+ ehci_set_fetch_addr(ehci, async, ehci_get_desc_addr(ehci, sitd.next));
ehci_set_state(ehci, async, EST_FETCHENTRY);
return 1;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 69+ messages in thread
* [PATCH v3 13/17] hw/usb/hcd-ehci: Add descriptor address offset property
2026-04-16 1:49 [PATCH v3 00/17] hw/usb/ehci: Add 64-bit descriptor addressing support Jamin Lin
` (11 preceding siblings ...)
2026-04-16 1:49 ` [PATCH v3 12/17] hw/usb/hcd-ehci: Implement 64-bit siTD " Jamin Lin
@ 2026-04-16 1:49 ` Jamin Lin
2026-04-17 6:23 ` Philippe Mathieu-Daudé
2026-04-17 6:45 ` Cédric Le Goater
2026-04-16 1:50 ` [PATCH v3 14/17] hw/arm/aspeed_ast27x0: Enable 64-bit EHCI DMA addressing Jamin Lin
` (4 subsequent siblings)
17 siblings, 2 replies; 69+ messages in thread
From: Jamin Lin @ 2026-04-16 1:49 UTC (permalink / raw)
To: philmd@linaro.org, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Jamin Lin, Troy Lee, flwu@google.com, nabihestefan@google.com
When 64-bit addressing is supported, the Linux EHCI driver programs the
segment register to zero. See ehci_run function:
https://github.com/torvalds/linux/blob/master/drivers/usb/host/ehci-hcd.c
The driver comment also notes that descriptor structures allocated from
the DMA pool use segment zero semantics.
Descriptor memory is allocated using the DMA API. The platform driver
configures a 64-bit DMA mask so memory can be allocated above 4GB.
See ehci_platform_probe function:
https://github.com/torvalds/linux/blob/master/drivers/usb/host/ehci-platform.c
On AST2700 platforms, system DRAM is mapped above 4GB at 0x400000000.
As a result, descriptor addresses constructed directly from the guest
EHCI registers do not match the actual system address used by the
controller when fetching queue heads (QH) and queue element transfer
descriptors (qTD).
Introduce a descriptor-addr-offset property so platforms can provide an
address offset applied when constructing descriptor addresses. This
allows systems where DRAM resides above 4GB to correctly access EHCI
descriptors while keeping the default behavior unchanged for existing
machines.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
hw/usb/hcd-ehci.h | 1 +
hw/usb/hcd-ehci-pci.c | 2 ++
hw/usb/hcd-ehci-sysbus.c | 2 ++
hw/usb/hcd-ehci.c | 7 ++++++-
4 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
index 6406f536e8..05d8db4a5d 100644
--- a/hw/usb/hcd-ehci.h
+++ b/hw/usb/hcd-ehci.h
@@ -264,6 +264,7 @@ struct EHCIState {
/* properties */
uint32_t maxframes;
bool caps_64bit_addr;
+ uint64_t descriptor_addr_offset;
/*
* EHCI spec version 1.0 Section 2.3
diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c
index 2ea8549db9..115d05ede0 100644
--- a/hw/usb/hcd-ehci-pci.c
+++ b/hw/usb/hcd-ehci-pci.c
@@ -139,6 +139,8 @@ static const Property ehci_pci_properties[] = {
DEFINE_PROP_UINT32("maxframes", EHCIPCIState, ehci.maxframes, 128),
DEFINE_PROP_BOOL("caps-64bit-addr", EHCIPCIState, ehci.caps_64bit_addr,
false),
+ DEFINE_PROP_UINT64("descriptor-addr-offset", EHCIPCIState,
+ ehci.descriptor_addr_offset, 0),
};
static const VMStateDescription vmstate_ehci_pci = {
diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c
index 61215e9f3d..df138fb339 100644
--- a/hw/usb/hcd-ehci-sysbus.c
+++ b/hw/usb/hcd-ehci-sysbus.c
@@ -36,6 +36,8 @@ static const Property ehci_sysbus_properties[] = {
false),
DEFINE_PROP_BOOL("caps-64bit-addr", EHCISysBusState, ehci.caps_64bit_addr,
false),
+ DEFINE_PROP_UINT64("descriptor-addr-offset", EHCISysBusState,
+ ehci.descriptor_addr_offset, 0),
};
static void usb_ehci_sysbus_realize(DeviceState *dev, Error **errp)
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index e1d5ecbad7..ea9d5846bc 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -162,7 +162,12 @@ static uint64_t ehci_get_buf_addr(EHCIState *s, uint32_t hi, uint32_t low,
static uint64_t ehci_get_desc_addr(EHCIState *s, uint32_t low)
{
- return ehci_get_buf_addr(s, s->ctrldssegment, low, UINT32_MAX);
+ uint64_t addr;
+
+ addr = ehci_get_buf_addr(s, s->ctrldssegment, low, UINT32_MAX);
+ addr += s->descriptor_addr_offset;
+
+ return addr;
}
static void ehci_trace_usbsts(uint32_t mask, int state)
--
2.43.0
^ permalink raw reply related [flat|nested] 69+ messages in thread
* [PATCH v3 14/17] hw/arm/aspeed_ast27x0: Enable 64-bit EHCI DMA addressing
2026-04-16 1:49 [PATCH v3 00/17] hw/usb/ehci: Add 64-bit descriptor addressing support Jamin Lin
` (12 preceding siblings ...)
2026-04-16 1:49 ` [PATCH v3 13/17] hw/usb/hcd-ehci: Add descriptor address offset property Jamin Lin
@ 2026-04-16 1:50 ` Jamin Lin
2026-04-17 6:23 ` Philippe Mathieu-Daudé
2026-04-16 1:50 ` [PATCH v3 15/17] hw/arm/aspeed_ast27x0: Set EHCI descriptor address offset Jamin Lin
` (3 subsequent siblings)
17 siblings, 1 reply; 69+ messages in thread
From: Jamin Lin @ 2026-04-16 1:50 UTC (permalink / raw)
To: philmd@linaro.org, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Jamin Lin, Troy Lee, flwu@google.com, nabihestefan@google.com,
Cédric Le Goater
AST2700 supports a 64-bit DRAM address space. Therefore, DMA
transactions must be capable of accessing 64-bit addresses.
Enable the "caps-64bit-addr" property for the EHCI controllers
on AST2700 so that USB DMA operations can correctly handle
64-bit memory addresses.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
---
hw/arm/aspeed_ast27x0.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index 87dcb82e1b..4a1f7cad73 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -856,6 +856,8 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp)
/* EHCI */
for (i = 0; i < sc->ehcis_num; i++) {
+ object_property_set_bool(OBJECT(&s->ehci[i]), "caps-64bit-addr", true,
+ &error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), errp)) {
return;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 69+ messages in thread
* [PATCH v3 15/17] hw/arm/aspeed_ast27x0: Set EHCI descriptor address offset
2026-04-16 1:49 [PATCH v3 00/17] hw/usb/ehci: Add 64-bit descriptor addressing support Jamin Lin
` (13 preceding siblings ...)
2026-04-16 1:50 ` [PATCH v3 14/17] hw/arm/aspeed_ast27x0: Enable 64-bit EHCI DMA addressing Jamin Lin
@ 2026-04-16 1:50 ` Jamin Lin
2026-04-17 6:25 ` Philippe Mathieu-Daudé
2026-04-16 1:50 ` [PATCH v3 16/17] tests/functional/arm/test_aspeed_ast2600_sdk: Add USB EHCI test for AST2600 SDK Jamin Lin
` (2 subsequent siblings)
17 siblings, 1 reply; 69+ messages in thread
From: Jamin Lin @ 2026-04-16 1:50 UTC (permalink / raw)
To: philmd@linaro.org, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Jamin Lin, Troy Lee, flwu@google.com, nabihestefan@google.com
On AST2700 platforms, system DRAM is mapped above 4GB with the
base address at 0x400000000.
The Linux EHCI driver programs the segment register to zero when
64-bit addressing is supported. As a result, descriptor addresses
derived from the EHCI registers do not include the DRAM base
address.
Descriptor memory is allocated through the DMA API with a 64-bit
DMA mask, which allows descriptors to be placed in DRAM above 4GB.
When running on AST2700, this means EHCI queue heads (QH) and queue
element transfer descriptors (qTD) reside at addresses starting
from 0x400000000.
Set the descriptor-addr-offset property to the DRAM base so the
emulated EHCI controller can construct the correct descriptor
addresses when accessing system memory.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
hw/arm/aspeed_ast27x0.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index 4a1f7cad73..3cdbf78ac1 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -858,6 +858,9 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp)
for (i = 0; i < sc->ehcis_num; i++) {
object_property_set_bool(OBJECT(&s->ehci[i]), "caps-64bit-addr", true,
&error_abort);
+ object_property_set_int(OBJECT(&s->ehci[i]), "descriptor-addr-offset",
+ sc->memmap[ASPEED_DEV_SDRAM],
+ &error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), errp)) {
return;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 69+ messages in thread
* [PATCH v3 16/17] tests/functional/arm/test_aspeed_ast2600_sdk: Add USB EHCI test for AST2600 SDK
2026-04-16 1:49 [PATCH v3 00/17] hw/usb/ehci: Add 64-bit descriptor addressing support Jamin Lin
` (14 preceding siblings ...)
2026-04-16 1:50 ` [PATCH v3 15/17] hw/arm/aspeed_ast27x0: Set EHCI descriptor address offset Jamin Lin
@ 2026-04-16 1:50 ` Jamin Lin
2026-04-17 6:27 ` Philippe Mathieu-Daudé
2026-04-16 1:50 ` [PATCH v3 17/17] tests/functional/aarch64/test_aspeed_ast2700: Add USB EHCI test for AST2700 A1/A2 Jamin Lin
2026-04-17 6:35 ` [PATCH v3 00/17] hw/usb/ehci: Add 64-bit descriptor addressing support Philippe Mathieu-Daudé
17 siblings, 1 reply; 69+ messages in thread
From: Jamin Lin @ 2026-04-16 1:50 UTC (permalink / raw)
To: philmd@linaro.org, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Jamin Lin, Troy Lee, flwu@google.com, nabihestefan@google.com
Add a functional test to verify USB EHCI support on the AST2600
SDK machine by attaching a USB keyboard device and checking its
enumeration via lsusb.
This introduces a helper routine that runs lsusb in the guest
and validates that the emulated "QEMU USB Keyboard" is detected.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
tests/functional/arm/test_aspeed_ast2600_sdk.py | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/tests/functional/arm/test_aspeed_ast2600_sdk.py b/tests/functional/arm/test_aspeed_ast2600_sdk.py
index d787e90d10..01548dd135 100755
--- a/tests/functional/arm/test_aspeed_ast2600_sdk.py
+++ b/tests/functional/arm/test_aspeed_ast2600_sdk.py
@@ -40,6 +40,11 @@ def do_ast2600_i3c_test(self):
'i3ctransfer -d /dev/bus/i3c/5-1234567890ab -r 8 | grep 0x | xargs',
'0x12 0x34 0x56 0x78 0x90 0xab 0xcd 0xef')
+ def do_ast2600_usb_ehci_test(self):
+ exec_command_and_wait_for_pattern(self,
+ 'lsusb',
+ 'QEMU QEMU USB Keyboard')
+
def test_arm_ast2600_evb_sdk(self):
self.set_machine('ast2600-evb')
self.require_netdev('user')
@@ -54,6 +59,7 @@ def test_arm_ast2600_evb_sdk(self):
self.vm.add_args('-netdev', 'user,id=net1')
self.vm.add_args('-device',
'mock-i3c-target,bus=dw.i3c.5,pid=0xab9078563412')
+ self.vm.add_args('-device', 'usb-kbd,bus=usb-bus.1')
self.do_test_arm_aspeed_sdk_start(
self.scratch_file("ast2600-default-image", "image-bmc"))
@@ -81,6 +87,7 @@ def test_arm_ast2600_evb_sdk(self):
'/sbin/hwclock -f /dev/rtc1', year)
self.do_ast2600_pcie_test()
self.do_ast2600_i3c_test()
+ self.do_ast2600_usb_ehci_test()
if __name__ == '__main__':
--
2.43.0
^ permalink raw reply related [flat|nested] 69+ messages in thread
* [PATCH v3 17/17] tests/functional/aarch64/test_aspeed_ast2700: Add USB EHCI test for AST2700 A1/A2
2026-04-16 1:49 [PATCH v3 00/17] hw/usb/ehci: Add 64-bit descriptor addressing support Jamin Lin
` (15 preceding siblings ...)
2026-04-16 1:50 ` [PATCH v3 16/17] tests/functional/arm/test_aspeed_ast2600_sdk: Add USB EHCI test for AST2600 SDK Jamin Lin
@ 2026-04-16 1:50 ` Jamin Lin
2026-04-17 6:27 ` Philippe Mathieu-Daudé
2026-04-17 6:35 ` [PATCH v3 00/17] hw/usb/ehci: Add 64-bit descriptor addressing support Philippe Mathieu-Daudé
17 siblings, 1 reply; 69+ messages in thread
From: Jamin Lin @ 2026-04-16 1:50 UTC (permalink / raw)
To: philmd@linaro.org, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Jamin Lin, Troy Lee, flwu@google.com, nabihestefan@google.com
Add a functional test to verify USB EHCI support on the AST2700 A2/A1
by attaching a USB keyboard device and checking its
enumeration via lsusb.
This introduces a helper routine that runs lsusb in the guest
and validates that the emulated "QEMU USB Keyboard" is detected.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
tests/functional/aarch64/test_aspeed_ast2700a1.py | 7 +++++++
tests/functional/aarch64/test_aspeed_ast2700a2.py | 7 +++++++
2 files changed, 14 insertions(+)
diff --git a/tests/functional/aarch64/test_aspeed_ast2700a1.py b/tests/functional/aarch64/test_aspeed_ast2700a1.py
index b0c08854da..42b8b200cf 100755
--- a/tests/functional/aarch64/test_aspeed_ast2700a1.py
+++ b/tests/functional/aarch64/test_aspeed_ast2700a1.py
@@ -118,6 +118,11 @@ def do_ast2700_pcie_test(self):
'ip addr show dev eth2',
'inet 10.0.2.15/24')
+ def do_ast2700_usb_ehci_test(self):
+ exec_command_and_wait_for_pattern(self,
+ 'lsusb',
+ 'QEMU QEMU USB Keyboard')
+
def start_ast2700_test(self, name, bus_id):
num_cpu = 4
load_images_list = [
@@ -161,10 +166,12 @@ def test_aarch64_ast2700a1_evb_sdk_v11_01(self):
self.archive_extract(self.ASSET_SDK_V1101_AST2700A1)
self.vm.add_args('-device', 'e1000e,netdev=net1,bus=pcie.2')
self.vm.add_args('-netdev', 'user,id=net1')
+ self.vm.add_args('-device', 'usb-kbd,bus=usb-bus.3')
self.start_ast2700_test('ast2700-a1-image', 1)
self.verify_openbmc_boot_and_login('ast2700-a1')
self.do_ast2700_i2c_test(1)
self.do_ast2700_pcie_test()
+ self.do_ast2700_usb_ehci_test()
def test_aarch64_ast2700a1_evb_sdk_vbootrom_v11_01(self):
self.set_machine('ast2700a1-evb')
diff --git a/tests/functional/aarch64/test_aspeed_ast2700a2.py b/tests/functional/aarch64/test_aspeed_ast2700a2.py
index ed414999f4..40e0ad81ed 100755
--- a/tests/functional/aarch64/test_aspeed_ast2700a2.py
+++ b/tests/functional/aarch64/test_aspeed_ast2700a2.py
@@ -121,6 +121,11 @@ def do_ast2700_pcie_test(self):
'ip addr show dev eth2',
'inet 10.0.2.15/24')
+ def do_ast2700_usb_ehci_test(self):
+ exec_command_and_wait_for_pattern(self,
+ 'lsusb',
+ 'QEMU QEMU USB Keyboard')
+
def start_ast2700_test(self, name, bus_id):
num_cpu = 4
load_images_list = [
@@ -164,10 +169,12 @@ def test_aarch64_ast2700a2_evb_sdk_v11_01(self):
self.archive_extract(self.ASSET_SDK_V1101_AST2700A2)
self.vm.add_args('-device', 'e1000e,netdev=net1,bus=pcie.2')
self.vm.add_args('-netdev', 'user,id=net1')
+ self.vm.add_args('-device', 'usb-kbd,bus=usb-bus.3')
self.start_ast2700_test('ast2700-default-image', 1)
self.verify_openbmc_boot_and_login('ast2700-default')
self.do_ast2700_i2c_test(1)
self.do_ast2700_pcie_test()
+ self.do_ast2700_usb_ehci_test()
def test_aarch64_ast2700a2_evb_sdk_vbootrom_v11_01(self):
self.set_machine('ast2700a2-evb')
--
2.43.0
^ permalink raw reply related [flat|nested] 69+ messages in thread
* Re: [PATCH v3 01/17] hw/usb/hcd-ehci: Remove unused EHCIfstn structure and dead code
2026-04-16 1:49 ` [PATCH v3 01/17] hw/usb/hcd-ehci: Remove unused EHCIfstn structure and dead code Jamin Lin
@ 2026-04-16 12:09 ` BALATON Zoltan
2026-04-17 1:16 ` Jamin Lin
2026-04-17 6:30 ` Cédric Le Goater
1 sibling, 1 reply; 69+ messages in thread
From: BALATON Zoltan @ 2026-04-16 12:09 UTC (permalink / raw)
To: Jamin Lin
Cc: philmd@linaro.org, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here, Troy Lee,
flwu@google.com, nabihestefan@google.com
On Thu, 16 Apr 2026, Jamin Lin wrote:
> The EHCIfstn structure, defined according to EHCI spec section 3.7,
> is currently unused in the EHCI implementation. Remove it to reduce
> unused code and improve maintainability.
>
> Additionally, drop a block of disabled (#if 0) code in
> ehci_state_advqueue() that was never implemented. This code path
> is incomplete and has no functional impact.
>
> No functional change.
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> ---
> hw/usb/hcd-ehci.h | 7 -------
> hw/usb/hcd-ehci.c | 11 -----------
> 2 files changed, 18 deletions(-)
>
> diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
> index 0ae8c06331..3aec0e047c 100644
> --- a/hw/usb/hcd-ehci.h
> +++ b/hw/usb/hcd-ehci.h
> @@ -202,13 +202,6 @@ typedef struct EHCIqh {
> #define BUFPTR_SBYTES_SH 5
> } EHCIqh;
>
> -/* EHCI spec version 1.0 Section 3.7
> - */
> -typedef struct EHCIfstn {
> - uint32_t next; /* Standard next link pointer */
> - uint32_t backptr; /* Standard next link pointer */
> -} EHCIfstn;
> -
> enum async_state {
> EHCI_ASYNC_NONE = 0,
> EHCI_ASYNC_INITIALIZED,
> diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
> index 57f930b099..5ea8461f70 100644
> --- a/hw/usb/hcd-ehci.c
> +++ b/hw/usb/hcd-ehci.c
> @@ -1756,17 +1756,6 @@ static int ehci_state_fetchsitd(EHCIState *ehci, int async)
> /* Section 4.10.2 - paragraph 3 */
> static int ehci_state_advqueue(EHCIQueue *q)
> {
> -#if 0
> - /* TO-DO: 4.10.2 - paragraph 2
> - * if I-bit is set to 1 and QH is not active
> - * go to horizontal QH
> - */
Is it worth to keep the comment in case it's still valid to remind we have
something missing here?
Regards,
BALATON Zoltan
> - if (I-bit set) {
> - ehci_set_state(ehci, async, EST_HORIZONTALQH);
> - goto out;
> - }
> -#endif
> -
> /*
> * want data and alt-next qTD is valid
> */
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 69+ messages in thread
* RE: [PATCH v3 01/17] hw/usb/hcd-ehci: Remove unused EHCIfstn structure and dead code
2026-04-16 12:09 ` BALATON Zoltan
@ 2026-04-17 1:16 ` Jamin Lin
2026-04-17 2:25 ` Jamin Lin
0 siblings, 1 reply; 69+ messages in thread
From: Jamin Lin @ 2026-04-17 1:16 UTC (permalink / raw)
To: BALATON Zoltan
Cc: philmd@linaro.org, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here, Troy Lee,
flwu@google.com, nabihestefan@google.com
Hi all,
> Subject: Re: [PATCH v3 01/17] hw/usb/hcd-ehci: Remove unused EHCIfstn
> structure and dead code
>
> On Thu, 16 Apr 2026, Jamin Lin wrote:
> > The EHCIfstn structure, defined according to EHCI spec section 3.7, is
> > currently unused in the EHCI implementation. Remove it to reduce
> > unused code and improve maintainability.
> >
> > Additionally, drop a block of disabled (#if 0) code in
> > ehci_state_advqueue() that was never implemented. This code path is
> > incomplete and has no functional impact.
> >
> > No functional change.
> >
> > Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> > ---
> > hw/usb/hcd-ehci.h | 7 -------
> > hw/usb/hcd-ehci.c | 11 -----------
> > 2 files changed, 18 deletions(-)
> >
> > diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index
> > 0ae8c06331..3aec0e047c 100644
> > --- a/hw/usb/hcd-ehci.h
> > +++ b/hw/usb/hcd-ehci.h
> > @@ -202,13 +202,6 @@ typedef struct EHCIqh {
> > #define BUFPTR_SBYTES_SH 5
> > } EHCIqh;
> >
> > -/* EHCI spec version 1.0 Section 3.7
> > - */
> > -typedef struct EHCIfstn {
> > - uint32_t next; /* Standard next link pointer */
> > - uint32_t backptr; /* Standard next link pointer */
> > -} EHCIfstn;
> > -
> > enum async_state {
> > EHCI_ASYNC_NONE = 0,
> > EHCI_ASYNC_INITIALIZED,
> > diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index
> > 57f930b099..5ea8461f70 100644
> > --- a/hw/usb/hcd-ehci.c
> > +++ b/hw/usb/hcd-ehci.c
> > @@ -1756,17 +1756,6 @@ static int ehci_state_fetchsitd(EHCIState
> > *ehci, int async)
> > /* Section 4.10.2 - paragraph 3 */
> > static int ehci_state_advqueue(EHCIQueue *q) { -#if 0
> > - /* TO-DO: 4.10.2 - paragraph 2
> > - * if I-bit is set to 1 and QH is not active
> > - * go to horizontal QH
> > - */
>
> Is it worth to keep the comment in case it's still valid to remind we have
> something missing here?
>
> Regards,
> BALATON Zoltan
>
If we decide to keep these comments as reminders for unimplemented parts,
please let me know. I will resend the patch series and drop this patch.
Thanks,
Jamin
> > - if (I-bit set) {
> > - ehci_set_state(ehci, async, EST_HORIZONTALQH);
> > - goto out;
> > - }
> > -#endif
> > -
> > /*
> > * want data and alt-next qTD is valid
> > */
> > --
> > 2.43.0
> >
^ permalink raw reply [flat|nested] 69+ messages in thread
* RE: [PATCH v3 01/17] hw/usb/hcd-ehci: Remove unused EHCIfstn structure and dead code
2026-04-17 1:16 ` Jamin Lin
@ 2026-04-17 2:25 ` Jamin Lin
2026-04-17 9:47 ` BALATON Zoltan
0 siblings, 1 reply; 69+ messages in thread
From: Jamin Lin @ 2026-04-17 2:25 UTC (permalink / raw)
To: BALATON Zoltan
Cc: philmd@linaro.org, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here, Troy Lee,
flwu@google.com, nabihestefan@google.com
Hi all,
> Subject: RE: [PATCH v3 01/17] hw/usb/hcd-ehci: Remove unused EHCIfstn
> structure and dead code
>
> Hi all,
>
> > Subject: Re: [PATCH v3 01/17] hw/usb/hcd-ehci: Remove unused EHCIfstn
> > structure and dead code
> >
> > On Thu, 16 Apr 2026, Jamin Lin wrote:
> > > The EHCIfstn structure, defined according to EHCI spec section 3.7,
> > > is currently unused in the EHCI implementation. Remove it to reduce
> > > unused code and improve maintainability.
> > >
> > > Additionally, drop a block of disabled (#if 0) code in
> > > ehci_state_advqueue() that was never implemented. This code path is
> > > incomplete and has no functional impact.
> > >
> > > No functional change.
> > >
> > > Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> > > ---
> > > hw/usb/hcd-ehci.h | 7 -------
> > > hw/usb/hcd-ehci.c | 11 -----------
> > > 2 files changed, 18 deletions(-)
> > >
> > > diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index
> > > 0ae8c06331..3aec0e047c 100644
> > > --- a/hw/usb/hcd-ehci.h
> > > +++ b/hw/usb/hcd-ehci.h
> > > @@ -202,13 +202,6 @@ typedef struct EHCIqh {
> > > #define BUFPTR_SBYTES_SH 5
> > > } EHCIqh;
> > >
> > > -/* EHCI spec version 1.0 Section 3.7
> > > - */
> > > -typedef struct EHCIfstn {
> > > - uint32_t next; /* Standard next link pointer
> */
> > > - uint32_t backptr; /* Standard next link pointer */
> > > -} EHCIfstn;
> > > -
> > > enum async_state {
> > > EHCI_ASYNC_NONE = 0,
> > > EHCI_ASYNC_INITIALIZED,
> > > diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index
> > > 57f930b099..5ea8461f70 100644
> > > --- a/hw/usb/hcd-ehci.c
> > > +++ b/hw/usb/hcd-ehci.c
> > > @@ -1756,17 +1756,6 @@ static int ehci_state_fetchsitd(EHCIState
> > > *ehci, int async)
> > > /* Section 4.10.2 - paragraph 3 */
> > > static int ehci_state_advqueue(EHCIQueue *q) { -#if 0
> > > - /* TO-DO: 4.10.2 - paragraph 2
> > > - * if I-bit is set to 1 and QH is not active
> > > - * go to horizontal QH
> > > - */
> >
> > Is it worth to keep the comment in case it's still valid to remind we
> > have something missing here?
> >
> > Regards,
> > BALATON Zoltan
> >
>
> If we decide to keep these comments as reminders for unimplemented parts,
> please let me know. I will resend the patch series and drop this patch.
>
> Thanks,
> Jamin
>
Another approach:
We can remove the #if 0 dead code and keep only the comments as a reminder that this part is not yet implemented.
Ex:
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -1756,16 +1756,10 @@ static int ehci_state_fetchsitd(EHCIState *ehci, int async)
/* Section 4.10.2 - paragraph 3 */
static int ehci_state_advqueue(EHCIQueue *q)
{
-#if 0
/* TO-DO: 4.10.2 - paragraph 2
* if I-bit is set to 1 and QH is not active
* go to horizontal QH
*/
- if (I-bit set) {
- ehci_set_state(ehci, async, EST_HORIZONTALQH);
- goto out;
- }
Thanks,
Jamin
> > > - if (I-bit set) {
> > > - ehci_set_state(ehci, async, EST_HORIZONTALQH);
> > > - goto out;
> > > - }
> > > -#endif
> > > -
> > > /*
> > > * want data and alt-next qTD is valid
> > > */
> > > --
> > > 2.43.0
> > >
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 06/17] hw/usb/hcd-ehci: Change descriptor addresses to 64-bit
2026-04-16 1:49 ` [PATCH v3 06/17] hw/usb/hcd-ehci: Change descriptor addresses to 64-bit Jamin Lin
@ 2026-04-17 4:54 ` Philippe Mathieu-Daudé
2026-04-17 7:01 ` Cédric Le Goater
1 sibling, 0 replies; 69+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-17 4:54 UTC (permalink / raw)
To: Jamin Lin, Cédric Le Goater, Peter Maydell, Steven Lee,
Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
On 16/4/26 03:49, Jamin Lin wrote:
> Change internal EHCI descriptor addresses from uint32_t to uint64_t.
>
> The following fields are updated:
> - EHCIPacket::qtdaddr
> - EHCIQueue::{qhaddr, qtdaddr}
> - EHCIState::{a_fetch_addr, p_fetch_addr}
>
> Update get_dwords() and put_dwords() to take 64-bit addresses and
> propagate the type change through the descriptor traversal paths.
>
> Adjust NLPTR_GET() to operate on 64-bit values:
>
> #define NLPTR_GET(x) ((x) & ~0x1fULL)
>
> so that link pointer masking works correctly when descriptor
> addresses exceed 32-bit space. The previous mask (0xffffffe0)
> implicitly truncated addresses to 32 bits.
>
> This patch does not change the on-wire descriptor layout yet.
> It only removes the internal 32-bit address limit and prepares
> for later patches that will add full 64-bit QH/qTD/iTD/siTD support.
>
> Update the EHCI trace-events prototypes for QH, qTD, iTD, and siTD to
> use uint64_t for the address argument and print it with PRIx64. This
> ensures full 64-bit addresses are shown in trace output and improves
> debugging of queue heads and transfer descriptors.
>
> Migration compatibility:
>
> The fetch address fields in EHCIState are extended from 32-bit to
> 64-bit, requiring a VMState version bump (v2 -> v3).
>
> Backward compatibility is preserved by keeping the legacy 32-bit
> fields (a_fetch_addr_pre_v3, p_fetch_addr_pre_v3) for pre-v3
> migration streams via VMSTATE_UINT32_TEST(), and introducing new
> 64-bit fields for v3+.
>
> In post_load, pre-v3 state is promoted to the 64-bit fields.
>
> No functional change.
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> ---
> hw/usb/hcd-ehci.h | 12 +++++----
> hw/usb/hcd-ehci.c | 64 +++++++++++++++++++++++++++++----------------
> hw/usb/trace-events | 24 ++++++++---------
> 3 files changed, 60 insertions(+), 40 deletions(-)
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 07/17] hw/usb/hcd-ehci: Add property to advertise 64-bit addressing capability
2026-04-16 1:49 ` [PATCH v3 07/17] hw/usb/hcd-ehci: Add property to advertise 64-bit addressing capability Jamin Lin
@ 2026-04-17 4:55 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 69+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-17 4:55 UTC (permalink / raw)
To: Jamin Lin, Cédric Le Goater, Peter Maydell, Steven Lee,
Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com,
Cédric Le Goater
On 16/4/26 03:49, Jamin Lin wrote:
> Introduce a new boolean property, "caps-64bit-addr", to control
> HCCPARAMS[0] (64-bit Addressing Capability).
>
> When enabled, the EHCI controller advertises support for 64-bit
> address memory pointers as defined in the EHCI specification
> (Table 2-7, HCCPARAMS). This allows software to use the 64-bit
> data structure formats described in Appendix B.
>
> When disabled (default), the controller reports 32-bit addressing
> capability and uses the standard 32-bit data structures.
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> Reviewed-by: Cédric Le Goater <clg@redhat.com>
> ---
> hw/usb/hcd-ehci.h | 1 +
> hw/usb/hcd-ehci-pci.c | 2 ++
> hw/usb/hcd-ehci-sysbus.c | 2 ++
> hw/usb/hcd-ehci.c | 5 ++++-
> 4 files changed, 9 insertions(+), 1 deletion(-)
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 09/17] hw/usb/hcd-ehci: Implement 64-bit QH descriptor addressing
2026-04-16 1:49 ` [PATCH v3 09/17] hw/usb/hcd-ehci: Implement 64-bit QH descriptor addressing Jamin Lin
@ 2026-04-17 5:03 ` Philippe Mathieu-Daudé
2026-04-17 5:40 ` Jamin Lin
0 siblings, 1 reply; 69+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-17 5:03 UTC (permalink / raw)
To: Jamin Lin, Cédric Le Goater, Peter Maydell, Steven Lee,
Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
On 16/4/26 03:49, Jamin Lin wrote:
> EHCI supports 64-bit control data structure addressing when the
> 64-bit Addressing Capability bit in HCCPARAMS is set. In that mode,
> the CTRLDSSEGMENT register supplies the upper 32 bits which are
> concatenated with 32-bit link pointer fields to form full 64-bit
> descriptor addresses (EHCI 1.0, section 2.3.5 and Appendix B).
>
> The current implementation assumes 32-bit QH descriptor addresses
> and directly uses link pointer values without applying the
> CTRLDSSEGMENT upper dword.
>
> Introduce a helper, ehci_get_desc_addr(), to construct full 64-bit
> descriptor addresses when 64-bit capability is enabled. Update QH
> traversal paths (async list walk, horizontal QH link, and periodic
> schedule entry handling) to use the translated 64-bit addresses.
>
> EHCI 64-bit buffer pointer fields are defined in Appendix B as
> split 32-bit low/high parts located at separate offsets, rather
> than a single contiguous 64-bit field. Therefore, the buffer
> pointers cannot be represented as uint64_t bufptr[5] without
> violating the descriptor layout defined by the specification.
>
> Introduce ehci_get_buf_addr() to construct full 64-bit buffer
> addresses from bufptr[] and bufptr_hi[] fields. Use this helper
> when calculating transfer buffer addresses so that data buffers
> above 4GB are correctly handled.
>
> Also add bufptr_hi[5] to EHCIqh to support 64-bit buffer pointer
> fields as defined in Appendix B.
>
> When 64-bit capability is disabled, descriptor addresses remain
> 32-bit and existing behaviour is unchanged.
>
> Note: Similar split 64-bit buffer pointer handling is required for
> qTD, iTD and siTD descriptors, which will be addressed in follow-up
> changes.
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> ---
> hw/usb/hcd-ehci.h | 4 ++++
> hw/usb/hcd-ehci.c | 48 ++++++++++++++++++++++++++++++++++-----------
> hw/usb/trace-events | 2 +-
> 3 files changed, 42 insertions(+), 12 deletions(-)
>
> diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
> index fe4c508c32..773f376834 100644
> --- a/hw/usb/hcd-ehci.h
> +++ b/hw/usb/hcd-ehci.h
> @@ -141,6 +141,9 @@ typedef struct EHCIqtd {
> #define QTD_BUFPTR_SH 12
> } EHCIqtd;
>
> +/* QH overlay: altnext_qtd, token, bufptr[5], bufptr_hi[5] */
> +#define EHCI_QH_OVERLAY_COUNT 12
> +
> /*
> * EHCI spec version 1.0 Section 3.6
> */
> @@ -194,6 +197,7 @@ typedef struct EHCIqh {
> #define BUFPTR_FRAMETAG_MASK 0x0000001f
> #define BUFPTR_SBYTES_MASK 0x00000fe0
> #define BUFPTR_SBYTES_SH 5
> + uint32_t bufptr_hi[5];
> } EHCIqh;
>
> enum async_state {
> diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
> index b9e4251d62..37ae637e08 100644
> --- a/hw/usb/hcd-ehci.c
> +++ b/hw/usb/hcd-ehci.c
> @@ -147,6 +147,24 @@ static const char *addr2str(hwaddr addr)
> return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), addr);
> }
>
> +static uint64_t ehci_get_buf_addr(EHCIState *s, uint32_t hi, uint32_t low,
> + uint32_t mask)
Rename @mask as @low_mask? Or directly use 64-bit?
static uint64_t ehci_get_buf_addr(const EHCIState *s,
uint32_t hi, uint32_t lo,
uint64_t mask)
{
uint64_t addr = s->caps_64bit_addr ? deposit64(lo, 0, 32, hi): lo;
return addr & mask;
}
> +{
> + uint64_t addr;
> +
> + addr = (uint64_t)(low & mask);
> + if (s->caps_64bit_addr) {
> + addr |= (uint64_t)hi << 32;
> + }
> +
> + return addr;
> +}
> +
> +static uint64_t ehci_get_desc_addr(EHCIState *s, uint32_t low)
> +{
> + return ehci_get_buf_addr(s, s->ctrldssegment, low, UINT32_MAX);
> +}
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 05/17] hw/usb/hcd-ehci: Replace DPRINTF debug logs with trace events
2026-04-16 1:49 ` [PATCH v3 05/17] hw/usb/hcd-ehci: Replace DPRINTF debug logs with trace events Jamin Lin
@ 2026-04-17 5:04 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 69+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-17 5:04 UTC (permalink / raw)
To: Jamin Lin, Cédric Le Goater, Peter Maydell, Steven Lee,
Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
On 16/4/26 03:49, Jamin Lin wrote:
> Replace legacy DPRINTF() debug logging in the EHCI host controller
> implementation with QEMU trace events.
>
> The EHCI_DEBUG macro and associated DPRINTF() definitions are
> removed as they are no longer needed.
>
> Trace events are added for:
> - packet submission and completion
> - queue head execution state
> - periodic schedule advancement
> - ITD error conditions
> - port state handling
> - skipped microframes
>
> No functional change.
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> ---
> hw/usb/hcd-ehci.h | 10 ---------
> hw/usb/hcd-ehci.c | 49 +++++++++++++++++++--------------------------
> hw/usb/trace-events | 9 +++++++++
> 3 files changed, 30 insertions(+), 38 deletions(-)
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 69+ messages in thread
* RE: [PATCH v3 09/17] hw/usb/hcd-ehci: Implement 64-bit QH descriptor addressing
2026-04-17 5:03 ` Philippe Mathieu-Daudé
@ 2026-04-17 5:40 ` Jamin Lin
2026-04-17 6:14 ` Philippe Mathieu-Daudé
0 siblings, 1 reply; 69+ messages in thread
From: Jamin Lin @ 2026-04-17 5:40 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
Hi Philippe,
> Subject: Re: [PATCH v3 09/17] hw/usb/hcd-ehci: Implement 64-bit QH
> descriptor addressing
>
> On 16/4/26 03:49, Jamin Lin wrote:
> > EHCI supports 64-bit control data structure addressing when the 64-bit
> > Addressing Capability bit in HCCPARAMS is set. In that mode, the
> > CTRLDSSEGMENT register supplies the upper 32 bits which are
> > concatenated with 32-bit link pointer fields to form full 64-bit
> > descriptor addresses (EHCI 1.0, section 2.3.5 and Appendix B).
> >
> > The current implementation assumes 32-bit QH descriptor addresses and
> > directly uses link pointer values without applying the CTRLDSSEGMENT
> > upper dword.
> >
> > Introduce a helper, ehci_get_desc_addr(), to construct full 64-bit
> > descriptor addresses when 64-bit capability is enabled. Update QH
> > traversal paths (async list walk, horizontal QH link, and periodic
> > schedule entry handling) to use the translated 64-bit addresses.
> >
> > EHCI 64-bit buffer pointer fields are defined in Appendix B as split
> > 32-bit low/high parts located at separate offsets, rather than a
> > single contiguous 64-bit field. Therefore, the buffer pointers cannot
> > be represented as uint64_t bufptr[5] without violating the descriptor
> > layout defined by the specification.
> >
> > Introduce ehci_get_buf_addr() to construct full 64-bit buffer
> > addresses from bufptr[] and bufptr_hi[] fields. Use this helper when
> > calculating transfer buffer addresses so that data buffers above 4GB
> > are correctly handled.
> >
> > Also add bufptr_hi[5] to EHCIqh to support 64-bit buffer pointer
> > fields as defined in Appendix B.
> >
> > When 64-bit capability is disabled, descriptor addresses remain 32-bit
> > and existing behaviour is unchanged.
> >
> > Note: Similar split 64-bit buffer pointer handling is required for
> > qTD, iTD and siTD descriptors, which will be addressed in follow-up
> > changes.
> >
> > Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> > ---
> > hw/usb/hcd-ehci.h | 4 ++++
> > hw/usb/hcd-ehci.c | 48
> ++++++++++++++++++++++++++++++++++-----------
> > hw/usb/trace-events | 2 +-
> > 3 files changed, 42 insertions(+), 12 deletions(-)
> >
> > diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index
> > fe4c508c32..773f376834 100644
> > --- a/hw/usb/hcd-ehci.h
> > +++ b/hw/usb/hcd-ehci.h
> > @@ -141,6 +141,9 @@ typedef struct EHCIqtd {
> > #define QTD_BUFPTR_SH 12
> > } EHCIqtd;
> >
> > +/* QH overlay: altnext_qtd, token, bufptr[5], bufptr_hi[5] */ #define
> > +EHCI_QH_OVERLAY_COUNT 12
> > +
> > /*
> > * EHCI spec version 1.0 Section 3.6
> > */
> > @@ -194,6 +197,7 @@ typedef struct EHCIqh {
> > #define BUFPTR_FRAMETAG_MASK 0x0000001f
> > #define BUFPTR_SBYTES_MASK 0x00000fe0
> > #define BUFPTR_SBYTES_SH 5
> > + uint32_t bufptr_hi[5];
> > } EHCIqh;
> >
> > enum async_state {
> > diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index
> > b9e4251d62..37ae637e08 100644
> > --- a/hw/usb/hcd-ehci.c
> > +++ b/hw/usb/hcd-ehci.c
> > @@ -147,6 +147,24 @@ static const char *addr2str(hwaddr addr)
> > return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names),
> addr);
> > }
> >
> > +static uint64_t ehci_get_buf_addr(EHCIState *s, uint32_t hi, uint32_t low,
> > + uint32_t mask)
>
> Rename @mask as @low_mask? Or directly use 64-bit?
>
> static uint64_t ehci_get_buf_addr(const EHCIState *s,
> uint32_t hi, uint32_t lo,
> uint64_t mask) {
> uint64_t addr = s->caps_64bit_addr ? deposit64(lo, 0, 32, hi): lo;
>
> return addr & mask;
> }
>
Thanks for the review and suggestion.
In the current code, the mask (e.g. QTD_BUFPTR_MASK) is defined as a 32-bit value and is intended to apply only to the low 32 bits of the buffer pointer.
If we change the function to take a 64-bit mask and apply it to the full 64-bit address (as in the proposed version),
the upper 32 bits (bits 63–32) may be unintentionally cleared when the mask is only 32-bit wide.
For example:
#define QTD_BUFPTR_MASK 0xfffff000
In this case, applying "addr & mask" after combining hi/lo would zero out the high 32 bits, which breaks 64-bit addressing.
To preserve the original semantics, the mask should only be applied to the low part before combining with the high 32 bits.
So I suggest renaming the parameter to make this explicit. I will change this function as below. What do you think?
static uint64_t ehci_get_buf_addr(EHCIState *s, uint32_t hi, uint32_t lo,
uint32_t lo_mask)
{
uint64_t addr = lo & lo_mask;
if (s->caps_64bit_addr) {
addr = deposit64(addr, 32, 32, hi);
}
return addr;
}
Thanks,
Jamin
> > +{
> > + uint64_t addr;
> > +
> > + addr = (uint64_t)(low & mask);
> > + if (s->caps_64bit_addr) {
> > + addr |= (uint64_t)hi << 32;
> > + }
> > +
> > + return addr;
> > +}
> > +
> > +static uint64_t ehci_get_desc_addr(EHCIState *s, uint32_t low) {
> > + return ehci_get_buf_addr(s, s->ctrldssegment, low, UINT32_MAX); }
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 09/17] hw/usb/hcd-ehci: Implement 64-bit QH descriptor addressing
2026-04-17 5:40 ` Jamin Lin
@ 2026-04-17 6:14 ` Philippe Mathieu-Daudé
2026-04-17 7:02 ` Jamin Lin
0 siblings, 1 reply; 69+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-17 6:14 UTC (permalink / raw)
To: Jamin Lin, Cédric Le Goater, Peter Maydell, Steven Lee,
Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
On 17/4/26 07:40, Jamin Lin wrote:
> Hi Philippe,
>
>> Subject: Re: [PATCH v3 09/17] hw/usb/hcd-ehci: Implement 64-bit QH
>> descriptor addressing
>>
>> On 16/4/26 03:49, Jamin Lin wrote:
>>> EHCI supports 64-bit control data structure addressing when the 64-bit
>>> Addressing Capability bit in HCCPARAMS is set. In that mode, the
>>> CTRLDSSEGMENT register supplies the upper 32 bits which are
>>> concatenated with 32-bit link pointer fields to form full 64-bit
>>> descriptor addresses (EHCI 1.0, section 2.3.5 and Appendix B).
>>>
>>> The current implementation assumes 32-bit QH descriptor addresses and
>>> directly uses link pointer values without applying the CTRLDSSEGMENT
>>> upper dword.
>>>
>>> Introduce a helper, ehci_get_desc_addr(), to construct full 64-bit
>>> descriptor addresses when 64-bit capability is enabled. Update QH
>>> traversal paths (async list walk, horizontal QH link, and periodic
>>> schedule entry handling) to use the translated 64-bit addresses.
>>>
>>> EHCI 64-bit buffer pointer fields are defined in Appendix B as split
>>> 32-bit low/high parts located at separate offsets, rather than a
>>> single contiguous 64-bit field. Therefore, the buffer pointers cannot
>>> be represented as uint64_t bufptr[5] without violating the descriptor
>>> layout defined by the specification.
>>>
>>> Introduce ehci_get_buf_addr() to construct full 64-bit buffer
>>> addresses from bufptr[] and bufptr_hi[] fields. Use this helper when
>>> calculating transfer buffer addresses so that data buffers above 4GB
>>> are correctly handled.
>>>
>>> Also add bufptr_hi[5] to EHCIqh to support 64-bit buffer pointer
>>> fields as defined in Appendix B.
>>>
>>> When 64-bit capability is disabled, descriptor addresses remain 32-bit
>>> and existing behaviour is unchanged.
>>>
>>> Note: Similar split 64-bit buffer pointer handling is required for
>>> qTD, iTD and siTD descriptors, which will be addressed in follow-up
>>> changes.
>>>
>>> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
>>> ---
>>> hw/usb/hcd-ehci.h | 4 ++++
>>> hw/usb/hcd-ehci.c | 48
>> ++++++++++++++++++++++++++++++++++-----------
>>> hw/usb/trace-events | 2 +-
>>> 3 files changed, 42 insertions(+), 12 deletions(-)
>>> +static uint64_t ehci_get_buf_addr(EHCIState *s, uint32_t hi, uint32_t low,
>>> + uint32_t mask)
>>
>> Rename @mask as @low_mask? Or directly use 64-bit?
>>
>> static uint64_t ehci_get_buf_addr(const EHCIState *s,
>> uint32_t hi, uint32_t lo,
>> uint64_t mask) {
>> uint64_t addr = s->caps_64bit_addr ? deposit64(lo, 0, 32, hi): lo;
>>
>> return addr & mask;
>> }
>>
> Thanks for the review and suggestion.
>
> In the current code, the mask (e.g. QTD_BUFPTR_MASK) is defined as a 32-bit value and is intended to apply only to the low 32 bits of the buffer pointer.
> If we change the function to take a 64-bit mask and apply it to the full 64-bit address (as in the proposed version),
> the upper 32 bits (bits 63–32) may be unintentionally cleared when the mask is only 32-bit wide.
Right.
>
> For example:
>
> #define QTD_BUFPTR_MASK 0xfffff000
>
> In this case, applying "addr & mask" after combining hi/lo would zero out the high 32 bits, which breaks 64-bit addressing.
> To preserve the original semantics, the mask should only be applied to the low part before combining with the high 32 bits.
> So I suggest renaming the parameter to make this explicit. I will change this function as below. What do you think?
>
> static uint64_t ehci_get_buf_addr(
"const"
EHCIState *s, uint32_t hi, uint32_t lo,
> uint32_t lo_mask)
> {
> uint64_t addr = lo & lo_mask;
>
> if (s->caps_64bit_addr) {
> addr = deposit64(addr, 32, 32, hi);
> }
>
> return addr;
> }
Perfect, using "const":
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 10/17] hw/usb/hcd-ehci: Implement 64-bit qTD descriptor addressing
2026-04-16 1:49 ` [PATCH v3 10/17] hw/usb/hcd-ehci: Implement 64-bit qTD " Jamin Lin
@ 2026-04-17 6:14 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 69+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-17 6:14 UTC (permalink / raw)
To: Jamin Lin, Cédric Le Goater, Peter Maydell, Steven Lee,
Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
On 16/4/26 03:49, Jamin Lin wrote:
> EHCI supports 64-bit addressing when the 64-bit Addressing Capability
> bit in HCCPARAMS is set. In that mode, the CTRLDSSEGMENT register
> provides the upper 32 bits that are concatenated with 32-bit link
> pointer values to form 64-bit control data structure addresses
> (EHCI 1.0, section 2.3.5 and Appendix B).
>
> qTD link pointers (current_qtd/next_qtd/altnext_qtd and qTD.next)
> are stored as 32-bit values in the data structures and must be
> expanded to full 64-bit descriptor addresses when 64-bit mode is
> enabled. Update the qTD traversal paths to use ehci_get_desc_addr()
> when following link pointers.
>
> Appendix B also defines high dword fields for qTD buffer pointers.
> Add bufptr_hi[5] to EHCIqtd and extend qTD fetch and QH overlay
> handling to load and propagate the high buffer pointer fields.
>
> When 64-bit capability is disabled, descriptor and buffer addresses
> remain 32-bit and existing behaviour is unchanged.
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> ---
> hw/usb/hcd-ehci.h | 1 +
> hw/usb/hcd-ehci.c | 19 ++++++++++++-------
> 2 files changed, 13 insertions(+), 7 deletions(-)
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 11/17] hw/usb/hcd-ehci: Implement 64-bit iTD descriptor addressing
2026-04-16 1:49 ` [PATCH v3 11/17] hw/usb/hcd-ehci: Implement 64-bit iTD " Jamin Lin
@ 2026-04-17 6:15 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 69+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-17 6:15 UTC (permalink / raw)
To: Jamin Lin, Cédric Le Goater, Peter Maydell, Steven Lee,
Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
On 16/4/26 03:49, Jamin Lin wrote:
> EHCI supports 64-bit control data structure addressing when the
> 64-bit Addressing Capability bit in HCCPARAMS is set. In that mode,
> the CTRLDSSEGMENT register provides the upper 32 bits that are
> concatenated with 32-bit link pointer values to form full 64-bit
> descriptor addresses (EHCI 1.0, section 2.3.5 and Appendix B).
>
> iTD link pointers are stored as 32-bit values and must be expanded
> to full 64-bit descriptor addresses when 64-bit mode is enabled.
> Update the iTD traversal path to use ehci_get_desc_addr() when
> following link pointers.
>
> Appendix B also defines high dword fields for iTD buffer pointers.
> Add bufptr_hi[7] to EHCIitd and use ehci_get_buf_addr() to construct
> full 64-bit buffer addresses from bufptr[] and bufptr_hi[] fields
> when processing isochronous transfers. This allows buffers above
> 4GB to be handled correctly.
>
> When 64-bit capability is disabled, descriptor and buffer addresses
> remain 32-bit and existing behaviour is unchanged.
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> ---
> hw/usb/hcd-ehci.h | 1 +
> hw/usb/hcd-ehci.c | 9 ++++++---
> 2 files changed, 7 insertions(+), 3 deletions(-)
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 13/17] hw/usb/hcd-ehci: Add descriptor address offset property
2026-04-16 1:49 ` [PATCH v3 13/17] hw/usb/hcd-ehci: Add descriptor address offset property Jamin Lin
@ 2026-04-17 6:23 ` Philippe Mathieu-Daudé
2026-04-22 5:00 ` Jamin Lin
2026-04-17 6:45 ` Cédric Le Goater
1 sibling, 1 reply; 69+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-17 6:23 UTC (permalink / raw)
To: Jamin Lin, Cédric Le Goater, Peter Maydell, Steven Lee,
Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
On 16/4/26 03:49, Jamin Lin wrote:
> When 64-bit addressing is supported, the Linux EHCI driver programs the
> segment register to zero. See ehci_run function:
> https://github.com/torvalds/linux/blob/master/drivers/usb/host/ehci-hcd.c
>
> The driver comment also notes that descriptor structures allocated from
> the DMA pool use segment zero semantics.
>
> Descriptor memory is allocated using the DMA API. The platform driver
> configures a 64-bit DMA mask so memory can be allocated above 4GB.
> See ehci_platform_probe function:
> https://github.com/torvalds/linux/blob/master/drivers/usb/host/ehci-platform.c
>
> On AST2700 platforms, system DRAM is mapped above 4GB at 0x400000000.
> As a result, descriptor addresses constructed directly from the guest
> EHCI registers do not match the actual system address used by the
> controller when fetching queue heads (QH) and queue element transfer
> descriptors (qTD).
>
> Introduce a descriptor-addr-offset property so platforms can provide an
> address offset applied when constructing descriptor addresses. This
> allows systems where DRAM resides above 4GB to correctly access EHCI
> descriptors while keeping the default behavior unchanged for existing
> machines.
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> ---
> hw/usb/hcd-ehci.h | 1 +
> hw/usb/hcd-ehci-pci.c | 2 ++
> hw/usb/hcd-ehci-sysbus.c | 2 ++
> hw/usb/hcd-ehci.c | 7 ++++++-
> 4 files changed, 11 insertions(+), 1 deletion(-)
>
> diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
> index 6406f536e8..05d8db4a5d 100644
> --- a/hw/usb/hcd-ehci.h
> +++ b/hw/usb/hcd-ehci.h
> @@ -264,6 +264,7 @@ struct EHCIState {
> /* properties */
> uint32_t maxframes;
> bool caps_64bit_addr;
> + uint64_t descriptor_addr_offset;
I note OHCI uses "dma_addr_t dma_offset;" here.
>
> /*
> * EHCI spec version 1.0 Section 2.3
> diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c
> index 2ea8549db9..115d05ede0 100644
> --- a/hw/usb/hcd-ehci-pci.c
> +++ b/hw/usb/hcd-ehci-pci.c
> @@ -139,6 +139,8 @@ static const Property ehci_pci_properties[] = {
> DEFINE_PROP_UINT32("maxframes", EHCIPCIState, ehci.maxframes, 128),
> DEFINE_PROP_BOOL("caps-64bit-addr", EHCIPCIState, ehci.caps_64bit_addr,
> false),
> + DEFINE_PROP_UINT64("descriptor-addr-offset", EHCIPCIState,
> + ehci.descriptor_addr_offset, 0),
> };
I note OHCI uses DEFINE_PROP_DMAADDR() here. Single use, maybe better
remove it and stick to uint64_t as you use.
Could we have a DEFINE_EHCI_COMMON_PROPERTIES() macro for common
entries instead, such DEFINE_SDHCI_COMMON_PROPERTIES()?
>
> static const VMStateDescription vmstate_ehci_pci = {
> diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c
> index 61215e9f3d..df138fb339 100644
> --- a/hw/usb/hcd-ehci-sysbus.c
> +++ b/hw/usb/hcd-ehci-sysbus.c
> @@ -36,6 +36,8 @@ static const Property ehci_sysbus_properties[] = {
> false),
> DEFINE_PROP_BOOL("caps-64bit-addr", EHCISysBusState, ehci.caps_64bit_addr,
> false),
> + DEFINE_PROP_UINT64("descriptor-addr-offset", EHCISysBusState,
> + ehci.descriptor_addr_offset, 0),
> };
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 14/17] hw/arm/aspeed_ast27x0: Enable 64-bit EHCI DMA addressing
2026-04-16 1:50 ` [PATCH v3 14/17] hw/arm/aspeed_ast27x0: Enable 64-bit EHCI DMA addressing Jamin Lin
@ 2026-04-17 6:23 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 69+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-17 6:23 UTC (permalink / raw)
To: Jamin Lin, Cédric Le Goater, Peter Maydell, Steven Lee,
Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com,
Cédric Le Goater
On 16/4/26 03:50, Jamin Lin wrote:
> AST2700 supports a 64-bit DRAM address space. Therefore, DMA
> transactions must be capable of accessing 64-bit addresses.
>
> Enable the "caps-64bit-addr" property for the EHCI controllers
> on AST2700 so that USB DMA operations can correctly handle
> 64-bit memory addresses.
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> Reviewed-by: Cédric Le Goater <clg@redhat.com>
> ---
> hw/arm/aspeed_ast27x0.c | 2 ++
> 1 file changed, 2 insertions(+)
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 15/17] hw/arm/aspeed_ast27x0: Set EHCI descriptor address offset
2026-04-16 1:50 ` [PATCH v3 15/17] hw/arm/aspeed_ast27x0: Set EHCI descriptor address offset Jamin Lin
@ 2026-04-17 6:25 ` Philippe Mathieu-Daudé
2026-04-22 5:03 ` Jamin Lin
0 siblings, 1 reply; 69+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-17 6:25 UTC (permalink / raw)
To: Jamin Lin, Cédric Le Goater, Peter Maydell, Steven Lee,
Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
On 16/4/26 03:50, Jamin Lin wrote:
> On AST2700 platforms, system DRAM is mapped above 4GB with the
> base address at 0x400000000.
>
> The Linux EHCI driver programs the segment register to zero when
> 64-bit addressing is supported. As a result, descriptor addresses
> derived from the EHCI registers do not include the DRAM base
> address.
>
> Descriptor memory is allocated through the DMA API with a 64-bit
> DMA mask, which allows descriptors to be placed in DRAM above 4GB.
> When running on AST2700, this means EHCI queue heads (QH) and queue
> element transfer descriptors (qTD) reside at addresses starting
> from 0x400000000.
>
> Set the descriptor-addr-offset property to the DRAM base so the
> emulated EHCI controller can construct the correct descriptor
> addresses when accessing system memory.
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> ---
> hw/arm/aspeed_ast27x0.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
> index 4a1f7cad73..3cdbf78ac1 100644
> --- a/hw/arm/aspeed_ast27x0.c
> +++ b/hw/arm/aspeed_ast27x0.c
> @@ -858,6 +858,9 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp)
> for (i = 0; i < sc->ehcis_num; i++) {
> object_property_set_bool(OBJECT(&s->ehci[i]), "caps-64bit-addr", true,
> &error_abort);
> + object_property_set_int(OBJECT(&s->ehci[i]), "descriptor-addr-offset",
> + sc->memmap[ASPEED_DEV_SDRAM],
> + &error_abort);
Squash with previous? Or invert 14 <-> 15 order?
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 16/17] tests/functional/arm/test_aspeed_ast2600_sdk: Add USB EHCI test for AST2600 SDK
2026-04-16 1:50 ` [PATCH v3 16/17] tests/functional/arm/test_aspeed_ast2600_sdk: Add USB EHCI test for AST2600 SDK Jamin Lin
@ 2026-04-17 6:27 ` Philippe Mathieu-Daudé
2026-04-17 7:40 ` Jamin Lin
0 siblings, 1 reply; 69+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-17 6:27 UTC (permalink / raw)
To: Jamin Lin, Cédric Le Goater, Peter Maydell, Steven Lee,
Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
On 16/4/26 03:50, Jamin Lin wrote:
> Add a functional test to verify USB EHCI support on the AST2600
> SDK machine by attaching a USB keyboard device and checking its
> enumeration via lsusb.
>
> This introduces a helper routine that runs lsusb in the guest
> and validates that the emulated "QEMU USB Keyboard" is detected.
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> ---
> tests/functional/arm/test_aspeed_ast2600_sdk.py | 7 +++++++
> 1 file changed, 7 insertions(+)
This should be patch #1 :)
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 17/17] tests/functional/aarch64/test_aspeed_ast2700: Add USB EHCI test for AST2700 A1/A2
2026-04-16 1:50 ` [PATCH v3 17/17] tests/functional/aarch64/test_aspeed_ast2700: Add USB EHCI test for AST2700 A1/A2 Jamin Lin
@ 2026-04-17 6:27 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 69+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-17 6:27 UTC (permalink / raw)
To: Jamin Lin, Cédric Le Goater, Peter Maydell, Steven Lee,
Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
On 16/4/26 03:50, Jamin Lin wrote:
> Add a functional test to verify USB EHCI support on the AST2700 A2/A1
> by attaching a USB keyboard device and checking its
> enumeration via lsusb.
>
> This introduces a helper routine that runs lsusb in the guest
> and validates that the emulated "QEMU USB Keyboard" is detected.
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> ---
> tests/functional/aarch64/test_aspeed_ast2700a1.py | 7 +++++++
> tests/functional/aarch64/test_aspeed_ast2700a2.py | 7 +++++++
> 2 files changed, 14 insertions(+)
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 12/17] hw/usb/hcd-ehci: Implement 64-bit siTD descriptor addressing
2026-04-16 1:49 ` [PATCH v3 12/17] hw/usb/hcd-ehci: Implement 64-bit siTD " Jamin Lin
@ 2026-04-17 6:27 ` Philippe Mathieu-Daudé
2026-04-17 7:44 ` Jamin Lin
0 siblings, 1 reply; 69+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-17 6:27 UTC (permalink / raw)
To: Jamin Lin, Cédric Le Goater, Peter Maydell, Steven Lee,
Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
On 16/4/26 03:49, Jamin Lin wrote:
> EHCI supports 64-bit control data structure addressing when the
> 64-bit Addressing Capability bit in HCCPARAMS is set. In that mode,
> the CTRLDSSEGMENT register provides the upper 32 bits that are
> concatenated with 32-bit link pointer values to form full 64-bit
> descriptor addresses (EHCI 1.0, section 2.3.5 and Appendix B).
>
> siTD link pointers are stored as 32-bit values and must be expanded
> to full 64-bit descriptor addresses when 64-bit mode is enabled.
> Update the siTD traversal path to use ehci_get_desc_addr() when
> following link pointers.
>
> Appendix B also defines high dword fields for siTD buffer pointers.
> Add bufptr_hi[] fields to EHCIsitd and use ehci_get_buf_addr() to
> construct full 64-bit buffer addresses from bufptr[] and bufptr_hi[]
> when processing split isochronous transfers. This allows buffers
> above 4GB to be handled correctly.
>
> When 64-bit capability is disabled, descriptor and buffer addresses
> remain 32-bit and existing behaviour is unchanged.
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> ---
> hw/usb/hcd-ehci.h | 1 +
> hw/usb/hcd-ehci.c | 2 +-
> 2 files changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
> index af8c080c60..6406f536e8 100644
> --- a/hw/usb/hcd-ehci.h
> +++ b/hw/usb/hcd-ehci.h
> @@ -109,6 +109,7 @@ typedef struct EHCIsitd {
> #define SITD_BUFPTR_TCNT_MASK 0x00000007
>
> uint32_t backptr; /* Standard next link pointer */
> + uint32_t bufptr_hi[2];
Not used?
> } EHCIsitd;
>
> /*
> diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
> index 3db1c25e4d..e1d5ecbad7 100644
> --- a/hw/usb/hcd-ehci.c
> +++ b/hw/usb/hcd-ehci.c
> @@ -1791,7 +1791,7 @@ static int ehci_state_fetchsitd(EHCIState *ehci, int async)
> warn_report("Skipping active siTD");
> }
>
> - ehci_set_fetch_addr(ehci, async, sitd.next);
> + ehci_set_fetch_addr(ehci, async, ehci_get_desc_addr(ehci, sitd.next));
> ehci_set_state(ehci, async, EST_FETCHENTRY);
> return 1;
> }
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 01/17] hw/usb/hcd-ehci: Remove unused EHCIfstn structure and dead code
2026-04-16 1:49 ` [PATCH v3 01/17] hw/usb/hcd-ehci: Remove unused EHCIfstn structure and dead code Jamin Lin
2026-04-16 12:09 ` BALATON Zoltan
@ 2026-04-17 6:30 ` Cédric Le Goater
1 sibling, 0 replies; 69+ messages in thread
From: Cédric Le Goater @ 2026-04-17 6:30 UTC (permalink / raw)
To: Jamin Lin, philmd@linaro.org, Peter Maydell, Steven Lee, Troy Lee,
Kane Chen, Andrew Jeffery, Joel Stanley, open list:ASPEED BMCs,
open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
On 4/16/26 03:49, Jamin Lin wrote:
> The EHCIfstn structure, defined according to EHCI spec section 3.7,
> is currently unused in the EHCI implementation. Remove it to reduce
> unused code and improve maintainability.
>
> Additionally, drop a block of disabled (#if 0) code in
> ehci_state_advqueue() that was never implemented. This code path
> is incomplete and has no functional impact.
>
> No functional change.
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Thanks,
C.
> ---
> hw/usb/hcd-ehci.h | 7 -------
> hw/usb/hcd-ehci.c | 11 -----------
> 2 files changed, 18 deletions(-)
>
> diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
> index 0ae8c06331..3aec0e047c 100644
> --- a/hw/usb/hcd-ehci.h
> +++ b/hw/usb/hcd-ehci.h
> @@ -202,13 +202,6 @@ typedef struct EHCIqh {
> #define BUFPTR_SBYTES_SH 5
> } EHCIqh;
>
> -/* EHCI spec version 1.0 Section 3.7
> - */
> -typedef struct EHCIfstn {
> - uint32_t next; /* Standard next link pointer */
> - uint32_t backptr; /* Standard next link pointer */
> -} EHCIfstn;
> -
> enum async_state {
> EHCI_ASYNC_NONE = 0,
> EHCI_ASYNC_INITIALIZED,
> diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
> index 57f930b099..5ea8461f70 100644
> --- a/hw/usb/hcd-ehci.c
> +++ b/hw/usb/hcd-ehci.c
> @@ -1756,17 +1756,6 @@ static int ehci_state_fetchsitd(EHCIState *ehci, int async)
> /* Section 4.10.2 - paragraph 3 */
> static int ehci_state_advqueue(EHCIQueue *q)
> {
> -#if 0
> - /* TO-DO: 4.10.2 - paragraph 2
> - * if I-bit is set to 1 and QH is not active
> - * go to horizontal QH
> - */
> - if (I-bit set) {
> - ehci_set_state(ehci, async, EST_HORIZONTALQH);
> - goto out;
> - }
> -#endif
> -
> /*
> * want data and alt-next qTD is valid
> */
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 03/17] hw/usb/hcd-ehci.c: Fix coding style issues reported by checkpatch
2026-04-16 1:49 ` [PATCH v3 03/17] hw/usb/hcd-ehci.c: " Jamin Lin
@ 2026-04-17 6:31 ` Cédric Le Goater
2026-04-17 6:32 ` Philippe Mathieu-Daudé
1 sibling, 0 replies; 69+ messages in thread
From: Cédric Le Goater @ 2026-04-17 6:31 UTC (permalink / raw)
To: Jamin Lin, philmd@linaro.org, Peter Maydell, Steven Lee, Troy Lee,
Kane Chen, Andrew Jeffery, Joel Stanley, open list:ASPEED BMCs,
open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
On 4/16/26 03:49, Jamin Lin wrote:
> No functional change.
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> ---
> hw/usb/hcd-ehci.c | 126 +++++++++++++++++++++++++---------------------
> 1 file changed, 69 insertions(+), 57 deletions(-)
>
> diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
> index 5ea8461f70..9b92384bac 100644
> --- a/hw/usb/hcd-ehci.c
> +++ b/hw/usb/hcd-ehci.c
> @@ -41,21 +41,23 @@
> #define FRAME_TIMER_NS (NANOSECONDS_PER_SECOND / FRAME_TIMER_FREQ)
> #define UFRAME_TIMER_NS (FRAME_TIMER_NS / 8)
>
> -#define NB_MAXINTRATE 8 // Max rate at which controller issues ints
> -#define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction
> -#define MAX_QH 100 // Max allowable queue heads in a chain
> +#define NB_MAXINTRATE 8 /* Max rate at which controller issues ints */
> +#define BUFF_SIZE (5 * 4096) /* Max bytes to transfer per transaction */
> +#define MAX_QH 100 /* Max allowable queue heads in a chain */
> #define MIN_UFR_PER_TICK 24 /* Min frames to process when catching up */
> #define PERIODIC_ACTIVE 512 /* Micro-frames */
>
> -/* Internal periodic / asynchronous schedule state machine states
> +/*
> + * Internal periodic / asynchronous schedule state machine states
> */
> typedef enum {
> EST_INACTIVE = 1000,
> EST_ACTIVE,
> EST_EXECUTING,
> EST_SLEEPING,
> - /* The following states are internal to the state machine function
> - */
> + /*
> + * The following states are internal to the state machine function
> + */
> EST_WAITLISTHEAD,
> EST_FETCHENTRY,
> EST_FETCHQH,
> @@ -71,13 +73,13 @@ typedef enum {
> /* macros for accessing fields within next link pointer entry */
> #define NLPTR_GET(x) ((x) & 0xffffffe0)
> #define NLPTR_TYPE_GET(x) (((x) >> 1) & 3)
> -#define NLPTR_TBIT(x) ((x) & 1) // 1=invalid, 0=valid
> +#define NLPTR_TBIT(x) ((x) & 1) /* 1=invalid, 0=valid */
>
> /* link pointer types */
> -#define NLPTR_TYPE_ITD 0 // isoc xfer descriptor
> -#define NLPTR_TYPE_QH 1 // queue head
> -#define NLPTR_TYPE_STITD 2 // split xaction, isoc xfer descriptor
> -#define NLPTR_TYPE_FSTN 3 // frame span traversal node
> +#define NLPTR_TYPE_ITD 0 /* isoc xfer descriptor */
> +#define NLPTR_TYPE_QH 1 /* queue head */
> +#define NLPTR_TYPE_STITD 2 /* split xaction, isoc xfer descriptor */
> +#define NLPTR_TYPE_FSTN 3 /* frame span traversal node */
>
> #define SET_LAST_RUN_CLOCK(s) \
> (s)->last_run_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> @@ -88,10 +90,10 @@ typedef enum {
>
> #define set_field(data, newval, field) do { \
> uint32_t val = *data; \
> - val &= ~ field##_MASK; \
> + val &= ~field##_MASK; \
> val |= ((newval) << field##_SH) & field##_MASK; \
> *data = val; \
> - } while(0)
> + } while (0)
>
> static const char *ehci_state_names[] = {
> [EST_INACTIVE] = "INACTIVE",
> @@ -472,8 +474,10 @@ static bool ehci_verify_pid(EHCIQueue *q, EHCIqtd *qtd)
> }
> }
>
> -/* Finish executing and writeback a packet outside of the regular
> - fetchqh -> fetchqtd -> execute -> writeback cycle */
> +/*
> + * Finish executing and writeback a packet outside of the regular
> + * fetchqh -> fetchqtd -> execute -> writeback cycle
> + */
> static void ehci_writeback_async_complete_packet(EHCIPacket *p)
> {
> EHCIQueue *q = p->queue;
> @@ -733,7 +737,7 @@ static void ehci_detach(USBPort *port)
> ehci_queues_rip_device(s, port->dev, 0);
> ehci_queues_rip_device(s, port->dev, 1);
>
> - *portsc &= ~(PORTSC_CONNECT|PORTSC_PED|PORTSC_SUSPEND);
> + *portsc &= ~(PORTSC_CONNECT | PORTSC_PED | PORTSC_SUSPEND);
> *portsc |= PORTSC_CSC;
>
> ehci_raise_irq(s, USBSTS_PCD);
> @@ -858,7 +862,7 @@ void ehci_reset(void *opaque)
> * Do the detach before touching portsc, so that it correctly gets send to
> * us or to our companion based on PORTSC_POWNER before the reset.
> */
> - for(i = 0; i < EHCI_PORTS; i++) {
> + for (i = 0; i < EHCI_PORTS; i++) {
> devs[i] = s->ports[i].dev;
> if (devs[i] && devs[i]->attached) {
> usb_detach(&s->ports[i]);
> @@ -877,7 +881,7 @@ void ehci_reset(void *opaque)
> s->astate = EST_INACTIVE;
> s->pstate = EST_INACTIVE;
>
> - for(i = 0; i < EHCI_PORTS; i++) {
> + for (i = 0; i < EHCI_PORTS; i++) {
> if (s->companion_ports[i]) {
> s->portsc[i] = PORTSC_POWNER | PORTSC_PPOWER;
> } else {
> @@ -942,8 +946,9 @@ static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner)
> uint32_t *portsc = &s->portsc[port];
> uint32_t orig;
>
> - if (s->companion_ports[port] == NULL)
> + if (s->companion_ports[port] == NULL) {
> return;
> + }
>
> owner = owner & PORTSC_POWNER;
> orig = *portsc & PORTSC_POWNER;
> @@ -988,7 +993,7 @@ static void ehci_port_write(void *ptr, hwaddr addr,
> trace_usb_ehci_port_reset(port, 1);
> }
>
> - if (!(val & PORTSC_PRESET) &&(*portsc & PORTSC_PRESET)) {
> + if (!(val & PORTSC_PRESET) && (*portsc & PORTSC_PRESET)) {
> trace_usb_ehci_port_reset(port, 0);
> if (dev && dev->attached) {
> usb_port_reset(&s->ports[port]);
> @@ -1065,8 +1070,10 @@ static void ehci_opreg_write(void *ptr, hwaddr addr,
> break;
>
> case USBSTS:
> - val &= USBSTS_RO_MASK; // bits 6 through 31 are RO
> - ehci_clear_usbsts(s, val); // bits 0 through 5 are R/WC
> + /* bits 6 through 31 are RO */
> + val &= USBSTS_RO_MASK;
> + /* bits 0 through 5 are R/WC */
> + ehci_clear_usbsts(s, val);
> val = s->usbsts;
> ehci_update_irq(s);
> break;
> @@ -1131,8 +1138,7 @@ static void ehci_flush_qh(EHCIQueue *q)
> put_dwords(q->ehci, addr + 3 * sizeof(uint32_t), qh + 3, dwords - 3);
> }
>
> -// 4.10.2
> -
> +/* 4.10.2 */
> static int ehci_qh_do_overlay(EHCIQueue *q)
> {
> EHCIPacket *p = QTAILQ_FIRST(&q->packets);
> @@ -1145,8 +1151,7 @@ static int ehci_qh_do_overlay(EHCIQueue *q)
> assert(p != NULL);
> assert(p->qtdaddr == q->qtdaddr);
>
> - // remember values in fields to preserve in qh after overlay
> -
> + /* remember values in fields to preserve in qh after overlay */
> dtoggle = q->qh.token & QTD_TOKEN_DTOGGLE;
> ping = q->qh.token & QTD_TOKEN_PING;
>
> @@ -1170,7 +1175,7 @@ static int ehci_qh_do_overlay(EHCIQueue *q)
> }
>
> if (!(q->qh.epchar & QH_EPCHAR_DTC)) {
> - // preserve QH DT bit
> + /* preserve QH DT bit */
> q->qh.token &= ~QTD_TOKEN_DTOGGLE;
> q->qh.token |= dtoggle;
> }
> @@ -1397,9 +1402,7 @@ static int ehci_execute(EHCIPacket *p, const char *action)
> return 1;
> }
>
> -/* 4.7.2
> - */
> -
> +/* 4.7.2 */
> static int ehci_process_itd(EHCIState *ehci,
> EHCIitd *itd,
> uint32_t addr)
> @@ -1411,13 +1414,13 @@ static int ehci_process_itd(EHCIState *ehci,
>
> ehci->periodic_sched_active = PERIODIC_ACTIVE;
>
> - dir =(itd->bufptr[1] & ITD_BUFPTR_DIRECTION);
> + dir = (itd->bufptr[1] & ITD_BUFPTR_DIRECTION);
> devaddr = get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR);
> endp = get_field(itd->bufptr[0], ITD_BUFPTR_EP);
> max = get_field(itd->bufptr[1], ITD_BUFPTR_MAXPKT);
> mult = get_field(itd->bufptr[2], ITD_BUFPTR_MULT);
>
> - for(i = 0; i < 8; i++) {
> + for (i = 0; i < 8; i++) {
> if (itd->transact[i] & ITD_XACT_ACTIVE) {
> pg = get_field(itd->transact[i], ITD_XACT_PGSEL);
> off = itd->transact[i] & ITD_XACT_OFFSET_MASK;
> @@ -1513,8 +1516,9 @@ static int ehci_process_itd(EHCIState *ehci,
> }
>
>
> -/* This state is the entry point for asynchronous schedule
> - * processing. Entry here constitutes a EHCI start event state (4.8.5)
> +/*
> + * This state is the entry point for asynchronous schedule
> + * processing. Entry here constitutes a EHCI start event state (4.8.5)
> */
> static int ehci_state_waitlisthead(EHCIState *ehci, int async)
> {
> @@ -1531,7 +1535,7 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async)
> ehci_queues_rip_unused(ehci, async);
>
> /* Find the head of the list (4.9.1.1) */
> - for(i = 0; i < MAX_QH; i++) {
> + for (i = 0; i < MAX_QH; i++) {
> if (get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &qh,
> sizeof(EHCIqh) >> 2) < 0) {
> return 0;
> @@ -1564,8 +1568,9 @@ out:
> }
>
>
> -/* This state is the entry point for periodic schedule processing as
> - * well as being a continuation state for async processing.
> +/*
> + * This state is the entry point for periodic schedule processing as
> + * well as being a continuation state for async processing.
> */
> static int ehci_state_fetchentry(EHCIState *ehci, int async)
> {
> @@ -1674,7 +1679,7 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
>
> #if EHCI_DEBUG
> if (q->qhaddr != q->qh.next) {
> - DPRINTF("FETCHQH: QH 0x%08x (h %x halt %x active %x) next 0x%08x\n",
> + DPRINTF("FETCHQH: QH 0x%08x (h %x halt %x active %x) next 0x%08x\n",
> q->qhaddr,
> q->qh.epchar & QH_EPCHAR_H,
> q->qh.token & QTD_TOKEN_HALT,
> @@ -1924,8 +1929,10 @@ static int ehci_state_execute(EHCIQueue *q)
> return -1;
> }
>
> - // TODO verify enough time remains in the uframe as in 4.4.1.1
> - // TODO write back ptr to async list when done or out of time
> + /*
> + * TODO verify enough time remains in the uframe as in 4.4.1.1
> + * TODO write back ptr to async list when done or out of time
> + */
>
> /* 4.10.3, bottom of page 82, go horizontal on transaction counter == 0 */
> if (!q->async && q->transact_ctr == 0) {
> @@ -2036,7 +2043,7 @@ static void ehci_advance_state(EHCIState *ehci, int async)
> int again;
>
> do {
> - switch(ehci_get_state(ehci, async)) {
> + switch (ehci_get_state(ehci, async)) {
> case EST_WAITLISTHEAD:
> again = ehci_state_waitlisthead(ehci, async);
> break;
> @@ -2115,21 +2122,20 @@ static void ehci_advance_state(EHCIState *ehci, int async)
> ehci_reset(ehci);
> again = 0;
> }
> - }
> - while (again);
> + } while (again);
> }
>
> static void ehci_advance_async_state(EHCIState *ehci)
> {
> const int async = 1;
>
> - switch(ehci_get_state(ehci, async)) {
> + switch (ehci_get_state(ehci, async)) {
> case EST_INACTIVE:
> if (!ehci_async_enabled(ehci)) {
> break;
> }
> ehci_set_state(ehci, async, EST_ACTIVE);
> - // No break, fall through to ACTIVE
> + /* No break, fall through to ACTIVE */
>
> case EST_ACTIVE:
> if (!ehci_async_enabled(ehci)) {
> @@ -2153,7 +2159,8 @@ static void ehci_advance_async_state(EHCIState *ehci)
> ehci_set_state(ehci, async, EST_WAITLISTHEAD);
> ehci_advance_state(ehci, async);
>
> - /* If the doorbell is set, the guest wants to make a change to the
> + /*
> + * If the doorbell is set, the guest wants to make a change to the
> * schedule. The host controller needs to release cached data.
> * (section 4.8.2)
> */
> @@ -2180,13 +2187,13 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
> uint32_t list;
> const int async = 0;
>
> - // 4.6
> + /* 4.6 */
>
> - switch(ehci_get_state(ehci, async)) {
> + switch (ehci_get_state(ehci, async)) {
> case EST_INACTIVE:
> if (!(ehci->frindex & 7) && ehci_periodic_enabled(ehci)) {
> ehci_set_state(ehci, async, EST_ACTIVE);
> - // No break, fall through to ACTIVE
> + /* No break, fall through to ACTIVE */
> } else
> break;
>
> @@ -2210,7 +2217,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
>
> DPRINTF("PERIODIC state adv fr=%d. [%08X] -> %08X\n",
> ehci->frindex / 8, list, entry);
> - ehci_set_fetch_addr(ehci, async,entry);
> + ehci_set_fetch_addr(ehci, async, entry);
> ehci_set_state(ehci, async, EST_FETCHENTRY);
> ehci_advance_state(ehci, async);
> ehci_queues_rip_unused(ehci, async);
> @@ -2235,7 +2242,8 @@ static void ehci_update_frindex(EHCIState *ehci, int uframes)
> ehci_raise_irq(ehci, USBSTS_FLR);
> }
>
> - /* How many times will frindex roll over 0x4000 with this frame count?
> + /*
> + * How many times will frindex roll over 0x4000 with this frame count?
> * usbsts_frindex is decremented by 0x4000 on rollover until it reaches 0
> */
> int rollovers = (ehci->frindex + uframes) / 0x4000;
> @@ -2315,8 +2323,9 @@ static void ehci_work_bh(void *opaque)
> ehci->async_stepdown++;
> }
>
> - /* Async is not inside loop since it executes everything it can once
> - * called
> + /*
> + * Async is not inside loop since it executes everything it can once
> + * called
> */
> if (ehci_async_enabled(ehci) || ehci->astate != EST_INACTIVE) {
> need_timer++;
> @@ -2334,15 +2343,18 @@ static void ehci_work_bh(void *opaque)
> }
>
> if (need_timer) {
> - /* If we've raised int, we speed up the timer, so that we quickly
> - * notice any new packets queued up in response */
> + /*
> + * If we've raised int, we speed up the timer, so that we quickly
> + * notice any new packets queued up in response
> + */
> if (ehci->int_req_by_async && (ehci->usbsts & USBSTS_INT)) {
> expire_time = t_now +
> NANOSECONDS_PER_SECOND / (FRAME_TIMER_FREQ * 4);
> ehci->int_req_by_async = false;
> } else {
> - expire_time = t_now + (NANOSECONDS_PER_SECOND
> - * (ehci->async_stepdown+1) / FRAME_TIMER_FREQ);
> + expire_time = t_now
> + + (NANOSECONDS_PER_SECOND * (ehci->async_stepdown + 1) /
> + FRAME_TIMER_FREQ);
> }
> timer_mod(ehci->frame_timer, expire_time);
> }
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Thanks,
C.
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 04/17] hw/usb/hcd-ehci.c: Replace fprintf(stderr, ...) with qemu_log_mask(LOG_GUEST_ERROR)
2026-04-16 1:49 ` [PATCH v3 04/17] hw/usb/hcd-ehci.c: Replace fprintf(stderr, ...) with qemu_log_mask(LOG_GUEST_ERROR) Jamin Lin
@ 2026-04-17 6:31 ` Philippe Mathieu-Daudé
2026-04-17 8:41 ` Jamin Lin
0 siblings, 1 reply; 69+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-17 6:31 UTC (permalink / raw)
To: Jamin Lin, Cédric Le Goater, Peter Maydell, Steven Lee,
Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
On 16/4/26 03:49, Jamin Lin wrote:
> Replace direct fprintf(stderr, ...) calls with qemu_log_mask()
> using LOG_GUEST_ERROR in the EHCI controller implementation.
>
> Direct writes to stderr are discouraged in QEMU as they bypass
> the logging framework and cannot be filtered or controlled at
> runtime. Using qemu_log_mask() ensures that guest-visible errors
> are properly categorized and can be managed via QEMU logging
> options.
>
> All affected messages correspond to guest-triggerable error
> conditions, so LOG_GUEST_ERROR is used consistently.
>
> This change improves integration with QEMU's logging infrastructure
> and aligns with upstream coding guidelines.
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> ---
> hw/usb/hcd-ehci.c | 43 +++++++++++++++++++++++++------------------
> 1 file changed, 25 insertions(+), 18 deletions(-)
> @@ -532,7 +533,7 @@ static void ehci_free_packet(EHCIPacket *p)
> }
> if (p->async == EHCI_ASYNC_FINISHED &&
> p->packet.status == USB_RET_SUCCESS) {
> - fprintf(stderr,
> + qemu_log_mask(LOG_GUEST_ERROR,
> "EHCI: Dropping completed packet from halted %s ep %02X\n",
> (p->pid == USB_TOKEN_IN) ? "in" : "out",
> get_field(p->queue->qh.epchar, QH_EPCHAR_EP));
> @@ -1042,8 +1043,9 @@ static void ehci_opreg_write(void *ptr, hwaddr addr,
>
> /* not supporting dynamic frame list size at the moment */
> if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) {
> - fprintf(stderr, "attempt to set frame list size -- value %d\n",
> - (int)val & USBCMD_FLS);
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "attempt to set frame list size -- value %d\n",
PRId64
> + (int)val & USBCMD_FLS);
> val &= ~USBCMD_FLS;
> }
> @@ -1584,7 +1589,8 @@ static int ehci_state_fetchentry(EHCIState *ehci, int async)
>
> /* section 4.8, only QH in async schedule */
> if (async && (NLPTR_TYPE_GET(entry) != NLPTR_TYPE_QH)) {
> - fprintf(stderr, "non queue head request in async schedule\n");
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "non queue head request in async schedule\n");
> return -1;
> }
>
> @@ -1606,7 +1612,7 @@ static int ehci_state_fetchentry(EHCIState *ehci, int async)
>
> default:
> /* TODO: handle FSTN type */
> - fprintf(stderr, "FETCHENTRY: entry at %X is of type %u "
> + qemu_log_mask(LOG_GUEST_ERROR, "FETCHENTRY: entry at %X is of type %u "
"0x%x"
> "which is not supported yet\n", entry, NLPTR_TYPE_GET(entry));
> return -1;
> }
> @@ -2112,13 +2118,14 @@ static void ehci_advance_state(EHCIState *ehci, int async)
> break;
>
> default:
> - fprintf(stderr, "Bad state!\n");
> + qemu_log_mask(LOG_GUEST_ERROR, "Bad state!\n");
Just remove for "bad state" entries?
> g_assert_not_reached();
> }
>
> if (again < 0 || itd_count > 16) {
> /* TODO: notify guest (raise HSE irq?) */
> - fprintf(stderr, "processing error - resetting ehci HC\n");
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "processing error - resetting ehci HC\n");
> ehci_reset(ehci);
> again = 0;
> }
> @@ -2175,7 +2182,7 @@ static void ehci_advance_async_state(EHCIState *ehci)
>
> default:
> /* this should only be due to a developer mistake */
> - fprintf(stderr, "ehci: Bad asynchronous state %d. "
> + qemu_log_mask(LOG_GUEST_ERROR, "ehci: Bad asynchronous state %d. "
> "Resetting to active\n", ehci->astate);
Ditto.
> g_assert_not_reached();
> }
> @@ -2225,7 +2232,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
>
> default:
> /* this should only be due to a developer mistake */
> - fprintf(stderr, "ehci: Bad periodic state %d. "
> + qemu_log_mask(LOG_GUEST_ERROR, "ehci: Bad periodic state %d. "
> "Resetting to active\n", ehci->pstate);
> g_assert_not_reached();
Ditto.
> }
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 03/17] hw/usb/hcd-ehci.c: Fix coding style issues reported by checkpatch
2026-04-16 1:49 ` [PATCH v3 03/17] hw/usb/hcd-ehci.c: " Jamin Lin
2026-04-17 6:31 ` Cédric Le Goater
@ 2026-04-17 6:32 ` Philippe Mathieu-Daudé
1 sibling, 0 replies; 69+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-17 6:32 UTC (permalink / raw)
To: Jamin Lin, Cédric Le Goater, Peter Maydell, Steven Lee,
Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
On 16/4/26 03:49, Jamin Lin wrote:
> No functional change.
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> ---
> hw/usb/hcd-ehci.c | 126 +++++++++++++++++++++++++---------------------
> 1 file changed, 69 insertions(+), 57 deletions(-)
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 02/17] hw/usb/hcd-ehci.h: Fix coding style issues reported by checkpatch
2026-04-16 1:49 ` [PATCH v3 02/17] hw/usb/hcd-ehci.h: Fix coding style issues reported by checkpatch Jamin Lin
@ 2026-04-17 6:32 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 69+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-17 6:32 UTC (permalink / raw)
To: Jamin Lin, Cédric Le Goater, Peter Maydell, Steven Lee,
Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com,
Cédric Le Goater
On 16/4/26 03:49, Jamin Lin wrote:
> No functional change.
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> Reviewed-by: Cédric Le Goater <clg@redhat.com>
> ---
> hw/usb/hcd-ehci.h | 17 +++++++++++------
> 1 file changed, 11 insertions(+), 6 deletions(-)
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 08/17] hw/usb/hcd-ehci: Reject CTRLDSSEGMENT writes without 64-bit capability
2026-04-16 1:49 ` [PATCH v3 08/17] hw/usb/hcd-ehci: Reject CTRLDSSEGMENT writes without 64-bit capability Jamin Lin
@ 2026-04-17 6:33 ` Philippe Mathieu-Daudé
2026-04-17 8:07 ` Jamin Lin
0 siblings, 1 reply; 69+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-17 6:33 UTC (permalink / raw)
To: Jamin Lin, Cédric Le Goater, Peter Maydell, Steven Lee,
Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
On 16/4/26 03:49, Jamin Lin wrote:
> The EHCI CTRLDSSEGMENT register provides the upper 32 bits [63:32] used to
> form 64-bit addresses for EHCI control data structures. Per EHCI 1.0
> spec section 2.3.5, when the HCCPARAMS 64-bit Addressing Capability bit
> is zero, CTRLDSSEGMENT is not used: software cannot write it and reads
> must return zero.
>
> Add a capability check in the operational register write handler and
> reject guest writes to CTRLDSSEGMENT when 64-bit addressing is
> not enabled.
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> ---
> hw/usb/hcd-ehci.c | 9 ++++++++-
> 1 file changed, 8 insertions(+), 1 deletion(-)
>
> diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
> index 6409457186..b9e4251d62 100644
> --- a/hw/usb/hcd-ehci.c
> +++ b/hw/usb/hcd-ehci.c
> @@ -1108,7 +1108,14 @@ static void ehci_opreg_write(void *ptr, hwaddr addr,
> " is enabled and HC is enabled\n");
> }
> break;
> -
> + case CTRLDSSEGMENT:
> + if (!s->caps_64bit_addr) {
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "ehci: write to CTRLDSSEGMENT while "
> + " 64-bit addressing capability is disabled\n");
> + return;
> + }
> + break;
I'd squash with previous.
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 00/17] hw/usb/ehci: Add 64-bit descriptor addressing support
2026-04-16 1:49 [PATCH v3 00/17] hw/usb/ehci: Add 64-bit descriptor addressing support Jamin Lin
` (16 preceding siblings ...)
2026-04-16 1:50 ` [PATCH v3 17/17] tests/functional/aarch64/test_aspeed_ast2700: Add USB EHCI test for AST2700 A1/A2 Jamin Lin
@ 2026-04-17 6:35 ` Philippe Mathieu-Daudé
17 siblings, 0 replies; 69+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-17 6:35 UTC (permalink / raw)
To: Jamin Lin, Cédric Le Goater, Peter Maydell, Steven Lee,
Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
Hi Jamin,
On 16/4/26 03:49, Jamin Lin wrote:
> v1
> 1. Fix checkpatch coding style issues
> 2. Implement 64-bit addressing for QH/qTD/iTD/siTD descriptors
> 3. Add descriptor address offset property
> 4. Enable 64-bit EHCI DMA addressing on AST2700
> 5. Configure descriptor address offset for AST2700
>
> v2
> 1. Remove unused EHCIfstn structure and dead code
> 2. Replace fprintf(stderr, ...) with qemu_log_mask(LOG_GUEST_ERROR)
> 3. Replace DPRINTF debug logs with trace events
> 4. Add functional tests for USB EHCI on AST2600 and AST2700 A1/A2
> 5. Fix review issue
>
> v3:
> 1. Add Migration version test function
> 2. Add EHCI 64-bit buffer pointer fields description in commit log
I left trivial comments on v3 and expect v4 to be the last one :)
Regards,
Phil.
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 13/17] hw/usb/hcd-ehci: Add descriptor address offset property
2026-04-16 1:49 ` [PATCH v3 13/17] hw/usb/hcd-ehci: Add descriptor address offset property Jamin Lin
2026-04-17 6:23 ` Philippe Mathieu-Daudé
@ 2026-04-17 6:45 ` Cédric Le Goater
2026-04-17 7:08 ` Philippe Mathieu-Daudé
1 sibling, 1 reply; 69+ messages in thread
From: Cédric Le Goater @ 2026-04-17 6:45 UTC (permalink / raw)
To: Jamin Lin, philmd@linaro.org, Peter Maydell, Steven Lee, Troy Lee,
Kane Chen, Andrew Jeffery, Joel Stanley, open list:ASPEED BMCs,
open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
On 4/16/26 03:49, Jamin Lin wrote:
> When 64-bit addressing is supported, the Linux EHCI driver programs the
> segment register to zero. See ehci_run function:
> https://github.com/torvalds/linux/blob/master/drivers/usb/host/ehci-hcd.c
>
> The driver comment also notes that descriptor structures allocated from
> the DMA pool use segment zero semantics.
>
> Descriptor memory is allocated using the DMA API. The platform driver
> configures a 64-bit DMA mask so memory can be allocated above 4GB.
> See ehci_platform_probe function:
> https://github.com/torvalds/linux/blob/master/drivers/usb/host/ehci-platform.c
>
> On AST2700 platforms, system DRAM is mapped above 4GB at 0x400000000.
> As a result, descriptor addresses constructed directly from the guest
> EHCI registers do not match the actual system address used by the
> controller when fetching queue heads (QH) and queue element transfer
> descriptors (qTD).
>
> Introduce a descriptor-addr-offset property so platforms can provide an
> address offset applied when constructing descriptor addresses. This
> allows systems where DRAM resides above 4GB to correctly access EHCI
> descriptors while keeping the default behavior unchanged for existing
> machines.
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> ---
> hw/usb/hcd-ehci.h | 1 +
> hw/usb/hcd-ehci-pci.c | 2 ++
> hw/usb/hcd-ehci-sysbus.c | 2 ++
> hw/usb/hcd-ehci.c | 7 ++++++-
> 4 files changed, 11 insertions(+), 1 deletion(-)
>
> diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
> index 6406f536e8..05d8db4a5d 100644
> --- a/hw/usb/hcd-ehci.h
> +++ b/hw/usb/hcd-ehci.h
> @@ -264,6 +264,7 @@ struct EHCIState {
> /* properties */
> uint32_t maxframes;
> bool caps_64bit_addr;
> + uint64_t descriptor_addr_offset;
>
> /*
> * EHCI spec version 1.0 Section 2.3
> diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c
> index 2ea8549db9..115d05ede0 100644
> --- a/hw/usb/hcd-ehci-pci.c
> +++ b/hw/usb/hcd-ehci-pci.c
> @@ -139,6 +139,8 @@ static const Property ehci_pci_properties[] = {
> DEFINE_PROP_UINT32("maxframes", EHCIPCIState, ehci.maxframes, 128),
> DEFINE_PROP_BOOL("caps-64bit-addr", EHCIPCIState, ehci.caps_64bit_addr,
> false),
> + DEFINE_PROP_UINT64("descriptor-addr-offset", EHCIPCIState,
> + ehci.descriptor_addr_offset, 0),
> };
>
> static const VMStateDescription vmstate_ehci_pci = {
> diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c
> index 61215e9f3d..df138fb339 100644
> --- a/hw/usb/hcd-ehci-sysbus.c
> +++ b/hw/usb/hcd-ehci-sysbus.c
> @@ -36,6 +36,8 @@ static const Property ehci_sysbus_properties[] = {
> false),
> DEFINE_PROP_BOOL("caps-64bit-addr", EHCISysBusState, ehci.caps_64bit_addr,
> false),
> + DEFINE_PROP_UINT64("descriptor-addr-offset", EHCISysBusState,
> + ehci.descriptor_addr_offset, 0),
> };
>
> static void usb_ehci_sysbus_realize(DeviceState *dev, Error **errp)
> diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
> index e1d5ecbad7..ea9d5846bc 100644
> --- a/hw/usb/hcd-ehci.c
> +++ b/hw/usb/hcd-ehci.c
> @@ -162,7 +162,12 @@ static uint64_t ehci_get_buf_addr(EHCIState *s, uint32_t hi, uint32_t low,
>
> static uint64_t ehci_get_desc_addr(EHCIState *s, uint32_t low)
> {
> - return ehci_get_buf_addr(s, s->ctrldssegment, low, UINT32_MAX);
> + uint64_t addr;
> +
> + addr = ehci_get_buf_addr(s, s->ctrldssegment, low, UINT32_MAX);
> + addr += s->descriptor_addr_offset;
Instead, can we force a default value for ctrldssegment when
caps_64bit_addr is set ?
I am still trying to digest :
https://lore.kernel.org/qemu-devel/TYPPR06MB8206C7461E004C4FF07B8E92FC242@TYPPR06MB8206.apcprd06.prod.outlook.com/
We have time let's take a moment to think about the workaround.
Thanks,
C.
> + return addr;
> }
>
> static void ehci_trace_usbsts(uint32_t mask, int state)
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 06/17] hw/usb/hcd-ehci: Change descriptor addresses to 64-bit
2026-04-16 1:49 ` [PATCH v3 06/17] hw/usb/hcd-ehci: Change descriptor addresses to 64-bit Jamin Lin
2026-04-17 4:54 ` Philippe Mathieu-Daudé
@ 2026-04-17 7:01 ` Cédric Le Goater
2026-04-17 15:10 ` Peter Xu
1 sibling, 1 reply; 69+ messages in thread
From: Cédric Le Goater @ 2026-04-17 7:01 UTC (permalink / raw)
To: Jamin Lin, philmd@linaro.org, Peter Maydell, Steven Lee, Troy Lee,
Kane Chen, Andrew Jeffery, Joel Stanley, open list:ASPEED BMCs,
open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com, Fabiano Rosas,
'Peter Xu'
+ Peter, Fabiano,
On 4/16/26 03:49, Jamin Lin wrote:
> Change internal EHCI descriptor addresses from uint32_t to uint64_t.
>
> The following fields are updated:
> - EHCIPacket::qtdaddr
> - EHCIQueue::{qhaddr, qtdaddr}
> - EHCIState::{a_fetch_addr, p_fetch_addr}
>
> Update get_dwords() and put_dwords() to take 64-bit addresses and
> propagate the type change through the descriptor traversal paths.
>
> Adjust NLPTR_GET() to operate on 64-bit values:
>
> #define NLPTR_GET(x) ((x) & ~0x1fULL)
>
> so that link pointer masking works correctly when descriptor
> addresses exceed 32-bit space. The previous mask (0xffffffe0)
> implicitly truncated addresses to 32 bits.
>
> This patch does not change the on-wire descriptor layout yet.
> It only removes the internal 32-bit address limit and prepares
> for later patches that will add full 64-bit QH/qTD/iTD/siTD support.
>
> Update the EHCI trace-events prototypes for QH, qTD, iTD, and siTD to
> use uint64_t for the address argument and print it with PRIx64. This
> ensures full 64-bit addresses are shown in trace output and improves
> debugging of queue heads and transfer descriptors.
>
> Migration compatibility:
>
> The fetch address fields in EHCIState are extended from 32-bit to
> 64-bit, requiring a VMState version bump (v2 -> v3).
>
> Backward compatibility is preserved by keeping the legacy 32-bit
> fields (a_fetch_addr_pre_v3, p_fetch_addr_pre_v3) for pre-v3
> migration streams via VMSTATE_UINT32_TEST(), and introducing new
> 64-bit fields for v3+.
>
> In post_load, pre-v3 state is promoted to the 64-bit fields.
Since ehci is supported by downstream, I'd prefer that the
migration maintainers also verify the implementation.
Thanks,
C.
> No functional change.
>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> ---
> hw/usb/hcd-ehci.h | 12 +++++----
> hw/usb/hcd-ehci.c | 64 +++++++++++++++++++++++++++++----------------
> hw/usb/trace-events | 24 ++++++++---------
> 3 files changed, 60 insertions(+), 40 deletions(-)
>
> diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
> index 4234591cb4..24eea9d23b 100644
> --- a/hw/usb/hcd-ehci.h
> +++ b/hw/usb/hcd-ehci.h
> @@ -208,7 +208,7 @@ struct EHCIPacket {
> QTAILQ_ENTRY(EHCIPacket) next;
>
> EHCIqtd qtd; /* copy of current QTD (being worked on) */
> - uint32_t qtdaddr; /* address QTD read from */
> + uint64_t qtdaddr; /* address QTD read from */
>
> USBPacket packet;
> QEMUSGList sgl;
> @@ -229,8 +229,8 @@ struct EHCIQueue {
> * when guest removes an entry (doorbell, handshake sequence)
> */
> EHCIqh qh; /* copy of current QH (being worked on) */
> - uint32_t qhaddr; /* address QH read from */
> - uint32_t qtdaddr; /* address QTD read from */
> + uint64_t qhaddr; /* address QH read from */
> + uint64_t qtdaddr; /* address QTD read from */
> int last_pid; /* pid of last packet executed */
> USBDevice *dev;
> QTAILQ_HEAD(, EHCIPacket) packets;
> @@ -294,8 +294,10 @@ struct EHCIState {
> EHCIQueueHead pqueues;
>
> /* which address to look at next */
> - uint32_t a_fetch_addr;
> - uint32_t p_fetch_addr;
> + uint32_t a_fetch_addr_pre_v3;
> + uint32_t p_fetch_addr_pre_v3;
> + uint64_t a_fetch_addr;
> + uint64_t p_fetch_addr;
>
> USBPacket ipacket;
> QEMUSGList isgl;
> diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
> index d0ea4949f9..35173d27b4 100644
> --- a/hw/usb/hcd-ehci.c
> +++ b/hw/usb/hcd-ehci.c
> @@ -72,7 +72,7 @@ typedef enum {
> } EHCI_STATES;
>
> /* macros for accessing fields within next link pointer entry */
> -#define NLPTR_GET(x) ((x) & 0xffffffe0)
> +#define NLPTR_GET(x) ((x) & ~0x1fULL)
> #define NLPTR_TYPE_GET(x) (((x) >> 1) & 3)
> #define NLPTR_TBIT(x) ((x) & 1) /* 1=invalid, 0=valid */
>
> @@ -287,7 +287,7 @@ static int ehci_get_state(EHCIState *s, int async)
> return async ? s->astate : s->pstate;
> }
>
> -static void ehci_set_fetch_addr(EHCIState *s, int async, uint32_t addr)
> +static void ehci_set_fetch_addr(EHCIState *s, int async, uint64_t addr)
> {
> if (async) {
> s->a_fetch_addr = addr;
> @@ -296,7 +296,7 @@ static void ehci_set_fetch_addr(EHCIState *s, int async, uint32_t addr)
> }
> }
>
> -static int ehci_get_fetch_addr(EHCIState *s, int async)
> +static uint64_t ehci_get_fetch_addr(EHCIState *s, int async)
> {
> return async ? s->a_fetch_addr : s->p_fetch_addr;
> }
> @@ -373,7 +373,7 @@ static inline bool ehci_periodic_enabled(EHCIState *s)
> }
>
> /* Get an array of dwords from main memory */
> -static inline int get_dwords(EHCIState *ehci, uint32_t addr,
> +static inline int get_dwords(EHCIState *ehci, uint64_t addr,
> uint32_t *buf, int num)
> {
> int i;
> @@ -395,7 +395,7 @@ static inline int get_dwords(EHCIState *ehci, uint32_t addr,
> }
>
> /* Put an array of dwords in to main memory */
> -static inline int put_dwords(EHCIState *ehci, uint32_t addr,
> +static inline int put_dwords(EHCIState *ehci, uint64_t addr,
> uint32_t *buf, int num)
> {
> int i;
> @@ -549,7 +549,7 @@ static void ehci_free_packet(EHCIPacket *p)
>
> /* queue management */
>
> -static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, uint32_t addr, int async)
> +static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, uint64_t addr, int async)
> {
> EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
> EHCIQueue *q;
> @@ -622,7 +622,7 @@ static void ehci_free_queue(EHCIQueue *q, const char *warn)
> g_free(q);
> }
>
> -static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr,
> +static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint64_t addr,
> int async)
> {
> EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
> @@ -1135,7 +1135,7 @@ static void ehci_flush_qh(EHCIQueue *q)
> {
> uint32_t *qh = (uint32_t *) &q->qh;
> uint32_t dwords = sizeof(EHCIqh) >> 2;
> - uint32_t addr = NLPTR_GET(q->qhaddr);
> + uint64_t addr = NLPTR_GET(q->qhaddr);
>
> put_dwords(q->ehci, addr + 3 * sizeof(uint32_t), qh + 3, dwords - 3);
> }
> @@ -1406,12 +1406,13 @@ static int ehci_execute(EHCIPacket *p, const char *action)
> /* 4.7.2 */
> static int ehci_process_itd(EHCIState *ehci,
> EHCIitd *itd,
> - uint32_t addr)
> + uint64_t addr)
> {
> USBDevice *dev;
> USBEndpoint *ep;
> uint32_t i, len, pid, dir, devaddr, endp;
> - uint32_t pg, off, ptr1, ptr2, max, mult;
> + uint32_t pg, off, max, mult;
> + uint64_t ptr1, ptr2;
>
> ehci->periodic_sched_active = PERIODIC_ACTIVE;
>
> @@ -1528,7 +1529,7 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async)
> EHCIqh qh;
> int i = 0;
> int again = 0;
> - uint32_t entry = ehci->asynclistaddr;
> + uint64_t entry = ehci->asynclistaddr;
>
> /* set reclamation flag at start event (4.8.6) */
> if (async) {
> @@ -1578,7 +1579,7 @@ out:
> static int ehci_state_fetchentry(EHCIState *ehci, int async)
> {
> int again = 0;
> - uint32_t entry = ehci_get_fetch_addr(ehci, async);
> + uint64_t entry = ehci_get_fetch_addr(ehci, async);
>
> if (NLPTR_TBIT(entry)) {
> ehci_set_state(ehci, async, EST_ACTIVE);
> @@ -1610,8 +1611,10 @@ static int ehci_state_fetchentry(EHCIState *ehci, int async)
>
> default:
> /* TODO: handle FSTN type */
> - qemu_log_mask(LOG_GUEST_ERROR, "FETCHENTRY: entry at %X is of type %u "
> - "which is not supported yet\n", entry, NLPTR_TYPE_GET(entry));
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "FETCHENTRY: entry at %" PRIx64 "is of type %" PRIu64
> + "which is not supported yet\n",
> + entry, NLPTR_TYPE_GET(entry));
> return -1;
> }
>
> @@ -1621,7 +1624,7 @@ out:
>
> static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
> {
> - uint32_t entry;
> + uint64_t entry;
> EHCIQueue *q;
> EHCIqh qh;
>
> @@ -1710,7 +1713,7 @@ out:
>
> static int ehci_state_fetchitd(EHCIState *ehci, int async)
> {
> - uint32_t entry;
> + uint64_t entry;
> EHCIitd itd;
>
> assert(!async);
> @@ -1736,7 +1739,7 @@ static int ehci_state_fetchitd(EHCIState *ehci, int async)
>
> static int ehci_state_fetchsitd(EHCIState *ehci, int async)
> {
> - uint32_t entry;
> + uint64_t entry;
> EHCIsitd sitd;
>
> assert(!async);
> @@ -1794,7 +1797,7 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
> EHCIqtd qtd;
> EHCIPacket *p;
> int again = 1;
> - uint32_t addr;
> + uint64_t addr;
>
> addr = NLPTR_GET(q->qtdaddr);
> if (get_dwords(q->ehci, addr + 8, &qtd.token, 1) < 0) {
> @@ -1877,7 +1880,7 @@ static int ehci_fill_queue(EHCIPacket *p)
> USBEndpoint *ep = p->packet.ep;
> EHCIQueue *q = p->queue;
> EHCIqtd qtd = p->qtd;
> - uint32_t qtdaddr;
> + uint64_t qtdaddr;
>
> for (;;) {
> if (NLPTR_TBIT(qtd.next) != 0) {
> @@ -2000,7 +2003,8 @@ static int ehci_state_executing(EHCIQueue *q)
> static int ehci_state_writeback(EHCIQueue *q)
> {
> EHCIPacket *p = QTAILQ_FIRST(&q->packets);
> - uint32_t *qtd, addr;
> + uint32_t *qtd;
> + uint64_t addr;
> int again = 0;
>
> /* Write back the QTD from the QH area */
> @@ -2441,6 +2445,11 @@ static int usb_ehci_post_load(void *opaque, int version_id)
> }
> }
>
> + if (version_id < 3) {
> + s->a_fetch_addr = s->a_fetch_addr_pre_v3;
> + s->p_fetch_addr = s->p_fetch_addr_pre_v3;
> + }
> +
> return 0;
> }
>
> @@ -2470,9 +2479,14 @@ static void usb_ehci_vm_state_change(void *opaque, bool running, RunState state)
> }
> }
>
> +static bool ehci_core_is_before_version_3(void *opaque, int version_id)
> +{
> + return version_id < 3;
> +}
> +
> const VMStateDescription vmstate_ehci = {
> .name = "ehci-core",
> - .version_id = 2,
> + .version_id = 3,
> .minimum_version_id = 1,
> .pre_save = usb_ehci_pre_save,
> .post_load = usb_ehci_post_load,
> @@ -2501,8 +2515,12 @@ const VMStateDescription vmstate_ehci = {
> /* schedule state */
> VMSTATE_UINT32(astate, EHCIState),
> VMSTATE_UINT32(pstate, EHCIState),
> - VMSTATE_UINT32(a_fetch_addr, EHCIState),
> - VMSTATE_UINT32(p_fetch_addr, EHCIState),
> + VMSTATE_UINT32_TEST(a_fetch_addr_pre_v3, EHCIState,
> + ehci_core_is_before_version_3),
> + VMSTATE_UINT32_TEST(p_fetch_addr_pre_v3, EHCIState,
> + ehci_core_is_before_version_3),
> + VMSTATE_UINT64_V(a_fetch_addr, EHCIState, 3),
> + VMSTATE_UINT64_V(p_fetch_addr, EHCIState, 3),
> VMSTATE_END_OF_LIST()
> }
> };
> diff --git a/hw/usb/trace-events b/hw/usb/trace-events
> index 0d4318dcf1..8c90688bb3 100644
> --- a/hw/usb/trace-events
> +++ b/hw/usb/trace-events
> @@ -86,15 +86,15 @@ usb_ehci_portsc_write(uint32_t addr, uint32_t port, uint32_t val) "wr mmio 0x%04
> usb_ehci_portsc_change(uint32_t addr, uint32_t port, uint32_t new, uint32_t old) "ch mmio 0x%04x [port %d] = 0x%x (old: 0x%x)"
> usb_ehci_usbsts(const char *sts, int state) "usbsts %s %d"
> usb_ehci_state(const char *schedule, const char *state) "%s schedule %s"
> -usb_ehci_qh_ptrs(void *q, uint32_t addr, uint32_t nxt, uint32_t c_qtd, uint32_t n_qtd, uint32_t a_qtd) "q %p - QH @ 0x%08x: next 0x%08x qtds 0x%08x,0x%08x,0x%08x"
> -usb_ehci_qh_fields(uint32_t addr, int rl, int mplen, int eps, int ep, int devaddr) "QH @ 0x%08x - rl %d, mplen %d, eps %d, ep %d, dev %d"
> -usb_ehci_qh_bits(uint32_t addr, int c, int h, int dtc, int i) "QH @ 0x%08x - c %d, h %d, dtc %d, i %d"
> +usb_ehci_qh_ptrs(void *q, uint64_t addr, uint32_t nxt, uint32_t c_qtd, uint32_t n_qtd, uint32_t a_qtd) "q %p - QH @ 0x%" PRIx64 ": next 0x%08x qtds 0x%08x,0x%08x,0x%08x"
> +usb_ehci_qh_fields(uint64_t addr, int rl, int mplen, int eps, int ep, int devaddr) "QH @ 0x%" PRIx64 " - rl %d, mplen %d, eps %d, ep %d, dev %d"
> +usb_ehci_qh_bits(uint64_t addr, int c, int h, int dtc, int i) "QH @ 0x%" PRIx64 " - c %d, h %d, dtc %d, i %d"
> usb_ehci_qh_tbytes(uint32_t tbytes) "updating tbytes to %d"
> -usb_ehci_qtd_ptrs(void *q, uint32_t addr, uint32_t nxt, uint32_t altnext) "q %p - QTD @ 0x%08x: next 0x%08x altnext 0x%08x"
> -usb_ehci_qtd_fields(uint32_t addr, int tbytes, int cpage, int cerr, int pid) "QTD @ 0x%08x - tbytes %d, cpage %d, cerr %d, pid %d"
> -usb_ehci_qtd_bits(uint32_t addr, int ioc, int active, int halt, int babble, int xacterr) "QTD @ 0x%08x - ioc %d, active %d, halt %d, babble %d, xacterr %d"
> -usb_ehci_itd(uint32_t addr, uint32_t nxt, uint32_t mplen, uint32_t mult, uint32_t ep, uint32_t devaddr) "ITD @ 0x%08x: next 0x%08x - mplen %d, mult %d, ep %d, dev %d"
> -usb_ehci_sitd(uint32_t addr, uint32_t nxt, uint32_t active) "ITD @ 0x%08x: next 0x%08x - active %d"
> +usb_ehci_qtd_ptrs(void *q, uint64_t addr, uint32_t nxt, uint32_t altnext) "q %p - QTD @ 0x%" PRIx64 ": next 0x%08x altnext 0x%08x"
> +usb_ehci_qtd_fields(uint64_t addr, int tbytes, int cpage, int cerr, int pid) "QTD @ 0x%" PRIx64 " - tbytes %d, cpage %d, cerr %d, pid %d"
> +usb_ehci_qtd_bits(uint64_t addr, int ioc, int active, int halt, int babble, int xacterr) "QTD @ 0x%" PRIx64 " - ioc %d, active %d, halt %d, babble %d, xacterr %d"
> +usb_ehci_itd(uint64_t addr, uint32_t nxt, uint32_t mplen, uint32_t mult, uint32_t ep, uint32_t devaddr) "ITD @ 0x%" PRIx64 ": next 0x%08x - mplen %d, mult %d, ep %d, dev %d"
> +usb_ehci_sitd(uint64_t addr, uint32_t nxt, uint32_t active) "SITD @ 0x%" PRIx64 ": next 0x%08x - active %d"
> usb_ehci_port_attach(uint32_t port, const char *owner, const char *device) "attach port #%d, owner %s, device %s"
> usb_ehci_port_detach(uint32_t port, const char *owner) "detach port #%d, owner %s"
> usb_ehci_port_reset(uint32_t port, int enable) "reset port #%d - %d"
> @@ -104,15 +104,15 @@ usb_ehci_port_resume(uint32_t port) "port #%d"
> usb_ehci_port_disable(uint32_t port) "port #%d"
> usb_ehci_queue_action(void *q, const char *action) "q %p: %s"
> usb_ehci_packet_action(void *q, void *p, const char *action) "q %p p %p: %s"
> -usb_ehci_packet_submit(uint32_t qhaddr, uint32_t next, uint32_t qtdaddr, int pid, size_t len, int endp, int status, int actual_length) "qh=0x%x, next=0x%x, qtd=0x%x, pid=0x%x, len=%zd, endp=0x%x, status=%d, actual_length=%d"
> +usb_ehci_packet_submit(uint64_t qhaddr, uint32_t next, uint64_t qtdaddr, int pid, size_t len, int endp, int status, int actual_length) "qh=0x%" PRIx64 ", next=0x%x, qtd=0x%" PRIx64 ", pid=0x%x, len=%zd, endp=0x%x, status=%d, actual_length=%d"
> usb_ehci_irq(uint32_t level, uint32_t frindex, uint32_t sts, uint32_t mask) "level %d, frindex 0x%04x, sts 0x%x, mask 0x%x"
> usb_ehci_guest_bug(const char *reason) "%s"
> usb_ehci_doorbell_ring(void) ""
> usb_ehci_doorbell_ack(void) ""
> usb_ehci_dma_error(void) ""
> -usb_ehci_execute_complete(uint32_t qhaddr, uint32_t next, uint32_t qtdaddr, int status, int actual_length) "qhaddr=0x%x, next=0x%x, qtdaddr=0x%x, status=%d, actual_length=%d"
> -usb_ehci_fetchqh_reclaim_done(uint32_t qhaddr) "QH 0x%08x H-bit set, reclamation status reset - done processing"
> -usb_ehci_fetchqh_dbg(uint32_t qhaddr, uint32_t h, uint32_t halt, uint32_t active, uint32_t next) "QH 0x%08x (h 0x%x halt 0x%x active 0x%x) next 0x%08x"
> +usb_ehci_execute_complete(uint64_t qhaddr, uint32_t next, uint64_t qtdaddr, int status, int actual_length) "qhaddr=0x%" PRIx64 ", next=0x%x, qtdaddr=0x%" PRIx64 ", status=%d, actual_length=%d"
> +usb_ehci_fetchqh_reclaim_done(uint64_t qhaddr) "QH 0x%" PRIx64 " H-bit set, reclamation status reset - done processing"
> +usb_ehci_fetchqh_dbg(uint64_t qhaddr, uint32_t h, uint32_t halt, uint32_t active, uint32_t next) "QH 0x%" PRIx64 " (h 0x%x halt 0x%x active 0x%x) next 0x%08x"
> usb_ehci_periodic_state_advance(uint32_t frame, uint32_t list, uint32_t entry) "frame=%d, list=0x%x, entry=0x%x"
> usb_ehci_skipped_uframes(uint64_t skipped_uframes) "skipped %" PRIu64 " uframes"
> usb_ehci_log(const char *msg) "%s"
^ permalink raw reply [flat|nested] 69+ messages in thread
* RE: [PATCH v3 09/17] hw/usb/hcd-ehci: Implement 64-bit QH descriptor addressing
2026-04-17 6:14 ` Philippe Mathieu-Daudé
@ 2026-04-17 7:02 ` Jamin Lin
0 siblings, 0 replies; 69+ messages in thread
From: Jamin Lin @ 2026-04-17 7:02 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
Hi Philippe,
> Subject: Re: [PATCH v3 09/17] hw/usb/hcd-ehci: Implement 64-bit QH
> descriptor addressing
>
> On 17/4/26 07:40, Jamin Lin wrote:
> > Hi Philippe,
> >
> >> Subject: Re: [PATCH v3 09/17] hw/usb/hcd-ehci: Implement 64-bit QH
> >> descriptor addressing
> >>
> >> On 16/4/26 03:49, Jamin Lin wrote:
> >>> EHCI supports 64-bit control data structure addressing when the
> >>> 64-bit Addressing Capability bit in HCCPARAMS is set. In that mode,
> >>> the CTRLDSSEGMENT register supplies the upper 32 bits which are
> >>> concatenated with 32-bit link pointer fields to form full 64-bit
> >>> descriptor addresses (EHCI 1.0, section 2.3.5 and Appendix B).
> >>>
> >>> The current implementation assumes 32-bit QH descriptor addresses
> >>> and directly uses link pointer values without applying the
> >>> CTRLDSSEGMENT upper dword.
> >>>
> >>> Introduce a helper, ehci_get_desc_addr(), to construct full 64-bit
> >>> descriptor addresses when 64-bit capability is enabled. Update QH
> >>> traversal paths (async list walk, horizontal QH link, and periodic
> >>> schedule entry handling) to use the translated 64-bit addresses.
> >>>
> >>> EHCI 64-bit buffer pointer fields are defined in Appendix B as split
> >>> 32-bit low/high parts located at separate offsets, rather than a
> >>> single contiguous 64-bit field. Therefore, the buffer pointers
> >>> cannot be represented as uint64_t bufptr[5] without violating the
> >>> descriptor layout defined by the specification.
> >>>
> >>> Introduce ehci_get_buf_addr() to construct full 64-bit buffer
> >>> addresses from bufptr[] and bufptr_hi[] fields. Use this helper when
> >>> calculating transfer buffer addresses so that data buffers above 4GB
> >>> are correctly handled.
> >>>
> >>> Also add bufptr_hi[5] to EHCIqh to support 64-bit buffer pointer
> >>> fields as defined in Appendix B.
> >>>
> >>> When 64-bit capability is disabled, descriptor addresses remain
> >>> 32-bit and existing behaviour is unchanged.
> >>>
> >>> Note: Similar split 64-bit buffer pointer handling is required for
> >>> qTD, iTD and siTD descriptors, which will be addressed in follow-up
> >>> changes.
> >>>
> >>> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> >>> ---
> >>> hw/usb/hcd-ehci.h | 4 ++++
> >>> hw/usb/hcd-ehci.c | 48
> >> ++++++++++++++++++++++++++++++++++-----------
> >>> hw/usb/trace-events | 2 +-
> >>> 3 files changed, 42 insertions(+), 12 deletions(-)
>
>
> >>> +static uint64_t ehci_get_buf_addr(EHCIState *s, uint32_t hi, uint32_t low,
> >>> + uint32_t mask)
> >>
> >> Rename @mask as @low_mask? Or directly use 64-bit?
> >>
> >> static uint64_t ehci_get_buf_addr(const EHCIState *s,
> >> uint32_t hi, uint32_t lo,
> >> uint64_t mask) {
> >> uint64_t addr = s->caps_64bit_addr ? deposit64(lo, 0, 32, hi):
> >> lo;
> >>
> >> return addr & mask;
> >> }
> >>
> > Thanks for the review and suggestion.
> >
> > In the current code, the mask (e.g. QTD_BUFPTR_MASK) is defined as a
> 32-bit value and is intended to apply only to the low 32 bits of the buffer
> pointer.
> > If we change the function to take a 64-bit mask and apply it to the
> > full 64-bit address (as in the proposed version), the upper 32 bits (bits 63–32)
> may be unintentionally cleared when the mask is only 32-bit wide.
>
> Right.
>
> >
> > For example:
> >
> > #define QTD_BUFPTR_MASK 0xfffff000
> >
> > In this case, applying "addr & mask" after combining hi/lo would zero out the
> high 32 bits, which breaks 64-bit addressing.
> > To preserve the original semantics, the mask should only be applied to the
> low part before combining with the high 32 bits.
> > So I suggest renaming the parameter to make this explicit. I will change this
> function as below. What do you think?
> >
> > static uint64_t ehci_get_buf_addr(
>
> "const"
>
Thanks for the suggestion.
Will add.
Jamin
> EHCIState *s, uint32_t hi, uint32_t lo,
> > uint32_t lo_mask) {
> > uint64_t addr = lo & lo_mask;
> >
> > if (s->caps_64bit_addr) {
> > addr = deposit64(addr, 32, 32, hi);
> > }
> >
> > return addr;
> > }
> Perfect, using "const":
>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 13/17] hw/usb/hcd-ehci: Add descriptor address offset property
2026-04-17 6:45 ` Cédric Le Goater
@ 2026-04-17 7:08 ` Philippe Mathieu-Daudé
2026-04-20 5:47 ` Jamin Lin
0 siblings, 1 reply; 69+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-17 7:08 UTC (permalink / raw)
To: Cédric Le Goater, Jamin Lin, Peter Maydell, Steven Lee,
Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
On 17/4/26 08:45, Cédric Le Goater wrote:
> On 4/16/26 03:49, Jamin Lin wrote:
>> When 64-bit addressing is supported, the Linux EHCI driver programs the
>> segment register to zero. See ehci_run function:
>> https://github.com/torvalds/linux/blob/master/drivers/usb/host/ehci-hcd.c
>>
>> The driver comment also notes that descriptor structures allocated from
>> the DMA pool use segment zero semantics.
>>
>> Descriptor memory is allocated using the DMA API. The platform driver
>> configures a 64-bit DMA mask so memory can be allocated above 4GB.
>> See ehci_platform_probe function:
>> https://github.com/torvalds/linux/blob/master/drivers/usb/host/ehci-
>> platform.c
>>
>> On AST2700 platforms, system DRAM is mapped above 4GB at 0x400000000.
>> As a result, descriptor addresses constructed directly from the guest
>> EHCI registers do not match the actual system address used by the
>> controller when fetching queue heads (QH) and queue element transfer
>> descriptors (qTD).
>>
>> Introduce a descriptor-addr-offset property so platforms can provide an
>> address offset applied when constructing descriptor addresses. This
>> allows systems where DRAM resides above 4GB to correctly access EHCI
>> descriptors while keeping the default behavior unchanged for existing
>> machines.
>>
>> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
>> ---
>> hw/usb/hcd-ehci.h | 1 +
>> hw/usb/hcd-ehci-pci.c | 2 ++
>> hw/usb/hcd-ehci-sysbus.c | 2 ++
>> hw/usb/hcd-ehci.c | 7 ++++++-
>> 4 files changed, 11 insertions(+), 1 deletion(-)
>> diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
>> index e1d5ecbad7..ea9d5846bc 100644
>> --- a/hw/usb/hcd-ehci.c
>> +++ b/hw/usb/hcd-ehci.c
>> @@ -162,7 +162,12 @@ static uint64_t ehci_get_buf_addr(EHCIState *s,
>> uint32_t hi, uint32_t low,
>> static uint64_t ehci_get_desc_addr(EHCIState *s, uint32_t low)
>> {
>> - return ehci_get_buf_addr(s, s->ctrldssegment, low, UINT32_MAX);
>> + uint64_t addr;
>> +
>> + addr = ehci_get_buf_addr(s, s->ctrldssegment, low, UINT32_MAX);
>> + addr += s->descriptor_addr_offset;
>
>
> Instead, can we force a default value for ctrldssegment when
> caps_64bit_addr is set ?
>
> I am still trying to digest :
>
> https://lore.kernel.org/qemu-devel/
> TYPPR06MB8206C7461E004C4FF07B8E92FC242@TYPPR06MB8206.apcprd06.prod.outlook.com/
Same here, but since it doesn't break and I don't have much more time
to dedicate to this I ended thinking "good enough for now, could be
improved later", so no objection on my side.
>
> We have time let's take a moment to think about the workaround.
Then keep me in the loop!
^ permalink raw reply [flat|nested] 69+ messages in thread
* RE: [PATCH v3 16/17] tests/functional/arm/test_aspeed_ast2600_sdk: Add USB EHCI test for AST2600 SDK
2026-04-17 6:27 ` Philippe Mathieu-Daudé
@ 2026-04-17 7:40 ` Jamin Lin
2026-04-17 8:44 ` Philippe Mathieu-Daudé
0 siblings, 1 reply; 69+ messages in thread
From: Jamin Lin @ 2026-04-17 7:40 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
Hi Philippe
> Subject: Re: [PATCH v3 16/17] tests/functional/arm/test_aspeed_ast2600_sdk:
> Add USB EHCI test for AST2600 SDK
>
> On 16/4/26 03:50, Jamin Lin wrote:
> > Add a functional test to verify USB EHCI support on the AST2600 SDK
> > machine by attaching a USB keyboard device and checking its
> > enumeration via lsusb.
> >
> > This introduces a helper routine that runs lsusb in the guest and
> > validates that the emulated "QEMU USB Keyboard" is detected.
> >
> > Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> > ---
> > tests/functional/arm/test_aspeed_ast2600_sdk.py | 7 +++++++
> > 1 file changed, 7 insertions(+)
>
> This should be patch #1 :)
>
This patch series updates the USB EHCI model to support 64-bit.
I added a functional test (AST2600) to ensure that these changes do not impact the existing 32-bit support.
For this reason, I placed this patch in the current order.
If you still think the patch order should be adjusted, please let me know.
Thanks,
Jamin
> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 69+ messages in thread
* RE: [PATCH v3 12/17] hw/usb/hcd-ehci: Implement 64-bit siTD descriptor addressing
2026-04-17 6:27 ` Philippe Mathieu-Daudé
@ 2026-04-17 7:44 ` Jamin Lin
2026-04-17 8:42 ` Philippe Mathieu-Daudé
0 siblings, 1 reply; 69+ messages in thread
From: Jamin Lin @ 2026-04-17 7:44 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
Hi Philippe,
> Subject: Re: [PATCH v3 12/17] hw/usb/hcd-ehci: Implement 64-bit siTD
> descriptor addressing
>
> On 16/4/26 03:49, Jamin Lin wrote:
> > EHCI supports 64-bit control data structure addressing when the 64-bit
> > Addressing Capability bit in HCCPARAMS is set. In that mode, the
> > CTRLDSSEGMENT register provides the upper 32 bits that are
> > concatenated with 32-bit link pointer values to form full 64-bit
> > descriptor addresses (EHCI 1.0, section 2.3.5 and Appendix B).
> >
> > siTD link pointers are stored as 32-bit values and must be expanded to
> > full 64-bit descriptor addresses when 64-bit mode is enabled.
> > Update the siTD traversal path to use ehci_get_desc_addr() when
> > following link pointers.
> >
> > Appendix B also defines high dword fields for siTD buffer pointers.
> > Add bufptr_hi[] fields to EHCIsitd and use ehci_get_buf_addr() to
> > construct full 64-bit buffer addresses from bufptr[] and bufptr_hi[]
> > when processing split isochronous transfers. This allows buffers above
> > 4GB to be handled correctly.
> >
> > When 64-bit capability is disabled, descriptor and buffer addresses
> > remain 32-bit and existing behaviour is unchanged.
> >
> > Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> > ---
> > hw/usb/hcd-ehci.h | 1 +
> > hw/usb/hcd-ehci.c | 2 +-
> > 2 files changed, 2 insertions(+), 1 deletion(-)
> >
> > diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index
> > af8c080c60..6406f536e8 100644
> > --- a/hw/usb/hcd-ehci.h
> > +++ b/hw/usb/hcd-ehci.h
> > @@ -109,6 +109,7 @@ typedef struct EHCIsitd {
> > #define SITD_BUFPTR_TCNT_MASK 0x00000007
> >
> > uint32_t backptr; /* Standard next link pointer
> */
> > + uint32_t bufptr_hi[2];
>
> Not used?
>
Thanks for the review.
Yes, bufptr_hi is not used for siTD. I will remove it.
Thanks,
Jamin
> > } EHCIsitd;
> >
> > /*
> > diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index
> > 3db1c25e4d..e1d5ecbad7 100644
> > --- a/hw/usb/hcd-ehci.c
> > +++ b/hw/usb/hcd-ehci.c
> > @@ -1791,7 +1791,7 @@ static int ehci_state_fetchsitd(EHCIState *ehci, int
> async)
> > warn_report("Skipping active siTD");
> > }
> >
> > - ehci_set_fetch_addr(ehci, async, sitd.next);
> > + ehci_set_fetch_addr(ehci, async, ehci_get_desc_addr(ehci,
> > + sitd.next));
> > ehci_set_state(ehci, async, EST_FETCHENTRY);
> > return 1;
> > }
^ permalink raw reply [flat|nested] 69+ messages in thread
* RE: [PATCH v3 08/17] hw/usb/hcd-ehci: Reject CTRLDSSEGMENT writes without 64-bit capability
2026-04-17 6:33 ` Philippe Mathieu-Daudé
@ 2026-04-17 8:07 ` Jamin Lin
0 siblings, 0 replies; 69+ messages in thread
From: Jamin Lin @ 2026-04-17 8:07 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
Hi Philippe,
> Subject: Re: [PATCH v3 08/17] hw/usb/hcd-ehci: Reject CTRLDSSEGMENT
> writes without 64-bit capability
>
> On 16/4/26 03:49, Jamin Lin wrote:
> > The EHCI CTRLDSSEGMENT register provides the upper 32 bits [63:32]
> > used to form 64-bit addresses for EHCI control data structures. Per
> > EHCI 1.0 spec section 2.3.5, when the HCCPARAMS 64-bit Addressing
> > Capability bit is zero, CTRLDSSEGMENT is not used: software cannot
> > write it and reads must return zero.
> >
> > Add a capability check in the operational register write handler and
> > reject guest writes to CTRLDSSEGMENT when 64-bit addressing is not
> > enabled.
> >
> > Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> > ---
> > hw/usb/hcd-ehci.c | 9 ++++++++-
> > 1 file changed, 8 insertions(+), 1 deletion(-)
> >
> > diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index
> > 6409457186..b9e4251d62 100644
> > --- a/hw/usb/hcd-ehci.c
> > +++ b/hw/usb/hcd-ehci.c
> > @@ -1108,7 +1108,14 @@ static void ehci_opreg_write(void *ptr, hwaddr
> addr,
> > " is enabled and HC is enabled\n");
> > }
> > break;
> > -
> > + case CTRLDSSEGMENT:
> > + if (!s->caps_64bit_addr) {
> > + qemu_log_mask(LOG_GUEST_ERROR,
> > + "ehci: write to CTRLDSSEGMENT while "
> > + " 64-bit addressing capability is
> disabled\n");
> > + return;
> > + }
> > + break;
>
> I'd squash with previous.
Thanks for the review and suggestion.
Will do.
Jamin
^ permalink raw reply [flat|nested] 69+ messages in thread
* RE: [PATCH v3 04/17] hw/usb/hcd-ehci.c: Replace fprintf(stderr, ...) with qemu_log_mask(LOG_GUEST_ERROR)
2026-04-17 6:31 ` Philippe Mathieu-Daudé
@ 2026-04-17 8:41 ` Jamin Lin
0 siblings, 0 replies; 69+ messages in thread
From: Jamin Lin @ 2026-04-17 8:41 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
Hi Philippe,
> Subject: Re: [PATCH v3 04/17] hw/usb/hcd-ehci.c: Replace fprintf(stderr, ...)
> with qemu_log_mask(LOG_GUEST_ERROR)
>
> On 16/4/26 03:49, Jamin Lin wrote:
> > Replace direct fprintf(stderr, ...) calls with qemu_log_mask() using
> > LOG_GUEST_ERROR in the EHCI controller implementation.
> >
> > Direct writes to stderr are discouraged in QEMU as they bypass the
> > logging framework and cannot be filtered or controlled at runtime.
> > Using qemu_log_mask() ensures that guest-visible errors are properly
> > categorized and can be managed via QEMU logging options.
> >
> > All affected messages correspond to guest-triggerable error
> > conditions, so LOG_GUEST_ERROR is used consistently.
> >
> > This change improves integration with QEMU's logging infrastructure
> > and aligns with upstream coding guidelines.
> >
> > Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> > ---
> > hw/usb/hcd-ehci.c | 43 +++++++++++++++++++++++++------------------
> > 1 file changed, 25 insertions(+), 18 deletions(-)
>
>
> > @@ -532,7 +533,7 @@ static void ehci_free_packet(EHCIPacket *p)
> > }
> > if (p->async == EHCI_ASYNC_FINISHED &&
> > p->packet.status == USB_RET_SUCCESS) {
> > - fprintf(stderr,
> > + qemu_log_mask(LOG_GUEST_ERROR,
> > "EHCI: Dropping completed packet from halted %s ep
> %02X\n",
> > (p->pid == USB_TOKEN_IN) ? "in" : "out",
> > get_field(p->queue->qh.epchar, QH_EPCHAR_EP));
> @@
> > -1042,8 +1043,9 @@ static void ehci_opreg_write(void *ptr, hwaddr
> > addr,
> >
> > /* not supporting dynamic frame list size at the moment */
> > if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) {
> > - fprintf(stderr, "attempt to set frame list size -- value %d\n",
> > - (int)val & USBCMD_FLS);
> > + qemu_log_mask(LOG_GUEST_ERROR,
> > + "attempt to set frame list size -- value
> > + %d\n",
>
> PRId64
Will update
>
> > + (int)val & USBCMD_FLS);
> > val &= ~USBCMD_FLS;
> > }
>
> > @@ -1584,7 +1589,8 @@ static int ehci_state_fetchentry(EHCIState
> > *ehci, int async)
> >
> > /* section 4.8, only QH in async schedule */
> > if (async && (NLPTR_TYPE_GET(entry) != NLPTR_TYPE_QH)) {
> > - fprintf(stderr, "non queue head request in async schedule\n");
> > + qemu_log_mask(LOG_GUEST_ERROR,
> > + "non queue head request in async schedule\n");
> > return -1;
> > }
> >
> > @@ -1606,7 +1612,7 @@ static int ehci_state_fetchentry(EHCIState
> > *ehci, int async)
> >
> > default:
> > /* TODO: handle FSTN type */
> > - fprintf(stderr, "FETCHENTRY: entry at %X is of type %u "
> > + qemu_log_mask(LOG_GUEST_ERROR, "FETCHENTRY: entry at %X
> is of type %u "
>
> "0x%x"
Will update
>
> > "which is not supported yet\n", entry,
> NLPTR_TYPE_GET(entry));
> > return -1;
> > }
> > @@ -2112,13 +2118,14 @@ static void ehci_advance_state(EHCIState *ehci,
> int async)
> > break;
> >
> > default:
> > - fprintf(stderr, "Bad state!\n");
> > + qemu_log_mask(LOG_GUEST_ERROR, "Bad state!\n");
>
> Just remove for "bad state" entries?
>
Will remove it.
> > g_assert_not_reached();
> > }
> >
> > if (again < 0 || itd_count > 16) {
> > /* TODO: notify guest (raise HSE irq?) */
> > - fprintf(stderr, "processing error - resetting ehci HC\n");
> > + qemu_log_mask(LOG_GUEST_ERROR,
> > + "processing error - resetting ehci HC\n");
> > ehci_reset(ehci);
> > again = 0;
> > }
> > @@ -2175,7 +2182,7 @@ static void ehci_advance_async_state(EHCIState
> > *ehci)
> >
> > default:
> > /* this should only be due to a developer mistake */
> > - fprintf(stderr, "ehci: Bad asynchronous state %d. "
> > + qemu_log_mask(LOG_GUEST_ERROR, "ehci: Bad asynchronous
> state %d. "
> > "Resetting to active\n", ehci->astate);
>
> Ditto.
>
Will remove it.
> > g_assert_not_reached();
> > }
> > @@ -2225,7 +2232,7 @@ static void
> > ehci_advance_periodic_state(EHCIState *ehci)
> >
> > default:
> > /* this should only be due to a developer mistake */
> > - fprintf(stderr, "ehci: Bad periodic state %d. "
> > + qemu_log_mask(LOG_GUEST_ERROR, "ehci: Bad periodic state
> %d. "
> > "Resetting to active\n", ehci->pstate);
> > g_assert_not_reached();
>
> Ditto.
>
Will remove it.
Thanks for the review and suggestion
Jamin
> > }
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 12/17] hw/usb/hcd-ehci: Implement 64-bit siTD descriptor addressing
2026-04-17 7:44 ` Jamin Lin
@ 2026-04-17 8:42 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 69+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-17 8:42 UTC (permalink / raw)
To: Jamin Lin, Cédric Le Goater, Peter Maydell, Steven Lee,
Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
On 17/4/26 09:44, Jamin Lin wrote:
> Hi Philippe,
>
>> Subject: Re: [PATCH v3 12/17] hw/usb/hcd-ehci: Implement 64-bit siTD
>> descriptor addressing
>>
>> On 16/4/26 03:49, Jamin Lin wrote:
>>> EHCI supports 64-bit control data structure addressing when the 64-bit
>>> Addressing Capability bit in HCCPARAMS is set. In that mode, the
>>> CTRLDSSEGMENT register provides the upper 32 bits that are
>>> concatenated with 32-bit link pointer values to form full 64-bit
>>> descriptor addresses (EHCI 1.0, section 2.3.5 and Appendix B).
>>>
>>> siTD link pointers are stored as 32-bit values and must be expanded to
>>> full 64-bit descriptor addresses when 64-bit mode is enabled.
>>> Update the siTD traversal path to use ehci_get_desc_addr() when
>>> following link pointers.
>>>
>>> Appendix B also defines high dword fields for siTD buffer pointers.
>>> Add bufptr_hi[] fields to EHCIsitd and use ehci_get_buf_addr() to
>>> construct full 64-bit buffer addresses from bufptr[] and bufptr_hi[]
>>> when processing split isochronous transfers. This allows buffers above
>>> 4GB to be handled correctly.
>>>
>>> When 64-bit capability is disabled, descriptor and buffer addresses
>>> remain 32-bit and existing behaviour is unchanged.
>>>
>>> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
>>> ---
>>> hw/usb/hcd-ehci.h | 1 +
>>> hw/usb/hcd-ehci.c | 2 +-
>>> 2 files changed, 2 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index
>>> af8c080c60..6406f536e8 100644
>>> --- a/hw/usb/hcd-ehci.h
>>> +++ b/hw/usb/hcd-ehci.h
>>> @@ -109,6 +109,7 @@ typedef struct EHCIsitd {
>>> #define SITD_BUFPTR_TCNT_MASK 0x00000007
>>>
>>> uint32_t backptr; /* Standard next link pointer
>> */
>>> + uint32_t bufptr_hi[2];
>>
>> Not used?
>>
>
> Thanks for the review.
> Yes, bufptr_hi is not used for siTD. I will remove it.
With it removed:
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 16/17] tests/functional/arm/test_aspeed_ast2600_sdk: Add USB EHCI test for AST2600 SDK
2026-04-17 7:40 ` Jamin Lin
@ 2026-04-17 8:44 ` Philippe Mathieu-Daudé
2026-04-17 8:50 ` Jamin Lin
0 siblings, 1 reply; 69+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-17 8:44 UTC (permalink / raw)
To: Jamin Lin, Cédric Le Goater, Peter Maydell, Steven Lee,
Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
On 17/4/26 09:40, Jamin Lin wrote:
> Hi Philippe
>
>> Subject: Re: [PATCH v3 16/17] tests/functional/arm/test_aspeed_ast2600_sdk:
>> Add USB EHCI test for AST2600 SDK
>>
>> On 16/4/26 03:50, Jamin Lin wrote:
>>> Add a functional test to verify USB EHCI support on the AST2600 SDK
>>> machine by attaching a USB keyboard device and checking its
>>> enumeration via lsusb.
>>>
>>> This introduces a helper routine that runs lsusb in the guest and
>>> validates that the emulated "QEMU USB Keyboard" is detected.
>>>
>>> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
>>> ---
>>> tests/functional/arm/test_aspeed_ast2600_sdk.py | 7 +++++++
>>> 1 file changed, 7 insertions(+)
>>
>> This should be patch #1 :)
>>
>
> This patch series updates the USB EHCI model to support 64-bit.
>
> I added a functional test (AST2600) to ensure that these changes do not impact the existing 32-bit support.
This is also my understanding, first add the AST2600 test to ensure
we do not break anything while implementing 64-bit desc addressing.
> For this reason, I placed this patch in the current order.
> If you still think the patch order should be adjusted, please let me know.
>
> Thanks,
> Jamin
>
>> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 69+ messages in thread
* RE: [PATCH v3 16/17] tests/functional/arm/test_aspeed_ast2600_sdk: Add USB EHCI test for AST2600 SDK
2026-04-17 8:44 ` Philippe Mathieu-Daudé
@ 2026-04-17 8:50 ` Jamin Lin
0 siblings, 0 replies; 69+ messages in thread
From: Jamin Lin @ 2026-04-17 8:50 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
Hi Philippe
> Subject: Re: [PATCH v3 16/17] tests/functional/arm/test_aspeed_ast2600_sdk:
> Add USB EHCI test for AST2600 SDK
>
> On 17/4/26 09:40, Jamin Lin wrote:
> > Hi Philippe
> >
> >> Subject: Re: [PATCH v3 16/17]
> tests/functional/arm/test_aspeed_ast2600_sdk:
> >> Add USB EHCI test for AST2600 SDK
> >>
> >> On 16/4/26 03:50, Jamin Lin wrote:
> >>> Add a functional test to verify USB EHCI support on the AST2600 SDK
> >>> machine by attaching a USB keyboard device and checking its
> >>> enumeration via lsusb.
> >>>
> >>> This introduces a helper routine that runs lsusb in the guest and
> >>> validates that the emulated "QEMU USB Keyboard" is detected.
> >>>
> >>> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> >>> ---
> >>> tests/functional/arm/test_aspeed_ast2600_sdk.py | 7 +++++++
> >>> 1 file changed, 7 insertions(+)
> >>
> >> This should be patch #1 :)
> >>
> >
> > This patch series updates the USB EHCI model to support 64-bit.
> >
> > I added a functional test (AST2600) to ensure that these changes do not
> impact the existing 32-bit support.
>
> This is also my understanding, first add the AST2600 test to ensure we do not
> break anything while implementing 64-bit desc addressing.
>
Thanks for the suggestion.
I will move this patch before the 64-bit descriptor addressing changes.
> > For this reason, I placed this patch in the current order.
> > If you still think the patch order should be adjusted, please let me know.
> >
> > Thanks,
> > Jamin
> >
> >> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 69+ messages in thread
* RE: [PATCH v3 01/17] hw/usb/hcd-ehci: Remove unused EHCIfstn structure and dead code
2026-04-17 2:25 ` Jamin Lin
@ 2026-04-17 9:47 ` BALATON Zoltan
2026-04-20 3:46 ` Jamin Lin
0 siblings, 1 reply; 69+ messages in thread
From: BALATON Zoltan @ 2026-04-17 9:47 UTC (permalink / raw)
To: Jamin Lin
Cc: philmd@linaro.org, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here, Troy Lee,
flwu@google.com, nabihestefan@google.com
On Fri, 17 Apr 2026, Jamin Lin wrote:
> Hi all,
>
>> Subject: RE: [PATCH v3 01/17] hw/usb/hcd-ehci: Remove unused EHCIfstn
>> structure and dead code
>>
>> Hi all,
>>
>>> Subject: Re: [PATCH v3 01/17] hw/usb/hcd-ehci: Remove unused EHCIfstn
>>> structure and dead code
>>>
>>> On Thu, 16 Apr 2026, Jamin Lin wrote:
>>>> The EHCIfstn structure, defined according to EHCI spec section 3.7,
>>>> is currently unused in the EHCI implementation. Remove it to reduce
>>>> unused code and improve maintainability.
>>>>
>>>> Additionally, drop a block of disabled (#if 0) code in
>>>> ehci_state_advqueue() that was never implemented. This code path is
>>>> incomplete and has no functional impact.
>>>>
>>>> No functional change.
>>>>
>>>> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
>>>> ---
>>>> hw/usb/hcd-ehci.h | 7 -------
>>>> hw/usb/hcd-ehci.c | 11 -----------
>>>> 2 files changed, 18 deletions(-)
>>>>
>>>> diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index
>>>> 0ae8c06331..3aec0e047c 100644
>>>> --- a/hw/usb/hcd-ehci.h
>>>> +++ b/hw/usb/hcd-ehci.h
>>>> @@ -202,13 +202,6 @@ typedef struct EHCIqh {
>>>> #define BUFPTR_SBYTES_SH 5
>>>> } EHCIqh;
>>>>
>>>> -/* EHCI spec version 1.0 Section 3.7
>>>> - */
>>>> -typedef struct EHCIfstn {
>>>> - uint32_t next; /* Standard next link pointer
>> */
>>>> - uint32_t backptr; /* Standard next link pointer */
>>>> -} EHCIfstn;
>>>> -
>>>> enum async_state {
>>>> EHCI_ASYNC_NONE = 0,
>>>> EHCI_ASYNC_INITIALIZED,
>>>> diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index
>>>> 57f930b099..5ea8461f70 100644
>>>> --- a/hw/usb/hcd-ehci.c
>>>> +++ b/hw/usb/hcd-ehci.c
>>>> @@ -1756,17 +1756,6 @@ static int ehci_state_fetchsitd(EHCIState
>>>> *ehci, int async)
>>>> /* Section 4.10.2 - paragraph 3 */
>>>> static int ehci_state_advqueue(EHCIQueue *q) { -#if 0
>>>> - /* TO-DO: 4.10.2 - paragraph 2
>>>> - * if I-bit is set to 1 and QH is not active
>>>> - * go to horizontal QH
>>>> - */
>>>
>>> Is it worth to keep the comment in case it's still valid to remind we
>>> have something missing here?
>>>
>>> Regards,
>>> BALATON Zoltan
>>>
>>
>> If we decide to keep these comments as reminders for unimplemented parts,
>> please let me know. I will resend the patch series and drop this patch.
>>
>> Thanks,
>> Jamin
>>
>
> Another approach:
> We can remove the #if 0 dead code and keep only the comments as a reminder that this part is not yet implemented.
>
> Ex:
> --- a/hw/usb/hcd-ehci.c
> +++ b/hw/usb/hcd-ehci.c
> @@ -1756,16 +1756,10 @@ static int ehci_state_fetchsitd(EHCIState *ehci, int async)
> /* Section 4.10.2 - paragraph 3 */
> static int ehci_state_advqueue(EHCIQueue *q)
> {
> -#if 0
> /* TO-DO: 4.10.2 - paragraph 2
> * if I-bit is set to 1 and QH is not active
> * go to horizontal QH
> */
> - if (I-bit set) {
> - ehci_set_state(ehci, async, EST_HORIZONTALQH);
> - goto out;
> - }
>
> Thanks,
> Jamin
That's what I meant to leave the comment but OK the remove ineffective
code.
Regards,
BALATON Zoltan
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 06/17] hw/usb/hcd-ehci: Change descriptor addresses to 64-bit
2026-04-17 7:01 ` Cédric Le Goater
@ 2026-04-17 15:10 ` Peter Xu
2026-04-20 5:56 ` Jamin Lin
0 siblings, 1 reply; 69+ messages in thread
From: Peter Xu @ 2026-04-17 15:10 UTC (permalink / raw)
To: Cédric Le Goater
Cc: Jamin Lin, philmd@linaro.org, Peter Maydell, Steven Lee, Troy Lee,
Kane Chen, Andrew Jeffery, Joel Stanley, open list:ASPEED BMCs,
open list:All patches CC here, Troy Lee, flwu@google.com,
nabihestefan@google.com, Fabiano Rosas
On Fri, Apr 17, 2026 at 09:01:34AM +0200, Cédric Le Goater wrote:
> + Peter, Fabiano,
>
> On 4/16/26 03:49, Jamin Lin wrote:
> > Change internal EHCI descriptor addresses from uint32_t to uint64_t.
> >
> > The following fields are updated:
> > - EHCIPacket::qtdaddr
> > - EHCIQueue::{qhaddr, qtdaddr}
> > - EHCIState::{a_fetch_addr, p_fetch_addr}
> >
> > Update get_dwords() and put_dwords() to take 64-bit addresses and
> > propagate the type change through the descriptor traversal paths.
> >
> > Adjust NLPTR_GET() to operate on 64-bit values:
> >
> > #define NLPTR_GET(x) ((x) & ~0x1fULL)
> >
> > so that link pointer masking works correctly when descriptor
> > addresses exceed 32-bit space. The previous mask (0xffffffe0)
> > implicitly truncated addresses to 32 bits.
> >
> > This patch does not change the on-wire descriptor layout yet.
> > It only removes the internal 32-bit address limit and prepares
> > for later patches that will add full 64-bit QH/qTD/iTD/siTD support.
> >
> > Update the EHCI trace-events prototypes for QH, qTD, iTD, and siTD to
> > use uint64_t for the address argument and print it with PRIx64. This
> > ensures full 64-bit addresses are shown in trace output and improves
> > debugging of queue heads and transfer descriptors.
> >
> > Migration compatibility:
> >
> > The fetch address fields in EHCIState are extended from 32-bit to
> > 64-bit, requiring a VMState version bump (v2 -> v3).
> >
> > Backward compatibility is preserved by keeping the legacy 32-bit
> > fields (a_fetch_addr_pre_v3, p_fetch_addr_pre_v3) for pre-v3
> > migration streams via VMSTATE_UINT32_TEST(), and introducing new
> > 64-bit fields for v3+.
> >
> > In post_load, pre-v3 state is promoted to the 64-bit fields.
>
> Since ehci is supported by downstream, I'd prefer that the
> migration maintainers also verify the implementation.
Thanks, I'll only look at the migration bits.
[...]
> > @@ -2441,6 +2445,11 @@ static int usb_ehci_post_load(void *opaque, int version_id)
> > }
> > }
> > + if (version_id < 3) {
> > + s->a_fetch_addr = s->a_fetch_addr_pre_v3;
> > + s->p_fetch_addr = s->p_fetch_addr_pre_v3;
> > + }
> > +
> > return 0;
> > }
> > @@ -2470,9 +2479,14 @@ static void usb_ehci_vm_state_change(void *opaque, bool running, RunState state)
> > }
> > }
> > +static bool ehci_core_is_before_version_3(void *opaque, int version_id)
> > +{
> > + return version_id < 3;
> > +}
> > +
> > const VMStateDescription vmstate_ehci = {
> > .name = "ehci-core",
> > - .version_id = 2,
> > + .version_id = 3,
> > .minimum_version_id = 1,
> > .pre_save = usb_ehci_pre_save,
> > .post_load = usb_ehci_post_load,
> > @@ -2501,8 +2515,12 @@ const VMStateDescription vmstate_ehci = {
> > /* schedule state */
> > VMSTATE_UINT32(astate, EHCIState),
> > VMSTATE_UINT32(pstate, EHCIState),
> > - VMSTATE_UINT32(a_fetch_addr, EHCIState),
> > - VMSTATE_UINT32(p_fetch_addr, EHCIState),
> > + VMSTATE_UINT32_TEST(a_fetch_addr_pre_v3, EHCIState,
> > + ehci_core_is_before_version_3),
> > + VMSTATE_UINT32_TEST(p_fetch_addr_pre_v3, EHCIState,
> > + ehci_core_is_before_version_3),
> > + VMSTATE_UINT64_V(a_fetch_addr, EHCIState, 3),
> > + VMSTATE_UINT64_V(p_fetch_addr, EHCIState, 3),
TL;DR: I feel like we still need machine type compat properties.
Details:
When a v2 stream arrives, two _TEST()s will do the loading, then
post_load() extend it to 64bits, looks fine.
When a v3 stream arrives, two _TEST()s got skipped then latter two take
effect. post_load() skips. Looks fine.
When migrating to another QEMU, due to the fact saving vmstates always take
vmsd's version declared (3), I don't see how it can migrate back to a v2
stream; it didn't know about v3.
Jiamin, have you tested migrating from a new QEMU binary back to another
old one? For upstream and serious devices, we need to guarantee
bi-directional migrations, back and forth.
Thanks,
> > VMSTATE_END_OF_LIST()
> > }
> > };
--
Peter Xu
^ permalink raw reply [flat|nested] 69+ messages in thread
* RE: [PATCH v3 01/17] hw/usb/hcd-ehci: Remove unused EHCIfstn structure and dead code
2026-04-17 9:47 ` BALATON Zoltan
@ 2026-04-20 3:46 ` Jamin Lin
0 siblings, 0 replies; 69+ messages in thread
From: Jamin Lin @ 2026-04-20 3:46 UTC (permalink / raw)
To: BALATON Zoltan
Cc: philmd@linaro.org, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here, Troy Lee,
flwu@google.com, nabihestefan@google.com
Hi BALATON
>
> Subject: RE: [PATCH v3 01/17] hw/usb/hcd-ehci: Remove unused EHCIfstn
> structure and dead code
>
> On Fri, 17 Apr 2026, Jamin Lin wrote:
> > Hi all,
> >
> >> Subject: RE: [PATCH v3 01/17] hw/usb/hcd-ehci: Remove unused EHCIfstn
> >> structure and dead code
> >>
> >> Hi all,
> >>
> >>> Subject: Re: [PATCH v3 01/17] hw/usb/hcd-ehci: Remove unused
> >>> EHCIfstn structure and dead code
> >>>
> >>> On Thu, 16 Apr 2026, Jamin Lin wrote:
> >>>> The EHCIfstn structure, defined according to EHCI spec section 3.7,
> >>>> is currently unused in the EHCI implementation. Remove it to reduce
> >>>> unused code and improve maintainability.
> >>>>
> >>>> Additionally, drop a block of disabled (#if 0) code in
> >>>> ehci_state_advqueue() that was never implemented. This code path is
> >>>> incomplete and has no functional impact.
> >>>>
> >>>> No functional change.
> >>>>
> >>>> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> >>>> ---
> >>>> hw/usb/hcd-ehci.h | 7 -------
> >>>> hw/usb/hcd-ehci.c | 11 -----------
> >>>> 2 files changed, 18 deletions(-)
> >>>>
> >>>> diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index
> >>>> 0ae8c06331..3aec0e047c 100644
> >>>> --- a/hw/usb/hcd-ehci.h
> >>>> +++ b/hw/usb/hcd-ehci.h
> >>>> @@ -202,13 +202,6 @@ typedef struct EHCIqh {
> >>>> #define BUFPTR_SBYTES_SH 5
> >>>> } EHCIqh;
> >>>>
> >>>> -/* EHCI spec version 1.0 Section 3.7
> >>>> - */
> >>>> -typedef struct EHCIfstn {
> >>>> - uint32_t next; /* Standard next link pointer
> >> */
> >>>> - uint32_t backptr; /* Standard next link pointer
> */
> >>>> -} EHCIfstn;
> >>>> -
> >>>> enum async_state {
> >>>> EHCI_ASYNC_NONE = 0,
> >>>> EHCI_ASYNC_INITIALIZED,
> >>>> diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index
> >>>> 57f930b099..5ea8461f70 100644
> >>>> --- a/hw/usb/hcd-ehci.c
> >>>> +++ b/hw/usb/hcd-ehci.c
> >>>> @@ -1756,17 +1756,6 @@ static int ehci_state_fetchsitd(EHCIState
> >>>> *ehci, int async)
> >>>> /* Section 4.10.2 - paragraph 3 */
> >>>> static int ehci_state_advqueue(EHCIQueue *q) { -#if 0
> >>>> - /* TO-DO: 4.10.2 - paragraph 2
> >>>> - * if I-bit is set to 1 and QH is not active
> >>>> - * go to horizontal QH
> >>>> - */
> >>>
> >>> Is it worth to keep the comment in case it's still valid to remind
> >>> we have something missing here?
> >>>
> >>> Regards,
> >>> BALATON Zoltan
> >>>
> >>
> >> If we decide to keep these comments as reminders for unimplemented
> >> parts, please let me know. I will resend the patch series and drop this patch.
> >>
> >> Thanks,
> >> Jamin
> >>
> >
> > Another approach:
> > We can remove the #if 0 dead code and keep only the comments as a
> reminder that this part is not yet implemented.
> >
> > Ex:
> > --- a/hw/usb/hcd-ehci.c
> > +++ b/hw/usb/hcd-ehci.c
> > @@ -1756,16 +1756,10 @@ static int ehci_state_fetchsitd(EHCIState
> > *ehci, int async)
> > /* Section 4.10.2 - paragraph 3 */
> > static int ehci_state_advqueue(EHCIQueue *q) { -#if 0
> > /* TO-DO: 4.10.2 - paragraph 2
> > * if I-bit is set to 1 and QH is not active
> > * go to horizontal QH
> > */
> > - if (I-bit set) {
> > - ehci_set_state(ehci, async, EST_HORIZONTALQH);
> > - goto out;
> > - }
> >
> > Thanks,
> > Jamin
>
> That's what I meant to leave the comment but OK the remove ineffective code.
Thanks for the suggestion.
Will do.
Jamin
>
> Regards,
> BALATON Zoltan
^ permalink raw reply [flat|nested] 69+ messages in thread
* RE: [PATCH v3 13/17] hw/usb/hcd-ehci: Add descriptor address offset property
2026-04-17 7:08 ` Philippe Mathieu-Daudé
@ 2026-04-20 5:47 ` Jamin Lin
2026-04-20 7:08 ` Cédric Le Goater
0 siblings, 1 reply; 69+ messages in thread
From: Jamin Lin @ 2026-04-20 5:47 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
Hi Philippe, Cédric
> >> - return ehci_get_buf_addr(s, s->ctrldssegment, low, UINT32_MAX);
> >> + uint64_t addr;
> >> +
> >> + addr = ehci_get_buf_addr(s, s->ctrldssegment, low, UINT32_MAX);
> >> + addr += s->descriptor_addr_offset;
> >
> >
> > Instead, can we force a default value for ctrldssegment when
> > caps_64bit_addr is set ?
> >
> > I am still trying to digest :
> >
> > https://lore.kernel.org/qemu-devel/
> >
> TYPPR06MB8206C7461E004C4FF07B8E92FC242@TYPPR06MB8206.apcprd06.
> prod.out
> > look.com/
>
> Same here, but since it doesn't break and I don't have much more time to
> dedicate to this I ended thinking "good enough for now, could be improved
> later", so no objection on my side.
>
> >
> > We have time let's take a moment to think about the workaround.
>
> Then keep me in the loop!
Thanks for the review and the suggestion.
I tried to address this by introducing a new property:
aspeed-ast2700-workaround.
When this property is enabled:
1. We force bit 2 of the CTRLDSSEGMENT register to 1 during initialization (when caps_64bit_addr is set).
2. Additionally, if firmware writes to the CTRLDSSEGMENT register, we also ensure that bit 2 remains set.
This keeps the behavior contained to AST2700-specific usage and avoids impacting other platforms.
Let me know if you think this approach makes sense, or if you'd prefer a different direction.
Jamin
diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
index af8c080c60..0a58dca668 100644
--- a/hw/usb/hcd-ehci.h
+++ b/hw/usb/hcd-ehci.h
@@ -263,6 +263,7 @@ struct EHCIState {
/* properties */
uint32_t maxframes;
bool caps_64bit_addr;
+ bool aspeed_ast2700_workaround;
/*
* EHCI spec version 1.0 Section 2.3
diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index 4a1f7cad73..83114bae90 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -858,6 +858,9 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp)
for (i = 0; i < sc->ehcis_num; i++) {
object_property_set_bool(OBJECT(&s->ehci[i]), "caps-64bit-addr", true,
&error_abort);
+ object_property_set_bool(OBJECT(&s->ehci[i]),
+ "aspeed-ast2700-workaround", true,
+ &error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), errp)) {
return;
}
diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c
index 61215e9f3d..01f72a5a1e 100644
--- a/hw/usb/hcd-ehci-sysbus.c
+++ b/hw/usb/hcd-ehci-sysbus.c
@@ -36,6 +36,9 @@ static const Property ehci_sysbus_properties[] = {
false),
DEFINE_PROP_BOOL("caps-64bit-addr", EHCISysBusState, ehci.caps_64bit_addr,
false),
+ DEFINE_PROP_BOOL("aspeed-ast2700-workaround", EHCISysBusState,
+ ehci.aspeed_ast2700_workaround,
+ false),
};
static void usb_ehci_sysbus_realize(DeviceState *dev, Error **errp)
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 7f90fd119d..403d7e84a7 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -1133,6 +1133,9 @@ static void ehci_opreg_write(void *ptr, hwaddr addr,
" 64-bit addressing capability is disabled\n");
return;
}
+ if (s->aspeed_ast2700_workaround) {
+ val |= BIT(2);
+ }
break;
case ASYNCLISTADDR:
if (ehci_async_enabled(s)) {
@@ -2582,6 +2585,9 @@ void usb_ehci_realize(EHCIState *s, DeviceState *dev, Error **errp)
}
if (s->caps_64bit_addr) {
s->caps[0x08] |= BIT(0);
+ if (s->aspeed_ast2700_workaround) {
+ s->ctrldssegment |= BIT(2);
+ }
}
^ permalink raw reply related [flat|nested] 69+ messages in thread
* RE: [PATCH v3 06/17] hw/usb/hcd-ehci: Change descriptor addresses to 64-bit
2026-04-17 15:10 ` Peter Xu
@ 2026-04-20 5:56 ` Jamin Lin
2026-04-20 13:34 ` Peter Xu
2026-04-20 16:04 ` Cédric Le Goater
0 siblings, 2 replies; 69+ messages in thread
From: Jamin Lin @ 2026-04-20 5:56 UTC (permalink / raw)
To: Peter Xu, Cédric Le Goater, philmd@linaro.org
Cc: philmd@linaro.org, Peter Maydell, Steven Lee, Troy Lee, Kane Chen,
Andrew Jeffery, Joel Stanley, open list:ASPEED BMCs,
open list:All patches CC here, Troy Lee, flwu@google.com,
nabihestefan@google.com, Fabiano Rosas
Hi Peter, Philippe, Cédric
> Subject: Re: [PATCH v3 06/17] hw/usb/hcd-ehci: Change descriptor addresses to
> 64-bit
>
> On Fri, Apr 17, 2026 at 09:01:34AM +0200, Cédric Le Goater wrote:
> > + Peter, Fabiano,
> >
> > On 4/16/26 03:49, Jamin Lin wrote:
> > > Change internal EHCI descriptor addresses from uint32_t to uint64_t.
> > >
> > > The following fields are updated:
> > > - EHCIPacket::qtdaddr
> > > - EHCIQueue::{qhaddr, qtdaddr}
> > > - EHCIState::{a_fetch_addr, p_fetch_addr}
> > >
> > > Update get_dwords() and put_dwords() to take 64-bit addresses and
> > > propagate the type change through the descriptor traversal paths.
> > >
> > > Adjust NLPTR_GET() to operate on 64-bit values:
> > >
> > > #define NLPTR_GET(x) ((x) & ~0x1fULL)
> > >
> > > so that link pointer masking works correctly when descriptor
> > > addresses exceed 32-bit space. The previous mask (0xffffffe0)
> > > implicitly truncated addresses to 32 bits.
> > >
> > > This patch does not change the on-wire descriptor layout yet.
> > > It only removes the internal 32-bit address limit and prepares for
> > > later patches that will add full 64-bit QH/qTD/iTD/siTD support.
> > >
> > > Update the EHCI trace-events prototypes for QH, qTD, iTD, and siTD
> > > to use uint64_t for the address argument and print it with PRIx64.
> > > This ensures full 64-bit addresses are shown in trace output and
> > > improves debugging of queue heads and transfer descriptors.
> > >
> > > Migration compatibility:
> > >
> > > The fetch address fields in EHCIState are extended from 32-bit to
> > > 64-bit, requiring a VMState version bump (v2 -> v3).
> > >
> > > Backward compatibility is preserved by keeping the legacy 32-bit
> > > fields (a_fetch_addr_pre_v3, p_fetch_addr_pre_v3) for pre-v3
> > > migration streams via VMSTATE_UINT32_TEST(), and introducing new
> > > 64-bit fields for v3+.
> > >
> > > In post_load, pre-v3 state is promoted to the 64-bit fields.
> >
> > Since ehci is supported by downstream, I'd prefer that the migration
> > maintainers also verify the implementation.
>
> Thanks, I'll only look at the migration bits.
>
> [...]
>
> > > @@ -2441,6 +2445,11 @@ static int usb_ehci_post_load(void *opaque, int
> version_id)
> > > }
> > > }
> > > + if (version_id < 3) {
> > > + s->a_fetch_addr = s->a_fetch_addr_pre_v3;
> > > + s->p_fetch_addr = s->p_fetch_addr_pre_v3;
> > > + }
> > > +
> > > return 0;
> > > }
> > > @@ -2470,9 +2479,14 @@ static void usb_ehci_vm_state_change(void
> *opaque, bool running, RunState state)
> > > }
> > > }
> > > +static bool ehci_core_is_before_version_3(void *opaque, int
> > > +version_id) {
> > > + return version_id < 3;
> > > +}
> > > +
> > > const VMStateDescription vmstate_ehci = {
> > > .name = "ehci-core",
> > > - .version_id = 2,
> > > + .version_id = 3,
> > > .minimum_version_id = 1,
> > > .pre_save = usb_ehci_pre_save,
> > > .post_load = usb_ehci_post_load,
> > > @@ -2501,8 +2515,12 @@ const VMStateDescription vmstate_ehci = {
> > > /* schedule state */
> > > VMSTATE_UINT32(astate, EHCIState),
> > > VMSTATE_UINT32(pstate, EHCIState),
> > > - VMSTATE_UINT32(a_fetch_addr, EHCIState),
> > > - VMSTATE_UINT32(p_fetch_addr, EHCIState),
> > > + VMSTATE_UINT32_TEST(a_fetch_addr_pre_v3, EHCIState,
> > > + ehci_core_is_before_version_3),
> > > + VMSTATE_UINT32_TEST(p_fetch_addr_pre_v3, EHCIState,
> > > + ehci_core_is_before_version_3),
> > > + VMSTATE_UINT64_V(a_fetch_addr, EHCIState, 3),
> > > + VMSTATE_UINT64_V(p_fetch_addr, EHCIState, 3),
>
> TL;DR: I feel like we still need machine type compat properties.
>
I don't understand this: Could you please describe it in more detail?
> Details:
>
> When a v2 stream arrives, two _TEST()s will do the loading, then
> post_load() extend it to 64bits, looks fine.
>
> When a v3 stream arrives, two _TEST()s got skipped then latter two take effect.
> post_load() skips. Looks fine.
>
> When migrating to another QEMU, due to the fact saving vmstates always take
> vmsd's version declared (3), I don't see how it can migrate back to a v2 stream;
> it didn't know about v3.
>
> Jiamin, have you tested migrating from a new QEMU binary back to another
> old one? For upstream and serious devices, we need to guarantee
> bi-directional migrations, back and forth.
>
Sorry, I am not familiar with the design of QEMU migration, and I don't know how to test it.
I added these hook functions based on Philippe's suggestion and review.
Could you tell me how to test migration to ensure both version 3 and version 2 are workable?
Thanks for the help, review, and suggestions.
> Thanks,
>
> > > VMSTATE_END_OF_LIST()
> > > }
> > > };
>
> --
> Peter Xu
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 13/17] hw/usb/hcd-ehci: Add descriptor address offset property
2026-04-20 5:47 ` Jamin Lin
@ 2026-04-20 7:08 ` Cédric Le Goater
2026-04-22 6:58 ` Jamin Lin
0 siblings, 1 reply; 69+ messages in thread
From: Cédric Le Goater @ 2026-04-20 7:08 UTC (permalink / raw)
To: Jamin Lin, Philippe Mathieu-Daudé, Peter Maydell, Steven Lee,
Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
On 4/20/26 07:47, Jamin Lin wrote:
> Hi Philippe, Cédric
>
>>>> - return ehci_get_buf_addr(s, s->ctrldssegment, low, UINT32_MAX);
>>>> + uint64_t addr;
>>>> +
>>>> + addr = ehci_get_buf_addr(s, s->ctrldssegment, low, UINT32_MAX);
>>>> + addr += s->descriptor_addr_offset;
>>>
>>>
>>> Instead, can we force a default value for ctrldssegment when
>>> caps_64bit_addr is set ?
>>>
>>> I am still trying to digest :
>>>
>>> https://lore.kernel.org/qemu-devel/
>>>
>> TYPPR06MB8206C7461E004C4FF07B8E92FC242@TYPPR06MB8206.apcprd06.
>> prod.out
>>> look.com/
>>
>> Same here, but since it doesn't break and I don't have much more time to
>> dedicate to this I ended thinking "good enough for now, could be improved
>> later", so no objection on my side.
>>
>>>
>>> We have time let's take a moment to think about the workaround.
>>
>> Then keep me in the loop!
>
>
> Thanks for the review and the suggestion.
>
> I tried to address this by introducing a new property:
> aspeed-ast2700-workaround.
This is not specific to AST2700.
I think a forced default value for CTRLDSSEGMENT would be more
appropriate. Perhaps "ctrldssegment-default", as a uint32_t,
which defaults to 0x0 and when the ast2700 SoC is realized,
set to BIT(2).
>
> When this property is enabled:
>
> 1. We force bit 2 of the CTRLDSSEGMENT register to 1 during initialization (when caps_64bit_addr is set).
> 2. Additionally, if firmware writes to the CTRLDSSEGMENT register, we also ensure that bit 2 remains set.
>
> This keeps the behavior contained to AST2700-specific usage and avoids impacting other platforms.
> Let me know if you think this approach makes sense, or if you'd prefer a different direction.
>
> Jamin
>
> diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
> index af8c080c60..0a58dca668 100644
> --- a/hw/usb/hcd-ehci.h
> +++ b/hw/usb/hcd-ehci.h
> @@ -263,6 +263,7 @@ struct EHCIState {
> /* properties */
> uint32_t maxframes;
> bool caps_64bit_addr;
> + bool aspeed_ast2700_workaround;
>
> /*
> * EHCI spec version 1.0 Section 2.3
> diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
> index 4a1f7cad73..83114bae90 100644
> --- a/hw/arm/aspeed_ast27x0.c
> +++ b/hw/arm/aspeed_ast27x0.c
> @@ -858,6 +858,9 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp)
> for (i = 0; i < sc->ehcis_num; i++) {
> object_property_set_bool(OBJECT(&s->ehci[i]), "caps-64bit-addr", true,
> &error_abort);
> + object_property_set_bool(OBJECT(&s->ehci[i]),
> + "aspeed-ast2700-workaround", true,
> + &error_abort);
> if (!sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), errp)) {
> return;
> }
> diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c
> index 61215e9f3d..01f72a5a1e 100644
> --- a/hw/usb/hcd-ehci-sysbus.c
> +++ b/hw/usb/hcd-ehci-sysbus.c
> @@ -36,6 +36,9 @@ static const Property ehci_sysbus_properties[] = {
> false),
> DEFINE_PROP_BOOL("caps-64bit-addr", EHCISysBusState, ehci.caps_64bit_addr,
> false),
> + DEFINE_PROP_BOOL("aspeed-ast2700-workaround", EHCISysBusState,
> + ehci.aspeed_ast2700_workaround,
> + false),
> };
>
> static void usb_ehci_sysbus_realize(DeviceState *dev, Error **errp)
> diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
> index 7f90fd119d..403d7e84a7 100644
> --- a/hw/usb/hcd-ehci.c
> +++ b/hw/usb/hcd-ehci.c
> @@ -1133,6 +1133,9 @@ static void ehci_opreg_write(void *ptr, hwaddr addr,
> " 64-bit addressing capability is disabled\n");
> return;
> }
> + if (s->aspeed_ast2700_workaround) {
> + val |= BIT(2);
> + }
With the proposal above, this would be changed to :
val |= s->ctrldssegment_default;
> break;
> case ASYNCLISTADDR:
> if (ehci_async_enabled(s)) {
> @@ -2582,6 +2585,9 @@ void usb_ehci_realize(EHCIState *s, DeviceState *dev, Error **errp)
> }
> if (s->caps_64bit_addr) {
> s->caps[0x08] |= BIT(0);
> + if (s->aspeed_ast2700_workaround) {
> + s->ctrldssegment |= BIT(2);
Shouldn't these assignments be in the reset handlers ?
Thanks,
C.
> + }
> }
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 06/17] hw/usb/hcd-ehci: Change descriptor addresses to 64-bit
2026-04-20 5:56 ` Jamin Lin
@ 2026-04-20 13:34 ` Peter Xu
2026-04-22 9:21 ` Jamin Lin
2026-04-20 16:04 ` Cédric Le Goater
1 sibling, 1 reply; 69+ messages in thread
From: Peter Xu @ 2026-04-20 13:34 UTC (permalink / raw)
To: Jamin Lin
Cc: Cédric Le Goater, philmd@linaro.org, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here, Troy Lee,
flwu@google.com, nabihestefan@google.com, Fabiano Rosas
On Mon, Apr 20, 2026 at 05:56:11AM +0000, Jamin Lin wrote:
> Hi Peter, Philippe, Cédric
Hi, Jamin,
[...]
> > > > @@ -2501,8 +2515,12 @@ const VMStateDescription vmstate_ehci = {
> > > > /* schedule state */
> > > > VMSTATE_UINT32(astate, EHCIState),
> > > > VMSTATE_UINT32(pstate, EHCIState),
> > > > - VMSTATE_UINT32(a_fetch_addr, EHCIState),
> > > > - VMSTATE_UINT32(p_fetch_addr, EHCIState),
> > > > + VMSTATE_UINT32_TEST(a_fetch_addr_pre_v3, EHCIState,
> > > > + ehci_core_is_before_version_3),
> > > > + VMSTATE_UINT32_TEST(p_fetch_addr_pre_v3, EHCIState,
> > > > + ehci_core_is_before_version_3),
> > > > + VMSTATE_UINT64_V(a_fetch_addr, EHCIState, 3),
> > > > + VMSTATE_UINT64_V(p_fetch_addr, EHCIState, 3),
> >
> > TL;DR: I feel like we still need machine type compat properties.
> >
>
> I don't understand this: Could you please describe it in more detail?
See hw/core/machine.c and entries added into hw_compat_*[] arrays. IIUC,
if this is an important device and if we want to guarantee bidirectional
migration (I'll explain later), then we should stick with machine compat
properties.
>
> > Details:
> >
> > When a v2 stream arrives, two _TEST()s will do the loading, then
> > post_load() extend it to 64bits, looks fine.
> >
> > When a v3 stream arrives, two _TEST()s got skipped then latter two take effect.
> > post_load() skips. Looks fine.
> >
> > When migrating to another QEMU, due to the fact saving vmstates always take
> > vmsd's version declared (3), I don't see how it can migrate back to a v2 stream;
> > it didn't know about v3.
> >
> > Jiamin, have you tested migrating from a new QEMU binary back to another
> > old one? For upstream and serious devices, we need to guarantee
> > bi-directional migrations, back and forth.
> >
>
> Sorry, I am not familiar with the design of QEMU migration, and I don't know how to test it.
> I added these hook functions based on Philippe's suggestion and review.
> Could you tell me how to test migration to ensure both version 3 and version 2 are workable?
Since this patch already modified VMSDs, I believe migration test should
have been carried out at the very minimum.. Logically if vmsd versioning
is used, we should also have tested forward migrations, because that's only
for that.
What I'm talking about is I think backward migration will fail.
Forward migration describes the case when a VM hosted by an old QEMU binary
(e.g. QEMU v10.2.0) is migrated to a new QEMU (e.g., after this patch
applied on top of master).
Backward migration describes the case when a VM hosted by a new QEMU binary
(e.g., after this patch applied on top of master) is migrated back to an
old QEMU binary (e.g. QEMU v10.2.0).
For different devices, we should allow different level of support on
migration. Any device that may be important to either upstream QEMU or
downstreams should better allow bi-directional migration. In this case we
need to use machine compat properties I mentioned. I'm not yet sure where
EHCI controller falls e.g. v.s. XHCI.. when not sure, we can also just
stick with machine compat properties to be on the safe side.
For more info, you can also refer to:
https://www.qemu.org/docs/master/devel/migration/compatibility.html
Thanks,
--
Peter Xu
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 06/17] hw/usb/hcd-ehci: Change descriptor addresses to 64-bit
2026-04-20 5:56 ` Jamin Lin
2026-04-20 13:34 ` Peter Xu
@ 2026-04-20 16:04 ` Cédric Le Goater
2026-04-22 9:10 ` Jamin Lin
1 sibling, 1 reply; 69+ messages in thread
From: Cédric Le Goater @ 2026-04-20 16:04 UTC (permalink / raw)
To: Jamin Lin, Peter Xu, philmd@linaro.org
Cc: Peter Maydell, Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery,
Joel Stanley, open list:ASPEED BMCs,
open list:All patches CC here, Troy Lee, flwu@google.com,
nabihestefan@google.com, Fabiano Rosas
On 4/20/26 07:56, Jamin Lin wrote:
> Hi Peter, Philippe, Cédric
>
>> Subject: Re: [PATCH v3 06/17] hw/usb/hcd-ehci: Change descriptor addresses to
>> 64-bit
>>
>> On Fri, Apr 17, 2026 at 09:01:34AM +0200, Cédric Le Goater wrote:
>>> + Peter, Fabiano,
>>>
>>> On 4/16/26 03:49, Jamin Lin wrote:
>>>> Change internal EHCI descriptor addresses from uint32_t to uint64_t.
>>>>
>>>> The following fields are updated:
>>>> - EHCIPacket::qtdaddr
>>>> - EHCIQueue::{qhaddr, qtdaddr}
>>>> - EHCIState::{a_fetch_addr, p_fetch_addr}
>>>>
>>>> Update get_dwords() and put_dwords() to take 64-bit addresses and
>>>> propagate the type change through the descriptor traversal paths.
>>>>
>>>> Adjust NLPTR_GET() to operate on 64-bit values:
>>>>
>>>> #define NLPTR_GET(x) ((x) & ~0x1fULL)
>>>>
>>>> so that link pointer masking works correctly when descriptor
>>>> addresses exceed 32-bit space. The previous mask (0xffffffe0)
>>>> implicitly truncated addresses to 32 bits.
>>>>
>>>> This patch does not change the on-wire descriptor layout yet.
>>>> It only removes the internal 32-bit address limit and prepares for
>>>> later patches that will add full 64-bit QH/qTD/iTD/siTD support.
>>>>
>>>> Update the EHCI trace-events prototypes for QH, qTD, iTD, and siTD
>>>> to use uint64_t for the address argument and print it with PRIx64.
>>>> This ensures full 64-bit addresses are shown in trace output and
>>>> improves debugging of queue heads and transfer descriptors.
>>>>
>>>> Migration compatibility:
>>>>
>>>> The fetch address fields in EHCIState are extended from 32-bit to
>>>> 64-bit, requiring a VMState version bump (v2 -> v3).
>>>>
>>>> Backward compatibility is preserved by keeping the legacy 32-bit
>>>> fields (a_fetch_addr_pre_v3, p_fetch_addr_pre_v3) for pre-v3
>>>> migration streams via VMSTATE_UINT32_TEST(), and introducing new
>>>> 64-bit fields for v3+.
>>>>
>>>> In post_load, pre-v3 state is promoted to the 64-bit fields.
>>>
>>> Since ehci is supported by downstream, I'd prefer that the migration
>>> maintainers also verify the implementation.
>>
>> Thanks, I'll only look at the migration bits.
>>
>> [...]
>>
>>>> @@ -2441,6 +2445,11 @@ static int usb_ehci_post_load(void *opaque, int
>> version_id)
>>>> }
>>>> }
>>>> + if (version_id < 3) {
>>>> + s->a_fetch_addr = s->a_fetch_addr_pre_v3;
>>>> + s->p_fetch_addr = s->p_fetch_addr_pre_v3;
>>>> + }
>>>> +
>>>> return 0;
>>>> }
>>>> @@ -2470,9 +2479,14 @@ static void usb_ehci_vm_state_change(void
>> *opaque, bool running, RunState state)
>>>> }
>>>> }
>>>> +static bool ehci_core_is_before_version_3(void *opaque, int
>>>> +version_id) {
>>>> + return version_id < 3;
>>>> +}
>>>> +
>>>> const VMStateDescription vmstate_ehci = {
>>>> .name = "ehci-core",
>>>> - .version_id = 2,
>>>> + .version_id = 3,
>>>> .minimum_version_id = 1,
>>>> .pre_save = usb_ehci_pre_save,
>>>> .post_load = usb_ehci_post_load,
>>>> @@ -2501,8 +2515,12 @@ const VMStateDescription vmstate_ehci = {
>>>> /* schedule state */
>>>> VMSTATE_UINT32(astate, EHCIState),
>>>> VMSTATE_UINT32(pstate, EHCIState),
>>>> - VMSTATE_UINT32(a_fetch_addr, EHCIState),
>>>> - VMSTATE_UINT32(p_fetch_addr, EHCIState),
>>>> + VMSTATE_UINT32_TEST(a_fetch_addr_pre_v3, EHCIState,
>>>> + ehci_core_is_before_version_3),
>>>> + VMSTATE_UINT32_TEST(p_fetch_addr_pre_v3, EHCIState,
>>>> + ehci_core_is_before_version_3),
>>>> + VMSTATE_UINT64_V(a_fetch_addr, EHCIState, 3),
>>>> + VMSTATE_UINT64_V(p_fetch_addr, EHCIState, 3),
>>
>> TL;DR: I feel like we still need machine type compat properties.
>>
>
> I don't understand this: Could you please describe it in more detail?
>
>> Details:
>>
>> When a v2 stream arrives, two _TEST()s will do the loading, then
>> post_load() extend it to 64bits, looks fine.
>>
>> When a v3 stream arrives, two _TEST()s got skipped then latter two take effect.
>> post_load() skips. Looks fine.
>>
>> When migrating to another QEMU, due to the fact saving vmstates always take
>> vmsd's version declared (3), I don't see how it can migrate back to a v2 stream;
>> it didn't know about v3.
>>
>> Jiamin, have you tested migrating from a new QEMU binary back to another
>> old one? For upstream and serious devices, we need to guarantee
>> bi-directional migrations, back and forth.
>>
>
> Sorry, I am not familiar with the design of QEMU migration, and I don't know how to test it.
> I added these hook functions based on Philippe's suggestion and review.
> Could you tell me how to test migration to ensure both version 3 and version 2 are workable?
Migrating a running guest back and forth between QEMU [1] and [2]
should be possible :
[1] path/to/qemu-10.2/install/bin/qemu-system-x86_64 -M pc-q35-10.2 \
... \
-device usb-ehci \
-device usb-kbd
[2] path/to/myqemu-with-patches/install/bin/qemu-system-x86_64 -M pc-q35-10.2 \
... \
-device usb-ehci \
-device usb-kbd
This is required to guarantee forward and backward compatibility of
QEMU pc-q35-10.2 machine instances.
C.
^ permalink raw reply [flat|nested] 69+ messages in thread
* RE: [PATCH v3 13/17] hw/usb/hcd-ehci: Add descriptor address offset property
2026-04-17 6:23 ` Philippe Mathieu-Daudé
@ 2026-04-22 5:00 ` Jamin Lin
0 siblings, 0 replies; 69+ messages in thread
From: Jamin Lin @ 2026-04-22 5:00 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
Hi Philippe,
> Subject: Re: [PATCH v3 13/17] hw/usb/hcd-ehci: Add descriptor address offset
> property
>
> On 16/4/26 03:49, Jamin Lin wrote:
> > When 64-bit addressing is supported, the Linux EHCI driver programs
> > the segment register to zero. See ehci_run function:
> > https://github.com/torvalds/linux/blob/master/drivers/usb/host/ehci-hc
> > d.c
> >
> > The driver comment also notes that descriptor structures allocated
> > from the DMA pool use segment zero semantics.
> >
> > Descriptor memory is allocated using the DMA API. The platform driver
> > configures a 64-bit DMA mask so memory can be allocated above 4GB.
> > See ehci_platform_probe function:
> > https://github.com/torvalds/linux/blob/master/drivers/usb/host/ehci-pl
> > atform.c
> >
> > On AST2700 platforms, system DRAM is mapped above 4GB at
> 0x400000000.
> > As a result, descriptor addresses constructed directly from the guest
> > EHCI registers do not match the actual system address used by the
> > controller when fetching queue heads (QH) and queue element transfer
> > descriptors (qTD).
> >
> > Introduce a descriptor-addr-offset property so platforms can provide
> > an address offset applied when constructing descriptor addresses. This
> > allows systems where DRAM resides above 4GB to correctly access EHCI
> > descriptors while keeping the default behavior unchanged for existing
> > machines.
> >
> > Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> > ---
> > hw/usb/hcd-ehci.h | 1 +
> > hw/usb/hcd-ehci-pci.c | 2 ++
> > hw/usb/hcd-ehci-sysbus.c | 2 ++
> > hw/usb/hcd-ehci.c | 7 ++++++-
> > 4 files changed, 11 insertions(+), 1 deletion(-)
> >
> > diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index
> > 6406f536e8..05d8db4a5d 100644
> > --- a/hw/usb/hcd-ehci.h
> > +++ b/hw/usb/hcd-ehci.h
> > @@ -264,6 +264,7 @@ struct EHCIState {
> > /* properties */
> > uint32_t maxframes;
> > bool caps_64bit_addr;
> > + uint64_t descriptor_addr_offset;
>
> I note OHCI uses "dma_addr_t dma_offset;" here.
>
> >
> > /*
> > * EHCI spec version 1.0 Section 2.3 diff --git
> > a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c index
> > 2ea8549db9..115d05ede0 100644
> > --- a/hw/usb/hcd-ehci-pci.c
> > +++ b/hw/usb/hcd-ehci-pci.c
> > @@ -139,6 +139,8 @@ static const Property ehci_pci_properties[] = {
> > DEFINE_PROP_UINT32("maxframes", EHCIPCIState, ehci.maxframes,
> 128),
> > DEFINE_PROP_BOOL("caps-64bit-addr", EHCIPCIState,
> ehci.caps_64bit_addr,
> > false),
> > + DEFINE_PROP_UINT64("descriptor-addr-offset", EHCIPCIState,
> > + ehci.descriptor_addr_offset, 0),
> > };
>
> I note OHCI uses DEFINE_PROP_DMAADDR() here. Single use, maybe better
> remove it and stick to uint64_t as you use.
>
Thanks for the suggestion and review.
Based on Cédric’s feedback, I will update the ctrldssegment-default property to use a uint32_t type.
>
> Could we have a DEFINE_EHCI_COMMON_PROPERTIES() macro for common
> entries instead, such DEFINE_SDHCI_COMMON_PROPERTIES()?
>
Will do
Thanks,
Jamin
> >
> > static const VMStateDescription vmstate_ehci_pci = { diff --git
> > a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c index
> > 61215e9f3d..df138fb339 100644
> > --- a/hw/usb/hcd-ehci-sysbus.c
> > +++ b/hw/usb/hcd-ehci-sysbus.c
> > @@ -36,6 +36,8 @@ static const Property ehci_sysbus_properties[] = {
> > false),
> > DEFINE_PROP_BOOL("caps-64bit-addr", EHCISysBusState,
> ehci.caps_64bit_addr,
> > false),
> > + DEFINE_PROP_UINT64("descriptor-addr-offset", EHCISysBusState,
> > + ehci.descriptor_addr_offset, 0),
> > };
>
^ permalink raw reply [flat|nested] 69+ messages in thread
* RE: [PATCH v3 15/17] hw/arm/aspeed_ast27x0: Set EHCI descriptor address offset
2026-04-17 6:25 ` Philippe Mathieu-Daudé
@ 2026-04-22 5:03 ` Jamin Lin
0 siblings, 0 replies; 69+ messages in thread
From: Jamin Lin @ 2026-04-22 5:03 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, Cédric Le Goater, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
Hi Philippe
> Subject: Re: [PATCH v3 15/17] hw/arm/aspeed_ast27x0: Set EHCI descriptor
> address offset
>
> On 16/4/26 03:50, Jamin Lin wrote:
> > On AST2700 platforms, system DRAM is mapped above 4GB with the base
> > address at 0x400000000.
> >
> > The Linux EHCI driver programs the segment register to zero when
> > 64-bit addressing is supported. As a result, descriptor addresses
> > derived from the EHCI registers do not include the DRAM base address.
> >
> > Descriptor memory is allocated through the DMA API with a 64-bit DMA
> > mask, which allows descriptors to be placed in DRAM above 4GB.
> > When running on AST2700, this means EHCI queue heads (QH) and queue
> > element transfer descriptors (qTD) reside at addresses starting from
> > 0x400000000.
> >
> > Set the descriptor-addr-offset property to the DRAM base so the
> > emulated EHCI controller can construct the correct descriptor
> > addresses when accessing system memory.
> >
> > Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> > ---
> > hw/arm/aspeed_ast27x0.c | 3 +++
> > 1 file changed, 3 insertions(+)
> >
> > diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c index
> > 4a1f7cad73..3cdbf78ac1 100644
> > --- a/hw/arm/aspeed_ast27x0.c
> > +++ b/hw/arm/aspeed_ast27x0.c
> > @@ -858,6 +858,9 @@ static void aspeed_soc_ast2700_realize(DeviceState
> *dev, Error **errp)
> > for (i = 0; i < sc->ehcis_num; i++) {
> > object_property_set_bool(OBJECT(&s->ehci[i]),
> "caps-64bit-addr", true,
> > &error_abort);
> > + object_property_set_int(OBJECT(&s->ehci[i]),
> "descriptor-addr-offset",
> > +
> sc->memmap[ASPEED_DEV_SDRAM],
> > + &error_abort);
>
> Squash with previous? Or invert 14 <-> 15 order?
Thanks for the suggestion and review.
Will invert patch order.
Jamin
^ permalink raw reply [flat|nested] 69+ messages in thread
* RE: [PATCH v3 13/17] hw/usb/hcd-ehci: Add descriptor address offset property
2026-04-20 7:08 ` Cédric Le Goater
@ 2026-04-22 6:58 ` Jamin Lin
0 siblings, 0 replies; 69+ messages in thread
From: Jamin Lin @ 2026-04-22 6:58 UTC (permalink / raw)
To: Cédric Le Goater, Philippe Mathieu-Daudé, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here
Cc: Troy Lee, flwu@google.com, nabihestefan@google.com
Hi Cédric,
> Subject: Re: [PATCH v3 13/17] hw/usb/hcd-ehci: Add descriptor address offset
> property
> >
> > I tried to address this by introducing a new property:
> > aspeed-ast2700-workaround.
>
> This is not specific to AST2700.
>
> I think a forced default value for CTRLDSSEGMENT would be more appropriate.
> Perhaps "ctrldssegment-default", as a uint32_t, which defaults to 0x0 and
> when the ast2700 SoC is realized, set to BIT(2).
>
Thanks for the suggestion and review.
Will do
>
> >
> > + if (s->aspeed_ast2700_workaround) {
> > + val |= BIT(2);
> > + }
>
> With the proposal above, this would be changed to :
>
> val |= s->ctrldssegment_default;
>
Will do
> > break;
> > case ASYNCLISTADDR:
> > if (ehci_async_enabled(s)) { @@ -2582,6 +2585,9 @@ void
> > usb_ehci_realize(EHCIState *s, DeviceState *dev, Error **errp)
> > }
> > if (s->caps_64bit_addr) {
> > s->caps[0x08] |= BIT(0);
> > + if (s->aspeed_ast2700_workaround) {
> > + s->ctrldssegment |= BIT(2);
>
> Shouldn't these assignments be in the reset handlers ?
>
Yes, with above solution, we do not need it in the reset handlers.
Will remove it.
Appreciate your kindly support and help.
Jamin
> Thanks,
>
> C.
>
>
> > + }
> > }
^ permalink raw reply [flat|nested] 69+ messages in thread
* RE: [PATCH v3 06/17] hw/usb/hcd-ehci: Change descriptor addresses to 64-bit
2026-04-20 16:04 ` Cédric Le Goater
@ 2026-04-22 9:10 ` Jamin Lin
0 siblings, 0 replies; 69+ messages in thread
From: Jamin Lin @ 2026-04-22 9:10 UTC (permalink / raw)
To: Cédric Le Goater, Peter Xu, philmd@linaro.org
Cc: Peter Maydell, Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery,
Joel Stanley, open list:ASPEED BMCs,
open list:All patches CC here, Troy Lee, flwu@google.com,
nabihestefan@google.com, Fabiano Rosas
Hi Cédric
> Subject: Re: [PATCH v3 06/17] hw/usb/hcd-ehci: Change descriptor addresses to
> 64-bit
>
> On 4/20/26 07:56, Jamin Lin wrote:
> > Hi Peter, Philippe, Cédric
> >
> >> Subject: Re: [PATCH v3 06/17] hw/usb/hcd-ehci: Change descriptor
> >> addresses to 64-bit
> >>
> >> On Fri, Apr 17, 2026 at 09:01:34AM +0200, Cédric Le Goater wrote:
> >>> + Peter, Fabiano,
> >>>
> >>> On 4/16/26 03:49, Jamin Lin wrote:
> >>>> Change internal EHCI descriptor addresses from uint32_t to uint64_t.
> >>>>
> >>>> The following fields are updated:
> >>>> - EHCIPacket::qtdaddr
> >>>> - EHCIQueue::{qhaddr, qtdaddr}
> >>>> - EHCIState::{a_fetch_addr, p_fetch_addr}
> >>>>
> >>>> Update get_dwords() and put_dwords() to take 64-bit addresses and
> >>>> propagate the type change through the descriptor traversal paths.
> >>>>
> >>>> Adjust NLPTR_GET() to operate on 64-bit values:
> >>>>
> >>>> #define NLPTR_GET(x) ((x) & ~0x1fULL)
> >>>>
> >>>> so that link pointer masking works correctly when descriptor
> >>>> addresses exceed 32-bit space. The previous mask (0xffffffe0)
> >>>> implicitly truncated addresses to 32 bits.
> >>>>
> >>>> This patch does not change the on-wire descriptor layout yet.
> >>>> It only removes the internal 32-bit address limit and prepares for
> >>>> later patches that will add full 64-bit QH/qTD/iTD/siTD support.
> >>>>
> >>>> Update the EHCI trace-events prototypes for QH, qTD, iTD, and siTD
> >>>> to use uint64_t for the address argument and print it with PRIx64.
> >>>> This ensures full 64-bit addresses are shown in trace output and
> >>>> improves debugging of queue heads and transfer descriptors.
> >>>>
> >>>> Migration compatibility:
> >>>>
> >>>> The fetch address fields in EHCIState are extended from 32-bit to
> >>>> 64-bit, requiring a VMState version bump (v2 -> v3).
> >>>>
> >>>> Backward compatibility is preserved by keeping the legacy 32-bit
> >>>> fields (a_fetch_addr_pre_v3, p_fetch_addr_pre_v3) for pre-v3
> >>>> migration streams via VMSTATE_UINT32_TEST(), and introducing new
> >>>> 64-bit fields for v3+.
> >>>>
> >>>> In post_load, pre-v3 state is promoted to the 64-bit fields.
> >>>
> >>> Since ehci is supported by downstream, I'd prefer that the migration
> >>> maintainers also verify the implementation.
> >>
> >> Thanks, I'll only look at the migration bits.
> >>
> >> [...]
> >>
> >>>> @@ -2441,6 +2445,11 @@ static int usb_ehci_post_load(void *opaque,
> >>>> int
> >> version_id)
> >>>> }
> >>>> }
> >>>> + if (version_id < 3) {
> >>>> + s->a_fetch_addr = s->a_fetch_addr_pre_v3;
> >>>> + s->p_fetch_addr = s->p_fetch_addr_pre_v3;
> >>>> + }
> >>>> +
> >>>> return 0;
> >>>> }
> >>>> @@ -2470,9 +2479,14 @@ static void usb_ehci_vm_state_change(void
> >> *opaque, bool running, RunState state)
> >>>> }
> >>>> }
> >>>> +static bool ehci_core_is_before_version_3(void *opaque, int
> >>>> +version_id) {
> >>>> + return version_id < 3;
> >>>> +}
> >>>> +
> >>>> const VMStateDescription vmstate_ehci = {
> >>>> .name = "ehci-core",
> >>>> - .version_id = 2,
> >>>> + .version_id = 3,
> >>>> .minimum_version_id = 1,
> >>>> .pre_save = usb_ehci_pre_save,
> >>>> .post_load = usb_ehci_post_load,
> >>>> @@ -2501,8 +2515,12 @@ const VMStateDescription vmstate_ehci = {
> >>>> /* schedule state */
> >>>> VMSTATE_UINT32(astate, EHCIState),
> >>>> VMSTATE_UINT32(pstate, EHCIState),
> >>>> - VMSTATE_UINT32(a_fetch_addr, EHCIState),
> >>>> - VMSTATE_UINT32(p_fetch_addr, EHCIState),
> >>>> + VMSTATE_UINT32_TEST(a_fetch_addr_pre_v3, EHCIState,
> >>>> + ehci_core_is_before_version_3),
> >>>> + VMSTATE_UINT32_TEST(p_fetch_addr_pre_v3, EHCIState,
> >>>> + ehci_core_is_before_version_3),
> >>>> + VMSTATE_UINT64_V(a_fetch_addr, EHCIState, 3),
> >>>> + VMSTATE_UINT64_V(p_fetch_addr, EHCIState, 3),
> >>
> >> TL;DR: I feel like we still need machine type compat properties.
> >>
> >
> > I don't understand this: Could you please describe it in more detail?
> >
> >> Details:
> >>
> >> When a v2 stream arrives, two _TEST()s will do the loading, then
> >> post_load() extend it to 64bits, looks fine.
> >>
> >> When a v3 stream arrives, two _TEST()s got skipped then latter two take
> effect.
> >> post_load() skips. Looks fine.
> >>
> >> When migrating to another QEMU, due to the fact saving vmstates
> >> always take vmsd's version declared (3), I don't see how it can
> >> migrate back to a v2 stream; it didn't know about v3.
> >>
> >> Jiamin, have you tested migrating from a new QEMU binary back to
> >> another old one? For upstream and serious devices, we need to
> >> guarantee bi-directional migrations, back and forth.
> >>
> >
> > Sorry, I am not familiar with the design of QEMU migration, and I don't know
> how to test it.
> > I added these hook functions based on Philippe's suggestion and review.
> > Could you tell me how to test migration to ensure both version 3 and version
> 2 are workable?
>
>
> Migrating a running guest back and forth between QEMU [1] and [2] should be
> possible :
>
> [1] path/to/qemu-10.2/install/bin/qemu-system-x86_64 -M pc-q35-10.2 \
> ... \
> -device usb-ehci \
> -device usb-kbd
>
> [2] path/to/myqemu-with-patches/install/bin/qemu-system-x86_64 -M
> pc-q35-10.2 \
> ... \
> -device usb-ehci \
> -device usb-kbd
>
> This is required to guarantee forward and backward compatibility of QEMU
> pc-q35-10.2 machine instances.
>
>
Thanks for the migration test steps.
I have tested both forward and backward migration for EHCI and observed failures in both directions.
I will revise my changes in a follow-up patch to address these issues and ensure that the migration tests pass.
Thanks,
Jamin
> C.
^ permalink raw reply [flat|nested] 69+ messages in thread
* RE: [PATCH v3 06/17] hw/usb/hcd-ehci: Change descriptor addresses to 64-bit
2026-04-20 13:34 ` Peter Xu
@ 2026-04-22 9:21 ` Jamin Lin
2026-04-22 14:37 ` Peter Xu
0 siblings, 1 reply; 69+ messages in thread
From: Jamin Lin @ 2026-04-22 9:21 UTC (permalink / raw)
To: Peter Xu, Cédric Le Goater, philmd@linaro.org
Cc: Peter Maydell, Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery,
Joel Stanley, open list:ASPEED BMCs,
open list:All patches CC here, Troy Lee, flwu@google.com,
nabihestefan@google.com, Fabiano Rosas
Hi Peter, Cédric and Philippe
> Subject: Re: [PATCH v3 06/17] hw/usb/hcd-ehci: Change descriptor addresses to
> 64-bit
>
> On Mon, Apr 20, 2026 at 05:56:11AM +0000, Jamin Lin wrote:
> > Hi Peter, Philippe, Cédric
>
> Hi, Jamin,
>
> [...]
>
> > > > > @@ -2501,8 +2515,12 @@ const VMStateDescription vmstate_ehci = {
> > > > > /* schedule state */
> > > > > VMSTATE_UINT32(astate, EHCIState),
> > > > > VMSTATE_UINT32(pstate, EHCIState),
> > > > > - VMSTATE_UINT32(a_fetch_addr, EHCIState),
> > > > > - VMSTATE_UINT32(p_fetch_addr, EHCIState),
> > > > > + VMSTATE_UINT32_TEST(a_fetch_addr_pre_v3, EHCIState,
> > > > > + ehci_core_is_before_version_3),
> > > > > + VMSTATE_UINT32_TEST(p_fetch_addr_pre_v3, EHCIState,
> > > > > + ehci_core_is_before_version_3),
> > > > > + VMSTATE_UINT64_V(a_fetch_addr, EHCIState, 3),
> > > > > + VMSTATE_UINT64_V(p_fetch_addr, EHCIState, 3),
> > >
> > > TL;DR: I feel like we still need machine type compat properties.
> > >
> >
> > I don't understand this: Could you please describe it in more detail?
>
> See hw/core/machine.c and entries added into hw_compat_*[] arrays. IIUC,
> if this is an important device and if we want to guarantee bidirectional
> migration (I'll explain later), then we should stick with machine compat
> properties.
>
> >
> > > Details:
> > >
> > > When a v2 stream arrives, two _TEST()s will do the loading, then
> > > post_load() extend it to 64bits, looks fine.
> > >
> > > When a v3 stream arrives, two _TEST()s got skipped then latter two take
> effect.
> > > post_load() skips. Looks fine.
> > >
> > > When migrating to another QEMU, due to the fact saving vmstates
> > > always take vmsd's version declared (3), I don't see how it can
> > > migrate back to a v2 stream; it didn't know about v3.
> > >
> > > Jiamin, have you tested migrating from a new QEMU binary back to
> > > another old one? For upstream and serious devices, we need to
> > > guarantee bi-directional migrations, back and forth.
> > >
> >
> > Sorry, I am not familiar with the design of QEMU migration, and I don't know
> how to test it.
> > I added these hook functions based on Philippe's suggestion and review.
> > Could you tell me how to test migration to ensure both version 3 and version
> 2 are workable?
>
> Since this patch already modified VMSDs, I believe migration test should have
> been carried out at the very minimum.. Logically if vmsd versioning is used,
> we should also have tested forward migrations, because that's only for that.
>
> What I'm talking about is I think backward migration will fail.
>
> Forward migration describes the case when a VM hosted by an old QEMU
> binary (e.g. QEMU v10.2.0) is migrated to a new QEMU (e.g., after this patch
> applied on top of master).
>
> Backward migration describes the case when a VM hosted by a new QEMU
> binary (e.g., after this patch applied on top of master) is migrated back to an
> old QEMU binary (e.g. QEMU v10.2.0).
>
> For different devices, we should allow different level of support on migration.
> Any device that may be important to either upstream QEMU or downstreams
> should better allow bi-directional migration. In this case we need to use
> machine compat properties I mentioned. I'm not yet sure where EHCI
> controller falls e.g. v.s. XHCI.. when not sure, we can also just stick with
> machine compat properties to be on the safe side.
>
> For more info, you can also refer to:
>
> https://www.qemu.org/docs/master/devel/migration/compatibility.html
>
> Thanks,
>
> --
> Peter Xu
Thanks for your support and the detailed explanation.
Following Cédric’s comments, I now understand how to properly test migration. With the changes below, both forward and backward migration tests pass.
Could you please review these changes, or would you prefer that I resend them as v4?
Thanks again for your guidance and support.
Jamin
diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
index 310183bbc4..bd165c793c 100644
--- a/hw/usb/hcd-ehci.h
+++ b/hw/usb/hcd-ehci.h
@@ -264,6 +264,7 @@ struct EHCIState {
uint32_t maxframes;
bool caps_64bit_addr;
uint32_t ctrldssegment_default;
+ bool migrate_fetch_addr_64bit;
/*
* EHCI spec version 1.0 Section 2.3
@@ -321,7 +322,9 @@ struct EHCIState {
DEFINE_PROP_UINT32("maxframes", _state, ehci.maxframes, 128), \
DEFINE_PROP_BOOL("caps-64bit-addr", _state, ehci.caps_64bit_addr, false), \
DEFINE_PROP_UINT32("ctrldssegment-default", _state, \
- ehci.ctrldssegment_default, 0)
+ ehci.ctrldssegment_default, 0), \
+ DEFINE_PROP_BOOL("x-migrate-fetch-addr-64bit", _state, \
+ ehci.migrate_fetch_addr_64bit, true)
extern const VMStateDescription vmstate_ehci;
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 0aa77a57e9..e77400c7ab 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -41,6 +41,8 @@
GlobalProperty hw_compat_10_2[] = {
{ "scsi-block", "migrate-pr", "off" },
{ "isa-cirrus-vga", "global-vmstate", "true" },
+ { "sysbus-ehci-usb", "x-migrate-fetch-addr-64bit", "off" },
+ { "pci-ehci-usb", "x-migrate-fetch-addr-64bit", "off" },
};
const size_t hw_compat_10_2_len = G_N_ELEMENTS(hw_compat_10_2);
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 983b1731f9..87528ddc02 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -2469,6 +2469,9 @@ static int usb_ehci_pre_save(void *opaque)
ehci->last_run_ns -= (ehci->frindex - new_frindex) * UFRAME_TIMER_NS;
ehci->frindex = new_frindex;
+ ehci->a_fetch_addr_pre_v3 = ehci->a_fetch_addr;
+ ehci->p_fetch_addr_pre_v3 = ehci->p_fetch_addr;
+
return 0;
}
@@ -2489,10 +2492,8 @@ static int usb_ehci_post_load(void *opaque, int version_id)
}
}
- if (version_id < 3) {
- s->a_fetch_addr = s->a_fetch_addr_pre_v3;
- s->p_fetch_addr = s->p_fetch_addr_pre_v3;
- }
+ s->a_fetch_addr = s->a_fetch_addr_pre_v3;
+ s->p_fetch_addr = s->p_fetch_addr_pre_v3;
return 0;
}
@@ -2523,14 +2524,29 @@ static void usb_ehci_vm_state_change(void *opaque, bool running, RunState state)
}
}
-static bool ehci_core_is_before_version_3(void *opaque, int version_id)
+static bool ehci_fetch_addr_64_needed(void *opaque)
{
- return version_id < 3;
+ EHCIState *s = opaque;
+
+ return s->migrate_fetch_addr_64bit;
}
+static const VMStateDescription vmstate_ehci_fetch_addr_64 = {
+ .name = "ehci-core/fetch-addr64",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = ehci_fetch_addr_64_needed,
+ .fields = (const VMStateField[]) {
+ /* mmio registers */
+ VMSTATE_UINT64(a_fetch_addr, EHCIState),
+ VMSTATE_UINT64(p_fetch_addr, EHCIState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
const VMStateDescription vmstate_ehci = {
.name = "ehci-core",
- .version_id = 3,
+ .version_id = 2,
.minimum_version_id = 1,
.pre_save = usb_ehci_pre_save,
.post_load = usb_ehci_post_load,
@@ -2559,14 +2575,14 @@ const VMStateDescription vmstate_ehci = {
/* schedule state */
VMSTATE_UINT32(astate, EHCIState),
VMSTATE_UINT32(pstate, EHCIState),
- VMSTATE_UINT32_TEST(a_fetch_addr_pre_v3, EHCIState,
- ehci_core_is_before_version_3),
- VMSTATE_UINT32_TEST(p_fetch_addr_pre_v3, EHCIState,
- ehci_core_is_before_version_3),
- VMSTATE_UINT64_V(a_fetch_addr, EHCIState, 3),
- VMSTATE_UINT64_V(p_fetch_addr, EHCIState, 3),
+ VMSTATE_UINT32(a_fetch_addr_pre_v3, EHCIState),
+ VMSTATE_UINT32(p_fetch_addr_pre_v3, EHCIState),
VMSTATE_END_OF_LIST()
- }
+ },
+ .subsections = (const VMStateDescription * const []) {
+ &vmstate_ehci_fetch_addr_64,
+ NULL,
+ },
};
void usb_ehci_realize(EHCIState *s, DeviceState *dev, Error **errp)
^ permalink raw reply related [flat|nested] 69+ messages in thread
* Re: [PATCH v3 06/17] hw/usb/hcd-ehci: Change descriptor addresses to 64-bit
2026-04-22 9:21 ` Jamin Lin
@ 2026-04-22 14:37 ` Peter Xu
2026-04-23 1:48 ` Jamin Lin
0 siblings, 1 reply; 69+ messages in thread
From: Peter Xu @ 2026-04-22 14:37 UTC (permalink / raw)
To: Jamin Lin
Cc: Cédric Le Goater, philmd@linaro.org, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here, Troy Lee,
flwu@google.com, nabihestefan@google.com, Fabiano Rosas
On Wed, Apr 22, 2026 at 09:21:55AM +0000, Jamin Lin wrote:
> Hi Peter, Cédric and Philippe
>
> > Subject: Re: [PATCH v3 06/17] hw/usb/hcd-ehci: Change descriptor addresses to
> > 64-bit
> >
> > On Mon, Apr 20, 2026 at 05:56:11AM +0000, Jamin Lin wrote:
> > > Hi Peter, Philippe, Cédric
> >
> > Hi, Jamin,
> >
> > [...]
> >
> > > > > > @@ -2501,8 +2515,12 @@ const VMStateDescription vmstate_ehci = {
> > > > > > /* schedule state */
> > > > > > VMSTATE_UINT32(astate, EHCIState),
> > > > > > VMSTATE_UINT32(pstate, EHCIState),
> > > > > > - VMSTATE_UINT32(a_fetch_addr, EHCIState),
> > > > > > - VMSTATE_UINT32(p_fetch_addr, EHCIState),
> > > > > > + VMSTATE_UINT32_TEST(a_fetch_addr_pre_v3, EHCIState,
> > > > > > + ehci_core_is_before_version_3),
> > > > > > + VMSTATE_UINT32_TEST(p_fetch_addr_pre_v3, EHCIState,
> > > > > > + ehci_core_is_before_version_3),
> > > > > > + VMSTATE_UINT64_V(a_fetch_addr, EHCIState, 3),
> > > > > > + VMSTATE_UINT64_V(p_fetch_addr, EHCIState, 3),
> > > >
> > > > TL;DR: I feel like we still need machine type compat properties.
> > > >
> > >
> > > I don't understand this: Could you please describe it in more detail?
> >
> > See hw/core/machine.c and entries added into hw_compat_*[] arrays. IIUC,
> > if this is an important device and if we want to guarantee bidirectional
> > migration (I'll explain later), then we should stick with machine compat
> > properties.
> >
> > >
> > > > Details:
> > > >
> > > > When a v2 stream arrives, two _TEST()s will do the loading, then
> > > > post_load() extend it to 64bits, looks fine.
> > > >
> > > > When a v3 stream arrives, two _TEST()s got skipped then latter two take
> > effect.
> > > > post_load() skips. Looks fine.
> > > >
> > > > When migrating to another QEMU, due to the fact saving vmstates
> > > > always take vmsd's version declared (3), I don't see how it can
> > > > migrate back to a v2 stream; it didn't know about v3.
> > > >
> > > > Jiamin, have you tested migrating from a new QEMU binary back to
> > > > another old one? For upstream and serious devices, we need to
> > > > guarantee bi-directional migrations, back and forth.
> > > >
> > >
> > > Sorry, I am not familiar with the design of QEMU migration, and I don't know
> > how to test it.
> > > I added these hook functions based on Philippe's suggestion and review.
> > > Could you tell me how to test migration to ensure both version 3 and version
> > 2 are workable?
> >
> > Since this patch already modified VMSDs, I believe migration test should have
> > been carried out at the very minimum.. Logically if vmsd versioning is used,
> > we should also have tested forward migrations, because that's only for that.
> >
> > What I'm talking about is I think backward migration will fail.
> >
> > Forward migration describes the case when a VM hosted by an old QEMU
> > binary (e.g. QEMU v10.2.0) is migrated to a new QEMU (e.g., after this patch
> > applied on top of master).
> >
> > Backward migration describes the case when a VM hosted by a new QEMU
> > binary (e.g., after this patch applied on top of master) is migrated back to an
> > old QEMU binary (e.g. QEMU v10.2.0).
> >
> > For different devices, we should allow different level of support on migration.
> > Any device that may be important to either upstream QEMU or downstreams
> > should better allow bi-directional migration. In this case we need to use
> > machine compat properties I mentioned. I'm not yet sure where EHCI
> > controller falls e.g. v.s. XHCI.. when not sure, we can also just stick with
> > machine compat properties to be on the safe side.
> >
> > For more info, you can also refer to:
> >
> > https://www.qemu.org/docs/master/devel/migration/compatibility.html
> >
> > Thanks,
> >
> > --
> > Peter Xu
> Thanks for your support and the detailed explanation.
> Following Cédric’s comments, I now understand how to properly test migration. With the changes below, both forward and backward migration tests pass.
> Could you please review these changes, or would you prefer that I resend them as v4?
Per what I read on Phil's reply on the cover letter, he prefers you to
resend anyway. Better do it. Comments inline.
>
> Thanks again for your guidance and support.
>
> Jamin
>
> diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
> index 310183bbc4..bd165c793c 100644
> --- a/hw/usb/hcd-ehci.h
> +++ b/hw/usb/hcd-ehci.h
> @@ -264,6 +264,7 @@ struct EHCIState {
> uint32_t maxframes;
> bool caps_64bit_addr;
> uint32_t ctrldssegment_default;
> + bool migrate_fetch_addr_64bit;
>
> /*
> * EHCI spec version 1.0 Section 2.3
> @@ -321,7 +322,9 @@ struct EHCIState {
> DEFINE_PROP_UINT32("maxframes", _state, ehci.maxframes, 128), \
> DEFINE_PROP_BOOL("caps-64bit-addr", _state, ehci.caps_64bit_addr, false), \
> DEFINE_PROP_UINT32("ctrldssegment-default", _state, \
> - ehci.ctrldssegment_default, 0)
> + ehci.ctrldssegment_default, 0), \
> + DEFINE_PROP_BOOL("x-migrate-fetch-addr-64bit", _state, \
> + ehci.migrate_fetch_addr_64bit, true)
The diff looks a bit weird; this chunk is not present in hw/usb/hcd-ehci.h
in master branch, but maybe this series touched it.. in that case it's
fine.
>
> extern const VMStateDescription vmstate_ehci;
>
> diff --git a/hw/core/machine.c b/hw/core/machine.c
> index 0aa77a57e9..e77400c7ab 100644
> --- a/hw/core/machine.c
> +++ b/hw/core/machine.c
> @@ -41,6 +41,8 @@
> GlobalProperty hw_compat_10_2[] = {
> { "scsi-block", "migrate-pr", "off" },
> { "isa-cirrus-vga", "global-vmstate", "true" },
> + { "sysbus-ehci-usb", "x-migrate-fetch-addr-64bit", "off" },
> + { "pci-ehci-usb", "x-migrate-fetch-addr-64bit", "off" },
I'm still looking at master branch, vmstate_ehci is referenced in both
"ehci-sysbus" (vmstate_ehci_sysbus) and "ehci" (vmstate_ehci_pci). Here
you used different names, I'm not sure if it's relevant to your other
patches, please double check.
Also if there're two drivers involved, IIUC we should need to add two bool
properties.. I only saw one above. Again, not sure if it's relevant to
what your prior patch did, but please double check.
> };
> const size_t hw_compat_10_2_len = G_N_ELEMENTS(hw_compat_10_2);
>
> diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
> index 983b1731f9..87528ddc02 100644
> --- a/hw/usb/hcd-ehci.c
> +++ b/hw/usb/hcd-ehci.c
> @@ -2469,6 +2469,9 @@ static int usb_ehci_pre_save(void *opaque)
> ehci->last_run_ns -= (ehci->frindex - new_frindex) * UFRAME_TIMER_NS;
> ehci->frindex = new_frindex;
>
> + ehci->a_fetch_addr_pre_v3 = ehci->a_fetch_addr;
> + ehci->p_fetch_addr_pre_v3 = ehci->p_fetch_addr;
This looks fine if you always prepare the 32bit versions of the addr, but
it can also be put under a "if (!ehci_fetch_addr_64_needed(...))". Not a
big deal.
> +
> return 0;
> }
>
> @@ -2489,10 +2492,8 @@ static int usb_ehci_post_load(void *opaque, int version_id)
> }
> }
>
> - if (version_id < 3) {
> - s->a_fetch_addr = s->a_fetch_addr_pre_v3;
> - s->p_fetch_addr = s->p_fetch_addr_pre_v3;
> - }
> + s->a_fetch_addr = s->a_fetch_addr_pre_v3;
> + s->p_fetch_addr = s->p_fetch_addr_pre_v3;
This one looks risky, it will also run on new machine types, I think a "if
(!ehci_fetch_addr_64_needed(...))" is required here (unlike the pre_save),
otherwise I suspect you may overwrite the 64bits with 32bits after
migration. It may explode when high 32bits have something nonzero?
>
> return 0;
> }
> @@ -2523,14 +2524,29 @@ static void usb_ehci_vm_state_change(void *opaque, bool running, RunState state)
> }
> }
>
> -static bool ehci_core_is_before_version_3(void *opaque, int version_id)
> +static bool ehci_fetch_addr_64_needed(void *opaque)
> {
> - return version_id < 3;
> + EHCIState *s = opaque;
> +
> + return s->migrate_fetch_addr_64bit;
> }
Yes this is the traditional way.
>
> +static const VMStateDescription vmstate_ehci_fetch_addr_64 = {
> + .name = "ehci-core/fetch-addr64",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .needed = ehci_fetch_addr_64_needed,
> + .fields = (const VMStateField[]) {
> + /* mmio registers */
> + VMSTATE_UINT64(a_fetch_addr, EHCIState),
> + VMSTATE_UINT64(p_fetch_addr, EHCIState),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> const VMStateDescription vmstate_ehci = {
> .name = "ehci-core",
> - .version_id = 3,
> + .version_id = 2,
> .minimum_version_id = 1,
> .pre_save = usb_ehci_pre_save,
> .post_load = usb_ehci_post_load,
> @@ -2559,14 +2575,14 @@ const VMStateDescription vmstate_ehci = {
> /* schedule state */
> VMSTATE_UINT32(astate, EHCIState),
> VMSTATE_UINT32(pstate, EHCIState),
> - VMSTATE_UINT32_TEST(a_fetch_addr_pre_v3, EHCIState,
> - ehci_core_is_before_version_3),
> - VMSTATE_UINT32_TEST(p_fetch_addr_pre_v3, EHCIState,
> - ehci_core_is_before_version_3),
> - VMSTATE_UINT64_V(a_fetch_addr, EHCIState, 3),
> - VMSTATE_UINT64_V(p_fetch_addr, EHCIState, 3),
> + VMSTATE_UINT32(a_fetch_addr_pre_v3, EHCIState),
> + VMSTATE_UINT32(p_fetch_addr_pre_v3, EHCIState),
> VMSTATE_END_OF_LIST()
> - }
> + },
> + .subsections = (const VMStateDescription * const []) {
> + &vmstate_ehci_fetch_addr_64,
IMHO you don't need to make it a subsection, you can use
VMSTATE_UINT64_TEST().
Similarly you can also use VMSTATE_UINT32_TEST() to only migrate 32bit
versions in old machine types.
With those you can keep them together and add a comment, may look better
than subsections where you split them apart, it'll be harder to follow in
the future.
Thanks,
> + NULL,
> + },
> };
>
> void usb_ehci_realize(EHCIState *s, DeviceState *dev, Error **errp)
--
Peter Xu
^ permalink raw reply [flat|nested] 69+ messages in thread
* RE: [PATCH v3 06/17] hw/usb/hcd-ehci: Change descriptor addresses to 64-bit
2026-04-22 14:37 ` Peter Xu
@ 2026-04-23 1:48 ` Jamin Lin
2026-04-23 16:03 ` Peter Xu
0 siblings, 1 reply; 69+ messages in thread
From: Jamin Lin @ 2026-04-23 1:48 UTC (permalink / raw)
To: Peter Xu
Cc: Cédric Le Goater, philmd@linaro.org, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here, Troy Lee,
flwu@google.com, nabihestefan@google.com, Fabiano Rosas
Hi Peter,
> Subject: Re: [PATCH v3 06/17] hw/usb/hcd-ehci: Change descriptor addresses to
> 64-bit
>
> On Wed, Apr 22, 2026 at 09:21:55AM +0000, Jamin Lin wrote:
> > Hi Peter, Cédric and Philippe
> >
> > > Subject: Re: [PATCH v3 06/17] hw/usb/hcd-ehci: Change descriptor
> > > addresses to 64-bit
> > >
> > > On Mon, Apr 20, 2026 at 05:56:11AM +0000, Jamin Lin wrote:
> > > > Hi Peter, Philippe, Cédric
> > >
> > > Hi, Jamin,
> > >
> > > [...]
> > >
> > > > > > > @@ -2501,8 +2515,12 @@ const VMStateDescription vmstate_ehci
> = {
> > > > > > > /* schedule state */
> > > > > > > VMSTATE_UINT32(astate, EHCIState),
> > > > > > > VMSTATE_UINT32(pstate, EHCIState),
> > > > > > > - VMSTATE_UINT32(a_fetch_addr, EHCIState),
> > > > > > > - VMSTATE_UINT32(p_fetch_addr, EHCIState),
> > > > > > > + VMSTATE_UINT32_TEST(a_fetch_addr_pre_v3,
> EHCIState,
> > > > > > > +
> ehci_core_is_before_version_3),
> > > > > > > + VMSTATE_UINT32_TEST(p_fetch_addr_pre_v3,
> EHCIState,
> > > > > > > +
> ehci_core_is_before_version_3),
> > > > > > > + VMSTATE_UINT64_V(a_fetch_addr, EHCIState, 3),
> > > > > > > + VMSTATE_UINT64_V(p_fetch_addr, EHCIState, 3),
> > > > >
> > > > > TL;DR: I feel like we still need machine type compat properties.
> > > > >
> > > >
> > > > I don't understand this: Could you please describe it in more detail?
> > >
> > > See hw/core/machine.c and entries added into hw_compat_*[] arrays.
> > > IIUC, if this is an important device and if we want to guarantee
> > > bidirectional migration (I'll explain later), then we should stick
> > > with machine compat properties.
> > >
> > > >
> > > > > Details:
> > > > >
> > > > > When a v2 stream arrives, two _TEST()s will do the loading, then
> > > > > post_load() extend it to 64bits, looks fine.
> > > > >
> > > > > When a v3 stream arrives, two _TEST()s got skipped then latter
> > > > > two take
> > > effect.
> > > > > post_load() skips. Looks fine.
> > > > >
> > > > > When migrating to another QEMU, due to the fact saving vmstates
> > > > > always take vmsd's version declared (3), I don't see how it can
> > > > > migrate back to a v2 stream; it didn't know about v3.
> > > > >
> > > > > Jiamin, have you tested migrating from a new QEMU binary back to
> > > > > another old one? For upstream and serious devices, we need to
> > > > > guarantee bi-directional migrations, back and forth.
> > > > >
> > > >
> > > > Sorry, I am not familiar with the design of QEMU migration, and I
> > > > don't know
> > > how to test it.
> > > > I added these hook functions based on Philippe's suggestion and review.
> > > > Could you tell me how to test migration to ensure both version 3
> > > > and version
> > > 2 are workable?
> > >
> > > Since this patch already modified VMSDs, I believe migration test
> > > should have been carried out at the very minimum.. Logically if
> > > vmsd versioning is used, we should also have tested forward migrations,
> because that's only for that.
> > >
> > > What I'm talking about is I think backward migration will fail.
> > >
> > > Forward migration describes the case when a VM hosted by an old QEMU
> > > binary (e.g. QEMU v10.2.0) is migrated to a new QEMU (e.g., after
> > > this patch applied on top of master).
> > >
> > > Backward migration describes the case when a VM hosted by a new QEMU
> > > binary (e.g., after this patch applied on top of master) is migrated
> > > back to an old QEMU binary (e.g. QEMU v10.2.0).
> > >
> > > For different devices, we should allow different level of support on
> migration.
> > > Any device that may be important to either upstream QEMU or
> > > downstreams should better allow bi-directional migration. In this
> > > case we need to use machine compat properties I mentioned. I'm not
> > > yet sure where EHCI controller falls e.g. v.s. XHCI.. when not sure,
> > > we can also just stick with machine compat properties to be on the safe
> side.
> > >
> > > For more info, you can also refer to:
> > >
> > > https://www.qemu.org/docs/master/devel/migration/compatibility.html
> > >
> > > Thanks,
> > >
> > > --
> > > Peter Xu
> > Thanks for your support and the detailed explanation.
> > Following Cédric’s comments, I now understand how to properly test
> migration. With the changes below, both forward and backward migration tests
> pass.
> > Could you please review these changes, or would you prefer that I resend
> them as v4?
>
> Per what I read on Phil's reply on the cover letter, he prefers you to resend
> anyway. Better do it. Comments inline.
>
Thanks for the review and suggestion.
Will resend v4 soon and loop you.
> >
> > Thanks again for your guidance and support.
> >
> > Jamin
> >
> > diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index
> > 310183bbc4..bd165c793c 100644
> > --- a/hw/usb/hcd-ehci.h
> > +++ b/hw/usb/hcd-ehci.h
> > @@ -264,6 +264,7 @@ struct EHCIState {
> > uint32_t maxframes;
> > bool caps_64bit_addr;
> > uint32_t ctrldssegment_default;
> > + bool migrate_fetch_addr_64bit;
> >
> > /*
> > * EHCI spec version 1.0 Section 2.3 @@ -321,7 +322,9 @@ struct
> > EHCIState {
> > DEFINE_PROP_UINT32("maxframes", _state, ehci.maxframes, 128), \
> > DEFINE_PROP_BOOL("caps-64bit-addr", _state, ehci.caps_64bit_addr,
> false), \
> > DEFINE_PROP_UINT32("ctrldssegment-default", _state, \
> > - ehci.ctrldssegment_default, 0)
> > + ehci.ctrldssegment_default, 0), \
> > + DEFINE_PROP_BOOL("x-migrate-fetch-addr-64bit", _state, \
> > + ehci.migrate_fetch_addr_64bit, true)
>
> The diff looks a bit weird; this chunk is not present in hw/usb/hcd-ehci.h in
> master branch, but maybe this series touched it.. in that case it's fine.
>
> >
> > extern const VMStateDescription vmstate_ehci;
> >
> > diff --git a/hw/core/machine.c b/hw/core/machine.c index
> > 0aa77a57e9..e77400c7ab 100644
> > --- a/hw/core/machine.c
> > +++ b/hw/core/machine.c
> > @@ -41,6 +41,8 @@
> > GlobalProperty hw_compat_10_2[] = {
> > { "scsi-block", "migrate-pr", "off" },
> > { "isa-cirrus-vga", "global-vmstate", "true" },
> > + { "sysbus-ehci-usb", "x-migrate-fetch-addr-64bit", "off" },
> > + { "pci-ehci-usb", "x-migrate-fetch-addr-64bit", "off" },
>
> I'm still looking at master branch, vmstate_ehci is referenced in both
> "ehci-sysbus" (vmstate_ehci_sysbus) and "ehci" (vmstate_ehci_pci). Here you
> used different names, I'm not sure if it's relevant to your other patches, please
> double check.
>
It seems that we need to use the device type name here.
For the PCI EHCI controller, looking at hcd-ehci-pci.c:
The VMStateDescription name is "ehci":
static const VMStateDescription vmstate_ehci_pci = {
.name = "ehci",
.version_id = 2,
.minimum_version_id = 1,
.fields = (const VMStateField[]) {
VMSTATE_PCI_DEVICE(pcidev, EHCIPCIState),
VMSTATE_STRUCT(ehci, EHCIPCIState, 2, vmstate_ehci, EHCIState),
VMSTATE_END_OF_LIST()
}
};
However, the actual device type name is defined via TYPE_PCI_EHCI,
which resolves to "pci-ehci-usb" and is used when registering the device:
static void ehci_pci_register_types(void)
{
TypeInfo ehci_type_info = {
.parent = TYPE_PCI_EHCI,
.class_init = ehci_data_class_init,
};
int i;
type_register_static(&ehci_pci_type_info);
for (i = 0; i < ARRAY_SIZE(ehci_pci_info); i++) {
ehci_type_info.name = ehci_pci_info[i].name;
ehci_type_info.class_data = ehci_pci_info + i;
type_register_static(&ehci_type_info);
}
}
So in machine compat properties, it seems we should use the device type
name ("pci-ehci-usb"), rather than the VMStateDescription name ("ehci").
I also tried changing it to "ehci", but migration failed in that case,
so it looks like "pci-ehci-usb" is the correct one to use here.
Could you please confirm if this is the expected usage?
> Also if there're two drivers involved, IIUC we should need to add two bool
> properties.. I only saw one above. Again, not sure if it's relevant to what your
> prior patch did, but please double check.
>
> > };
> > const size_t hw_compat_10_2_len = G_N_ELEMENTS(hw_compat_10_2);
> >
> > diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index
> > 983b1731f9..87528ddc02 100644
> > --- a/hw/usb/hcd-ehci.c
> > +++ b/hw/usb/hcd-ehci.c
> > @@ -2469,6 +2469,9 @@ static int usb_ehci_pre_save(void *opaque)
> > ehci->last_run_ns -= (ehci->frindex - new_frindex) *
> UFRAME_TIMER_NS;
> > ehci->frindex = new_frindex;
> >
> > + ehci->a_fetch_addr_pre_v3 = ehci->a_fetch_addr;
> > + ehci->p_fetch_addr_pre_v3 = ehci->p_fetch_addr;
>
> This looks fine if you always prepare the 32bit versions of the addr, but it can
> also be put under a "if (!ehci_fetch_addr_64_needed(...))". Not a big deal.
>
Will add
> > +
> > return 0;
> > }
> >
> > @@ -2489,10 +2492,8 @@ static int usb_ehci_post_load(void *opaque, int
> version_id)
> > }
> > }
> >
> > - if (version_id < 3) {
> > - s->a_fetch_addr = s->a_fetch_addr_pre_v3;
> > - s->p_fetch_addr = s->p_fetch_addr_pre_v3;
> > - }
> > + s->a_fetch_addr = s->a_fetch_addr_pre_v3;
> > + s->p_fetch_addr = s->p_fetch_addr_pre_v3;
>
> This one looks risky, it will also run on new machine types, I think a "if
> (!ehci_fetch_addr_64_needed(...))" is required here (unlike the pre_save),
> otherwise I suspect you may overwrite the 64bits with 32bits after migration.
> It may explode when high 32bits have something nonzero?
>
Will add
> >
> > return 0;
> > }
> > @@ -2523,14 +2524,29 @@ static void usb_ehci_vm_state_change(void
> *opaque, bool running, RunState state)
> > }
> > }
> >
> > -static bool ehci_core_is_before_version_3(void *opaque, int
> > version_id)
> > +static bool ehci_fetch_addr_64_needed(void *opaque)
> > {
> > - return version_id < 3;
> > + EHCIState *s = opaque;
> > +
> > + return s->migrate_fetch_addr_64bit;
> > }
>
> Yes this is the traditional way.
>
> >
> > +static const VMStateDescription vmstate_ehci_fetch_addr_64 = {
> > + .name = "ehci-core/fetch-addr64",
> > + .version_id = 1,
> > + .minimum_version_id = 1,
> > + .needed = ehci_fetch_addr_64_needed,
> > + .fields = (const VMStateField[]) {
> > + /* mmio registers */
> > + VMSTATE_UINT64(a_fetch_addr, EHCIState),
> > + VMSTATE_UINT64(p_fetch_addr, EHCIState),
> > + VMSTATE_END_OF_LIST()
> > + }
> > +};
> > +
Will remove
> > const VMStateDescription vmstate_ehci = {
> > .name = "ehci-core",
> > - .version_id = 3,
> > + .version_id = 2,
> > .minimum_version_id = 1,
> > .pre_save = usb_ehci_pre_save,
> > .post_load = usb_ehci_post_load,
> > @@ -2559,14 +2575,14 @@ const VMStateDescription vmstate_ehci = {
> > /* schedule state */
> > VMSTATE_UINT32(astate, EHCIState),
> > VMSTATE_UINT32(pstate, EHCIState),
> > - VMSTATE_UINT32_TEST(a_fetch_addr_pre_v3, EHCIState,
> > - ehci_core_is_before_version_3),
> > - VMSTATE_UINT32_TEST(p_fetch_addr_pre_v3, EHCIState,
> > - ehci_core_is_before_version_3),
> > - VMSTATE_UINT64_V(a_fetch_addr, EHCIState, 3),
> > - VMSTATE_UINT64_V(p_fetch_addr, EHCIState, 3),
> > + VMSTATE_UINT32(a_fetch_addr_pre_v3, EHCIState),
> > + VMSTATE_UINT32(p_fetch_addr_pre_v3, EHCIState),
> > VMSTATE_END_OF_LIST()
> > - }
> > + },
> > + .subsections = (const VMStateDescription * const []) {
> > + &vmstate_ehci_fetch_addr_64,
>
> IMHO you don't need to make it a subsection, you can use
> VMSTATE_UINT64_TEST().
>
Will add
> Similarly you can also use VMSTATE_UINT32_TEST() to only migrate 32bit
> versions in old machine types.
>
Will add
> With those you can keep them together and add a comment, may look better
> than subsections where you split them apart, it'll be harder to follow in the
> future.
>
> Thanks,
>
> > + NULL,
> > + },
> > };
> >
> > void usb_ehci_realize(EHCIState *s, DeviceState *dev, Error **errp)
>
> --
> Peter Xu
Thanks,
Jamin
^ permalink raw reply [flat|nested] 69+ messages in thread
* Re: [PATCH v3 06/17] hw/usb/hcd-ehci: Change descriptor addresses to 64-bit
2026-04-23 1:48 ` Jamin Lin
@ 2026-04-23 16:03 ` Peter Xu
0 siblings, 0 replies; 69+ messages in thread
From: Peter Xu @ 2026-04-23 16:03 UTC (permalink / raw)
To: Jamin Lin
Cc: Cédric Le Goater, philmd@linaro.org, Peter Maydell,
Steven Lee, Troy Lee, Kane Chen, Andrew Jeffery, Joel Stanley,
open list:ASPEED BMCs, open list:All patches CC here, Troy Lee,
flwu@google.com, nabihestefan@google.com, Fabiano Rosas
On Thu, Apr 23, 2026 at 01:48:36AM +0000, Jamin Lin wrote:
> It seems that we need to use the device type name here.
Heh, yeah, you should be right.
--
Peter Xu
^ permalink raw reply [flat|nested] 69+ messages in thread
end of thread, other threads:[~2026-04-23 16:04 UTC | newest]
Thread overview: 69+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-16 1:49 [PATCH v3 00/17] hw/usb/ehci: Add 64-bit descriptor addressing support Jamin Lin
2026-04-16 1:49 ` [PATCH v3 01/17] hw/usb/hcd-ehci: Remove unused EHCIfstn structure and dead code Jamin Lin
2026-04-16 12:09 ` BALATON Zoltan
2026-04-17 1:16 ` Jamin Lin
2026-04-17 2:25 ` Jamin Lin
2026-04-17 9:47 ` BALATON Zoltan
2026-04-20 3:46 ` Jamin Lin
2026-04-17 6:30 ` Cédric Le Goater
2026-04-16 1:49 ` [PATCH v3 02/17] hw/usb/hcd-ehci.h: Fix coding style issues reported by checkpatch Jamin Lin
2026-04-17 6:32 ` Philippe Mathieu-Daudé
2026-04-16 1:49 ` [PATCH v3 03/17] hw/usb/hcd-ehci.c: " Jamin Lin
2026-04-17 6:31 ` Cédric Le Goater
2026-04-17 6:32 ` Philippe Mathieu-Daudé
2026-04-16 1:49 ` [PATCH v3 04/17] hw/usb/hcd-ehci.c: Replace fprintf(stderr, ...) with qemu_log_mask(LOG_GUEST_ERROR) Jamin Lin
2026-04-17 6:31 ` Philippe Mathieu-Daudé
2026-04-17 8:41 ` Jamin Lin
2026-04-16 1:49 ` [PATCH v3 05/17] hw/usb/hcd-ehci: Replace DPRINTF debug logs with trace events Jamin Lin
2026-04-17 5:04 ` Philippe Mathieu-Daudé
2026-04-16 1:49 ` [PATCH v3 06/17] hw/usb/hcd-ehci: Change descriptor addresses to 64-bit Jamin Lin
2026-04-17 4:54 ` Philippe Mathieu-Daudé
2026-04-17 7:01 ` Cédric Le Goater
2026-04-17 15:10 ` Peter Xu
2026-04-20 5:56 ` Jamin Lin
2026-04-20 13:34 ` Peter Xu
2026-04-22 9:21 ` Jamin Lin
2026-04-22 14:37 ` Peter Xu
2026-04-23 1:48 ` Jamin Lin
2026-04-23 16:03 ` Peter Xu
2026-04-20 16:04 ` Cédric Le Goater
2026-04-22 9:10 ` Jamin Lin
2026-04-16 1:49 ` [PATCH v3 07/17] hw/usb/hcd-ehci: Add property to advertise 64-bit addressing capability Jamin Lin
2026-04-17 4:55 ` Philippe Mathieu-Daudé
2026-04-16 1:49 ` [PATCH v3 08/17] hw/usb/hcd-ehci: Reject CTRLDSSEGMENT writes without 64-bit capability Jamin Lin
2026-04-17 6:33 ` Philippe Mathieu-Daudé
2026-04-17 8:07 ` Jamin Lin
2026-04-16 1:49 ` [PATCH v3 09/17] hw/usb/hcd-ehci: Implement 64-bit QH descriptor addressing Jamin Lin
2026-04-17 5:03 ` Philippe Mathieu-Daudé
2026-04-17 5:40 ` Jamin Lin
2026-04-17 6:14 ` Philippe Mathieu-Daudé
2026-04-17 7:02 ` Jamin Lin
2026-04-16 1:49 ` [PATCH v3 10/17] hw/usb/hcd-ehci: Implement 64-bit qTD " Jamin Lin
2026-04-17 6:14 ` Philippe Mathieu-Daudé
2026-04-16 1:49 ` [PATCH v3 11/17] hw/usb/hcd-ehci: Implement 64-bit iTD " Jamin Lin
2026-04-17 6:15 ` Philippe Mathieu-Daudé
2026-04-16 1:49 ` [PATCH v3 12/17] hw/usb/hcd-ehci: Implement 64-bit siTD " Jamin Lin
2026-04-17 6:27 ` Philippe Mathieu-Daudé
2026-04-17 7:44 ` Jamin Lin
2026-04-17 8:42 ` Philippe Mathieu-Daudé
2026-04-16 1:49 ` [PATCH v3 13/17] hw/usb/hcd-ehci: Add descriptor address offset property Jamin Lin
2026-04-17 6:23 ` Philippe Mathieu-Daudé
2026-04-22 5:00 ` Jamin Lin
2026-04-17 6:45 ` Cédric Le Goater
2026-04-17 7:08 ` Philippe Mathieu-Daudé
2026-04-20 5:47 ` Jamin Lin
2026-04-20 7:08 ` Cédric Le Goater
2026-04-22 6:58 ` Jamin Lin
2026-04-16 1:50 ` [PATCH v3 14/17] hw/arm/aspeed_ast27x0: Enable 64-bit EHCI DMA addressing Jamin Lin
2026-04-17 6:23 ` Philippe Mathieu-Daudé
2026-04-16 1:50 ` [PATCH v3 15/17] hw/arm/aspeed_ast27x0: Set EHCI descriptor address offset Jamin Lin
2026-04-17 6:25 ` Philippe Mathieu-Daudé
2026-04-22 5:03 ` Jamin Lin
2026-04-16 1:50 ` [PATCH v3 16/17] tests/functional/arm/test_aspeed_ast2600_sdk: Add USB EHCI test for AST2600 SDK Jamin Lin
2026-04-17 6:27 ` Philippe Mathieu-Daudé
2026-04-17 7:40 ` Jamin Lin
2026-04-17 8:44 ` Philippe Mathieu-Daudé
2026-04-17 8:50 ` Jamin Lin
2026-04-16 1:50 ` [PATCH v3 17/17] tests/functional/aarch64/test_aspeed_ast2700: Add USB EHCI test for AST2700 A1/A2 Jamin Lin
2026-04-17 6:27 ` Philippe Mathieu-Daudé
2026-04-17 6:35 ` [PATCH v3 00/17] hw/usb/ehci: Add 64-bit descriptor addressing support Philippe Mathieu-Daudé
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.