1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
4 #include <linux/kernel.h>
12 static int mlxsw_env_validate_cable_ident(struct mlxsw_core *core, int id,
15 char eeprom_tmp[MLXSW_REG_MCIA_EEPROM_SIZE];
16 char mcia_pl[MLXSW_REG_MCIA_LEN];
20 mlxsw_reg_mcia_pack(mcia_pl, id, 0, MLXSW_REG_MCIA_PAGE0_LO_OFF, 0, 1,
21 MLXSW_REG_MCIA_I2C_ADDR_LOW);
22 err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl);
25 mlxsw_reg_mcia_eeprom_memcpy_from(mcia_pl, eeprom_tmp);
26 ident = eeprom_tmp[0];
28 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP:
31 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP: /* fall-through */
32 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS: /* fall-through */
33 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28: /* fall-through */
34 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_DD:
45 mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module,
46 u16 offset, u16 size, void *data,
47 unsigned int *p_read_size)
49 char eeprom_tmp[MLXSW_REG_MCIA_EEPROM_SIZE];
50 char mcia_pl[MLXSW_REG_MCIA_LEN];
55 size = min_t(u16, size, MLXSW_REG_MCIA_EEPROM_SIZE);
57 if (offset < MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH &&
58 offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH)
59 /* Cross pages read, read until offset 256 in low page */
60 size = MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH - offset;
62 i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_LOW;
63 if (offset >= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) {
64 i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_HIGH;
65 offset -= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH;
68 mlxsw_reg_mcia_pack(mcia_pl, module, 0, 0, offset, size, i2c_addr);
70 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl);
74 status = mlxsw_reg_mcia_status_get(mcia_pl);
78 mlxsw_reg_mcia_eeprom_memcpy_from(mcia_pl, eeprom_tmp);
79 memcpy(data, eeprom_tmp, size);
85 int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module,
88 char eeprom_tmp[MLXSW_REG_MCIA_EEPROM_SIZE];
90 u8 buf[MLXSW_REG_MCIA_TH_ITEM_SIZE];
93 char mcia_pl[MLXSW_REG_MCIA_LEN] = {0};
94 char mtbr_pl[MLXSW_REG_MTBR_LEN] = {0};
99 mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module,
101 err = mlxsw_reg_query(core, MLXSW_REG(mtbr), mtbr_pl);
105 /* Don't read temperature thresholds for module with no valid info. */
106 mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &module_temp, NULL);
107 switch (module_temp) {
108 case MLXSW_REG_MTBR_BAD_SENS_INFO: /* fall-through */
109 case MLXSW_REG_MTBR_NO_CONN: /* fall-through */
110 case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */
111 case MLXSW_REG_MTBR_INDEX_NA:
115 /* Do not consider thresholds for zero temperature. */
116 if (!MLXSW_REG_MTMP_TEMP_TO_MC(module_temp)) {
123 /* Read Free Side Device Temperature Thresholds from page 03h
124 * (MSB at lower byte address).
126 * 128-129 - Temp High Alarm (SFP_TEMP_HIGH_ALARM);
127 * 130-131 - Temp Low Alarm (SFP_TEMP_LOW_ALARM);
128 * 132-133 - Temp High Warning (SFP_TEMP_HIGH_WARN);
129 * 134-135 - Temp Low Warning (SFP_TEMP_LOW_WARN);
132 /* Validate module identifier value. */
133 err = mlxsw_env_validate_cable_ident(core, module, &qsfp);
138 mlxsw_reg_mcia_pack(mcia_pl, module, 0,
139 MLXSW_REG_MCIA_TH_PAGE_NUM,
140 MLXSW_REG_MCIA_TH_PAGE_OFF + off,
141 MLXSW_REG_MCIA_TH_ITEM_SIZE,
142 MLXSW_REG_MCIA_I2C_ADDR_LOW);
144 mlxsw_reg_mcia_pack(mcia_pl, module, 0,
145 MLXSW_REG_MCIA_PAGE0_LO,
146 off, MLXSW_REG_MCIA_TH_ITEM_SIZE,
147 MLXSW_REG_MCIA_I2C_ADDR_HIGH);
149 err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl);
153 mlxsw_reg_mcia_eeprom_memcpy_from(mcia_pl, eeprom_tmp);
154 memcpy(temp_thresh.buf, eeprom_tmp, MLXSW_REG_MCIA_TH_ITEM_SIZE);
155 *temp = temp_thresh.temp * 1000;
160 int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module,
161 struct ethtool_modinfo *modinfo)
163 u8 module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE];
164 u16 offset = MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE;
165 u8 module_rev_id, module_id;
166 unsigned int read_size;
169 err = mlxsw_env_query_module_eeprom(mlxsw_core, module, 0, offset,
170 module_info, &read_size);
174 if (read_size < offset)
177 module_rev_id = module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID];
178 module_id = module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID];
181 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP:
182 modinfo->type = ETH_MODULE_SFF_8436;
183 modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
185 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS: /* fall-through */
186 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28:
187 if (module_id == MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28 ||
189 MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID_8636) {
190 modinfo->type = ETH_MODULE_SFF_8636;
191 modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
193 modinfo->type = ETH_MODULE_SFF_8436;
194 modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
197 case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP:
198 modinfo->type = ETH_MODULE_SFF_8472;
199 modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
207 EXPORT_SYMBOL(mlxsw_env_get_module_info);
209 int mlxsw_env_get_module_eeprom(struct net_device *netdev,
210 struct mlxsw_core *mlxsw_core, int module,
211 struct ethtool_eeprom *ee, u8 *data)
213 int offset = ee->offset;
214 unsigned int read_size;
221 memset(data, 0, ee->len);
223 while (i < ee->len) {
224 err = mlxsw_env_query_module_eeprom(mlxsw_core, module, offset,
225 ee->len - i, data + i,
228 netdev_err(netdev, "Eeprom query failed\n");
238 EXPORT_SYMBOL(mlxsw_env_get_module_eeprom);