nfp: ethtool: support reporting link modes
authorYu Xiao <yu.xiao@corigine.com>
Fri, 25 Nov 2022 11:30:30 +0000 (12:30 +0100)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 29 Nov 2022 14:28:52 +0000 (15:28 +0100)
Add support for reporting link modes,
including `Supported link modes` and `Advertised link modes`,
via ethtool $DEV.

A new command `SPCODE_READ_MEDIA` is added to read info from
management firmware. Also, the mapping table `nfp_eth_media_table`
associates the link modes between NFP and kernel. Both of them
help to support this ability.

Signed-off-by: Yu Xiao <yu.xiao@corigine.com>
Reviewed-by: Louis Peens <louis.peens@corigine.com>
Signed-off-by: Simon Horman <simon.horman@corigine.com>
Reviewed-by: Alexander Lobakin <alexandr.lobakin@intel.com>
Link: https://lore.kernel.org/r/20221125113030.141642-1-simon.horman@corigine.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/netronome/nfp/nfp_main.h
drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c

index 5a18af672e6be60759534aa92df76471df32d1a0..14a751bfe1fe15f3648e9fd5fb7c934bad77a00b 100644 (file)
@@ -27,6 +27,7 @@ struct nfp_hwinfo;
 struct nfp_mip;
 struct nfp_net;
 struct nfp_nsp_identify;
+struct nfp_eth_media_buf;
 struct nfp_port;
 struct nfp_rtsym;
 struct nfp_rtsym_table;
index 0058ba2b3505b5b5cc0dd58f175a1333124997aa..e0cc60d12dda5ca4cb4e4b4384c95da1a63a37ad 100644 (file)
@@ -293,6 +293,76 @@ nfp_net_set_fec_link_mode(struct nfp_eth_table_port *eth_port,
        }
 }
 
+static const u16 nfp_eth_media_table[] = {
+       [NFP_MEDIA_1000BASE_CX]         = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
+       [NFP_MEDIA_1000BASE_KX]         = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
+       [NFP_MEDIA_10GBASE_KX4]         = ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
+       [NFP_MEDIA_10GBASE_KR]          = ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
+       [NFP_MEDIA_10GBASE_CX4]         = ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
+       [NFP_MEDIA_10GBASE_CR]          = ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
+       [NFP_MEDIA_10GBASE_SR]          = ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
+       [NFP_MEDIA_10GBASE_ER]          = ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
+       [NFP_MEDIA_25GBASE_KR]          = ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
+       [NFP_MEDIA_25GBASE_KR_S]        = ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
+       [NFP_MEDIA_25GBASE_CR]          = ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
+       [NFP_MEDIA_25GBASE_CR_S]        = ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
+       [NFP_MEDIA_25GBASE_SR]          = ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
+       [NFP_MEDIA_40GBASE_CR4]         = ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
+       [NFP_MEDIA_40GBASE_KR4]         = ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
+       [NFP_MEDIA_40GBASE_SR4]         = ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
+       [NFP_MEDIA_40GBASE_LR4]         = ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
+       [NFP_MEDIA_50GBASE_KR]          = ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
+       [NFP_MEDIA_50GBASE_SR]          = ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
+       [NFP_MEDIA_50GBASE_CR]          = ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
+       [NFP_MEDIA_50GBASE_LR]          = ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
+       [NFP_MEDIA_50GBASE_ER]          = ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
+       [NFP_MEDIA_50GBASE_FR]          = ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
+       [NFP_MEDIA_100GBASE_KR4]        = ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
+       [NFP_MEDIA_100GBASE_SR4]        = ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
+       [NFP_MEDIA_100GBASE_CR4]        = ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
+       [NFP_MEDIA_100GBASE_KP4]        = ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
+       [NFP_MEDIA_100GBASE_CR10]       = ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
+};
+
+static void nfp_add_media_link_mode(struct nfp_port *port,
+                                   struct nfp_eth_table_port *eth_port,
+                                   struct ethtool_link_ksettings *cmd)
+{
+       u64 supported_modes[2], advertised_modes[2];
+       struct nfp_eth_media_buf ethm = {
+               .eth_index = eth_port->eth_index,
+       };
+       struct nfp_cpp *cpp = port->app->cpp;
+
+       if (nfp_eth_read_media(cpp, &ethm))
+               return;
+
+       for (u32 i = 0; i < 2; i++) {
+               supported_modes[i] = le64_to_cpu(ethm.supported_modes[i]);
+               advertised_modes[i] = le64_to_cpu(ethm.advertised_modes[i]);
+       }
+
+       for (u32 i = 0; i < NFP_MEDIA_LINK_MODES_NUMBER; i++) {
+               if (i < 64) {
+                       if (supported_modes[0] & BIT_ULL(i))
+                               __set_bit(nfp_eth_media_table[i],
+                                         cmd->link_modes.supported);
+
+                       if (advertised_modes[0] & BIT_ULL(i))
+                               __set_bit(nfp_eth_media_table[i],
+                                         cmd->link_modes.advertising);
+               } else {
+                       if (supported_modes[1] & BIT_ULL(i - 64))
+                               __set_bit(nfp_eth_media_table[i],
+                                         cmd->link_modes.supported);
+
+                       if (advertised_modes[1] & BIT_ULL(i - 64))
+                               __set_bit(nfp_eth_media_table[i],
+                                         cmd->link_modes.advertising);
+               }
+       }
+}
+
 /**
  * nfp_net_get_link_ksettings - Get Link Speed settings
  * @netdev:    network interface device structure
@@ -311,6 +381,8 @@ nfp_net_get_link_ksettings(struct net_device *netdev,
        u16 sts;
 
        /* Init to unknowns */
