* the PHY
  */
 #include <linux/delay.h>
+#include "net_driver.h"
 #include "efx.h"
 #include "phy.h"
 #include "boards.h"
        i2c_smbus_read_byte_data(hwmon_client, RSL);
 }
 
-static void sfe4001_fini(struct efx_nic *efx)
+static int sfe4001_poweron(struct efx_nic *efx)
 {
-       EFX_INFO(efx, "%s\n", __func__);
-
-       sfe4001_poweroff(efx);
-       i2c_unregister_device(efx->board_info.ioexp_client);
-       i2c_unregister_device(efx->board_info.hwmon_client);
-}
-
-/* The P0_EN_3V3X line on SFE4001 boards (from A2 onward) is connected
- * to the FLASH_CFG_1 input on the DSP.  We must keep it high at power-
- * up to allow writing the flash (done through MDIO from userland).
- */
-unsigned int sfe4001_phy_flash_cfg;
-module_param_named(phy_flash_cfg, sfe4001_phy_flash_cfg, uint, 0444);
-MODULE_PARM_DESC(phy_flash_cfg,
-                "Force PHY to enter flash configuration mode");
-
-/* This board uses an I2C expander to provider power to the PHY, which needs to
- * be turned on before the PHY can be used.
- * Context: Process context, rtnl lock held
- */
-int sfe4001_init(struct efx_nic *efx)
-{
-       struct i2c_client *hwmon_client, *ioexp_client;
+       struct i2c_client *hwmon_client = efx->board_info.hwmon_client;
+       struct i2c_client *ioexp_client = efx->board_info.ioexp_client;
        unsigned int i, j;
        int rc;
        u8 out;
        efx_dword_t reg;
 
-       hwmon_client = i2c_new_dummy(&efx->i2c_adap, MAX6647);
-       if (!hwmon_client)
-               return -EIO;
-       efx->board_info.hwmon_client = hwmon_client;
-
-       ioexp_client = i2c_new_dummy(&efx->i2c_adap, PCA9539);
-       if (!ioexp_client) {
-               rc = -EIO;
-               goto fail_hwmon;
-       }
-       efx->board_info.ioexp_client = ioexp_client;
-
-       /* 10Xpress has fixed-function LED pins, so there is no board-specific
-        * blink code. */
-       efx->board_info.blink = tenxpress_phy_blink;
-
        /* Ensure that XGXS and XAUI SerDes are held in reset */
        EFX_POPULATE_DWORD_7(reg, XX_PWRDNA_EN, 1,
                             XX_PWRDNB_EN, 1,
        falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC);
        udelay(10);
 
-       efx->board_info.fini = sfe4001_fini;
-
-       /* Set DSP over-temperature alert threshold */
-       EFX_INFO(efx, "DSP cut-out at %dC\n", xgphy_max_temperature);
-       rc = i2c_smbus_write_byte_data(hwmon_client, WLHO,
-                                      xgphy_max_temperature);
-       if (rc)
-               goto fail_ioexp;
-
-       /* Read it back and verify */
-       rc = i2c_smbus_read_byte_data(hwmon_client, RLHN);
-       if (rc < 0)
-               goto fail_ioexp;
-       if (rc != xgphy_max_temperature) {
-               rc = -EFAULT;
-               goto fail_ioexp;
-       }
-
        /* Clear any previous over-temperature alert */
        rc = i2c_smbus_read_byte_data(hwmon_client, RSL);
        if (rc < 0)
-               goto fail_ioexp;
+               return rc;
 
        /* Enable port 0 and port 1 outputs on IO expander */
        rc = i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0x00);
        if (rc)
-               goto fail_ioexp;
+               return rc;
        rc = i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG,
                                       0xff & ~(1 << P1_SPARE_LBN));
        if (rc)
                out = 0xff & ~((1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) |
                               (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) |
                               (1 << P0_X_TRST_LBN));
-               if (sfe4001_phy_flash_cfg)
+               if (efx->phy_mode & PHY_MODE_SPECIAL)
                        out |= 1 << P0_EN_3V3X_LBN;
 
                rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
                /* In flash config mode, DSP does not turn on AFE, so
                 * just wait 1 second.
                 */
