Thread (2 messages) 2 messages, 2 authors, 1d ago
WARM1d

[PATCH] net: stmmac: recalibrate CBS idle slope when EST is enabled

From: <hidden>
Date: 2026-07-01 05:32:49
Subsystem: networking drivers, stmmac ethernet driver, the rest · Maintainers: Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds

From: Nazim Amirul <redacted>

When both CBS (Credit-Based Shaper) and EST (Enhanced Scheduled
Transmit, IEEE 802.1Qbv) are active simultaneously, the CBS idle slope
configured for a queue must be adjusted to account for the EST gate
duty cycle.

Under normal CBS operation, credit accumulates continuously at the
configured idle slope rate. However, when EST is enabled, credit can
only accumulate while the queue's transmission gate is open. This means
the effective bandwidth delivered by CBS is reduced proportionally to
the fraction of time the gate is open.

To preserve the intended bandwidth allocation, the idle slope must be
scaled up by the ratio of the cycle time to the gate open time:

  idleSlope = operIdleSlope * (cycleTime / gateOpenTime)

Store the time interval (ti_ns) and gate mask for each GCL entry when
configuring EST via tc-taprio, then use these values in tc_setup_cbs to
recalculate the idle slope when EST is active.

If EST is not enabled, the cycle time is zero, or the queue's gate open
time is zero, the idle slope is left unchanged. The recalculated value
is capped at MAX_IDLE_SLOPE_CREDIT to prevent hardware register overflow.

Signed-off-by: Nazim Amirul <redacted>
---
 drivers/net/ethernet/stmicro/stmmac/stmmac.h  |  2 +
 .../net/ethernet/stmicro/stmmac/stmmac_tc.c   | 55 ++++++++++++++++++-
 2 files changed, 54 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 8ba8f03e1ce0..8eb73ca6e7e4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -237,6 +237,8 @@ struct stmmac_est {
 	u32 ter;
 	u32 gcl_unaligned[EST_GCL];
 	u32 gcl[EST_GCL];
+	u32 ti_ns[EST_GCL];
+	u32 gates[EST_GCL];
 	u32 gcl_size;
 	u32 max_sdu[MTL_MAX_TX_QUEUES];
 };
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
index d78652718599..1215946e49cb 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
@@ -11,6 +11,8 @@
 #include "dwmac5.h"
 #include "stmmac.h"
 
+#define MAX_IDLE_SLOPE_CREDIT 0x1FFFFF
+
 static void tc_fill_all_pass_entry(struct stmmac_tc_entry *entry)
 {
 	memset(entry, 0, sizeof(*entry));
@@ -332,13 +334,14 @@ static int tc_init(struct stmmac_priv *priv)
 static int tc_setup_cbs(struct stmmac_priv *priv,
 			struct tc_cbs_qopt_offload *qopt)
 {
+	u64 value, scaling = 0, cycle_time_ns = 0, open_time = 0, tti_ns = 0;
 	u32 tx_queues_count = priv->plat->tx_queues_to_use;
+	u32 gate = 0x1 << qopt->queue;
 	s64 port_transmit_rate_kbps;
 	u32 queue = qopt->queue;
+	u32 ptr, idle_slope;
 	u32 mode_to_use;
-	u64 value;
-	u32 ptr;
-	int ret;
+	int ret, row;
 
 	/* Queue 0 is not AVB capable */
 	if (queue <= 0 || queue >= tx_queues_count)
@@ -402,6 +405,50 @@ static int tc_setup_cbs(struct stmmac_priv *priv,
 	value = qopt->locredit * 1024ll * 8;
 	priv->plat->tx_queues_cfg[queue].low_credit = value & GENMASK(31, 0);
 
+	/* If EST is not enabled, no need to recalibrate idle slope */
+	if (!priv->est)
+		goto config_cbs;
+	if (!priv->est->enable)
+		goto config_cbs;
+
+	cycle_time_ns = (priv->est->ctr[1] * NSEC_PER_SEC) +
+			 priv->est->ctr[0];
+	if (!cycle_time_ns)
+		goto config_cbs;
+
+	/* Sum the gate open time for this queue across all GCL entries. Entries
+	 * beyond the cycle time are truncated. Any remaining cycle time after
+	 * the last GCL entry is treated as gate-open (implicit open).
+	 */
+	for (row = 0; row < priv->est->gcl_size; row++) {
+		tti_ns += priv->est->ti_ns[row];
+		if (priv->est->gates[row] & gate)
+			open_time += priv->est->ti_ns[row];
+		if (tti_ns > cycle_time_ns) {
+			if (priv->est->gates[row] & gate)
+				open_time -= tti_ns - cycle_time_ns;
+			break;
+		}
+	}
+	if (tti_ns < cycle_time_ns)
+		open_time += cycle_time_ns - tti_ns;
+	if (!open_time)
+		goto config_cbs;
+
+	/* When EST is active, credit accumulates only when the gate is open,
+	 * so scale up the idle slope by the duty cycle:
+	 * idleSlope = operIdleSlope * (cycleTime / gateOpenTime)
+	 */
+	scaling = cycle_time_ns;
+	do_div(scaling, open_time);
+	idle_slope = priv->plat->tx_queues_cfg[queue].idle_slope;
+	idle_slope *= scaling;
+	if (idle_slope > MAX_IDLE_SLOPE_CREDIT)
+		idle_slope = MAX_IDLE_SLOPE_CREDIT;
+
+	priv->plat->tx_queues_cfg[queue].idle_slope = idle_slope;
+
+config_cbs:
 	ret = stmmac_config_cbs(priv, priv->hw,
 				priv->plat->tx_queues_cfg[queue].send_slope,
 				priv->plat->tx_queues_cfg[queue].idle_slope,
@@ -1031,6 +1078,8 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
 		}
 
 		priv->est->gcl[i] = delta_ns | (gates << wid);
+		priv->est->ti_ns[i] = delta_ns;
+		priv->est->gates[i] = gates;
 	}
 
 	mutex_lock(&priv->est_lock);
-- 
2.43.7
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help