[PATCH 20/40] drm/amdgpu: EEPROM respects I2C quirks

Luben Tuikov luben.tuikov at amd.com
Fri Jun 11 17:37:27 UTC 2021


On 2021-06-11 1:17 p.m., Luben Tuikov wrote:
> On 2021-06-11 1:01 p.m., Alex Deucher wrote:
>> On Tue, Jun 8, 2021 at 5:40 PM Luben Tuikov <luben.tuikov at amd.com> wrote:
>>> Consult the i2c_adapter.quirks table for
>>> the maximum read/write data length per bus
>>> transaction. Do not exceed this transaction
>>> limit.
>>>
>>> Cc: Jean Delvare <jdelvare at suse.de>
>>> Cc: Alexander Deucher <Alexander.Deucher at amd.com>
>>> Cc: Andrey Grodzovsky <Andrey.Grodzovsky at amd.com>
>>> Cc: Lijo Lazar <Lijo.Lazar at amd.com>
>>> Cc: Stanley Yang <Stanley.Yang at amd.com>
>>> Cc: Hawking Zhang <Hawking.Zhang at amd.com>
>>> Signed-off-by: Luben Tuikov <luben.tuikov at amd.com>
>>> ---
>>>  drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c | 80 +++++++++++++++++-----
>>>  1 file changed, 64 insertions(+), 16 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c
>>> index 7fdb5bd2fc8bc8..94aeda1c7f8ca0 100644
>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c
>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c
>>> @@ -32,20 +32,9 @@
>>>
>>>  #define EEPROM_OFFSET_SIZE 2
>>>
>>> -/**
>>> - * amdgpu_eeprom_xfer -- Read/write from/to an I2C EEPROM device
>>> - * @i2c_adap: pointer to the I2C adapter to use
>>> - * @slave_addr: I2C address of the slave device
>>> - * @eeprom_addr: EEPROM address from which to read/write
>>> - * @eeprom_buf: pointer to data buffer to read into/write from
>>> - * @buf_size: the size of @eeprom_buf
>>> - * @read: True if reading from the EEPROM, false if writing
>>> - *
>>> - * Returns the number of bytes read/written; -errno on error.
>>> - */
>>> -int amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap,
>>> -                      u16 slave_addr, u16 eeprom_addr,
>>> -                      u8 *eeprom_buf, u16 buf_size, bool read)
>>> +static int __amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap,
>>> +                               u16 slave_addr, u16 eeprom_addr,
>>> +                               u8 *eeprom_buf, u16 buf_size, bool read)
>>>  {
>>>         u8 eeprom_offset_buf[EEPROM_OFFSET_SIZE];
>>>         struct i2c_msg msgs[] = {
>>> @@ -65,8 +54,8 @@ int amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap,
>>>         u16 len;
>>>
>>>         r = 0;
>>> -       for (len = 0; buf_size > 0;
>>> -            buf_size -= len, eeprom_addr += len, eeprom_buf += len) {
>>> +       for ( ; buf_size > 0;
>>> +             buf_size -= len, eeprom_addr += len, eeprom_buf += len) {
>>>                 /* Set the EEPROM address we want to write to/read from.
>>>                  */
>>>                 msgs[0].buf[0] = (eeprom_addr >> 8) & 0xff;
>>> @@ -120,3 +109,62 @@ int amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap,
>>>
>>>         return r < 0 ? r : eeprom_buf - p;
>>>  }
>>> +
>>> +/**
>>> + * amdgpu_eeprom_xfer -- Read/write from/to an I2C EEPROM device
>>> + * @i2c_adap: pointer to the I2C adapter to use
>>> + * @slave_addr: I2C address of the slave device
>>> + * @eeprom_addr: EEPROM address from which to read/write
>>> + * @eeprom_buf: pointer to data buffer to read into/write from
>>> + * @buf_size: the size of @eeprom_buf
>>> + * @read: True if reading from the EEPROM, false if writing
>>> + *
>>> + * Returns the number of bytes read/written; -errno on error.
>>> + */
>>> +int amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap,
>>> +                      u16 slave_addr, u16 eeprom_addr,
>>> +                      u8 *eeprom_buf, u16 buf_size, bool read)
>>> +{
>>> +       const struct i2c_adapter_quirks *quirks = i2c_adap->quirks;
>>> +       u16 limit;
>>> +
>>> +       if (!quirks)
>>> +               limit = 0;
>>> +       else if (read)
>>> +               limit = quirks->max_read_len;
>>> +       else
>>> +               limit = quirks->max_write_len;
>>> +
>>> +       if (limit == 0) {
>>> +               return __amdgpu_eeprom_xfer(i2c_adap, slave_addr, eeprom_addr,
>>> +                                           eeprom_buf, buf_size, read);
>>> +       } else if (limit <= EEPROM_OFFSET_SIZE) {
>>> +               dev_err_ratelimited(&i2c_adap->dev,
>>> +                                   "maddr:0x%04X size:0x%02X:quirk max_%s_len must be > %d",
>>> +                                   eeprom_addr, buf_size,
>>> +                                   read ? "read" : "write", EEPROM_OFFSET_SIZE);
>>> +               return -EINVAL;
>> I presume we handle this case properly at higher levels (i.e., split
>> up EEPROM updates into smaller transactions)?
> Absolutely we do.
> (We break it down twice: once per this limit and again per page size and page boundary. It'll work always. :-) )
>
> But this is different--this means that the user has set a limit less than 2, which means we can't even send a set-address phase to set the EEPROM memory address offset we want to read or write from, and thus the chattiness.
>
> I just noticed that it is less-than-or-equal, which means the smallest limit the user can set which would work is 3. But 2 would also work, then all transfers would be 2 bytes long. Does it matter? I guess I can change this from LTE to LT, to mean that a minimum transfer of 2 is the smallest we support. I've changed it to LT. :-)

Ooops, no!
It was correct the way I had it.
It has to be LTE due to the comment below, else the min(0, u16) is 0 and we'll not send anything. :-)

Regards,
Luben

>
> Regards,
> Luben
>
>> Alex
>>
>>
>>> +       } else {
>>> +               u16 ps; /* Partial size */
>>> +               int res = 0, r;
>>> +
>>> +               /* The "limit" includes all data bytes sent/received,
>>> +                * which would include the EEPROM_OFFSET_SIZE bytes.
>>> +                * Account for them here.
>>> +                */
>>> +               limit -= EEPROM_OFFSET_SIZE;
>>> +               for ( ; buf_size > 0;
>>> +                     buf_size -= ps, eeprom_addr += ps, eeprom_buf += ps) {
>>> +                       ps = min(limit, buf_size);
>>> +
>>> +                       r = __amdgpu_eeprom_xfer(i2c_adap,
>>> +                                                slave_addr, eeprom_addr,
>>> +                                                eeprom_buf, ps, read);
>>> +                       if (r < 0)
>>> +                               return r;
>>> +                       res += r;
>>> +               }
>>> +
>>> +               return res;
>>> +       }
>>> +}
>>> --
>>> 2.32.0
>>>
>>> _______________________________________________
>>> amd-gfx mailing list
>>> amd-gfx at lists.freedesktop.org
>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Flists.freedesktop.org%2Fmailman%2Flistinfo%2Famd-gfx&data=04%7C01%7Cluben.tuikov%40amd.com%7Cc8502a7f4dd94666468408d92cfa95e6%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637590277035962948%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=UsBaf7trds%2BjmJ8yhIaMoLNdq2Rxk3EXY5jztgzjFL0%3D&reserved=0



More information about the amd-gfx mailing list