Re: [PATCH] CHROMIUM: tpm: tpm_tis_i2c: Lock the I2C adapter for asequence of requests.

From: Bryan Freed
Date: Wed May 02 2012 - 13:25:12 EST


(Sorry for resending...)

Andi, it is not clear what i2c_smbus_* functions in particular will
improve upon this change.

All i2c_smbus_* functions go through i2c_smbus_xfer() which at some
point will i2c_lock_adapter() for each request.
This is true for adapters that support SMBUS (where the lock occurs
directly in i2c_smbus_xfer()) or just I2C (where the lock occurs in
i2c_transfer() called through i2c_smbus_xfer_emulated()).

The goal of this change is for the tpm_tis_i2c driver to be able to
lock an adapter over the duration of several I2C requests.
Presumably, that is why i2c_lock_adapter() is exported.

bryan.

On Wed, May 2, 2012 at 8:17 AM, Andi Shyti <andi.shyti@xxxxxxxxx> wrote:
> Hi again :),
>
> On Wed, May 02, 2012 at 04:03:36PM +0200, Peter Huewe wrote:
>> From: Bryan Freed <bfreed@xxxxxxxxxxxx>
>>
>> This is derived from Peter Huewe's recommended fix:
>>
>> On some ChromeOS systems, a TPM sharing the I2C bus with another device
>> gets confused when it sees I2C requests to that other device.
>> This change locks the I2C adapter for the duration of the full sequence
>> of I2C requests the TPM needs to complete.
>>
>> smbus_xfer is not supported, but SMBUS is not supported by the original
>> driver, either.
>>
>> Signed-off-by: Bryan Freed <bfreed@xxxxxxxxxxxx>
>> Signed-off-by: Peter Huewe <peter.huewe@xxxxxxxxxxxx>
>> ---
>>  drivers/char/tpm/tpm_tis_i2c.c |   42 ++++++++++++++++++++++++++++++++++++---
>>  1 files changed, 38 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/char/tpm/tpm_tis_i2c.c b/drivers/char/tpm/tpm_tis_i2c.c
>> index 8975abf..e68f209 100644
>> --- a/drivers/char/tpm/tpm_tis_i2c.c
>> +++ b/drivers/char/tpm/tpm_tis_i2c.c
>> @@ -61,6 +61,28 @@ static struct tpm_inf_dev tpm_dev;
>>
>>
>>  /*
>> + * Copy i2c-core:i2c_transfer() as close as possible without the adapter locks
>> + * and algorithm check.  These are done by the caller for atomicity.
>> + */
>> +static int i2c_transfer_nolock(struct i2c_adapter *adap, struct i2c_msg *msgs,
>> +                            int num)
>> +{
>> +     unsigned long orig_jiffies;
>> +     int ret, try;
>> +
>> +     /* Retry automatically on arbitration loss */
>> +     orig_jiffies = jiffies;
>> +     for (ret = 0, try = 0; try <= adap->retries; try++) {
>> +             ret = adap->algo->master_xfer(adap, msgs, num);
>> +             if (ret != -EAGAIN)
>> +                     break;
>> +             if (time_after(jiffies, orig_jiffies + adap->timeout))
>> +                     break;
>> +     }
>> +     return ret;
>> +}
>> +
>> +/*
>>   * iic_tpm_read() - read from TPM register
>>   * @addr: register address to read from
>>   * @buffer: provided by caller
>> @@ -83,8 +105,13 @@ static int iic_tpm_read(u8 addr, u8 *buffer, size_t len)
>>       int rc;
>>       int count;
>>
>> +     /* Lock the adapter for the duration of the whole sequence. */
>> +     if (!tpm_dev.client->adapter->algo->master_xfer)
>> +             return -EOPNOTSUPP;
>> +     i2c_lock_adapter(tpm_dev.client->adapter);
>> +
>>       for (count = 0; count < MAX_COUNT; count++) {
>> -             rc = i2c_transfer(tpm_dev.client->adapter, &msg1, 1);
>> +             rc = i2c_transfer_nolock(tpm_dev.client->adapter, &msg1, 1);
>>               if (rc > 0)
>>                       break; /* break here to skip sleep */
>>
>> @@ -92,19 +119,21 @@ static int iic_tpm_read(u8 addr, u8 *buffer, size_t len)
>>       }
>>
>>       if (rc <= 0)
>> -             return -EIO;
>> +             goto out;
>>
>>       /* After the TPM has successfully received the register address it needs
>>        * some time, thus we're sleeping here again, before retrieving the data
>>        */
>>       for (count = 0; count < MAX_COUNT; count++) {
>>               usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI);
>> -             rc = i2c_transfer(tpm_dev.client->adapter, &msg2, 1);
>> +             rc = i2c_transfer_nolock(tpm_dev.client->adapter, &msg2, 1);
>>               if (rc > 0)
>>                       break;
>>
>>       }
>>
>> +out:
>> +     i2c_unlock_adapter(tpm_dev.client->adapter);
>>       if (rc <= 0)
>>               return -EIO;
>>
>> @@ -121,17 +150,22 @@ static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len,
>>
>>       struct i2c_msg msg1 = { tpm_dev.client->addr, 0, len + 1, tpm_dev.buf };
>>
>> +     if (!tpm_dev.client->adapter->algo->master_xfer)
>> +             return -EOPNOTSUPP;
>> +     i2c_lock_adapter(tpm_dev.client->adapter);
>> +
>>       tpm_dev.buf[0] = addr;
>>       memcpy(&(tpm_dev.buf[1]), buffer, len);
>>
>>       for (count = 0; count < max_count; count++) {
>> -             rc = i2c_transfer(tpm_dev.client->adapter, &msg1, 1);
>> +             rc = i2c_transfer_nolock(tpm_dev.client->adapter, &msg1, 1);
>>               if (rc > 0)
>>                       break;
>>
>>               usleep_range(sleep_low, sleep_hi);
>>       }
>>
>> +     i2c_unlock_adapter(tpm_dev.client->adapter);
>>       if (rc <= 0)
>>               return -EIO;
>>
>
>
>
> try to have a look to the i2c_smbus* function, you could avoid
> lot of code
>
> Andi
>
>> --
>> 1.7.6.msysgit.0
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>> the body of a message to majordomo@xxxxxxxxxxxxxxx
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> Please read the FAQ at  http://www.tux.org/lkml/
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/