On 2021-06-11 1:01 p.m., Alex Deucher wrote:
> On Tue, Jun 8, 2021 at 5:40 PM Luben Tuikov <[email protected]> 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 <[email protected]>
>> Cc: Alexander Deucher <[email protected]>
>> Cc: Andrey Grodzovsky <[email protected]>
>> Cc: Lijo Lazar <[email protected]>
>> Cc: Stanley Yang <[email protected]>
>> Cc: Hawking Zhang <[email protected]>
>> Signed-off-by: Luben Tuikov <[email protected]>
>> ---
>> 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. :-)
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
>> [email protected]
>> 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
_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx