qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v2] i2c: Fix SMBus read transactions to avoid do


From: Frederic Konrad
Subject: Re: [Qemu-devel] [PATCH v2] i2c: Fix SMBus read transactions to avoid double events
Date: Wed, 6 Jul 2016 08:57:58 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.8.0

On 06/28/2016 09:30 PM, address@hidden wrote:
> From: Corey Minyard <address@hidden>
> 
> Change 2293c27faddf (i2c: implement broadcast write) added broadcast
> capability to the I2C bus, but it broke SMBus read transactions.
> An SMBus read transaction does two i2c_start_transaction() calls
> without an intervening i2c_end_transfer() call.  This will
> result in i2c_start_transfer() adding the same device to the
> current_devs list twice, and then the ->event() for the same
> device gets called twice in the second call to i2c_start_transfer(),
> resulting in the smbus code getting confused.

Hi Corey,

I didn't know that we can do two i2c_start_transfer without an
end_transfert in the middle. Maybe worth a comment in the code?

Otherwise:
Reviewed-by: KONRAD Frederic <address@hidden>
Tested-by: KONRAD Frederic <address@hidden>

Thanks,
Fred

> 
> Note that this happens even with pure I2C devices when simulating
> SMBus over I2C.
> 
> This fix only scans the bus if the current set of devices is empty.
> This means that the current set of devices stays fixed until
> i2c_end_transfer() is called, which is really what you want.
> 
> This also deletes the empty check from the top of i2c_end_transfer().
> It's unnecessary, and it prevents the broadcast variable from being
> set to false at the end of the transaction if no devices were on
> the bus.
> 
> Cc: KONRAD Frederic <address@hidden>
> Cc: Alistair Francis <address@hidden>
> Cc: Peter Crosthwaite <address@hidden>
> Cc: Kwon <address@hidden>
> Cc: Peter Maydell <address@hidden>
> Signed-off-by: Corey Minyard <address@hidden>
> ---
>  hw/i2c/core.c | 28 +++++++++++++++-------------
>  1 file changed, 15 insertions(+), 13 deletions(-)
> 
> This fix should work with I2C devices as well as SMBus devices.
> 
> Sorry for not thinking it through all the way before.
> 
> diff --git a/hw/i2c/core.c b/hw/i2c/core.c
> index abb3efb..6313d31 100644
> --- a/hw/i2c/core.c
> +++ b/hw/i2c/core.c
> @@ -101,15 +101,21 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, 
> int recv)
>          bus->broadcast = true;
>      }
>  
> -    QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
> -        DeviceState *qdev = kid->child;
> -        I2CSlave *candidate = I2C_SLAVE(qdev);
> -        if ((candidate->address == address) || (bus->broadcast)) {
> -            node = g_malloc(sizeof(struct I2CNode));
> -            node->elt = candidate;
> -            QLIST_INSERT_HEAD(&bus->current_devs, node, next);
> -            if (!bus->broadcast) {
> -                break;
> +    /*
> +     * If there are already devices in the list, that means we are in
> +     * the middle of a transaction and we shouldn't rescan the bus.
> +     */
> +    if (QLIST_EMPTY(&bus->current_devs)) {
> +        QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
> +            DeviceState *qdev = kid->child;
> +            I2CSlave *candidate = I2C_SLAVE(qdev);
> +            if ((candidate->address == address) || (bus->broadcast)) {
> +                node = g_malloc(sizeof(struct I2CNode));
> +                node->elt = candidate;
> +                QLIST_INSERT_HEAD(&bus->current_devs, node, next);
> +                if (!bus->broadcast) {
> +                    break;
> +                }
>              }
>          }
>      }
> @@ -134,10 +140,6 @@ void i2c_end_transfer(I2CBus *bus)
>      I2CSlaveClass *sc;
>      I2CNode *node, *next;
>  
> -    if (QLIST_EMPTY(&bus->current_devs)) {
> -        return;
> -    }
> -
>      QLIST_FOREACH_SAFE(node, &bus->current_devs, next, next) {
>          sc = I2C_SLAVE_GET_CLASS(node->elt);
>          if (sc->event) {
> 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]