RE: [PATCH v3 4/8] i2c/aspeed: Fix DMA receive first-byte handling for block reads

Jamin Lin <[email protected]>
Newsgroups org.nongnu.qemu-arm,org.nongnu.qemu-devel
Message-ID <TYZPR06MB49809554770467FE75ECEAA9FCDD2@TYZPR06MB4980.apcprd06.prod.outlook.com>
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 */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.