diff options
-rw-r--r-- | drivers/net/sfc/net_driver.h | 16 | ||||
-rw-r--r-- | drivers/net/sfc/nic.c | 42 | ||||
-rw-r--r-- | drivers/net/sfc/tx.c | 12 |
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 | */ |
167 | struct efx_tx_queue { | 177 | struct 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 */ | ||
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); |
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 | ||
433 | int efx_probe_tx_queue(struct efx_tx_queue *tx_queue) | 443 | int 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 */ |