@samitouri / QOSamiQemu / commits / 2d3dc20d9d

hw/i3c: fix CMD/data FIFO depth reset values to match real silicon

The Linux DW-I3C master driver infers controller queue depths at probe by reading two status registers that report free queue slots, which at probe (queues empty) equals the full depth. It then uses those values to gate every I3C transfer -- any batch whose word count exceeds the advertised depth is rejected with -EOPNOTSUPP. QUEUE_STATUS_LEVEL (0x4c) [7:0] -> cmdfifodepth (cmd slots) DATA_BUFFER_STATUS_LEVEL (0x50) [7:0] -> datafifodepth (32-bit words) Per the AST2600 datasheet the reset values are 0x10 and 0x40 (16 cmd slots, 64 words = 256 B). QEMU was advertising 0x02 and 0x10, making the kernel believe the controller can only do 64-byte transfers. The visible symptom was -EOPNOTSUPP on any I3C transfer whose payload exceeded 64 B (datafifodepth = 0x10 = 16 words = 64 B). The underlying FIFOs in QEMU were already allocated at the right size (fifo32_create takes word counts; the existing defaults give 16 cmd slots and 64 data words). Only the advertised reset values were wrong. Correct the reset values in dw_i3c_resets[], and additionally drive the advertised depths from the queue-capacity configs in the reset handlers (as is already done for the device/char table pointers), so a configured override is reflected in what the guest reads instead of being silently ignored. The advertised fields are 8-bit, so the depth saturates at 255 regardless of the wider capacity configs. With this fix the guest sees datafifodepth=64 words and accepts transfers up to 256 B. Fixes: e974c6957576 ("hw/i3c/dw-i3c: Add more reset values") Cc: qemu-stable@nongnu.org Signed-off-by: Jithu Joseph <jithu.joseph@oss.qualcomm.com> Reviewed-by: Jamin Lin <jamin_lin@aspeedtech.com> Link: https://lore.kernel.org/qemu-devel/20260604142207.2118098-2-jithu.joseph@oss.qualcomm.com Signed-off-by: Cédric Le Goater <clg@redhat.com>

Jithu Joseph committed Jun 4, 2026 at 07:22 UTC 2d3dc20d9d716729e06093311f678dc739affe5b
1 file changed +10 -2
hw/i3c/dw-i3c.c
+10 -2
@@ -282,8 +282,8 @@ static const uint32_t dw_i3c_resets[DW_I3C_NR_REGS] = {
282 [R_QUEUE_THLD_CTRL] = 0x01000101,
283 [R_DATA_BUFFER_THLD_CTRL] = 0x01010100,
284 [R_SLV_EVENT_CTRL] = 0x0000000b,
285 - [R_QUEUE_STATUS_LEVEL] = 0x00000002,
286 - [R_DATA_BUFFER_STATUS_LEVEL] = 0x00000010,
285 + [R_QUEUE_STATUS_LEVEL] = 0x00000010,
286 + [R_DATA_BUFFER_STATUS_LEVEL] = 0x00000040,
287 [R_PRESENT_STATE] = 0x00000003,
288 [R_I3C_VER_ID] = 0x3130302a,
289 [R_I3C_VER_TYPE] = 0x6c633033,
@@ -947,6 +947,10 @@ static void dw_i3c_reset(DeviceState *dev)
947 s->cfg.dev_char_table_pointer);
948 ARRAY_FIELD_DP32(s->regs, DEV_CHAR_TABLE_POINTER, DEV_CHAR_TABLE_DEPTH,
949 s->cfg.dev_char_table_depth);
950 + ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, CMD_QUEUE_EMPTY_LOC,
951 + s->cfg.cmd_resp_queue_capacity_bytes);
952 + ARRAY_FIELD_DP32(s->regs, DATA_BUFFER_STATUS_LEVEL, TX_BUF_EMPTY_LOC,
953 + s->cfg.tx_rx_queue_capacity_bytes);
954
955 dw_i3c_cmd_queue_reset(s);
956 dw_i3c_resp_queue_reset(s);
@@ -1793,6 +1797,10 @@ static void dw_i3c_reset_enter(Object *obj, ResetType type)
1797 s->cfg.dev_char_table_pointer);
1798 ARRAY_FIELD_DP32(s->regs, DEV_CHAR_TABLE_POINTER, DEV_CHAR_TABLE_DEPTH,
1799 s->cfg.dev_char_table_depth);
1800 + ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, CMD_QUEUE_EMPTY_LOC,
1801 + s->cfg.cmd_resp_queue_capacity_bytes);
1802 + ARRAY_FIELD_DP32(s->regs, DATA_BUFFER_STATUS_LEVEL, TX_BUF_EMPTY_LOC,
1803 + s->cfg.tx_rx_queue_capacity_bytes);
1804 }
1805
1806 static void dw_i3c_realize(DeviceState *dev, Error **errp)