OSDN Git Service

sfc: support the ethtool ksettings API properly so that 25/50/100G works
authorEdward Cree <ecree@solarflare.com>
Wed, 10 Jan 2018 18:00:14 +0000 (18:00 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 10 Jan 2018 21:23:38 +0000 (16:23 -0500)
Store and handle ethtool link mode masks within the driver instead of
 just a single u32.  However, quite a significant amount of existing code
 wants to manipulate the masks directly, and thus now uses the first
 unsigned long (i.e. mask[0]) as though it were a legacy u32 mask.  This
 is ok because all the bits that code is interested in are in the first
 32 bits of the mask; but it might be a good idea to change them in
 future to use the proper bitmap API.

Signed-off-by: Edward Cree <ecree@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/sfc/efx.c
drivers/net/ethernet/sfc/efx.h
drivers/net/ethernet/sfc/ethtool.c
drivers/net/ethernet/sfc/mcdi_port.c
drivers/net/ethernet/sfc/net_driver.h

index 3780161..12f0abc 100644 (file)
@@ -953,31 +953,42 @@ void efx_link_status_changed(struct efx_nic *efx)
                netif_info(efx, link, efx->net_dev, "link down\n");
 }
 
-void efx_link_set_advertising(struct efx_nic *efx, u32 advertising)
+void efx_link_set_advertising(struct efx_nic *efx,
+                             const unsigned long *advertising)
 {
-       efx->link_advertising = advertising;
-       if (advertising) {
-               if (advertising & ADVERTISED_Pause)
-                       efx->wanted_fc |= (EFX_FC_TX | EFX_FC_RX);
-               else
-                       efx->wanted_fc &= ~(EFX_FC_TX | EFX_FC_RX);
-               if (advertising & ADVERTISED_Asym_Pause)
-                       efx->wanted_fc ^= EFX_FC_TX;
-       }
+       memcpy(efx->link_advertising, advertising,
+              sizeof(__ETHTOOL_DECLARE_LINK_MODE_MASK()));
+
+       efx->link_advertising[0] |= ADVERTISED_Autoneg;
+       if (advertising[0] & ADVERTISED_Pause)
+               efx->wanted_fc |= (EFX_FC_TX | EFX_FC_RX);
+       else
+               efx->wanted_fc &= ~(EFX_FC_TX | EFX_FC_RX);
+       if (advertising[0] & ADVERTISED_Asym_Pause)
+               efx->wanted_fc ^= EFX_FC_TX;
+}
+
+/* Equivalent to efx_link_set_advertising with all-zeroes, except does not
+ * force the Autoneg bit on.
+ */
+void efx_link_clear_advertising(struct efx_nic *efx)
+{
+       bitmap_zero(efx->link_advertising, __ETHTOOL_LINK_MODE_MASK_NBITS);
+       efx->wanted_fc &= ~(EFX_FC_TX | EFX_FC_RX);
 }
 
 void efx_link_set_wanted_fc(struct efx_nic *efx, u8 wanted_fc)
 {
        efx->wanted_fc = wanted_fc;
-       if (efx->link_advertising) {
+       if (efx->link_advertising[0]) {
                if (wanted_fc & EFX_FC_RX)
-                       efx->link_advertising |= (ADVERTISED_Pause |
-                                                 ADVERTISED_Asym_Pause);
+                       efx->link_advertising[0] |= (ADVERTISED_Pause |
+                                                    ADVERTISED_Asym_Pause);
                else
-                       efx->link_advertising &= ~(ADVERTISED_Pause |
-                                                  ADVERTISED_Asym_Pause);
+                       efx->link_advertising[0] &= ~(ADVERTISED_Pause |
+                                                     ADVERTISED_Asym_Pause);
                if (wanted_fc & EFX_FC_TX)
-                       efx->link_advertising ^= ADVERTISED_Asym_Pause;
+                       efx->link_advertising[0] ^= ADVERTISED_Asym_Pause;
        }
 }
 
index 16da3e9..0cddc5a 100644 (file)
@@ -258,7 +258,9 @@ static inline void efx_schedule_channel_irq(struct efx_channel *channel)
 }
 
 void efx_link_status_changed(struct efx_nic *efx);
-void efx_link_set_advertising(struct efx_nic *efx, u32);
+void efx_link_set_advertising(struct efx_nic *efx,
+                             const unsigned long *advertising);
+void efx_link_clear_advertising(struct efx_nic *efx);
 void efx_link_set_wanted_fc(struct efx_nic *efx, u8);
 
 static inline void efx_device_detach_sync(struct efx_nic *efx)
index 3747b56..4db2dc2 100644 (file)
@@ -720,7 +720,7 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
                goto out;
        }
 
-       if ((wanted_fc & EFX_FC_AUTO) && !efx->link_advertising) {
+       if ((wanted_fc & EFX_FC_AUTO) && !efx->link_advertising[0]) {
                netif_dbg(efx, drv, efx->net_dev,
                          "Autonegotiation is disabled\n");
                rc = -EINVAL;
@@ -732,10 +732,10 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
            (wanted_fc & EFX_FC_TX) && !(efx->wanted_fc & EFX_FC_TX))
                efx->type->prepare_enable_fc_tx(efx);
 
-       old_adv = efx->link_advertising;
+       old_adv = efx->link_advertising[0];
        old_fc = efx->wanted_fc;
        efx_link_set_wanted_fc(efx, wanted_fc);
-       if (efx->link_advertising != old_adv ||
+       if (efx->link_advertising[0] != old_adv ||
            (efx->wanted_fc ^ old_fc) & EFX_FC_AUTO) {
                rc = efx->phy_op->reconfigure(efx);
                if (rc) {
index 35593d6..6d913dd 100644 (file)
@@ -171,89 +171,96 @@ static int efx_mcdi_mdio_write(struct net_device *net_dev,
        return 0;
 }
 
-static u32 mcdi_to_ethtool_cap(u32 media, u32 cap)
+static void mcdi_to_ethtool_linkset(u32 media, u32 cap, unsigned long *linkset)
 {
-       u32 result = 0;
+       #define SET_BIT(name)   __set_bit(ETHTOOL_LINK_MODE_ ## name ## _BIT, \
+                                         linkset)
 
+       bitmap_zero(linkset, __ETHTOOL_LINK_MODE_MASK_NBITS);
        switch (media) {
        case MC_CMD_MEDIA_KX4:
-               result |= SUPPORTED_Backplane;
+               SET_BIT(Backplane);
                if (cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN))
-                       result |= SUPPORTED_1000baseKX_Full;
+                       SET_BIT(1000baseKX_Full);
                if (cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN))
-                       result |= SUPPORTED_10000baseKX4_Full;
+                       SET_BIT(10000baseKX4_Full);
                if (cap & (1 << MC_CMD_PHY_CAP_40000FDX_LBN))
-                       result |= SUPPORTED_40000baseKR4_Full;
+                       SET_BIT(40000baseKR4_Full);
                break;
 
        case MC_CMD_MEDIA_XFP:
        case MC_CMD_MEDIA_SFP_PLUS:
        case MC_CMD_MEDIA_QSFP_PLUS:
-               result |= SUPPORTED_FIBRE;
+               SET_BIT(FIBRE);
                if (cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN))
-                       result |= SUPPORTED_1000baseT_Full;
+                       SET_BIT(1000baseT_Full);
                if (cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN))
-                       result |= SUPPORTED_10000baseT_Full;
+                       SET_BIT(10000baseT_Full);
                if (cap & (1 << MC_CMD_PHY_CAP_40000FDX_LBN))
-                       result |= SUPPORTED_40000baseCR4_Full;
+                       SET_BIT(40000baseCR4_Full);
                break;
 
        case MC_CMD_MEDIA_BASE_T:
-               result |= SUPPORTED_TP;
+               SET_BIT(TP);
                if (cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN))
-                       result |= SUPPORTED_10baseT_Half;
+                       SET_BIT(10baseT_Half);
                if (cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN))
-                       result |= SUPPORTED_10baseT_Full;
+                       SET_BIT(10baseT_Full);
                if (cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN))
-                       result |= SUPPORTED_100baseT_Half;
+                       SET_BIT(100baseT_Half);
                if (cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN))
-                       result |= SUPPORTED_100baseT_Full;
+                       SET_BIT(100baseT_Full);
                if (cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN))
-                       result |= SUPPORTED_1000baseT_Half;
+                       SET_BIT(1000baseT_Half);
                if (cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN))
