Convert from using the old u32 supported, advertising, etc. link settings
to the new link mode settings that support bit positions / settings
greater than 32 bits.

Signed-off-by: Tom Lendacky <thomas.lenda...@amd.com>
---
 drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c |   56 ++--
 drivers/net/ethernet/amd/xgbe/xgbe-mdio.c    |   77 +++---
 drivers/net/ethernet/amd/xgbe/xgbe-phy-v1.c  |   54 ++--
 drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c  |  350 ++++++++++++++------------
 drivers/net/ethernet/amd/xgbe/xgbe.h         |   50 +++-
 5 files changed, 345 insertions(+), 242 deletions(-)

diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c 
b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
index f80b186..cea25ac 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
@@ -267,6 +267,7 @@ static int xgbe_set_pauseparam(struct net_device *netdev,
                               struct ethtool_pauseparam *pause)
 {
        struct xgbe_prv_data *pdata = netdev_priv(netdev);
+       struct ethtool_link_ksettings *lks = &pdata->phy.lks;
        int ret = 0;
 
        if (pause->autoneg && (pdata->phy.autoneg != AUTONEG_ENABLE)) {
@@ -279,16 +280,21 @@ static int xgbe_set_pauseparam(struct net_device *netdev,
        pdata->phy.tx_pause = pause->tx_pause;
        pdata->phy.rx_pause = pause->rx_pause;
 
-       pdata->phy.advertising &= ~ADVERTISED_Pause;
-       pdata->phy.advertising &= ~ADVERTISED_Asym_Pause;
+       XGBE_CLR_ADV(lks, Pause);
+       XGBE_CLR_ADV(lks, Asym_Pause);
 
        if (pause->rx_pause) {
-               pdata->phy.advertising |= ADVERTISED_Pause;
-               pdata->phy.advertising |= ADVERTISED_Asym_Pause;
+               XGBE_SET_ADV(lks, Pause);
+               XGBE_SET_ADV(lks, Asym_Pause);
        }
 
-       if (pause->tx_pause)
-               pdata->phy.advertising ^= ADVERTISED_Asym_Pause;
+       if (pause->tx_pause) {
+               /* Equivalent to XOR of Asym_Pause */
+               if (XGBE_ADV(lks, Asym_Pause))
+                       XGBE_CLR_ADV(lks, Asym_Pause);
+               else
+                       XGBE_SET_ADV(lks, Asym_Pause);
+       }
 
        if (netif_running(netdev))
                ret = pdata->phy_if.phy_config_aneg(pdata);
@@ -300,22 +306,20 @@ static int xgbe_get_link_ksettings(struct net_device 
*netdev,
                                   struct ethtool_link_ksettings *cmd)
 {
        struct xgbe_prv_data *pdata = netdev_priv(netdev);
+       struct ethtool_link_ksettings *lks = &pdata->phy.lks;
 
        cmd->base.phy_address = pdata->phy.address;
 
-       ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
-                                               pdata->phy.supported);
-       ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
-                                               pdata->phy.advertising);
-       ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising,
-                                               pdata->phy.lp_advertising);
-
        cmd->base.autoneg = pdata->phy.autoneg;
        cmd->base.speed = pdata->phy.speed;
        cmd->base.duplex = pdata->phy.duplex;
 
        cmd->base.port = PORT_NONE;
 
+       XGBE_LM_COPY(cmd, supported, lks, supported);
+       XGBE_LM_COPY(cmd, advertising, lks, advertising);
+       XGBE_LM_COPY(cmd, lp_advertising, lks, lp_advertising);
+
        return 0;
 }
 
@@ -323,7 +327,8 @@ static int xgbe_set_link_ksettings(struct net_device 
*netdev,
                                   const struct ethtool_link_ksettings *cmd)
 {
        struct xgbe_prv_data *pdata = netdev_priv(netdev);
-       u32 advertising;
+       struct ethtool_link_ksettings *lks = &pdata->phy.lks;
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(advertising);
        u32 speed;
        int ret;
 
@@ -355,15 +360,17 @@ static int xgbe_set_link_ksettings(struct net_device 
*netdev,
                }
        }
 
-       ethtool_convert_link_mode_to_legacy_u32(&advertising,
-                                               cmd->link_modes.advertising);
-
        netif_dbg(pdata, link, netdev,
-                 "requested advertisement %#x, phy supported %#x\n",
-                 advertising, pdata->phy.supported);
+                 "requested advertisement 0x%*pb, phy supported 0x%*pb\n",
+                 __ETHTOOL_LINK_MODE_MASK_NBITS, cmd->link_modes.advertising,
+                 __ETHTOOL_LINK_MODE_MASK_NBITS, lks->link_modes.supported);
+
+       bitmap_and(advertising,
+                  cmd->link_modes.advertising, lks->link_modes.supported,
+                  __ETHTOOL_LINK_MODE_MASK_NBITS);
 
-       advertising &= pdata->phy.supported;
-       if ((cmd->base.autoneg == AUTONEG_ENABLE) && !advertising) {
+       if ((cmd->base.autoneg == AUTONEG_ENABLE) &&
+           bitmap_empty(advertising, __ETHTOOL_LINK_MODE_MASK_NBITS)) {
                netdev_err(netdev,
                           "unsupported requested advertisement\n");
                return -EINVAL;
@@ -373,12 +380,13 @@ static int xgbe_set_link_ksettings(struct net_device 
*netdev,
        pdata->phy.autoneg = cmd->base.autoneg;
        pdata->phy.speed = speed;
        pdata->phy.duplex = cmd->base.duplex;
-       pdata->phy.advertising = advertising;
+       bitmap_copy(lks->link_modes.advertising, advertising,
+                   __ETHTOOL_LINK_MODE_MASK_NBITS);
 
        if (cmd->base.autoneg == AUTONEG_ENABLE)
-               pdata->phy.advertising |= ADVERTISED_Autoneg;
+               XGBE_SET_ADV(lks, Autoneg);
        else
-               pdata->phy.advertising &= ~ADVERTISED_Autoneg;
+               XGBE_CLR_ADV(lks, Autoneg);
 
        if (netif_running(netdev))
                ret = pdata->phy_if.phy_config_aneg(pdata);
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c 
b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
index 2409202..072b9f6 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
@@ -615,12 +615,14 @@ static enum xgbe_an xgbe_an73_page_received(struct 
xgbe_prv_data *pdata)
 
 static enum xgbe_an xgbe_an73_incompat_link(struct xgbe_prv_data *pdata)
 {
+       struct ethtool_link_ksettings *lks = &pdata->phy.lks;
+
        /* Be sure we aren't looping trying to negotiate */
        if (xgbe_in_kr_mode(pdata)) {
                pdata->kr_state = XGBE_RX_ERROR;
 
-               if (!(pdata->phy.advertising & ADVERTISED_1000baseKX_Full) &&
-                   !(pdata->phy.advertising & ADVERTISED_2500baseX_Full))
+               if (!XGBE_ADV(lks, 1000baseKX_Full) &&
+                   !XGBE_ADV(lks, 2500baseX_Full))
                        return XGBE_AN_NO_LINK;
 
                if (pdata->kx_state != XGBE_RX_BPA)
@@ -628,7 +630,7 @@ static enum xgbe_an xgbe_an73_incompat_link(struct 
xgbe_prv_data *pdata)
        } else {
                pdata->kx_state = XGBE_RX_ERROR;
 
-               if (!(pdata->phy.advertising & ADVERTISED_10000baseKR_Full))
+               if (!XGBE_ADV(lks, 10000baseKR_Full))
                        return XGBE_AN_NO_LINK;
 
                if (pdata->kr_state != XGBE_RX_BPA)
@@ -944,18 +946,19 @@ static void xgbe_an_state_machine(struct work_struct 
*work)
 
 static void xgbe_an37_init(struct xgbe_prv_data *pdata)
 {
-       unsigned int advertising, reg;
+       struct ethtool_link_ksettings lks;
+       unsigned int reg;
 
-       advertising = pdata->phy_if.phy_impl.an_advertising(pdata);
+       pdata->phy_if.phy_impl.an_advertising(pdata, &lks);
 
        /* Set up Advertisement register */
        reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE);
-       if (advertising & ADVERTISED_Pause)
+       if (XGBE_ADV(&lks, Pause))
                reg |= 0x100;
        else
                reg &= ~0x100;
 
-       if (advertising & ADVERTISED_Asym_Pause)
+       if (XGBE_ADV(&lks, Asym_Pause))
                reg |= 0x80;
        else
                reg &= ~0x80;
@@ -992,13 +995,14 @@ static void xgbe_an37_init(struct xgbe_prv_data *pdata)
 
 static void xgbe_an73_init(struct xgbe_prv_data *pdata)
 {
-       unsigned int advertising, reg;
+       struct ethtool_link_ksettings lks;
+       unsigned int reg;
 
-       advertising = pdata->phy_if.phy_impl.an_advertising(pdata);
+       pdata->phy_if.phy_impl.an_advertising(pdata, &lks);
 
        /* Set up Advertisement register 3 first */
        reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
-       if (advertising & ADVERTISED_10000baseR_FEC)
+       if (XGBE_ADV(&lks, 10000baseR_FEC))
                reg |= 0xc000;
        else
                reg &= ~0xc000;
@@ -1007,13 +1011,13 @@ static void xgbe_an73_init(struct xgbe_prv_data *pdata)
 
        /* Set up Advertisement register 2 next */
        reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
-       if (advertising & ADVERTISED_10000baseKR_Full)
+       if (XGBE_ADV(&lks, 10000baseKR_Full))
                reg |= 0x80;
        else
                reg &= ~0x80;
 
-       if ((advertising & ADVERTISED_1000baseKX_Full) ||
-           (advertising & ADVERTISED_2500baseX_Full))
+       if (XGBE_ADV(&lks, 1000baseKX_Full) ||
+           XGBE_ADV(&lks, 2500baseX_Full))
                reg |= 0x20;
        else
                reg &= ~0x20;
@@ -1022,12 +1026,12 @@ static void xgbe_an73_init(struct xgbe_prv_data *pdata)
 
        /* Set up Advertisement register 1 last */
        reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
-       if (advertising & ADVERTISED_Pause)
+       if (XGBE_ADV(&lks, Pause))
                reg |= 0x400;
        else
                reg &= ~0x400;
 
-       if (advertising & ADVERTISED_Asym_Pause)
+       if (XGBE_ADV(&lks, Asym_Pause))
                reg |= 0x800;
        else
                reg &= ~0x800;
@@ -1283,9 +1287,10 @@ static enum xgbe_mode xgbe_phy_status_aneg(struct 
xgbe_prv_data *pdata)
 
 static void xgbe_phy_status_result(struct xgbe_prv_data *pdata)
 {
+       struct ethtool_link_ksettings *lks = &pdata->phy.lks;
        enum xgbe_mode mode;
 
-       pdata->phy.lp_advertising = 0;
+       XGBE_ZERO_LP_ADV(lks);
 
        if ((pdata->phy.autoneg != AUTONEG_ENABLE) || pdata->parallel_detect)
                mode = xgbe_cur_mode(pdata);
@@ -1515,17 +1520,21 @@ static void xgbe_dump_phy_registers(struct 
xgbe_prv_data *pdata)
 
 static int xgbe_phy_best_advertised_speed(struct xgbe_prv_data *pdata)
 {
-       if (pdata->phy.advertising & ADVERTISED_10000baseKR_Full)
+       struct ethtool_link_ksettings *lks = &pdata->phy.lks;
+
+       if (XGBE_ADV(lks, 10000baseKR_Full))
                return SPEED_10000;
-       else if (pdata->phy.advertising & ADVERTISED_10000baseT_Full)
+       else if (XGBE_ADV(lks, 10000baseT_Full))
                return SPEED_10000;
-       else if (pdata->phy.advertising & ADVERTISED_2500baseX_Full)
+       else if (XGBE_ADV(lks, 2500baseX_Full))
                return SPEED_2500;
-       else if (pdata->phy.advertising & ADVERTISED_1000baseKX_Full)
+       else if (XGBE_ADV(lks, 2500baseT_Full))
+               return SPEED_2500;
+       else if (XGBE_ADV(lks, 1000baseKX_Full))
                return SPEED_1000;
-       else if (pdata->phy.advertising & ADVERTISED_1000baseT_Full)
+       else if (XGBE_ADV(lks, 1000baseT_Full))
                return SPEED_1000;
-       else if (pdata->phy.advertising & ADVERTISED_100baseT_Full)
+       else if (XGBE_ADV(lks, 100baseT_Full))
                return SPEED_100;
 
        return SPEED_UNKNOWN;
@@ -1538,6 +1547,7 @@ static void xgbe_phy_exit(struct xgbe_prv_data *pdata)
 
 static int xgbe_phy_init(struct xgbe_prv_data *pdata)
 {
+       struct ethtool_link_ksettings *lks = &pdata->phy.lks;
        int ret;
 
        mutex_init(&pdata->an_mutex);
@@ -1555,11 +1565,13 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
        ret = pdata->phy_if.phy_impl.init(pdata);
        if (ret)
                return ret;
-       pdata->phy.advertising = pdata->phy.supported;
+
+       /* Copy supported link modes to advertising link modes */
+       XGBE_LM_COPY(lks, advertising, lks, supported);
 
        pdata->phy.address = 0;
 
-       if (pdata->phy.advertising & ADVERTISED_Autoneg) {
+       if (XGBE_ADV(lks, Autoneg)) {
                pdata->phy.autoneg = AUTONEG_ENABLE;
                pdata->phy.speed = SPEED_UNKNOWN;
                pdata->phy.duplex = DUPLEX_UNKNOWN;
@@ -1576,16 +1588,21 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
        pdata->phy.rx_pause = pdata->rx_pause;
 
        /* Fix up Flow Control advertising */
-       pdata->phy.advertising &= ~ADVERTISED_Pause;
-       pdata->phy.advertising &= ~ADVERTISED_Asym_Pause;
+       XGBE_CLR_ADV(lks, Pause);
+       XGBE_CLR_ADV(lks, Asym_Pause);
 
        if (pdata->rx_pause) {
-               pdata->phy.advertising |= ADVERTISED_Pause;
-               pdata->phy.advertising |= ADVERTISED_Asym_Pause;
+               XGBE_SET_ADV(lks, Pause);
+               XGBE_SET_ADV(lks, Asym_Pause);
        }
 
-       if (pdata->tx_pause)
-               pdata->phy.advertising ^= ADVERTISED_Asym_Pause;
+       if (pdata->tx_pause) {
+               /* Equivalent to XOR of Asym_Pause */
+               if (XGBE_ADV(lks, Asym_Pause))
+                       XGBE_CLR_ADV(lks, Asym_Pause);
+               else
+                       XGBE_SET_ADV(lks, Asym_Pause);
+       }
 
        if (netif_msg_drv(pdata))
                xgbe_dump_phy_registers(pdata);
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v1.c 
b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v1.c
index c75edca..d16eae4 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v1.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v1.c
@@ -231,20 +231,21 @@ static void xgbe_phy_kr_training_post(struct 
xgbe_prv_data *pdata)
 
 static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata)
 {
+       struct ethtool_link_ksettings *lks = &pdata->phy.lks;
        struct xgbe_phy_data *phy_data = pdata->phy_data;
        enum xgbe_mode mode;
        unsigned int ad_reg, lp_reg;
 
-       pdata->phy.lp_advertising |= ADVERTISED_Autoneg;
-       pdata->phy.lp_advertising |= ADVERTISED_Backplane;
+       XGBE_SET_LP_ADV(lks, Autoneg);
+       XGBE_SET_LP_ADV(lks, Backplane);
 
        /* Compare Advertisement and Link Partner register 1 */
        ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
        lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA);
        if (lp_reg & 0x400)
-               pdata->phy.lp_advertising |= ADVERTISED_Pause;
+               XGBE_SET_LP_ADV(lks, Pause);
        if (lp_reg & 0x800)
-               pdata->phy.lp_advertising |= ADVERTISED_Asym_Pause;
+               XGBE_SET_LP_ADV(lks, Asym_Pause);
 
        if (pdata->phy.pause_autoneg) {
                /* Set flow control based on auto-negotiation result */
@@ -266,12 +267,12 @@ static enum xgbe_mode xgbe_phy_an_outcome(struct 
xgbe_prv_data *pdata)
        ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
        lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1);
        if (lp_reg & 0x80)
-               pdata->phy.lp_advertising |= ADVERTISED_10000baseKR_Full;
+               XGBE_SET_LP_ADV(lks, 10000baseKR_Full);
        if (lp_reg & 0x20) {
                if (phy_data->speed_set == XGBE_SPEEDSET_2500_10000)
-                       pdata->phy.lp_advertising |= ADVERTISED_2500baseX_Full;
+                       XGBE_SET_LP_ADV(lks, 2500baseX_Full);
                else
-                       pdata->phy.lp_advertising |= ADVERTISED_1000baseKX_Full;
+                       XGBE_SET_LP_ADV(lks, 1000baseKX_Full);
        }
 
        ad_reg &= lp_reg;
@@ -290,14 +291,17 @@ static enum xgbe_mode xgbe_phy_an_outcome(struct 
xgbe_prv_data *pdata)
        ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
        lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2);
        if (lp_reg & 0xc000)
-               pdata->phy.lp_advertising |= ADVERTISED_10000baseR_FEC;
+               XGBE_SET_LP_ADV(lks, 10000baseR_FEC);
 
        return mode;
 }
 
-static unsigned int xgbe_phy_an_advertising(struct xgbe_prv_data *pdata)
+static void xgbe_phy_an_advertising(struct xgbe_prv_data *pdata,
+                                   struct ethtool_link_ksettings *dlks)
 {
-       return pdata->phy.advertising;
+       struct ethtool_link_ksettings *slks = &pdata->phy.lks;
+
+       XGBE_LM_COPY(dlks, advertising, slks, advertising);
 }
 
 static int xgbe_phy_an_config(struct xgbe_prv_data *pdata)
@@ -565,11 +569,10 @@ static void xgbe_phy_set_mode(struct xgbe_prv_data 
*pdata, enum xgbe_mode mode)
 }
 
 static bool xgbe_phy_check_mode(struct xgbe_prv_data *pdata,
-                               enum xgbe_mode mode, u32 advert)
+                               enum xgbe_mode mode, bool advert)
 {
        if (pdata->phy.autoneg == AUTONEG_ENABLE) {
-               if (pdata->phy.advertising & advert)
-                       return true;
+               return advert;
        } else {
                enum xgbe_mode cur_mode;
 
@@ -583,16 +586,18 @@ static bool xgbe_phy_check_mode(struct xgbe_prv_data 
*pdata,
 
 static bool xgbe_phy_use_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode)
 {
+       struct ethtool_link_ksettings *lks = &pdata->phy.lks;
+
        switch (mode) {
        case XGBE_MODE_KX_1000:
                return xgbe_phy_check_mode(pdata, mode,
-                                          ADVERTISED_1000baseKX_Full);
+                                          XGBE_ADV(lks, 1000baseKX_Full));
        case XGBE_MODE_KX_2500:
                return xgbe_phy_check_mode(pdata, mode,
-                                          ADVERTISED_2500baseX_Full);
+                                          XGBE_ADV(lks, 2500baseX_Full));
        case XGBE_MODE_KR:
                return xgbe_phy_check_mode(pdata, mode,
-                                          ADVERTISED_10000baseKR_Full);
+                                          XGBE_ADV(lks, 10000baseKR_Full));
        default:
                return false;
        }
@@ -672,6 +677,7 @@ static void xgbe_phy_exit(struct xgbe_prv_data *pdata)
 
 static int xgbe_phy_init(struct xgbe_prv_data *pdata)
 {
+       struct ethtool_link_ksettings *lks = &pdata->phy.lks;
        struct xgbe_phy_data *phy_data;
        int ret;
 
@@ -790,21 +796,23 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
        }
 
        /* Initialize supported features */
-       pdata->phy.supported = SUPPORTED_Autoneg;
-       pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
-       pdata->phy.supported |= SUPPORTED_Backplane;
-       pdata->phy.supported |= SUPPORTED_10000baseKR_Full;
+       XGBE_ZERO_SUP(lks);
+       XGBE_SET_SUP(lks, Autoneg);
+       XGBE_SET_SUP(lks, Pause);
+       XGBE_SET_SUP(lks, Asym_Pause);
+       XGBE_SET_SUP(lks, Backplane);
+       XGBE_SET_SUP(lks, 10000baseKR_Full);
        switch (phy_data->speed_set) {
        case XGBE_SPEEDSET_1000_10000:
-               pdata->phy.supported |= SUPPORTED_1000baseKX_Full;
+               XGBE_SET_SUP(lks, 1000baseKX_Full);
                break;
        case XGBE_SPEEDSET_2500_10000:
-               pdata->phy.supported |= SUPPORTED_2500baseX_Full;
+               XGBE_SET_SUP(lks, 2500baseX_Full);
                break;
        }
 
        if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE)
-               pdata->phy.supported |= SUPPORTED_10000baseR_FEC;
+               XGBE_SET_SUP(lks, 10000baseR_FEC);
 
        pdata->phy_data = phy_data;
 
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c 
b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
index 4463487..bb8b264 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
@@ -711,18 +711,13 @@ static int xgbe_phy_mii_read(struct mii_bus *mii, int 
addr, int reg)
 
 static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata)
 {
+       struct ethtool_link_ksettings *lks = &pdata->phy.lks;
        struct xgbe_phy_data *phy_data = pdata->phy_data;
 
        if (!phy_data->sfp_mod_absent && !phy_data->sfp_changed)
                return;
 
-       pdata->phy.supported &= ~SUPPORTED_Autoneg;
-       pdata->phy.supported &= ~(SUPPORTED_Pause | SUPPORTED_Asym_Pause);
-       pdata->phy.supported &= ~SUPPORTED_TP;
-       pdata->phy.supported &= ~SUPPORTED_FIBRE;
-       pdata->phy.supported &= ~SUPPORTED_100baseT_Full;
-       pdata->phy.supported &= ~SUPPORTED_1000baseT_Full;
-       pdata->phy.supported &= ~SUPPORTED_10000baseT_Full;
+       XGBE_ZERO_SUP(lks);
 
        if (phy_data->sfp_mod_absent) {
                pdata->phy.speed = SPEED_UNKNOWN;
@@ -730,18 +725,13 @@ static void xgbe_phy_sfp_phy_settings(struct 
xgbe_prv_data *pdata)
                pdata->phy.autoneg = AUTONEG_ENABLE;
                pdata->phy.pause_autoneg = AUTONEG_ENABLE;
 
-               pdata->phy.supported |= SUPPORTED_Autoneg;
-               pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
-               pdata->phy.supported |= SUPPORTED_TP;
-               pdata->phy.supported |= SUPPORTED_FIBRE;
-               if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100)
-                       pdata->phy.supported |= SUPPORTED_100baseT_Full;
-               if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
-                       pdata->phy.supported |= SUPPORTED_1000baseT_Full;
-               if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000)
-                       pdata->phy.supported |= SUPPORTED_10000baseT_Full;
+               XGBE_SET_SUP(lks, Autoneg);
+               XGBE_SET_SUP(lks, Pause);
+               XGBE_SET_SUP(lks, Asym_Pause);
+               XGBE_SET_SUP(lks, TP);
+               XGBE_SET_SUP(lks, FIBRE);
 
-               pdata->phy.advertising = pdata->phy.supported;
+               XGBE_LM_COPY(lks, advertising, lks, supported);
 
                return;
        }
@@ -755,8 +745,18 @@ static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data 
*pdata)
                pdata->phy.duplex = DUPLEX_UNKNOWN;
                pdata->phy.autoneg = AUTONEG_ENABLE;
                pdata->phy.pause_autoneg = AUTONEG_ENABLE;
-               pdata->phy.supported |= SUPPORTED_Autoneg;
-               pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
+               XGBE_SET_SUP(lks, Autoneg);
+               XGBE_SET_SUP(lks, Pause);
+               XGBE_SET_SUP(lks, Asym_Pause);
+               if (phy_data->sfp_base == XGBE_SFP_BASE_1000_T) {
+                       if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100)
+                               XGBE_SET_SUP(lks, 100baseT_Full);
+                       if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
+                               XGBE_SET_SUP(lks, 1000baseT_Full);
+               } else {
+                       if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
+                               XGBE_SET_SUP(lks, 1000baseX_Full);
+               }
                break;
        case XGBE_SFP_BASE_10000_SR:
        case XGBE_SFP_BASE_10000_LR:
@@ -767,6 +767,27 @@ static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data 
*pdata)
                pdata->phy.duplex = DUPLEX_FULL;
                pdata->phy.autoneg = AUTONEG_DISABLE;
                pdata->phy.pause_autoneg = AUTONEG_DISABLE;
