diff options
author | David S. Miller <davem@davemloft.net> | 2010-12-10 10:20:43 -0800 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-12-10 10:20:43 -0800 |
commit | cf78f8ee3de7d8d5b47d371c95716d0e4facf1c4 (patch) | |
tree | ffd211dfe1d4f0d91fe10396b05e261865f62b61 /drivers/net/sfc/nic.c | |
parent | 1e13f863ca88014d9550876c05c939fdab1017d1 (diff) | |
parent | c39d35ebffeea5996a6f8fd8430fae9acfb8aeaf (diff) |
Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/bwh/sfc-next-2.6
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 399b12abe2fd..da386599ab68 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) FR_AZ_TX_DESC_UPD_DWORD_P0, tx_queue->queue); } +/* Write pointer and first descriptor for TX descriptor ring */ +static inline void efx_push_tx_desc(struct efx_tx_queue *tx_queue, + const efx_qword_t *txd) +{ + unsigned write_ptr; + efx_oword_t reg; + + BUILD_BUG_ON(FRF_AZ_TX_DESC_LBN != 0); + BUILD_BUG_ON(FR_AA_TX_DESC_UPD_KER != FR_BZ_TX_DESC_UPD_P0); + + write_ptr = tx_queue->write_count & tx_queue->ptr_mask; + EFX_POPULATE_OWORD_2(reg, FRF_AZ_TX_DESC_PUSH_CMD, true, + FRF_AZ_TX_DESC_WPTR, write_ptr); + reg.qword[0] = *txd; + efx_writeo_page(tx_queue->efx, ®, + FR_BZ_TX_DESC_UPD_P0, tx_queue->queue); +} + +static inline bool +efx_may_push_tx_desc(struct efx_tx_queue *tx_queue, unsigned int write_count) +{ + unsigned empty_read_count = ACCESS_ONCE(tx_queue->empty_read_count); + + if (empty_read_count == 0) + return false; + + tx_queue->empty_read_count = 0; + return ((empty_read_count ^ write_count) & ~EFX_EMPTY_COUNT_VALID) == 0; +} /* For each entry inserted into the software descriptor ring, create a * 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) struct efx_tx_buffer *buffer; efx_qword_t *txd; unsigned write_ptr; + unsigned old_write_count = tx_queue->write_count; BUG_ON(tx_queue->write_count == tx_queue->insert_count); @@ -391,7 +421,15 @@ void efx_nic_push_buffers(struct efx_tx_queue *tx_queue) } while (tx_queue->write_count != tx_queue->insert_count); wmb(); /* Ensure descriptors are written before they are fetched */ - efx_notify_tx_desc(tx_queue); + + if (efx_may_push_tx_desc(tx_queue, old_write_count)) { + txd = efx_tx_desc(tx_queue, + old_write_count & tx_queue->ptr_mask); + efx_push_tx_desc(tx_queue, txd); + ++tx_queue->pushes; + } else { + efx_notify_tx_desc(tx_queue); + } } /* Allocate hardware resources for a TX queue */ @@ -1632,7 +1670,7 @@ void efx_nic_init_common(struct efx_nic *efx) EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER, 0xfe); EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER_EN, 1); EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_ONE_PKT_PER_Q, 1); - EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PUSH_EN, 0); + EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PUSH_EN, 1); EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_DIS_NON_IP_EV, 1); /* Enable SW_EV to inherit in char driver - assume harmless here */ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_SOFT_EVT_EN, 1); |