diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2012-07-03 22:58:33 -0400 |
---|---|---|
committer | Ben Hutchings <bhutchings@solarflare.com> | 2012-07-17 11:12:33 -0400 |
commit | d4f2cecce138c34960c467d0ae38a6d4bcd6af7b (patch) | |
tree | 19a93bad8f6a56361b3b2f12beecae97be4d8ea0 | |
parent | 0f1e54ae52b950ed79074ae794d027d6c97fd34e (diff) |
sfc: Disable VF queues during register self-test
Currently VF queues and drivers may remain active during this test.
This could cause memory corruption or spurious test failures.
Therefore we reset the port/function before running these tests on
Siena.
On Falcon this doesn't work: we have to do some additional
initialisation before some blocks will work again. So refactor the
reset/register-test sequence into an efx_nic_type method so
efx_selftest() doesn't have to consider such quirks.
In the process, fix another minor bug: Siena does not have an
'invisible' reset and the self-test currently fails to push the PHY
configuration after resetting. Passing RESET_TYPE_ALL to
efx_reset_{down,up}() fixes this.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
-rw-r--r-- | drivers/net/ethernet/sfc/falcon.c | 35 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/net_driver.h | 7 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/nic.c | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/selftest.c | 62 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/siena.c | 29 |
5 files changed, 76 insertions, 60 deletions
diff --git a/drivers/net/ethernet/sfc/falcon.c b/drivers/net/ethernet/sfc/falcon.c index 3a1ca2bd1548..12b573a8e82b 100644 --- a/drivers/net/ethernet/sfc/falcon.c +++ b/drivers/net/ethernet/sfc/falcon.c | |||
@@ -25,9 +25,12 @@ | |||
25 | #include "io.h" | 25 | #include "io.h" |
26 | #include "phy.h" | 26 | #include "phy.h" |
27 | #include "workarounds.h" | 27 | #include "workarounds.h" |
28 | #include "selftest.h" | ||
28 | 29 | ||
29 | /* Hardware control for SFC4000 (aka Falcon). */ | 30 | /* Hardware control for SFC4000 (aka Falcon). */ |
30 | 31 | ||
32 | static int falcon_reset_hw(struct efx_nic *efx, enum reset_type method); | ||
33 | |||
31 | static const unsigned int | 34 | static const unsigned int |
32 | /* "Large" EEPROM device: Atmel AT25640 or similar | 35 | /* "Large" EEPROM device: Atmel AT25640 or similar |
33 | * 8 KB, 16-bit address, 32 B write block */ | 36 | * 8 KB, 16-bit address, 32 B write block */ |
@@ -1034,10 +1037,34 @@ static const struct efx_nic_register_test falcon_b0_register_tests[] = { | |||
1034 | EFX_OWORD32(0x0003FF0F, 0x00000000, 0x00000000, 0x00000000) }, | 1037 | EFX_OWORD32(0x0003FF0F, 0x00000000, 0x00000000, 0x00000000) }, |
1035 | }; | 1038 | }; |
1036 | 1039 | ||
1037 | static int falcon_b0_test_registers(struct efx_nic *efx) | 1040 | static int |
1041 | falcon_b0_test_chip(struct efx_nic *efx, struct efx_self_tests *tests) | ||
1038 | { | 1042 | { |
1039 | return efx_nic_test_registers(efx, falcon_b0_register_tests, | 1043 | enum reset_type reset_method = RESET_TYPE_INVISIBLE; |
1040 | ARRAY_SIZE(falcon_b0_register_tests)); | 1044 | int rc, rc2; |
1045 | |||
1046 | mutex_lock(&efx->mac_lock); | ||
1047 | if (efx->loopback_modes) { | ||
1048 | /* We need the 312 clock from the PHY to test the XMAC | ||
1049 | * registers, so move into XGMII loopback if available */ | ||
1050 | if (efx->loopback_modes & (1 << LOOPBACK_XGMII)) | ||
1051 | efx->loopback_mode = LOOPBACK_XGMII; | ||
1052 | else | ||
1053 | efx->loopback_mode = __ffs(efx->loopback_modes); | ||
1054 | } | ||
1055 | __efx_reconfigure_port(efx); | ||
1056 | mutex_unlock(&efx->mac_lock); | ||
1057 | |||
1058 | efx_reset_down(efx, reset_method); | ||
1059 | |||
1060 | tests->registers = | ||
1061 | efx_nic_test_registers(efx, falcon_b0_register_tests, | ||
1062 | ARRAY_SIZE(falcon_b0_register_tests)) | ||
1063 | ? -1 : 1; | ||
1064 | |||
1065 | rc = falcon_reset_hw(efx, reset_method); | ||
1066 | rc2 = efx_reset_up(efx, reset_method, rc == 0); | ||
1067 | return rc ? rc : rc2; | ||
1041 | } | 1068 | } |
1042 | 1069 | ||
1043 | /************************************************************************** | 1070 | /************************************************************************** |
@@ -1818,7 +1845,7 @@ const struct efx_nic_type falcon_b0_nic_type = { | |||
1818 | .get_wol = falcon_get_wol, | 1845 | .get_wol = falcon_get_wol, |
1819 | .set_wol = falcon_set_wol, | 1846 | .set_wol = falcon_set_wol, |
1820 | .resume_wol = efx_port_dummy_op_void, | 1847 | .resume_wol = efx_port_dummy_op_void, |
1821 | .test_registers = falcon_b0_test_registers, | 1848 | .test_chip = falcon_b0_test_chip, |
1822 | .test_nvram = falcon_test_nvram, | 1849 | .test_nvram = falcon_test_nvram, |
1823 | 1850 | ||
1824 | .revision = EFX_REV_FALCON_B0, | 1851 | .revision = EFX_REV_FALCON_B0, |
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 8a9f6d48214d..55be2fdb0e62 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h | |||
@@ -68,6 +68,8 @@ | |||
68 | #define EFX_TXQ_TYPES 4 | 68 | #define EFX_TXQ_TYPES 4 |
69 | #define EFX_MAX_TX_QUEUES (EFX_TXQ_TYPES * EFX_MAX_CHANNELS) | 69 | #define EFX_MAX_TX_QUEUES (EFX_TXQ_TYPES * EFX_MAX_CHANNELS) |
70 | 70 | ||
71 | struct efx_self_tests; | ||
72 | |||
71 | /** | 73 | /** |
72 | * struct efx_special_buffer - An Efx special buffer | 74 | * struct efx_special_buffer - An Efx special buffer |
73 | * @addr: CPU base address of the buffer | 75 | * @addr: CPU base address of the buffer |
@@ -901,7 +903,8 @@ static inline unsigned int efx_port_num(struct efx_nic *efx) | |||
901 | * @get_wol: Get WoL configuration from driver state | 903 | * @get_wol: Get WoL configuration from driver state |
902 | * @set_wol: Push WoL configuration to the NIC | 904 | * @set_wol: Push WoL configuration to the NIC |
903 | * @resume_wol: Synchronise WoL state between driver and MC (e.g. after resume) | 905 | * @resume_wol: Synchronise WoL state between driver and MC (e.g. after resume) |
904 | * @test_registers: Test read/write functionality of control registers | 906 | * @test_chip: Test registers. Should use efx_nic_test_registers(), and is |
907 | * expected to reset the NIC. | ||
905 | * @test_nvram: Test validity of NVRAM contents | 908 | * @test_nvram: Test validity of NVRAM contents |
906 | * @revision: Hardware architecture revision | 909 | * @revision: Hardware architecture revision |
907 | * @mem_map_size: Memory BAR mapped size | 910 | * @mem_map_size: Memory BAR mapped size |
@@ -946,7 +949,7 @@ struct efx_nic_type { | |||
946 | void (*get_wol)(struct efx_nic *efx, struct ethtool_wolinfo *wol); | 949 | void (*get_wol)(struct efx_nic *efx, struct ethtool_wolinfo *wol); |
947 | int (*set_wol)(struct efx_nic *efx, u32 type); | 950 | int (*set_wol)(struct efx_nic *efx, u32 type); |
948 | void (*resume_wol)(struct efx_nic *efx); | 951 | void (*resume_wol)(struct efx_nic *efx); |
949 | int (*test_registers)(struct efx_nic *efx); | 952 | int (*test_chip)(struct efx_nic *efx, struct efx_self_tests *tests); |
950 | int (*test_nvram)(struct efx_nic *efx); | 953 | int (*test_nvram)(struct efx_nic *efx); |
951 | 954 | ||
952 | int revision; | 955 | int revision; |
diff --git a/drivers/net/ethernet/sfc/nic.c b/drivers/net/ethernet/sfc/nic.c index 287738db24e5..326d799762d6 100644 --- a/drivers/net/ethernet/sfc/nic.c +++ b/drivers/net/ethernet/sfc/nic.c | |||
@@ -124,9 +124,6 @@ int efx_nic_test_registers(struct efx_nic *efx, | |||
124 | unsigned address = 0, i, j; | 124 | unsigned address = 0, i, j; |
125 | efx_oword_t mask, imask, original, reg, buf; | 125 | efx_oword_t mask, imask, original, reg, buf; |
126 | 126 | ||
127 | /* Falcon should be in loopback to isolate the XMAC from the PHY */ | ||
128 | WARN_ON(!LOOPBACK_INTERNAL(efx)); | ||
129 | |||
130 | for (i = 0; i < n_regs; ++i) { | 127 | for (i = 0; i < n_regs; ++i) { |
131 | address = regs[i].address; | 128 | address = regs[i].address; |
132 | mask = imask = regs[i].mask; | 129 | mask = imask = regs[i].mask; |
diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c index ccc428fc267b..96068d15b601 100644 --- a/drivers/net/ethernet/sfc/selftest.c +++ b/drivers/net/ethernet/sfc/selftest.c | |||
@@ -120,19 +120,6 @@ static int efx_test_nvram(struct efx_nic *efx, struct efx_self_tests *tests) | |||
120 | return rc; | 120 | return rc; |
121 | } | 121 | } |
122 | 122 | ||
123 | static int efx_test_chip(struct efx_nic *efx, struct efx_self_tests *tests) | ||
124 | { | ||
125 | int rc = 0; | ||
126 | |||
127 | /* Test register access */ | ||
128 | if (efx->type->test_registers) { | ||
129 | rc = efx->type->test_registers(efx); | ||
130 | tests->registers = rc ? -1 : 1; | ||
131 | } | ||
132 | |||
133 | return rc; | ||
134 | } | ||
135 | |||
136 | /************************************************************************** | 123 | /************************************************************************** |
137 | * | 124 | * |
138 | * Interrupt and event queue testing | 125 | * Interrupt and event queue testing |
@@ -699,8 +686,7 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, | |||
699 | { | 686 | { |
700 | enum efx_loopback_mode loopback_mode = efx->loopback_mode; | 687 | enum efx_loopback_mode loopback_mode = efx->loopback_mode; |
701 | int phy_mode = efx->phy_mode; | 688 | int phy_mode = efx->phy_mode; |
702 | enum reset_type reset_method = RESET_TYPE_INVISIBLE; | 689 | int rc_test = 0, rc_reset, rc; |
703 | int rc_test = 0, rc_reset = 0, rc; | ||
704 | 690 | ||
705 | efx_selftest_async_cancel(efx); | 691 | efx_selftest_async_cancel(efx); |
706 | 692 | ||
@@ -737,44 +723,26 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, | |||
737 | */ | 723 | */ |
738 | netif_device_detach(efx->net_dev); | 724 | netif_device_detach(efx->net_dev); |
739 | 725 | ||
740 | mutex_lock(&efx->mac_lock); | 726 | if (efx->type->test_chip) { |
741 | if (efx->loopback_modes) { | 727 | rc_reset = efx->type->test_chip(efx, tests); |
742 | /* We need the 312 clock from the PHY to test the XMAC | 728 | if (rc_reset) { |
743 | * registers, so move into XGMII loopback if available */ | 729 | netif_err(efx, hw, efx->net_dev, |
744 | if (efx->loopback_modes & (1 << LOOPBACK_XGMII)) | 730 | "Unable to recover from chip test\n"); |
745 | efx->loopback_mode = LOOPBACK_XGMII; | 731 | efx_schedule_reset(efx, RESET_TYPE_DISABLE); |
746 | else | 732 | return rc_reset; |
747 | efx->loopback_mode = __ffs(efx->loopback_modes); | 733 | } |
748 | } | ||
749 | |||
750 | __efx_reconfigure_port(efx); | ||
751 | mutex_unlock(&efx->mac_lock); | ||
752 | |||
753 | /* free up all consumers of SRAM (including all the queues) */ | ||
754 | efx_reset_down(efx, reset_method); | ||
755 | |||
756 | rc = efx_test_chip(efx, tests); | ||
757 | if (rc && !rc_test) | ||
758 | rc_test = rc; | ||
759 | 734 | ||
760 | /* reset the chip to recover from the register test */ | 735 | if ((tests->registers < 0) && !rc_test) |
761 | rc_reset = efx->type->reset(efx, reset_method); | 736 | rc_test = -EIO; |
737 | } | ||
762 | 738 | ||
763 | /* Ensure that the phy is powered and out of loopback | 739 | /* Ensure that the phy is powered and out of loopback |
764 | * for the bist and loopback tests */ | 740 | * for the bist and loopback tests */ |
741 | mutex_lock(&efx->mac_lock); | ||
765 | efx->phy_mode &= ~PHY_MODE_LOW_POWER; | 742 | efx->phy_mode &= ~PHY_MODE_LOW_POWER; |
766 | efx->loopback_mode = LOOPBACK_NONE; | 743 | efx->loopback_mode = LOOPBACK_NONE; |
767 | 744 | __efx_reconfigure_port(efx); | |
768 | rc = efx_reset_up(efx, reset_method, rc_reset == 0); | 745 | mutex_unlock(&efx->mac_lock); |
769 | if (rc && !rc_reset) | ||
770 | rc_reset = rc; | ||
771 | |||
772 | if (rc_reset) { | ||
773 | netif_err(efx, drv, efx->net_dev, | ||
774 | "Unable to recover from chip test\n"); | ||
775 | efx_schedule_reset(efx, RESET_TYPE_DISABLE); | ||
776 | return rc_reset; | ||
777 | } | ||
778 | 746 | ||
779 | rc = efx_test_phy(efx, tests, flags); | 747 | rc = efx_test_phy(efx, tests, flags); |
780 | if (rc && !rc_test) | 748 | if (rc && !rc_test) |
diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c index 9f8d7cea3967..2354886293db 100644 --- a/drivers/net/ethernet/sfc/siena.c +++ b/drivers/net/ethernet/sfc/siena.c | |||
@@ -25,10 +25,12 @@ | |||
25 | #include "workarounds.h" | 25 | #include "workarounds.h" |
26 | #include "mcdi.h" | 26 | #include "mcdi.h" |
27 | #include "mcdi_pcol.h" | 27 | #include "mcdi_pcol.h" |
28 | #include "selftest.h" | ||
28 | 29 | ||
29 | /* Hardware control for SFC9000 family including SFL9021 (aka Siena). */ | 30 | /* Hardware control for SFC9000 family including SFL9021 (aka Siena). */ |
30 | 31 | ||
31 | static void siena_init_wol(struct efx_nic *efx); | 32 | static void siena_init_wol(struct efx_nic *efx); |
33 | static int siena_reset_hw(struct efx_nic *efx, enum reset_type method); | ||
32 | 34 | ||
33 | 35 | ||
34 | static void siena_push_irq_moderation(struct efx_channel *channel) | 36 | static void siena_push_irq_moderation(struct efx_channel *channel) |
@@ -154,10 +156,29 @@ static const struct efx_nic_register_test siena_register_tests[] = { | |||
154 | EFX_OWORD32(0xFFFFFFFF, 0xFFFFFFFF, 0x00000007, 0x00000000) }, | 156 | EFX_OWORD32(0xFFFFFFFF, 0xFFFFFFFF, 0x00000007, 0x00000000) }, |
155 | }; | 157 | }; |
156 | 158 | ||
157 | static int siena_test_registers(struct efx_nic *efx) | 159 | static int siena_test_chip(struct efx_nic *efx, struct efx_self_tests *tests) |
158 | { | 160 | { |
159 | return efx_nic_test_registers(efx, siena_register_tests, | 161 | enum reset_type reset_method = reset_method; |
160 | ARRAY_SIZE(siena_register_tests)); | 162 | int rc, rc2; |
163 | |||
164 | efx_reset_down(efx, reset_method); | ||
165 | |||
166 | /* Reset the chip immediately so that it is completely | ||
167 | * quiescent regardless of what any VF driver does. | ||
168 | */ | ||
169 | rc = siena_reset_hw(efx, reset_method); | ||
170 | if (rc) | ||
171 | goto out; | ||
172 | |||
173 | tests->registers = | ||
174 | efx_nic_test_registers(efx, siena_register_tests, | ||
175 | ARRAY_SIZE(siena_register_tests)) | ||
176 | ? -1 : 1; | ||
177 | |||
178 | rc = siena_reset_hw(efx, reset_method); | ||
179 | out: | ||
180 | rc2 = efx_reset_up(efx, reset_method, rc == 0); | ||
181 | return rc ? rc : rc2; | ||
161 | } | 182 | } |
162 | 183 | ||
163 | /************************************************************************** | 184 | /************************************************************************** |
@@ -649,7 +670,7 @@ const struct efx_nic_type siena_a0_nic_type = { | |||
649 | .get_wol = siena_get_wol, | 670 | .get_wol = siena_get_wol, |
650 | .set_wol = siena_set_wol, | 671 | .set_wol = siena_set_wol, |
651 | .resume_wol = siena_init_wol, | 672 | .resume_wol = siena_init_wol, |
652 | .test_registers = siena_test_registers, | 673 | .test_chip = siena_test_chip, |
653 | .test_nvram = efx_mcdi_nvram_test_all, | 674 | .test_nvram = efx_mcdi_nvram_test_all, |
654 | 675 | ||
655 | .revision = EFX_REV_SIENA_A0, | 676 | .revision = EFX_REV_SIENA_A0, |