+               if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) {
+                       switch (phy_data->sfp_base) {
+                       case XGBE_SFP_BASE_10000_SR:
+                               XGBE_SET_SUP(lks, 10000baseSR_Full);
+                               break;
+                       case XGBE_SFP_BASE_10000_LR:
+                               XGBE_SET_SUP(lks, 10000baseLR_Full);
+                               break;
+                       case XGBE_SFP_BASE_10000_LRM:
+                               XGBE_SET_SUP(lks, 10000baseLRM_Full);
+                               break;
+                       case XGBE_SFP_BASE_10000_ER:
+                               XGBE_SET_SUP(lks, 10000baseER_Full);
+                               break;
+                       case XGBE_SFP_BASE_10000_CR:
+                               XGBE_SET_SUP(lks, 10000baseCR_Full);
+                               break;
+                       default:
+                               break;
+                       }
+               }
                break;
        default:
                pdata->phy.speed = SPEED_UNKNOWN;
@@ -780,38 +801,14 @@ static void xgbe_phy_sfp_phy_settings(struct 
xgbe_prv_data *pdata)
        case XGBE_SFP_BASE_1000_T:
        case XGBE_SFP_BASE_1000_CX:
        case XGBE_SFP_BASE_10000_CR:
-               pdata->phy.supported |= SUPPORTED_TP;
+               XGBE_SET_SUP(lks, TP);
                break;
        default:
