diff options
| author | Stuart Hodgson <smhodgson@solarflare.com> | 2012-05-01 18:50:43 +0100 | 
|---|---|---|
| committer | Ben Hutchings <bhutchings@solarflare.com> | 2012-05-10 03:10:46 +0100 | 
| commit | c087bd2cfdaf334d7d0c32bd1fcc1a23d5b88973 (patch) | |
| tree | 9b0edadd759f4210ad890a686880f85e31f0bc2c /drivers/net/ethernet/sfc/mcdi_phy.c | |
| parent | 41c3cb6d20f0252308e9796fa4f3dacb4960de91 (diff) | |
| download | olio-linux-3.10-c087bd2cfdaf334d7d0c32bd1fcc1a23d5b88973.tar.xz olio-linux-3.10-c087bd2cfdaf334d7d0c32bd1fcc1a23d5b88973.zip  | |
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>
Diffstat (limited to 'drivers/net/ethernet/sfc/mcdi_phy.c')
| -rw-r--r-- | drivers/net/ethernet/sfc/mcdi_phy.c | 76 | 
1 files changed, 76 insertions, 0 deletions
diff --git a/drivers/net/ethernet/sfc/mcdi_phy.c b/drivers/net/ethernet/sfc/mcdi_phy.c index 7bcad899a93..13cb40fe90c 100644 --- a/drivers/net/ethernet/sfc/mcdi_phy.c +++ b/drivers/net/ethernet/sfc/mcdi_phy.c @@ -739,6 +739,80 @@ static const char *efx_mcdi_phy_test_name(struct efx_nic *efx,  	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 = {  	.probe		= efx_mcdi_phy_probe,  	.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,  	.run_tests	= efx_mcdi_phy_run_tests,  	.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,  };  |