aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/sfc/tx_common.c
diff options
context:
space:
mode:
authorTom Zhao <tzhao@solarflare.com>2020-03-05 11:38:45 +0000
committerDavid S. Miller <davem@davemloft.net>2020-03-05 14:56:57 -0800
commit3b4f06c715d0d3ecd6497275e3c85fe91462d0ee (patch)
treece62bc533650ccd16ca01c9dd325a96b62999c37 /drivers/net/ethernet/sfc/tx_common.c
parentnet: hns3: fix a not link up issue when fibre port supports autoneg (diff)
downloadlinux-dev-3b4f06c715d0d3ecd6497275e3c85fe91462d0ee.tar.xz
linux-dev-3b4f06c715d0d3ecd6497275e3c85fe91462d0ee.zip
sfc: complete the next packet when we receive a timestamp
We now ignore the "completion" event when using tx queue timestamping, and only pay attention to the two (high and low) timestamp events. The NIC will send a pair of timestamp events for every packet transmitted. The current firmware may merge the completion events, and it is possible that future versions may reorder the completion and timestamp events. As such the completion event is not useful. Without this patch in place a merged completion event on a queue with timestamping will cause a "spurious TX completion" error. This affects SFN8000-series adapters. Signed-off-by: Tom Zhao <tzhao@solarflare.com> Acked-by: Martin Habets <mhabets@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/sfc/tx_common.c')
-rw-r--r--drivers/net/ethernet/sfc/tx_common.c29
1 files changed, 16 insertions, 13 deletions
diff --git a/drivers/net/ethernet/sfc/tx_common.c b/drivers/net/ethernet/sfc/tx_common.c
index b1571e9789d0..70876df1da69 100644
--- a/drivers/net/ethernet/sfc/tx_common.c
+++ b/drivers/net/ethernet/sfc/tx_common.c
@@ -80,7 +80,6 @@ void efx_init_tx_queue(struct efx_tx_queue *tx_queue)
tx_queue->xmit_more_available = false;
tx_queue->timestamping = (efx_ptp_use_mac_tx_timestamps(efx) &&
tx_queue->channel == efx_ptp_channel(efx));
- tx_queue->completed_desc_ptr = tx_queue->ptr_mask;
tx_queue->completed_timestamp_major = 0;
tx_queue->completed_timestamp_minor = 0;
@@ -210,10 +209,9 @@ static void efx_dequeue_buffers(struct efx_tx_queue *tx_queue,
while (read_ptr != stop_index) {
struct efx_tx_buffer *buffer = &tx_queue->buffer[read_ptr];
- if (!(buffer->flags & EFX_TX_BUF_OPTION) &&
- unlikely(buffer->len == 0)) {
+ if (!efx_tx_buffer_in_use(buffer)) {
netif_err(efx, tx_err, efx->net_dev,
- "TX queue %d spurious TX completion id %x\n",
+ "TX queue %d spurious TX completion id %d\n",
tx_queue->queue, read_ptr);
efx_schedule_reset(efx, RESET_TYPE_TX_SKIP);
return;
@@ -226,6 +224,19 @@ static void efx_dequeue_buffers(struct efx_tx_queue *tx_queue,
}
}
+void efx_xmit_done_check_empty(struct efx_tx_queue *tx_queue)
+{
+ if ((int)(tx_queue->read_count - tx_queue->old_write_count) >= 0) {
+ tx_queue->old_write_count = READ_ONCE(tx_queue->write_count);
+ if (tx_queue->read_count == tx_queue->old_write_count) {
+ /* Ensure that read_count is flushed. */
+ smp_mb();
+ tx_queue->empty_read_count =
+ tx_queue->read_count | EFX_EMPTY_COUNT_VALID;
+ }
+ }
+}
+
void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
{
unsigned int fill_level, pkts_compl = 0, bytes_compl = 0;
@@ -256,15 +267,7 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
netif_tx_wake_queue(tx_queue->core_txq);
}
- /* Check whether the hardware queue is now empty */
- if ((int)(tx_queue->read_count - tx_queue->old_write_count) >= 0) {
- tx_queue->old_write_count = READ_ONCE(tx_queue->write_count);
- if (tx_queue->read_count == tx_queue->old_write_count) {
- smp_mb();
- tx_queue->empty_read_count =
- tx_queue->read_count | EFX_EMPTY_COUNT_VALID;
- }
- }
+ efx_xmit_done_check_empty(tx_queue);
}
/* Remove buffers put into a tx_queue for the current packet.