aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2009-03-04 05:01:15 -0500
committerDavid S. Miller <davem@davemloft.net>2009-03-04 20:40:24 -0500
commit4720bc6cfe70b606cf62a244c7a5391e59923e45 (patch)
tree545d302af8e36501f3001473a2826bf7c9fd6764
parent32d760073eacd41ecc815db1e958f0e1e0b82d57 (diff)
sfc: Fix search for flush completion events
When flushing queues we disable normal interrupt and event handling and poll event queue 0 looking for flush completions. Unfortunately the flush event polling loop fails to move past any other type of event. This problem has not been observed in production hardware but appears to be a possibility. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/sfc/falcon.c21
1 files changed, 9 insertions, 12 deletions
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index efd121c42a21..82c10f4de1b8 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -1187,31 +1187,29 @@ static void falcon_poll_flush_events(struct efx_nic *efx)
1187 struct efx_channel *channel = &efx->channel[0]; 1187 struct efx_channel *channel = &efx->channel[0];
1188 struct efx_tx_queue *tx_queue; 1188 struct efx_tx_queue *tx_queue;
1189 struct efx_rx_queue *rx_queue; 1189 struct efx_rx_queue *rx_queue;
1190 unsigned int read_ptr, i; 1190 unsigned int read_ptr = channel->eventq_read_ptr;
1191 unsigned int end_ptr = (read_ptr - 1) & FALCON_EVQ_MASK;
1191 1192
1192 read_ptr = channel->eventq_read_ptr; 1193 do {
1193 for (i = 0; i < FALCON_EVQ_SIZE; ++i) {
1194 efx_qword_t *event = falcon_event(channel, read_ptr); 1194 efx_qword_t *event = falcon_event(channel, read_ptr);
1195 int ev_code, ev_sub_code, ev_queue; 1195 int ev_code, ev_sub_code, ev_queue;
1196 bool ev_failed; 1196 bool ev_failed;
1197
1197 if (!falcon_event_present(event)) 1198 if (!falcon_event_present(event))
1198 break; 1199 break;
1199 1200
1200 ev_code = EFX_QWORD_FIELD(*event, EV_CODE); 1201 ev_code = EFX_QWORD_FIELD(*event, EV_CODE);
1201 if (ev_code != DRIVER_EV_DECODE)
1202 continue;
1203
1204 ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE); 1202 ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE);
1205 switch (ev_sub_code) { 1203 if (ev_code == DRIVER_EV_DECODE &&
1206 case TX_DESCQ_FLS_DONE_EV_DECODE: 1204 ev_sub_code == TX_DESCQ_FLS_DONE_EV_DECODE) {
1207 ev_queue = EFX_QWORD_FIELD(*event, 1205 ev_queue = EFX_QWORD_FIELD(*event,
1208 DRIVER_EV_TX_DESCQ_ID); 1206 DRIVER_EV_TX_DESCQ_ID);
1209 if (ev_queue < EFX_TX_QUEUE_COUNT) { 1207 if (ev_queue < EFX_TX_QUEUE_COUNT) {
1210 tx_queue = efx->tx_queue + ev_queue; 1208 tx_queue = efx->tx_queue + ev_queue;
1211 tx_queue->flushed = true; 1209 tx_queue->flushed = true;
1212 } 1210 }
1213 break; 1211 } else if (ev_code == DRIVER_EV_DECODE &&
1214 case RX_DESCQ_FLS_DONE_EV_DECODE: 1212 ev_sub_code == RX_DESCQ_FLS_DONE_EV_DECODE) {
1215 ev_queue = EFX_QWORD_FIELD(*event, 1213 ev_queue = EFX_QWORD_FIELD(*event,
1216 DRIVER_EV_RX_DESCQ_ID); 1214 DRIVER_EV_RX_DESCQ_ID);
1217 ev_failed = EFX_QWORD_FIELD(*event, 1215 ev_failed = EFX_QWORD_FIELD(*event,
@@ -1225,11 +1223,10 @@ static void falcon_poll_flush_events(struct efx_nic *efx)
1225 else 1223 else
1226 rx_queue->flushed = true; 1224 rx_queue->flushed = true;
1227 } 1225 }
1228 break;
1229 } 1226 }
1230 1227
1231 read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK; 1228 read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK;
1232 } 1229 } while (read_ptr != end_ptr);
1233} 1230}
1234 1231
1235/* Handle tx and rx flushes at the same time, since they run in 1232/* Handle tx and rx flushes at the same time, since they run in