Skip to content

Commit bb64143

Browse files
Gal Pressmandavem330
authored andcommitted
net/mlx5e: Add ethtool support for dump module EEPROM
Add query MCIA, PMLP registers infrastructure and commands. Add ethtool support for get_module_info() and get_module_eeprom() callbacks. Signed-off-by: Gal Pressman <[email protected]> Signed-off-by: Saeed Mahameed <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent da54d24 commit bb64143

File tree

4 files changed

+173
-1
lines changed

4 files changed

+173
-1
lines changed

drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1159,6 +1159,84 @@ static int mlx5e_set_phys_id(struct net_device *dev,
11591159
return mlx5_set_port_beacon(mdev, beacon_duration);
11601160
}
11611161

1162+
static int mlx5e_get_module_info(struct net_device *netdev,
1163+
struct ethtool_modinfo *modinfo)
1164+
{
1165+
struct mlx5e_priv *priv = netdev_priv(netdev);
1166+
struct mlx5_core_dev *dev = priv->mdev;
1167+
int size_read = 0;
1168+
u8 data[4];
1169+
1170+
size_read = mlx5_query_module_eeprom(dev, 0, 2, data);
1171+
if (size_read < 2)
1172+
return -EIO;
1173+
1174+
/* data[0] = identifier byte */
1175+
switch (data[0]) {
1176+
case MLX5_MODULE_ID_QSFP:
1177+
modinfo->type = ETH_MODULE_SFF_8436;
1178+
modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
1179+
break;
1180+
case MLX5_MODULE_ID_QSFP_PLUS:
1181+
case MLX5_MODULE_ID_QSFP28:
1182+
/* data[1] = revision id */
1183+
if (data[0] == MLX5_MODULE_ID_QSFP28 || data[1] >= 0x3) {
1184+
modinfo->type = ETH_MODULE_SFF_8636;
1185+
modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
1186+
} else {
1187+
modinfo->type = ETH_MODULE_SFF_8436;
1188+
modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
1189+
}
1190+
break;
1191+
case MLX5_MODULE_ID_SFP:
1192+
modinfo->type = ETH_MODULE_SFF_8472;
1193+
modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
1194+
break;
1195+
default:
1196+
netdev_err(priv->netdev, "%s: cable type not recognized:0x%x\n",
1197+
__func__, data[0]);
1198+
return -EINVAL;
1199+
}
1200+
1201+
return 0;
1202+
}
1203+
1204+
static int mlx5e_get_module_eeprom(struct net_device *netdev,
1205+
struct ethtool_eeprom *ee,
1206+
u8 *data)
1207+
{
1208+
struct mlx5e_priv *priv = netdev_priv(netdev);
1209+
struct mlx5_core_dev *mdev = priv->mdev;
1210+
int offset = ee->offset;
1211+
int size_read;
1212+
int i = 0;
1213+
1214+
if (!ee->len)
1215+
return -EINVAL;
1216+
1217+
memset(data, 0, ee->len);
1218+
1219+
while (i < ee->len) {
1220+
size_read = mlx5_query_module_eeprom(mdev, offset, ee->len - i,
1221+
data + i);
1222+
1223+
if (!size_read)
1224+
/* Done reading */
1225+
return 0;
1226+
1227+
if (size_read < 0) {
1228+
netdev_err(priv->netdev, "%s: mlx5_query_eeprom failed:0x%x\n",
1229+
__func__, size_read);
1230+
return 0;
1231+
}
1232+
1233+
i += size_read;
1234+
offset += size_read;
1235+
}
1236+
1237+
return 0;
1238+
}
1239+
11621240
const struct ethtool_ops mlx5e_ethtool_ops = {
11631241
.get_drvinfo = mlx5e_get_drvinfo,
11641242
.get_link = ethtool_op_get_link,
@@ -1186,4 +1264,6 @@ const struct ethtool_ops mlx5e_ethtool_ops = {
11861264
.set_phys_id = mlx5e_set_phys_id,
11871265
.get_wol = mlx5e_get_wol,
11881266
.set_wol = mlx5e_set_wol,
1267+
.get_module_info = mlx5e_get_module_info,
1268+
.get_module_eeprom = mlx5e_get_module_eeprom,
11891269
};

drivers/net/ethernet/mellanox/mlx5/core/port.c

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,82 @@ void mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, int *oper_mtu,
310310
}
311311
EXPORT_SYMBOL_GPL(mlx5_query_port_oper_mtu);
312312

