Skip to content
/ linux Public

Commit 1e27b9e

Browse files
idoschdavem330
authored andcommitted
mlxsw: core: Add support for module EEPROM read by page
Add support for ethtool_ops::get_module_eeprom_by_page() which allows user space to read transceiver module EEPROM based on passed parameters. The I2C address is not validated in order to avoid module-specific code. In case of wrong address, error will be returned from device's firmware. Tested by comparing output with legacy method (ioctl) output. Signed-off-by: Ido Schimmel <idosch@nvidia.com> Tested-by: Vadim Pasternak <vadimp@nvidia.com> Reviewed-by: Jiri Pirko <jiri@nvidia.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent cecefb3 commit 1e27b9e

File tree

4 files changed

+108
-0
lines changed

4 files changed

+108
-0
lines changed

drivers/net/ethernet/mellanox/mlxsw/core_env.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include <linux/kernel.h>
55
#include <linux/err.h>
6+
#include <linux/ethtool.h>
67
#include <linux/sfp.h>
78

89
#include "core.h"
@@ -315,6 +316,79 @@ int mlxsw_env_get_module_eeprom(struct net_device *netdev,
315316
}
316317
EXPORT_SYMBOL(mlxsw_env_get_module_eeprom);
317318

319+
static int mlxsw_env_mcia_status_process(const char *mcia_pl,
320+
struct netlink_ext_ack *extack)
321+
{
322+
u8 status = mlxsw_reg_mcia_status_get(mcia_pl);
323+
324+
switch (status) {
325+
case MLXSW_REG_MCIA_STATUS_GOOD:
326+
return 0;
327+
case MLXSW_REG_MCIA_STATUS_NO_EEPROM_MODULE:
328+
NL_SET_ERR_MSG_MOD(extack, "No response from module's EEPROM");
329+
return -EIO;
330+
case MLXSW_REG_MCIA_STATUS_MODULE_NOT_SUPPORTED:
331+
NL_SET_ERR_MSG_MOD(extack, "Module type not supported by the device");
332+
return -EOPNOTSUPP;
333+
case MLXSW_REG_MCIA_STATUS_MODULE_NOT_CONNECTED:
334+
NL_SET_ERR_MSG_MOD(extack, "No module present indication");
335+
return -EIO;
336+
case MLXSW_REG_MCIA_STATUS_I2C_ERROR:
337+
NL_SET_ERR_MSG_MOD(extack, "Error occurred while trying to access module's EEPROM using I2C");
338+
return -EIO;
339+
case MLXSW_REG_MCIA_STATUS_MODULE_DISABLED:
340+
NL_SET_ERR_MSG_MOD(extack, "Module is disabled");
341+
return -EIO;
342+
default:
343+
NL_SET_ERR_MSG_MOD(extack, "Unknown error");
344+
return -EIO;
345+
}
346+
}
347+
348+
int
349+
mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, u8 module,
350+
const struct ethtool_module_eeprom *page,
351+
struct netlink_ext_ack *extack)
352+
{
353+
u32 bytes_read = 0;
354+
u16 device_addr;
355+
356+
/* Offset cannot be larger than 2 * ETH_MODULE_EEPROM_PAGE_LEN */
357+
device_addr = page->offset;
358+
359+
while (bytes_read < page->length) {
360+
char eeprom_tmp[MLXSW_REG_MCIA_EEPROM_SIZE];
361+
char mcia_pl[MLXSW_REG_MCIA_LEN];
362+
u8 size;
363+
int err;
364+
365+
size = min_t(u8, page->length - bytes_read,
366+
MLXSW_REG_MCIA_EEPROM_SIZE);
367+
368+
mlxsw_reg_mcia_pack(mcia_pl, module, 0, page->page,
369+
device_addr + bytes_read, size,
370+
page->i2c_address);
371+
mlxsw_reg_mcia_bank_number_set(mcia_pl, page->bank);
372+
373+
err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl);
374+
if (err) {
375+
NL_SET_ERR_MSG_MOD(extack, "Failed to access module's EEPROM");
376+
return err;
377+
}
378+
379+
err = mlxsw_env_mcia_status_process(mcia_pl, extack);
380+
if (err)
381+
return err;
382+
383+
mlxsw_reg_mcia_eeprom_memcpy_from(mcia_pl, eeprom_tmp);
384+
memcpy(page->data + bytes_read, eeprom_tmp, size);
385+
bytes_read += size;
386+
}
387+
388+
return bytes_read;
389+
}
390+
EXPORT_SYMBOL(mlxsw_env_get_module_eeprom_by_page);
391+
318392
static int mlxsw_env_module_has_temp_sensor(struct mlxsw_core *mlxsw_core,
319393
u8 module,
320394
bool *p_has_temp_sensor)

