aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sfc/falcon.c
diff options
context:
space:
mode:
authorSteve Hodgson <shodgson@solarflare.com>2009-11-28 05:34:05 +0000
committerDavid S. Miller <davem@davemloft.net>2009-11-28 23:58:50 -0800
commitfdaa9aed21c8c8b529f3c94a5ffa138bf3360b75 (patch)
tree6db7fd76481b3f87f0f4e94e1bd55c0624fba296 /drivers/net/sfc/falcon.c
parentvlan: support "loose binding" to the underlying network device (diff)
downloadlinux-dev-fdaa9aed21c8c8b529f3c94a5ffa138bf3360b75.tar.xz
linux-dev-fdaa9aed21c8c8b529f3c94a5ffa138bf3360b75.zip
sfc: Simplify PHY polling
Falcon can generate events for LASI interrupts from the PHY, but in practice we have never implemented this in reference designs. Instead we have polled, inserted the appropriate events, and then handled the events later. This is a waste of time and code. Instead, make PHY poll functions update the link state synchronously and report whether it changed. We can still make use of the LASI registers as a shortcut on the SFT9001. 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.c69
1 files changed, 42 insertions, 27 deletions
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index e26043eb01b5..e16faad70283 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -893,8 +893,7 @@ static void falcon_handle_global_event(struct efx_channel *channel,
if (EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_G_PHY0_INTR) ||
EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XG_PHY0_INTR) ||
EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XFP_PHY0_INTR)) {
- efx->phy_op->clear_interrupt(efx);
- queue_work(efx->workqueue, &efx->phy_work);
+ /* Ignored */
handled = true;
}
@@ -1140,20 +1139,6 @@ void falcon_generate_test_event(struct efx_channel *channel, unsigned int magic)
falcon_generate_event(channel, &test_event);
}
-void falcon_sim_phy_event(struct efx_nic *efx)
-{
- efx_qword_t phy_event;
-
- EFX_POPULATE_QWORD_1(phy_event, FSF_AZ_EV_CODE,
- FSE_AZ_EV_CODE_GLOBAL_EV);
- if (EFX_IS10G(efx))
- EFX_SET_QWORD_FIELD(phy_event, FSF_AB_GLB_EV_XG_PHY0_INTR, 1);
- else
- EFX_SET_QWORD_FIELD(phy_event, FSF_AB_GLB_EV_G_PHY0_INTR, 1);
-
- falcon_generate_event(&efx->channel[0], &phy_event);
-}
-
/**************************************************************************
*
* Flush handling
@@ -2063,6 +2048,25 @@ static void falcon_stats_timer_func(unsigned long context)
spin_unlock(&efx->stats_lock);
}
+static bool falcon_loopback_link_poll(struct efx_nic *efx)
+{
+ struct efx_link_state old_state = efx->link_state;
+
+ WARN_ON(!mutex_is_locked(&efx->mac_lock));
+ WARN_ON(!LOOPBACK_INTERNAL(efx));
+
+ efx->link_state.fd = true;
+ efx->link_state.fc = efx->wanted_fc;
+ efx->link_state.up = true;
+
+ if (efx->loopback_mode == LOOPBACK_GMAC)
+ efx->link_state.speed = 1000;
+ else
+ efx->link_state.speed = 10000;
+
+ return !efx_link_state_equal(&efx->link_state, &old_state);
+}
+
/**************************************************************************
*
* PHY access via GMII
@@ -2225,15 +2229,6 @@ int falcon_switch_mac(struct efx_nic *efx)
/* Don't try to fetch MAC stats while we're switching MACs */
falcon_stop_nic_stats(efx);
- /* Internal loopbacks override the phy speed setting */
- if (efx->loopback_mode == LOOPBACK_GMAC) {
- efx->link_state.speed = 1000;
- efx->link_state.fd = true;
- } else if (LOOPBACK_INTERNAL(efx)) {
- efx->link_state.speed = 10000;
- efx->link_state.fd = true;
- }
-
WARN_ON(!mutex_is_locked(&efx->mac_lock));
efx->mac_op = (EFX_IS10G(efx) ?
&falcon_xmac_operations : &falcon_gmac_operations);
@@ -2610,16 +2605,36 @@ fail5:
void falcon_monitor(struct efx_nic *efx)
{
+ bool link_changed;
int rc;
+ BUG_ON(!mutex_is_locked(&efx->mac_lock));
+
rc = falcon_board(efx)->type->monitor(efx);
if (rc) {
EFX_ERR(efx, "Board sensor %s; shutting down PHY\n",
(rc == -ERANGE) ? "reported fault" : "failed");
efx->phy_mode |= PHY_MODE_LOW_POWER;
- falcon_sim_phy_event(efx);
+ __efx_reconfigure_port(efx);
}
- efx->phy_op->poll(efx);
+
+ if (LOOPBACK_INTERNAL(efx))
+ link_changed = falcon_loopback_link_poll(efx);
+ else
+ link_changed = efx->phy_op->poll(efx);
+
+ if (link_changed) {
+ falcon_stop_nic_stats(efx);
+ falcon_deconfigure_mac_wrapper(efx);
+
+ falcon_switch_mac(efx);
+ efx->mac_op->reconfigure(efx);
+
+ falcon_start_nic_stats(efx);
+
+ efx_link_status_changed(efx);
+ }
+
if (EFX_IS10G(efx))
falcon_poll_xmac(efx);
}