313+
static int mlx5_query_module_num(struct mlx5_core_dev *dev, int *module_num)
314+
{
315+
u32 out[MLX5_ST_SZ_DW(pmlp_reg)];
316+
u32 in[MLX5_ST_SZ_DW(pmlp_reg)];
317+
int module_mapping;
318+
int err;
319+
320+
memset(in, 0, sizeof(in));
321+
322+
MLX5_SET(pmlp_reg, in, local_port, 1);
323+
324+
err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out),
325+
MLX5_REG_PMLP, 0, 0);
326+
if (err)
327+
return err;
328+
329+
module_mapping = MLX5_GET(pmlp_reg, out, lane0_module_mapping);
330+
*module_num = module_mapping & MLX5_EEPROM_IDENTIFIER_BYTE_MASK;
331+
332+
return 0;
333+
}
334+
335+
int mlx5_query_module_eeprom(struct mlx5_core_dev *dev,
336+
u16 offset, u16 size, u8 *data)
337+
{
338+
u32 out[MLX5_ST_SZ_DW(mcia_reg)];
339+
u32 in[MLX5_ST_SZ_DW(mcia_reg)];
340+
int module_num;
341+
u16 i2c_addr;
342+
int status;
343+
int err;
344+
void *ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0);
345+
346+
err = mlx5_query_module_num(dev, &module_num);
347+
if (err)
348+
return err;
349+
350+
memset(in, 0, sizeof(in));
351+
size = min_t(int, size, MLX5_EEPROM_MAX_BYTES);
352+
353+
if (offset < MLX5_EEPROM_PAGE_LENGTH &&
354+
offset + size > MLX5_EEPROM_PAGE_LENGTH)
355+
/* Cross pages read, read until offset 256 in low page */
356+
size -= offset + size - MLX5_EEPROM_PAGE_LENGTH;
357+
358+
i2c_addr = MLX5_I2C_ADDR_LOW;
359+
if (offset >= MLX5_EEPROM_PAGE_LENGTH) {
360+
i2c_addr = MLX5_I2C_ADDR_HIGH;
361+
offset -= MLX5_EEPROM_PAGE_LENGTH;
362+
}
363+
364+
MLX5_SET(mcia_reg, in, l, 0);
365+
MLX5_SET(mcia_reg, in, module, module_num);
366+
MLX5_SET(mcia_reg, in, i2c_device_address, i2c_addr);
367+
MLX5_SET(mcia_reg, in, page_number, 0);
368+
MLX5_SET(mcia_reg, in, device_address, offset);
369+
MLX5_SET(mcia_reg, in, size, size);
370+
371+
err = mlx5_core_access_reg(dev, in, sizeof(in), out,
372+
sizeof(out), MLX5_REG_MCIA, 0, 0);
373+
if (err)
374+
return err;
375+
376+
status = MLX5_GET(mcia_reg, out, status);
377+
if (status) {
378+
mlx5_core_err(dev, "query_mcia_reg failed: status: 0x%x\n",
379+
status);
380+
return -EIO;
381+
}
382+
383+
memcpy(data, ptr, size);
384+
385+
return size;
386+
}
387+
EXPORT_SYMBOL_GPL(mlx5_query_module_eeprom);
388+
313389
static int mlx5_query_port_pvlc(struct mlx5_core_dev *dev, u32 *pvlc,
314390
int pvlc_size, u8 local_port)
315391
{

include/linux/mlx5/driver.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,10 @@ enum {
113113
MLX5_REG_PELC = 0x500e,
114114
MLX5_REG_PVLC = 0x500f,
115115
MLX5_REG_PCMR = 0x5041,
116-
MLX5_REG_PMLP = 0, /* TBD */
116+
MLX5_REG_PMLP = 0x5002,
117117
MLX5_REG_NODE_DESC = 0x6001,
118118
MLX5_REG_HOST_ENDIANNESS = 0x7004,
119+
MLX5_REG_MCIA = 0x9014,
119120
MLX5_REG_MLCR = 0x902b,
120121
};
121122

include/linux/mlx5/port.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,19 @@ enum mlx5_beacon_duration {
4040
MLX5_BEACON_DURATION_INF = 0xffff,
4141
};
4242

43+
enum mlx5_module_id {
44+
MLX5_MODULE_ID_SFP = 0x3,
45+
MLX5_MODULE_ID_QSFP = 0xC,
46+
MLX5_MODULE_ID_QSFP_PLUS = 0xD,
47+
MLX5_MODULE_ID_QSFP28 = 0x11,
48+
};
49+
50+
#define MLX5_EEPROM_MAX_BYTES 32
51+
#define MLX5_EEPROM_IDENTIFIER_BYTE_MASK 0x000000ff
52+
#define MLX5_I2C_ADDR_LOW 0x50
53+
#define MLX5_I2C_ADDR_HIGH 0x51
54+
#define MLX5_EEPROM_PAGE_LENGTH 256
55+
4356
int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps);
4457
int mlx5_query_port_ptys(struct mlx5_core_dev *dev, u32 *ptys,
4558
int ptys_size, int proto_mask, u8 local_port);
@@ -93,5 +106,7 @@ int mlx5_query_port_wol(struct mlx5_core_dev *mdev, u8 *wol_mode);
93106
int mlx5_set_port_fcs(struct mlx5_core_dev *mdev, u8 enable);
94107
void mlx5_query_port_fcs(struct mlx5_core_dev *mdev, bool *supported,
95108
bool *enabled);
109+
int mlx5_query_module_eeprom(struct mlx5_core_dev *dev,
110+
u16 offset, u16 size, u8 *data);
96111

97112
#endif /* __MLX5_PORT_H__ */

0 commit comments

Comments
 (0)