diff options
author | Steve Hodgson <shodgson@solarflare.com> | 2009-11-28 05:34:05 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-11-28 23:58:50 -0800 |
commit | fdaa9aed21c8c8b529f3c94a5ffa138bf3360b75 (patch) | |
tree | 6db7fd76481b3f87f0f4e94e1bd55c0624fba296 /drivers/net/sfc/falcon.c | |
parent | 5e7565930524410f097f5b04f8aba663089a6ffc (diff) | |
download | linux-fdaa9aed21c8c8b529f3c94a5ffa138bf3360b75.tar.bz2 |
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.c | 69 |
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); } |