Hi Mikail,
> -----Original Message-----
> From: Cédric Le Goater <[email protected]>
> Sent: Tuesday, August 11, 2026 12:31 PM
> To: Mikail Sadic <[email protected]>; [email protected]
> Cc: [email protected]; [email protected]; [email protected];
> [email protected]; [email protected]; Steven Lee
> <[email protected]>; [email protected]; Jamin Lin
> <[email protected]>; Kane Chen <[email protected]>;
> [email protected]; [email protected]; [email protected];
> [email protected]; [email protected]; [email protected]
> Subject: Re: [PATCH v3 4/8] i2c/aspeed: Fix DMA receive first-byte handling
> for
> block reads
>
> Jamin,
>
> I would appreciate a feedback from you on this change.
>
Hi Mikail,
Before going further -- are you sure this value is correct in DMA mode?
AST2600/AST2700 datasheet, I2CC08 (Transmit/Receive Byte Buffer):
15:8 RO Receive Byte Buffer
"This register is valid when DMA Buffer is not enabled."
That reads to me as: the receive byte buffer only holds a defined value
in pool buffer mode, not when DMA is enabled. If that is right, then
modelling it in the DMA path makes QEMU report a block length the
silicon would not provide, and a driver relying on it would pass under
emulation but fail on a real board.
Have you confirmed this works on real hardware, or only in QEMU?
If the datasheet reading is correct, I think the mirror belongs in the
pool buffer path instead -- ast2600_i2c_setup_buff_rx() does not enable
the DMA buffer, yet aspeed_i2c_bus_recv()'s RX_BUFF_EN branch never
updates reg_byte_buf either. That is also the default mode:
i2c-ast2600.c sets mode = BUFF_MODE and no AST2600 board DT overrides
aspeed,transfer-mode.
1. On AST2600, is your setup using DMA mode or buffer mode? ---> AS far As I
know, customers should use the buffer mode because I2C DMA mode issue in
AST2600.
2. Are you testing AST2700 as well? There both modes set RX_DMA_EN (DMA and
Buffer mode) --
ast2700_i2c_setup_buff_rx() does too -- so I2CC08[15:8] would never
be valid, and the driver reads the length from "BYTE_DATA_LOG (0x84)",
which QEMU does not model at all. That would need a separate patch.
https://github.com/AspeedTech-BMC/linux/commit/f9938ec5799e83f5b09d3a7acac7287c0cde2c26
https://patchwork.kernel.org/project/qemu-devel/patch/[email protected]/
Thanks,
Jamin
> 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 */