summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core_env.c45
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/reg.h93
2 files changed, 112 insertions, 26 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c
index 0107cbc32fc7..d637c0348fa1 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c
@@ -32,6 +32,7 @@ struct mlxsw_env {
const struct mlxsw_bus_info *bus_info;
u8 max_module_count; /* Maximum number of modules per-slot. */
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 mlxsw_env_line_card *line_cards[];
};
@@ -111,7 +112,7 @@ mlxsw_env_validate_cable_ident(struct mlxsw_core *core, u8 slot_index, int id,
if (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_I2C_ADDR_LOW);
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,
int module, u16 offset, u16 size, void *data,
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 *eeprom_tmp;
u16 i2c_addr;
@@ -153,11 +155,7 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, u8 slot_index,
int status;
int err;
- /* MCIA register accepts buffer size <= 48. Page of size 128 should be
- * 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);
+ size = min_t(u16, size, mlxsw_env->max_eeprom_len);
if (offset < 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,
}
}
- 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);
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,
page = MLXSW_REG_MCIA_TH_PAGE_CMIS_NUM;
else
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_ITEM_SIZE,
MLXSW_REG_MCIA_I2C_ADDR_LOW);
} 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,
off, MLXSW_REG_MCIA_TH_ITEM_SIZE,
MLXSW_REG_MCIA_I2C_ADDR_HIGH);
@@ -489,9 +487,9 @@ mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core,
u8 size;
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,
page->i2c_address);
mlxsw_reg_mcia_bank_number_set(mcia_pl, page->bank);
@@ -1359,6 +1357,26 @@ static struct mlxsw_linecards_event_ops mlxsw_env_event_ops = {
.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,
const struct mlxsw_bus_info *bus_info,
struct mlxsw_env **p_env)
@@ -1427,10 +1445,15 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core,
if (err)
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;
return 0;
+err_eeprom_len_query:
err_type_set:
mlxsw_env_module_event_disable(env, 0);
err_mlxsw_env_module_event_enable:
diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h
index df63f3923372..4b90ae44b476 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h
@@ -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_LEN 0x40
+#define MLXSW_REG_MCIA_LEN 0x94
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
* Module number.
* Access: Index
@@ -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_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_HIGH 0x51
#define MLXSW_REG_MCIA_PAGE0_LO_OFF 0xa0
@@ -9753,7 +9744,7 @@ enum mlxsw_reg_mcia_eeprom_module_info {
* Bytes to read/write.
* 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+
* 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);
MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH + 1)
static inline void mlxsw_reg_mcia_pack(char *payload, u8 slot_index, u8 module,
- u8 lock, u8 page_number,
- u16 device_addr, u8 size,
+ u8 page_number, u16 device_addr, u8 size,
u8 i2c_device_addr)
{
MLXSW_REG_ZERO(mcia, payload);
mlxsw_reg_mcia_slot_set(payload, slot_index);
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_device_address_set(payload, device_addr);
mlxsw_reg_mcia_size_set(payload, size);
@@ -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]);
}
+/* 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 Register is used to configure the Packet Sampling mechanism.
@@ -12974,10 +13036,11 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = {
MLXSW_REG(mcion),
MLXSW_REG(mtpps),
MLXSW_REG(mtutc),
- MLXSW_REG(mpsc),
MLXSW_REG(mcqi),
MLXSW_REG(mcc),
MLXSW_REG(mcda),
+ MLXSW_REG(mcam),
+ MLXSW_REG(mpsc),
MLXSW_REG(mgpc),
MLXSW_REG(mprs),
MLXSW_REG(mogcr),