sfc: Added support for new ethtool APIs for obtaining module eeprom
Currently allows for SFP+ eeprom to be returned using the ethtool API. This can be extended in future to handle different eeprom formats and sizes Signed-off-by: Stuart Hodgson <smhodgson@solarflare.com> [bwh: Drop redundant validation, comment, whitespace] Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
This commit is contained in:
parent
41c3cb6d20
commit
c087bd2cfd
|
@ -1108,6 +1108,39 @@ static int efx_ethtool_set_rxfh_indir(struct net_device *net_dev,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int efx_ethtool_get_module_eeprom(struct net_device *net_dev,
|
||||||
|
struct ethtool_eeprom *ee,
|
||||||
|
u8 *data)
|
||||||
|
{
|
||||||
|
struct efx_nic *efx = netdev_priv(net_dev);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!efx->phy_op || !efx->phy_op->get_module_eeprom)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
mutex_lock(&efx->mac_lock);
|
||||||
|
ret = efx->phy_op->get_module_eeprom(efx, ee, data);
|
||||||
|
mutex_unlock(&efx->mac_lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int efx_ethtool_get_module_info(struct net_device *net_dev,
|
||||||
|
struct ethtool_modinfo *modinfo)
|
||||||
|
{
|
||||||
|
struct efx_nic *efx = netdev_priv(net_dev);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!efx->phy_op || !efx->phy_op->get_module_info)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
mutex_lock(&efx->mac_lock);
|
||||||
|
ret = efx->phy_op->get_module_info(efx, modinfo);
|
||||||
|
mutex_unlock(&efx->mac_lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
const struct ethtool_ops efx_ethtool_ops = {
|
const struct ethtool_ops efx_ethtool_ops = {
|
||||||
.get_settings = efx_ethtool_get_settings,
|
.get_settings = efx_ethtool_get_settings,
|
||||||
.set_settings = efx_ethtool_set_settings,
|
.set_settings = efx_ethtool_set_settings,
|
||||||
|
@ -1137,4 +1170,6 @@ const struct ethtool_ops efx_ethtool_ops = {
|
||||||
.get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size,
|
.get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size,
|
||||||
.get_rxfh_indir = efx_ethtool_get_rxfh_indir,
|
.get_rxfh_indir = efx_ethtool_get_rxfh_indir,
|
||||||
.set_rxfh_indir = efx_ethtool_set_rxfh_indir,
|
.set_rxfh_indir = efx_ethtool_set_rxfh_indir,
|
||||||
|
.get_module_info = efx_ethtool_get_module_info,
|
||||||
|
.get_module_eeprom = efx_ethtool_get_module_eeprom,
|
||||||
};
|
};
|
||||||
|
|
|
@ -739,6 +739,80 @@ static const char *efx_mcdi_phy_test_name(struct efx_nic *efx,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SFP_PAGE_SIZE 128
|
||||||
|
#define SFP_NUM_PAGES 2
|
||||||
|
static int efx_mcdi_phy_get_module_eeprom(struct efx_nic *efx,
|
||||||
|
struct ethtool_eeprom *ee, u8 *data)
|
||||||
|
{
|
||||||
|
u8 outbuf[MC_CMD_GET_PHY_MEDIA_INFO_OUT_LENMAX];
|
||||||
|
u8 inbuf[MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN];
|
||||||
|
size_t outlen;
|
||||||
|
int rc;
|
||||||
|
unsigned int payload_len;
|
||||||
|
unsigned int space_remaining = ee->len;
|
||||||
|
unsigned int page;
|
||||||
|
unsigned int page_off;
|
||||||
|
unsigned int to_copy;
|
||||||
|
u8 *user_data = data;
|
||||||
|
|
||||||
|
BUILD_BUG_ON(SFP_PAGE_SIZE * SFP_NUM_PAGES != ETH_MODULE_SFF_8079_LEN);
|
||||||
|
|
||||||
|
page_off = ee->offset % SFP_PAGE_SIZE;
|
||||||
|
page = ee->offset / SFP_PAGE_SIZE;
|
||||||
|
|
||||||
|
while (space_remaining && (page < SFP_NUM_PAGES)) {
|
||||||
|
MCDI_SET_DWORD(inbuf, GET_PHY_MEDIA_INFO_IN_PAGE, page);
|
||||||
|
|
||||||
|
rc = efx_mcdi_rpc(efx, MC_CMD_GET_PHY_MEDIA_INFO,
|
||||||
|
inbuf, sizeof(inbuf),
|
||||||
|
outbuf, sizeof(outbuf),
|
||||||
|
&outlen);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
if (outlen < (MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATA_OFST +
|
||||||
|
SFP_PAGE_SIZE))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
payload_len = MCDI_DWORD(outbuf,
|
||||||
|
GET_PHY_MEDIA_INFO_OUT_DATALEN);
|
||||||
|
if (payload_len != SFP_PAGE_SIZE)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
/* Copy as much as we can into data */
|
||||||
|
payload_len -= page_off;
|
||||||
|
to_copy = (space_remaining < payload_len) ?
|
||||||
|
space_remaining : payload_len;
|
||||||
|
|
||||||
|
memcpy(user_data,
|
||||||
|
outbuf + page_off +
|
||||||
|
MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATA_OFST,
|
||||||
|
to_copy);
|
||||||
|
|
||||||
|
space_remaining -= to_copy;
|
||||||
|
user_data += to_copy;
|
||||||
|
page_off = 0;
|
||||||
|
page++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int efx_mcdi_phy_get_module_info(struct efx_nic *efx,
|
||||||
|
struct ethtool_modinfo *modinfo)
|
||||||
|
{
|
||||||
|
struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
|
||||||
|
|
||||||
|
switch (phy_cfg->media) {
|
||||||
|
case MC_CMD_MEDIA_SFP_PLUS:
|
||||||
|
modinfo->type = ETH_MODULE_SFF_8079;
|
||||||
|
modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const struct efx_phy_operations efx_mcdi_phy_ops = {
|
const struct efx_phy_operations efx_mcdi_phy_ops = {
|
||||||
.probe = efx_mcdi_phy_probe,
|
.probe = efx_mcdi_phy_probe,
|
||||||
.init = efx_port_dummy_op_int,
|
.init = efx_port_dummy_op_int,
|
||||||
|
@ -751,4 +825,6 @@ const struct efx_phy_operations efx_mcdi_phy_ops = {
|
||||||
.test_alive = efx_mcdi_phy_test_alive,
|
.test_alive = efx_mcdi_phy_test_alive,
|
||||||
.run_tests = efx_mcdi_phy_run_tests,
|
.run_tests = efx_mcdi_phy_run_tests,
|
||||||
.test_name = efx_mcdi_phy_test_name,
|
.test_name = efx_mcdi_phy_test_name,
|
||||||
|
.get_module_eeprom = efx_mcdi_phy_get_module_eeprom,
|
||||||
|
.get_module_info = efx_mcdi_phy_get_module_info,
|
||||||
};
|
};
|
||||||
|
|
|
@ -519,6 +519,11 @@ struct efx_phy_operations {
|
||||||
int (*test_alive) (struct efx_nic *efx);
|
int (*test_alive) (struct efx_nic *efx);
|
||||||
const char *(*test_name) (struct efx_nic *efx, unsigned int index);
|
const char *(*test_name) (struct efx_nic *efx, unsigned int index);
|
||||||
int (*run_tests) (struct efx_nic *efx, int *results, unsigned flags);
|
int (*run_tests) (struct efx_nic *efx, int *results, unsigned flags);
|
||||||
|
int (*get_module_eeprom) (struct efx_nic *efx,
|
||||||
|
struct ethtool_eeprom *ee,
|
||||||
|
u8 *data);
|
||||||
|
int (*get_module_info) (struct efx_nic *efx,
|
||||||
|
struct ethtool_modinfo *modinfo);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue