sfc: Replace PHY MDIO test with an 'alive' test
authorBen Hutchings <bhutchings@solarflare.com>
Wed, 3 Feb 2010 09:30:50 +0000 (09:30 +0000)
committerDavid S. Miller <davem@davemloft.net>
Thu, 4 Feb 2010 03:12:44 +0000 (19:12 -0800)
SFC9000-family boards do not all use MDIO PHYs, so we need a different
test for PHY aliveness.

Introduce a PHY operation test_alive().  For PHYs attached to Falcon,
use a common implementation based on the existing PHY MDIO test.
For PHYs managed through MCDI, use the appropriate MCDI request.

Change test name in ethtool from 'core mdio' to 'phy alive'.

Rename test_results::mdio to phy_alive and test_results::phy to phy_ext.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/sfc/ethtool.c
drivers/net/sfc/mcdi_phy.c
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/selftest.h
drivers/net/sfc/tenxpress.c

index 6c0bbed8c47721d08ed9ee456ce29a31207a2996..635c4205b4fbf5bb52a5d3e033b0d0158b90f90a 100644 (file)
@@ -342,8 +342,8 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx,
        unsigned int n = 0, i;
        enum efx_loopback_mode mode;
 
-       efx_fill_test(n++, strings, data, &tests->mdio,
-                     "core", 0, "mdio", NULL);
+       efx_fill_test(n++, strings, data, &tests->phy_alive,
+                     "phy", 0, "alive", NULL);
        efx_fill_test(n++, strings, data, &tests->nvram,
                      "core", 0, "nvram", NULL);
        efx_fill_test(n++, strings, data, &tests->interrupt,
@@ -379,7 +379,7 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx,
                        if (name == NULL)
                                break;
 
-                       efx_fill_test(n++, strings, data, &tests->phy[i],
+                       efx_fill_test(n++, strings, data, &tests->phy_ext[i],
                                      "phy", 0, name, NULL);
                }
        }
index d87e74d3994e61e39d5fb41bf56d5d7189db47c6..34c22fa986e2b3147a08a27666a7f0dd4a545b6b 100644 (file)
@@ -572,6 +572,27 @@ static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ec
        return 0;
 }
 
+static int efx_mcdi_phy_test_alive(struct efx_nic *efx)
+{
+       u8 outbuf[MC_CMD_GET_PHY_STATE_OUT_LEN];
+       size_t outlen;
+       int rc;
+
+       BUILD_BUG_ON(MC_CMD_GET_PHY_STATE_IN_LEN != 0);
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_GET_PHY_STATE, NULL, 0,
+                         outbuf, sizeof(outbuf), &outlen);
+       if (rc)
+               return rc;
+
+       if (outlen < MC_CMD_GET_PHY_STATE_OUT_LEN)
+               return -EMSGSIZE;
+       if (MCDI_DWORD(outbuf, GET_PHY_STATE_STATE) != MC_CMD_PHY_STATE_OK)
+               return -EINVAL;
+
+       return 0;
+}
+
 struct efx_phy_operations efx_mcdi_phy_ops = {
        .probe          = efx_mcdi_phy_probe,
        .init           = efx_port_dummy_op_int,
@@ -581,6 +602,7 @@ struct efx_phy_operations efx_mcdi_phy_ops = {
        .remove         = efx_mcdi_phy_remove,
        .get_settings   = efx_mcdi_phy_get_settings,
        .set_settings   = efx_mcdi_phy_set_settings,
+       .test_alive     = efx_mcdi_phy_test_alive,
        .run_tests      = NULL,
        .test_name      = NULL,
 };
index 1574e52f05940f2e4ce7cc63c1a15c67b069223e..0548fcbbdcd0982ec1b8d2ca9b278d935951d7bc 100644 (file)
@@ -335,3 +335,27 @@ enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx)
                mii_advertise_flowctrl(efx->wanted_fc),
                efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_LPA));
 }
