Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'mlxsw-speed-up-transceiver-module-eeprom-dump'

Petr Machata says:

====================
mlxsw: Speed up transceiver module EEPROM dump

Ido Schimmel writes:

Old firmware versions could only read up to 48 bytes from a transceiver
module's EEPROM in one go. Newer versions can read up to 128 bytes,
resulting in fewer transactions.

Query support for the new capability during driver initialization and if
supported, read up to 128 bytes in one go.

This is going to be especially useful for upcoming transceiver module
firmware flashing support.

Before:

# perf stat -e devlink:devlink_hwmsg -- ethtool -m swp11 page 0x1 offset 128 length 128 i2c 0x50
[...]
Performance counter stats for 'ethtool -m swp11 page 0x1 offset 128 length 128 i2c 0x50':

3 devlink:devlink_hwmsg

After:

# perf stat -e devlink:devlink_hwmsg -- ethtool -m swp11 page 0x1 offset 128 length 128 i2c 0x50
[...]
Performance counter stats for 'ethtool -m swp11 page 0x1 offset 128 length 128 i2c 0x50':

1 devlink:devlink_hwmsg

Patches #1-#4 are preparations / cleanups.

Patch #5 adds support for the new read size.
====================

Link: https://lore.kernel.org/r/cover.1690281940.git.petrm@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+112 -26
+34 -11
drivers/net/ethernet/mellanox/mlxsw/core_env.c
··· 32 32 const struct mlxsw_bus_info *bus_info; 33 33 u8 max_module_count; /* Maximum number of modules per-slot. */ 34 34 u8 num_of_slots; /* Including the main board. */ 35 + u8 max_eeprom_len; /* Maximum module EEPROM transaction length. */ 35 36 struct mutex line_cards_lock; /* Protects line cards. */ 36 37 struct mlxsw_env_line_card *line_cards[]; 37 38 }; ··· 112 111 if (err) 113 112 return err; 114 113 115 - mlxsw_reg_mcia_pack(mcia_pl, slot_index, id, 0, 114 + mlxsw_reg_mcia_pack(mcia_pl, slot_index, id, 116 115 MLXSW_REG_MCIA_PAGE0_LO_OFF, 0, 1, 117 116 MLXSW_REG_MCIA_I2C_ADDR_LOW); 118 117 err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl); ··· 147 146 int module, u16 offset, u16 size, void *data, 148 147 bool qsfp, unsigned int *p_read_size) 149 148 { 149 + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 150 150 char mcia_pl[MLXSW_REG_MCIA_LEN]; 151 151 char *eeprom_tmp; 152 152 u16 i2c_addr; ··· 155 153 int status; 156 154 int err; 157 155 158 - /* MCIA register accepts buffer size <= 48. Page of size 128 should be 159 - * read by chunks of size 48, 48, 32. Align the size of the last chunk 160 - * to avoid reading after the end of the page. 161 - */ 162 - size = min_t(u16, size, MLXSW_REG_MCIA_EEPROM_SIZE); 156 + size = min_t(u16, size, mlxsw_env->max_eeprom_len); 163 157 164 158 if (offset < MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH && 165 159 offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) ··· 186 188 } 187 189 } 188 190 189 - mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, 0, page, offset, size, 191 + mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, page, offset, size, 190 192 i2c_addr); 191 193 192 194 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl); ··· 264 266 page = MLXSW_REG_MCIA_TH_PAGE_CMIS_NUM; 265 267 else 266 268 page = MLXSW_REG_MCIA_TH_PAGE_NUM; 267 - mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, 0, page, 269 + mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, page, 268 270 MLXSW_REG_MCIA_TH_PAGE_OFF + off, 269 271 MLXSW_REG_MCIA_TH_ITEM_SIZE, 270 272 MLXSW_REG_MCIA_I2C_ADDR_LOW); 271 273 } else { 272 - mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, 0, 274 + mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, 273 275 MLXSW_REG_MCIA_PAGE0_LO, 274 276 off, MLXSW_REG_MCIA_TH_ITEM_SIZE, 275 277 MLXSW_REG_MCIA_I2C_ADDR_HIGH); ··· 487 489 u8 size; 488 490 489 491 size = min_t(u8, page->length - bytes_read, 490 - MLXSW_REG_MCIA_EEPROM_SIZE); 492 + mlxsw_env->max_eeprom_len); 491 493 492 - mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, 0, page->page, 494 + mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, page->page, 493 495 device_addr + bytes_read, size, 494 496 page->i2c_address); 495 497 mlxsw_reg_mcia_bank_number_set(mcia_pl, page->bank); ··· 1357 1359 .got_inactive = mlxsw_env_got_inactive, 1358 1360 }; 1359 1361 1362 + static int mlxsw_env_max_module_eeprom_len_query(struct mlxsw_env *mlxsw_env) 1363 + { 1364 + char mcam_pl[MLXSW_REG_MCAM_LEN]; 1365 + bool mcia_128b_supported; 1366 + int err; 1367 + 1368 + mlxsw_reg_mcam_pack(mcam_pl, 1369 + MLXSW_REG_MCAM_FEATURE_GROUP_ENHANCED_FEATURES); 1370 + err = mlxsw_reg_query(mlxsw_env->core, MLXSW_REG(mcam), mcam_pl); 1371 + if (err) 1372 + return err; 1373 + 1374 + mlxsw_reg_mcam_unpack(mcam_pl, MLXSW_REG_MCAM_MCIA_128B, 1375 + &mcia_128b_supported); 1376 + 1377 + mlxsw_env->max_eeprom_len = mcia_128b_supported ? 128 : 48; 1378 + 1379 + return 0; 1380 + } 1381 + 1360 1382 int mlxsw_env_init(struct mlxsw_core *mlxsw_core, 1361 1383 const struct mlxsw_bus_info *bus_info, 1362 1384 struct mlxsw_env **p_env) ··· 1445 1427 if (err) 1446 1428 goto err_type_set; 1447 1429 1430 + err = mlxsw_env_max_module_eeprom_len_query(env); 1431 + if (err) 1432 + goto err_eeprom_len_query; 1433 + 1448 1434 env->line_cards[0]->active = true; 1449 1435 1450 1436 return 0; 1451 1437 1438 + err_eeprom_len_query: 1452 1439 err_type_set: 1453 1440 mlxsw_env_module_event_disable(env, 0); 1454 1441 err_mlxsw_env_module_event_enable:
+78 -15
drivers/net/ethernet/mellanox/mlxsw/reg.h
··· 9640 9640 */ 9641 9641 9642 9642 #define MLXSW_REG_MCIA_ID 0x9014 9643 - #define MLXSW_REG_MCIA_LEN 0x40 9643 + #define MLXSW_REG_MCIA_LEN 0x94 9644 9644 9645 9645 MLXSW_REG_DEFINE(mcia, MLXSW_REG_MCIA_ID, MLXSW_REG_MCIA_LEN); 9646 - 9647 - /* reg_mcia_l 9648 - * Lock bit. Setting this bit will lock the access to the specific 9649 - * cable. Used for updating a full page in a cable EPROM. Any access 9650 - * other then subsequence writes will fail while the port is locked. 9651 - * Access: RW 9652 - */ 9653 - MLXSW_ITEM32(reg, mcia, l, 0x00, 31, 1); 9654 9646 9655 9647 /* reg_mcia_module 9656 9648 * Module number. ··· 9708 9716 9709 9717 #define MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH 256 9710 9718 #define MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH 128 9711 - #define MLXSW_REG_MCIA_EEPROM_SIZE 48 9712 9719 #define MLXSW_REG_MCIA_I2C_ADDR_LOW 0x50 9713 9720 #define MLXSW_REG_MCIA_I2C_ADDR_HIGH 0x51 9714 9721 #define MLXSW_REG_MCIA_PAGE0_LO_OFF 0xa0 ··· 9744 9753 * Bytes to read/write. 9745 9754 * Access: RW 9746 9755 */ 9747 - MLXSW_ITEM_BUF(reg, mcia, eeprom, 0x10, MLXSW_REG_MCIA_EEPROM_SIZE); 9756 + MLXSW_ITEM_BUF(reg, mcia, eeprom, 0x10, 128); 9748 9757 9749 9758 /* This is used to access the optional upper pages (1-3) in the QSFP+ 9750 9759 * memory map. Page 1 is available on offset 256 through 383, page 2 - ··· 9755 9764 MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH + 1) 9756 9765 9757 9766 static inline void mlxsw_reg_mcia_pack(char *payload, u8 slot_index, u8 module, 9758 - u8 lock, u8 page_number, 9759 - u16 device_addr, u8 size, 9767 + u8 page_number, u16 device_addr, u8 size, 9760 9768 u8 i2c_device_addr) 9761 9769 { 9762 9770 MLXSW_REG_ZERO(mcia, payload); 9763 9771 mlxsw_reg_mcia_slot_set(payload, slot_index); 9764 9772 mlxsw_reg_mcia_module_set(payload, module); 9765 - mlxsw_reg_mcia_l_set(payload, lock); 9766 9773 mlxsw_reg_mcia_page_number_set(payload, page_number); 9767 9774 mlxsw_reg_mcia_device_address_set(payload, device_addr); 9768 9775 mlxsw_reg_mcia_size_set(payload, size); ··· 10568 10579 10569 10580 for (i = 0; i < size / 4; i++) 10570 10581 mlxsw_reg_mcda_data_set(payload, i, *(u32 *) &data[i * 4]); 10582 + } 10583 + 10584 + /* MCAM - Management Capabilities Mask Register 10585 + * -------------------------------------------- 10586 + * Reports the device supported management features. 10587 + */ 10588 + #define MLXSW_REG_MCAM_ID 0x907F 10589 + #define MLXSW_REG_MCAM_LEN 0x48 10590 + 10591 + MLXSW_REG_DEFINE(mcam, MLXSW_REG_MCAM_ID, MLXSW_REG_MCAM_LEN); 10592 + 10593 + enum mlxsw_reg_mcam_feature_group { 10594 + /* Enhanced features. */ 10595 + MLXSW_REG_MCAM_FEATURE_GROUP_ENHANCED_FEATURES, 10596 + }; 10597 + 10598 + /* reg_mcam_feature_group 10599 + * Feature list mask index. 10600 + * Access: Index 10601 + */ 10602 + MLXSW_ITEM32(reg, mcam, feature_group, 0x00, 16, 8); 10603 + 10604 + enum mlxsw_reg_mcam_mng_feature_cap_mask_bits { 10605 + /* If set, MCIA supports 128 bytes payloads. Otherwise, 48 bytes. */ 10606 + MLXSW_REG_MCAM_MCIA_128B = 34, 10607 + }; 10608 + 10609 + #define MLXSW_REG_BYTES_PER_DWORD 0x4 10610 + 10611 + /* reg_mcam_mng_feature_cap_mask 10612 + * Supported port's enhanced features. 10613 + * Based on feature_group index. 10614 + * When bit is set, the feature is supported in the device. 10615 + * Access: RO 10616 + */ 10617 + #define MLXSW_REG_MCAM_MNG_FEATURE_CAP_MASK_DWORD(_dw_num, _offset) \ 10618 + MLXSW_ITEM_BIT_ARRAY(reg, mcam, mng_feature_cap_mask_dw##_dw_num, \ 10619 + _offset, MLXSW_REG_BYTES_PER_DWORD, 1) 10620 + 10621 + /* The access to the bits in the field 'mng_feature_cap_mask' is not same to 10622 + * other mask fields in other registers. In most of the cases bit #0 is the 10623 + * first one in the last dword. In MCAM register, the first dword contains bits 10624 + * #0-#31 and so on, so the access to the bits is simpler using bit array per 10625 + * dword. Declare each dword of 'mng_feature_cap_mask' field separately. 10626 + */ 10627 + MLXSW_REG_MCAM_MNG_FEATURE_CAP_MASK_DWORD(0, 0x28); 10628 + MLXSW_REG_MCAM_MNG_FEATURE_CAP_MASK_DWORD(1, 0x2C); 10629 + MLXSW_REG_MCAM_MNG_FEATURE_CAP_MASK_DWORD(2, 0x30); 10630 + MLXSW_REG_MCAM_MNG_FEATURE_CAP_MASK_DWORD(3, 0x34); 10631 + 10632 + static inline void 10633 + mlxsw_reg_mcam_pack(char *payload, enum mlxsw_reg_mcam_feature_group feat_group) 10634 + { 10635 + MLXSW_REG_ZERO(mcam, payload); 10636 + mlxsw_reg_mcam_feature_group_set(payload, feat_group); 10637 + } 10638 + 10639 + static inline void 10640 + mlxsw_reg_mcam_unpack(char *payload, 10641 + enum mlxsw_reg_mcam_mng_feature_cap_mask_bits bit, 10642 + bool *p_mng_feature_cap_val) 10643 + { 10644 + int offset = bit % (MLXSW_REG_BYTES_PER_DWORD * BITS_PER_BYTE); 10645 + int dword = bit / (MLXSW_REG_BYTES_PER_DWORD * BITS_PER_BYTE); 10646 + u8 (*getters[])(const char *, u16) = { 10647 + mlxsw_reg_mcam_mng_feature_cap_mask_dw0_get, 10648 + mlxsw_reg_mcam_mng_feature_cap_mask_dw1_get, 10649 + mlxsw_reg_mcam_mng_feature_cap_mask_dw2_get, 10650 + mlxsw_reg_mcam_mng_feature_cap_mask_dw3_get, 10651 + }; 10652 + 10653 + if (!WARN_ON_ONCE(dword >= ARRAY_SIZE(getters))) 10654 + *p_mng_feature_cap_val = getters[dword](payload, offset); 10571 10655 } 10572 10656 10573 10657 /* MPSC - Monitoring Packet Sampling Configuration Register ··· 13036 12974 MLXSW_REG(mcion), 13037 12975 MLXSW_REG(mtpps), 13038 12976 MLXSW_REG(mtutc), 13039 - MLXSW_REG(mpsc), 13040 12977 MLXSW_REG(mcqi), 13041 12978 MLXSW_REG(mcc), 13042 12979 MLXSW_REG(mcda), 12980 + MLXSW_REG(mcam), 12981 + MLXSW_REG(mpsc), 13043 12982 MLXSW_REG(mgpc), 13044 12983 MLXSW_REG(mprs), 13045 12984 MLXSW_REG(mogcr),