-               if (sfe4001_phy_flash_cfg) {
+               if (efx->phy_mode & PHY_MODE_SPECIAL) {
                        schedule_timeout_uninterruptible(HZ);
-                       goto done;
+                       return 0;
                }
 
                for (j = 0; j < 10; ++j) {
                        if (rc < 0)
                                goto fail_on;
                        if (rc & (1 << P1_AFE_PWD_LBN))
-                               goto done;
+                               return 0;
                }
        }
 
        EFX_INFO(efx, "timed out waiting for DSP boot\n");
        rc = -ETIMEDOUT;
-       goto fail_on;
+fail_on:
+       sfe4001_poweroff(efx);
+       return rc;
+}
+
+/* On SFE4001 rev A2 and later, we can control the FLASH_CFG_1 pin
+ * using the 3V3X output of the IO-expander.  Allow the user to set
+ * this when the device is stopped, and keep it stopped then.
+ */
+
+static ssize_t show_phy_flash_cfg(struct device *dev,
+                                 struct device_attribute *attr, char *buf)
+{
+       struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
+       return sprintf(buf, "%d\n", !!(efx->phy_mode & PHY_MODE_SPECIAL));
+}
+
+static ssize_t set_phy_flash_cfg(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t count)
+{
+       struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
+       enum efx_phy_mode old_mode, new_mode;
+       int err;
+
+       rtnl_lock();
+       old_mode = efx->phy_mode;
+       if (count == 0 || *buf == '0')
+               new_mode = old_mode & ~PHY_MODE_SPECIAL;
+       else
+               new_mode = PHY_MODE_SPECIAL;
+       if (old_mode == new_mode) {
+               err = 0;
+       } else if (efx->state != STATE_RUNNING || netif_running(efx->net_dev)) {
+               err = -EBUSY;
+       } else {
+               efx->phy_mode = new_mode;
+               err = sfe4001_poweron(efx);
+               efx_reconfigure_port(efx);
+       }
+       rtnl_unlock();
+
+       return err ? err : count;
+}
+
+static DEVICE_ATTR(phy_flash_cfg, 0644, show_phy_flash_cfg, set_phy_flash_cfg);
+
+static void sfe4001_fini(struct efx_nic *efx)
+{
+       EFX_INFO(efx, "%s\n", __func__);
+
+       device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg);
+       sfe4001_poweroff(efx);
+       i2c_unregister_device(efx->board_info.ioexp_client);
+       i2c_unregister_device(efx->board_info.hwmon_client);
+}
+
+/* This board uses an I2C expander to provider power to the PHY, which needs to
+ * be turned on before the PHY can be used.
+ * Context: Process context, rtnl lock held
+ */
+int sfe4001_init(struct efx_nic *efx)
+{
+       struct i2c_client *hwmon_client;
+       int rc;
+
+       hwmon_client = i2c_new_dummy(&efx->i2c_adap, MAX6647);
+       if (!hwmon_client)
+               return -EIO;
+       efx->board_info.hwmon_client = hwmon_client;
+
+       /* Set DSP over-temperature alert threshold */
+       EFX_INFO(efx, "DSP cut-out at %dC\n", xgphy_max_temperature);
+       rc = i2c_smbus_write_byte_data(hwmon_client, WLHO,
+                                      xgphy_max_temperature);
+       if (rc)
+               goto fail_ioexp;
+
+       /* Read it back and verify */
+       rc = i2c_smbus_read_byte_data(hwmon_client, RLHN);
+       if (rc < 0)
+               goto fail_ioexp;
+       if (rc != xgphy_max_temperature) {
+               rc = -EFAULT;
+               goto fail_ioexp;
+       }
+
+       efx->board_info.ioexp_client = i2c_new_dummy(&efx->i2c_adap, PCA9539);
+       if (!efx->board_info.ioexp_client) {
+               rc = -EIO;
+               goto fail_hwmon;
+       }
+
+       /* 10Xpress has fixed-function LED pins, so there is no board-specific
+        * blink code. */
+       efx->board_info.blink = tenxpress_phy_blink;
+
+       efx->board_info.fini = sfe4001_fini;
+
+       rc = sfe4001_poweron(efx);
+       if (rc)
+               goto fail_ioexp;
+
+       rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg);
+       if (rc)
+               goto fail_on;
 
