Commit c087bd2cfdaf334d7d0c32bd1fcc1a23d5b88973
Committed by
Ben Hutchings
1 parent
41c3cb6d20
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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 | /** |