r6040: fix link checking with switches
[safe/jmp/linux-2.6] / drivers / net / sfc / falcon_xmac.c
index e57545d..c84a2ce 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
@@ -11,7 +11,7 @@
 #include <linux/delay.h>
 #include "net_driver.h"
 #include "efx.h"
-#include "falcon.h"
+#include "nic.h"
 #include "regs.h"
 #include "io.h"
 #include "mac.h"
@@ -26,7 +26,7 @@
  *************************************************************************/
 
 /* Configure the XAUI driver that is an output from Falcon */
-static void falcon_setup_xaui(struct efx_nic *efx)
+void falcon_setup_xaui(struct efx_nic *efx)
 {
        efx_oword_t sdctl, txdrv;
 
@@ -85,42 +85,31 @@ int falcon_reset_xaui(struct efx_nic *efx)
        return -ETIMEDOUT;
 }
 
-static void falcon_mask_status_intr(struct efx_nic *efx, bool enable)
+static void falcon_ack_status_intr(struct efx_nic *efx)
 {
        efx_oword_t reg;
 
-       if ((falcon_rev(efx) != FALCON_REV_B0) || LOOPBACK_INTERNAL(efx))
+       if ((efx_nic_rev(efx) != EFX_REV_FALCON_B0) || LOOPBACK_INTERNAL(efx))
                return;
 
-       /* We expect xgmii faults if the wireside link is up */
+       /* We expect xgmii faults if the wireside link is down */
        if (!EFX_WORKAROUND_5147(efx) || !efx->link_state.up)
                return;
 
        /* We can only use this interrupt to signal the negative edge of
         * xaui_align [we have to poll the positive edge]. */
-       if (!efx->mac_up)
+       if (efx->xmac_poll_required)
                return;
 
-       /* Flush the ISR */
-       if (enable)
-               efx_reado(efx, &reg, FR_AB_XM_MGT_INT_MSK);
-
-       EFX_POPULATE_OWORD_2(reg,
-                            FRF_AB_XM_MSK_RMTFLT, !enable,
-                            FRF_AB_XM_MSK_LCLFLT, !enable);
-       efx_writeo(efx, &reg, FR_AB_XM_MGT_INT_MASK);
+       efx_reado(efx, &reg, FR_AB_XM_MGT_INT_MSK);
 }
 
-/* Get status of XAUI link */
-bool falcon_xaui_link_ok(struct efx_nic *efx)
+static bool falcon_xgxs_link_ok(struct efx_nic *efx)
 {
        efx_oword_t reg;
        bool align_done, link_ok = false;
        int sync_status;
 
-       if (LOOPBACK_INTERNAL(efx))
-               return true;
-
        /* Read link status */
        efx_reado(efx, &reg, FR_AB_XX_CORE_STAT);
 
@@ -135,19 +124,30 @@ bool falcon_xaui_link_ok(struct efx_nic *efx)
        EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_DISPERR, FFE_AB_XX_STAT_ALL_LANES);
        efx_writeo(efx, &reg, FR_AB_XX_CORE_STAT);
 
-       /* If the link is up, then check the phy side of the xaui link */
-       if (efx->link_state.up && link_ok)
-               if (efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS))
-                       link_ok = efx_mdio_phyxgxs_lane_sync(efx);
-
        return link_ok;
 }
 
-static void falcon_reconfigure_xmac_core(struct efx_nic *efx)
+static bool falcon_xmac_link_ok(struct efx_nic *efx)
+{
+       /*
+        * Check MAC's XGXS link status except when using XGMII loopback
+        * which bypasses the XGXS block.
+        * If possible, check PHY's XGXS link status except when using
+        * MAC loopback.
+        */
+       return (efx->loopback_mode == LOOPBACK_XGMII ||
+               falcon_xgxs_link_ok(efx)) &&
+               (!(efx->mdio.mmds & (1 << MDIO_MMD_PHYXS)) ||
+                LOOPBACK_INTERNAL(efx) || 
+                efx_mdio_phyxgxs_lane_sync(efx));
+}
+
+void falcon_reconfigure_xmac_core(struct efx_nic *efx)
 {
        unsigned int max_frame_len;
        efx_oword_t reg;
        bool rx_fc = !!(efx->link_state.fc & EFX_FC_RX);
+       bool tx_fc = !!(efx->link_state.fc & EFX_FC_TX);
 
        /* Configure MAC  - cut-thru mode is hard wired on */
        EFX_POPULATE_OWORD_3(reg,
@@ -162,7 +162,7 @@ static void falcon_reconfigure_xmac_core(struct efx_nic *efx)
                             FRF_AB_XM_TX_PRMBL, 1,
                             FRF_AB_XM_AUTO_PAD, 1,
                             FRF_AB_XM_TXCRC, 1,
-                            FRF_AB_XM_FCNTL, 1,
+                            FRF_AB_XM_FCNTL, tx_fc,
                             FRF_AB_XM_IPG, 0x3);
        efx_writeo(efx, &reg, FR_AB_XM_TX_CFG);
 
@@ -243,42 +243,48 @@ static void falcon_reconfigure_xgxs_core(struct efx_nic *efx)
 }
 
 
