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@xxxxxxx> 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@xxxxxxx> >>> Cc: Alexander Deucher <Alexander.Deucher@xxxxxxx> >>> Cc: Andrey Grodzovsky <Andrey.Grodzovsky@xxxxxxx> >>> Cc: Lijo Lazar <Lijo.Lazar@xxxxxxx> >>> Cc: Stanley Yang <Stanley.Yang@xxxxxxx> >>> Cc: Hawking Zhang <Hawking.Zhang@xxxxxxx> >>> Signed-off-by: Luben Tuikov <luben.tuikov@xxxxxxx> >>> --- >>> 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@xxxxxxxxxxxxxxxxxxxxx >>> 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 amd-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/amd-gfx