Hi Cédric

> Subject: Re: [PATCH v1 4/8] hw/i2c/aspeed_i2c: Fix DMA moving data into
> incorrect address
> 
> On 2/2/26 07:19, Jamin Lin wrote:
> > From: Jamin Lin <[email protected]>
> >
> > In the previous design, the I2C model updated dma_dram_offset only
> > when firmware programmed the RX/TX DMA buffer address registers. The
> > firmware used to rewrite these registers before issuing each DMA command.
> >
> > The firmware driver behavior has changed to program the DMA address
> > registers only once during I2C initialization. As a result, the I2C
> > model no longer refreshes dma_dram_offset, causing DMA to move data
> > into an incorrect DRAM address.
> >
> > Fix this by introducing helper functions to update dma_dram_offset
> > from the DMA address registers, and invoke them right before handling
> > TX/RX DMA operations. This guarantees DMA always uses the correct
> > buffer address even if the registers are programmed only once.
> >
> > Signed-off-by: Jamin Lin <[email protected]>
> 
> Should we backport to stable branches too ?
> 

It would be great if this could also be applied to the stable branches.
I will add a Fixes tag.

Thanks-Jamin

> Thanks,
> 
> C.
> 
> 
> > ---
> >   hw/i2c/aspeed_i2c.c | 87
> +++++++++++++++++++++++++++++++--------------
> >   1 file changed, 61 insertions(+), 26 deletions(-)
> >
> > diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c index
> > 1ee73a8f5e..fb3d6a5600 100644
> > --- a/hw/i2c/aspeed_i2c.c
> > +++ b/hw/i2c/aspeed_i2c.c
> > @@ -116,8 +116,6 @@ static uint64_t
> aspeed_i2c_bus_old_read(AspeedI2CBus *bus, hwaddr offset,
> >               value = -1;
> >               break;
> >           }
> > -
> > -        value = extract64(bus->dma_dram_offset, 0, 32);
> >           break;
> >       case A_I2CD_DMA_LEN:
> >           if (!aic->has_dma) {
> > @@ -221,6 +219,64 @@ static uint8_t aspeed_i2c_get_state(AspeedI2CBus
> *bus)
> >       return SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD,
> TX_STATE);
> >   }
> >
> > +/*
> > + * The AST2700 support the maximum DRAM size is 8 GB.
> > + * The DRAM offset range is from 0x0_0000_0000 to
> > + * 0x1_FFFF_FFFF and it is enough to use bits [33:0]
> > + * saving the dram offset.
> > + * Therefore, save the high part physical address bit[1:0]
> > + * of Tx/Rx buffer address as dma_dram_offset bit[33:32].
> > + */
> > +static void aspeed_i2c_set_tx_dma_dram_offset(AspeedI2CBus *bus) {
> > +    AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
> > +    uint32_t value;
> > +
> > +    assert(aic->has_dma);
> > +
> > +    if (aspeed_i2c_is_new_mode(bus->controller)) {
> > +        value = bus->regs[R_I2CM_DMA_TX_ADDR];
> > +        bus->dma_dram_offset =
> > +            deposit64(bus->dma_dram_offset, 0, 32,
> > +                      FIELD_EX32(value, I2CM_DMA_TX_ADDR,
> ADDR));
> > +        if (!aic->has_dma64) {
> > +            value = bus->regs[R_I2CM_DMA_TX_ADDR_HI];
> > +            bus->dma_dram_offset =
> > +                deposit64(bus->dma_dram_offset, 32, 32,
> > +                          extract32(value, 0, 2));
> > +        }
> > +    } else {
> > +        value = bus->regs[R_I2CD_DMA_ADDR];
> > +        bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 0,
> 32,
> > +                                         value & 0x3ffffffc);
> > +    }
> > +}
> > +
> > +static void aspeed_i2c_set_rx_dma_dram_offset(AspeedI2CBus *bus) {
> > +    AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
> > +    uint32_t value;
> > +
> > +    assert(aic->has_dma);
> > +
> > +    if (aspeed_i2c_is_new_mode(bus->controller)) {
> > +        value = bus->regs[R_I2CM_DMA_RX_ADDR];
> > +        bus->dma_dram_offset =
> > +            deposit64(bus->dma_dram_offset, 0, 32,
> > +                      FIELD_EX32(value, I2CM_DMA_RX_ADDR,
> ADDR));
> > +        if (!aic->has_dma64) {
> > +            value = bus->regs[R_I2CM_DMA_RX_ADDR_HI];
> > +            bus->dma_dram_offset =
> > +                deposit64(bus->dma_dram_offset, 32, 32,
> > +                          extract32(value, 0, 2));
> > +        }
> > +    } else {
> > +        value = bus->regs[R_I2CD_DMA_ADDR];
> > +        bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 0,
> 32,
> > +                                         value & 0x3ffffffc);
> > +    }
> > +}
> > +
> >   static int aspeed_i2c_dma_read(AspeedI2CBus *bus, uint8_t *data)
> >   {
> >       MemTxResult result;
> > @@ -270,6 +326,7 @@ static int aspeed_i2c_bus_send(AspeedI2CBus *bus)
> >           if (aspeed_i2c_is_new_mode(bus->controller)) {
> >               ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS,
> TX_LEN, 0);
> >           }
> > +        aspeed_i2c_set_tx_dma_dram_offset(bus);
> >           while (bus->regs[reg_dma_len]) {
> >               uint8_t data;
> >               ret = aspeed_i2c_dma_read(bus, &data); @@ -335,6
> +392,7
> > @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus)
> >               ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS,
> RX_LEN, 0);
> >           }
> >
> > +        aspeed_i2c_set_rx_dma_dram_offset(bus);
> >           while (bus->regs[reg_dma_len]) {
> >               MemTxResult result;
> >
> > @@ -401,6 +459,7 @@ static uint8_t aspeed_i2c_get_addr(AspeedI2CBus
> *bus)
> >       } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd,
> TX_DMA_EN)) {
> >           uint8_t data;
> >
> > +        aspeed_i2c_set_tx_dma_dram_offset(bus);
> >           aspeed_i2c_dma_read(bus, &data);
> >           return data;
> >       } else {
> > @@ -657,16 +716,10 @@ static void
> aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset,
> >       case A_I2CM_DMA_TX_ADDR:
> >           bus->regs[R_I2CM_DMA_TX_ADDR] = FIELD_EX32(value,
> I2CM_DMA_TX_ADDR,
> >                                                      ADDR);
> > -        bus->dma_dram_offset =
> > -            deposit64(bus->dma_dram_offset, 0, 32,
> > -                      FIELD_EX32(value, I2CM_DMA_TX_ADDR,
> ADDR));
> >           break;
> >       case A_I2CM_DMA_RX_ADDR:
> >           bus->regs[R_I2CM_DMA_RX_ADDR] = FIELD_EX32(value,
> I2CM_DMA_RX_ADDR,
> >                                                      ADDR);
> > -        bus->dma_dram_offset =
> > -            deposit64(bus->dma_dram_offset, 0, 32,
> > -                      FIELD_EX32(value, I2CM_DMA_RX_ADDR,
> ADDR));
> >           break;
> >       case A_I2CM_DMA_LEN:
> >           w1t = FIELD_EX32(value, I2CM_DMA_LEN, RX_BUF_LEN_W1T)
> || @@
> > -748,15 +801,6 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus
> *bus, hwaddr offset,
> >           qemu_log_mask(LOG_UNIMP, "%s: Slave mode DMA TX is not
> implemented\n",
> >                         __func__);
> >           break;
> > -
> > -    /*
> > -     * The AST2700 support the maximum DRAM size is 8 GB.
> > -     * The DRAM offset range is from 0x0_0000_0000 to
> > -     * 0x1_FFFF_FFFF and it is enough to use bits [33:0]
> > -     * saving the dram offset.
> > -     * Therefore, save the high part physical address bit[1:0]
> > -     * of Tx/Rx buffer address as dma_dram_offset bit[33:32].
> > -     */
> >       case A_I2CM_DMA_TX_ADDR_HI:
> >           if (!aic->has_dma64) {
> >               qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits
> > support\n", @@ -766,8 +810,6 @@ static void
> aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset,
> >           bus->regs[R_I2CM_DMA_TX_ADDR_HI] = FIELD_EX32(value,
> >
> I2CM_DMA_TX_ADDR_HI,
> >
> ADDR_HI);
> > -        bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 32,
> 32,
> > -                                         extract32(value, 0, 2));
> >           break;
> >       case A_I2CM_DMA_RX_ADDR_HI:
> >           if (!aic->has_dma64) {
> > @@ -778,8 +820,6 @@ static void
> aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset,
> >           bus->regs[R_I2CM_DMA_RX_ADDR_HI] = FIELD_EX32(value,
> >
> I2CM_DMA_RX_ADDR_HI,
> >
> ADDR_HI);
> > -        bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 32,
> 32,
> > -                                         extract32(value, 0, 2));
> >           break;
> >       case A_I2CS_DMA_TX_ADDR_HI:
> >           qemu_log_mask(LOG_UNIMP,
> > @@ -795,8 +835,6 @@ static void
> aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset,
> >           bus->regs[R_I2CS_DMA_RX_ADDR_HI] = FIELD_EX32(value,
> >
> I2CS_DMA_RX_ADDR_HI,
> >
> ADDR_HI);
> > -        bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 32,
> 32,
> > -                                         extract32(value, 0, 2));
> >           break;
> >       default:
> >           qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"
> > HWADDR_PRIx "\n", @@ -887,9 +925,6 @@ static void
> aspeed_i2c_bus_old_write(AspeedI2CBus *bus, hwaddr offset,
> >               qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA
> support\n",  __func__);
> >               break;
> >           }
> > -
> > -        bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 0, 32,
> > -                                         value & 0x3ffffffc);
> >           break;
> >
> >       case A_I2CD_DMA_LEN:

Reply via email to