aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sfc
diff options
context:
space:
mode:
authorSteve Hodgson <shodgson@solarflare.com>2010-04-28 05:30:22 -0400
committerDavid S. Miller <davem@davemloft.net>2010-04-28 15:44:42 -0400
commitaffaf485ca628cb7d7f57ae5e2b8c710c58b11aa (patch)
treed97dcebeaa665059faa67b01d3800c05666fc5a4 /drivers/net/sfc
parentc28884c57400de326ba4c1ff9608f1d425bdd0fd (diff)
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>
Diffstat (limited to 'drivers/net/sfc')
-rw-r--r--drivers/net/sfc/mcdi_phy.c146
1 files changed, 144 insertions, 2 deletions
diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c
index 5d344874f29..6032c0e1f1f 100644
--- a/drivers/net/sfc/mcdi_phy.c
+++ b/drivers/net/sfc/mcdi_phy.c
@@ -17,6 +17,8 @@
17#include "mcdi.h" 17#include "mcdi.h"
18#include "mcdi_pcol.h" 18#include "mcdi_pcol.h"
19#include "mdio_10g.h" 19#include "mdio_10g.h"
20#include "nic.h"
21#include "selftest.h"
20 22
21struct efx_mcdi_phy_cfg { 23struct efx_mcdi_phy_cfg {
22 u32 flags; 24 u32 flags;
@@ -594,6 +596,146 @@ static int efx_mcdi_phy_test_alive(struct efx_nic *efx)
594 return 0; 596 return 0;
595} 597}
596 598
599static const char *const mcdi_sft9001_cable_diag_names[] = {
600 "cable.pairA.length",
601 "cable.pairB.length",
602 "cable.pairC.length",
603 "cable.pairD.length",
604 "cable.pairA.status",
605 "cable.pairB.status",
606 "cable.pairC.status",
607 "cable.pairD.status",
608};
609
610static int efx_mcdi_bist(struct efx_nic *efx, unsigned int bist_mode,
611 int *results)
612{
613 unsigned int retry, i, count = 0;
614 size_t outlen;
615 u32 status;
616 u8 *buf, *ptr;
617 int rc;
618
619 buf = kzalloc(0x100, GFP_KERNEL);
620 if (buf == NULL)
621 return -ENOMEM;
622
623 BUILD_BUG_ON(MC_CMD_START_BIST_OUT_LEN != 0);
624 MCDI_SET_DWORD(buf, START_BIST_IN_TYPE, bist_mode);
625 rc = efx_mcdi_rpc(efx, MC_CMD_START_BIST, buf, MC_CMD_START_BIST_IN_LEN,
626 NULL, 0, NULL);
627 if (rc)
628 goto out;
629
630 /* Wait up to 10s for BIST to finish */
631 for (retry = 0; retry < 100; ++retry) {
632 BUILD_BUG_ON(MC_CMD_POLL_BIST_IN_LEN != 0);
633 rc = efx_mcdi_rpc(efx, MC_CMD_POLL_BIST, NULL, 0,
634 buf, 0x100, &outlen);
635 if (rc)
636 goto out;
637
638 status = MCDI_DWORD(buf, POLL_BIST_OUT_RESULT);
639 if (status != MC_CMD_POLL_BIST_RUNNING)
640 goto finished;
641
642 msleep(100);
643 }
644
645 rc = -ETIMEDOUT;
646 goto out;
647
648finished:
649 results[count++] = (status == MC_CMD_POLL_BIST_PASSED) ? 1 : -1;
650
651 /* SFT9001 specific cable diagnostics output */
652 if (efx->phy_type == PHY_TYPE_SFT9001B &&
653 (bist_mode == MC_CMD_PHY_BIST_CABLE_SHORT ||
654 bist_mode == MC_CMD_PHY_BIST_CABLE_LONG)) {
655 ptr = MCDI_PTR(buf, POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A);
656 if (status == MC_CMD_POLL_BIST_PASSED &&
657 outlen >= MC_CMD_POLL_BIST_OUT_SFT9001_LEN) {
658 for (i = 0; i < 8; i++) {
659 results[count + i] =
660 EFX_DWORD_FIELD(((efx_dword_t *)ptr)[i],
661 EFX_DWORD_0);
662 }
663 }
664 count += 8;
665 }
666 rc = count;
667
668out:
669 kfree(buf);
670
671 return rc;
672}
673
674static int efx_mcdi_phy_run_tests(struct efx_nic *efx, int *results,
675 unsigned flags)
676{
677 struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
678 u32 mode;
679 int rc;
680
681 if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_BIST_LBN)) {
682 rc = efx_mcdi_bist(efx, MC_CMD_PHY_BIST, results);
683 if (rc < 0)
684 return rc;
685
686 results += rc;
687 }
688
689 /* If we support both LONG and SHORT, then run each in response to
690 * break or not. Otherwise, run the one we support */
691 mode = 0;
692 if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_SHORT_LBN)) {
693 if ((flags & ETH_TEST_FL_OFFLINE) &&
694 (phy_cfg->flags &
695 (1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_LONG_LBN)))
696 mode = MC_CMD_PHY_BIST_CABLE_LONG;
697 else
698 mode = MC_CMD_PHY_BIST_CABLE_SHORT;
699 } else if (phy_cfg->flags &
700 (1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_LONG_LBN))
701 mode = MC_CMD_PHY_BIST_CABLE_LONG;
702
703 if (mode != 0) {
704 rc = efx_mcdi_bist(efx, mode, results);
705 if (rc < 0)
706 return rc;
707 results += rc;
708 }
709
710 return 0;
711}
712
713const char *efx_mcdi_phy_test_name(struct efx_nic *efx, unsigned int index)
714{
715 struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
716
717 if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_BIST_LBN)) {
718 if (index == 0)
719 return "bist";
720 --index;
721 }
722
723 if (phy_cfg->flags & ((1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_SHORT_LBN) |
724 (1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_LONG_LBN))) {
725 if (index == 0)
726 return "cable";
727 --index;
728
729 if (efx->phy_type == PHY_TYPE_SFT9001B) {
730 if (index < ARRAY_SIZE(mcdi_sft9001_cable_diag_names))
731 return mcdi_sft9001_cable_diag_names[index];
732 index -= ARRAY_SIZE(mcdi_sft9001_cable_diag_names);
733 }
734 }
735
736 return NULL;
737}
738
597struct efx_phy_operations efx_mcdi_phy_ops = { 739struct efx_phy_operations efx_mcdi_phy_ops = {
598 .probe = efx_mcdi_phy_probe, 740 .probe = efx_mcdi_phy_probe,
599 .init = efx_port_dummy_op_int, 741 .init = efx_port_dummy_op_int,
@@ -604,6 +746,6 @@ struct efx_phy_operations efx_mcdi_phy_ops = {
604 .get_settings = efx_mcdi_phy_get_settings, 746 .get_settings = efx_mcdi_phy_get_settings,
605 .set_settings = efx_mcdi_phy_set_settings, 747 .set_settings = efx_mcdi_phy_set_settings,
606 .test_alive = efx_mcdi_phy_test_alive, 748 .test_alive = efx_mcdi_phy_test_alive,
607 .run_tests = NULL, 749 .run_tests = efx_mcdi_phy_run_tests,
608 .test_name = NULL, 750 .test_name = efx_mcdi_phy_test_name,
609}; 751};