-                       result |= SUPPORTED_1000baseT_Full;
+                       SET_BIT(1000baseT_Full);
                if (cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN))
-                       result |= SUPPORTED_10000baseT_Full;
+                       SET_BIT(10000baseT_Full);
                break;
        }
 
        if (cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN))
-               result |= SUPPORTED_Pause;
+               SET_BIT(Pause);
        if (cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN))
-               result |= SUPPORTED_Asym_Pause;
+               SET_BIT(Asym_Pause);
        if (cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
-               result |= SUPPORTED_Autoneg;
+               SET_BIT(Autoneg);
 
-       return result;
+       #undef SET_BIT
 }
 
-static u32 ethtool_to_mcdi_cap(u32 cap)
+static u32 ethtool_linkset_to_mcdi_cap(const unsigned long *linkset)
 {
        u32 result = 0;
 
-       if (cap & SUPPORTED_10baseT_Half)
+       #define TEST_BIT(name)  test_bit(ETHTOOL_LINK_MODE_ ## name ## _BIT, \
+                                        linkset)
+
+       if (TEST_BIT(10baseT_Half))
                result |= (1 << MC_CMD_PHY_CAP_10HDX_LBN);
-       if (cap & SUPPORTED_10baseT_Full)
+       if (TEST_BIT(10baseT_Full))
                result |= (1 << MC_CMD_PHY_CAP_10FDX_LBN);
-       if (cap & SUPPORTED_100baseT_Half)
+       if (TEST_BIT(100baseT_Half))
                result |= (1 << MC_CMD_PHY_CAP_100HDX_LBN);
-       if (cap & SUPPORTED_100baseT_Full)
+       if (TEST_BIT(100baseT_Full))
                result |= (1 << MC_CMD_PHY_CAP_100FDX_LBN);
-       if (cap & SUPPORTED_1000baseT_Half)
+       if (TEST_BIT(1000baseT_Half))
                result |= (1 << MC_CMD_PHY_CAP_1000HDX_LBN);
-       if (cap & (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseKX_Full))
+       if (TEST_BIT(1000baseT_Full) || TEST_BIT(1000baseKX_Full))
                result |= (1 << MC_CMD_PHY_CAP_1000FDX_LBN);
-       if (cap & (SUPPORTED_10000baseT_Full | SUPPORTED_10000baseKX4_Full))
+       if (TEST_BIT(10000baseT_Full) || TEST_BIT(10000baseKX4_Full))
                result |= (1 << MC_CMD_PHY_CAP_10000FDX_LBN);
-       if (cap & (SUPPORTED_40000baseCR4_Full | SUPPORTED_40000baseKR4_Full))
+       if (TEST_BIT(40000baseCR4_Full) || TEST_BIT(40000baseKR4_Full))
                result |= (1 << MC_CMD_PHY_CAP_40000FDX_LBN);
-       if (cap & SUPPORTED_Pause)
+       if (TEST_BIT(Pause))
                result |= (1 << MC_CMD_PHY_CAP_PAUSE_LBN);
-       if (cap & SUPPORTED_Asym_Pause)
+       if (TEST_BIT(Asym_Pause))
                result |= (1 << MC_CMD_PHY_CAP_ASYM_LBN);
-       if (cap & SUPPORTED_Autoneg)
+       if (TEST_BIT(Autoneg))
                result |= (1 << MC_CMD_PHY_CAP_AN_LBN);
 
+       #undef TEST_BIT
+
        return result;
 }
 
@@ -285,7 +292,7 @@ static u32 efx_get_mcdi_phy_flags(struct efx_nic *efx)
        return flags;
 }
 
-static u32 mcdi_to_ethtool_media(u32 media)
+static u8 mcdi_to_ethtool_media(u32 media)
 {
        switch (media) {
        case MC_CMD_MEDIA_XAUI:
@@ -371,8 +378,8 @@ static int efx_mcdi_phy_probe(struct efx_nic *efx)
 
        caps = MCDI_DWORD(outbuf, GET_LINK_OUT_CAP);
        if (caps & (1 << MC_CMD_PHY_CAP_AN_LBN))
-               efx->link_advertising =
-                       mcdi_to_ethtool_cap(phy_data->media, caps);
+               mcdi_to_ethtool_linkset(phy_data->media, caps,
+                                       efx->link_advertising);
        else
                phy_data->forced_cap = caps;
 
@@ -435,8 +442,8 @@ fail:
 int efx_mcdi_port_reconfigure(struct efx_nic *efx)
 {
        struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
-       u32 caps = (efx->link_advertising ?
-                   ethtool_to_mcdi_cap(efx->link_advertising) :
+       u32 caps = (efx->link_advertising[0] ?
+                   ethtool_linkset_to_mcdi_cap(efx->link_advertising) :
                    phy_cfg->forced_cap);
 
        return efx_mcdi_set_link(efx, caps, efx_get_mcdi_phy_flags(efx),
@@ -509,34 +516,28 @@ static void efx_mcdi_phy_get_link_ksettings(struct efx_nic *efx,
        struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
        MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_LINK_OUT_LEN);
        int rc;
-       u32 supported, advertising, lp_advertising;
 
-       supported = mcdi_to_ethtool_cap(phy_cfg->media, phy_cfg->supported_cap);
-       advertising = efx->link_advertising;
        cmd->base.speed = efx->link_state.speed;
        cmd->base.duplex = efx->link_state.fd;
        cmd->base.port = mcdi_to_ethtool_media(phy_cfg->media);
        cmd->base.phy_address = phy_cfg->port;
-       cmd->base.autoneg = !!(efx->link_advertising & ADVERTISED_Autoneg);
+       cmd->base.autoneg = !!(efx->link_advertising[0] & ADVERTISED_Autoneg);
        cmd->base.mdio_support = (efx->mdio.mode_support &
                              (MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22));
 
-       ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
-                                               supported);
-       ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
-                                               advertising);
+       mcdi_to_ethtool_linkset(phy_cfg->media, phy_cfg->supported_cap,
+                               cmd->link_modes.supported);
+       memcpy(cmd->link_modes.advertising, efx->link_advertising,
+              sizeof(__ETHTOOL_DECLARE_LINK_MODE_MASK()));
 
        BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0);
        rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
                          outbuf, sizeof(outbuf), NULL);
        if (rc)
                return;
-       lp_advertising =
-               mcdi_to_ethtool_cap(phy_cfg->media,
-                                   MCDI_DWORD(outbuf, GET_LINK_OUT_LP_CAP));
-
-       ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising,
-                                               lp_advertising);
+       mcdi_to_ethtool_linkset(phy_cfg->media,
+                               MCDI_DWORD(outbuf, GET_LINK_OUT_LP_CAP),
+                               cmd->link_modes.lp_advertising);
 }
 
 static int
@@ -546,14 +547,10 @@ efx_mcdi_phy_set_link_ksettings(struct efx_nic *efx,
        struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
        u32 caps;
        int rc;
-       u32 advertising;
-
-       ethtool_convert_link_mode_to_legacy_u32(&advertising,
-                                               cmd->link_modes.advertising);
 
        if (cmd->base.autoneg) {
-               caps = (ethtool_to_mcdi_cap(advertising) |
-                        1 << MC_CMD_PHY_CAP_AN_LBN);
+               caps = (ethtool_linkset_to_mcdi_cap(cmd->link_modes.advertising) |
+                       1 << MC_CMD_PHY_CAP_AN_LBN);
        } else if (cmd->base.duplex) {
                switch (cmd->base.speed) {
                case 10:     caps = 1 << MC_CMD_PHY_CAP_10FDX_LBN;     break;
@@ -581,11 +578,10 @@ efx_mcdi_phy_set_link_ksettings(struct efx_nic *efx,
                return rc;
 
        if (cmd->base.autoneg) {
-               efx_link_set_advertising(
-                       efx, advertising | ADVERTISED_Autoneg);
+               efx_link_set_advertising(efx, cmd->link_modes.advertising);
                phy_cfg->forced_cap = 0;
        } else {
-               efx_link_set_advertising(efx, 0);
+               efx_link_clear_advertising(efx);
                phy_cfg->forced_cap = caps;
        }
        return 0;
index 4cedc5c..3dd42f3 100644 (file)
@@ -937,7 +937,7 @@ struct efx_nic {
        unsigned int mdio_bus;
        enum efx_phy_mode phy_mode;
 
-       u32 link_advertising;
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(link_advertising);
        struct efx_link_state link_state;
        unsigned int n_link_state_changes;