/* Test generation and receipt of interrupts */ staticint efx_test_interrupts(struct efx_nic *efx, struct efx_self_tests *tests)
{ unsignedlong timeout, wait; int cpu; int rc;
/* Wait for arrival of test interrupt. */
netif_dbg(efx, drv, efx->net_dev, "waiting for test interrupt\n"); do {
schedule_timeout_uninterruptible(wait);
cpu = efx_nic_irq_test_irq_cpu(efx); if (cpu >= 0) goto success;
wait *= 2;
} while (time_before(jiffies, timeout));
netif_err(efx, drv, efx->net_dev, "timed out waiting for interrupt\n"); return -ETIMEDOUT;
success:
netif_dbg(efx, drv, efx->net_dev, "%s test interrupt seen on CPU%d\n",
INT_MODE(efx), cpu);
tests->interrupt = 1; return0;
}
/* Wait for arrival of interrupts. NAPI processing may or may *notcompleteintime,butwecancopeinanycase.
*/ do {
schedule_timeout_uninterruptible(wait);
/* Transmit N copies of buffer */ for (i = 0; i < state->packet_count; i++) { /* Allocate an skb, holding an extra reference for
* transmit completion counting */
skb = alloc_skb(sizeof(state->payload), GFP_KERNEL); if (!skb) return -ENOMEM;
state->skbs[i] = skb;
skb_get(skb);
/* Copy the payload in, incrementing the source address to
* exercise the rss vectors */
payload = skb_put(skb, sizeof(state->payload));
memcpy(payload, &state->payload, sizeof(state->payload));
payload->ip.saddr = htonl(INADDR_LOOPBACK | (i << 2)); /* Strip off the leading padding */
skb_pull(skb, offsetof(struct efx_loopback_payload, header)); /* Strip off the trailing padding */
skb_trim(skb, EFX_LOOPBACK_PAYLOAD_LEN);
/* Ensure everything we've written is visible to the
* interrupt handler. */
smp_wmb();
if (rc != NETDEV_TX_OK) {
netif_err(efx, drv, efx->net_dev, "TX queue %d could not transmit packet %d of " "%d in %s loopback test\n", tx_queue->label,
i + 1, state->packet_count,
LOOPBACK_MODE(efx));
/* Defer cleaning up the other skbs for the caller */
kfree_skb(skb); return -EPIPE;
}
}
/* Count the number of tx completions, and decrement the refcnt. Any
* skbs not already completed will be free'd when the queue is flushed */ for (i = 0; i < state->packet_count; i++) {
skb = state->skbs[i]; if (skb && !skb_shared(skb))
++tx_done;
dev_kfree_skb(skb);
}
netif_tx_unlock_bh(efx->net_dev);
/* Check TX completion and received packet counts */
rx_good = atomic_read(&state->rx_good);
rx_bad = atomic_read(&state->rx_bad); if (tx_done != state->packet_count) { /* Don't free the skbs; they will be picked up on TX *overfloworchannelteardown.
*/
netif_err(efx, drv, efx->net_dev, "TX queue %d saw only %d out of an expected %d " "TX completion events in %s loopback test\n",
tx_queue->label, tx_done, state->packet_count,
LOOPBACK_MODE(efx));
rc = -ETIMEDOUT; /* Allow to fall through so we see the RX errors as well */
}
/* We may always be up to a flush away from our desired packet total */ if (rx_good != state->packet_count) {
netif_dbg(efx, drv, efx->net_dev, "TX queue %d saw only %d out of an expected %d " "received packets in %s loopback test\n",
tx_queue->label, rx_good, state->packet_count,
LOOPBACK_MODE(efx));
rc = -ETIMEDOUT; /* Fall through */
}
/* This will normally complete very quickly, but be
* prepared to wait much longer. */
msleep(1); if (!efx_poll_loopback(efx)) {
msleep(LOOPBACK_TIMEOUT_MS);
efx_poll_loopback(efx);
}
if (begin_rc || end_rc) { /* Wait a while to ensure there are no packets
* floating around after a failure. */
schedule_timeout_uninterruptible(HZ / 10); return begin_rc ? begin_rc : end_rc;
}
}
netif_dbg(efx, drv, efx->net_dev, "TX queue %d passed %s loopback test with a burst length " "of %d packets\n", tx_queue->label, LOOPBACK_MODE(efx),
state->packet_count);
return0;
}
/* Wait for link up. On Falcon, we would prefer to rely on efx_monitor, but *anycontentiononthemaclock(viae.g.efx_mac_mcast_work)causesit *todelayandretry.Therefore,it'ssafertojustpolldirectly.Wait
* for link up and any faults to dissipate. */ staticint efx_wait_for_link(struct efx_nic *efx)
{ struct efx_link_state *link_state = &efx->link_state; int count, link_up_count = 0; bool link_up;
/* Set the port loopback_selftest member. From this point on *allreceivedpacketswillbedropped.Markthestateas
* "flushing" so all inflight packets are dropped */
state = kzalloc(sizeof(*state), GFP_KERNEL); if (state == NULL) return -ENOMEM;
BUG_ON(efx->loopback_selftest);
state->flush = true;
efx->loopback_selftest = state;
/* Test all supported loopback modes */ for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) { if (!(loopback_modes & (1 << mode))) continue;
/* Move the port into the specified loopback mode. */
state->flush = true;
mutex_lock(&efx->mac_lock);
efx->loopback_mode = mode;
rc = __efx_siena_reconfigure_port(efx);
mutex_unlock(&efx->mac_lock); if (rc) {
netif_err(efx, drv, efx->net_dev, "unable to move into %s loopback\n",
LOOPBACK_MODE(efx)); goto out;
}
rc = efx_wait_for_link(efx); if (rc) {
netif_err(efx, drv, efx->net_dev, "loopback %s never came up\n",
LOOPBACK_MODE(efx)); goto out;
}
/* Test all enabled types of TX queue */
efx_for_each_channel_tx_queue(tx_queue, channel) {
state->offload_csum = (tx_queue->type &
EFX_TXQ_TYPE_OUTER_CSUM);
rc = efx_test_loopback(tx_queue,
&tests->loopback[mode]); if (rc) goto out;
}
}
out: /* Remove the flush. The caller will remove the loopback setting */
state->flush = true;
efx->loopback_selftest = NULL;
wmb();
kfree(state);
/* Ensure that the phy is powered and out of loopback
* for the bist and loopback tests */
mutex_lock(&efx->mac_lock);
efx->phy_mode &= ~PHY_MODE_LOW_POWER;
efx->loopback_mode = LOOPBACK_NONE;
__efx_siena_reconfigure_port(efx);
mutex_unlock(&efx->mac_lock);
/* restore the PHY to the previous state */
mutex_lock(&efx->mac_lock);
efx->phy_mode = phy_mode;
efx->loopback_mode = loopback_mode;
__efx_siena_reconfigure_port(efx);
mutex_unlock(&efx->mac_lock);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.