sfc: Refactor link configuration
authorBen Hutchings <bhutchings@solarflare.com>
Sun, 29 Nov 2009 03:42:41 +0000 (03:42 +0000)
committerDavid S. Miller <davem@davemloft.net>
Mon, 30 Nov 2009 00:46:28 +0000 (16:46 -0800)
Refactor PHY, MAC and NIC configuration operations so that the
existing link configuration can be re-pushed with:

efx->phy_op->reconfigure(efx);
efx->mac_op->reconfigure(efx);

and a new configuration with:

efx->nic_op->reconfigure_port(efx);

(plus locking and error-checking).

We have not held the link settings in software (aside from flow
control), and have relied on asking the hardware what they are.  This
is a problem because in some cases the hardware may no longer be in a
state to tell us.  In particular, if an entire multi-port board is
reset through one port, the driver bindings to other ports have no
chance to save settings before recovering.

We only actually need to keep track of the autonegotiation settings,
so add an ethtool advertising mask to struct efx_nic, initialise it
in PHY init and update it as necessary.

Remove now-unneeded uses of efx_phy_op::{get,set}_settings() and
struct ethtool_cmd.

Much of this was done by Steve Hodgson <shodgson@solarflare.com>.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
15 files changed:
drivers/net/sfc/efx.c
drivers/net/sfc/efx.h
drivers/net/sfc/ethtool.c
drivers/net/sfc/falcon.c
drivers/net/sfc/falcon.h
drivers/net/sfc/falcon_boards.c
drivers/net/sfc/falcon_gmac.c
drivers/net/sfc/falcon_xmac.c
drivers/net/sfc/mac.h
drivers/net/sfc/mdio_10g.c
drivers/net/sfc/mdio_10g.h
drivers/net/sfc/net_driver.h
drivers/net/sfc/qt202x_phy.c
drivers/net/sfc/selftest.c
drivers/net/sfc/tenxpress.c

index 73ab246d9f2a3cf877c1c1916c2d0a2d63c6e71e..4210121eeff9b018c5c1d5c94ec445776e2a521b 100644 (file)
@@ -620,16 +620,49 @@ void efx_link_status_changed(struct efx_nic *efx)
 
 }
 
+void efx_link_set_advertising(struct efx_nic *efx, u32 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;
+       }
+}
+
+void efx_link_set_wanted_fc(struct efx_nic *efx, enum efx_fc_type wanted_fc)
+{
+       efx->wanted_fc = wanted_fc;
+       if (efx->link_advertising) {
+               if (wanted_fc & EFX_FC_RX)
+                       efx->link_advertising |= (ADVERTISED_Pause |
+                                                 ADVERTISED_Asym_Pause);
+               else
+                       efx->link_advertising &= ~(ADVERTISED_Pause |
+                                                  ADVERTISED_Asym_Pause);
+               if (wanted_fc & EFX_FC_TX)
+                       efx->link_advertising ^= ADVERTISED_Asym_Pause;
+       }
+}
+
 static void efx_fini_port(struct efx_nic *efx);
 
-/* This call reinitialises the MAC to pick up new PHY settings. The
- * caller must hold the mac_lock */
-void __efx_reconfigure_port(struct efx_nic *efx)
+/* Push loopback/power/transmit disable settings to the PHY, and reconfigure
+ * the MAC appropriately. All other PHY configuration changes are pushed
+ * through phy_op->set_settings(), and pushed asynchronously to the MAC
+ * through efx_monitor().
+ *
+ * Callers must hold the mac_lock
+ */
+int __efx_reconfigure_port(struct efx_nic *efx)
 {
-       WARN_ON(!mutex_is_locked(&efx->mac_lock));
+       enum efx_phy_mode phy_mode;
+       int rc;
 
-       EFX_LOG(efx, "reconfiguring MAC from PHY settings on CPU %d\n",
-               raw_smp_processor_id());
+       WARN_ON(!mutex_is_locked(&efx->mac_lock));
 
        /* Serialise the promiscuous flag with efx_set_multicast_list. */
        if (efx_dev_registered(efx)) {
@@ -637,42 +670,34 @@ void __efx_reconfigure_port(struct efx_nic *efx)
                netif_addr_unlock_bh(efx->net_dev);
        }
 
-       efx->type->stop_stats(efx);
-       falcon_deconfigure_mac_wrapper(efx);
-
-       /* Reconfigure the PHY, disabling transmit in mac level loopback. */
+       /* Disable PHY transmit in mac level loopbacks */
+       phy_mode = efx->phy_mode;
        if (LOOPBACK_INTERNAL(efx))
                efx->phy_mode |= PHY_MODE_TX_DISABLED;
        else
                efx->phy_mode &= ~PHY_MODE_TX_DISABLED;
-       efx->phy_op->reconfigure(efx);
-
-       if (falcon_switch_mac(efx))
-               goto fail;
 
-       efx->mac_op->reconfigure(efx);
+       rc = efx->type->reconfigure_port(efx);
 
-       efx->type->start_stats(efx);
-
-       /* Inform kernel of loss/gain of carrier */
-       efx_link_status_changed(efx);
-       return;
+       if (rc)
+               efx->phy_mode = phy_mode;
 
-fail:
-       EFX_ERR(efx, "failed to reconfigure MAC\n");
-       efx->port_enabled = false;
-       efx_fini_port(efx);
+       return rc;
 }
 
 /* Reinitialise the MAC to pick up new PHY settings, even if the port is
  * disabled. */
-void efx_reconfigure_port(struct efx_nic *efx)
+int efx_reconfigure_port(struct efx_nic *efx)
 {
+       int rc;
+
        EFX_ASSERT_RESET_SERIALISED(efx);
 
        mutex_lock(&efx->mac_lock);
-       __efx_reconfigure_port(efx);
+       rc = __efx_reconfigure_port(efx);
        mutex_unlock(&efx->mac_lock);
+
+       return rc;
 }
 
 /* Asynchronous work item for changing MAC promiscuity and multicast
@@ -737,14 +762,18 @@ static int efx_init_port(struct efx_nic *efx)
        rc = efx->phy_op->init(efx);
        if (rc)
                goto fail1;
-       efx->phy_op->reconfigure(efx);
-       rc = falcon_switch_mac(efx);
-       if (rc)
-               goto fail2;
-       efx->mac_op->reconfigure(efx);
 
        efx->port_initialized = true;
 
+       /* Reconfigure the MAC before creating dma queues (required for
+        * Falcon/A1 where RX_INGR_EN/TX_DRAIN_EN isn't supported) */
+       efx->mac_op->reconfigure(efx);
+
+       /* Ensure the PHY advertises the correct flow control settings */
+       rc = efx->phy_op->reconfigure(efx);
+       if (rc)
+               goto fail2;
+
        mutex_unlock(&efx->mac_lock);
        return 0;
 
@@ -1209,12 +1238,6 @@ static void efx_stop_all(struct efx_nic *efx)
        /* Flush efx_mac_work(), refill_workqueue, monitor_work */
        efx_flush_all(efx);
 
-       /* Isolate the MAC from the TX and RX engines, so that queue
-        * flushes will complete in a timely fashion. */
-       falcon_deconfigure_mac_wrapper(efx);
-       msleep(10); /* Let the Rx FIFO drain */
-       falcon_drain_tx_fifo(efx);
-
        /* Stop the kernel transmit interface late, so the watchdog
         * timer isn't ticking over the flush */
        if (efx_dev_registered(efx)) {
@@ -1491,7 +1514,14 @@ static int efx_change_mtu(struct net_device *net_dev, int new_mtu)
        EFX_LOG(efx, "changing MTU to %d\n", new_mtu);
 
        efx_fini_channels(efx);
+
+       mutex_lock(&efx->mac_lock);
+       /* Reconfigure the MAC before enabling the dma queues so that
+        * the RX buffers don't overflow */
        net_dev->mtu = new_mtu;
+       efx->mac_op->reconfigure(efx);
+       mutex_unlock(&efx->mac_lock);
+
        efx_init_channels(efx);
 
        efx_start_all(efx);
@@ -1515,7 +1545,9 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data)
        memcpy(net_dev->dev_addr, new_addr, net_dev->addr_len);
 
        /* Reconfigure the MAC */
-       efx_reconfigure_port(efx);
+       mutex_lock(&efx->mac_lock);
+       efx->mac_op->reconfigure(efx);
+       mutex_unlock(&efx->mac_lock);
 
        return 0;
 }
@@ -1682,8 +1714,7 @@ static void efx_unregister_netdev(struct efx_nic *efx)
 
 /* Tears down the entire software state and most of the hardware state
  * before reset.  */
-void efx_reset_down(struct efx_nic *efx, enum reset_type method,
-                   struct ethtool_cmd *ecmd)
+void efx_reset_down(struct efx_nic *efx, enum reset_type method)
 {
        EFX_ASSERT_RESET_SERIALISED(efx);
 
@@ -1691,8 +1722,6 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method,
        mutex_lock(&efx->mac_lock);
        mutex_lock(&efx->spi_lock);
 
-       efx->phy_op->get_settings(efx, ecmd);
-
        efx_fini_channels(efx);
        if (efx->port_initialized && method != RESET_TYPE_INVISIBLE)
                efx->phy_op->fini(efx);
@@ -1704,8 +1733,7 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method,
  * that we were unable to reinitialise the hardware, and the
  * driver should be disabled. If ok is false, then the rx and tx
  * engines are not restarted, pending a RESET_DISABLE. */
-int efx_reset_up(struct efx_nic *efx, enum reset_type method,
-                struct ethtool_cmd *ecmd, bool ok)
+int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok)
 {
        int rc;
 
@@ -1722,16 +1750,17 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method,
                        rc = efx->phy_op->init(efx);
                        if (rc)
                                ok = false;
+                       if (efx->phy_op->reconfigure(efx))
+                               EFX_ERR(efx, "could not restore PHY settings\n");
                }
                if (!ok)
                        efx->port_initialized = false;
        }
 
        if (ok) {
-               efx_init_channels(efx);
+               efx->mac_op->reconfigure(efx);
 
-               if (efx->phy_op->set_settings(efx, ecmd))
-                       EFX_ERR(efx, "could not restore PHY settings\n");
+               efx_init_channels(efx);
        }
 
        mutex_unlock(&efx->spi_lock);
@@ -1753,7 +1782,6 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method,
  */
 static int efx_reset(struct efx_nic *efx)
 {
-       struct ethtool_cmd ecmd;
        enum reset_type method = efx->reset_pending;
        int rc = 0;
 
@@ -1769,7 +1797,7 @@ static int efx_reset(struct efx_nic *efx)
 
        EFX_INFO(efx, "resetting (%s)\n", RESET_TYPE(method));
 
-       efx_reset_down(efx, method, &ecmd);
+       efx_reset_down(efx, method);
 
        rc = efx->type->reset(efx, method);
        if (rc) {
@@ -1788,10 +1816,10 @@ static int efx_reset(struct efx_nic *efx)
 
        /* Leave device stopped if necessary */
        if (method == RESET_TYPE_DISABLE) {
-               efx_reset_up(efx, method, &ecmd, false);
+               efx_reset_up(efx, method, false);
                rc = -EIO;
        } else {
-               rc = efx_reset_up(efx, method, &ecmd, true);
+               rc = efx_reset_up(efx, method, true);
        }
 
 out_disable:
@@ -1895,7 +1923,7 @@ bool efx_port_dummy_op_poll(struct efx_nic *efx)
 
 static struct efx_phy_operations efx_dummy_phy_operations = {
        .init            = efx_port_dummy_op_int,
-       .reconfigure     = efx_port_dummy_op_void,
+       .reconfigure     = efx_port_dummy_op_int,
        .poll            = efx_port_dummy_op_poll,
        .fini            = efx_port_dummy_op_void,
 };
index 15edda2a22422c04692fd3efaac0ea06624bbc01..c78500321586b32f928351ecde99d2a6118257ea 100644 (file)
@@ -60,8 +60,8 @@ extern void efx_process_channel_now(struct efx_channel *channel);
 #define EFX_EVQ_MASK (EFX_EVQ_SIZE - 1)
 
 /* Ports */
-extern void efx_reconfigure_port(struct efx_nic *efx);
-extern void __efx_reconfigure_port(struct efx_nic *efx);
+extern int efx_reconfigure_port(struct efx_nic *efx);
+extern int __efx_reconfigure_port(struct efx_nic *efx);
 
 /* Ethtool support */
 extern int efx_ethtool_get_settings(struct net_device *net_dev,
@@ -71,10 +71,8 @@ extern int efx_ethtool_set_settings(struct net_device *net_dev,
 extern const struct ethtool_ops efx_ethtool_ops;
 
 /* Reset handling */
-extern void efx_reset_down(struct efx_nic *efx, enum reset_type method,
-                          struct ethtool_cmd *ecmd);
-extern int efx_reset_up(struct efx_nic *efx, enum reset_type method,
-                       struct ethtool_cmd *ecmd, bool ok);
+extern void efx_reset_down(struct efx_nic *efx, enum reset_type method);
+extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok);
 
 /* Global */
 extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type);
@@ -115,5 +113,7 @@ static inline void efx_schedule_channel(struct efx_channel *channel)
 }
 
 extern void efx_link_status_changed(struct efx_nic *efx);
+extern void efx_link_set_advertising(struct efx_nic *efx, u32);
+extern void efx_link_set_wanted_fc(struct efx_nic *efx, enum efx_fc_type);
 
 #endif /* EFX_EFX_H */
index 49e0aed920d362532bc44b293e9c5bf2167c64af..d95d0fa399ff816dd03d3931fa2f51eec9d3f083 100644 (file)
@@ -10,7 +10,6 @@
 
 #include <linux/netdevice.h>
 #include <linux/ethtool.h>
-#include <linux/mdio.h>
 #include <linux/rtnetlink.h>
 #include "net_driver.h"
 #include "workarounds.h"
@@ -191,6 +190,7 @@ int efx_ethtool_get_settings(struct net_device *net_dev,
                             struct ethtool_cmd *ecmd)
 {
        struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_link_state *link_state = &efx->link_state;
 
        mutex_lock(&efx->mac_lock);
        efx->phy_op->get_settings(efx, ecmd);
@@ -198,6 +198,13 @@ int efx_ethtool_get_settings(struct net_device *net_dev,
 
        /* Falcon GMAC does not support 1000Mbps HD */
        ecmd->supported &= ~SUPPORTED_1000baseT_Half;
+       /* Both MACs support pause frames (bidirectional and respond-only) */
+       ecmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
+
+       if (LOOPBACK_INTERNAL(efx)) {
+               ecmd->speed = link_state->speed;
+               ecmd->duplex = link_state->fd ? DUPLEX_FULL : DUPLEX_HALF;
+       }
 
        return 0;
 }
@@ -219,9 +226,6 @@ int efx_ethtool_set_settings(struct net_device *net_dev,
        mutex_lock(&efx->mac_lock);
        rc = efx->phy_op->set_settings(efx, ecmd);
        mutex_unlock(&efx->mac_lock);
-       if (!rc)
-               efx_reconfigure_port(efx);
-
        return rc;
 }
 
@@ -658,8 +662,12 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
                                      struct ethtool_pauseparam *pause)
 {
        struct efx_nic *efx = netdev_priv(net_dev);
-       enum efx_fc_type wanted_fc;
+       enum efx_fc_type wanted_fc, old_fc;
+       u32 old_adv;
        bool reset;
+       int rc = 0;
+
+       mutex_lock(&efx->mac_lock);
 
        wanted_fc = ((pause->rx_pause ? EFX_FC_RX : 0) |
                     (pause->tx_pause ? EFX_FC_TX : 0) |
@@ -667,14 +675,14 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
 
        if ((wanted_fc & EFX_FC_TX) && !(wanted_fc & EFX_FC_RX)) {
                EFX_LOG(efx, "Flow control unsupported: tx ON rx OFF\n");
-               return -EINVAL;
+               rc = -EINVAL;
+               goto out;
        }
 
-       if (!(efx->phy_op->mmds & MDIO_DEVS_AN) &&
-           (wanted_fc & EFX_FC_AUTO)) {
-               EFX_LOG(efx, "PHY does not support flow control "
-                       "autonegotiation\n");
-               return -EINVAL;
+       if ((wanted_fc & EFX_FC_AUTO) && !efx->link_advertising) {
+               EFX_LOG(efx, "Autonegotiation is disabled\n");
+               rc = -EINVAL;
+               goto out;
        }
 
        /* TX flow control may automatically turn itself off if the
@@ -686,25 +694,38 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
        if (EFX_WORKAROUND_11482(efx) && reset) {
                if (efx_nic_rev(efx) == EFX_REV_FALCON_B0) {
                        /* Recover by resetting the EM block */
-                       if (efx->link_state.up)
-                               falcon_drain_tx_fifo(efx);
+                       falcon_stop_nic_stats(efx);
+                       falcon_drain_tx_fifo(efx);
+                       efx->mac_op->reconfigure(efx);
+                       falcon_start_nic_stats(efx);
                } else {
                        /* Schedule a reset to recover */
                        efx_schedule_reset(efx, RESET_TYPE_INVISIBLE);
                }
        }
 
-       /* Try to push the pause parameters */
-       mutex_lock(&efx->mac_lock);
+       old_adv = efx->link_advertising;
+       old_fc = efx->wanted_fc;
+       efx_link_set_wanted_fc(efx, wanted_fc);
+       if (efx->link_advertising != old_adv ||
+           (efx->wanted_fc ^ old_fc) & EFX_FC_AUTO) {
+               rc = efx->phy_op->reconfigure(efx);
+               if (rc) {
+                       EFX_ERR(efx, "Unable to advertise requested flow "
+                               "control setting\n");
+                       goto out;
+               }
+       }
 
-       efx->wanted_fc = wanted_fc;
-       if (efx->phy_op->mmds & MDIO_DEVS_AN)
-               mdio45_ethtool_spauseparam_an(&efx->mdio, pause);
-       __efx_reconfigure_port(efx);
+       /* Reconfigure the MAC. The PHY *may* generate a link state change event
+        * if the user just changed the advertised capabilities, but there's no
+        * harm doing this twice */
+       efx->mac_op->reconfigure(efx);
 
+out:
        mutex_unlock(&efx->mac_lock);
 
-       return 0;
+       return rc;
 }
 
 static void efx_ethtool_get_pauseparam(struct net_device *net_dev,
index f6d10213d0b7fcde5053d23e9248ee3751a72267..3466616c01c0b1be1f149318ad4936ceeac506a9 100644 (file)
@@ -1193,6 +1193,8 @@ static void falcon_poll_flush_events(struct efx_nic *efx)
        channel->eventq_read_ptr = read_ptr;
 }
 
+static void falcon_deconfigure_mac_wrapper(struct efx_nic *efx);
+
 static void falcon_prepare_flush(struct efx_nic *efx)
 {
        falcon_deconfigure_mac_wrapper(efx);
@@ -1836,9 +1838,10 @@ static void falcon_push_multicast_hash(struct efx_nic *efx)
        efx_writeo(efx, &mc_hash->oword[1], FR_AB_MAC_MC_HASH_REG1);
 }
 
-static int falcon_reset_macs(struct efx_nic *efx)
+static void falcon_reset_macs(struct efx_nic *efx)
 {
-       efx_oword_t reg;
+       struct falcon_nic_data *nic_data = efx->nic_data;
+       efx_oword_t reg, mac_ctrl;
        int count;
 
        if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) {
@@ -1853,7 +1856,7 @@ static int falcon_reset_macs(struct efx_nic *efx)
                        EFX_POPULATE_OWORD_1(reg, FRF_AB_GM_SW_RST, 0);
                        efx_writeo(efx, &reg, FR_AB_GM_CFG1);
                        udelay(1000);
-                       return 0;
+                       return;
                } else {
                        EFX_POPULATE_OWORD_1(reg, FRF_AB_XM_CORE_RST, 1);
                        efx_writeo(efx, &reg, FR_AB_XM_GLB_CFG);
@@ -1862,22 +1865,20 @@ static int falcon_reset_macs(struct efx_nic *efx)
                                efx_reado(efx, &reg, FR_AB_XM_GLB_CFG);
                                if (EFX_OWORD_FIELD(reg, FRF_AB_XM_CORE_RST) ==
                                    0)
-                                       return 0;
+                                       return;
                                udelay(10);
                        }
 
                        EFX_ERR(efx, "timed out waiting for XMAC core reset\n");
-                       return -ETIMEDOUT;
                }
        }
 
-       /* MAC stats will fail whilst the TX fifo is draining. Serialise
-        * the drain sequence with the statistics fetch */
-       falcon_stop_nic_stats(efx);
+       /* Mac stats will fail whist the TX fifo is draining */
+       WARN_ON(nic_data->stats_disable_count == 0);
 
-       efx_reado(efx, &reg, FR_AB_MAC_CTRL);
-       EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN, 1);
-       efx_writeo(efx, &reg, FR_AB_MAC_CTRL);
+       efx_reado(efx, &mac_ctrl, FR_AB_MAC_CTRL);
+       EFX_SET_OWORD_FIELD(mac_ctrl, FRF_BB_TXFIFO_DRAIN_EN, 1);
+       efx_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL);
 
        efx_reado(efx, &reg, FR_AB_GLB_CTL);
        EFX_SET_OWORD_FIELD(reg, FRF_AB_RST_XGTX, 1);
@@ -1903,14 +1904,9 @@ static int falcon_reset_macs(struct efx_nic *efx)
                udelay(10);
        }
 
-       /* If we've reset the EM block and the link is up, then
-        * we'll have to kick the XAUI link so the PHY can recover */
-       if (efx->link_state.up && EFX_IS10G(efx) && EFX_WORKAROUND_5147(efx))
-               falcon_reset_xaui(efx);
-
-       falcon_start_nic_stats(efx);
-
-       return 0;
+       /* Ensure the correct MAC is selected before statistics
+        * are re-enabled by the caller */
+       efx_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL);
 }
 
 void falcon_drain_tx_fifo(struct efx_nic *efx)
@@ -1929,7 +1925,7 @@ void falcon_drain_tx_fifo(struct efx_nic *efx)
        falcon_reset_macs(efx);
 }
 
-void falcon_deconfigure_mac_wrapper(struct efx_nic *efx)
+static void falcon_deconfigure_mac_wrapper(struct efx_nic *efx)
 {
        efx_oword_t reg;
 
@@ -1941,8 +1937,8 @@ void falcon_deconfigure_mac_wrapper(struct efx_nic *efx)
        EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 0);
        efx_writeo(efx, &reg, FR_AZ_RX_CFG);
 
-       if (!efx->link_state.up)
-               falcon_drain_tx_fifo(efx);
+       /* Isolate TX -> MAC */
+       falcon_drain_tx_fifo(efx);
 }
 
 void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
@@ -2044,6 +2040,8 @@ static void falcon_stats_timer_func(unsigned long context)
        spin_unlock(&efx->stats_lock);
 }
 
+static void falcon_switch_mac(struct efx_nic *efx);
+
 static bool falcon_loopback_link_poll(struct efx_nic *efx)
 {
        struct efx_link_state old_state = efx->link_state;
@@ -2063,6 +2061,38 @@ static bool falcon_loopback_link_poll(struct efx_nic *efx)
        return !efx_link_state_equal(&efx->link_state, &old_state);
 }
 
+static int falcon_reconfigure_port(struct efx_nic *efx)
+{
+       int rc;
+
+       WARN_ON(efx_nic_rev(efx) > EFX_REV_FALCON_B0);
+
+       /* Poll the PHY link state *before* reconfiguring it. This means we
+        * will pick up the correct speed (in loopback) to select the correct
+        * MAC.
+        */
+       if (LOOPBACK_INTERNAL(efx))
+               falcon_loopback_link_poll(efx);
+       else
+               efx->phy_op->poll(efx);
+
+       falcon_stop_nic_stats(efx);
+       falcon_deconfigure_mac_wrapper(efx);
+
+       falcon_switch_mac(efx);
+
+       efx->phy_op->reconfigure(efx);
+       rc = efx->mac_op->reconfigure(efx);
+       BUG_ON(rc);
+
+       falcon_start_nic_stats(efx);
+
+       /* Synchronise efx->link_state with the kernel */
+       efx_link_status_changed(efx);
+
+       return 0;
+}
+
 /**************************************************************************
  *
  * PHY access via GMII
@@ -2215,17 +2245,15 @@ static void falcon_clock_mac(struct efx_nic *efx)
        }
 }
 
-int falcon_switch_mac(struct efx_nic *efx)
+static void falcon_switch_mac(struct efx_nic *efx)
 {
        struct efx_mac_operations *old_mac_op = efx->mac_op;
        struct falcon_nic_data *nic_data = efx->nic_data;
        unsigned int stats_done_offset;
-       int rc = 0;
-
-       /* Don't try to fetch MAC stats while we're switching MACs */
-       falcon_stop_nic_stats(efx);
 
        WARN_ON(!mutex_is_locked(&efx->mac_lock));
+       WARN_ON(nic_data->stats_disable_count == 0);
+
        efx->mac_op = (EFX_IS10G(efx) ?
                       &falcon_xmac_operations : &falcon_gmac_operations);
 
@@ -2236,18 +2264,14 @@ int falcon_switch_mac(struct efx_nic *efx)
        nic_data->stats_dma_done = efx->stats_buffer.addr + stats_done_offset;
 
        if (old_mac_op == efx->mac_op)
-               goto out;
+               return;
 
        falcon_clock_mac(efx);
 
        EFX_LOG(efx, "selected %cMAC\n", EFX_IS10G(efx) ? 'X' : 'G');
        /* Not all macs support a mac-level link state */
        efx->xmac_poll_required = false;
-
-       rc = falcon_reset_macs(efx);
-out:
-       falcon_start_nic_stats(efx);
-       return rc;
+       falcon_reset_macs(efx);
 }
 
 /* This call is responsible for hooking in the MAC and PHY operations */
@@ -2597,7 +2621,8 @@ static void falcon_monitor(struct efx_nic *efx)
                EFX_ERR(efx, "Board sensor %s; shutting down PHY\n",
                        (rc == -ERANGE) ? "reported fault" : "failed");
                efx->phy_mode |= PHY_MODE_LOW_POWER;
-               __efx_reconfigure_port(efx);
+               rc = __efx_reconfigure_port(efx);
+               WARN_ON(rc);
        }
 
        if (LOOPBACK_INTERNAL(efx))
@@ -2610,7 +2635,8 @@ static void falcon_monitor(struct efx_nic *efx)
                falcon_deconfigure_mac_wrapper(efx);
 
                falcon_switch_mac(efx);
-               efx->mac_op->reconfigure(efx);
+               rc = efx->mac_op->reconfigure(efx);
+               BUG_ON(rc);
 
                falcon_start_nic_stats(efx);
 
@@ -3239,6 +3265,7 @@ struct efx_nic_type falcon_a1_nic_type = {
        .stop_stats = falcon_stop_nic_stats,
        .push_irq_moderation = falcon_push_irq_moderation,
        .push_multicast_hash = falcon_push_multicast_hash,
+       .reconfigure_port = falcon_reconfigure_port,
        .default_mac_ops = &falcon_xmac_operations,
 
        .revision = EFX_REV_FALCON_A1,
@@ -3271,6 +3298,7 @@ struct efx_nic_type falcon_b0_nic_type = {
        .stop_stats = falcon_stop_nic_stats,
        .push_irq_moderation = falcon_push_irq_moderation,
        .push_multicast_hash = falcon_push_multicast_hash,
+       .reconfigure_port = falcon_reconfigure_port,
        .default_mac_ops = &falcon_xmac_operations,
 
        .revision = EFX_REV_FALCON_B0,
index 3fe64849c98d5fd8b73ebac0fdea2cbf030b9855..560a3f9895a5319cdf7d5ee2db49a03a03e537b7 100644 (file)
@@ -130,10 +130,7 @@ extern int falcon_process_eventq(struct efx_channel *channel, int rx_quota);
 extern void falcon_eventq_read_ack(struct efx_channel *channel);
 
 /* MAC/PHY */
-extern int falcon_switch_mac(struct efx_nic *efx);
-extern bool falcon_xaui_link_ok(struct efx_nic *efx);
 extern void falcon_drain_tx_fifo(struct efx_nic *efx);
-extern void falcon_deconfigure_mac_wrapper(struct efx_nic *efx);
 extern void falcon_reconfigure_mac_wrapper(struct efx_nic *efx);
 
 /* Interrupts and test events */
index da750959c61a47aa0b965f62f852178dea29a6e8..b92decc9521bc4f5547b39e2aaeaef98836d9d9d 100644 (file)
@@ -352,7 +352,8 @@ static ssize_t set_phy_flash_cfg(struct device *dev,
                        err = sfe4001_poweron(efx);
                else
                        err = sfn4111t_reset(efx);
-               efx_reconfigure_port(efx);
+               if (!err)
+                       err = efx_reconfigure_port(efx);
                if (!(new_mode & PHY_MODE_SPECIAL))
                        falcon_start_nic_stats(efx);
        }
index 66d499cc23f2b016ddff74cea3a5f077e4e631f7..19dd3ac3d1c70aa671beac71290ade2db534d3a3 100644 (file)
@@ -22,7 +22,7 @@
  *
  *************************************************************************/
 
-static void falcon_reconfigure_gmac(struct efx_nic *efx)
+static int falcon_reconfigure_gmac(struct efx_nic *efx)
 {
        struct efx_link_state *link_state = &efx->link_state;
        bool loopback, tx_fc, rx_fc, bytemode;
@@ -123,6 +123,8 @@ static void falcon_reconfigure_gmac(struct efx_nic *efx)
        udelay(10);
 
        falcon_reconfigure_mac_wrapper(efx);
+
+       return 0;
 }
 
 static void falcon_update_stats_gmac(struct efx_nic *efx)
index 60dc0975cfa4f53a6c9f3c1e33cb2d5b48d2169d..898afc1b5ef1efe6c80ae951bd2d93521e889471 100644 (file)
@@ -112,7 +112,7 @@ static void falcon_mask_status_intr(struct efx_nic *efx, bool enable)
 }
 
 /* Get status of XAUI link */
-bool falcon_xaui_link_ok(struct efx_nic *efx)
+static bool falcon_xaui_link_ok(struct efx_nic *efx)
 {
        efx_oword_t reg;
        bool align_done, link_ok = false;
@@ -143,7 +143,7 @@ bool falcon_xaui_link_ok(struct efx_nic *efx)
        return link_ok;
 }
 
-static void falcon_reconfigure_xmac_core(struct efx_nic *efx)
+void falcon_reconfigure_xmac_core(struct efx_nic *efx)
 {
        unsigned int max_frame_len;
        efx_oword_t reg;
@@ -275,7 +275,7 @@ static bool falcon_xmac_check_fault(struct efx_nic *efx)
        return !falcon_check_xaui_link_up(efx, 5);
 }
 
-static void falcon_reconfigure_xmac(struct efx_nic *efx)
+static int falcon_reconfigure_xmac(struct efx_nic *efx)
 {
        falcon_mask_status_intr(efx, false);
 
@@ -286,6 +286,8 @@ static void falcon_reconfigure_xmac(struct efx_nic *efx)
 
        efx->xmac_poll_required = !falcon_check_xaui_link_up(efx, 5);
        falcon_mask_status_intr(efx, true);
+
+       return 0;
 }
 
 static void falcon_update_stats_xmac(struct efx_nic *efx)
index 4e7074278fe1f7b4fde0c619d6b1160502139efd..d2af50f1747bef759c7030ba2c9d6487e9e14f47 100644 (file)
@@ -15,5 +15,6 @@
 
 extern struct efx_mac_operations falcon_gmac_operations;
 extern struct efx_mac_operations falcon_xmac_operations;
+extern void falcon_reconfigure_xmac_core(struct efx_nic *efx);
 
 #endif
index 231e580acc9a398495a7ada269d3a2cf4e94746d..1f62a5c002fd17f2985573ec0a92c4996d140a1b 100644 (file)
@@ -248,8 +248,6 @@ void efx_mdio_set_mmds_lpower(struct efx_nic *efx,
 int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
 {
        struct ethtool_cmd prev;
-       bool xnp;
-       int reg;
 
        efx->phy_op->get_settings(efx, &prev);
 
@@ -269,30 +267,47 @@ int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
            (ecmd->advertising | SUPPORTED_Autoneg) & ~prev.supported)
                return -EINVAL;
 
-       xnp = (ecmd->advertising & ADVERTISED_10000baseT_Full
-              || EFX_WORKAROUND_13204(efx));
+       efx_link_set_advertising(efx, ecmd->advertising | ADVERTISED_Autoneg);
+       efx_mdio_an_reconfigure(efx);
+       return 0;
+}
+
+/**
+ * efx_mdio_an_reconfigure - Push advertising flags and restart autonegotiation
+ * @efx:               Efx NIC
+ */
+void efx_mdio_an_reconfigure(struct efx_nic *efx)
+{
+       bool xnp = (efx->link_advertising & ADVERTISED_10000baseT_Full
+                   || EFX_WORKAROUND_13204(efx));
+       int reg;
+
+       WARN_ON(!(efx->mdio.mmds & MDIO_DEVS_AN));
 
        /* Set up the base page */
        reg = ADVERTISE_CSMA;
-       if (ecmd->advertising & ADVERTISED_10baseT_Half)
+       if (efx->link_advertising & ADVERTISED_10baseT_Half)
                reg |= ADVERTISE_10HALF;
-       if (ecmd->advertising & ADVERTISED_10baseT_Full)
+       if (efx->link_advertising & ADVERTISED_10baseT_Full)
                reg |= ADVERTISE_10FULL;
-       if (ecmd->advertising & ADVERTISED_100baseT_Half)
+       if (efx->link_advertising & ADVERTISED_100baseT_Half)
                reg |= ADVERTISE_100HALF;
-       if (ecmd->advertising & ADVERTISED_100baseT_Full)
+       if (efx->link_advertising & ADVERTISED_100baseT_Full)
                reg |= ADVERTISE_100FULL;
        if (xnp)
                reg |= ADVERTISE_RESV;
-       else if (ecmd->advertising & (ADVERTISED_1000baseT_Half |
-                                     ADVERTISED_1000baseT_Full))
+       else if (efx->link_advertising & (ADVERTISED_1000baseT_Half |
+                                         ADVERTISED_1000baseT_Full))
                reg |= ADVERTISE_NPAGE;
-       reg |= mii_advertise_flowctrl(efx->wanted_fc);
+       if (efx->link_advertising & ADVERTISED_Pause)
+               reg |= ADVERTISE_PAUSE_CAP;
+       if (efx->link_advertising & ADVERTISED_Asym_Pause)
+               reg |= ADVERTISE_PAUSE_ASYM;
        efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg);
 
        /* Set up the (extended) next page if necessary */
        if (efx->phy_op->set_npage_adv)
-               efx->phy_op->set_npage_adv(efx, ecmd->advertising);
+               efx->phy_op->set_npage_adv(efx, efx->link_advertising);
 
        /* Enable and restart AN */
        reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_CTRL1);
@@ -305,8 +320,6 @@ int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
        else
                reg &= ~MDIO_AN_CTRL1_XNP;
        efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg);
-
-       return 0;
 }
 
 enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx)