-/* Try and bring the Falcon side of the Falcon-Phy XAUI link fails
- * to come back up. Bash it until it comes back up */
-static void falcon_check_xaui_link_up(struct efx_nic *efx, int tries)
+/* Try to bring up the Falcon side of the Falcon-Phy XAUI link */
+static bool falcon_xmac_link_ok_retry(struct efx_nic *efx, int tries)
 {
-       efx->mac_up = falcon_xaui_link_ok(efx);
+       bool mac_up = falcon_xmac_link_ok(efx);
 
-       if ((efx->loopback_mode == LOOPBACK_NETWORK) ||
+       if (LOOPBACK_MASK(efx) & LOOPBACKS_EXTERNAL(efx) & LOOPBACKS_WS ||
            efx_phy_mode_disabled(efx->phy_mode))
                /* XAUI link is expected to be down */
-               return;
+               return mac_up;
 
        falcon_stop_nic_stats(efx);
 
-       while (!efx->mac_up && tries) {
+       while (!mac_up && tries) {
                EFX_LOG(efx, "bashing xaui\n");
                falcon_reset_xaui(efx);
                udelay(200);
 
-               efx->mac_up = falcon_xaui_link_ok(efx);
+               mac_up = falcon_xmac_link_ok(efx);
                --tries;
        }
 
        falcon_start_nic_stats(efx);
+
+       return mac_up;
 }
 
-static void falcon_reconfigure_xmac(struct efx_nic *efx)
+static bool falcon_xmac_check_fault(struct efx_nic *efx)
 {
-       falcon_mask_status_intr(efx, false);
+       return !falcon_xmac_link_ok_retry(efx, 5);
+}
 
+static int falcon_reconfigure_xmac(struct efx_nic *efx)
+{
        falcon_reconfigure_xgxs_core(efx);
        falcon_reconfigure_xmac_core(efx);
 
        falcon_reconfigure_mac_wrapper(efx);
 
-       falcon_check_xaui_link_up(efx, 5);
-       falcon_mask_status_intr(efx, true);
+       efx->xmac_poll_required = !falcon_xmac_link_ok_retry(efx, 5);
+       falcon_ack_status_intr(efx);
+
+       return 0;
 }
 
 static void falcon_update_stats_xmac(struct efx_nic *efx)
@@ -341,35 +347,18 @@ static void falcon_update_stats_xmac(struct efx_nic *efx)
                 mac_stats->rx_control * 64);
 }
 
-static void falcon_xmac_irq(struct efx_nic *efx)
-{
-       /* The XGMII link has a transient fault, which indicates either:
-        *   - there's a transient xgmii fault
-        *   - falcon's end of the xaui link may need a kick
-        *   - the wire-side link may have gone down, but the lasi/poll()
-        *     hasn't noticed yet.
-        *
-        * We only want to even bother polling XAUI if we're confident it's
-        * not (1) or (3). In both cases, the only reliable way to spot this
-        * is to wait a bit. We do this here by forcing the mac link state
-        * to down, and waiting for the mac poll to come round and check
-        */
-       efx->mac_up = false;
-}
-
-static void falcon_poll_xmac(struct efx_nic *efx)
+void falcon_poll_xmac(struct efx_nic *efx)
 {
-       if (!EFX_WORKAROUND_5147(efx) || !efx->link_state.up || efx->mac_up)
+       if (!EFX_WORKAROUND_5147(efx) || !efx->link_state.up ||
+           !efx->xmac_poll_required)
                return;
 
-       falcon_mask_status_intr(efx, false);
-       falcon_check_xaui_link_up(efx, 1);
-       falcon_mask_status_intr(efx, true);
+       efx->xmac_poll_required = !falcon_xmac_link_ok_retry(efx, 1);
+       falcon_ack_status_intr(efx);
 }
 
 struct efx_mac_operations falcon_xmac_operations = {
        .reconfigure    = falcon_reconfigure_xmac,
        .update_stats   = falcon_update_stats_xmac,
-       .irq            = falcon_xmac_irq,
-       .poll           = falcon_poll_xmac,
+       .check_fault    = falcon_xmac_check_fault,
 };