-done:
        EFX_INFO(efx, "PHY is powered on\n");
        return 0;
 
 fail_on:
        sfe4001_poweroff(efx);
 fail_ioexp:
-       i2c_unregister_device(ioexp_client);
+       i2c_unregister_device(efx->board_info.ioexp_client);
 fail_hwmon:
-       i2c_unregister_device(hwmon_client);
+       i2c_unregister_device(hwmon_client);
        return rc;
 }
 
                 "Max number of CRC errors before XAUI reset");
 
 struct tenxpress_phy_data {
-       enum tenxpress_state state;
        enum efx_loopback_mode loopback_mode;
        atomic_t bad_crc_count;
-       bool tx_disabled;
+       enum efx_phy_mode phy_mode;
        int bad_lp_tries;
 };
 
-static int tenxpress_state_is(struct efx_nic *efx, int state)
-{
-       struct tenxpress_phy_data *phy_data = efx->phy_data;
-       return (phy_data != NULL) && (state == phy_data->state);
-}
-
-void tenxpress_set_state(struct efx_nic *efx,
-                               enum tenxpress_state state)
-{
-       struct tenxpress_phy_data *phy_data = efx->phy_data;
-       if (phy_data != NULL)
-               phy_data->state = state;
-}
-
 void tenxpress_crc_err(struct efx_nic *efx)
 {
        struct tenxpress_phy_data *phy_data = efx->phy_data;
        if (!phy_data)
                return -ENOMEM;
        efx->phy_data = phy_data;
+       phy_data->phy_mode = efx->phy_mode;
 
-       tenxpress_set_state(efx, TENXPRESS_STATUS_NORMAL);
-
-       if (!sfe4001_phy_flash_cfg) {
-               rc = mdio_clause45_wait_reset_mmds(efx,
-                                                  TENXPRESS_REQUIRED_DEVS);
-               if (rc < 0)
-                       goto fail;
-       }
+       rc = mdio_clause45_wait_reset_mmds(efx,
+                                          TENXPRESS_REQUIRED_DEVS);
+       if (rc < 0)
+               goto fail;
 
        rc = mdio_clause45_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0);
        if (rc < 0)
        bool loop_change = LOOPBACK_OUT_OF(phy_data, efx,
                                           TENXPRESS_LOOPBACKS);
 
-       if (!tenxpress_state_is(efx, TENXPRESS_STATUS_NORMAL))
+       if (efx->phy_mode & PHY_MODE_SPECIAL) {
+               phy_data->phy_mode = efx->phy_mode;
                return;
+       }
 
        /* When coming out of transmit disable, coming out of low power
         * mode, or moving out of any PHY internal loopback mode,
         * perform a special software reset */
-       if ((phy_data->tx_disabled && !efx->tx_disabled) ||
+       if ((efx->phy_mode == PHY_MODE_NORMAL &&
+            phy_data->phy_mode != PHY_MODE_NORMAL) ||
            loop_change) {
                tenxpress_special_reset(efx);
                falcon_reset_xaui(efx);
        mdio_clause45_phy_reconfigure(efx);
        tenxpress_phyxs_loopback(efx);
 
-       phy_data->tx_disabled = efx->tx_disabled;
        phy_data->loopback_mode = efx->loopback_mode;
+       phy_data->phy_mode = efx->phy_mode;
        efx->link_up = tenxpress_link_ok(efx, false);
        efx->link_options = GM_LPA_10000FULL;
 }
 static int tenxpress_phy_check_hw(struct efx_nic *efx)
 {
        struct tenxpress_phy_data *phy_data = efx->phy_data;
-       bool phy_up = tenxpress_state_is(efx, TENXPRESS_STATUS_NORMAL);
        bool link_ok;
 
-       link_ok = phy_up && tenxpress_link_ok(efx, true);
+       link_ok = (phy_data->phy_mode == PHY_MODE_NORMAL &&
+                  tenxpress_link_ok(efx, true));
 
        if (link_ok != efx->link_up)
                falcon_xmac_sim_phy_event(efx);
 
-       /* Nothing to check if we've already shut down the PHY */
-       if (!phy_up)
+       if (phy_data->phy_mode != PHY_MODE_NORMAL)
                return 0;
 
        if (atomic_read(&phy_data->bad_crc_count) > crc_error_reset_threshold) {