Jamin, I would appreciate a feedback from you on this change.
On 8/10/26 20:57, Mikail Sadic wrote:
An SMBus block read (I2C_M_RECV_LEN) reads the block length from the first received byte. The Linux/U-Boot aspeed I2C driver obtains that first byte from the I2CC_STS_AND_BUFF register (modelled here as reg_byte_buf), even when the transfer uses DMA. The DMA receive path, however, only wrote received data to DRAM and never updated reg_byte_buf, so block reads read a stale/zero length. Mirror the first DMA-received byte into reg_byte_buf so that I2C_M_RECV_LEN transfers using DMA report the correct block length. This is required for the ucd9000 driver, which uses i2c_smbus_read_block_data(). Signed-off-by: Mikail Sadic <[email protected]>
Does this change deserve a Fixes: tag ? Thanks, C.
--- hw/i2c/aspeed_i2c.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c index 27afcaecee..facb54d27e 100644 --- a/hw/i2c/aspeed_i2c.c +++ b/hw/i2c/aspeed_i2c.c @@ -365,6 +365,7 @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus) uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus); uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); + bool first_dma_byte; int pool_rx_count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, RX_SIZE) + 1;@@ -391,6 +392,7 @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus)}aspeed_i2c_set_rx_dma_dram_offset(bus);+ first_dma_byte = true; while (bus->regs[reg_dma_len]) { MemTxResult result;@@ -407,6 +409,11 @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus)return; }+ /* Mirror first byte to reg_byte_buf for I2C_M_RECV_LEN. */+ if (first_dma_byte) { + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, data); + first_dma_byte = false; + } bus->dma_dram_offset++; bus->regs[reg_dma_len]--; /* In new mode, keep track of how many bytes we RXed */
