aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sfc/nic.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/sfc/nic.c')
-rw-r--r--drivers/net/sfc/nic.c42
1 files changed, 40 insertions, 2 deletions
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);