Commit 601ad04f authored by Jakub Kicinski's avatar Jakub Kicinski

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.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents c1b0b611 1f4aea1f
...@@ -32,6 +32,7 @@ struct mlxsw_env { ...@@ -32,6 +32,7 @@ struct mlxsw_env {
const struct mlxsw_bus_info *bus_info; const struct mlxsw_bus_info *bus_info;
u8 max_module_count; /* Maximum number of modules per-slot. */ u8 max_module_count; /* Maximum number of modules per-slot. */
u8 num_of_slots; /* Including the main board. */ u8 num_of_slots; /* Including the main board. */
u8 max_eeprom_len; /* Maximum module EEPROM transaction length. */
struct mutex line_cards_lock; /* Protects line cards. */ struct mutex line_cards_lock; /* Protects line cards. */
struct mlxsw_env_line_card *line_cards[]; struct mlxsw_env_line_card *line_cards[];
}; };
...@@ -111,7 +112,7 @@ mlxsw_env_validate_cable_ident(struct mlxsw_core *core, u8 slot_index, int id, ...@@ -111,7 +112,7 @@ mlxsw_env_validate_cable_ident(struct mlxsw_core *core, u8 slot_index, int id,
if (err) if (err)
return err; return err;
mlxsw_reg_mcia_pack(mcia_pl, slot_index, id, 0, mlxsw_reg_mcia_pack(mcia_pl, slot_index, id,
MLXSW_REG_MCIA_PAGE0_LO_OFF, 0, 1, MLXSW_REG_MCIA_PAGE0_LO_OFF, 0, 1,
MLXSW_REG_MCIA_I2C_ADDR_LOW); MLXSW_REG_MCIA_I2C_ADDR_LOW);
err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl); err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl);
...@@ -146,6 +147,7 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, u8 slot_index, ...@@ -146,6 +147,7 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, u8 slot_index,
int module, u16 offset, u16 size, void *data, int module, u16 offset, u16 size, void *data,
bool qsfp, unsigned int *p_read_size) bool qsfp, unsigned int *p_read_size)
{ {
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
char mcia_pl[MLXSW_REG_MCIA_LEN]; char mcia_pl[MLXSW_REG_MCIA_LEN];
char *eeprom_tmp; char *eeprom_tmp;
u16 i2c_addr; u16 i2c_addr;
...@@ -153,11 +155,7 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, u8 slot_index, ...@@ -153,11 +155,7 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, u8 slot_index,
int status; int status;
int err; int err;
/* MCIA register accepts buffer size <= 48. Page of size 128 should be size = min_t(u16, size, mlxsw_env->max_eeprom_len);
* read by chunks of size 48, 48, 32. Align the size of the last chunk
* to avoid reading after the end of the page.
*/
size = min_t(u16, size, MLXSW_REG_MCIA_EEPROM_SIZE);
if (offset < MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH && if (offset < MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH &&
offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH)
...@@ -188,7 +186,7 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, u8 slot_index, ...@@ -188,7 +186,7 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, u8 slot_index,
} }
} }
mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, 0, page, offset, size, mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, page, offset, size,
i2c_addr); i2c_addr);
err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl); err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl);
...@@ -266,12 +264,12 @@ mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, u8 slot_index, ...@@ -266,12 +264,12 @@ mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, u8 slot_index,
page = MLXSW_REG_MCIA_TH_PAGE_CMIS_NUM; page = MLXSW_REG_MCIA_TH_PAGE_CMIS_NUM;
else else
page = MLXSW_REG_MCIA_TH_PAGE_NUM; page = MLXSW_REG_MCIA_TH_PAGE_NUM;
mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, 0, page, mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, page,
MLXSW_REG_MCIA_TH_PAGE_OFF + off, MLXSW_REG_MCIA_TH_PAGE_OFF + off,
MLXSW_REG_MCIA_TH_ITEM_SIZE, MLXSW_REG_MCIA_TH_ITEM_SIZE,
MLXSW_REG_MCIA_I2C_ADDR_LOW); MLXSW_REG_MCIA_I2C_ADDR_LOW);
} else { } else {
mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, 0, mlxsw_reg_mcia_pack(mcia_pl, slot_index, module,
MLXSW_REG_MCIA_PAGE0_LO, MLXSW_REG_MCIA_PAGE0_LO,
off, MLXSW_REG_MCIA_TH_ITEM_SIZE, off, MLXSW_REG_MCIA_TH_ITEM_SIZE,
MLXSW_REG_MCIA_I2C_ADDR_HIGH); MLXSW_REG_MCIA_I2C_ADDR_HIGH);
...@@ -489,9 +487,9 @@ mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, ...@@ -489,9 +487,9 @@ mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core,
u8 size; u8 size;
size = min_t(u8, page->length - bytes_read, size = min_t(u8, page->length - bytes_read,
MLXSW_REG_MCIA_EEPROM_SIZE); mlxsw_env->max_eeprom_len);
mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, 0, page->page, mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, page->page,
device_addr + bytes_read, size, device_addr + bytes_read, size,
page->i2c_address); page->i2c_address);
mlxsw_reg_mcia_bank_number_set(mcia_pl, page->bank); mlxsw_reg_mcia_bank_number_set(mcia_pl, page->bank);
...@@ -1359,6 +1357,26 @@ static struct mlxsw_linecards_event_ops mlxsw_env_event_ops = { ...@@ -1359,6 +1357,26 @@ static struct mlxsw_linecards_event_ops mlxsw_env_event_ops = {
.got_inactive = mlxsw_env_got_inactive, .got_inactive = mlxsw_env_got_inactive,
}; };
static int mlxsw_env_max_module_eeprom_len_query(struct mlxsw_env *mlxsw_env)
{
char mcam_pl[MLXSW_REG_MCAM_LEN];
bool mcia_128b_supported;
int err;
mlxsw_reg_mcam_pack(mcam_pl,
MLXSW_REG_MCAM_FEATURE_GROUP_ENHANCED_FEATURES);
err = mlxsw_reg_query(mlxsw_env->core, MLXSW_REG(mcam), mcam_pl);
if (err)
return err;
mlxsw_reg_mcam_unpack(mcam_pl, MLXSW_REG_MCAM_MCIA_128B,
&mcia_128b_supported);
mlxsw_env->max_eeprom_len = mcia_128b_supported ? 128 : 48;
return 0;
}
int mlxsw_env_init(struct mlxsw_core *mlxsw_core, int mlxsw_env_init(struct mlxsw_core *mlxsw_core,
const struct mlxsw_bus_info *bus_info, const struct mlxsw_bus_info *bus_info,
struct mlxsw_env **p_env) struct mlxsw_env **p_env)
...@@ -1427,10 +1445,15 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, ...@@ -1427,10 +1445,15 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core,
if (err) if (err)
goto err_type_set; goto err_type_set;
err = mlxsw_env_max_module_eeprom_len_query(env);
if (err)
goto err_eeprom_len_query;
env->line_cards[0]->active = true; env->line_cards[0]->active = true;
return 0; return 0;
err_eeprom_len_query:
err_type_set: err_type_set:
mlxsw_env_module_event_disable(env, 0); mlxsw_env_module_event_disable(env, 0);
err_mlxsw_env_module_event_enable: err_mlxsw_env_module_event_enable:
......
...@@ -9640,18 +9640,10 @@ static inline void mlxsw_reg_mtbr_temp_unpack(char *payload, int rec_ind, ...@@ -9640,18 +9640,10 @@ static inline void mlxsw_reg_mtbr_temp_unpack(char *payload, int rec_ind,
*/ */
#define MLXSW_REG_MCIA_ID 0x9014 #define MLXSW_REG_MCIA_ID 0x9014
#define MLXSW_REG_MCIA_LEN 0x40 #define MLXSW_REG_MCIA_LEN 0x94
MLXSW_REG_DEFINE(mcia, MLXSW_REG_MCIA_ID, MLXSW_REG_MCIA_LEN); MLXSW_REG_DEFINE(mcia, MLXSW_REG_MCIA_ID, MLXSW_REG_MCIA_LEN);
/* reg_mcia_l
* Lock bit. Setting this bit will lock the access to the specific
* cable. Used for updating a full page in a cable EPROM. Any access
* other then subsequence writes will fail while the port is locked.
* Access: RW
*/
MLXSW_ITEM32(reg, mcia, l, 0x00, 31, 1);
/* reg_mcia_module /* reg_mcia_module
* Module number. * Module number.
* Access: Index * Access: Index
...@@ -9716,7 +9708,6 @@ MLXSW_ITEM32(reg, mcia, size, 0x08, 0, 16); ...@@ -9716,7 +9708,6 @@ MLXSW_ITEM32(reg, mcia, size, 0x08, 0, 16);
#define MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH 256 #define MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH 256
#define MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH 128 #define MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH 128
#define MLXSW_REG_MCIA_EEPROM_SIZE 48
#define MLXSW_REG_MCIA_I2C_ADDR_LOW 0x50 #define MLXSW_REG_MCIA_I2C_ADDR_LOW 0x50
#define MLXSW_REG_MCIA_I2C_ADDR_HIGH 0x51 #define MLXSW_REG_MCIA_I2C_ADDR_HIGH 0x51
#define MLXSW_REG_MCIA_PAGE0_LO_OFF 0xa0 #define MLXSW_REG_MCIA_PAGE0_LO_OFF 0xa0
...@@ -9753,7 +9744,7 @@ enum mlxsw_reg_mcia_eeprom_module_info { ...@@ -9753,7 +9744,7 @@ enum mlxsw_reg_mcia_eeprom_module_info {
* Bytes to read/write. * Bytes to read/write.
* Access: RW * Access: RW
*/ */
MLXSW_ITEM_BUF(reg, mcia, eeprom, 0x10, MLXSW_REG_MCIA_EEPROM_SIZE); MLXSW_ITEM_BUF(reg, mcia, eeprom, 0x10, 128);
/* This is used to access the optional upper pages (1-3) in the QSFP+ /* This is used to access the optional upper pages (1-3) in the QSFP+
* memory map. Page 1 is available on offset 256 through 383, page 2 - * memory map. Page 1 is available on offset 256 through 383, page 2 -
...@@ -9764,14 +9755,12 @@ MLXSW_ITEM_BUF(reg, mcia, eeprom, 0x10, MLXSW_REG_MCIA_EEPROM_SIZE); ...@@ -9764,14 +9755,12 @@ MLXSW_ITEM_BUF(reg, mcia, eeprom, 0x10, MLXSW_REG_MCIA_EEPROM_SIZE);
MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH + 1) MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH + 1)
static inline void mlxsw_reg_mcia_pack(char *payload, u8 slot_index, u8 module, static inline void mlxsw_reg_mcia_pack(char *payload, u8 slot_index, u8 module,
u8 lock, u8 page_number, u8 page_number, u16 device_addr, u8 size,
u16 device_addr, u8 size,
u8 i2c_device_addr) u8 i2c_device_addr)
{ {
MLXSW_REG_ZERO(mcia, payload); MLXSW_REG_ZERO(mcia, payload);
mlxsw_reg_mcia_slot_set(payload, slot_index); mlxsw_reg_mcia_slot_set(payload, slot_index);
mlxsw_reg_mcia_module_set(payload, module); mlxsw_reg_mcia_module_set(payload, module);
mlxsw_reg_mcia_l_set(payload, lock);
mlxsw_reg_mcia_page_number_set(payload, page_number); mlxsw_reg_mcia_page_number_set(payload, page_number);
mlxsw_reg_mcia_device_address_set(payload, device_addr); mlxsw_reg_mcia_device_address_set(payload, device_addr);
mlxsw_reg_mcia_size_set(payload, size); mlxsw_reg_mcia_size_set(payload, size);
...@@ -10581,6 +10570,79 @@ static inline void mlxsw_reg_mcda_pack(char *payload, u32 update_handle, ...@@ -10581,6 +10570,79 @@ static inline void mlxsw_reg_mcda_pack(char *payload, u32 update_handle,
mlxsw_reg_mcda_data_set(payload, i, *(u32 *) &data[i * 4]); mlxsw_reg_mcda_data_set(payload, i, *(u32 *) &data[i * 4]);
} }
/* MCAM - Management Capabilities Mask Register
* --------------------------------------------
* Reports the device supported management features.
*/
#define MLXSW_REG_MCAM_ID 0x907F
#define MLXSW_REG_MCAM_LEN 0x48
MLXSW_REG_DEFINE(mcam, MLXSW_REG_MCAM_ID, MLXSW_REG_MCAM_LEN);
enum mlxsw_reg_mcam_feature_group {
/* Enhanced features. */
MLXSW_REG_MCAM_FEATURE_GROUP_ENHANCED_FEATURES,
};
/* reg_mcam_feature_group
* Feature list mask index.
* Access: Index
*/
MLXSW_ITEM32(reg, mcam, feature_group, 0x00, 16, 8);
enum mlxsw_reg_mcam_mng_feature_cap_mask_bits {
/* If set, MCIA supports 128 bytes payloads. Otherwise, 48 bytes. */
MLXSW_REG_MCAM_MCIA_128B = 34,
};
#define MLXSW_REG_BYTES_PER_DWORD 0x4
/* reg_mcam_mng_feature_cap_mask
* Supported port's enhanced features.
* Based on feature_group index.
* When bit is set, the feature is supported in the device.
* Access: RO
*/
#define MLXSW_REG_MCAM_MNG_FEATURE_CAP_MASK_DWORD(_dw_num, _offset) \
MLXSW_ITEM_BIT_ARRAY(reg, mcam, mng_feature_cap_mask_dw##_dw_num, \
_offset, MLXSW_REG_BYTES_PER_DWORD, 1)
/* The access to the bits in the field 'mng_feature_cap_mask' is not same to
* other mask fields in other registers. In most of the cases bit #0 is the
* first one in the last dword. In MCAM register, the first dword contains bits
* #0-#31 and so on, so the access to the bits is simpler using bit array per
* dword. Declare each dword of 'mng_feature_cap_mask' field separately.
*/
MLXSW_REG_MCAM_MNG_FEATURE_CAP_MASK_DWORD(0, 0x28);
MLXSW_REG_MCAM_MNG_FEATURE_CAP_MASK_DWORD(1, 0x2C);
MLXSW_REG_MCAM_MNG_FEATURE_CAP_MASK_DWORD(2, 0x30);
MLXSW_REG_MCAM_MNG_FEATURE_CAP_MASK_DWORD(3, 0x34);
static inline void
mlxsw_reg_mcam_pack(char *payload, enum mlxsw_reg_mcam_feature_group feat_group)
{
MLXSW_REG_ZERO(mcam, payload);
mlxsw_reg_mcam_feature_group_set(payload, feat_group);
}
static inline void
mlxsw_reg_mcam_unpack(char *payload,
enum mlxsw_reg_mcam_mng_feature_cap_mask_bits bit,
bool *p_mng_feature_cap_val)
{
int offset = bit % (MLXSW_REG_BYTES_PER_DWORD * BITS_PER_BYTE);
int dword = bit / (MLXSW_REG_BYTES_PER_DWORD * BITS_PER_BYTE);
u8 (*getters[])(const char *, u16) = {
mlxsw_reg_mcam_mng_feature_cap_mask_dw0_get,
mlxsw_reg_mcam_mng_feature_cap_mask_dw1_get,
mlxsw_reg_mcam_mng_feature_cap_mask_dw2_get,
mlxsw_reg_mcam_mng_feature_cap_mask_dw3_get,
};
if (!WARN_ON_ONCE(dword >= ARRAY_SIZE(getters)))
*p_mng_feature_cap_val = getters[dword](payload, offset);
}
/* MPSC - Monitoring Packet Sampling Configuration Register /* MPSC - Monitoring Packet Sampling Configuration Register
* -------------------------------------------------------- * --------------------------------------------------------
* MPSC Register is used to configure the Packet Sampling mechanism. * MPSC Register is used to configure the Packet Sampling mechanism.
...@@ -12974,10 +13036,11 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { ...@@ -12974,10 +13036,11 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = {
MLXSW_REG(mcion), MLXSW_REG(mcion),
MLXSW_REG(mtpps), MLXSW_REG(mtpps),
MLXSW_REG(mtutc), MLXSW_REG(mtutc),
MLXSW_REG(mpsc),
MLXSW_REG(mcqi), MLXSW_REG(mcqi),
MLXSW_REG(mcc), MLXSW_REG(mcc),
MLXSW_REG(mcda), MLXSW_REG(mcda),
MLXSW_REG(mcam),
MLXSW_REG(mpsc),
MLXSW_REG(mgpc), MLXSW_REG(mgpc),
MLXSW_REG(mprs), MLXSW_REG(mprs),
MLXSW_REG(mogcr), MLXSW_REG(mogcr),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment