git: a6bda3e1ef4d - main - enetc: Simply TX ring credits counting logic

From: Wojciech Macek <wma_at_FreeBSD.org>
Date: Mon, 31 Jan 2022 08:00:03 UTC
The branch main has been updated by wma:

URL: https://cgit.FreeBSD.org/src/commit/?id=a6bda3e1ef4d06e3243a65533f9faf678816a48e

commit a6bda3e1ef4d06e3243a65533f9faf678816a48e
Author:     Kornel Duleba <mindal@semihalf.com>
AuthorDate: 2022-01-27 09:24:26 +0000
Commit:     Wojciech Macek <wma@FreeBSD.org>
CommitDate: 2022-01-31 07:57:48 +0000

    enetc: Simply TX ring credits counting logic
    
    According to the RM rings can hold at most ring_size - 1 descriptors at any time.
    No additional logic is needed since iflib already respects this constrain.
    Thanks to that the pidx == cidx situation is not ambiguous and indicates an
    empty ring.
    Use that to simplify the logic that calculates the amount of processed frames.
    
    Obtained from: Semihalf
    Sponsored by: Alstom Group
---
 sys/dev/enetc/enetc.h    |  3 +--
 sys/dev/enetc/if_enetc.c | 36 ++++++++++++++++++++----------------
 2 files changed, 21 insertions(+), 18 deletions(-)

diff --git a/sys/dev/enetc/enetc.h b/sys/dev/enetc/enetc.h
index 57edc2b26f2c..84b109a3e144 100644
--- a/sys/dev/enetc/enetc.h
+++ b/sys/dev/enetc/enetc.h
@@ -52,8 +52,7 @@ struct enetc_tx_queue {
 	union enetc_tx_bd	*ring;
 	uint64_t		ring_paddr;
 
-	qidx_t			next_to_clean;
-	bool			ring_full;
+	qidx_t			cidx;
 
 	struct if_irq		irq;
 };
diff --git a/sys/dev/enetc/if_enetc.c b/sys/dev/enetc/if_enetc.c
index 6f15db3ffe6c..75c582e81696 100644
--- a/sys/dev/enetc/if_enetc.c
+++ b/sys/dev/enetc/if_enetc.c
@@ -503,8 +503,7 @@ enetc_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs,
 		queue->sc = sc;
 		queue->ring = (union enetc_tx_bd*)(vaddrs[i]);
 		queue->ring_paddr = paddrs[i];
-		queue->next_to_clean = 0;
-		queue->ring_full = false;
+		queue->cidx = 0;
 	}
 
 	return (0);
@@ -1125,8 +1124,6 @@ enetc_isc_txd_encap(void *data, if_pkt_info_t ipi)
 
 	desc->flags |= ENETC_TXBD_FLAGS_F;
 	ipi->ipi_new_pidx = pidx;
-	if (pidx == queue->next_to_clean)
-		queue->ring_full = true;
 
 	return (0);
 }
@@ -1144,28 +1141,35 @@ enetc_isc_txd_credits_update(void *data, uint16_t qid, bool clear)
 {
 	struct enetc_softc *sc = data;
 	struct enetc_tx_queue *queue;
-	qidx_t next_to_clean, next_to_process;
-	int clean_count;
+	int cidx, hw_cidx, count;
 
 	queue = &sc->tx_queues[qid];
-	next_to_process =
-	    ENETC_TXQ_RD4(sc, qid, ENETC_TBCIR) & ENETC_TBCIR_IDX_MASK;
-	next_to_clean = queue->next_to_clean;
+	hw_cidx = ENETC_TXQ_RD4(sc, qid, ENETC_TBCIR) & ENETC_TBCIR_IDX_MASK;
+	cidx = queue->cidx;
 
-	if (next_to_clean == next_to_process && !queue->ring_full)
+	/*
+	 * RM states that the ring can hold at most ring_size - 1 descriptors.
+	 * Thanks to that we can assume that the ring is empty if cidx == pidx.
+	 * This requirement is guaranteed implicitly by iflib as it will only
+	 * encap a new frame if we have at least nfrags + 2 descriptors available
+	 * on the ring. This driver uses at most one additional descriptor for
+	 * VLAN tag insertion.
+	 * Also RM states that the TBCIR register is only updated once all
+	 * descriptors in the chain have been processed.
+	 */
+	if (cidx == hw_cidx)
 		return (0);
 
 	if (!clear)
 		return (1);
 
-	clean_count = next_to_process - next_to_clean;
-	if (clean_count <= 0)
-		clean_count += sc->tx_queue_size;
+	count = hw_cidx - cidx;
+	if (count < 0)
+		count += sc->tx_queue_size;
 
-	queue->next_to_clean = next_to_process;
-	queue->ring_full = false;
+	queue->cidx = hw_cidx;
 
-	return (clean_count);
+	return (count);
 }
 
 static int