+       ethtool_link_ksettings_zero_link_mode(cmd, supported);
+       ethtool_link_ksettings_zero_link_mode(cmd, advertising);
        ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
        cmd->base.port = PORT_OTHER;
        cmd->base.speed = SPEED_UNKNOWN;
@@ -321,6 +393,7 @@ nfp_net_get_link_ksettings(struct net_device *netdev,
        if (eth_port) {
                ethtool_link_ksettings_add_link_mode(cmd, supported, Pause);
                ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause);
+               nfp_add_media_link_mode(port, eth_port, cmd);
                if (eth_port->supp_aneg) {
                        ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg);
                        if (eth_port->aneg == NFP_ANEG_AUTO) {
index 730fea214b8abf14aada24c831d3909548cbd7e1..7136bc48530ba08cf431339481bb352e34e8a9b6 100644 (file)
@@ -100,6 +100,7 @@ enum nfp_nsp_cmd {
        SPCODE_FW_LOADED        = 19, /* Is application firmware loaded */
        SPCODE_VERSIONS         = 21, /* Report FW versions */
        SPCODE_READ_SFF_EEPROM  = 22, /* Read module EEPROM */
+       SPCODE_READ_MEDIA       = 23, /* Get either the supported or advertised media for a port */
 };
 
 struct nfp_nsp_dma_buf {
@@ -1100,4 +1101,20 @@ int nfp_nsp_read_module_eeprom(struct nfp_nsp *state, int eth_index,
        kfree(buf);
 
        return ret;
+};
+
+int nfp_nsp_read_media(struct nfp_nsp *state, void *buf, unsigned int size)
+{
+       struct nfp_nsp_command_buf_arg media = {
+               {
+                       .code           = SPCODE_READ_MEDIA,
+                       .option         = size,
+               },
+               .in_buf         = buf,
+               .in_size        = size,
+               .out_buf        = buf,
+               .out_size       = size,
+       };
+
+       return nfp_nsp_command_buf(state, &media);
 }
index 992d72ac98d38926d8e18b66e79b28a3e8bd6153..8f5cab0032d08edde7552c97a9d3996d86e1f899 100644 (file)
@@ -65,6 +65,11 @@ static inline bool nfp_nsp_has_read_module_eeprom(struct nfp_nsp *state)
        return nfp_nsp_get_abi_ver_minor(state) > 28;
 }
 
+static inline bool nfp_nsp_has_read_media(struct nfp_nsp *state)
+{
+       return nfp_nsp_get_abi_ver_minor(state) > 33;
+}
+
 enum nfp_eth_interface {
        NFP_INTERFACE_NONE      = 0,
        NFP_INTERFACE_SFP       = 1,
@@ -97,6 +102,47 @@ enum nfp_eth_fec {
        NFP_FEC_DISABLED_BIT,
 };
 
+/* link modes about RJ45 haven't been used, so there's no mapping to them */
+enum nfp_ethtool_link_mode_list {
+       NFP_MEDIA_W0_RJ45_10M,
+       NFP_MEDIA_W0_RJ45_10M_HD,
+       NFP_MEDIA_W0_RJ45_100M,
+       NFP_MEDIA_W0_RJ45_100M_HD,
+       NFP_MEDIA_W0_RJ45_1G,
+       NFP_MEDIA_W0_RJ45_2P5G,
+       NFP_MEDIA_W0_RJ45_5G,
+       NFP_MEDIA_W0_RJ45_10G,
+       NFP_MEDIA_1000BASE_CX,
+       NFP_MEDIA_1000BASE_KX,
+       NFP_MEDIA_10GBASE_KX4,
+       NFP_MEDIA_10GBASE_KR,
+       NFP_MEDIA_10GBASE_CX4,
+       NFP_MEDIA_10GBASE_CR,
+       NFP_MEDIA_10GBASE_SR,
+       NFP_MEDIA_10GBASE_ER,
+       NFP_MEDIA_25GBASE_KR,
+       NFP_MEDIA_25GBASE_KR_S,
+       NFP_MEDIA_25GBASE_CR,
+       NFP_MEDIA_25GBASE_CR_S,
+       NFP_MEDIA_25GBASE_SR,
+       NFP_MEDIA_40GBASE_CR4,
+       NFP_MEDIA_40GBASE_KR4,
+       NFP_MEDIA_40GBASE_SR4,
+       NFP_MEDIA_40GBASE_LR4,
+       NFP_MEDIA_50GBASE_KR,
+       NFP_MEDIA_50GBASE_SR,
+       NFP_MEDIA_50GBASE_CR,
+       NFP_MEDIA_50GBASE_LR,
+       NFP_MEDIA_50GBASE_ER,
+       NFP_MEDIA_50GBASE_FR,
+       NFP_MEDIA_100GBASE_KR4,
+       NFP_MEDIA_100GBASE_SR4,
+       NFP_MEDIA_100GBASE_CR4,
+       NFP_MEDIA_100GBASE_KP4,
+       NFP_MEDIA_100GBASE_CR10,
+       NFP_MEDIA_LINK_MODES_NUMBER
+};
+
 #define NFP_FEC_AUTO           BIT(NFP_FEC_AUTO_BIT)
 #define NFP_FEC_BASER          BIT(NFP_FEC_BASER_BIT)
 #define NFP_FEC_REED_SOLOMON   BIT(NFP_FEC_REED_SOLOMON_BIT)
@@ -256,6 +302,16 @@ enum nfp_nsp_sensor_id {
 int nfp_hwmon_read_sensor(struct nfp_cpp *cpp, enum nfp_nsp_sensor_id id,
                          long *val);
 
+struct nfp_eth_media_buf {
+       u8 eth_index;
+       u8 reserved[7];
+       __le64 supported_modes[2];
+       __le64 advertised_modes[2];
+};
+
+int nfp_nsp_read_media(struct nfp_nsp *state, void *buf, unsigned int size);
+int nfp_eth_read_media(struct nfp_cpp *cpp, struct nfp_eth_media_buf *ethm);
+
 #define NFP_NSP_VERSION_BUFSZ  1024 /* reasonable size, not in the ABI */
 
 enum nfp_nsp_versions {
index bb64efec4c46b336fc0ebb64d7b665cd1bd5aeec..570ac1bb2122f72fe429fb2f2b240c821a77caf8 100644 (file)
@@ -647,3 +647,29 @@ int __nfp_eth_set_split(struct nfp_nsp *nsp, unsigned int lanes)
        return NFP_ETH_SET_BIT_CONFIG(nsp, NSP_ETH_RAW_PORT, NSP_ETH_PORT_LANES,
                                      lanes, NSP_ETH_CTRL_SET_LANES);
 }
+
+int nfp_eth_read_media(struct nfp_cpp *cpp, struct nfp_eth_media_buf *ethm)
+{
+       struct nfp_nsp *nsp;
+       int ret;
+
+       nsp = nfp_nsp_open(cpp);
+       if (IS_ERR(nsp)) {
+               nfp_err(cpp, "Failed to access the NSP: %pe\n", nsp);
+               return PTR_ERR(nsp);
+       }
+
+       if (!nfp_nsp_has_read_media(nsp)) {
+               nfp_warn(cpp, "Reading media link modes not supported. Please update flash\n");
+               ret = -EOPNOTSUPP;
+               goto exit_close_nsp;
+       }
+
+       ret = nfp_nsp_read_media(nsp, ethm, sizeof(*ethm));
+       if (ret)
+               nfp_err(cpp, "Reading media link modes failed: %pe\n", ERR_PTR(ret));
+
+exit_close_nsp:
+       nfp_nsp_close(nsp);
+       return ret;
+}