]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/net/ethernet/sfc/ef10.c
sfc: Add MC BISTs to ethtool offline self test on EF10
[karo-tx-linux.git] / drivers / net / ethernet / sfc / ef10.c
index 676c3c057bfba69e69b6116e212e2d03fdff330c..5d46d155b6423470084e606b8d082ac80db5a9b0 100644 (file)
@@ -14,6 +14,7 @@
 #include "mcdi_pcol.h"
 #include "nic.h"
 #include "workarounds.h"
+#include "selftest.h"
 #include <linux/in.h>
 #include <linux/jhash.h>
 #include <linux/wait.h>
@@ -3195,6 +3196,87 @@ static int efx_ef10_mac_reconfigure(struct efx_nic *efx)
        return efx_mcdi_set_mac(efx);
 }
 
+static int efx_ef10_start_bist(struct efx_nic *efx, u32 bist_type)
+{
+       MCDI_DECLARE_BUF(inbuf, MC_CMD_START_BIST_IN_LEN);
+
+       MCDI_SET_DWORD(inbuf, START_BIST_IN_TYPE, bist_type);
+       return efx_mcdi_rpc(efx, MC_CMD_START_BIST, inbuf, sizeof(inbuf),
+                           NULL, 0, NULL);
+}
+
+/* MC BISTs follow a different poll mechanism to phy BISTs.
+ * The BIST is done in the poll handler on the MC, and the MCDI command
+ * will block until the BIST is done.
+ */
+static int efx_ef10_poll_bist(struct efx_nic *efx)
+{
+       int rc;
+       MCDI_DECLARE_BUF(outbuf, MC_CMD_POLL_BIST_OUT_LEN);
+       size_t outlen;
+       u32 result;
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_POLL_BIST, NULL, 0,
+                          outbuf, sizeof(outbuf), &outlen);
+       if (rc != 0)
+               return rc;
+
+       if (outlen < MC_CMD_POLL_BIST_OUT_LEN)
+               return -EIO;
+
+       result = MCDI_DWORD(outbuf, POLL_BIST_OUT_RESULT);
+       switch (result) {
+       case MC_CMD_POLL_BIST_PASSED:
+               netif_dbg(efx, hw, efx->net_dev, "BIST passed.\n");
+               return 0;
+       case MC_CMD_POLL_BIST_TIMEOUT:
+               netif_err(efx, hw, efx->net_dev, "BIST timed out\n");
+               return -EIO;
+       case MC_CMD_POLL_BIST_FAILED:
+               netif_err(efx, hw, efx->net_dev, "BIST failed.\n");
+               return -EIO;
+       default:
+               netif_err(efx, hw, efx->net_dev,
+                         "BIST returned unknown result %u", result);
+               return -EIO;
+       }
+}
+
+static int efx_ef10_run_bist(struct efx_nic *efx, u32 bist_type)
+{
+       int rc;
+
+       netif_dbg(efx, drv, efx->net_dev, "starting BIST type %u\n", bist_type);
+
+       rc = efx_ef10_start_bist(efx, bist_type);
+       if (rc != 0)
+               return rc;
+
+       return efx_ef10_poll_bist(efx);
+}
+
+static int
+efx_ef10_test_chip(struct efx_nic *efx, struct efx_self_tests *tests)
+{
+       int rc, rc2;
+
+       efx_reset_down(efx, RESET_TYPE_WORLD);
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_ENABLE_OFFLINE_BIST,
+                         NULL, 0, NULL, 0, NULL);
+       if (rc != 0)
+               goto out;
+
+       tests->memory = efx_ef10_run_bist(efx, MC_CMD_MC_MEM_BIST) ? -1 : 1;
+       tests->registers = efx_ef10_run_bist(efx, MC_CMD_REG_BIST) ? -1 : 1;
+
+       rc = efx_mcdi_reset(efx, RESET_TYPE_WORLD);
+
+out:
+       rc2 = efx_reset_up(efx, RESET_TYPE_WORLD, rc == 0);
+       return rc ? rc : rc2;
+}
+
 #ifdef CONFIG_SFC_MTD
 
 struct efx_ef10_nvram_type_info {
@@ -3345,7 +3427,7 @@ const struct efx_nic_type efx_hunt_a0_nic_type = {
        .get_wol = efx_ef10_get_wol,
        .set_wol = efx_ef10_set_wol,
        .resume_wol = efx_port_dummy_op_void,
-       /* TODO: test_chip */
+       .test_chip = efx_ef10_test_chip,
        .test_nvram = efx_mcdi_nvram_test_all,
        .mcdi_request = efx_ef10_mcdi_request,
        .mcdi_poll_response = efx_ef10_mcdi_poll_response,