index 75b37f101231dae982cd4c0810f885b3540ce24a..dbc8e7de2929d9aa24702ff5761c4734f9ba5fcf 100644 (file)
@@ -86,6 +86,9 @@ extern void efx_mdio_set_mmds_lpower(struct efx_nic *efx,
 /* Set (some of) the PHY settings over MDIO */
 extern int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd);
 
+/* Push advertising flags and restart autonegotiation */
+extern void efx_mdio_an_reconfigure(struct efx_nic *efx);
+
 /* Get pause parameters from AN if available (otherwise return
  * requested pause parameters)
  */
index 32806f9a7e49d92b83f5e7ed2a82a0824a04c4b7..f63a05c4e38bd7ac738a0b9382717ede53266379 100644 (file)
@@ -517,7 +517,7 @@ static inline bool efx_link_state_equal(const struct efx_link_state *left,
  * @check_fault: Check fault state. True if fault present.
  */
 struct efx_mac_operations {
-       void (*reconfigure) (struct efx_nic *efx);
+       int (*reconfigure) (struct efx_nic *efx);
        void (*update_stats) (struct efx_nic *efx);
        bool (*check_fault)(struct efx_nic *efx);
 };
@@ -544,7 +544,7 @@ struct efx_phy_operations {
        enum efx_mac_type macs;
        int (*init) (struct efx_nic *efx);
        void (*fini) (struct efx_nic *efx);
-       void (*reconfigure) (struct efx_nic *efx);
+       int (*reconfigure) (struct efx_nic *efx);
        bool (*poll) (struct efx_nic *efx);
        void (*get_settings) (struct efx_nic *efx,
                              struct ethtool_cmd *ecmd);
@@ -730,6 +730,7 @@ union efx_multicast_hash {
  * @mdio: PHY MDIO interface
  * @phy_mode: PHY operating mode. Serialised by @mac_lock.
  * @xmac_poll_required: XMAC link state needs polling
+ * @link_advertising: Autonegotiation advertising flags
  * @link_state: Current state of the link
  * @n_link_state_changes: Number of times the link has changed state
  * @promiscuous: Promiscuous flag. Protected by netif_tx_lock.
@@ -813,6 +814,7 @@ struct efx_nic {
        enum efx_phy_mode phy_mode;
 
        bool xmac_poll_required;
+       u32 link_advertising;
        struct efx_link_state link_state;
        unsigned int n_link_state_changes;
 
@@ -858,6 +860,7 @@ static inline const char *efx_dev_name(struct efx_nic *efx)
  * @stop_stats: Stop the regular fetching of statistics
  * @push_irq_moderation: Apply interrupt moderation value
  * @push_multicast_hash: Apply multicast hash table
+ * @reconfigure_port: Push loopback/power/txdis changes to the MAC and PHY
  * @default_mac_ops: efx_mac_operations to set at startup
  * @revision: Hardware architecture revision
  * @mem_map_size: Memory BAR mapped size
@@ -890,6 +893,7 @@ struct efx_nic_type {
        void (*stop_stats)(struct efx_nic *efx);
        void (*push_irq_moderation)(struct efx_channel *channel);
        void (*push_multicast_hash)(struct efx_nic *efx);
+       int (*reconfigure_port)(struct efx_nic *efx);
        struct efx_mac_operations *default_mac_ops;
 
        int revision;
index 3d7370e39787e5fdac32efb38801c32d3f353fb9..4c38516a552525ca45fd2229bc4659ee2a7ea736 100644 (file)
@@ -178,7 +178,7 @@ static bool qt202x_phy_poll(struct efx_nic *efx)
        return efx->link_state.up != was_up;
 }
 
-static void qt202x_phy_reconfigure(struct efx_nic *efx)
+static int qt202x_phy_reconfigure(struct efx_nic *efx)
 {
        struct qt202x_phy_data *phy_data = efx->phy_data;
 
@@ -207,6 +207,8 @@ static void qt202x_phy_reconfigure(struct efx_nic *efx)
        efx_mdio_phy_reconfigure(efx);
 
        phy_data->phy_mode = efx->phy_mode;
+
+       return 0;
 }
 
 static void qt202x_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
index 15d4d9c813622a9ffb8a19cf32ca1c1cc06d03a9..dddeb9dfb373fe3fcbc39d8c0608acdec7b81376 100644 (file)
@@ -659,7 +659,6 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
        enum efx_loopback_mode loopback_mode = efx->loopback_mode;
        int phy_mode = efx->phy_mode;
        enum reset_type reset_method = RESET_TYPE_INVISIBLE;
-       struct ethtool_cmd ecmd;
        struct efx_channel *channel;
        int rc_test = 0, rc_reset = 0, rc;
 
@@ -712,7 +711,7 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
        mutex_unlock(&efx->mac_lock);
 
        /* free up all consumers of SRAM (including all the queues) */
-       efx_reset_down(efx, reset_method, &ecmd);
+       efx_reset_down(efx, reset_method);
 
        rc = efx_test_chip(efx, tests);
        if (rc && !rc_test)
@@ -726,7 +725,7 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
        efx->phy_mode &= ~PHY_MODE_LOW_POWER;
        efx->loopback_mode = LOOPBACK_NONE;
 
-       rc = efx_reset_up(efx, reset_method, &ecmd, rc_reset == 0);
+       rc = efx_reset_up(efx, reset_method, rc_reset == 0);
        if (rc && !rc_reset)
                rc_reset = rc;
 
@@ -745,10 +744,12 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
                rc_test = rc;
 
        /* restore the PHY to the previous state */
-       efx->loopback_mode = loopback_mode;
+       mutex_lock(&efx->mac_lock);
        efx->phy_mode = phy_mode;
        efx->port_inhibited = false;
-       efx_ethtool_set_settings(efx->net_dev, &ecmd);
+       efx->loopback_mode = loopback_mode;
+       __efx_reconfigure_port(efx);
+       mutex_unlock(&efx->mac_lock);
 
        return rc_test;
 }
index 1bd79650a00f7be5c50028d91aca8b19adf9b343..c30185393cdc36fc4266612356ac58c5e4b6d0c9 100644 (file)
@@ -199,15 +199,16 @@ static ssize_t set_phy_short_reach(struct device *dev,
                                   const char *buf, size_t count)
 {
        struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
+       int rc;
 
        rtnl_lock();
        efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR,
                          MDIO_PMA_10GBT_TXPWR_SHORT,
                          count != 0 && *buf != '0');
-       efx_reconfigure_port(efx);
+       rc = efx_reconfigure_port(efx);
        rtnl_unlock();
 
-       return count;
+       return rc < 0 ? rc : (ssize_t)count;
 }
 
 static DEVICE_ATTR(phy_short_reach, 0644, show_phy_short_reach,
@@ -300,7 +301,6 @@ static int tenxpress_init(struct efx_nic *efx)
 static int tenxpress_phy_init(struct efx_nic *efx)
 {
        struct tenxpress_phy_data *phy_data;
-       u16 old_adv, adv;
        int rc = 0;
 
        falcon_board(efx)->type->init_phy(efx);
@@ -335,14 +335,14 @@ static int tenxpress_phy_init(struct efx_nic *efx)
        if (rc < 0)
                goto fail;
 
-       /* Set pause advertising */
-       old_adv = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
-       adv = ((old_adv & ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM)) |
-              mii_advertise_flowctrl(efx->wanted_fc));
-       if (adv != old_adv) {
-               efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, adv);
-               mdio45_nway_restart(&efx->mdio);
-       }
+       /* Initialise advertising flags */
+       efx->link_advertising = (ADVERTISED_TP | ADVERTISED_Autoneg |
+                                 ADVERTISED_10000baseT_Full);
+       if (efx->phy_type != PHY_TYPE_SFX7101)
+               efx->link_advertising |= (ADVERTISED_1000baseT_Full |
+                                          ADVERTISED_100baseT_Full);
+       efx_link_set_wanted_fc(efx, efx->wanted_fc);
+       efx_mdio_an_reconfigure(efx);
 
        if (efx->phy_type == PHY_TYPE_SFT9001B) {
                rc = device_create_file(&efx->pci_dev->dev,
@@ -500,49 +500,41 @@ static void tenxpress_low_power(struct efx_nic *efx)
                        !!(efx->phy_mode & PHY_MODE_LOW_POWER));
 }
 
-static void tenxpress_phy_reconfigure(struct efx_nic *efx)
+static int tenxpress_phy_reconfigure(struct efx_nic *efx)
 {
        struct tenxpress_phy_data *phy_data = efx->phy_data;
-       struct ethtool_cmd ecmd;
        bool phy_mode_change, loop_reset;
 
        if (efx->phy_mode & (PHY_MODE_OFF | PHY_MODE_SPECIAL)) {
                phy_data->phy_mode = efx->phy_mode;
-               return;
+               return 0;
        }
 
-       tenxpress_low_power(efx);
-
        phy_mode_change = (efx->phy_mode == PHY_MODE_NORMAL &&
                           phy_data->phy_mode != PHY_MODE_NORMAL);
        loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, efx->phy_op->loopbacks) ||
                      LOOPBACK_CHANGED(phy_data, efx, 1 << LOOPBACK_GPHY));
 
        if (loop_reset || phy_mode_change) {
-               int rc;
-
-               efx->phy_op->get_settings(efx, &ecmd);
+               tenxpress_special_reset(efx);
 
-               if (loop_reset || phy_mode_change) {
-                       tenxpress_special_reset(efx);
-
-                       /* Reset XAUI if we were in 10G, and are staying
-                        * in 10G. If we're moving into and out of 10G
-                        * then xaui will be reset anyway */
-                       if (EFX_IS10G(efx))
-                               falcon_reset_xaui(efx);
-               }
-
-               rc = efx->phy_op->set_settings(efx, &ecmd);
-               WARN_ON(rc);
+               /* Reset XAUI if we were in 10G, and are staying
+                * in 10G. If we're moving into and out of 10G
+                * then xaui will be reset anyway */
+               if (EFX_IS10G(efx))
+                       falcon_reset_xaui(efx);
        }
 
+       tenxpress_low_power(efx);
        efx_mdio_transmit_disable(efx);
        efx_mdio_phy_reconfigure(efx);
        tenxpress_ext_loopback(efx);
+       efx_mdio_an_reconfigure(efx);
 
        phy_data->loopback_mode = efx->loopback_mode;
        phy_data->phy_mode = efx->phy_mode;
+
+       return 0;
 }
 
 static void
