|
@@ -563,14 +563,49 @@ efx_test_loopback(struct efx_tx_queue *tx_queue,
|
|
|
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,
|
|
|
unsigned int loopback_modes)
|
|
|
{
|
|
|
enum efx_loopback_mode mode;
|
|
|
struct efx_loopback_state *state;
|
|
|
struct efx_tx_queue *tx_queue;
|
|
|
- bool link_up;
|
|
|
- int count, rc = 0;
|
|
|
+ int rc = 0;
|
|
|
|
|
|
/* Set the port loopback_selftest member. From this point on
|
|
|
* all received packets will be dropped. Mark the state as
|
|
@@ -589,43 +624,23 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests,
|
|
|
|
|
|
/* Move the port into the specified loopback mode. */
|
|
|
state->flush = true;
|
|
|
+ mutex_lock(&efx->mac_lock);
|
|
|
efx->loopback_mode = mode;
|
|
|
- efx_reconfigure_port(efx);
|
|
|
-
|
|
|
- /* Wait for the PHY to signal the link is up. Interrupts
|
|
|
- * are enabled for PHY's using LASI, otherwise we poll()
|
|
|
- * 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);
|
|
|
+ rc = __efx_reconfigure_port(efx);
|
|
|
+ mutex_unlock(&efx->mac_lock);
|
|
|
+ if (rc) {
|
|
|
+ EFX_ERR(efx, "unable to move into %s loopback\n",
|
|
|
+ LOOPBACK_MODE(efx));
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
|
|
|
- /* The link should now be up. If it isn't, there is no point
|
|
|
- * in attempting a loopback test */
|
|
|
- if (!link_up) {
|
|
|
+ rc = efx_wait_for_link(efx);
|
|
|
+ if (rc) {
|
|
|
EFX_ERR(efx, "loopback %s never came up\n",
|
|
|
LOOPBACK_MODE(efx));
|
|
|
- rc = -EIO;
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- EFX_LOG(efx, "link came up in %s loopback in %d iterations\n",
|
|
|
- LOOPBACK_MODE(efx), count);
|
|
|
-
|
|
|
/* Test every TX queue */
|
|
|
efx_for_each_tx_queue(tx_queue, efx) {
|
|
|
state->offload_csum = (tx_queue->queue ==
|