+
+int efx_mdio_test_alive(struct efx_nic *efx)
+{
+       int rc;
+       int devad = __ffs(efx->mdio.mmds);
+       u16 physid1, physid2;
+
+       mutex_lock(&efx->mac_lock);
+
+       physid1 = efx_mdio_read(efx, devad, MDIO_DEVID1);
+       physid2 = efx_mdio_read(efx, devad, MDIO_DEVID2);
+
+       if ((physid1 == 0x0000) || (physid1 == 0xffff) ||
+           (physid2 == 0x0000) || (physid2 == 0xffff)) {
+               EFX_ERR(efx, "no MDIO PHY present with ID %d\n",
+                       efx->mdio.prtad);
+               rc = -EINVAL;
+       } else {
+               rc = efx_mdio_check_mmds(efx, efx->mdio.mmds, 0);
+       }
+
+       mutex_unlock(&efx->mac_lock);
+       return rc;
+}
index f6ac9503339dc365cd28659fa873c074d8deb0d0..f89e719296031194a6953eba58daebe66b08164b 100644 (file)
@@ -106,4 +106,7 @@ efx_mdio_set_flag(struct efx_nic *efx, int devad, int addr,
        mdio_set_flag(&efx->mdio, efx->mdio.prtad, devad, addr, mask, state);
 }
 
+/* Liveness self-test for MDIO PHYs */
+extern int efx_mdio_test_alive(struct efx_nic *efx);
+
 #endif /* EFX_MDIO_10G_H */
