diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2008-12-26 16:48:00 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-12-26 16:48:00 -0500 |
commit | 307505e9a4ce0b13b2f996385669039806e07390 (patch) | |
tree | 964307da71ddcd8b5bfcced1d701d80964a1b090 /drivers/net/sfc | |
parent | 1796721a5a691a5d392abf8070ad40a0b787b667 (diff) |
sfc: SFT9001: Add cable diagnostics
The SFT9001 firmware implements cable diagnostics; run those and
include their results in a self-test. In case of a cable fault, do
not fail the self-test as a whole; only faults in the NIC should cause
that.
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/tenxpress.c | 115 |
1 files changed, 107 insertions, 8 deletions
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index bd204820e189..b9768760fae7 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c | |||
@@ -106,6 +106,25 @@ | |||
106 | #define PMA_PMD_SPEED_LBN 4 | 106 | #define PMA_PMD_SPEED_LBN 4 |
107 | #define PMA_PMD_SPEED_WIDTH 4 | 107 | #define PMA_PMD_SPEED_WIDTH 4 |
108 | 108 | ||
109 | /* Cable diagnostics - SFT9001 only */ | ||
110 | #define PMA_PMD_CDIAG_CTRL_REG 49213 | ||
111 | #define CDIAG_CTRL_IMMED_LBN 15 | ||
112 | #define CDIAG_CTRL_BRK_LINK_LBN 12 | ||
113 | #define CDIAG_CTRL_IN_PROG_LBN 11 | ||
114 | #define CDIAG_CTRL_LEN_UNIT_LBN 10 | ||
115 | #define CDIAG_CTRL_LEN_METRES 1 | ||
116 | #define PMA_PMD_CDIAG_RES_REG 49174 | ||
117 | #define CDIAG_RES_A_LBN 12 | ||
118 | #define CDIAG_RES_B_LBN 8 | ||
119 | #define CDIAG_RES_C_LBN 4 | ||
120 | #define CDIAG_RES_D_LBN 0 | ||
121 | #define CDIAG_RES_WIDTH 4 | ||
122 | #define CDIAG_RES_OPEN 2 | ||
123 | #define CDIAG_RES_OK 1 | ||
124 | #define CDIAG_RES_INVALID 0 | ||
125 | /* Set of 4 registers for pairs A-D */ | ||
126 | #define PMA_PMD_CDIAG_LEN_REG 49175 | ||
127 | |||
109 | /* Serdes control registers - SFT9001 only */ | 128 | /* Serdes control registers - SFT9001 only */ |
110 | #define PMA_PMD_CSERDES_CTRL_REG 64258 | 129 | #define PMA_PMD_CSERDES_CTRL_REG 64258 |
111 | /* Set the 156.25 MHz output to 312.5 MHz to drive Falcon's XMAC */ | 130 | /* Set the 156.25 MHz output to 312.5 MHz to drive Falcon's XMAC */ |
@@ -654,12 +673,12 @@ void tenxpress_phy_blink(struct efx_nic *efx, bool blink) | |||
654 | PMA_PMD_LED_OVERR_REG, reg); | 673 | PMA_PMD_LED_OVERR_REG, reg); |
655 | } | 674 | } |
656 | 675 | ||
657 | static const char *const tenxpress_test_names[] = { | 676 | static const char *const sfx7101_test_names[] = { |
658 | "bist" | 677 | "bist" |
659 | }; | 678 | }; |
660 | 679 | ||
661 | static int | 680 | static int |
662 | tenxpress_run_tests(struct efx_nic *efx, int *results, unsigned flags) | 681 | sfx7101_run_tests(struct efx_nic *efx, int *results, unsigned flags) |
663 | { | 682 | { |
664 | int rc; | 683 | int rc; |
665 | 684 | ||
@@ -672,6 +691,86 @@ tenxpress_run_tests(struct efx_nic *efx, int *results, unsigned flags) | |||
672 | return rc; | 691 | return rc; |
673 | } | 692 | } |
674 | 693 | ||
694 | static const char *const sft9001_test_names[] = { | ||
695 | "bist", | ||
696 | "cable.pairA.status", | ||
697 | "cable.pairB.status", | ||
698 | "cable.pairC.status", | ||
699 | "cable.pairD.status", | ||
700 | "cable.pairA.length", | ||
701 | "cable.pairB.length", | ||
702 | "cable.pairC.length", | ||
703 | "cable.pairD.length", | ||
704 | }; | ||
705 | |||
706 | static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags) | ||
707 | { | ||
708 | struct ethtool_cmd ecmd; | ||
709 | int phy_id = efx->mii.phy_id; | ||
710 | int rc = 0, rc2, i, res_reg; | ||
711 | |||
712 | if (!(flags & ETH_TEST_FL_OFFLINE)) | ||
713 | return 0; | ||
714 | |||
715 | efx->phy_op->get_settings(efx, &ecmd); | ||
716 | |||
717 | /* Initialise cable diagnostic results to unknown failure */ | ||
718 | for (i = 1; i < 9; ++i) | ||
719 | results[i] = -1; | ||
720 | |||
721 | /* Run cable diagnostics; wait up to 5 seconds for them to complete. | ||
722 | * A cable fault is not a self-test failure, but a timeout is. */ | ||
723 | mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, | ||
724 | PMA_PMD_CDIAG_CTRL_REG, | ||
725 | (1 << CDIAG_CTRL_IMMED_LBN) | | ||
726 | (1 << CDIAG_CTRL_BRK_LINK_LBN) | | ||
727 | (CDIAG_CTRL_LEN_METRES << CDIAG_CTRL_LEN_UNIT_LBN)); | ||
728 | i = 0; | ||
729 | while (mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, | ||
730 | PMA_PMD_CDIAG_CTRL_REG) & | ||
731 | (1 << CDIAG_CTRL_IN_PROG_LBN)) { | ||
732 | if (++i == 50) { | ||
733 | rc = -ETIMEDOUT; | ||
734 | goto reset; | ||
735 | } | ||
736 | msleep(100); | ||
737 | } | ||
738 | res_reg = mdio_clause45_read(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, | ||
739 | PMA_PMD_CDIAG_RES_REG); | ||
740 | for (i = 0; i < 4; i++) { | ||
741 | int pair_res = | ||
742 | (res_reg >> (CDIAG_RES_A_LBN - i * CDIAG_RES_WIDTH)) | ||
743 | & ((1 << CDIAG_RES_WIDTH) - 1); | ||
744 | int len_reg = mdio_clause45_read(efx, efx->mii.phy_id, | ||
745 | MDIO_MMD_PMAPMD, | ||
746 | PMA_PMD_CDIAG_LEN_REG + i); | ||
747 | if (pair_res == CDIAG_RES_OK) | ||
748 | results[1 + i] = 1; | ||
749 | else if (pair_res == CDIAG_RES_INVALID) | ||
750 | results[1 + i] = -1; | ||
751 | else | ||
752 | results[1 + i] = -pair_res; | ||
753 | if (pair_res != CDIAG_RES_INVALID && | ||
754 | pair_res != CDIAG_RES_OPEN && | ||
755 | len_reg != 0xffff) | ||
756 | results[5 + i] = len_reg; | ||
757 | } | ||
758 | |||
759 | /* We must reset to exit cable diagnostic mode. The BIST will | ||
760 | * also run when we do this. */ | ||
761 | reset: | ||
762 | rc2 = tenxpress_special_reset(efx); | ||
763 | results[0] = rc2 ? -1 : 1; | ||
764 | if (!rc) | ||
765 | rc = rc2; | ||
766 | |||
767 | rc2 = efx->phy_op->set_settings(efx, &ecmd); | ||
768 | if (!rc) | ||
769 | rc = rc2; | ||
770 | |||
771 | return rc; | ||
772 | } | ||
773 | |||
675 | static u32 tenxpress_get_xnp_lpa(struct efx_nic *efx) | 774 | static u32 tenxpress_get_xnp_lpa(struct efx_nic *efx) |
676 | { | 775 | { |
677 | int phy = efx->mii.phy_id; | 776 | int phy = efx->mii.phy_id; |
@@ -784,9 +883,9 @@ struct efx_phy_operations falcon_sfx7101_phy_ops = { | |||
784 | .clear_interrupt = efx_port_dummy_op_void, | 883 | .clear_interrupt = efx_port_dummy_op_void, |
785 | .get_settings = sfx7101_get_settings, | 884 | .get_settings = sfx7101_get_settings, |
786 | .set_settings = mdio_clause45_set_settings, | 885 | .set_settings = mdio_clause45_set_settings, |
787 | .num_tests = ARRAY_SIZE(tenxpress_test_names), | 886 | .num_tests = ARRAY_SIZE(sfx7101_test_names), |
788 | .test_names = tenxpress_test_names, | 887 | .test_names = sfx7101_test_names, |
789 | .run_tests = tenxpress_run_tests, | 888 | .run_tests = sfx7101_run_tests, |
790 | .mmds = TENXPRESS_REQUIRED_DEVS, | 889 | .mmds = TENXPRESS_REQUIRED_DEVS, |
791 | .loopbacks = SFX7101_LOOPBACKS, | 890 | .loopbacks = SFX7101_LOOPBACKS, |
792 | }; | 891 | }; |
@@ -801,9 +900,9 @@ struct efx_phy_operations falcon_sft9001_phy_ops = { | |||
801 | .get_settings = sft9001_get_settings, | 900 | .get_settings = sft9001_get_settings, |
802 | .set_settings = sft9001_set_settings, | 901 | .set_settings = sft9001_set_settings, |
803 | .set_xnp_advertise = sft9001_set_xnp_advertise, | 902 | .set_xnp_advertise = sft9001_set_xnp_advertise, |
804 | .num_tests = ARRAY_SIZE(tenxpress_test_names), | 903 | .num_tests = ARRAY_SIZE(sft9001_test_names), |
805 | .test_names = tenxpress_test_names, | 904 | .test_names = sft9001_test_names, |
806 | .run_tests = tenxpress_run_tests, | 905 | .run_tests = sft9001_run_tests, |
807 | .mmds = TENXPRESS_REQUIRED_DEVS, | 906 | .mmds = TENXPRESS_REQUIRED_DEVS, |
808 | .loopbacks = SFT9001_LOOPBACKS, | 907 | .loopbacks = SFT9001_LOOPBACKS, |
809 | }; | 908 | }; |