sfc: Generalise link state monitoring
Use the efx_nic_type::monitor operation or event handling as appropriate. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
d3245b28ef
commit
78c1f0a065
@ -1174,10 +1174,18 @@ static void efx_start_all(struct efx_nic *efx)
|
|||||||
|
|
||||||
falcon_enable_interrupts(efx);
|
falcon_enable_interrupts(efx);
|
||||||
|
|
||||||
/* Start the hardware monitor (if there is one) if we're in RUNNING */
|
/* Start the hardware monitor if there is one. Otherwise (we're link
|
||||||
if (efx->state == STATE_RUNNING && efx->type->monitor != NULL)
|
* event driven), we have to poll the PHY because after an event queue
|
||||||
|
* flush, we could have a missed a link state change */
|
||||||
|
if (efx->type->monitor != NULL) {
|
||||||
queue_delayed_work(efx->workqueue, &efx->monitor_work,
|
queue_delayed_work(efx->workqueue, &efx->monitor_work,
|
||||||
efx_monitor_interval);
|
efx_monitor_interval);
|
||||||
|
} else {
|
||||||
|
mutex_lock(&efx->mac_lock);
|
||||||
|
if (efx->phy_op->poll(efx))
|
||||||
|
efx_link_status_changed(efx);
|
||||||
|
mutex_unlock(&efx->mac_lock);
|
||||||
|
}
|
||||||
|
|
||||||
efx->type->start_stats(efx);
|
efx->type->start_stats(efx);
|
||||||
}
|
}
|
||||||
@ -1421,6 +1429,10 @@ static int efx_net_open(struct net_device *net_dev)
|
|||||||
if (efx->phy_mode & PHY_MODE_SPECIAL)
|
if (efx->phy_mode & PHY_MODE_SPECIAL)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
|
/* Notify the kernel of the link state polled during driver load,
|
||||||
|
* before the monitor starts running */
|
||||||
|
efx_link_status_changed(efx);
|
||||||
|
|
||||||
efx_start_all(efx);
|
efx_start_all(efx);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -563,14 +563,49 @@ efx_test_loopback(struct efx_tx_queue *tx_queue,
|
|||||||
return 0;
|
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,
|
static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests,
|
||||||
unsigned int loopback_modes)
|
unsigned int loopback_modes)
|
||||||
{
|
{
|
||||||
enum efx_loopback_mode mode;
|
enum efx_loopback_mode mode;
|
||||||
struct efx_loopback_state *state;
|
struct efx_loopback_state *state;
|
||||||
struct efx_tx_queue *tx_queue;
|
struct efx_tx_queue *tx_queue;
|
||||||
bool link_up;
|
int rc = 0;
|
||||||
int count, rc = 0;
|
|
||||||
|
|
||||||
/* Set the port loopback_selftest member. From this point on
|
/* Set the port loopback_selftest member. From this point on
|
||||||
* all received packets will be dropped. Mark the state as
|
* all received packets will be dropped. Mark the state as
|
||||||
@ -589,42 +624,22 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests,
|
|||||||
|
|
||||||
/* Move the port into the specified loopback mode. */
|
/* Move the port into the specified loopback mode. */
|
||||||
state->flush = true;
|
state->flush = true;
|
||||||
|
mutex_lock(&efx->mac_lock);
|
||||||
efx->loopback_mode = mode;
|
efx->loopback_mode = mode;
|
||||||
efx_reconfigure_port(efx);
|
rc = __efx_reconfigure_port(efx);
|
||||||
|
mutex_unlock(&efx->mac_lock);
|
||||||
/* Wait for the PHY to signal the link is up. Interrupts
|
if (rc) {
|
||||||
* are enabled for PHY's using LASI, otherwise we poll()
|
EFX_ERR(efx, "unable to move into %s loopback\n",
|
||||||
* 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);
|
|
||||||
|
|
||||||
/* The link should now be up. If it isn't, there is no point
|
|
||||||
* in attempting a loopback test */
|
|
||||||
if (!link_up) {
|
|
||||||
EFX_ERR(efx, "loopback %s never came up\n",
|
|
||||||
LOOPBACK_MODE(efx));
|
LOOPBACK_MODE(efx));
|
||||||
rc = -EIO;
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
EFX_LOG(efx, "link came up in %s loopback in %d iterations\n",
|
rc = efx_wait_for_link(efx);
|
||||||
LOOPBACK_MODE(efx), count);
|
if (rc) {
|
||||||
|
EFX_ERR(efx, "loopback %s never came up\n",
|
||||||
|
LOOPBACK_MODE(efx));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* Test every TX queue */
|
/* Test every TX queue */
|
||||||
efx_for_each_tx_queue(tx_queue, efx) {
|
efx_for_each_tx_queue(tx_queue, efx) {
|
||||||
|
Loading…
Reference in New Issue
Block a user