-               pdata->phy.supported |= SUPPORTED_FIBRE;
-       }
-
-       switch (phy_data->sfp_speed) {
-       case XGBE_SFP_SPEED_100_1000:
-               if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100)
-                       pdata->phy.supported |= SUPPORTED_100baseT_Full;
-               if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
-                       pdata->phy.supported |= SUPPORTED_1000baseT_Full;
-               break;
-       case XGBE_SFP_SPEED_1000:
-               if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
-                       pdata->phy.supported |= SUPPORTED_1000baseT_Full;
+               XGBE_SET_SUP(lks, FIBRE);
                break;
-       case XGBE_SFP_SPEED_10000:
-               if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000)
-                       pdata->phy.supported |= SUPPORTED_10000baseT_Full;
-               break;
-       default:
-               /* Choose the fastest supported speed */
-               if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000)
-                       pdata->phy.supported |= SUPPORTED_10000baseT_Full;
-               else if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
-                       pdata->phy.supported |= SUPPORTED_1000baseT_Full;
-               else if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100)
-                       pdata->phy.supported |= SUPPORTED_100baseT_Full;
        }
 
-       pdata->phy.advertising = pdata->phy.supported;
+       XGBE_LM_COPY(lks, advertising, lks, supported);
 }
 
 static bool xgbe_phy_sfp_bit_rate(struct xgbe_sfp_eeprom *sfp_eeprom,
@@ -888,8 +885,10 @@ static void xgbe_phy_external_phy_quirks(struct 
xgbe_prv_data *pdata)
 
 static int xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata)
 {
+       struct ethtool_link_ksettings *lks = &pdata->phy.lks;
        struct xgbe_phy_data *phy_data = pdata->phy_data;
        struct phy_device *phydev;
+       u32 advertising;
        int ret;
 
        /* If we already have a PHY, just return */
@@ -945,7 +944,10 @@ static int xgbe_phy_find_phy_device(struct xgbe_prv_data 
*pdata)
        phy_data->phydev = phydev;
 
        xgbe_phy_external_phy_quirks(pdata);
-       phydev->advertising &= pdata->phy.advertising;
+
+       ethtool_convert_link_mode_to_legacy_u32(&advertising,
+                                               lks->link_modes.advertising);
+       phydev->advertising &= advertising;
 
        phy_start_aneg(phy_data->phydev);
 
@@ -1352,6 +1354,7 @@ static unsigned char *xgbe_phy_sfp_eeprom(struct 
xgbe_prv_data *pdata)
 
 static void xgbe_phy_phydev_flowctrl(struct xgbe_prv_data *pdata)
 {
+       struct ethtool_link_ksettings *lks = &pdata->phy.lks;
        struct xgbe_phy_data *phy_data = pdata->phy_data;
        u16 lcl_adv = 0, rmt_adv = 0;
        u8 fc;
@@ -1368,11 +1371,11 @@ static void xgbe_phy_phydev_flowctrl(struct 
xgbe_prv_data *pdata)
                lcl_adv |= ADVERTISE_PAUSE_ASYM;
 
        if (phy_data->phydev->pause) {
-               pdata->phy.lp_advertising |= ADVERTISED_Pause;
+               XGBE_SET_LP_ADV(lks, Pause);
                rmt_adv |= LPA_PAUSE_CAP;
        }
        if (phy_data->phydev->asym_pause) {
-               pdata->phy.lp_advertising |= ADVERTISED_Asym_Pause;
+               XGBE_SET_LP_ADV(lks, Asym_Pause);
                rmt_adv |= LPA_PAUSE_ASYM;
        }
 
@@ -1385,10 +1388,11 @@ static void xgbe_phy_phydev_flowctrl(struct 
xgbe_prv_data *pdata)
 
 static enum xgbe_mode xgbe_phy_an37_sgmii_outcome(struct xgbe_prv_data *pdata)
 {
+       struct ethtool_link_ksettings *lks = &pdata->phy.lks;
        enum xgbe_mode mode;
 
-       pdata->phy.lp_advertising |= ADVERTISED_Autoneg;
-       pdata->phy.lp_advertising |= ADVERTISED_TP;
+       XGBE_SET_LP_ADV(lks, Autoneg);
+       XGBE_SET_LP_ADV(lks, TP);
 
        /* Use external PHY to determine flow control */
        if (pdata->phy.pause_autoneg)
@@ -1397,21 +1401,21 @@ static enum xgbe_mode 
xgbe_phy_an37_sgmii_outcome(struct xgbe_prv_data *pdata)
        switch (pdata->an_status & XGBE_SGMII_AN_LINK_SPEED) {
        case XGBE_SGMII_AN_LINK_SPEED_100:
                if (pdata->an_status & XGBE_SGMII_AN_LINK_DUPLEX) {
-                       pdata->phy.lp_advertising |= ADVERTISED_100baseT_Full;
+                       XGBE_SET_LP_ADV(lks, 100baseT_Full);
                        mode = XGBE_MODE_SGMII_100;
                } else {
                        /* Half-duplex not supported */
-                       pdata->phy.lp_advertising |= ADVERTISED_100baseT_Half;
+                       XGBE_SET_LP_ADV(lks, 100baseT_Half);
                        mode = XGBE_MODE_UNKNOWN;
                }
                break;
        case XGBE_SGMII_AN_LINK_SPEED_1000:
                if (pdata->an_status & XGBE_SGMII_AN_LINK_DUPLEX) {
-                       pdata->phy.lp_advertising |= ADVERTISED_1000baseT_Full;
+                       XGBE_SET_LP_ADV(lks, 1000baseT_Full);
                        mode = XGBE_MODE_SGMII_1000;
                } else {
                        /* Half-duplex not supported */
-                       pdata->phy.lp_advertising |= ADVERTISED_1000baseT_Half;
+                       XGBE_SET_LP_ADV(lks, 1000baseT_Half);
                        mode = XGBE_MODE_UNKNOWN;
                }
                break;
@@ -1424,19 +1428,20 @@ static enum xgbe_mode 
xgbe_phy_an37_sgmii_outcome(struct xgbe_prv_data *pdata)
 
 static enum xgbe_mode xgbe_phy_an37_outcome(struct xgbe_prv_data *pdata)
 {
+       struct ethtool_link_ksettings *lks = &pdata->phy.lks;
        enum xgbe_mode mode;
        unsigned int ad_reg, lp_reg;
 
-       pdata->phy.lp_advertising |= ADVERTISED_Autoneg;
-       pdata->phy.lp_advertising |= ADVERTISED_FIBRE;
+       XGBE_SET_LP_ADV(lks, Autoneg);
+       XGBE_SET_LP_ADV(lks, FIBRE);
 
        /* Compare Advertisement and Link Partner register */
        ad_reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE);
        lp_reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_LP_ABILITY);
        if (lp_reg & 0x100)
-               pdata->phy.lp_advertising |= ADVERTISED_Pause;
+               XGBE_SET_LP_ADV(lks, Pause);
        if (lp_reg & 0x80)
-               pdata->phy.lp_advertising |= ADVERTISED_Asym_Pause;
+               XGBE_SET_LP_ADV(lks, Asym_Pause);
 
        if (pdata->phy.pause_autoneg) {
                /* Set flow control based on auto-negotiation result */
@@ -1454,10 +1459,8 @@ static enum xgbe_mode xgbe_phy_an37_outcome(struct 
xgbe_prv_data *pdata)
                }
        }
 
-       if (lp_reg & 0x40)
-               pdata->phy.lp_advertising |= ADVERTISED_1000baseT_Half;
        if (lp_reg & 0x20)
-               pdata->phy.lp_advertising |= ADVERTISED_1000baseT_Full;
+               XGBE_SET_LP_ADV(lks, 1000baseX_Full);
 
        /* Half duplex is not supported */
        ad_reg &= lp_reg;
@@ -1468,12 +1471,13 @@ static enum xgbe_mode xgbe_phy_an37_outcome(struct 
xgbe_prv_data *pdata)
 
 static enum xgbe_mode xgbe_phy_an73_redrv_outcome(struct xgbe_prv_data *pdata)
 {
+       struct ethtool_link_ksettings *lks = &pdata->phy.lks;
        struct xgbe_phy_data *phy_data = pdata->phy_data;
        enum xgbe_mode mode;
        unsigned int ad_reg, lp_reg;
 
-       pdata->phy.lp_advertising |= ADVERTISED_Autoneg;
-       pdata->phy.lp_advertising |= ADVERTISED_Backplane;
+       XGBE_SET_LP_ADV(lks, Autoneg);
+       XGBE_SET_LP_ADV(lks, Backplane);
 
        /* Use external PHY to determine flow control */
        if (pdata->phy.pause_autoneg)
@@ -1483,9 +1487,9 @@ static enum xgbe_mode xgbe_phy_an73_redrv_outcome(struct 
xgbe_prv_data *pdata)
        ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
        lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1);
        if (lp_reg & 0x80)
-               pdata->phy.lp_advertising |= ADVERTISED_10000baseKR_Full;
+               XGBE_SET_LP_ADV(lks, 10000baseKR_Full);
        if (lp_reg & 0x20)
-               pdata->phy.lp_advertising |= ADVERTISED_1000baseKX_Full;
+               XGBE_SET_LP_ADV(lks, 1000baseKX_Full);
 
        ad_reg &= lp_reg;
        if (ad_reg & 0x80) {
@@ -1538,26 +1542,27 @@ static enum xgbe_mode 
xgbe_phy_an73_redrv_outcome(struct xgbe_prv_data *pdata)
        ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
        lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2);
        if (lp_reg & 0xc000)
-               pdata->phy.lp_advertising |= ADVERTISED_10000baseR_FEC;
+               XGBE_SET_LP_ADV(lks, 10000baseR_FEC);
 
        return mode;
 }
 
 static enum xgbe_mode xgbe_phy_an73_outcome(struct xgbe_prv_data *pdata)
 {
+       struct ethtool_link_ksettings *lks = &pdata->phy.lks;
        enum xgbe_mode mode;
        unsigned int ad_reg, lp_reg;
 
-       pdata->phy.lp_advertising |= ADVERTISED_Autoneg;
-       pdata->phy.lp_advertising |= ADVERTISED_Backplane;
+       XGBE_SET_LP_ADV(lks, Autoneg);
+       XGBE_SET_LP_ADV(lks, Backplane);
 
        /* Compare Advertisement and Link Partner register 1 */
        ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
        lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA);
        if (lp_reg & 0x400)
-               pdata->phy.lp_advertising |= ADVERTISED_Pause;
+               XGBE_SET_LP_ADV(lks, Pause);
        if (lp_reg & 0x800)
-               pdata->phy.lp_advertising |= ADVERTISED_Asym_Pause;
+               XGBE_SET_LP_ADV(lks, Asym_Pause);
 
        if (pdata->phy.pause_autoneg) {
                /* Set flow control based on auto-negotiation result */
@@ -1579,9 +1584,9 @@ static enum xgbe_mode xgbe_phy_an73_outcome(struct 
xgbe_prv_data *pdata)
        ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
        lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1);
        if (lp_reg & 0x80)
-               pdata->phy.lp_advertising |= ADVERTISED_10000baseKR_Full;
+               XGBE_SET_LP_ADV(lks, 10000baseKR_Full);
        if (lp_reg & 0x20)
-               pdata->phy.lp_advertising |= ADVERTISED_1000baseKX_Full;
+               XGBE_SET_LP_ADV(lks, 1000baseKX_Full);
 
        ad_reg &= lp_reg;
        if (ad_reg & 0x80)
@@ -1595,7 +1600,7 @@ static enum xgbe_mode xgbe_phy_an73_outcome(struct 
xgbe_prv_data *pdata)
        ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
        lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2);
        if (lp_reg & 0xc000)
