Skip to content

Commit

Permalink
nfp: implement ethtool get module EEPROM
Browse files Browse the repository at this point in the history
Now that the NSP provides the ability to read from the SFF modules'
EEPROM, we can use this interface to implement the ethtool callback.

If the NSP only provides partial data, we log the event from within
the driver but pass a success code to ethtool to prevent it from
discarding the partial data.

Signed-off-by: Dirk van der Merwe <dirk.vandermerwe@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Dirk van der Merwe authored and davem330 committed Apr 2, 2019
1 parent 593cb18 commit 61f7c6f
Showing 1 changed file with 131 additions and 0 deletions.
131 changes: 131 additions & 0 deletions drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <linux/pci.h>
#include <linux/ethtool.h>
#include <linux/firmware.h>
#include <linux/sfp.h>

#include "nfpcore/nfp.h"
#include "nfpcore/nfp_nsp.h"
Expand Down Expand Up @@ -152,6 +153,8 @@ static const struct nfp_et_stat nfp_mac_et_stats[] = {
#define NN_RVEC_GATHER_STATS 9
#define NN_RVEC_PER_Q_STATS 3

#define SFP_SFF_REV_COMPLIANCE 1

static void nfp_net_get_nspinfo(struct nfp_app *app, char *version)
{
struct nfp_nsp *nsp;
Expand Down Expand Up @@ -1096,6 +1099,130 @@ nfp_app_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
buffer);
}

static int
nfp_port_get_module_info(struct net_device *netdev,
struct ethtool_modinfo *modinfo)
{
struct nfp_eth_table_port *eth_port;
struct nfp_port *port;
unsigned int read_len;
struct nfp_nsp *nsp;
int err = 0;
u8 data;

port = nfp_port_from_netdev(netdev);
eth_port = nfp_port_get_eth_port(port);
if (!eth_port)
return -EOPNOTSUPP;

nsp = nfp_nsp_open(port->app->cpp);
if (IS_ERR(nsp)) {
err = PTR_ERR(nsp);
netdev_err(netdev, "Failed to access the NSP: %d\n", err);
return err;
}

if (!nfp_nsp_has_read_module_eeprom(nsp)) {
netdev_info(netdev, "reading module EEPROM not supported. Please update flash\n");
err = -EOPNOTSUPP;
goto exit_close_nsp;
}

switch (eth_port->interface) {
case NFP_INTERFACE_SFP:
case NFP_INTERFACE_SFP28:
err = nfp_nsp_read_module_eeprom(nsp, eth_port->eth_index,
SFP_SFF8472_COMPLIANCE, &data,
1, &read_len);
if (err < 0)
goto exit_close_nsp;

if (!data) {
modinfo->type = ETH_MODULE_SFF_8079;
modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
} else {
modinfo->type = ETH_MODULE_SFF_8472;
modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
}
break;
case NFP_INTERFACE_QSFP:
err = nfp_nsp_read_module_eeprom(nsp, eth_port->eth_index,
SFP_SFF_REV_COMPLIANCE, &data,
1, &read_len);
if (err < 0)
goto exit_close_nsp;

if (data < 0x3) {
modinfo->type = ETH_MODULE_SFF_8436;
modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
} else {
modinfo->type = ETH_MODULE_SFF_8636;
modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
}
break;
case NFP_INTERFACE_QSFP28:
modinfo->type = ETH_MODULE_SFF_8636;
modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
break;
default:
netdev_err(netdev, "Unsupported module 0x%x detected\n",
eth_port->interface);
err = -EINVAL;
}

exit_close_nsp:
nfp_nsp_close(nsp);
return err;
}

static int
nfp_port_get_module_eeprom(struct net_device *netdev,
struct ethtool_eeprom *eeprom, u8 *data)
{
struct nfp_eth_table_port *eth_port;
struct nfp_port *port;
struct nfp_nsp *nsp;
int err;

port = nfp_port_from_netdev(netdev);
eth_port = __nfp_port_get_eth_port(port);
if (!eth_port)
return -EOPNOTSUPP;

nsp = nfp_nsp_open(port->app->cpp);
if (IS_ERR(nsp)) {
err = PTR_ERR(nsp);
netdev_err(netdev, "Failed to access the NSP: %d\n", err);
return err;
}

if (!nfp_nsp_has_read_module_eeprom(nsp)) {
netdev_info(netdev, "reading module EEPROM not supported. Please update flash\n");
err = -EOPNOTSUPP;
goto exit_close_nsp;
}

err = nfp_nsp_read_module_eeprom(nsp, eth_port->eth_index,
eeprom->offset, data, eeprom->len,
&eeprom->len);
if (err < 0) {
if (eeprom->len) {
netdev_warn(netdev,
"Incomplete read from module EEPROM: %d\n",
err);
err = 0;
} else {
netdev_err(netdev,
"Reading from module EEPROM failed: %d\n",
err);
}
}

exit_close_nsp:
nfp_nsp_close(nsp);
return err;
}

static int nfp_net_set_coalesce(struct net_device *netdev,
struct ethtool_coalesce *ec)
{
Expand Down Expand Up @@ -1253,6 +1380,8 @@ static const struct ethtool_ops nfp_net_ethtool_ops = {
.set_dump = nfp_app_set_dump,
.get_dump_flag = nfp_app_get_dump_flag,
.get_dump_data = nfp_app_get_dump_data,
.get_module_info = nfp_port_get_module_info,
.get_module_eeprom = nfp_port_get_module_eeprom,
.get_coalesce = nfp_net_get_coalesce,
.set_coalesce = nfp_net_set_coalesce,
.get_channels = nfp_net_get_channels,
Expand All @@ -1272,6 +1401,8 @@ const struct ethtool_ops nfp_port_ethtool_ops = {
.set_dump = nfp_app_set_dump,
.get_dump_flag = nfp_app_get_dump_flag,
.get_dump_data = nfp_app_get_dump_data,
.get_module_info = nfp_port_get_module_info,
.get_module_eeprom = nfp_port_get_module_eeprom,
.get_link_ksettings = nfp_net_get_link_ksettings,
.set_link_ksettings = nfp_net_set_link_ksettings,
.get_fecparam = nfp_port_get_fecparam,
Expand Down

0 comments on commit 61f7c6f

Please sign in to comment.