Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/linux...
[sfrench/cifs-2.6.git] / drivers / net / sfc / selftest.c
index 817c7efc11e09b74bffb1f25e84b6e1035225f12..14949bb303a0bca7e87d4fea48e6e4f69d6eca0c 100644 (file)
@@ -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
 #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;
 }