sfc: Add Siena PHY BIST and cable diagnostic support
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
c28884c574
commit
affaf485ca
|
@ -17,6 +17,8 @@
|
||||||
#include "mcdi.h"
|
#include "mcdi.h"
|
||||||
#include "mcdi_pcol.h"
|
#include "mcdi_pcol.h"
|
||||||
#include "mdio_10g.h"
|
#include "mdio_10g.h"
|
||||||
|
#include "nic.h"
|
||||||
|
#include "selftest.h"
|
||||||
|
|
||||||
struct efx_mcdi_phy_cfg {
|
struct efx_mcdi_phy_cfg {
|
||||||
u32 flags;
|
u32 flags;
|
||||||
|
@ -594,6 +596,146 @@ static int efx_mcdi_phy_test_alive(struct efx_nic *efx)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *const mcdi_sft9001_cable_diag_names[] = {
|
||||||
|
"cable.pairA.length",
|
||||||
|
"cable.pairB.length",
|
||||||
|
"cable.pairC.length",
|
||||||
|
"cable.pairD.length",
|
||||||
|
"cable.pairA.status",
|
||||||
|
"cable.pairB.status",
|
||||||
|
"cable.pairC.status",
|
||||||
|
"cable.pairD.status",
|
||||||
|
};
|
||||||
|
|
||||||
|
static int efx_mcdi_bist(struct efx_nic *efx, unsigned int bist_mode,
|
||||||
|
int *results)
|
||||||
|
{
|
||||||
|
unsigned int retry, i, count = 0;
|
||||||
|
size_t outlen;
|
||||||
|
u32 status;
|
||||||
|
u8 *buf, *ptr;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
buf = kzalloc(0x100, GFP_KERNEL);
|
||||||
|
if (buf == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
BUILD_BUG_ON(MC_CMD_START_BIST_OUT_LEN != 0);
|
||||||
|
MCDI_SET_DWORD(buf, START_BIST_IN_TYPE, bist_mode);
|
||||||
|
rc = efx_mcdi_rpc(efx, MC_CMD_START_BIST, buf, MC_CMD_START_BIST_IN_LEN,
|
||||||
|
NULL, 0, NULL);
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* Wait up to 10s for BIST to finish */
|
||||||
|
for (retry = 0; retry < 100; ++retry) {
|
||||||
|
BUILD_BUG_ON(MC_CMD_POLL_BIST_IN_LEN != 0);
|
||||||
|
rc = efx_mcdi_rpc(efx, MC_CMD_POLL_BIST, NULL, 0,
|
||||||
|
buf, 0x100, &outlen);
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
status = MCDI_DWORD(buf, POLL_BIST_OUT_RESULT);
|
||||||
|
if (status != MC_CMD_POLL_BIST_RUNNING)
|
||||||
|
goto finished;
|
||||||
|
|
||||||
|
msleep(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = -ETIMEDOUT;
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
finished:
|
||||||
|
results[count++] = (status == MC_CMD_POLL_BIST_PASSED) ? 1 : -1;
|
||||||
|
|
||||||
|
/* SFT9001 specific cable diagnostics output */
|
||||||
|
if (efx->phy_type == PHY_TYPE_SFT9001B &&
|
||||||
|
(bist_mode == MC_CMD_PHY_BIST_CABLE_SHORT ||
|
||||||
|
bist_mode == MC_CMD_PHY_BIST_CABLE_LONG)) {
|
||||||
|
ptr = MCDI_PTR(buf, POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A);
|
||||||
|
if (status == MC_CMD_POLL_BIST_PASSED &&
|
||||||
|
outlen >= MC_CMD_POLL_BIST_OUT_SFT9001_LEN) {
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
results[count + i] =
|
||||||
|
EFX_DWORD_FIELD(((efx_dword_t *)ptr)[i],
|
||||||
|
EFX_DWORD_0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count += 8;
|
||||||
|
}
|
||||||
|
rc = count;
|
||||||
|
|
||||||
|
out:
|
||||||
|
kfree(buf);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int efx_mcdi_phy_run_tests(struct efx_nic *efx, int *results,
|
||||||
|
unsigned flags)
|
||||||
|
{
|
||||||
|
struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
|
||||||
|
u32 mode;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_BIST_LBN)) {
|
||||||
|
rc = efx_mcdi_bist(efx, MC_CMD_PHY_BIST, results);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
results += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we support both LONG and SHORT, then run each in response to
|
||||||
|
* break or not. Otherwise, run the one we support */
|
||||||
|
mode = 0;
|
||||||
|
if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_SHORT_LBN)) {
|
||||||
|
if ((flags & ETH_TEST_FL_OFFLINE) &&
|
||||||
|
(phy_cfg->flags &
|
||||||
|
(1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_LONG_LBN)))
|
||||||
|
mode = MC_CMD_PHY_BIST_CABLE_LONG;
|
||||||
|
else
|
||||||
|
mode = MC_CMD_PHY_BIST_CABLE_SHORT;
|
||||||
|
} else if (phy_cfg->flags &
|
||||||
|
(1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_LONG_LBN))
|
||||||
|
mode = MC_CMD_PHY_BIST_CABLE_LONG;
|
||||||
|
|
||||||
|
if (mode != 0) {
|
||||||
|
rc = efx_mcdi_bist(efx, mode, results);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
results += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *efx_mcdi_phy_test_name(struct efx_nic *efx, unsigned int index)
|
||||||
|
{
|
||||||
|
struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
|
||||||
|
|
||||||
|
if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_BIST_LBN)) {
|
||||||
|
if (index == 0)
|
||||||
|
return "bist";
|
||||||
|
--index;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (phy_cfg->flags & ((1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_SHORT_LBN) |
|
||||||
|
(1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_LONG_LBN))) {
|
||||||
|
if (index == 0)
|
||||||
|
return "cable";
|
||||||
|
--index;
|
||||||
|
|
||||||
|
if (efx->phy_type == PHY_TYPE_SFT9001B) {
|
||||||
|
if (index < ARRAY_SIZE(mcdi_sft9001_cable_diag_names))
|
||||||
|
return mcdi_sft9001_cable_diag_names[index];
|
||||||
|
index -= ARRAY_SIZE(mcdi_sft9001_cable_diag_names);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
struct efx_phy_operations efx_mcdi_phy_ops = {
|
struct efx_phy_operations efx_mcdi_phy_ops = {
|
||||||
.probe = efx_mcdi_phy_probe,
|
.probe = efx_mcdi_phy_probe,
|
||||||
.init = efx_port_dummy_op_int,
|
.init = efx_port_dummy_op_int,
|
||||||
|
@ -604,6 +746,6 @@ struct efx_phy_operations efx_mcdi_phy_ops = {
|
||||||
.get_settings = efx_mcdi_phy_get_settings,
|
.get_settings = efx_mcdi_phy_get_settings,
|
||||||
.set_settings = efx_mcdi_phy_set_settings,
|
.set_settings = efx_mcdi_phy_set_settings,
|
||||||
.test_alive = efx_mcdi_phy_test_alive,
|
.test_alive = efx_mcdi_phy_test_alive,
|
||||||
.run_tests = NULL,
|
.run_tests = efx_mcdi_phy_run_tests,
|
||||||
.test_name = NULL,
|
.test_name = efx_mcdi_phy_test_name,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue