aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/sfc/selftest.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/sfc/selftest.c')
-rw-r--r--drivers/net/sfc/selftest.c146
1 files changed, 77 insertions, 69 deletions
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c
index 817c7efc11e..14949bb303a 100644
--- a/drivers/net/sfc/selftest.c
+++ b/drivers/net/sfc/selftest.c
@@ -1,7 +1,7 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
- * Copyright 2006-2008 Solarflare Communications Inc.
+ * Copyright 2006-2009 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
@@ -20,14 +20,12 @@
#include <linux/rtnetlink.h>
#include <asm/io.h>
#include "net_driver.h"
-#include "ethtool.h"
#include "efx.h"
-#include "falcon.h"
+#include "nic.h"
#include "selftest.h"
-#include "boards.h"
#include "workarounds.h"
#include "spi.h"
-#include "falcon_io.h"
+#include "io.h"
#include "mdio_10g.h"
/*
@@ -57,6 +55,7 @@ static const char *payload_msg =
* @flush: Drop all packets in efx_loopback_rx_packet
* @packet_count: Number of packets being used in this test
* @skbs: An array of skbs transmitted
+ * @offload_csum: Checksums are being offloaded
* @rx_good: RX good packet count
* @rx_bad: RX bad packet count
* @payload: Payload used in tests
@@ -65,10 +64,7 @@ struct efx_loopback_state {
bool flush;
int packet_count;
struct sk_buff **skbs;
-
- /* Checksums are being offloaded */
bool offload_csum;
-
atomic_t rx_good;
atomic_t rx_bad;
struct efx_loopback_payload payload;
@@ -104,7 +100,7 @@ static int efx_test_mdio(struct efx_nic *efx, struct efx_self_tests *tests)
}
if (EFX_IS10G(efx)) {
- rc = efx_mdio_check_mmds(efx, efx->phy_op->mmds, 0);
+ rc = efx_mdio_check_mmds(efx, efx->mdio.mmds, 0);
if (rc)
goto out;
}
@@ -117,23 +113,26 @@ out:
static int efx_test_nvram(struct efx_nic *efx, struct efx_self_tests *tests)
{
- int rc;
+ int rc = 0;
+
+ if (efx->type->test_nvram) {
+ rc = efx->type->test_nvram(efx);
+ tests->nvram = rc ? -1 : 1;
+ }
- rc = falcon_read_nvram(efx, NULL);
- tests->nvram = rc ? -1 : 1;
return rc;
}
static int efx_test_chip(struct efx_nic *efx, struct efx_self_tests *tests)
{
- int rc;
+ int rc = 0;
- /* Not supported on A-series silicon */
- if (falcon_rev(efx) < FALCON_REV_B0)
- return 0;
+ /* Test register access */
+ if (efx->type->test_registers) {
+ rc = efx->type->test_registers(efx);
+ tests->registers = rc ? -1 : 1;
+ }
- rc = falcon_test_registers(efx);
- tests->registers = rc ? -1 : 1;
return rc;
}
@@ -165,7 +164,7 @@ static int efx_test_interrupts(struct efx_nic *efx,
goto success;
}
- falcon_generate_interrupt(efx);
+ efx_nic_generate_interrupt(efx);
/* Wait for arrival of test interrupt. */
EFX_LOG(efx, "waiting for test interrupt\n");
@@ -177,8 +176,8 @@ static int efx_test_interrupts(struct efx_nic *efx,
return -ETIMEDOUT;
success:
- EFX_LOG(efx, "test interrupt (mode %d) seen on CPU%d\n",
- efx->interrupt_mode, efx->last_irq_cpu);
+ EFX_LOG(efx, "%s test interrupt seen on CPU%d\n", INT_MODE(efx),
+ efx->last_irq_cpu);
tests->interrupt = 1;
return 0;
}
@@ -203,7 +202,7 @@ static int efx_test_eventq_irq(struct efx_channel *channel,
channel->eventq_magic = 0;
smp_wmb();
- falcon_generate_test_event(channel, magic);
+ efx_nic_generate_test_event(channel, magic);
/* Wait for arrival of interrupt */
count = 0;
@@ -254,9 +253,6 @@ static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests,
if (!efx->phy_op->run_tests)
return 0;
- EFX_BUG_ON_PARANOID(efx->phy_op->num_tests == 0 ||
- efx->phy_op->num_tests > EFX_MAX_PHY_TESTS);
-
mutex_lock(&efx->mac_lock);
rc = efx->phy_op->run_tests(efx, tests->phy, flags);
mutex_unlock(&efx->mac_lock);
@@ -426,7 +422,7 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue)
if (efx_dev_registered(efx))
netif_tx_lock_bh(efx->net_dev);
- rc = efx_xmit(efx, tx_queue, skb);
+ rc = efx_enqueue_skb(tx_queue, skb);
if (efx_dev_registered(efx))
netif_tx_unlock_bh(efx->net_dev);
@@ -439,7 +435,6 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue)
kfree_skb(skb);
return -EPIPE;
}
- efx->net_dev->trans_start = jiffies;
}
return 0;
@@ -527,7 +522,7 @@ efx_test_loopback(struct efx_tx_queue *tx_queue,
for (i = 0; i < 3; i++) {
/* Determine how many packets to send */
- state->packet_count = (efx->type->txd_ring_mask + 1) / 3;
+ state->packet_count = EFX_TXQ_SIZE / 3;
state->packet_count = min(1 << (i << 2), state->packet_count);
state->skbs = kzalloc(sizeof(state->skbs[0]) *
state->packet_count, GFP_KERNEL);
@@ -568,14 +563,49 @@ efx_test_loopback(struct efx_tx_queue *tx_queue,
return 0;
}
+/* Wait for link up. On Falcon, we would prefer to rely on efx_monitor, but
+ * any contention on the mac lock (via e.g. efx_mac_mcast_work) causes it
+ * to delay and retry. Therefore, it's safer to just poll directly. Wait
+ * for link up and any faults to dissipate. */
+static int efx_wait_for_link(struct efx_nic *efx)
+{
+ struct efx_link_state *link_state = &efx->link_state;
+ int count;
+ bool link_up;
+
+ for (count = 0; count < 40; count++) {
+ schedule_timeout_uninterruptible(HZ / 10);
+
+ if (efx->type->monitor != NULL) {
+ mutex_lock(&efx->mac_lock);
+ efx->type->monitor(efx);
+ mutex_unlock(&efx->mac_lock);
+ } else {
+ struct efx_channel *channel = &efx->channel[0];
+ if (channel->work_pending)
+ efx_process_channel_now(channel);
+ }
+
+ mutex_lock(&efx->mac_lock);
+ link_up = link_state->up;
+ if (link_up)
+ link_up = !efx->mac_op->check_fault(efx);
+ mutex_unlock(&efx->mac_lock);
+
+ if (link_up)
+ return 0;
+ }
+
+ return -ETIMEDOUT;
+}
+
static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests,
unsigned int loopback_modes)
{
enum efx_loopback_mode mode;
struct efx_loopback_state *state;
struct efx_tx_queue *tx_queue;
- bool link_up;
- int count, rc = 0;
+ int rc = 0;
/* Set the port loopback_selftest member. From this point on
* all received packets will be dropped. Mark the state as
@@ -594,46 +624,23 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests,
/* Move the port into the specified loopback mode. */
state->flush = true;
+ mutex_lock(&efx->mac_lock);
efx->loopback_mode = mode;
- efx_reconfigure_port(efx);
-
- /* Wait for the PHY to signal the link is up. Interrupts
- * are enabled for PHY's using LASI, otherwise we poll()
- * quickly */
- count = 0;
- do {
- struct efx_channel *channel = &efx->channel[0];
+ rc = __efx_reconfigure_port(efx);
+ mutex_unlock(&efx->mac_lock);
+ if (rc) {
+ EFX_ERR(efx, "unable to move into %s loopback\n",
+ LOOPBACK_MODE(efx));
+ goto out;
+ }
- efx->phy_op->poll(efx);
- schedule_timeout_uninterruptible(HZ / 10);
- if (channel->work_pending)
- efx_process_channel_now(channel);
- /* Wait for PHY events to be processed */
- flush_workqueue(efx->workqueue);
- rmb();
-
- /* We need both the phy and xaui links to be ok.
- * rather than relying on the falcon_xmac irq/poll
- * regime, just poll xaui directly */
- link_up = efx->link_up;
- if (link_up && EFX_IS10G(efx) &&
- !falcon_xaui_link_ok(efx))
- link_up = false;
-
- } while ((++count < 20) && !link_up);
-
- /* The link should now be up. If it isn't, there is no point
- * in attempting a loopback test */
- if (!link_up) {
+ rc = efx_wait_for_link(efx);
+ if (rc) {
EFX_ERR(efx, "loopback %s never came up\n",
LOOPBACK_MODE(efx));
- rc = -EIO;
goto out;
}
- EFX_LOG(efx, "link came up in %s loopback in %d iterations\n",
- LOOPBACK_MODE(efx), count);
-
/* Test every TX queue */
efx_for_each_tx_queue(tx_queue, efx) {
state->offload_csum = (tx_queue->queue ==
@@ -667,7 +674,6 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
enum efx_loopback_mode loopback_mode = efx->loopback_mode;
int phy_mode = efx->phy_mode;
enum reset_type reset_method = RESET_TYPE_INVISIBLE;
- struct ethtool_cmd ecmd;
struct efx_channel *channel;
int rc_test = 0, rc_reset = 0, rc;
@@ -720,21 +726,21 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
mutex_unlock(&efx->mac_lock);
/* free up all consumers of SRAM (including all the queues) */
- efx_reset_down(efx, reset_method, &ecmd);
+ efx_reset_down(efx, reset_method);
rc = efx_test_chip(efx, tests);
if (rc && !rc_test)
rc_test = rc;
/* reset the chip to recover from the register test */
- rc_reset = falcon_reset_hw(efx, reset_method);
+ rc_reset = efx->type->reset(efx, reset_method);
/* Ensure that the phy is powered and out of loopback
* for the bist and loopback tests */
efx->phy_mode &= ~PHY_MODE_LOW_POWER;
efx->loopback_mode = LOOPBACK_NONE;
- rc = efx_reset_up(efx, reset_method, &ecmd, rc_reset == 0);
+ rc = efx_reset_up(efx, reset_method, rc_reset == 0);
if (rc && !rc_reset)
rc_reset = rc;
@@ -753,10 +759,12 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
rc_test = rc;
/* restore the PHY to the previous state */
- efx->loopback_mode = loopback_mode;
+ mutex_lock(&efx->mac_lock);
efx->phy_mode = phy_mode;
efx->port_inhibited = false;
- efx_ethtool_set_settings(efx->net_dev, &ecmd);
+ efx->loopback_mode = loopback_mode;
+ __efx_reconfigure_port(efx);
+ mutex_unlock(&efx->mac_lock);
return rc_test;
}