@@ -646,6 +638,9 @@ sfx7101_run_tests(struct efx_nic *efx, int *results, unsigned flags)
        /* BIST is automatically run after a special software reset */
        rc = tenxpress_special_reset(efx);
        results[0] = rc ? -1 : 1;
+
+       efx_mdio_an_reconfigure(efx);
+
        return rc;
 }
 
@@ -663,12 +658,8 @@ static const char *const sft9001_test_names[] = {
 
 static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags)
 {
-       struct ethtool_cmd ecmd;
        int rc = 0, rc2, i, ctrl_reg, res_reg;
 
-       if (flags & ETH_TEST_FL_OFFLINE)
-               efx->phy_op->get_settings(efx, &ecmd);
-
        /* Initialise cable diagnostic results to unknown failure */
        for (i = 1; i < 9; ++i)
                results[i] = -1;
@@ -720,9 +711,7 @@ out:
                if (!rc)
                        rc = rc2;
 
-               rc2 = efx->phy_op->set_settings(efx, &ecmd);
-               if (!rc)
-                       rc = rc2;
+               efx_mdio_an_reconfigure(efx);
        }
 
        return rc;
@@ -753,7 +742,6 @@ tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
 
        mdio45_ethtool_gset_npage(&efx->mdio, ecmd, adv, lpa);
 
-       ecmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
        if (efx->phy_type != PHY_TYPE_SFX7101) {
                ecmd->supported |= (SUPPORTED_100baseT_Full |
                                    SUPPORTED_1000baseT_Full);