-               pdata->phy.lp_advertising |= ADVERTISED_10000baseR_FEC;
+               XGBE_SET_LP_ADV(lks, 10000baseR_FEC);
 
        return mode;
 }
@@ -1616,41 +1621,43 @@ static enum xgbe_mode xgbe_phy_an_outcome(struct 
xgbe_prv_data *pdata)
        }
 }
 
-static unsigned int xgbe_phy_an_advertising(struct xgbe_prv_data *pdata)
+static void xgbe_phy_an_advertising(struct xgbe_prv_data *pdata,
+                                   struct ethtool_link_ksettings *dlks)
 {
+       struct ethtool_link_ksettings *slks = &pdata->phy.lks;
        struct xgbe_phy_data *phy_data = pdata->phy_data;
-       unsigned int advertising;
+
+       XGBE_LM_COPY(dlks, advertising, slks, advertising);
 
        /* Without a re-driver, just return current advertising */
        if (!phy_data->redrv)
-               return pdata->phy.advertising;
+               return;
 
        /* With the KR re-driver we need to advertise a single speed */
-       advertising = pdata->phy.advertising;
-       advertising &= ~ADVERTISED_1000baseKX_Full;
-       advertising &= ~ADVERTISED_10000baseKR_Full;
+       XGBE_CLR_ADV(dlks, 1000baseKX_Full);
+       XGBE_CLR_ADV(dlks, 10000baseKR_Full);
 
        switch (phy_data->port_mode) {
        case XGBE_PORT_MODE_BACKPLANE:
-               advertising |= ADVERTISED_10000baseKR_Full;
+               XGBE_SET_ADV(dlks, 10000baseKR_Full);
                break;
        case XGBE_PORT_MODE_BACKPLANE_2500:
-               advertising |= ADVERTISED_1000baseKX_Full;
+               XGBE_SET_ADV(dlks, 1000baseKX_Full);
                break;
        case XGBE_PORT_MODE_1000BASE_T:
        case XGBE_PORT_MODE_1000BASE_X:
        case XGBE_PORT_MODE_NBASE_T:
-               advertising |= ADVERTISED_1000baseKX_Full;
+               XGBE_SET_ADV(dlks, 1000baseKX_Full);
                break;
        case XGBE_PORT_MODE_10GBASE_T:
                if (phy_data->phydev &&
                    (phy_data->phydev->speed == SPEED_10000))
-                       advertising |= ADVERTISED_10000baseKR_Full;
+                       XGBE_SET_ADV(dlks, 10000baseKR_Full);
                else
-                       advertising |= ADVERTISED_1000baseKX_Full;
+                       XGBE_SET_ADV(dlks, 1000baseKX_Full);
                break;
        case XGBE_PORT_MODE_10GBASE_R:
-               advertising |= ADVERTISED_10000baseKR_Full;
+               XGBE_SET_ADV(dlks, 10000baseKR_Full);
                break;
        case XGBE_PORT_MODE_SFP:
                switch (phy_data->sfp_base) {
@@ -1658,24 +1665,24 @@ static unsigned int xgbe_phy_an_advertising(struct 
xgbe_prv_data *pdata)
                case XGBE_SFP_BASE_1000_SX:
                case XGBE_SFP_BASE_1000_LX:
                case XGBE_SFP_BASE_1000_CX:
-                       advertising |= ADVERTISED_1000baseKX_Full;
+                       XGBE_SET_ADV(dlks, 1000baseKX_Full);
                        break;
                default:
-                       advertising |= ADVERTISED_10000baseKR_Full;
+                       XGBE_SET_ADV(dlks, 10000baseKR_Full);
                        break;
                }
                break;
        default:
-               advertising |= ADVERTISED_10000baseKR_Full;
+               XGBE_SET_ADV(dlks, 10000baseKR_Full);
                break;
        }
-
-       return advertising;
 }
 
 static int xgbe_phy_an_config(struct xgbe_prv_data *pdata)
 {
+       struct ethtool_link_ksettings *lks = &pdata->phy.lks;
        struct xgbe_phy_data *phy_data = pdata->phy_data;
+       u32 advertising;
        int ret;
 
        ret = xgbe_phy_find_phy_device(pdata);
@@ -1685,9 +1692,12 @@ static int xgbe_phy_an_config(struct xgbe_prv_data 
*pdata)
        if (!phy_data->phydev)
                return 0;
 
+       ethtool_convert_link_mode_to_legacy_u32(&advertising,
+                                               lks->link_modes.advertising);
+
        phy_data->phydev->autoneg = pdata->phy.autoneg;
        phy_data->phydev->advertising = phy_data->phydev->supported &
-                                       pdata->phy.advertising;
+                                       advertising;
 
        if (pdata->phy.autoneg != AUTONEG_ENABLE) {
                phy_data->phydev->speed = pdata->phy.speed;
@@ -2148,11 +2158,10 @@ static void xgbe_phy_set_mode(struct xgbe_prv_data 
*pdata, enum xgbe_mode mode)
 }
 
 static bool xgbe_phy_check_mode(struct xgbe_prv_data *pdata,
-                               enum xgbe_mode mode, u32 advert)
+                               enum xgbe_mode mode, bool advert)
 {
        if (pdata->phy.autoneg == AUTONEG_ENABLE) {
-               if (pdata->phy.advertising & advert)
-                       return true;
+               return advert;
        } else {
                enum xgbe_mode cur_mode;
 
@@ -2167,13 +2176,15 @@ static bool xgbe_phy_check_mode(struct xgbe_prv_data 
*pdata,
 static bool xgbe_phy_use_basex_mode(struct xgbe_prv_data *pdata,
                                    enum xgbe_mode mode)
 {
+       struct ethtool_link_ksettings *lks = &pdata->phy.lks;
+
        switch (mode) {
        case XGBE_MODE_X:
                return xgbe_phy_check_mode(pdata, mode,
-                                          ADVERTISED_1000baseT_Full);
+                                          XGBE_ADV(lks, 1000baseX_Full));
        case XGBE_MODE_KR:
                return xgbe_phy_check_mode(pdata, mode,
-                                          ADVERTISED_10000baseT_Full);
+                                          XGBE_ADV(lks, 10000baseKR_Full));
        default:
                return false;
        }
@@ -2182,19 +2193,21 @@ static bool xgbe_phy_use_basex_mode(struct 
xgbe_prv_data *pdata,
 static bool xgbe_phy_use_baset_mode(struct xgbe_prv_data *pdata,
                                    enum xgbe_mode mode)
 {
+       struct ethtool_link_ksettings *lks = &pdata->phy.lks;
+
        switch (mode) {
        case XGBE_MODE_SGMII_100:
                return xgbe_phy_check_mode(pdata, mode,
-                                          ADVERTISED_100baseT_Full);
+                                          XGBE_ADV(lks, 100baseT_Full));
        case XGBE_MODE_SGMII_1000:
                return xgbe_phy_check_mode(pdata, mode,
-                                          ADVERTISED_1000baseT_Full);
+                                          XGBE_ADV(lks, 1000baseT_Full));
        case XGBE_MODE_KX_2500:
                return xgbe_phy_check_mode(pdata, mode,
-                                          ADVERTISED_2500baseX_Full);
+                                          XGBE_ADV(lks, 2500baseT_Full));
        case XGBE_MODE_KR:
                return xgbe_phy_check_mode(pdata, mode,
-                                          ADVERTISED_10000baseT_Full);
+                                          XGBE_ADV(lks, 10000baseT_Full));
        default:
                return false;
        }