index d5aab5b3fa066e27666c44b01dd35c241a0b86f7..8f951e4f15be9a3aff56885982493487cf71592e 100644 (file)
@@ -516,8 +516,9 @@ struct efx_mac_operations {
  * @set_settings: Set ethtool settings. Serialised by the mac_lock.
  * @set_npage_adv: Set abilities advertised in (Extended) Next Page
  *     (only needed where AN bit is set in mmds)
+ * @test_alive: Test that PHY is 'alive' (online)
  * @test_name: Get the name of a PHY-specific test/result
- * @run_tests: Run tests and record results as appropriate.
+ * @run_tests: Run tests and record results as appropriate (offline).
  *     Flags are the ethtool tests flags.
  */
 struct efx_phy_operations {
@@ -532,6 +533,7 @@ struct efx_phy_operations {
        int (*set_settings) (struct efx_nic *efx,
                             struct ethtool_cmd *ecmd);
        void (*set_npage_adv) (struct efx_nic *efx, u32);
+       int (*test_alive) (struct efx_nic *efx);
        const char *(*test_name) (struct efx_nic *efx, unsigned int index);
        int (*run_tests) (struct efx_nic *efx, int *results, unsigned flags);
 };
index e0d13a451019753112ebc72e23cf9def99486896..14793d8bd6615008d446cafa835f5c6def35e8d2 100644 (file)
@@ -445,4 +445,5 @@ struct efx_phy_operations falcon_qt202x_phy_ops = {
        .remove          = qt202x_phy_remove,
        .get_settings    = qt202x_phy_get_settings,
        .set_settings    = efx_mdio_set_settings,
+       .test_alive      = efx_mdio_test_alive,
 };
index 250c8827b842e57d169dad1a73f8dcf387527c52..8a5a7b6d042d7d557b80294138d3202c82c103b5 100644 (file)
@@ -26,7 +26,6 @@
 #include "workarounds.h"
 #include "spi.h"
 #include "io.h"
-#include "mdio_10g.h"
 
 /*
  * Loopback test packet structure
@@ -76,42 +75,15 @@ struct efx_loopback_state {
  *
  **************************************************************************/
 
-static int efx_test_mdio(struct efx_nic *efx, struct efx_self_tests *tests)
+static int efx_test_phy_alive(struct efx_nic *efx, struct efx_self_tests *tests)
 {
        int rc = 0;
-       int devad;
-       u16 physid1, physid2;
-
-       if (efx->mdio.mode_support & MDIO_SUPPORTS_C45)
-               devad = __ffs(efx->mdio.mmds);
-       else if (efx->mdio.mode_support & MDIO_SUPPORTS_C22)
-               devad = MDIO_DEVAD_NONE;
-       else
-               return 0;
-
-       mutex_lock(&efx->mac_lock);
-       tests->mdio = -1;
-
-       physid1 = efx_mdio_read(efx, devad, MDIO_DEVID1);
-       physid2 = efx_mdio_read(efx, devad, MDIO_DEVID2);
 
-       if ((physid1 == 0x0000) || (physid1 == 0xffff) ||
-           (physid2 == 0x0000) || (physid2 == 0xffff)) {
-               EFX_ERR(efx, "no MDIO PHY present with ID %d\n",
-                       efx->mdio.prtad);
-               rc = -EINVAL;
-               goto out;
+       if (efx->phy_op->test_alive) {
+               rc = efx->phy_op->test_alive(efx);
+               tests->phy_alive = rc ? -1 : 1;
        }
 
-       if (EFX_IS10G(efx)) {
-               rc = efx_mdio_check_mmds(efx, efx->mdio.mmds, 0);
-               if (rc)
-                       goto out;
-       }
-
-out:
-       mutex_unlock(&efx->mac_lock);
-       tests->mdio = rc ? -1 : 1;
        return rc;
 }
 
@@ -258,7 +230,7 @@ static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests,
                return 0;
 
        mutex_lock(&efx->mac_lock);
-       rc = efx->phy_op->run_tests(efx, tests->phy, flags);
+       rc = efx->phy_op->run_tests(efx, tests->phy_ext, flags);
        mutex_unlock(&efx->mac_lock);
        return rc;
 }
@@ -684,7 +656,7 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
        /* Online (i.e. non-disruptive) testing
         * This checks interrupt generation, event delivery and PHY presence. */
 
-       rc = efx_test_mdio(efx, tests);
+       rc = efx_test_phy_alive(efx, tests);
        if (rc && !rc_test)
                rc_test = rc;
 
index f6feee04c96ba925ea187284cd6fffab812872ed..643bef72b99d0515647d7a783d056dfb79e88a03 100644 (file)
@@ -32,7 +32,7 @@ struct efx_loopback_self_tests {
  */
 struct efx_self_tests {
        /* online tests */
-       int mdio;
+       int phy_alive;
        int nvram;
        int interrupt;
        int eventq_dma[EFX_MAX_CHANNELS];
@@ -40,7 +40,7 @@ struct efx_self_tests {
        int eventq_poll[EFX_MAX_CHANNELS];
        /* offline tests */
        int registers;
-       int phy[EFX_MAX_PHY_TESTS];
+       int phy_ext[EFX_MAX_PHY_TESTS];
        struct efx_loopback_self_tests loopback[LOOPBACK_TEST_MAX + 1];
 };
 
index 3009c297c135a647e945b26fc3acfe38fc24237b..10db071bd8378c29822b4f360f7f729b16f3ccc1 100644 (file)
@@ -842,6 +842,7 @@ struct efx_phy_operations falcon_sfx7101_phy_ops = {
        .get_settings     = tenxpress_get_settings,
        .set_settings     = tenxpress_set_settings,
        .set_npage_adv    = sfx7101_set_npage_adv,
+       .test_alive       = efx_mdio_test_alive,
        .test_name        = sfx7101_test_name,
        .run_tests        = sfx7101_run_tests,
 };
@@ -856,6 +857,7 @@ struct efx_phy_operations falcon_sft9001_phy_ops = {
        .get_settings     = tenxpress_get_settings,
        .set_settings     = tenxpress_set_settings,
        .set_npage_adv    = sft9001_set_npage_adv,
+       .test_alive       = efx_mdio_test_alive,
        .test_name        = sft9001_test_name,
        .run_tests        = sft9001_run_tests,
 };