drivers/net/ethernet/mellanox/mlxsw/core_env.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#ifndef _MLXSW_CORE_ENV_H
55
#define _MLXSW_CORE_ENV_H
66

7+
#include <linux/ethtool.h>
8+
79
struct ethtool_modinfo;
810
struct ethtool_eeprom;
911

@@ -17,6 +19,11 @@ int mlxsw_env_get_module_eeprom(struct net_device *netdev,
1719
struct mlxsw_core *mlxsw_core, int module,
1820
struct ethtool_eeprom *ee, u8 *data);
1921

22+
int
23+
mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, u8 module,
24+
const struct ethtool_module_eeprom *page,
25+
struct netlink_ext_ack *extack);
26+
2027
int
2128
mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 module,
2229
u64 *p_counter);

drivers/net/ethernet/mellanox/mlxsw/minimal.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,23 @@ mlxsw_m_get_module_eeprom(struct net_device *netdev, struct ethtool_eeprom *ee,
112112
ee, data);
113113
}
114114

115+
static int
116+
mlxsw_m_get_module_eeprom_by_page(struct net_device *netdev,
117+
const struct ethtool_module_eeprom *page,
118+
struct netlink_ext_ack *extack)
119+
{
120+
struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
121+
struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
122+
123+
return mlxsw_env_get_module_eeprom_by_page(core, mlxsw_m_port->module,
124+
page, extack);
125+
}
126+
115127
static const struct ethtool_ops mlxsw_m_port_ethtool_ops = {
116128
.get_drvinfo = mlxsw_m_module_get_drvinfo,
117129
.get_module_info = mlxsw_m_get_module_info,
118130
.get_module_eeprom = mlxsw_m_get_module_eeprom,
131+
.get_module_eeprom_by_page = mlxsw_m_get_module_eeprom_by_page,
119132
};
120133

121134
static int

drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,6 +1050,19 @@ static int mlxsw_sp_get_module_eeprom(struct net_device *netdev,
10501050
return err;
10511051
}
10521052

1053+
static int
1054+
mlxsw_sp_get_module_eeprom_by_page(struct net_device *dev,
1055+
const struct ethtool_module_eeprom *page,
1056+
struct netlink_ext_ack *extack)
1057+
{
1058+
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
1059+
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1060+
u8 module = mlxsw_sp_port->mapping.module;
1061+
1062+
return mlxsw_env_get_module_eeprom_by_page(mlxsw_sp->core, module, page,
1063+
extack);
1064+
}
1065+
10531066
static int
10541067
mlxsw_sp_get_ts_info(struct net_device *netdev, struct ethtool_ts_info *info)
10551068
{
@@ -1199,6 +1212,7 @@ const struct ethtool_ops mlxsw_sp_port_ethtool_ops = {
11991212
.set_link_ksettings = mlxsw_sp_port_set_link_ksettings,
12001213
.get_module_info = mlxsw_sp_get_module_info,
12011214
.get_module_eeprom = mlxsw_sp_get_module_eeprom,
1215+
.get_module_eeprom_by_page = mlxsw_sp_get_module_eeprom_by_page,
12021216
.get_ts_info = mlxsw_sp_get_ts_info,
12031217
.get_eth_phy_stats = mlxsw_sp_get_eth_phy_stats,
12041218
.get_eth_mac_stats = mlxsw_sp_get_eth_mac_stats,

0 commit comments

Comments
 (0)