diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2008-09-01 07:49:02 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2008-09-03 09:53:48 -0400 |
commit | 8c8661e4cefdd1ddbfe7d5120f046694555d9e5c (patch) | |
tree | 0618e0392140bccadf012381e64a795dfe2e41a4 /drivers/net/sfc/selftest.c | |
parent | a515089c963b045f65c495cee1d344d8cb75e1d1 (diff) |
sfc: Extend self-tests
Include PMA/PMD in loopback self-tests as intended.
Add NVRAM checksum validation and include it in self-tests.
Add register self-tests.
Run PHY self-tests where available.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/net/sfc/selftest.c')
-rw-r--r-- | drivers/net/sfc/selftest.c | 277 |
1 files changed, 169 insertions, 108 deletions
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 2f7def657679..362956e3fe17 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c | |||
@@ -27,6 +27,9 @@ | |||
27 | #include "boards.h" | 27 | #include "boards.h" |
28 | #include "workarounds.h" | 28 | #include "workarounds.h" |
29 | #include "mac.h" | 29 | #include "mac.h" |
30 | #include "spi.h" | ||
31 | #include "falcon_io.h" | ||
32 | #include "mdio_10g.h" | ||
30 | 33 | ||
31 | /* | 34 | /* |
32 | * Loopback test packet structure | 35 | * Loopback test packet structure |
@@ -51,7 +54,7 @@ static const char *payload_msg = | |||
51 | "Hello world! This is an Efx loopback test in progress!"; | 54 | "Hello world! This is an Efx loopback test in progress!"; |
52 | 55 | ||
53 | /** | 56 | /** |
54 | * efx_selftest_state - persistent state during a selftest | 57 | * efx_loopback_state - persistent state during a loopback selftest |
55 | * @flush: Drop all packets in efx_loopback_rx_packet | 58 | * @flush: Drop all packets in efx_loopback_rx_packet |
56 | * @packet_count: Number of packets being used in this test | 59 | * @packet_count: Number of packets being used in this test |
57 | * @skbs: An array of skbs transmitted | 60 | * @skbs: An array of skbs transmitted |
@@ -59,7 +62,7 @@ static const char *payload_msg = | |||
59 | * @rx_bad: RX bad packet count | 62 | * @rx_bad: RX bad packet count |
60 | * @payload: Payload used in tests | 63 | * @payload: Payload used in tests |
61 | */ | 64 | */ |
62 | struct efx_selftest_state { | 65 | struct efx_loopback_state { |
63 | bool flush; | 66 | bool flush; |
64 | int packet_count; | 67 | int packet_count; |
65 | struct sk_buff **skbs; | 68 | struct sk_buff **skbs; |
@@ -74,21 +77,65 @@ struct efx_selftest_state { | |||
74 | 77 | ||
75 | /************************************************************************** | 78 | /************************************************************************** |
76 | * | 79 | * |
77 | * Configurable values | 80 | * MII, NVRAM and register tests |
78 | * | 81 | * |
79 | **************************************************************************/ | 82 | **************************************************************************/ |
80 | 83 | ||
81 | /* Level of loopback testing | 84 | static int efx_test_mii(struct efx_nic *efx, struct efx_self_tests *tests) |
82 | * | 85 | { |
83 | * The maximum packet burst length is 16**(n-1), i.e. | 86 | int rc = 0; |
84 | * | 87 | u16 physid1, physid2; |
85 | * - Level 0 : no packets | 88 | struct mii_if_info *mii = &efx->mii; |
86 | * - Level 1 : 1 packet | 89 | struct net_device *net_dev = efx->net_dev; |
87 | * - Level 2 : 17 packets (1 * 1 packet, 1 * 16 packets) | 90 | |
88 | * - Level 3 : 273 packets (1 * 1 packet, 1 * 16 packet, 1 * 256 packets) | 91 | if (efx->phy_type == PHY_TYPE_NONE) |
89 | * | 92 | return 0; |
90 | */ | 93 | |
91 | static unsigned int loopback_test_level = 3; | 94 | mutex_lock(&efx->mac_lock); |
95 | tests->mii = -1; | ||
96 | |||
97 | physid1 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID1); | ||
98 | physid2 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID2); | ||
99 | |||
100 | if ((physid1 == 0x0000) || (physid1 == 0xffff) || | ||
101 | (physid2 == 0x0000) || (physid2 == 0xffff)) { | ||
102 | EFX_ERR(efx, "no MII PHY present with ID %d\n", | ||
103 | mii->phy_id); | ||
104 | rc = -EINVAL; | ||
105 | goto out; | ||
106 | } | ||
107 | |||
108 | rc = mdio_clause45_check_mmds(efx, efx->phy_op->mmds, 0); | ||
109 | if (rc) | ||
110 | goto out; | ||
111 | |||
112 | out: | ||
113 | mutex_unlock(&efx->mac_lock); | ||
114 | tests->mii = rc ? -1 : 1; | ||
115 | return rc; | ||
116 | } | ||
117 | |||
118 | static int efx_test_nvram(struct efx_nic *efx, struct efx_self_tests *tests) | ||
119 | { | ||
120 | int rc; | ||
121 | |||
122 | rc = falcon_read_nvram(efx, NULL); | ||
123 | tests->nvram = rc ? -1 : 1; | ||
124 | return rc; | ||
125 | } | ||
126 | |||
127 | static int efx_test_chip(struct efx_nic *efx, struct efx_self_tests *tests) | ||
128 | { | ||
129 | int rc; | ||
130 | |||
131 | /* Not supported on A-series silicon */ | ||
132 | if (falcon_rev(efx) < FALCON_REV_B0) | ||
133 | return 0; | ||
134 | |||
135 | rc = falcon_test_registers(efx); | ||
136 | tests->registers = rc ? -1 : 1; | ||
137 | return rc; | ||
138 | } | ||
92 | 139 | ||
93 | /************************************************************************** | 140 | /************************************************************************** |
94 | * | 141 | * |
@@ -199,39 +246,18 @@ static int efx_test_eventq_irq(struct efx_channel *channel, | |||
199 | return 0; | 246 | return 0; |
200 | } | 247 | } |
201 | 248 | ||
202 | /************************************************************************** | 249 | static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests) |
203 | * | ||
204 | * PHY testing | ||
205 | * | ||
206 | **************************************************************************/ | ||
207 | |||
208 | /* Check PHY presence by reading the PHY ID registers */ | ||
209 | static int efx_test_phy(struct efx_nic *efx, | ||
210 | struct efx_self_tests *tests) | ||
211 | { | 250 | { |
212 | u16 physid1, physid2; | 251 | int rc; |
213 | struct mii_if_info *mii = &efx->mii; | ||
214 | struct net_device *net_dev = efx->net_dev; | ||
215 | |||
216 | if (efx->phy_type == PHY_TYPE_NONE) | ||
217 | return 0; | ||
218 | |||
219 | EFX_LOG(efx, "testing PHY presence\n"); | ||
220 | tests->phy_ok = -1; | ||
221 | |||
222 | physid1 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID1); | ||
223 | physid2 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID2); | ||
224 | 252 | ||
225 | if ((physid1 != 0x0000) && (physid1 != 0xffff) && | 253 | if (!efx->phy_op->test) |
226 | (physid2 != 0x0000) && (physid2 != 0xffff)) { | ||
227 | EFX_LOG(efx, "found MII PHY %d ID 0x%x:%x\n", | ||
228 | mii->phy_id, physid1, physid2); | ||
229 | tests->phy_ok = 1; | ||
230 | return 0; | 254 | return 0; |
231 | } | ||
232 | 255 | ||
233 | EFX_ERR(efx, "no MII PHY present with ID %d\n", mii->phy_id); | 256 | mutex_lock(&efx->mac_lock); |
234 | return -ENODEV; | 257 | rc = efx->phy_op->test(efx); |
258 | mutex_unlock(&efx->mac_lock); | ||
259 | tests->phy = rc ? -1 : 1; | ||
260 | return rc; | ||
235 | } | 261 | } |
236 | 262 | ||
237 | /************************************************************************** | 263 | /************************************************************************** |
@@ -247,7 +273,7 @@ static int efx_test_phy(struct efx_nic *efx, | |||
247 | void efx_loopback_rx_packet(struct efx_nic *efx, | 273 | void efx_loopback_rx_packet(struct efx_nic *efx, |
248 | const char *buf_ptr, int pkt_len) | 274 | const char *buf_ptr, int pkt_len) |
249 | { | 275 | { |
250 | struct efx_selftest_state *state = efx->loopback_selftest; | 276 | struct efx_loopback_state *state = efx->loopback_selftest; |
251 | struct efx_loopback_payload *received; | 277 | struct efx_loopback_payload *received; |
252 | struct efx_loopback_payload *payload; | 278 | struct efx_loopback_payload *payload; |
253 | 279 | ||
@@ -258,7 +284,7 @@ void efx_loopback_rx_packet(struct efx_nic *efx, | |||
258 | return; | 284 | return; |
259 | 285 | ||
260 | payload = &state->payload; | 286 | payload = &state->payload; |
261 | 287 | ||
262 | received = (struct efx_loopback_payload *) buf_ptr; | 288 | received = (struct efx_loopback_payload *) buf_ptr; |
263 | received->ip.saddr = payload->ip.saddr; | 289 | received->ip.saddr = payload->ip.saddr; |
264 | if (state->offload_csum) | 290 | if (state->offload_csum) |
@@ -332,7 +358,7 @@ void efx_loopback_rx_packet(struct efx_nic *efx, | |||
332 | /* Initialise an efx_selftest_state for a new iteration */ | 358 | /* Initialise an efx_selftest_state for a new iteration */ |
333 | static void efx_iterate_state(struct efx_nic *efx) | 359 | static void efx_iterate_state(struct efx_nic *efx) |
334 | { | 360 | { |
335 | struct efx_selftest_state *state = efx->loopback_selftest; | 361 | struct efx_loopback_state *state = efx->loopback_selftest; |
336 | struct net_device *net_dev = efx->net_dev; | 362 | struct net_device *net_dev = efx->net_dev; |
337 | struct efx_loopback_payload *payload = &state->payload; | 363 | struct efx_loopback_payload *payload = &state->payload; |
338 | 364 | ||
@@ -368,14 +394,14 @@ static void efx_iterate_state(struct efx_nic *efx) | |||
368 | static int efx_begin_loopback(struct efx_tx_queue *tx_queue) | 394 | static int efx_begin_loopback(struct efx_tx_queue *tx_queue) |
369 | { | 395 | { |
370 | struct efx_nic *efx = tx_queue->efx; | 396 | struct efx_nic *efx = tx_queue->efx; |
371 | struct efx_selftest_state *state = efx->loopback_selftest; | 397 | struct efx_loopback_state *state = efx->loopback_selftest; |
372 | struct efx_loopback_payload *payload; | 398 | struct efx_loopback_payload *payload; |
373 | struct sk_buff *skb; | 399 | struct sk_buff *skb; |
374 | int i, rc; | 400 | int i, rc; |
375 | 401 | ||
376 | /* Transmit N copies of buffer */ | 402 | /* Transmit N copies of buffer */ |
377 | for (i = 0; i < state->packet_count; i++) { | 403 | for (i = 0; i < state->packet_count; i++) { |
378 | /* Allocate an skb, holding an extra reference for | 404 | /* Allocate an skb, holding an extra reference for |
379 | * transmit completion counting */ | 405 | * transmit completion counting */ |
380 | skb = alloc_skb(sizeof(state->payload), GFP_KERNEL); | 406 | skb = alloc_skb(sizeof(state->payload), GFP_KERNEL); |
381 | if (!skb) | 407 | if (!skb) |
@@ -416,7 +442,7 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue) | |||
416 | 442 | ||
417 | static int efx_poll_loopback(struct efx_nic *efx) | 443 | static int efx_poll_loopback(struct efx_nic *efx) |
418 | { | 444 | { |
419 | struct efx_selftest_state *state = efx->loopback_selftest; | 445 | struct efx_loopback_state *state = efx->loopback_selftest; |
420 | struct efx_channel *channel; | 446 | struct efx_channel *channel; |
421 | 447 | ||
422 | /* NAPI polling is not enabled, so process channels | 448 | /* NAPI polling is not enabled, so process channels |
@@ -432,7 +458,7 @@ static int efx_end_loopback(struct efx_tx_queue *tx_queue, | |||
432 | struct efx_loopback_self_tests *lb_tests) | 458 | struct efx_loopback_self_tests *lb_tests) |
433 | { | 459 | { |
434 | struct efx_nic *efx = tx_queue->efx; | 460 | struct efx_nic *efx = tx_queue->efx; |
435 | struct efx_selftest_state *state = efx->loopback_selftest; | 461 | struct efx_loopback_state *state = efx->loopback_selftest; |
436 | struct sk_buff *skb; | 462 | struct sk_buff *skb; |
437 | int tx_done = 0, rx_good, rx_bad; | 463 | int tx_done = 0, rx_good, rx_bad; |
438 | int i, rc = 0; | 464 | int i, rc = 0; |
@@ -491,10 +517,10 @@ efx_test_loopback(struct efx_tx_queue *tx_queue, | |||
491 | struct efx_loopback_self_tests *lb_tests) | 517 | struct efx_loopback_self_tests *lb_tests) |
492 | { | 518 | { |
493 | struct efx_nic *efx = tx_queue->efx; | 519 | struct efx_nic *efx = tx_queue->efx; |
494 | struct efx_selftest_state *state = efx->loopback_selftest; | 520 | struct efx_loopback_state *state = efx->loopback_selftest; |
495 | int i, begin_rc, end_rc; | 521 | int i, begin_rc, end_rc; |
496 | 522 | ||
497 | for (i = 0; i < loopback_test_level; i++) { | 523 | for (i = 0; i < 3; i++) { |
498 | /* Determine how many packets to send */ | 524 | /* Determine how many packets to send */ |
499 | state->packet_count = (efx->type->txd_ring_mask + 1) / 3; | 525 | state->packet_count = (efx->type->txd_ring_mask + 1) / 3; |
500 | state->packet_count = min(1 << (i << 2), state->packet_count); | 526 | state->packet_count = min(1 << (i << 2), state->packet_count); |
@@ -537,42 +563,28 @@ efx_test_loopback(struct efx_tx_queue *tx_queue, | |||
537 | return 0; | 563 | return 0; |
538 | } | 564 | } |
539 | 565 | ||
540 | static int efx_test_loopbacks(struct efx_nic *efx, | 566 | static int efx_test_loopbacks(struct efx_nic *efx, struct ethtool_cmd ecmd, |
541 | struct efx_self_tests *tests, | 567 | struct efx_self_tests *tests, |
542 | unsigned int loopback_modes) | 568 | unsigned int loopback_modes) |
543 | { | 569 | { |
544 | struct efx_selftest_state *state = efx->loopback_selftest; | 570 | enum efx_loopback_mode mode; |
545 | struct ethtool_cmd ecmd, ecmd_loopback; | 571 | struct efx_loopback_state *state; |
546 | struct efx_tx_queue *tx_queue; | 572 | struct efx_tx_queue *tx_queue; |
547 | enum efx_loopback_mode old_mode, mode; | ||
548 | bool link_up; | 573 | bool link_up; |
549 | int count, rc; | 574 | int count, rc = 0; |
550 | |||
551 | rc = efx_ethtool_get_settings(efx->net_dev, &ecmd); | ||
552 | if (rc) { | ||
553 | EFX_ERR(efx, "could not get GMII settings\n"); | ||
554 | return rc; | ||
555 | } | ||
556 | old_mode = efx->loopback_mode; | ||
557 | |||
558 | /* Disable autonegotiation for the purposes of loopback */ | ||
559 | memcpy(&ecmd_loopback, &ecmd, sizeof(ecmd_loopback)); | ||
560 | if (ecmd_loopback.autoneg == AUTONEG_ENABLE) { | ||
561 | ecmd_loopback.autoneg = AUTONEG_DISABLE; | ||
562 | ecmd_loopback.duplex = DUPLEX_FULL; | ||
563 | ecmd_loopback.speed = SPEED_10000; | ||
564 | } | ||
565 | 575 | ||
566 | rc = efx_ethtool_set_settings(efx->net_dev, &ecmd_loopback); | 576 | /* Set the port loopback_selftest member. From this point on |
567 | if (rc) { | 577 | * all received packets will be dropped. Mark the state as |
568 | EFX_ERR(efx, "could not disable autonegotiation\n"); | 578 | * "flushing" so all inflight packets are dropped */ |
569 | goto out; | 579 | state = kzalloc(sizeof(*state), GFP_KERNEL); |
570 | } | 580 | if (state == NULL) |
571 | tests->loopback_speed = ecmd_loopback.speed; | 581 | return -ENOMEM; |
572 | tests->loopback_full_duplex = ecmd_loopback.duplex; | 582 | BUG_ON(efx->loopback_selftest); |
583 | state->flush = true; | ||
584 | efx->loopback_selftest = state; | ||
573 | 585 | ||
574 | /* Test all supported loopback modes */ | 586 | /* Test all supported loopback modes */ |
575 | for (mode = LOOPBACK_NONE; mode < LOOPBACK_TEST_MAX; mode++) { | 587 | for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) { |
576 | if (!(loopback_modes & (1 << mode))) | 588 | if (!(loopback_modes & (1 << mode))) |
577 | continue; | 589 | continue; |
578 | 590 | ||
@@ -601,7 +613,7 @@ static int efx_test_loopbacks(struct efx_nic *efx, | |||
601 | */ | 613 | */ |
602 | link_up = efx->link_up; | 614 | link_up = efx->link_up; |
603 | if (!falcon_xaui_link_ok(efx)) | 615 | if (!falcon_xaui_link_ok(efx)) |
604 | link_up = 0; | 616 | link_up = false; |
605 | 617 | ||
606 | } while ((++count < 20) && !link_up); | 618 | } while ((++count < 20) && !link_up); |
607 | 619 | ||
@@ -629,10 +641,11 @@ static int efx_test_loopbacks(struct efx_nic *efx, | |||
629 | } | 641 | } |
630 | 642 | ||
631 | out: | 643 | out: |
632 | /* Take out of loopback and restore PHY settings */ | 644 | /* Remove the flush. The caller will remove the loopback setting */ |
633 | state->flush = true; | 645 | state->flush = true; |
634 | efx->loopback_mode = old_mode; | 646 | efx->loopback_selftest = NULL; |
635 | efx_ethtool_set_settings(efx->net_dev, &ecmd); | 647 | wmb(); |
648 | kfree(state); | ||
636 | 649 | ||
637 | return rc; | 650 | return rc; |
638 | } | 651 | } |
@@ -648,18 +661,27 @@ static int efx_test_loopbacks(struct efx_nic *efx, | |||
648 | int efx_online_test(struct efx_nic *efx, struct efx_self_tests *tests) | 661 | int efx_online_test(struct efx_nic *efx, struct efx_self_tests *tests) |
649 | { | 662 | { |
650 | struct efx_channel *channel; | 663 | struct efx_channel *channel; |
651 | int rc; | 664 | int rc, rc2 = 0; |
665 | |||
666 | rc = efx_test_mii(efx, tests); | ||
667 | if (rc && !rc2) | ||
668 | rc2 = rc; | ||
669 | |||
670 | rc = efx_test_nvram(efx, tests); | ||
671 | if (rc && !rc2) | ||
672 | rc2 = rc; | ||
652 | 673 | ||
653 | rc = efx_test_interrupts(efx, tests); | 674 | rc = efx_test_interrupts(efx, tests); |
654 | if (rc) | 675 | if (rc && !rc2) |
655 | return rc; | 676 | rc2 = rc; |
677 | |||
656 | efx_for_each_channel(channel, efx) { | 678 | efx_for_each_channel(channel, efx) { |
657 | rc = efx_test_eventq_irq(channel, tests); | 679 | rc = efx_test_eventq_irq(channel, tests); |
658 | if (rc) | 680 | if (rc && !rc2) |
659 | return rc; | 681 | rc2 = rc; |
660 | } | 682 | } |
661 | rc = efx_test_phy(efx, tests); | 683 | |
662 | return rc; | 684 | return rc2; |
663 | } | 685 | } |
664 | 686 | ||
665 | /* Offline (i.e. disruptive) testing | 687 | /* Offline (i.e. disruptive) testing |
@@ -667,27 +689,66 @@ int efx_online_test(struct efx_nic *efx, struct efx_self_tests *tests) | |||
667 | int efx_offline_test(struct efx_nic *efx, | 689 | int efx_offline_test(struct efx_nic *efx, |
668 | struct efx_self_tests *tests, unsigned int loopback_modes) | 690 | struct efx_self_tests *tests, unsigned int loopback_modes) |
669 | { | 691 | { |
670 | struct efx_selftest_state *state; | 692 | enum efx_loopback_mode loopback_mode = efx->loopback_mode; |
671 | int rc; | 693 | int phy_mode = efx->phy_mode; |
694 | struct ethtool_cmd ecmd, ecmd_test; | ||
695 | int rc, rc2 = 0; | ||
696 | |||
697 | /* force the carrier state off so the kernel doesn't transmit during | ||
698 | * the loopback test, and the watchdog timeout doesn't fire. Also put | ||
699 | * falcon into loopback for the register test. | ||
700 | */ | ||
701 | mutex_lock(&efx->mac_lock); | ||
702 | efx->port_inhibited = true; | ||
703 | if (efx->loopback_modes) | ||
704 | efx->loopback_mode = __ffs(efx->loopback_modes); | ||
705 | __efx_reconfigure_port(efx); | ||
706 | mutex_unlock(&efx->mac_lock); | ||
707 | |||
708 | /* free up all consumers of SRAM (including all the queues) */ | ||
709 | efx_reset_down(efx, &ecmd); | ||
710 | |||
711 | rc = efx_test_chip(efx, tests); | ||
712 | if (rc && !rc2) | ||
713 | rc2 = rc; | ||
714 | |||
715 | /* reset the chip to recover from the register test */ | ||
716 | rc = falcon_reset_hw(efx, RESET_TYPE_ALL); | ||
717 | |||
718 | /* Modify the saved ecmd so that when efx_reset_up() restores the phy | ||
719 | * state, AN is disabled, and the phy is powered, and out of loopback */ | ||
720 | memcpy(&ecmd_test, &ecmd, sizeof(ecmd_test)); | ||
721 | if (ecmd_test.autoneg == AUTONEG_ENABLE) { | ||
722 | ecmd_test.autoneg = AUTONEG_DISABLE; | ||
723 | ecmd_test.duplex = DUPLEX_FULL; | ||
724 | ecmd_test.speed = SPEED_10000; | ||
725 | } | ||
726 | efx->loopback_mode = LOOPBACK_NONE; | ||
672 | 727 | ||
673 | /* Create a selftest_state structure to hold state for the test */ | 728 | rc = efx_reset_up(efx, &ecmd_test, rc == 0); |
674 | state = kzalloc(sizeof(*state), GFP_KERNEL); | 729 | if (rc) { |
675 | if (state == NULL) | 730 | EFX_ERR(efx, "Unable to recover from chip test\n"); |
676 | return -ENOMEM; | 731 | efx_schedule_reset(efx, RESET_TYPE_DISABLE); |
732 | return rc; | ||
733 | } | ||
677 | 734 | ||
678 | /* Set the port loopback_selftest member. From this point on | 735 | tests->loopback_speed = ecmd_test.speed; |
679 | * all received packets will be dropped. Mark the state as | 736 | tests->loopback_full_duplex = ecmd_test.duplex; |
680 | * "flushing" so all inflight packets are dropped */ | ||
681 | BUG_ON(efx->loopback_selftest); | ||
682 | state->flush = true; | ||
683 | efx->loopback_selftest = state; | ||
684 | 737 | ||
685 | rc = efx_test_loopbacks(efx, tests, loopback_modes); | 738 | rc = efx_test_phy(efx, tests); |
739 | if (rc && !rc2) | ||
740 | rc2 = rc; | ||
686 | 741 | ||
687 | efx->loopback_selftest = NULL; | 742 | rc = efx_test_loopbacks(efx, ecmd_test, tests, loopback_modes); |
688 | wmb(); | 743 | if (rc && !rc2) |
689 | kfree(state); | 744 | rc2 = rc; |
690 | 745 | ||
691 | return rc; | 746 | /* restore the PHY to the previous state */ |
747 | efx->loopback_mode = loopback_mode; | ||
748 | efx->phy_mode = phy_mode; | ||
749 | efx->port_inhibited = false; | ||
750 | efx_ethtool_set_settings(efx->net_dev, &ecmd); | ||
751 | |||
752 | return rc2; | ||
692 | } | 753 | } |
693 | 754 | ||