aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStuart Hodgson <smhodgson@solarflare.com>2012-05-01 13:50:43 -0400
committerBen Hutchings <bhutchings@solarflare.com>2012-05-09 22:10:46 -0400
commitc087bd2cfdaf334d7d0c32bd1fcc1a23d5b88973 (patch)
tree9b0edadd759f4210ad890a686880f85e31f0bc2c
parent41c3cb6d20f0252308e9796fa4f3dacb4960de91 (diff)
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>
-rw-r--r--drivers/net/ethernet/sfc/ethtool.c35
-rw-r--r--drivers/net/ethernet/sfc/mcdi_phy.c76
-rw-r--r--drivers/net/ethernet/sfc/net_driver.h5
3 files changed, 116 insertions, 0 deletions
diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c
index f22f45f515a8..b0a4558de248 100644
--- a/drivers/net/ethernet/sfc/ethtool.c
+++ b/drivers/net/ethernet/sfc/ethtool.c
@@ -1108,6 +1108,39 @@ static int efx_ethtool_set_rxfh_indir(struct net_device *net_dev,
1108 return 0; 1108 return 0;
1109} 1109}
1110 1110
1111static 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
1128static 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
1111const struct ethtool_ops efx_ethtool_ops = { 1144const struct ethtool_ops efx_ethtool_ops = {
1112 .get_settings = efx_ethtool_get_settings, 1145 .get_settings = efx_ethtool_get_settings,
1113 .set_settings = efx_ethtool_set_settings, 1146 .set_settings = efx_ethtool_set_settings,
@@ -1137,4 +1170,6 @@ const struct ethtool_ops efx_ethtool_ops = {
1137 .get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size, 1170 .get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size,
1138 .get_rxfh_indir = efx_ethtool_get_rxfh_indir, 1171 .get_rxfh_indir = efx_ethtool_get_rxfh_indir,
1139 .set_rxfh_indir = efx_ethtool_set_rxfh_indir, 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};
diff --git a/drivers/net/ethernet/sfc/mcdi_phy.c b/drivers/net/ethernet/sfc/mcdi_phy.c
index 7bcad899a936..13cb40fe90c1 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,
739 return NULL; 739 return NULL;
740} 740}
741 741
742#define SFP_PAGE_SIZE 128
743#define SFP_NUM_PAGES 2
744static 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
801static 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
742const struct efx_phy_operations efx_mcdi_phy_ops = { 816const struct efx_phy_operations efx_mcdi_phy_ops = {
743 .probe = efx_mcdi_phy_probe, 817 .probe = efx_mcdi_phy_probe,
744 .init = efx_port_dummy_op_int, 818 .init = efx_port_dummy_op_int,
@@ -751,4 +825,6 @@ const struct efx_phy_operations efx_mcdi_phy_ops = {
751 .test_alive = efx_mcdi_phy_test_alive, 825 .test_alive = efx_mcdi_phy_test_alive,
752 .run_tests = efx_mcdi_phy_run_tests, 826 .run_tests = efx_mcdi_phy_run_tests,
753 .test_name = efx_mcdi_phy_test_name, 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};
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index eaca447e2a2b..0e575359af17 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -519,6 +519,11 @@ struct efx_phy_operations {
519 int (*test_alive) (struct efx_nic *efx); 519 int (*test_alive) (struct efx_nic *efx);
520 const char *(*test_name) (struct efx_nic *efx, unsigned int index); 520 const char *(*test_name) (struct efx_nic *efx, unsigned int index);
521 int (*run_tests) (struct efx_nic *efx, int *results, unsigned flags); 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/**