@@ -2203,6 +2216,7 @@ static bool xgbe_phy_use_baset_mode(struct xgbe_prv_data 
*pdata,
 static bool xgbe_phy_use_sfp_mode(struct xgbe_prv_data *pdata,
                                  enum xgbe_mode mode)
 {
+       struct ethtool_link_ksettings *lks = &pdata->phy.lks;
        struct xgbe_phy_data *phy_data = pdata->phy_data;
 
        switch (mode) {
@@ -2210,22 +2224,26 @@ static bool xgbe_phy_use_sfp_mode(struct xgbe_prv_data 
*pdata,
                if (phy_data->sfp_base == XGBE_SFP_BASE_1000_T)
                        return false;
                return xgbe_phy_check_mode(pdata, mode,
-                                          ADVERTISED_1000baseT_Full);
+                                          XGBE_ADV(lks, 1000baseX_Full));
        case XGBE_MODE_SGMII_100:
                if (phy_data->sfp_base != XGBE_SFP_BASE_1000_T)
                        return false;
                return xgbe_phy_check_mode(pdata, mode,
-                                          ADVERTISED_100baseT_Full);
+                                          XGBE_ADV(lks, 100baseT_Full));
        case XGBE_MODE_SGMII_1000:
                if (phy_data->sfp_base != XGBE_SFP_BASE_1000_T)
                        return false;
                return xgbe_phy_check_mode(pdata, mode,
-                                          ADVERTISED_1000baseT_Full);
+                                          XGBE_ADV(lks, 1000baseT_Full));
        case XGBE_MODE_SFI:
                if (phy_data->sfp_mod_absent)
                        return true;
                return xgbe_phy_check_mode(pdata, mode,
-                                          ADVERTISED_10000baseT_Full);
+                                          XGBE_ADV(lks, 10000baseSR_Full)  ||
+                                          XGBE_ADV(lks, 10000baseLR_Full)  ||
+                                          XGBE_ADV(lks, 10000baseLRM_Full) ||
+                                          XGBE_ADV(lks, 10000baseER_Full)  ||
+                                          XGBE_ADV(lks, 10000baseCR_Full));
        default:
                return false;
        }
