summaryrefslogtreecommitdiff
path: root/drivers/net/sfc/falcon.c
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2009-11-29 03:42:41 +0000
committerDavid S. Miller <davem@davemloft.net>2009-11-29 16:46:28 -0800
commitd3245b28ef2a45ec4e115062a38100bd06229289 (patch)
tree036133fdf01a20f36086d5eb8606728859c056de /drivers/net/sfc/falcon.c
parentef2b90ee4dba7a3d9001f1f0003b860b39a4aaae (diff)
sfc: Refactor link configuration
Refactor PHY, MAC and NIC configuration operations so that the existing link configuration can be re-pushed with: efx->phy_op->reconfigure(efx); efx->mac_op->reconfigure(efx); and a new configuration with: efx->nic_op->reconfigure_port(efx); (plus locking and error-checking). We have not held the link settings in software (aside from flow control), and have relied on asking the hardware what they are. This is a problem because in some cases the hardware may no longer be in a state to tell us. In particular, if an entire multi-port board is reset through one port, the driver bindings to other ports have no chance to save settings before recovering. We only actually need to keep track of the autonegotiation settings, so add an ethtool advertising mask to struct efx_nic, initialise it in PHY init and update it as necessary. Remove now-unneeded uses of efx_phy_op::{get,set}_settings() and struct ethtool_cmd. Much of this was done by Steve Hodgson <shodgson@solarflare.com>. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/sfc/falcon.c')
-rw-r--r--drivers/net/sfc/falcon.c98
1 files changed, 63 insertions, 35 deletions
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index f6d10213d0b7..3466616c01c0 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -1193,6 +1193,8 @@ static void falcon_poll_flush_events(struct efx_nic *efx)
channel->eventq_read_ptr = read_ptr;
}
+static void falcon_deconfigure_mac_wrapper(struct efx_nic *efx);
+
static void falcon_prepare_flush(struct efx_nic *efx)
{
falcon_deconfigure_mac_wrapper(efx);
@@ -1836,9 +1838,10 @@ static void falcon_push_multicast_hash(struct efx_nic *efx)
efx_writeo(efx, &mc_hash->oword[1], FR_AB_MAC_MC_HASH_REG1);
}
-static int falcon_reset_macs(struct efx_nic *efx)
+static void falcon_reset_macs(struct efx_nic *efx)
{
- efx_oword_t reg;
+ struct falcon_nic_data *nic_data = efx->nic_data;
+ efx_oword_t reg, mac_ctrl;
int count;
if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) {
@@ -1853,7 +1856,7 @@ static int falcon_reset_macs(struct efx_nic *efx)
EFX_POPULATE_OWORD_1(reg, FRF_AB_GM_SW_RST, 0);
efx_writeo(efx, &reg, FR_AB_GM_CFG1);
udelay(1000);
- return 0;
+ return;
} else {
EFX_POPULATE_OWORD_1(reg, FRF_AB_XM_CORE_RST, 1);
efx_writeo(efx, &reg, FR_AB_XM_GLB_CFG);
@@ -1862,22 +1865,20 @@ static int falcon_reset_macs(struct efx_nic *efx)
efx_reado(efx, &reg, FR_AB_XM_GLB_CFG);
if (EFX_OWORD_FIELD(reg, FRF_AB_XM_CORE_RST) ==
0)
- return 0;
+ return;
udelay(10);
}
EFX_ERR(efx, "timed out waiting for XMAC core reset\n");
- return -ETIMEDOUT;
}
}
- /* MAC stats will fail whilst the TX fifo is draining. Serialise
- * the drain sequence with the statistics fetch */
- falcon_stop_nic_stats(efx);
+ /* Mac stats will fail whist the TX fifo is draining */
+ WARN_ON(nic_data->stats_disable_count == 0);
- efx_reado(efx, &reg, FR_AB_MAC_CTRL);
- EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN, 1);
- efx_writeo(efx, &reg, FR_AB_MAC_CTRL);
+ efx_reado(efx, &mac_ctrl, FR_AB_MAC_CTRL);
+ EFX_SET_OWORD_FIELD(mac_ctrl, FRF_BB_TXFIFO_DRAIN_EN, 1);
+ efx_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL);
efx_reado(efx, &reg, FR_AB_GLB_CTL);
EFX_SET_OWORD_FIELD(reg, FRF_AB_RST_XGTX, 1);
@@ -1903,14 +1904,9 @@ static int falcon_reset_macs(struct efx_nic *efx)
udelay(10);
}
- /* If we've reset the EM block and the link is up, then
- * we'll have to kick the XAUI link so the PHY can recover */
- if (efx->link_state.up && EFX_IS10G(efx) && EFX_WORKAROUND_5147(efx))
- falcon_reset_xaui(efx);
-
- falcon_start_nic_stats(efx);
-
- return 0;
+ /* Ensure the correct MAC is selected before statistics
+ * are re-enabled by the caller */
+ efx_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL);
}
void falcon_drain_tx_fifo(struct efx_nic *efx)
@@ -1929,7 +1925,7 @@ void falcon_drain_tx_fifo(struct efx_nic *efx)
falcon_reset_macs(efx);
}
-void falcon_deconfigure_mac_wrapper(struct efx_nic *efx)
+static void falcon_deconfigure_mac_wrapper(struct efx_nic *efx)
{
efx_oword_t reg;
@@ -1941,8 +1937,8 @@ void falcon_deconfigure_mac_wrapper(struct efx_nic *efx)
EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 0);
efx_writeo(efx, &reg, FR_AZ_RX_CFG);
- if (!efx->link_state.up)
- falcon_drain_tx_fifo(efx);
+ /* Isolate TX -> MAC */
+ falcon_drain_tx_fifo(efx);
}
void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
@@ -2044,6 +2040,8 @@ static void falcon_stats_timer_func(unsigned long context)
spin_unlock(&efx->stats_lock);
}
+static void falcon_switch_mac(struct efx_nic *efx);
+
static bool falcon_loopback_link_poll(struct efx_nic *efx)
{
struct efx_link_state old_state = efx->link_state;
@@ -2063,6 +2061,38 @@ static bool falcon_loopback_link_poll(struct efx_nic *efx)
return !efx_link_state_equal(&efx->link_state, &old_state);
}
+static int falcon_reconfigure_port(struct efx_nic *efx)
+{
+ int rc;
+
+ WARN_ON(efx_nic_rev(efx) > EFX_REV_FALCON_B0);
+
+ /* Poll the PHY link state *before* reconfiguring it. This means we
+ * will pick up the correct speed (in loopback) to select the correct
+ * MAC.
+ */
+ if (LOOPBACK_INTERNAL(efx))
+ falcon_loopback_link_poll(efx);
+ else
+ efx->phy_op->poll(efx);
+
+ falcon_stop_nic_stats(efx);
+ falcon_deconfigure_mac_wrapper(efx);
+
+ falcon_switch_mac(efx);
+
+ efx->phy_op->reconfigure(efx);
+ rc = efx->mac_op->reconfigure(efx);
+ BUG_ON(rc);
+
+ falcon_start_nic_stats(efx);
+
+ /* Synchronise efx->link_state with the kernel */
+ efx_link_status_changed(efx);
+
+ return 0;
+}
+
/**************************************************************************
*
* PHY access via GMII
@@ -2215,17 +2245,15 @@ static void falcon_clock_mac(struct efx_nic *efx)
}
}
-int falcon_switch_mac(struct efx_nic *efx)
+static void falcon_switch_mac(struct efx_nic *efx)
{
struct efx_mac_operations *old_mac_op = efx->mac_op;
struct falcon_nic_data *nic_data = efx->nic_data;
unsigned int stats_done_offset;
- int rc = 0;
-
- /* Don't try to fetch MAC stats while we're switching MACs */
- falcon_stop_nic_stats(efx);
WARN_ON(!mutex_is_locked(&efx->mac_lock));
+ WARN_ON(nic_data->stats_disable_count == 0);
+
efx->mac_op = (EFX_IS10G(efx) ?
&falcon_xmac_operations : &falcon_gmac_operations);
@@ -2236,18 +2264,14 @@ int falcon_switch_mac(struct efx_nic *efx)
nic_data->stats_dma_done = efx->stats_buffer.addr + stats_done_offset;
if (old_mac_op == efx->mac_op)
- goto out;
+ return;
falcon_clock_mac(efx);
EFX_LOG(efx, "selected %cMAC\n", EFX_IS10G(efx) ? 'X' : 'G');
/* Not all macs support a mac-level link state */
efx->xmac_poll_required = false;
-
- rc = falcon_reset_macs(efx);
-out:
- falcon_start_nic_stats(efx);
- return rc;
+ falcon_reset_macs(efx);
}
/* This call is responsible for hooking in the MAC and PHY operations */
@@ -2597,7 +2621,8 @@ static void falcon_monitor(struct efx_nic *efx)
EFX_ERR(efx, "Board sensor %s; shutting down PHY\n",
(rc == -ERANGE) ? "reported fault" : "failed");
efx->phy_mode |= PHY_MODE_LOW_POWER;
- __efx_reconfigure_port(efx);
+ rc = __efx_reconfigure_port(efx);
+ WARN_ON(rc);
}
if (LOOPBACK_INTERNAL(efx))
@@ -2610,7 +2635,8 @@ static void falcon_monitor(struct efx_nic *efx)
falcon_deconfigure_mac_wrapper(efx);
falcon_switch_mac(efx);
- efx->mac_op->reconfigure(efx);
+ rc = efx->mac_op->reconfigure(efx);
+ BUG_ON(rc);
falcon_start_nic_stats(efx);
@@ -3239,6 +3265,7 @@ struct efx_nic_type falcon_a1_nic_type = {
.stop_stats = falcon_stop_nic_stats,
.push_irq_moderation = falcon_push_irq_moderation,
.push_multicast_hash = falcon_push_multicast_hash,
+ .reconfigure_port = falcon_reconfigure_port,
.default_mac_ops = &falcon_xmac_operations,
.revision = EFX_REV_FALCON_A1,
@@ -3271,6 +3298,7 @@ struct efx_nic_type falcon_b0_nic_type = {
.stop_stats = falcon_stop_nic_stats,
.push_irq_moderation = falcon_push_irq_moderation,
.push_multicast_hash = falcon_push_multicast_hash,
+ .reconfigure_port = falcon_reconfigure_port,
.default_mac_ops = &falcon_xmac_operations,
.revision = EFX_REV_FALCON_B0,