Commit c087bd2cfdaf334d7d0c32bd1fcc1a23d5b88973

Authored by Stuart Hodgson
Committed by Ben Hutchings
1 parent 41c3cb6d20

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>

Showing 3 changed files with 116 additions and 0 deletions Side-by-side Diff

drivers/net/ethernet/sfc/ethtool.c
... ... @@ -1108,6 +1108,39 @@
1108 1108 return 0;
1109 1109 }
1110 1110  
  1111 +static int efx_ethtool_get_module_eeprom(struct net_device *net_dev,
  1112 + struct ethtool_eeprom *ee,
  1113 + u8 *data)
  1114 +{
  1115 + struct efx_nic *efx = netdev_priv(net_dev);
  1116 + int ret;
  1117 +
  1118 + if (!efx->phy_op || !efx->phy_op->get_module_eeprom)
  1119 + return -EOPNOTSUPP;
  1120 +
  1121 + mutex_lock(&efx->mac_lock);
  1122 + ret = efx->phy_op->get_module_eeprom(efx, ee, data);
  1123 + mutex_unlock(&efx->mac_lock);
  1124 +
  1125 + return ret;
  1126 +}
  1127 +
  1128 +static int efx_ethtool_get_module_info(struct net_device *net_dev,
  1129 + struct ethtool_modinfo *modinfo)
  1130 +{
  1131 + struct efx_nic *efx = netdev_priv(net_dev);
  1132 + int ret;
  1133 +
  1134 + if (!efx->phy_op || !efx->phy_op->get_module_info)
  1135 + return -EOPNOTSUPP;
  1136 +
  1137 + mutex_lock(&efx->mac_lock);
  1138 + ret = efx->phy_op->get_module_info(efx, modinfo);
  1139 + mutex_unlock(&efx->mac_lock);
  1140 +
  1141 + return ret;
  1142 +}
  1143 +
1111 1144 const struct ethtool_ops efx_ethtool_ops = {
1112 1145 .get_settings = efx_ethtool_get_settings,
1113 1146 .set_settings = efx_ethtool_set_settings,
... ... @@ -1137,5 +1170,7 @@
1137 1170 .get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size,
1138 1171 .get_rxfh_indir = efx_ethtool_get_rxfh_indir,
1139 1172 .set_rxfh_indir = efx_ethtool_set_rxfh_indir,
  1173 + .get_module_info = efx_ethtool_get_module_info,
  1174 + .get_module_eeprom = efx_ethtool_get_module_eeprom,
1140 1175 };
drivers/net/ethernet/sfc/mcdi_phy.c
... ... @@ -739,6 +739,80 @@
739 739 return NULL;
740 740 }
741 741  
  742 +#define SFP_PAGE_SIZE 128
  743 +#define SFP_NUM_PAGES 2
  744 +static int efx_mcdi_phy_get_module_eeprom(struct efx_nic *efx,
  745 + struct ethtool_eeprom *ee, u8 *data)
  746 +{
  747 + u8 outbuf[MC_CMD_GET_PHY_MEDIA_INFO_OUT_LENMAX];
  748 + u8 inbuf[MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN];
  749 + size_t outlen;
  750 + int rc;
  751 + unsigned int payload_len;
  752 + unsigned int space_remaining = ee->len;
  753 + unsigned int page;
  754 + unsigned int page_off;
  755 + unsigned int to_copy;
  756 + u8 *user_data = data;
  757 +
  758 + BUILD_BUG_ON(SFP_PAGE_SIZE * SFP_NUM_PAGES != ETH_MODULE_SFF_8079_LEN);
  759 +
  760 + page_off = ee->offset % SFP_PAGE_SIZE;
  761 + page = ee->offset / SFP_PAGE_SIZE;
  762 +
  763 + while (space_remaining && (page < SFP_NUM_PAGES)) {
  764 + MCDI_SET_DWORD(inbuf, GET_PHY_MEDIA_INFO_IN_PAGE, page);
  765 +
  766 + rc = efx_mcdi_rpc(efx, MC_CMD_GET_PHY_MEDIA_INFO,
  767 + inbuf, sizeof(inbuf),
  768 + outbuf, sizeof(outbuf),
  769 + &outlen);
  770 + if (rc)
  771 + return rc;
  772 +
  773 + if (outlen < (MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATA_OFST +
  774 + SFP_PAGE_SIZE))
  775 + return -EIO;
  776 +
  777 + payload_len = MCDI_DWORD(outbuf,
  778 + GET_PHY_MEDIA_INFO_OUT_DATALEN);
  779 + if (payload_len != SFP_PAGE_SIZE)
  780 + return -EIO;
  781 +
  782 + /* Copy as much as we can into data */
  783 + payload_len -= page_off;
  784 + to_copy = (space_remaining < payload_len) ?
  785 + space_remaining : payload_len;
  786 +
  787 + memcpy(user_data,
  788 + outbuf + page_off +
  789 + MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATA_OFST,
  790 + to_copy);
  791 +
  792 + space_remaining -= to_copy;
  793 + user_data += to_copy;
  794 + page_off = 0;
  795 + page++;
  796 + }
  797 +
  798 + return 0;
  799 +}
  800 +
  801 +static int efx_mcdi_phy_get_module_info(struct efx_nic *efx,
  802 + struct ethtool_modinfo *modinfo)
  803 +{
  804 + struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
  805 +
  806 + switch (phy_cfg->media) {
  807 + case MC_CMD_MEDIA_SFP_PLUS:
  808 + modinfo->type = ETH_MODULE_SFF_8079;
  809 + modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
  810 + return 0;
  811 + default:
  812 + return -EOPNOTSUPP;
  813 + }
  814 +}
  815 +
742 816 const struct efx_phy_operations efx_mcdi_phy_ops = {
743 817 .probe = efx_mcdi_phy_probe,
744 818 .init = efx_port_dummy_op_int,
... ... @@ -751,5 +825,7 @@
751 825 .test_alive = efx_mcdi_phy_test_alive,
752 826 .run_tests = efx_mcdi_phy_run_tests,
753 827 .test_name = efx_mcdi_phy_test_name,
  828 + .get_module_eeprom = efx_mcdi_phy_get_module_eeprom,
  829 + .get_module_info = efx_mcdi_phy_get_module_info,
754 830 };
drivers/net/ethernet/sfc/net_driver.h
... ... @@ -519,6 +519,11 @@
519 519 int (*test_alive) (struct efx_nic *efx);
520 520 const char *(*test_name) (struct efx_nic *efx, unsigned int index);
521 521 int (*run_tests) (struct efx_nic *efx, int *results, unsigned flags);
  522 + int (*get_module_eeprom) (struct efx_nic *efx,
  523 + struct ethtool_eeprom *ee,
  524 + u8 *data);
  525 + int (*get_module_info) (struct efx_nic *efx,
  526 + struct ethtool_modinfo *modinfo);
522 527 };
523 528  
524 529 /**