Skip to content

Commit

Permalink
sfc: Add Siena PHY BIST and cable diagnostic support
Browse files Browse the repository at this point in the history
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Steve Hodgson authored and David S. Miller committed Apr 28, 2010
1 parent c28884c commit affaf48
Showing 1 changed file with 144 additions and 2 deletions.
146 changes: 144 additions & 2 deletions drivers/net/sfc/mcdi_phy.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#include "mcdi.h"
#include "mcdi_pcol.h"
#include "mdio_10g.h"
#include "nic.h"
#include "selftest.h"

struct efx_mcdi_phy_cfg {
u32 flags;
Expand Down Expand Up @@ -594,6 +596,146 @@ static int efx_mcdi_phy_test_alive(struct efx_nic *efx)
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 = {
.probe = efx_mcdi_phy_probe,
.init = efx_port_dummy_op_int,
Expand All @@ -604,6 +746,6 @@ struct efx_phy_operations efx_mcdi_phy_ops = {
.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,
.run_tests = efx_mcdi_phy_run_tests,
.test_name = efx_mcdi_phy_test_name,
};

0 comments on commit affaf48

Please sign in to comment.