sfc: Update version, copyright dates, authors
[pandora-kernel.git] / drivers / net / sfc / selftest.c
index 74e84af..14949bb 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
@@ -21,7 +21,7 @@
 #include <asm/io.h>
 #include "net_driver.h"
 #include "efx.h"
-#include "falcon.h"
+#include "nic.h"
 #include "selftest.h"
 #include "workarounds.h"
 #include "spi.h"
@@ -100,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;
        }
@@ -113,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 (efx_nic_rev(efx) < EFX_REV_FALCON_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;
 }
 
@@ -161,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");
@@ -199,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;
@@ -250,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);
@@ -563,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
@@ -589,43 +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];
-
-                       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 MAC-PHY links to be OK */
-                       link_up = efx->link_state.up;
-                       if (link_up)
-                               link_up = !efx->mac_op->check_fault(efx);
-
-               } while ((++count < 20) && !link_up);
+               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;
+               }
 
-               /* 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 ==
@@ -659,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;
 
@@ -712,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;
 
@@ -745,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;
 }