From d5e8cc6c946e0857826dcfbb3585068858445bfe Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 6 Sep 2012 16:52:31 +0100 Subject: sfc: Really disable flow control while flushing Receiving pause frames can block TX queue flushes. Earlier changes work around this by reconfiguring the MAC during flushes for VFs, but during flushes for the PF we would only change the fc_disable counter. Unless the MAC is reconfigured for some other reason during the flush (which I would not expect to happen) this had no effect at all. Signed-off-by: Ben Hutchings --- drivers/net/ethernet/sfc/nic.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/ethernet/sfc/nic.c') diff --git a/drivers/net/ethernet/sfc/nic.c b/drivers/net/ethernet/sfc/nic.c index aab7cacb2e34..e10b7ec046c3 100644 --- a/drivers/net/ethernet/sfc/nic.c +++ b/drivers/net/ethernet/sfc/nic.c @@ -680,7 +680,6 @@ int efx_nic_flush_queues(struct efx_nic *efx) struct efx_tx_queue *tx_queue; int rc = 0; - efx->fc_disable++; efx->type->prepare_flush(efx); efx_for_each_channel(channel, efx) { @@ -742,7 +741,7 @@ int efx_nic_flush_queues(struct efx_nic *efx) atomic_set(&efx->rxq_flush_outstanding, 0); } - efx->fc_disable--; + efx->type->finish_flush(efx); return rc; } -- cgit v1.2.3 From 778cdaf639e34288c298f1d3d3503d0724ceabc7 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 18 Sep 2012 01:56:50 +0100 Subject: sfc: Remove confusing MMIO functions efx_writed_table() uses a step of 16 bytes but efx_readd_table() uses a step of 4 bytes. Why are they different? Firstly, register access is asymmetric: - The EVQ_RPTR table and RX_INDIRECTION_TBL can (or must?) be written as dwords even though they have a step size of 16 bytes, unlike most other CSRs. - In general, a read of any width is valid for registers, so long as it does not cross register boundaries. There is also no latching behaviour in the BIU, contrary to rumour. We write to the EVQ_RPTR table with efx_writed_table() but never read it back as it's write-only. We write to the RX_INDIRECTION_TBL with efx_writed_table(), but only read it back for the register dump, where we use efx_reado_table() as for any other table with step size of 16. We read MC_TREG_SMEM with efx_readd_table() for the register dump, but normally read and write it with efx_readd() and efx_writed() using offsets calculated in bytes. Since these functions are trivial and have few callers, it's clearer to open-code them at the call sites. While we're at it, update the comments on the BIU behaviour again. Signed-off-by: Ben Hutchings --- drivers/net/ethernet/sfc/io.h | 43 +++++++++++----------------------- drivers/net/ethernet/sfc/nic.c | 19 ++++++++++----- drivers/net/ethernet/sfc/siena_sriov.c | 2 +- 3 files changed, 28 insertions(+), 36 deletions(-) (limited to 'drivers/net/ethernet/sfc/nic.c') diff --git a/drivers/net/ethernet/sfc/io.h b/drivers/net/ethernet/sfc/io.h index 751d1ec112cc..96759aee1c6c 100644 --- a/drivers/net/ethernet/sfc/io.h +++ b/drivers/net/ethernet/sfc/io.h @@ -22,22 +22,21 @@ * * Notes on locking strategy: * - * Most CSRs are 128-bit (oword) and therefore cannot be read or - * written atomically. Access from the host is buffered by the Bus - * Interface Unit (BIU). Whenever the host reads from the lowest - * address of such a register, or from the address of a different such - * register, the BIU latches the register's value. Subsequent reads - * from higher addresses of the same register will read the latched - * value. Whenever the host writes part of such a register, the BIU - * collects the written value and does not write to the underlying - * register until all 4 dwords have been written. A similar buffering - * scheme applies to host access to the NIC's 64-bit SRAM. + * Many CSRs are very wide and cannot be read or written atomically. + * Writes from the host are buffered by the Bus Interface Unit (BIU) + * up to 128 bits. Whenever the host writes part of such a register, + * the BIU collects the written value and does not write to the + * underlying register until all 4 dwords have been written. A + * similar buffering scheme applies to host access to the NIC's 64-bit + * SRAM. * - * Access to different CSRs and 64-bit SRAM words must be serialised, - * since interleaved access can result in lost writes or lost - * information from read-to-clear fields. We use efx_nic::biu_lock - * for this. (We could use separate locks for read and write, but - * this is not normally a performance bottleneck.) + * Writes to different CSRs and 64-bit SRAM words must be serialised, + * since interleaved access can result in lost writes. We use + * efx_nic::biu_lock for this. + * + * We also serialise reads from 128-bit CSRs and SRAM with the same + * spinlock. This may not be necessary, but it doesn't really matter + * as there are no such reads on the fast path. * * The DMA descriptor pointers (RX_DESC_UPD and TX_DESC_UPD) are * 128-bit but are special-cased in the BIU to avoid the need for @@ -204,20 +203,6 @@ static inline void efx_reado_table(struct efx_nic *efx, efx_oword_t *value, efx_reado(efx, value, reg + index * sizeof(efx_oword_t)); } -/* Write a 32-bit CSR forming part of a table, or 32-bit SRAM */ -static inline void efx_writed_table(struct efx_nic *efx, efx_dword_t *value, - unsigned int reg, unsigned int index) -{ - efx_writed(efx, value, reg + index * sizeof(efx_oword_t)); -} - -/* Read a 32-bit CSR forming part of a table, or 32-bit SRAM */ -static inline void efx_readd_table(struct efx_nic *efx, efx_dword_t *value, - unsigned int reg, unsigned int index) -{ - efx_readd(efx, value, reg + index * sizeof(efx_dword_t)); -} - /* Page-mapped register block size */ #define EFX_PAGE_BLOCK_SIZE 0x2000 diff --git a/drivers/net/ethernet/sfc/nic.c b/drivers/net/ethernet/sfc/nic.c index e10b7ec046c3..368659d6362a 100644 --- a/drivers/net/ethernet/sfc/nic.c +++ b/drivers/net/ethernet/sfc/nic.c @@ -765,8 +765,13 @@ void efx_nic_eventq_read_ack(struct efx_channel *channel) EFX_POPULATE_DWORD_1(reg, FRF_AZ_EVQ_RPTR, channel->eventq_read_ptr & channel->eventq_mask); - efx_writed_table(efx, ®, efx->type->evq_rptr_tbl_base, - channel->channel); + + /* For Falcon A1, EVQ_RPTR_KER is documented as having a step size + * of 4 bytes, but it is really 16 bytes just like later revisions. + */ + efx_writed(efx, ®, + efx->type->evq_rptr_tbl_base + + FR_BZ_EVQ_RPTR_STEP * channel->channel); } /* Use HW to insert a SW defined event */ @@ -1564,7 +1569,9 @@ void efx_nic_push_rx_indir_table(struct efx_nic *efx) for (i = 0; i < FR_BZ_RX_INDIRECTION_TBL_ROWS; i++) { EFX_POPULATE_DWORD_1(dword, FRF_BZ_IT_QUEUE, efx->rx_indir_table[i]); - efx_writed_table(efx, &dword, FR_BZ_RX_INDIRECTION_TBL, i); + efx_writed(efx, &dword, + FR_BZ_RX_INDIRECTION_TBL + + FR_BZ_RX_INDIRECTION_TBL_STEP * i); } } @@ -2028,15 +2035,15 @@ void efx_nic_get_regs(struct efx_nic *efx, void *buf) for (i = 0; i < table->rows; i++) { switch (table->step) { - case 4: /* 32-bit register or SRAM */ - efx_readd_table(efx, buf, table->offset, i); + case 4: /* 32-bit SRAM */ + efx_readd(efx, buf, table->offset + 4 * i); break; case 8: /* 64-bit SRAM */ efx_sram_readq(efx, efx->membase + table->offset, buf, i); break; - case 16: /* 128-bit register */ + case 16: /* 128-bit-readable register */ efx_reado_table(efx, buf, table->offset, i); break; case 32: /* 128-bit register, interleaved */ diff --git a/drivers/net/ethernet/sfc/siena_sriov.c b/drivers/net/ethernet/sfc/siena_sriov.c index 6e62a018ea32..90f8d1604f5f 100644 --- a/drivers/net/ethernet/sfc/siena_sriov.c +++ b/drivers/net/ethernet/sfc/siena_sriov.c @@ -993,7 +993,7 @@ static void efx_sriov_reset_vf(struct efx_vf *vf, struct efx_buffer *buffer) FRF_AZ_EVQ_BUF_BASE_ID, buftbl); efx_writeo_table(efx, ®, FR_BZ_EVQ_PTR_TBL, abs_evq); EFX_POPULATE_DWORD_1(ptr, FRF_AZ_EVQ_RPTR, 0); - efx_writed_table(efx, &ptr, FR_BZ_EVQ_RPTR, abs_evq); + efx_writed(efx, &ptr, FR_BZ_EVQ_RPTR + FR_BZ_EVQ_RPTR_STEP * abs_evq); mutex_unlock(&vf->status_lock); } -- cgit v1.2.3 From c3771a35bebeea16c4fd94d1116010cc02b1f75e Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 19 Sep 2012 00:31:18 +0100 Subject: sfc: Do not initialise buffer in efx_alloc_special_buffer() Currently we initialise the newly allocated buffer to all-1s, which is important for event queues but not for descriptor queues. And since we also do that in efx_nic_init_eventq(), it is completely pointless to do it here. Signed-off-by: Ben Hutchings --- drivers/net/ethernet/sfc/nic.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net/ethernet/sfc/nic.c') diff --git a/drivers/net/ethernet/sfc/nic.c b/drivers/net/ethernet/sfc/nic.c index 368659d6362a..1327f29d086f 100644 --- a/drivers/net/ethernet/sfc/nic.c +++ b/drivers/net/ethernet/sfc/nic.c @@ -255,9 +255,6 @@ static int efx_alloc_special_buffer(struct efx_nic *efx, buffer->entries = len / EFX_BUF_SIZE; BUG_ON(buffer->dma_addr & (EFX_BUF_SIZE - 1)); - /* All zeros is a potentially valid event so memset to 0xff */ - memset(buffer->addr, 0xff, len); - /* Select new buffer ID */ buffer->index = efx->next_buffer_table; efx->next_buffer_table += buffer->entries; -- cgit v1.2.3 From 525d9e824018cd7cc8d8d44832ddcd363abfe6e1 Mon Sep 17 00:00:00 2001 From: Daniel Pieczko Date: Tue, 2 Oct 2012 13:36:18 +0100 Subject: sfc: Work-around flush timeout when flushes have completed We sometimes hit a "failed to flush" timeout on some TX queues, but the flushes have completed and the flush completion events seem to go missing. In this case, we can check the TX_DESC_PTR_TBL register and drain the queues if the flushes had finished. [bwh: Minor fixes to coding style] Signed-off-by: Ben Hutchings --- drivers/net/ethernet/sfc/net_driver.h | 1 + drivers/net/ethernet/sfc/nic.c | 56 ++++++++++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 4 deletions(-) (limited to 'drivers/net/ethernet/sfc/nic.c') diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 1014556df0e7..2d756c1d7142 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -200,6 +200,7 @@ struct efx_tx_queue { /* Members shared between paths and sometimes updated */ unsigned int empty_read_count ____cacheline_aligned_in_smp; #define EFX_EMPTY_COUNT_VALID 0x80000000 + atomic_t flush_outstanding; }; /** diff --git a/drivers/net/ethernet/sfc/nic.c b/drivers/net/ethernet/sfc/nic.c index 1327f29d086f..0ad790cc473c 100644 --- a/drivers/net/ethernet/sfc/nic.c +++ b/drivers/net/ethernet/sfc/nic.c @@ -73,6 +73,8 @@ _EFX_CHANNEL_MAGIC(_EFX_CHANNEL_MAGIC_TX_DRAIN, \ (_tx_queue)->queue) +static void efx_magic_event(struct efx_channel *channel, u32 magic); + /************************************************************************** * * Solarstorm hardware access @@ -491,6 +493,9 @@ static void efx_flush_tx_queue(struct efx_tx_queue *tx_queue) struct efx_nic *efx = tx_queue->efx; efx_oword_t tx_flush_descq; + WARN_ON(atomic_read(&tx_queue->flush_outstanding)); + atomic_set(&tx_queue->flush_outstanding, 1); + EFX_POPULATE_OWORD_2(tx_flush_descq, FRF_AZ_TX_FLUSH_DESCQ_CMD, 1, FRF_AZ_TX_FLUSH_DESCQ, tx_queue->queue); @@ -666,6 +671,47 @@ static bool efx_flush_wake(struct efx_nic *efx) && atomic_read(&efx->rxq_flush_pending) > 0)); } +static bool efx_check_tx_flush_complete(struct efx_nic *efx) +{ + bool i = true; + efx_oword_t txd_ptr_tbl; + struct efx_channel *channel; + struct efx_tx_queue *tx_queue; + + efx_for_each_channel(channel, efx) { + efx_for_each_channel_tx_queue(tx_queue, channel) { + efx_reado_table(efx, &txd_ptr_tbl, + FR_BZ_TX_DESC_PTR_TBL, tx_queue->queue); + if (EFX_OWORD_FIELD(txd_ptr_tbl, + FRF_AZ_TX_DESCQ_FLUSH) || + EFX_OWORD_FIELD(txd_ptr_tbl, + FRF_AZ_TX_DESCQ_EN)) { + netif_dbg(efx, hw, efx->net_dev, + "flush did not complete on TXQ %d\n", + tx_queue->queue); + i = false; + } else if (atomic_cmpxchg(&tx_queue->flush_outstanding, + 1, 0)) { + /* The flush is complete, but we didn't + * receive a flush completion event + */ + netif_dbg(efx, hw, efx->net_dev, + "flush complete on TXQ %d, so drain " + "the queue\n", tx_queue->queue); + /* Don't need to increment drain_pending as it + * has already been incremented for the queues + * which did not drain + */ + efx_magic_event(channel, + EFX_CHANNEL_MAGIC_TX_DRAIN( + tx_queue)); + } + } + } + + return i; +} + /* Flush all the transmit queues, and continue flushing receive queues until * they're all flushed. Wait for the DRAIN events to be recieved so that there * are no more RX and TX events left on any channel. */ @@ -726,7 +772,8 @@ int efx_nic_flush_queues(struct efx_nic *efx) timeout); } - if (atomic_read(&efx->drain_pending)) { + if (atomic_read(&efx->drain_pending) && + !efx_check_tx_flush_complete(efx)) { netif_err(efx, hw, efx->net_dev, "failed to flush %d queues " "(rx %d+%d)\n", atomic_read(&efx->drain_pending), atomic_read(&efx->rxq_flush_outstanding), @@ -1018,9 +1065,10 @@ efx_handle_tx_flush_done(struct efx_nic *efx, efx_qword_t *event) if (qid < EFX_TXQ_TYPES * efx->n_tx_channels) { tx_queue = efx_get_tx_queue(efx, qid / EFX_TXQ_TYPES, qid % EFX_TXQ_TYPES); - - efx_magic_event(tx_queue->channel, - EFX_CHANNEL_MAGIC_TX_DRAIN(tx_queue)); + if (atomic_cmpxchg(&tx_queue->flush_outstanding, 1, 0)) { + efx_magic_event(tx_queue->channel, + EFX_CHANNEL_MAGIC_TX_DRAIN(tx_queue)); + } } } -- cgit v1.2.3