aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/sfc/net_driver.h16
-rw-r--r--drivers/net/sfc/nic.c42
-rw-r--r--drivers/net/sfc/tx.c12
3 files changed, 68 insertions, 2 deletions
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 60d63711d43f..270e217a53f9 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -142,6 +142,12 @@ struct efx_tx_buffer {
142 * @flushed: Used when handling queue flushing 142 * @flushed: Used when handling queue flushing
143 * @read_count: Current read pointer. 143 * @read_count: Current read pointer.
144 * This is the number of buffers that have been removed from both rings. 144 * This is the number of buffers that have been removed from both rings.
145 * @old_write_count: The value of @write_count when last checked.
146 * This is here for performance reasons. The xmit path will
147 * only get the up-to-date value of @write_count if this
148 * variable indicates that the queue is empty. This is to
149 * avoid cache-line ping-pong between the xmit path and the
150 * completion path.
145 * @stopped: Stopped count. 151 * @stopped: Stopped count.
146 * Set if this TX queue is currently stopping its port. 152 * Set if this TX queue is currently stopping its port.
147 * @insert_count: Current insert pointer 153 * @insert_count: Current insert pointer
@@ -163,6 +169,10 @@ struct efx_tx_buffer {
163 * @tso_long_headers: Number of packets with headers too long for standard 169 * @tso_long_headers: Number of packets with headers too long for standard
164 * blocks 170 * blocks
165 * @tso_packets: Number of packets via the TSO xmit path 171 * @tso_packets: Number of packets via the TSO xmit path
172 * @pushes: Number of times the TX push feature has been used
173 * @empty_read_count: If the completion path has seen the queue as empty
174 * and the transmission path has not yet checked this, the value of
175 * @read_count bitwise-added to %EFX_EMPTY_COUNT_VALID; otherwise 0.
166 */ 176 */
167struct efx_tx_queue { 177struct efx_tx_queue {
168 /* Members which don't change on the fast path */ 178 /* Members which don't change on the fast path */
@@ -177,6 +187,7 @@ struct efx_tx_queue {
177 187
178 /* Members used mainly on the completion path */ 188 /* Members used mainly on the completion path */
179 unsigned int read_count ____cacheline_aligned_in_smp; 189 unsigned int read_count ____cacheline_aligned_in_smp;
190 unsigned int old_write_count;
180 int stopped; 191 int stopped;
181 192
182 /* Members used only on the xmit path */ 193 /* Members used only on the xmit path */
@@ -187,6 +198,11 @@ struct efx_tx_queue {
187 unsigned int tso_bursts; 198 unsigned int tso_bursts;
188 unsigned int tso_long_headers; 199 unsigned int tso_long_headers;
189 unsigned int tso_packets; 200 unsigned int tso_packets;
201 unsigned int pushes;
202
203 /* Members shared between paths and sometimes updated */
204 unsigned int empty_read_count ____cacheline_aligned_in_smp;
205#define EFX_EMPTY_COUNT_VALID 0x80000000
190}; 206};
191 207
192/** 208/**
diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c
index 9743cff15130..bda6b1bd072c 100644
--- a/drivers/net/sfc/nic.c
+++ b/drivers/net/sfc/nic.c
@@ -362,6 +362,35 @@ static inline void efx_notify_tx_desc(struct efx_tx_queue *tx_queue)
362 FR_AZ_TX_DESC_UPD_DWORD_P0, tx_queue->queue); 362 FR_AZ_TX_DESC_UPD_DWORD_P0, tx_queue->queue);
363} 363}
364 364
365/* Write pointer and first descriptor for TX descriptor ring */
366static inline void efx_push_tx_desc(struct efx_tx_queue *tx_queue,
367 const efx_qword_t *txd)
368{
369 unsigned write_ptr;
370 efx_oword_t reg;
371
372 BUILD_BUG_ON(FRF_AZ_TX_DESC_LBN != 0);
373 BUILD_BUG_ON(FR_AA_TX_DESC_UPD_KER != FR_BZ_TX_DESC_UPD_P0);
374
375 write_ptr = tx_queue->write_count & tx_queue->ptr_mask;
376 EFX_POPULATE_OWORD_2(reg, FRF_AZ_TX_DESC_PUSH_CMD, true,
377 FRF_AZ_TX_DESC_WPTR, write_ptr);
378 reg.qword[0] = *txd;
379 efx_writeo_page(tx_queue->efx, &reg,
380 FR_BZ_TX_DESC_UPD_P0, tx_queue->queue);
381}
382
383static inline bool
384efx_may_push_tx_desc(struct efx_tx_queue *tx_queue, unsigned int write_count)
385{
386 unsigned empty_read_count = ACCESS_ONCE(tx_queue->empty_read_count);
387
388 if (empty_read_count == 0)
389 return false;
390
391 tx_queue->empty_read_count = 0;
392 return ((empty_read_count ^ write_count) & ~EFX_EMPTY_COUNT_VALID) == 0;
393}
365 394
366/* For each entry inserted into the software descriptor ring, create a 395/* For each entry inserted into the software descriptor ring, create a
367 * descriptor in the hardware TX descriptor ring (in host memory), and 396 * descriptor in the hardware TX descriptor ring (in host memory), and
@@ -373,6 +402,7 @@ void efx_nic_push_buffers(struct efx_tx_queue *tx_queue)
373 struct efx_tx_buffer *buffer; 402 struct efx_tx_buffer *buffer;
374 efx_qword_t *txd; 403 efx_qword_t *txd;
375 unsigned write_ptr; 404 unsigned write_ptr;
405 unsigned old_write_count = tx_queue->write_count;
376 406
377 BUG_ON(tx_queue->write_count == tx_queue->insert_count); 407 BUG_ON(tx_queue->write_count == tx_queue->insert_count);
378 408
@@ -391,7 +421,15 @@ void efx_nic_push_buffers(struct efx_tx_queue *tx_queue)
391 } while (tx_queue->write_count != tx_queue->insert_count); 421 } while (tx_queue->write_count != tx_queue->insert_count);
392 422
393 wmb(); /* Ensure descriptors are written before they are fetched */ 423 wmb(); /* Ensure descriptors are written before they are fetched */
394 efx_notify_tx_desc(tx_queue); 424
425 if (efx_may_push_tx_desc(tx_queue, old_write_count)) {
426 txd = efx_tx_desc(tx_queue,
427 old_write_count & tx_queue->ptr_mask);
428 efx_push_tx_desc(tx_queue, txd);
429 ++tx_queue->pushes;
430 } else {
431 efx_notify_tx_desc(tx_queue);
432 }
395} 433}
396 434
397/* Allocate hardware resources for a TX queue */ 435/* Allocate hardware resources for a TX queue */
@@ -1626,7 +1664,7 @@ void efx_nic_init_common(struct efx_nic *efx)
1626 EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER, 0xfe); 1664 EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER, 0xfe);
1627 EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER_EN, 1); 1665 EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER_EN, 1);
1628 EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_ONE_PKT_PER_Q, 1); 1666 EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_ONE_PKT_PER_Q, 1);
1629 EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PUSH_EN, 0); 1667 EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PUSH_EN, 1);
1630 EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_DIS_NON_IP_EV, 1); 1668 EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_DIS_NON_IP_EV, 1);
1631 /* Enable SW_EV to inherit in char driver - assume harmless here */ 1669 /* Enable SW_EV to inherit in char driver - assume harmless here */
1632 EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_SOFT_EVT_EN, 1); 1670 EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_SOFT_EVT_EN, 1);
diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c
index fef22351ddbd..bdb92b4af683 100644
--- a/drivers/net/sfc/tx.c
+++ b/drivers/net/sfc/tx.c
@@ -428,6 +428,16 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
428 __netif_tx_unlock(queue); 428 __netif_tx_unlock(queue);
429 } 429 }
430 } 430 }
431
432 /* Check whether the hardware queue is now empty */
433 if ((int)(tx_queue->read_count - tx_queue->old_write_count) >= 0) {
434 tx_queue->old_write_count = ACCESS_ONCE(tx_queue->write_count);
435 if (tx_queue->read_count == tx_queue->old_write_count) {
436 smp_mb();
437 tx_queue->empty_read_count =
438 tx_queue->read_count | EFX_EMPTY_COUNT_VALID;
439 }
440 }
431} 441}
432 442
433int efx_probe_tx_queue(struct efx_tx_queue *tx_queue) 443int efx_probe_tx_queue(struct efx_tx_queue *tx_queue)
@@ -473,8 +483,10 @@ void efx_init_tx_queue(struct efx_tx_queue *tx_queue)
473 483
474 tx_queue->insert_count = 0; 484 tx_queue->insert_count = 0;
475 tx_queue->write_count = 0; 485 tx_queue->write_count = 0;
486 tx_queue->old_write_count = 0;
476 tx_queue->read_count = 0; 487 tx_queue->read_count = 0;
477 tx_queue->old_read_count = 0; 488 tx_queue->old_read_count = 0;
489 tx_queue->empty_read_count = 0 | EFX_EMPTY_COUNT_VALID;
478 BUG_ON(tx_queue->stopped); 490 BUG_ON(tx_queue->stopped);
479 491
480 /* Set up TX descriptor ring */ 492 /* Set up TX descriptor ring */