}
 }
 
+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, ðm))
+               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
        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;
        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) {
 
        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,
        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)
 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 {