diff options
Diffstat (limited to 'drivers/net/sfc/nic.c')
-rw-r--r-- | drivers/net/sfc/nic.c | 42 |
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 */ | ||
366 | static 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, ®, | ||
380 | FR_BZ_TX_DESC_UPD_P0, tx_queue->queue); | ||
381 | } | ||
382 | |||
383 | static inline bool | ||
384 | efx_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); |