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

Cédric Le Goater <[email protected]>
Newsgroups org.nongnu.qemu-arm,org.nongnu.qemu-devel
Message-ID <[email protected]>
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 */
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.