diff options
Diffstat (limited to 'drivers/net/sfc/selftest.c')
-rw-r--r-- | drivers/net/sfc/selftest.c | 183 |
1 files changed, 83 insertions, 100 deletions
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 817c7efc11e0..0106b1d9aae2 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /**************************************************************************** | 1 | /**************************************************************************** |
2 | * Driver for Solarflare Solarstorm network controllers and boards | 2 | * Driver for Solarflare Solarstorm network controllers and boards |
3 | * Copyright 2005-2006 Fen Systems Ltd. | 3 | * Copyright 2005-2006 Fen Systems Ltd. |
4 | * Copyright 2006-2008 Solarflare Communications Inc. | 4 | * Copyright 2006-2009 Solarflare Communications Inc. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms of the GNU General Public License version 2 as published | 7 | * under the terms of the GNU General Public License version 2 as published |
@@ -18,17 +18,13 @@ | |||
18 | #include <linux/in.h> | 18 | #include <linux/in.h> |
19 | #include <linux/udp.h> | 19 | #include <linux/udp.h> |
20 | #include <linux/rtnetlink.h> | 20 | #include <linux/rtnetlink.h> |
21 | #include <linux/slab.h> | ||
21 | #include <asm/io.h> | 22 | #include <asm/io.h> |
22 | #include "net_driver.h" | 23 | #include "net_driver.h" |
23 | #include "ethtool.h" | ||
24 | #include "efx.h" | 24 | #include "efx.h" |
25 | #include "falcon.h" | 25 | #include "nic.h" |
26 | #include "selftest.h" | 26 | #include "selftest.h" |
27 | #include "boards.h" | ||
28 | #include "workarounds.h" | 27 | #include "workarounds.h" |
29 | #include "spi.h" | ||
30 | #include "falcon_io.h" | ||
31 | #include "mdio_10g.h" | ||
32 | 28 | ||
33 | /* | 29 | /* |
34 | * Loopback test packet structure | 30 | * Loopback test packet structure |
@@ -49,7 +45,7 @@ static const unsigned char payload_source[ETH_ALEN] = { | |||
49 | 0x00, 0x0f, 0x53, 0x1b, 0x1b, 0x1b, | 45 | 0x00, 0x0f, 0x53, 0x1b, 0x1b, 0x1b, |
50 | }; | 46 | }; |
51 | 47 | ||
52 | static const char *payload_msg = | 48 | static const char payload_msg[] = |
53 | "Hello world! This is an Efx loopback test in progress!"; | 49 | "Hello world! This is an Efx loopback test in progress!"; |
54 | 50 | ||
55 | /** | 51 | /** |
@@ -57,6 +53,7 @@ static const char *payload_msg = | |||
57 | * @flush: Drop all packets in efx_loopback_rx_packet | 53 | * @flush: Drop all packets in efx_loopback_rx_packet |
58 | * @packet_count: Number of packets being used in this test | 54 | * @packet_count: Number of packets being used in this test |
59 | * @skbs: An array of skbs transmitted | 55 | * @skbs: An array of skbs transmitted |
56 | * @offload_csum: Checksums are being offloaded | ||
60 | * @rx_good: RX good packet count | 57 | * @rx_good: RX good packet count |
61 | * @rx_bad: RX bad packet count | 58 | * @rx_bad: RX bad packet count |
62 | * @payload: Payload used in tests | 59 | * @payload: Payload used in tests |
@@ -65,10 +62,7 @@ struct efx_loopback_state { | |||
65 | bool flush; | 62 | bool flush; |
66 | int packet_count; | 63 | int packet_count; |
67 | struct sk_buff **skbs; | 64 | struct sk_buff **skbs; |
68 | |||
69 | /* Checksums are being offloaded */ | ||
70 | bool offload_csum; | 65 | bool offload_csum; |
71 | |||
72 | atomic_t rx_good; | 66 | atomic_t rx_good; |
73 | atomic_t rx_bad; | 67 | atomic_t rx_bad; |
74 | struct efx_loopback_payload payload; | 68 | struct efx_loopback_payload payload; |
@@ -80,60 +74,40 @@ struct efx_loopback_state { | |||
80 | * | 74 | * |
81 | **************************************************************************/ | 75 | **************************************************************************/ |
82 | 76 | ||
83 | static int efx_test_mdio(struct efx_nic *efx, struct efx_self_tests *tests) | 77 | static int efx_test_phy_alive(struct efx_nic *efx, struct efx_self_tests *tests) |
84 | { | 78 | { |
85 | int rc = 0; | 79 | int rc = 0; |
86 | int devad = __ffs(efx->mdio.mmds); | ||
87 | u16 physid1, physid2; | ||
88 | |||
89 | if (efx->phy_type == PHY_TYPE_NONE) | ||
90 | return 0; | ||
91 | |||
92 | mutex_lock(&efx->mac_lock); | ||
93 | tests->mdio = -1; | ||
94 | |||
95 | physid1 = efx_mdio_read(efx, devad, MDIO_DEVID1); | ||
96 | physid2 = efx_mdio_read(efx, devad, MDIO_DEVID2); | ||
97 | 80 | ||
98 | if ((physid1 == 0x0000) || (physid1 == 0xffff) || | 81 | if (efx->phy_op->test_alive) { |
99 | (physid2 == 0x0000) || (physid2 == 0xffff)) { | 82 | rc = efx->phy_op->test_alive(efx); |
100 | EFX_ERR(efx, "no MDIO PHY present with ID %d\n", | 83 | tests->phy_alive = rc ? -1 : 1; |
101 | efx->mdio.prtad); | ||
102 | rc = -EINVAL; | ||
103 | goto out; | ||
104 | } | 84 | } |
105 | 85 | ||
106 | if (EFX_IS10G(efx)) { | ||
107 | rc = efx_mdio_check_mmds(efx, efx->phy_op->mmds, 0); | ||
108 | if (rc) | ||
109 | goto out; | ||
110 | } | ||
111 | |||
112 | out: | ||
113 | mutex_unlock(&efx->mac_lock); | ||
114 | tests->mdio = rc ? -1 : 1; | ||
115 | return rc; | 86 | return rc; |
116 | } | 87 | } |
117 | 88 | ||
118 | static int efx_test_nvram(struct efx_nic *efx, struct efx_self_tests *tests) | 89 | static int efx_test_nvram(struct efx_nic *efx, struct efx_self_tests *tests) |
119 | { | 90 | { |
120 | int rc; | 91 | int rc = 0; |
92 | |||
93 | if (efx->type->test_nvram) { | ||
94 | rc = efx->type->test_nvram(efx); | ||
95 | tests->nvram = rc ? -1 : 1; | ||
96 | } | ||
121 | 97 | ||
122 | rc = falcon_read_nvram(efx, NULL); | ||
123 | tests->nvram = rc ? -1 : 1; | ||
124 | return rc; | 98 | return rc; |
125 | } | 99 | } |
126 | 100 | ||
127 | static int efx_test_chip(struct efx_nic *efx, struct efx_self_tests *tests) | 101 | static int efx_test_chip(struct efx_nic *efx, struct efx_self_tests *tests) |
128 | { | 102 | { |
129 | int rc; | 103 | int rc = 0; |
130 | 104 | ||
131 | /* Not supported on A-series silicon */ | 105 | /* Test register access */ |
132 | if (falcon_rev(efx) < FALCON_REV_B0) | 106 | if (efx->type->test_registers) { |
133 | return 0; | 107 | rc = efx->type->test_registers(efx); |
108 | tests->registers = rc ? -1 : 1; | ||
109 | } | ||
134 | 110 | ||
135 | rc = falcon_test_registers(efx); | ||
136 | tests->registers = rc ? -1 : 1; | ||
137 | return rc; | 111 | return rc; |
138 | } | 112 | } |
139 | 113 | ||
@@ -165,7 +139,7 @@ static int efx_test_interrupts(struct efx_nic *efx, | |||
165 | goto success; | 139 | goto success; |
166 | } | 140 | } |
167 | 141 | ||
168 | falcon_generate_interrupt(efx); | 142 | efx_nic_generate_interrupt(efx); |
169 | 143 | ||
170 | /* Wait for arrival of test interrupt. */ | 144 | /* Wait for arrival of test interrupt. */ |
171 | EFX_LOG(efx, "waiting for test interrupt\n"); | 145 | EFX_LOG(efx, "waiting for test interrupt\n"); |
@@ -177,8 +151,8 @@ static int efx_test_interrupts(struct efx_nic *efx, | |||
177 | return -ETIMEDOUT; | 151 | return -ETIMEDOUT; |
178 | 152 | ||
179 | success: | 153 | success: |
180 | EFX_LOG(efx, "test interrupt (mode %d) seen on CPU%d\n", | 154 | EFX_LOG(efx, "%s test interrupt seen on CPU%d\n", INT_MODE(efx), |
181 | efx->interrupt_mode, efx->last_irq_cpu); | 155 | efx->last_irq_cpu); |
182 | tests->interrupt = 1; | 156 | tests->interrupt = 1; |
183 | return 0; | 157 | return 0; |
184 | } | 158 | } |
@@ -203,7 +177,7 @@ static int efx_test_eventq_irq(struct efx_channel *channel, | |||
203 | channel->eventq_magic = 0; | 177 | channel->eventq_magic = 0; |
204 | smp_wmb(); | 178 | smp_wmb(); |
205 | 179 | ||
206 | falcon_generate_test_event(channel, magic); | 180 | efx_nic_generate_test_event(channel, magic); |
207 | 181 | ||
208 | /* Wait for arrival of interrupt */ | 182 | /* Wait for arrival of interrupt */ |
209 | count = 0; | 183 | count = 0; |
@@ -254,11 +228,8 @@ static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests, | |||
254 | if (!efx->phy_op->run_tests) | 228 | if (!efx->phy_op->run_tests) |
255 | return 0; | 229 | return 0; |
256 | 230 | ||
257 | EFX_BUG_ON_PARANOID(efx->phy_op->num_tests == 0 || | ||
258 | efx->phy_op->num_tests > EFX_MAX_PHY_TESTS); | ||
259 | |||
260 | mutex_lock(&efx->mac_lock); | 231 | mutex_lock(&efx->mac_lock); |
261 | rc = efx->phy_op->run_tests(efx, tests->phy, flags); | 232 | rc = efx->phy_op->run_tests(efx, tests->phy_ext, flags); |
262 | mutex_unlock(&efx->mac_lock); | 233 | mutex_unlock(&efx->mac_lock); |
263 | return rc; | 234 | return rc; |
264 | } | 235 | } |
@@ -426,7 +397,7 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue) | |||
426 | 397 | ||
427 | if (efx_dev_registered(efx)) | 398 | if (efx_dev_registered(efx)) |
428 | netif_tx_lock_bh(efx->net_dev); | 399 | netif_tx_lock_bh(efx->net_dev); |
429 | rc = efx_xmit(efx, tx_queue, skb); | 400 | rc = efx_enqueue_skb(tx_queue, skb); |
430 | if (efx_dev_registered(efx)) | 401 | if (efx_dev_registered(efx)) |
431 | netif_tx_unlock_bh(efx->net_dev); | 402 | netif_tx_unlock_bh(efx->net_dev); |
432 | 403 | ||
@@ -439,7 +410,6 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue) | |||
439 | kfree_skb(skb); | 410 | kfree_skb(skb); |
440 | return -EPIPE; | 411 | return -EPIPE; |
441 | } | 412 | } |
442 | efx->net_dev->trans_start = jiffies; | ||
443 | } | 413 | } |
444 | 414 | ||
445 | return 0; | 415 | return 0; |
@@ -527,7 +497,7 @@ efx_test_loopback(struct efx_tx_queue *tx_queue, | |||
527 | 497 | ||
528 | for (i = 0; i < 3; i++) { | 498 | for (i = 0; i < 3; i++) { |
529 | /* Determine how many packets to send */ | 499 | /* Determine how many packets to send */ |
530 | state->packet_count = (efx->type->txd_ring_mask + 1) / 3; | 500 | state->packet_count = EFX_TXQ_SIZE / 3; |
531 | state->packet_count = min(1 << (i << 2), state->packet_count); | 501 | state->packet_count = min(1 << (i << 2), state->packet_count); |
532 | state->skbs = kzalloc(sizeof(state->skbs[0]) * | 502 | state->skbs = kzalloc(sizeof(state->skbs[0]) * |
533 | state->packet_count, GFP_KERNEL); | 503 | state->packet_count, GFP_KERNEL); |
@@ -568,14 +538,49 @@ efx_test_loopback(struct efx_tx_queue *tx_queue, | |||
568 | return 0; | 538 | return 0; |
569 | } | 539 | } |
570 | 540 | ||
541 | /* Wait for link up. On Falcon, we would prefer to rely on efx_monitor, but | ||
542 | * any contention on the mac lock (via e.g. efx_mac_mcast_work) causes it | ||
543 | * to delay and retry. Therefore, it's safer to just poll directly. Wait | ||
544 | * for link up and any faults to dissipate. */ | ||
545 | static int efx_wait_for_link(struct efx_nic *efx) | ||
546 | { | ||
547 | struct efx_link_state *link_state = &efx->link_state; | ||
548 | int count; | ||
549 | bool link_up; | ||
550 | |||
551 | for (count = 0; count < 40; count++) { | ||
552 | schedule_timeout_uninterruptible(HZ / 10); | ||
553 | |||
554 | if (efx->type->monitor != NULL) { | ||
555 | mutex_lock(&efx->mac_lock); | ||
556 | efx->type->monitor(efx); | ||
557 | mutex_unlock(&efx->mac_lock); | ||
558 | } else { | ||
559 | struct efx_channel *channel = &efx->channel[0]; | ||
560 | if (channel->work_pending) | ||
561 | efx_process_channel_now(channel); | ||
562 | } | ||
563 | |||
564 | mutex_lock(&efx->mac_lock); | ||
565 | link_up = link_state->up; | ||
566 | if (link_up) | ||
567 | link_up = !efx->mac_op->check_fault(efx); | ||
568 | mutex_unlock(&efx->mac_lock); | ||
569 | |||
570 | if (link_up) | ||
571 | return 0; | ||
572 | } | ||
573 | |||
574 | return -ETIMEDOUT; | ||
575 | } | ||
576 | |||
571 | static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, | 577 | static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, |
572 | unsigned int loopback_modes) | 578 | unsigned int loopback_modes) |
573 | { | 579 | { |
574 | enum efx_loopback_mode mode; | 580 | enum efx_loopback_mode mode; |
575 | struct efx_loopback_state *state; | 581 | struct efx_loopback_state *state; |
576 | struct efx_tx_queue *tx_queue; | 582 | struct efx_tx_queue *tx_queue; |
577 | bool link_up; | 583 | int rc = 0; |
578 | int count, rc = 0; | ||
579 | 584 | ||
580 | /* Set the port loopback_selftest member. From this point on | 585 | /* Set the port loopback_selftest member. From this point on |
581 | * all received packets will be dropped. Mark the state as | 586 | * all received packets will be dropped. Mark the state as |
@@ -594,46 +599,23 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, | |||
594 | 599 | ||
595 | /* Move the port into the specified loopback mode. */ | 600 | /* Move the port into the specified loopback mode. */ |
596 | state->flush = true; | 601 | state->flush = true; |
602 | mutex_lock(&efx->mac_lock); | ||
597 | efx->loopback_mode = mode; | 603 | efx->loopback_mode = mode; |
598 | efx_reconfigure_port(efx); | 604 | rc = __efx_reconfigure_port(efx); |
599 | 605 | mutex_unlock(&efx->mac_lock); | |
600 | /* Wait for the PHY to signal the link is up. Interrupts | 606 | if (rc) { |
601 | * are enabled for PHY's using LASI, otherwise we poll() | 607 | EFX_ERR(efx, "unable to move into %s loopback\n", |
602 | * quickly */ | 608 | LOOPBACK_MODE(efx)); |
603 | count = 0; | 609 | goto out; |
604 | do { | 610 | } |
605 | struct efx_channel *channel = &efx->channel[0]; | ||
606 | 611 | ||
607 | efx->phy_op->poll(efx); | 612 | rc = efx_wait_for_link(efx); |
608 | schedule_timeout_uninterruptible(HZ / 10); | 613 | if (rc) { |
609 | if (channel->work_pending) | ||
610 | efx_process_channel_now(channel); | ||
611 | /* Wait for PHY events to be processed */ | ||
612 | flush_workqueue(efx->workqueue); | ||
613 | rmb(); | ||
614 | |||
615 | /* We need both the phy and xaui links to be ok. | ||
616 | * rather than relying on the falcon_xmac irq/poll | ||
617 | * regime, just poll xaui directly */ | ||
618 | link_up = efx->link_up; | ||
619 | if (link_up && EFX_IS10G(efx) && | ||
620 | !falcon_xaui_link_ok(efx)) | ||
621 | link_up = false; | ||
622 | |||
623 | } while ((++count < 20) && !link_up); | ||
624 | |||
625 | /* The link should now be up. If it isn't, there is no point | ||
626 | * in attempting a loopback test */ | ||
627 | if (!link_up) { | ||
628 | EFX_ERR(efx, "loopback %s never came up\n", | 614 | EFX_ERR(efx, "loopback %s never came up\n", |
629 | LOOPBACK_MODE(efx)); | 615 | LOOPBACK_MODE(efx)); |
630 | rc = -EIO; | ||
631 | goto out; | 616 | goto out; |
632 | } | 617 | } |
633 | 618 | ||
634 | EFX_LOG(efx, "link came up in %s loopback in %d iterations\n", | ||
635 | LOOPBACK_MODE(efx), count); | ||
636 | |||
637 | /* Test every TX queue */ | 619 | /* Test every TX queue */ |
638 | efx_for_each_tx_queue(tx_queue, efx) { | 620 | efx_for_each_tx_queue(tx_queue, efx) { |
639 | state->offload_csum = (tx_queue->queue == | 621 | state->offload_csum = (tx_queue->queue == |
@@ -667,14 +649,13 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, | |||
667 | enum efx_loopback_mode loopback_mode = efx->loopback_mode; | 649 | enum efx_loopback_mode loopback_mode = efx->loopback_mode; |
668 | int phy_mode = efx->phy_mode; | 650 | int phy_mode = efx->phy_mode; |
669 | enum reset_type reset_method = RESET_TYPE_INVISIBLE; | 651 | enum reset_type reset_method = RESET_TYPE_INVISIBLE; |
670 | struct ethtool_cmd ecmd; | ||
671 | struct efx_channel *channel; | 652 | struct efx_channel *channel; |
672 | int rc_test = 0, rc_reset = 0, rc; | 653 | int rc_test = 0, rc_reset = 0, rc; |
673 | 654 | ||
674 | /* Online (i.e. non-disruptive) testing | 655 | /* Online (i.e. non-disruptive) testing |
675 | * This checks interrupt generation, event delivery and PHY presence. */ | 656 | * This checks interrupt generation, event delivery and PHY presence. */ |
676 | 657 | ||
677 | rc = efx_test_mdio(efx, tests); | 658 | rc = efx_test_phy_alive(efx, tests); |
678 | if (rc && !rc_test) | 659 | if (rc && !rc_test) |
679 | rc_test = rc; | 660 | rc_test = rc; |
680 | 661 | ||
@@ -720,21 +701,21 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, | |||
720 | mutex_unlock(&efx->mac_lock); | 701 | mutex_unlock(&efx->mac_lock); |
721 | 702 | ||
722 | /* free up all consumers of SRAM (including all the queues) */ | 703 | /* free up all consumers of SRAM (including all the queues) */ |
723 | efx_reset_down(efx, reset_method, &ecmd); | 704 | efx_reset_down(efx, reset_method); |
724 | 705 | ||
725 | rc = efx_test_chip(efx, tests); | 706 | rc = efx_test_chip(efx, tests); |
726 | if (rc && !rc_test) | 707 | if (rc && !rc_test) |
727 | rc_test = rc; | 708 | rc_test = rc; |
728 | 709 | ||
729 | /* reset the chip to recover from the register test */ | 710 | /* reset the chip to recover from the register test */ |
730 | rc_reset = falcon_reset_hw(efx, reset_method); | 711 | rc_reset = efx->type->reset(efx, reset_method); |
731 | 712 | ||
732 | /* Ensure that the phy is powered and out of loopback | 713 | /* Ensure that the phy is powered and out of loopback |
733 | * for the bist and loopback tests */ | 714 | * for the bist and loopback tests */ |
734 | efx->phy_mode &= ~PHY_MODE_LOW_POWER; | 715 | efx->phy_mode &= ~PHY_MODE_LOW_POWER; |
735 | efx->loopback_mode = LOOPBACK_NONE; | 716 | efx->loopback_mode = LOOPBACK_NONE; |
736 | 717 | ||
737 | rc = efx_reset_up(efx, reset_method, &ecmd, rc_reset == 0); | 718 | rc = efx_reset_up(efx, reset_method, rc_reset == 0); |
738 | if (rc && !rc_reset) | 719 | if (rc && !rc_reset) |
739 | rc_reset = rc; | 720 | rc_reset = rc; |
740 | 721 | ||
@@ -753,10 +734,12 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, | |||
753 | rc_test = rc; | 734 | rc_test = rc; |
754 | 735 | ||
755 | /* restore the PHY to the previous state */ | 736 | /* restore the PHY to the previous state */ |
756 | efx->loopback_mode = loopback_mode; | 737 | mutex_lock(&efx->mac_lock); |
757 | efx->phy_mode = phy_mode; | 738 | efx->phy_mode = phy_mode; |
758 | efx->port_inhibited = false; | 739 | efx->port_inhibited = false; |
759 | efx_ethtool_set_settings(efx->net_dev, &ecmd); | 740 | efx->loopback_mode = loopback_mode; |
741 | __efx_reconfigure_port(efx); | ||
742 | mutex_unlock(&efx->mac_lock); | ||
760 | 743 | ||
761 | return rc_test; | 744 | return rc_test; |
762 | } | 745 | } |