@@ -2234,10 +2252,12 @@ static bool xgbe_phy_use_sfp_mode(struct xgbe_prv_data 
*pdata,
 static bool xgbe_phy_use_bp_2500_mode(struct xgbe_prv_data *pdata,
                                      enum xgbe_mode mode)
 {
+       struct ethtool_link_ksettings *lks = &pdata->phy.lks;
+
        switch (mode) {
        case XGBE_MODE_KX_2500:
                return xgbe_phy_check_mode(pdata, mode,
-                                          ADVERTISED_2500baseX_Full);
+                                          XGBE_ADV(lks, 2500baseX_Full));
        default:
                return false;
        }
@@ -2246,13 +2266,15 @@ static bool xgbe_phy_use_bp_2500_mode(struct 
xgbe_prv_data *pdata,
 static bool xgbe_phy_use_bp_mode(struct xgbe_prv_data *pdata,
                                 enum xgbe_mode mode)
 {
+       struct ethtool_link_ksettings *lks = &pdata->phy.lks;
+
        switch (mode) {
        case XGBE_MODE_KX_1000:
                return xgbe_phy_check_mode(pdata, mode,
-                                          ADVERTISED_1000baseKX_Full);
+                                          XGBE_ADV(lks, 1000baseKX_Full));
        case XGBE_MODE_KR:
                return xgbe_phy_check_mode(pdata, mode,
-                                          ADVERTISED_10000baseKR_Full);
+                                          XGBE_ADV(lks, 10000baseKR_Full));
        default:
                return false;
        }
@@ -2820,6 +2842,7 @@ static void xgbe_phy_exit(struct xgbe_prv_data *pdata)
 static int xgbe_phy_init(struct xgbe_prv_data *pdata)
 {
        struct xgbe_phy_impl_if *phy_impl = &pdata->phy_if.phy_impl;
+       struct ethtool_link_ksettings *lks = &pdata->phy.lks;
        struct xgbe_phy_data *phy_data;
        struct mii_bus *mii;
        unsigned int reg;
@@ -2899,32 +2922,33 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
        phy_data->cur_mode = XGBE_MODE_UNKNOWN;
 
        /* Initialize supported features */
-       pdata->phy.supported = 0;
+       XGBE_ZERO_SUP(lks);
 
        switch (phy_data->port_mode) {
        /* Backplane support */
        case XGBE_PORT_MODE_BACKPLANE:
-               pdata->phy.supported |= SUPPORTED_Autoneg;
-               pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
-               pdata->phy.supported |= SUPPORTED_Backplane;
+               XGBE_SET_SUP(lks, Autoneg);
+               XGBE_SET_SUP(lks, Pause);
+               XGBE_SET_SUP(lks, Asym_Pause);
+               XGBE_SET_SUP(lks, Backplane);
                if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) {
-                       pdata->phy.supported |= SUPPORTED_1000baseKX_Full;
+                       XGBE_SET_SUP(lks, 1000baseKX_Full);
                        phy_data->start_mode = XGBE_MODE_KX_1000;
                }
                if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) {
-                       pdata->phy.supported |= SUPPORTED_10000baseKR_Full;
+                       XGBE_SET_SUP(lks, 10000baseKR_Full);
                        if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE)
-                               pdata->phy.supported |=
-                                       SUPPORTED_10000baseR_FEC;
+                               XGBE_SET_SUP(lks, 10000baseR_FEC);
                        phy_data->start_mode = XGBE_MODE_KR;
                }
 
                phy_data->phydev_mode = XGBE_MDIO_MODE_NONE;
                break;
        case XGBE_PORT_MODE_BACKPLANE_2500:
-               pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
-               pdata->phy.supported |= SUPPORTED_Backplane;
-               pdata->phy.supported |= SUPPORTED_2500baseX_Full;
+               XGBE_SET_SUP(lks, Pause);
+               XGBE_SET_SUP(lks, Asym_Pause);
+               XGBE_SET_SUP(lks, Backplane);
+               XGBE_SET_SUP(lks, 2500baseX_Full);
                phy_data->start_mode = XGBE_MODE_KX_2500;
 
                phy_data->phydev_mode = XGBE_MDIO_MODE_NONE;
@@ -2932,15 +2956,16 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
 
        /* MDIO 1GBase-T support */
        case XGBE_PORT_MODE_1000BASE_T:
-               pdata->phy.supported |= SUPPORTED_Autoneg;
-               pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
-               pdata->phy.supported |= SUPPORTED_TP;
+               XGBE_SET_SUP(lks, Autoneg);
+               XGBE_SET_SUP(lks, Pause);
+               XGBE_SET_SUP(lks, Asym_Pause);
+               XGBE_SET_SUP(lks, TP);
                if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) {
-                       pdata->phy.supported |= SUPPORTED_100baseT_Full;
+                       XGBE_SET_SUP(lks, 100baseT_Full);
                        phy_data->start_mode = XGBE_MODE_SGMII_100;
                }
                if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) {
-                       pdata->phy.supported |= SUPPORTED_1000baseT_Full;
+                       XGBE_SET_SUP(lks, 1000baseT_Full);
                        phy_data->start_mode = XGBE_MODE_SGMII_1000;
                }
 
@@ -2951,10 +2976,11 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
 
        /* MDIO Base-X support */
        case XGBE_PORT_MODE_1000BASE_X:
-               pdata->phy.supported |= SUPPORTED_Autoneg;
-               pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
-               pdata->phy.supported |= SUPPORTED_FIBRE;
-               pdata->phy.supported |= SUPPORTED_1000baseT_Full;
+               XGBE_SET_SUP(lks, Autoneg);
+               XGBE_SET_SUP(lks, Pause);
+               XGBE_SET_SUP(lks, Asym_Pause);
+               XGBE_SET_SUP(lks, FIBRE);
+               XGBE_SET_SUP(lks, 1000baseX_Full);
                phy_data->start_mode = XGBE_MODE_X;
 
                phy_data->phydev_mode = XGBE_MDIO_MODE_CL22;
@@ -2964,19 +2990,20 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
 
        /* MDIO NBase-T support */
        case XGBE_PORT_MODE_NBASE_T:
-               pdata->phy.supported |= SUPPORTED_Autoneg;
-               pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
-               pdata->phy.supported |= SUPPORTED_TP;
+               XGBE_SET_SUP(lks, Autoneg);
+               XGBE_SET_SUP(lks, Pause);
+               XGBE_SET_SUP(lks, Asym_Pause);
+               XGBE_SET_SUP(lks, TP);
                if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) {
-                       pdata->phy.supported |= SUPPORTED_100baseT_Full;
+                       XGBE_SET_SUP(lks, 100baseT_Full);
                        phy_data->start_mode = XGBE_MODE_SGMII_100;
                }
                if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) {
-                       pdata->phy.supported |= SUPPORTED_1000baseT_Full;
+                       XGBE_SET_SUP(lks, 1000baseT_Full);
                        phy_data->start_mode = XGBE_MODE_SGMII_1000;
                }
                if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_2500) {
-                       pdata->phy.supported |= SUPPORTED_2500baseX_Full;
+                       XGBE_SET_SUP(lks, 2500baseT_Full);
                        phy_data->start_mode = XGBE_MODE_KX_2500;
                }
 
