diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2011-04-04 14:22:11 +0100 |
---|---|---|
committer | Ben Hutchings <bhutchings@solarflare.com> | 2011-04-12 16:37:54 +0100 |
commit | d4fabcc8e8ecac21262b1a5b9684fe415b128bd2 (patch) | |
tree | b9c8f2532b4ff56589477b5f12f85ed4d70409e5 /drivers/net/sfc/nic.c | |
parent | 9d1aea62e45d447e7fc05d4e7f4e90f633e3abfc (diff) | |
download | linux-d4fabcc8e8ecac21262b1a5b9684fe415b128bd2.tar.bz2 |
sfc: Do not use efx_process_channel_now() in online self-test
During self-tests we use efx_process_channel_now() to handle
completion and other events synchronously. This disables interrupts
and NAPI processing for the channel in question, but it may still be
interrupted by another channel. A single socket may receive packets
from multiple net devices or even multiple channels of the same net
device, so this can result in deadlock on a socket lock.
Receiving packets in process context will also result in incorrect
classification by the network cgroup classifier.
Therefore, we must only use efx_process_channel_now() in the offline
loopback tests (which never deliver packets up the stack) and not for
the online interrupt and event tests.
For the interrupt test, there is no reason to process events. We
only care that an interrupt is raised.
For the event test, we want to know whether events have been received,
and there may be many events ahead of the one we inject. Therefore
remove efx_channel::magic_count and instead test whether
efx_channel::eventq_read_ptr advances. This is currently an event
queue index and might wrap around to exactly the same value, resulting
in a false negative. Therefore move the masking to efx_event() and
efx_nic_eventq_read_ack() so that it cannot wrap within the time of
the test.
The event test also tries to diagnose failures by checking whether an
event was delivered without causing an interrupt. Add and use a
helper function that only does this.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Diffstat (limited to 'drivers/net/sfc/nic.c')
-rw-r--r-- | drivers/net/sfc/nic.c | 22 |
1 files changed, 15 insertions, 7 deletions
diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index e8396614daf3..10f1cb79c147 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -84,7 +84,8 @@ static inline void efx_write_buf_tbl(struct efx_nic *efx, efx_qword_t *value, static inline efx_qword_t *efx_event(struct efx_channel *channel, unsigned int index) { - return ((efx_qword_t *) (channel->eventq.addr)) + index; + return ((efx_qword_t *) (channel->eventq.addr)) + + (index & channel->eventq_mask); } /* See if an event is present @@ -673,7 +674,8 @@ void efx_nic_eventq_read_ack(struct efx_channel *channel) efx_dword_t reg; struct efx_nic *efx = channel->efx; - EFX_POPULATE_DWORD_1(reg, FRF_AZ_EVQ_RPTR, channel->eventq_read_ptr); + EFX_POPULATE_DWORD_1(reg, FRF_AZ_EVQ_RPTR, + channel->eventq_read_ptr & channel->eventq_mask); efx_writed_table(efx, ®, efx->type->evq_rptr_tbl_base, channel->channel); } @@ -908,7 +910,7 @@ efx_handle_generated_event(struct efx_channel *channel, efx_qword_t *event) code = EFX_QWORD_FIELD(*event, FSF_AZ_DRV_GEN_EV_MAGIC); if (code == EFX_CHANNEL_MAGIC_TEST(channel)) - ++channel->magic_count; + ; /* ignore */ else if (code == EFX_CHANNEL_MAGIC_FILL(channel)) /* The queue must be empty, so we won't receive any rx * events, so efx_process_channel() won't refill the @@ -1015,8 +1017,7 @@ int efx_nic_process_eventq(struct efx_channel *channel, int budget) /* Clear this event by marking it all ones */ EFX_SET_QWORD(*p_event); - /* Increment read pointer */ - read_ptr = (read_ptr + 1) & channel->eventq_mask; + ++read_ptr; ev_code = EFX_QWORD_FIELD(event, FSF_AZ_EV_CODE); @@ -1060,6 +1061,13 @@ out: return spent; } +/* Check whether an event is present in the eventq at the current + * read pointer. Only useful for self-test. + */ +bool efx_nic_event_present(struct efx_channel *channel) +{ + return efx_event_present(efx_event(channel, channel->eventq_read_ptr)); +} /* Allocate buffer table entries for event queue */ int efx_nic_probe_eventq(struct efx_channel *channel) @@ -1165,7 +1173,7 @@ static void efx_poll_flush_events(struct efx_nic *efx) struct efx_tx_queue *tx_queue; struct efx_rx_queue *rx_queue; unsigned int read_ptr = channel->eventq_read_ptr; - unsigned int end_ptr = (read_ptr - 1) & channel->eventq_mask; + unsigned int end_ptr = read_ptr + channel->eventq_mask - 1; do { efx_qword_t *event = efx_event(channel, read_ptr); @@ -1205,7 +1213,7 @@ static void efx_poll_flush_events(struct efx_nic *efx) * it's ok to throw away every non-flush event */ EFX_SET_QWORD(*event); - read_ptr = (read_ptr + 1) & channel->eventq_mask; + ++read_ptr; } while (read_ptr != end_ptr); channel->eventq_read_ptr = read_ptr; |