[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