@@ -2987,19 +3014,20 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
 
        /* 10GBase-T support */
        case XGBE_PORT_MODE_10GBASE_T:
-               pdata->phy.supported |= SUPPORTED_Autoneg;
-               pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
-               pdata->phy.supported |= SUPPORTED_TP;
+               XGBE_SET_SUP(lks, Autoneg);
+               XGBE_SET_SUP(lks, Pause);
+               XGBE_SET_SUP(lks, Asym_Pause);
+               XGBE_SET_SUP(lks, TP);
                if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) {
-                       pdata->phy.supported |= SUPPORTED_100baseT_Full;
+                       XGBE_SET_SUP(lks, 100baseT_Full);
                        phy_data->start_mode = XGBE_MODE_SGMII_100;
                }
                if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) {
-                       pdata->phy.supported |= SUPPORTED_1000baseT_Full;
+                       XGBE_SET_SUP(lks, 1000baseT_Full);
                        phy_data->start_mode = XGBE_MODE_SGMII_1000;
                }
                if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) {
-                       pdata->phy.supported |= SUPPORTED_10000baseT_Full;
+                       XGBE_SET_SUP(lks, 10000baseT_Full);
                        phy_data->start_mode = XGBE_MODE_KR;
                }
 
@@ -3010,12 +3038,16 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
 
        /* 10GBase-R support */
        case XGBE_PORT_MODE_10GBASE_R:
-               pdata->phy.supported |= SUPPORTED_Autoneg;
-               pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
-               pdata->phy.supported |= SUPPORTED_TP;
-               pdata->phy.supported |= SUPPORTED_10000baseT_Full;
+               XGBE_SET_SUP(lks, Autoneg);
+               XGBE_SET_SUP(lks, Pause);
+               XGBE_SET_SUP(lks, Asym_Pause);
+               XGBE_SET_SUP(lks, FIBRE);
+               XGBE_SET_SUP(lks, 10000baseSR_Full);
+               XGBE_SET_SUP(lks, 10000baseLR_Full);
+               XGBE_SET_SUP(lks, 10000baseLRM_Full);
+               XGBE_SET_SUP(lks, 10000baseER_Full);
                if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE)
-                       pdata->phy.supported |= SUPPORTED_10000baseR_FEC;
+                       XGBE_SET_SUP(lks, 10000baseR_FEC);
                phy_data->start_mode = XGBE_MODE_SFI;
 
                phy_data->phydev_mode = XGBE_MDIO_MODE_NONE;
@@ -3023,22 +3055,17 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
 
        /* SFP support */
        case XGBE_PORT_MODE_SFP:
-               pdata->phy.supported |= SUPPORTED_Autoneg;
-               pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
-               pdata->phy.supported |= SUPPORTED_TP;
-               pdata->phy.supported |= SUPPORTED_FIBRE;
-               if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) {
-                       pdata->phy.supported |= SUPPORTED_100baseT_Full;
+               XGBE_SET_SUP(lks, Autoneg);
+               XGBE_SET_SUP(lks, Pause);
+               XGBE_SET_SUP(lks, Asym_Pause);
+               XGBE_SET_SUP(lks, TP);
+               XGBE_SET_SUP(lks, FIBRE);
+               if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100)
                        phy_data->start_mode = XGBE_MODE_SGMII_100;
-               }
-               if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) {
-                       pdata->phy.supported |= SUPPORTED_1000baseT_Full;
+               if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
                        phy_data->start_mode = XGBE_MODE_SGMII_1000;
-               }
-               if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) {
-                       pdata->phy.supported |= SUPPORTED_10000baseT_Full;
+               if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000)
                        phy_data->start_mode = XGBE_MODE_SFI;
-               }
 
                phy_data->phydev_mode = XGBE_MDIO_MODE_CL22;
                phy_impl->phydev_read = xgbe_phy_phydev_read;
@@ -3052,8 +3079,9 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
        }
 
        if (netif_msg_probe(pdata))
-               dev_dbg(pdata->dev, "phy supported=%#x\n",
-                       pdata->phy.supported);
+               dev_dbg(pdata->dev, "phy supported=0x%*pb\n",
+                       __ETHTOOL_LINK_MODE_MASK_NBITS,
+                       lks->link_modes.supported);
 
        if ((phy_data->conn_type & XGBE_CONN_TYPE_MDIO) &&
            (phy_data->phydev_mode != XGBE_MDIO_MODE_NONE)) {
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h 
b/drivers/net/ethernet/amd/xgbe/xgbe.h
index 929c6b2..12860be 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe.h
@@ -131,6 +131,7 @@
 #include <linux/cpumask.h>
 #include <linux/interrupt.h>
 #include <linux/dcache.h>
+#include <linux/ethtool.h>
 
 #define XGBE_DRV_NAME          "amd-xgbe"
 #define XGBE_DRV_VERSION       "1.0.3"
@@ -296,6 +297,48 @@
 /* MDIO port types */
 #define XGMAC_MAX_C22_PORT             3
 
+/* Link mode bit operations */
+#define XGBE_ZERO_SUP(_ls)             \
+       ethtool_link_ksettings_zero_link_mode((_ls), supported)
+
+#define XGBE_SET_SUP(_ls, _mode)       \
+       ethtool_link_ksettings_add_link_mode((_ls), supported, _mode)
+
+#define XGBE_CLR_SUP(_ls, _mode)       \
+       ethtool_link_ksettings_del_link_mode((_ls), supported, _mode)
+
+#define XGBE_IS_SUP(_ls, _mode)        \
+       ethtool_link_ksettings_test_link_mode((_ls), supported, _mode)
+
+#define XGBE_ZERO_ADV(_ls)             \
+       ethtool_link_ksettings_zero_link_mode((_ls), advertising)
+
+#define XGBE_SET_ADV(_ls, _mode)       \
+       ethtool_link_ksettings_add_link_mode((_ls), advertising, _mode)
+
+#define XGBE_CLR_ADV(_ls, _mode)       \
+       ethtool_link_ksettings_del_link_mode((_ls), advertising, _mode)
+
+#define XGBE_ADV(_ls, _mode)           \
+       ethtool_link_ksettings_test_link_mode((_ls), advertising, _mode)
+
+#define XGBE_ZERO_LP_ADV(_ls)          \
+       ethtool_link_ksettings_zero_link_mode((_ls), lp_advertising)
+
+#define XGBE_SET_LP_ADV(_ls, _mode)    \
+       ethtool_link_ksettings_add_link_mode((_ls), lp_advertising, _mode)
+
+#define XGBE_CLR_LP_ADV(_ls, _mode)    \
+       ethtool_link_ksettings_del_link_mode((_ls), lp_advertising, _mode)
+
+#define XGBE_LP_ADV(_ls, _mode)                \
+       ethtool_link_ksettings_test_link_mode((_ls), lp_advertising, _mode)
+
+#define XGBE_LM_COPY(_dst, _dname, _src, _sname)       \
+       bitmap_copy((_dst)->link_modes._dname,          \
+                   (_src)->link_modes._sname,          \
+                   __ETHTOOL_LINK_MODE_MASK_NBITS)
+
 struct xgbe_prv_data;
 
 struct xgbe_packet_data {
@@ -563,9 +606,7 @@ enum xgbe_mdio_mode {
 };
 
 struct xgbe_phy {
-       u32 supported;
-       u32 advertising;
-       u32 lp_advertising;
+       struct ethtool_link_ksettings lks;
 
        int address;
 
@@ -818,7 +859,8 @@ struct xgbe_phy_impl_if {
        int (*an_config)(struct xgbe_prv_data *);
 
        /* Set/override auto-negotiation advertisement settings */
-       unsigned int (*an_advertising)(struct xgbe_prv_data *);
+       void (*an_advertising)(struct xgbe_prv_data *,
+                              struct ethtool_link_ksettings *);
 
        /* Process results of auto-negotiation */
        enum xgbe_mode (*an_outcome)(struct xgbe_prv_data *);

Reply via email to