Commit 0fb53faa authored by Ben Hutchings's avatar Ben Hutchings

sfc: Remove dependence on NAPI polling in efx_test_eventq_irq()

We cannot safely assume that the NAPI handler will complete within the
20 ms that we allow for the event self-test.  The handler may be
deferred for longer than this, particularly on realtime kernels.

Instead, check whether either an event has been handled or (as in the
old failure path) whether an interrupt has been received and an event
has been delivered but not yet handled.  Use napi_disable() to
synchronize with the NAPI handler before checking, since it will
clear events before updating eventq_read_ptr.

Remove the test result chan.N.eventq.poll, since it is not an error
if the NAPI handler does not run during the test.
Signed-off-by: default avatarBen Hutchings <bhutchings@solarflare.com>
parent cc180b69
...@@ -404,10 +404,6 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx, ...@@ -404,10 +404,6 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx,
&tests->eventq_int[channel->channel], &tests->eventq_int[channel->channel],
EFX_CHANNEL_NAME(channel), EFX_CHANNEL_NAME(channel),
"eventq.int", NULL); "eventq.int", NULL);
efx_fill_test(n++, strings, data,
&tests->eventq_poll[channel->channel],
EFX_CHANNEL_NAME(channel),
"eventq.poll", NULL);
} }
efx_fill_test(n++, strings, data, &tests->registers, efx_fill_test(n++, strings, data, &tests->registers,
......
...@@ -161,11 +161,8 @@ static int efx_test_eventq_irq(struct efx_channel *channel, ...@@ -161,11 +161,8 @@ static int efx_test_eventq_irq(struct efx_channel *channel,
struct efx_self_tests *tests) struct efx_self_tests *tests)
{ {
struct efx_nic *efx = channel->efx; struct efx_nic *efx = channel->efx;
unsigned int read_ptr, count; unsigned int read_ptr;
bool napi_ran, dma_seen, int_seen;
tests->eventq_dma[channel->channel] = -1;
tests->eventq_int[channel->channel] = -1;
tests->eventq_poll[channel->channel] = -1;
read_ptr = channel->eventq_read_ptr; read_ptr = channel->eventq_read_ptr;
channel->efx->last_irq_cpu = -1; channel->efx->last_irq_cpu = -1;
...@@ -173,44 +170,48 @@ static int efx_test_eventq_irq(struct efx_channel *channel, ...@@ -173,44 +170,48 @@ static int efx_test_eventq_irq(struct efx_channel *channel,
efx_nic_generate_test_event(channel); efx_nic_generate_test_event(channel);
/* Wait for arrival of interrupt */ /* Wait for arrival of interrupt. NAPI processing may or may
count = 0; * not complete in time, but we can cope in any case.
do { */
schedule_timeout_uninterruptible(HZ / 100); msleep(10);
napi_disable(&channel->napi_str);
if (ACCESS_ONCE(channel->eventq_read_ptr) != read_ptr) if (channel->eventq_read_ptr != read_ptr) {
goto eventq_ok; napi_ran = true;
} while (++count < 2); dma_seen = true;
int_seen = true;
netif_err(efx, drv, efx->net_dev, } else {
"channel %d timed out waiting for event queue\n", napi_ran = false;
channel->channel); dma_seen = efx_nic_event_present(channel);
int_seen = efx->last_irq_cpu >= 0;
/* See if interrupt arrived */
if (channel->efx->last_irq_cpu >= 0) {
netif_err(efx, drv, efx->net_dev,
"channel %d saw interrupt on CPU%d "
"during event queue test\n", channel->channel,
raw_smp_processor_id());
tests->eventq_int[channel->channel] = 1;
} }
napi_enable(&channel->napi_str);
efx_nic_eventq_read_ack(channel);
tests->eventq_dma[channel->channel] = dma_seen ? 1 : -1;
tests->eventq_int[channel->channel] = int_seen ? 1 : -1;
/* Check to see if event was received even if interrupt wasn't */ if (dma_seen && int_seen) {
if (efx_nic_event_present(channel)) { netif_dbg(efx, drv, efx->net_dev,
"channel %d event queue passed (with%s NAPI)\n",
channel->channel, napi_ran ? "" : "out");
return 0;
} else {
/* Report failure and whether either interrupt or DMA worked */
netif_err(efx, drv, efx->net_dev, netif_err(efx, drv, efx->net_dev,
"channel %d event was generated, but " "channel %d timed out waiting for event queue\n",
"failed to trigger an interrupt\n", channel->channel); channel->channel);
tests->eventq_dma[channel->channel] = 1; if (int_seen)
netif_err(efx, drv, efx->net_dev,
"channel %d saw interrupt "
"during event queue test\n",
channel->channel);
if (dma_seen)
netif_err(efx, drv, efx->net_dev,
"channel %d event was generated, but "
"failed to trigger an interrupt\n",
channel->channel);
return -ETIMEDOUT;
} }
return -ETIMEDOUT;
eventq_ok:
netif_dbg(efx, drv, efx->net_dev, "channel %d event queue passed\n",
channel->channel);
tests->eventq_dma[channel->channel] = 1;
tests->eventq_int[channel->channel] = 1;
tests->eventq_poll[channel->channel] = 1;
return 0;
} }
static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests, static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests,
......
...@@ -37,7 +37,6 @@ struct efx_self_tests { ...@@ -37,7 +37,6 @@ struct efx_self_tests {
int interrupt; int interrupt;
int eventq_dma[EFX_MAX_CHANNELS]; int eventq_dma[EFX_MAX_CHANNELS];
int eventq_int[EFX_MAX_CHANNELS]; int eventq_int[EFX_MAX_CHANNELS];
int eventq_poll[EFX_MAX_CHANNELS];
/* offline tests */ /* offline tests */
int registers; int registers;
int phy_ext[EFX_MAX_PHY_TESTS]; int phy_ext[EFX_MAX_PHY_TESTS];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment