aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sfc/nic.c
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2011-04-04 09:22:11 -0400
committerBen Hutchings <bhutchings@solarflare.com>2011-04-12 11:37:54 -0400
commitd4fabcc8e8ecac21262b1a5b9684fe415b128bd2 (patch)
treeb9c8f2532b4ff56589477b5f12f85ed4d70409e5 /drivers/net/sfc/nic.c
parent9d1aea62e45d447e7fc05d4e7f4e90f633e3abfc (diff)
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.c22
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,
84static inline efx_qword_t *efx_event(struct efx_channel *channel, 84static inline efx_qword_t *efx_event(struct efx_channel *channel,
85 unsigned int index) 85 unsigned int index)
86{ 86{
87 return ((efx_qword_t *) (channel->eventq.addr)) + index; 87 return ((efx_qword_t *) (channel->eventq.addr)) +
88 (index & channel->eventq_mask);
88} 89}
89 90
90/* See if an event is present 91/* See if an event is present
@@ -673,7 +674,8 @@ void efx_nic_eventq_read_ack(struct efx_channel *channel)
673 efx_dword_t reg; 674 efx_dword_t reg;
674 struct efx_nic *efx = channel->efx; 675 struct efx_nic *efx = channel->efx;
675 676
676 EFX_POPULATE_DWORD_1(reg, FRF_AZ_EVQ_RPTR, channel->eventq_read_ptr); 677 EFX_POPULATE_DWORD_1(reg, FRF_AZ_EVQ_RPTR,
678 channel->eventq_read_ptr & channel->eventq_mask);
677 efx_writed_table(efx, &reg, efx->type->evq_rptr_tbl_base, 679 efx_writed_table(efx, &reg, efx->type->evq_rptr_tbl_base,
678 channel->channel); 680 channel->channel);
679} 681}
@@ -908,7 +910,7 @@ efx_handle_generated_event(struct efx_channel *channel, efx_qword_t *event)
908 910
909 code = EFX_QWORD_FIELD(*event, FSF_AZ_DRV_GEN_EV_MAGIC); 911 code = EFX_QWORD_FIELD(*event, FSF_AZ_DRV_GEN_EV_MAGIC);
910 if (code == EFX_CHANNEL_MAGIC_TEST(channel)) 912 if (code == EFX_CHANNEL_MAGIC_TEST(channel))
911 ++channel->magic_count; 913 ; /* ignore */
912 else if (code == EFX_CHANNEL_MAGIC_FILL(channel)) 914 else if (code == EFX_CHANNEL_MAGIC_FILL(channel))
913 /* The queue must be empty, so we won't receive any rx 915 /* The queue must be empty, so we won't receive any rx
914 * events, so efx_process_channel() won't refill the 916 * events, so efx_process_channel() won't refill the
@@ -1015,8 +1017,7 @@ int efx_nic_process_eventq(struct efx_channel *channel, int budget)
1015 /* Clear this event by marking it all ones */ 1017 /* Clear this event by marking it all ones */
1016 EFX_SET_QWORD(*p_event); 1018 EFX_SET_QWORD(*p_event);
1017 1019
1018 /* Increment read pointer */ 1020 ++read_ptr;
1019 read_ptr = (read_ptr + 1) & channel->eventq_mask;
1020 1021
1021 ev_code = EFX_QWORD_FIELD(event, FSF_AZ_EV_CODE); 1022 ev_code = EFX_QWORD_FIELD(event, FSF_AZ_EV_CODE);
1022 1023
@@ -1060,6 +1061,13 @@ out:
1060 return spent; 1061 return spent;
1061} 1062}
1062 1063
1064/* Check whether an event is present in the eventq at the current
1065 * read pointer. Only useful for self-test.
1066 */
1067bool efx_nic_event_present(struct efx_channel *channel)
1068{
1069 return efx_event_present(efx_event(channel, channel->eventq_read_ptr));
1070}
1063 1071
1064/* Allocate buffer table entries for event queue */ 1072/* Allocate buffer table entries for event queue */
1065int efx_nic_probe_eventq(struct efx_channel *channel) 1073int efx_nic_probe_eventq(struct efx_channel *channel)
@@ -1165,7 +1173,7 @@ static void efx_poll_flush_events(struct efx_nic *efx)
1165 struct efx_tx_queue *tx_queue; 1173 struct efx_tx_queue *tx_queue;
1166 struct efx_rx_queue *rx_queue; 1174 struct efx_rx_queue *rx_queue;
1167 unsigned int read_ptr = channel->eventq_read_ptr; 1175 unsigned int read_ptr = channel->eventq_read_ptr;
1168 unsigned int end_ptr = (read_ptr - 1) & channel->eventq_mask; 1176 unsigned int end_ptr = read_ptr + channel->eventq_mask - 1;
1169 1177
1170 do { 1178 do {
1171 efx_qword_t *event = efx_event(channel, read_ptr); 1179 efx_qword_t *event = efx_event(channel, read_ptr);
@@ -1205,7 +1213,7 @@ static void efx_poll_flush_events(struct efx_nic *efx)
1205 * it's ok to throw away every non-flush event */ 1213 * it's ok to throw away every non-flush event */
1206 EFX_SET_QWORD(*event); 1214 EFX_SET_QWORD(*event);
1207 1215
1208 read_ptr = (read_ptr + 1) & channel->eventq_mask; 1216 ++read_ptr;
1209 } while (read_ptr != end_ptr); 1217 } while (read_ptr != end_ptr);
1210 1218
1211 channel->eventq_read_ptr = read_ptr; 1219 channel->eventq_read_ptr = read_ptr;