From: David Yang <mmyangfl@gmail.com>
To: netdev@vger.kernel.org
Cc: David Yang <mmyangfl@gmail.com>, Andrew Lunn <andrew@lunn.ch>,
Vladimir Oltean <olteanv@gmail.com>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
linux-kernel@vger.kernel.org
Subject: [PATCH net-next v4 4/4] net: dsa: yt921x: Add port qdisc tbf support
Date: Fri, 10 Apr 2026 01:12:04 +0800 [thread overview]
Message-ID: <20260409171209.2575583-5-mmyangfl@gmail.com> (raw)
In-Reply-To: <20260409171209.2575583-1-mmyangfl@gmail.com>
Enable port shaping and support limiting the rate of outgoing traffic.
Signed-off-by: David Yang <mmyangfl@gmail.com>
---
drivers/net/dsa/yt921x.c | 134 +++++++++++++++++++++++++++++++++++++++
drivers/net/dsa/yt921x.h | 65 ++++++++++++++++++-
2 files changed, 198 insertions(+), 1 deletion(-)
diff --git a/drivers/net/dsa/yt921x.c b/drivers/net/dsa/yt921x.c
index f0ebbcd2151c..b50d76b2d164 100644
--- a/drivers/net/dsa/yt921x.c
+++ b/drivers/net/dsa/yt921x.c
@@ -24,6 +24,7 @@
#include <net/dsa.h>
#include <net/dscp.h>
#include <net/ieee8021q.h>
+#include <net/pkt_cls.h>
#include "yt921x.h"
@@ -1274,6 +1275,19 @@ yt921x_marker_tfm_police(struct yt921x_marker *marker,
priv, port, extack);
}
+static int
+yt921x_marker_tfm_shape(struct yt921x_marker *marker, u64 rate, u64 burst,
+ unsigned int flags, bool queue,
+ struct yt921x_priv *priv, int port,
+ struct netlink_ext_ack *extack)
+{
+ return yt921x_marker_tfm(marker, rate, burst, flags,
+ queue ? priv->queue_shape_slot_ns :
+ priv->port_shape_slot_ns, YT921X_SHAPE_CIR_MAX,
+ YT921X_SHAPE_CBS_MAX, YT921X_SHAPE_UNIT_MAX,
+ priv, port, extack);
+}
+
static int
yt921x_police_validate(const struct flow_action_police *police,
const struct flow_action *action,
@@ -1380,6 +1394,111 @@ yt921x_dsa_port_policer_add(struct dsa_switch *ds, int port,
return res;
}
+static int
+yt921x_tbf_validate(struct yt921x_priv *priv,
+ const struct tc_tbf_qopt_offload *qopt, int *queuep)
+{
+ struct device *dev = to_device(priv);
+ int queue = -1;
+
+ /* TODO: queue support */
+ if (qopt->parent != TC_H_ROOT) {
+ dev_err(dev, "Parent should be \"root\"\n");
+ return -EOPNOTSUPP;
+ }
+
+ switch (qopt->command) {
+ case TC_TBF_REPLACE: {
+ const struct tc_tbf_qopt_offload_replace_params *p;
+
+ p = &qopt->replace_params;
+
+ if (!p->rate.mpu) {
+ dev_info(dev, "Assuming you want mpu = 64\n");
+ } else if (p->rate.mpu != 64) {
+ dev_err(dev, "mpu other than 64 not supported\n");
+ return -EINVAL;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ *queuep = queue;
+ return 0;
+}
+
+static int
+yt921x_dsa_port_setup_tc_tbf_port(struct dsa_switch *ds, int port,
+ const struct tc_tbf_qopt_offload *qopt)
+{
+ struct yt921x_priv *priv = to_yt921x_priv(ds);
+ u32 ctrls[2];
+ int res;
+
+ switch (qopt->command) {
+ case TC_TBF_DESTROY:
+ ctrls[0] = 0;
+ ctrls[1] = 0;
+ break;
+ case TC_TBF_REPLACE: {
+ const struct tc_tbf_qopt_offload_replace_params *p;
+ struct yt921x_marker marker;
+ u64 burst;
+
+ p = &qopt->replace_params;
+
+ /* where is burst??? */
+ burst = div_u64(priv->port_shape_slot_ns * p->rate.rate_bytes_ps,
+ 1000000000) + 10000;
+ res = yt921x_marker_tfm_shape(&marker, p->rate.rate_bytes_ps,
+ burst,
+ YT921X_MARKER_SINGLE_BUCKET,
+ false, priv, port, NULL);
+ if (res)
+ return res;
+
+ ctrls[0] = YT921X_PORT_SHAPE_CTRLa_CIR(marker.cir) |
+ YT921X_PORT_SHAPE_CTRLa_CBS(marker.cbs);
+ ctrls[1] = YT921X_PORT_SHAPE_CTRLb_UNIT(marker.unit) |
+ YT921X_PORT_SHAPE_CTRLb_EN;
+ break;
+ }
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ mutex_lock(&priv->reg_lock);
+ res = yt921x_reg64_write(priv, YT921X_PORTn_SHAPE_CTRL(port), ctrls);
+ mutex_unlock(&priv->reg_lock);
+
+ return res;
+}
+
+static int
+yt921x_dsa_port_setup_tc(struct dsa_switch *ds, int port,
+ enum tc_setup_type type, void *type_data)
+{
+ struct yt921x_priv *priv = to_yt921x_priv(ds);
+ int res;
+
+ switch (type) {
+ case TC_SETUP_QDISC_TBF: {
+ const struct tc_tbf_qopt_offload *qopt = type_data;
+ int queue;
+
+ res = yt921x_tbf_validate(priv, qopt, &queue);
+ if (res)
+ return res;
+
+ return yt921x_dsa_port_setup_tc_tbf_port(ds, port, qopt);
+ }
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
static int
yt921x_mirror_del(struct yt921x_priv *priv, int port, bool ingress)
{
@@ -3526,6 +3645,20 @@ static int yt921x_chip_setup_tc(struct yt921x_priv *priv)
return res;
priv->meter_slot_ns = ctrl * op_ns;
+ ctrl = max(priv->port_shape_slot_ns / op_ns,
+ YT921X_PORT_SHAPE_SLOT_MIN);
+ res = yt921x_reg_write(priv, YT921X_PORT_SHAPE_SLOT, ctrl);
+ if (res)
+ return res;
+ priv->port_shape_slot_ns = ctrl * op_ns;
+
+ ctrl = max(priv->queue_shape_slot_ns / op_ns,
+ YT921X_QUEUE_SHAPE_SLOT_MIN);
+ res = yt921x_reg_write(priv, YT921X_QUEUE_SHAPE_SLOT, ctrl);
+ if (res)
+ return res;
+ priv->queue_shape_slot_ns = ctrl * op_ns;
+
return 0;
}
@@ -3682,6 +3815,7 @@ static const struct dsa_switch_ops yt921x_dsa_switch_ops = {
/* rate */
.port_policer_del = yt921x_dsa_port_policer_del,
.port_policer_add = yt921x_dsa_port_policer_add,
+ .port_setup_tc = yt921x_dsa_port_setup_tc,
/* hsr */
.port_hsr_leave = dsa_port_simple_hsr_leave,
.port_hsr_join = dsa_port_simple_hsr_join,
diff --git a/drivers/net/dsa/yt921x.h b/drivers/net/dsa/yt921x.h
index 01cc2298be94..1c4f4b56d1c8 100644
--- a/drivers/net/dsa/yt921x.h
+++ b/drivers/net/dsa/yt921x.h
@@ -524,6 +524,12 @@ enum yt921x_app_selector {
#define YT921X_PORT_VLAN_CTRL1_CVLAN_DROP_TAGGED BIT(1)
#define YT921X_PORT_VLAN_CTRL1_CVLAN_DROP_UNTAGGED BIT(0)
+#define YT921X_PORTn_PRIO_UCAST_QUEUE(port) (0x300200 + 4 * (port))
+#define YT921X_PORT_PRIOm_UCAST_QUEUE_M(m) (7 << (3 * (m)))
+#define YT921X_PORT_PRIOm_UCAST_QUEUE(m, x) ((x) << (3 * (m)))
+#define YT921X_PORTn_PRIO_MCAST_QUEUE(port) (0x300280 + 4 * (port))
+#define YT921X_PORT_PRIOm_MCAST_QUEUE_M(m) (3 << (2 * (m)))
+#define YT921X_PORT_PRIOm_MCAST_QUEUE(m, x) ((x) << (2 * (m)))
#define YT921X_MIRROR 0x300300
#define YT921X_MIRROR_IGR_PORTS_M GENMASK(26, 16)
#define YT921X_MIRROR_IGR_PORTS(x) FIELD_PREP(YT921X_MIRROR_IGR_PORTS_M, (x))
@@ -534,6 +540,47 @@ enum yt921x_app_selector {
#define YT921X_MIRROR_PORT_M GENMASK(3, 0)
#define YT921X_MIRROR_PORT(x) FIELD_PREP(YT921X_MIRROR_PORT_M, (x))
+#define YT921X_QUEUE_SHAPE_SLOT 0x340008
+#define YT921X_QUEUE_SHAPE_SLOT_SLOT_M GENMASK(11, 0)
+#define YT921X_PORT_SHAPE_SLOT 0x34000c
+#define YT921X_PORT_SHAPE_SLOT_SLOT_M GENMASK(11, 0)
+#define YT921X_QUEUEn_SCH(x) (0x341000 + 4 * (x))
+#define YT921X_QUEUE_SCH_E_DWRR_M GENMASK(27, 18)
+#define YT921X_QUEUE_SCH_E_DWRR(x) FIELD_PREP(YT921X_QUEUE_SCH_E_DWRR_M, (x))
+#define YT921X_QUEUE_SCH_C_DWRR_M GENMASK(17, 8)
+#define YT921X_QUEUE_SCH_C_DWRR(x) FIELD_PREP(YT921X_QUEUE_SCH_C_DWRR_M, (x))
+#define YT921X_QUEUE_SCH_E_PRIO_M GENMASK(7, 4)
+#define YT921X_QUEUE_SCH_E_PRIO(x) FIELD_PREP(YT921X_QUEUE_SCH_E_PRIO_M, (x))
+#define YT921X_QUEUE_SCH_C_PRIO_M GENMASK(3, 0)
+#define YT921X_QUEUE_SCH_C_PRIO(x) FIELD_PREP(YT921X_QUEUE_SCH_C_PRIO_M, (x))
+#define YT921X_C_DWRRn(x) (0x342000 + 4 * (x))
+#define YT921X_E_DWRRn(x) (0x343000 + 4 * (x))
+#define YT921X_DWRR_PKT_MODE BIT(0) /* 0: byte rate mode */
+#define YT921X_QUEUEn_SHAPE_CTRL(x) (0x34c000 + 0x10 * (x))
+#define YT921X_QUEUE_SHAPE_CTRLc_TOKEN_OVERFLOW_EN BIT(6)
+#define YT921X_QUEUE_SHAPE_CTRLc_E_EN BIT(5)
+#define YT921X_QUEUE_SHAPE_CTRLc_C_EN BIT(4)
+#define YT921X_QUEUE_SHAPE_CTRLc_PKT_MODE BIT(3) /* 0: byte rate mode */
+#define YT921X_QUEUE_SHAPE_CTRLc_UNIT_M GENMASK(2, 0)
+#define YT921X_QUEUE_SHAPE_CTRLc_UNIT(x) FIELD_PREP(YT921X_QUEUE_SHAPE_CTRLc_UNIT_M, (x))
+#define YT921X_QUEUE_SHAPE_CTRLb_EBS_M GENMASK(31, 18)
+#define YT921X_QUEUE_SHAPE_CTRLb_EBS(x) FIELD_PREP(YT921X_QUEUE_SHAPE_CTRLb_EBS_M, (x))
+#define YT921X_QUEUE_SHAPE_CTRLb_EIR_M GENMASK(17, 0)
+#define YT921X_QUEUE_SHAPE_CTRLb_EIR(x) FIELD_PREP(YT921X_QUEUE_SHAPE_CTRLb_EIR_M, (x))
+#define YT921X_QUEUE_SHAPE_CTRLa_CBS_M GENMASK(31, 18)
+#define YT921X_QUEUE_SHAPE_CTRLa_CBS(x) FIELD_PREP(YT921X_QUEUE_SHAPE_CTRLa_CBS_M, (x))
+#define YT921X_QUEUE_SHAPE_CTRLa_CIR_M GENMASK(17, 0)
+#define YT921X_QUEUE_SHAPE_CTRLa_CIR(x) FIELD_PREP(YT921X_QUEUE_SHAPE_CTRLa_CIR_M, (x))
+#define YT921X_PORTn_SHAPE_CTRL(port) (0x354000 + 8 * (port))
+#define YT921X_PORT_SHAPE_CTRLb_EN BIT(4)
+#define YT921X_PORT_SHAPE_CTRLb_PKT_MODE BIT(3) /* 0: byte rate mode */
+#define YT921X_PORT_SHAPE_CTRLb_UNIT_M GENMASK(2, 0)
+#define YT921X_PORT_SHAPE_CTRLb_UNIT(x) FIELD_PREP(YT921X_PORT_SHAPE_CTRLb_UNIT_M, (x))
+#define YT921X_PORT_SHAPE_CTRLa_CBS_M GENMASK(31, 18)
+#define YT921X_PORT_SHAPE_CTRLa_CBS(x) FIELD_PREP(YT921X_PORT_SHAPE_CTRLa_CBS_M, (x))
+#define YT921X_PORT_SHAPE_CTRLa_CIR_M GENMASK(17, 0)
+#define YT921X_PORT_SHAPE_CTRLa_CIR(x) FIELD_PREP(YT921X_PORT_SHAPE_CTRLa_CIR_M, (x))
+
#define YT921X_EDATA_EXTMODE 0xfb
#define YT921X_EDATA_LEN 0x100
@@ -559,6 +606,11 @@ enum yt921x_fdb_entry_status {
#define YT921X_METER_UNIT_MAX ((1 << 3) - 1)
#define YT921X_METER_CIR_MAX ((1 << 18) - 1)
#define YT921X_METER_CBS_MAX ((1 << 16) - 1)
+#define YT921X_PORT_SHAPE_SLOT_MIN 80
+#define YT921X_QUEUE_SHAPE_SLOT_MIN 132
+#define YT921X_SHAPE_UNIT_MAX ((1 << 3) - 1)
+#define YT921X_SHAPE_CIR_MAX ((1 << 18) - 1)
+#define YT921X_SHAPE_CBS_MAX ((1 << 14) - 1)
#define YT921X_LAG_NUM 2
#define YT921X_LAG_PORT_NUM 4
@@ -576,7 +628,16 @@ enum yt921x_fdb_entry_status {
#define YT921X_TAG_LEN 8
/* 8 internal + 2 external + 1 mcu */
-#define YT921X_PORT_NUM 11
+#define YT921X_PORT_NUM 11
+#define YT921X_UCAST_QUEUE_NUM 8
+#define YT921X_MCAST_QUEUE_NUM 4
+#define YT921X_PORT_QUEUE_NUM \
+ (YT921X_UCAST_QUEUE_NUM + YT921X_MCAST_QUEUE_NUM)
+#define YT921X_UCAST_QUEUE_ID(port, queue) \
+ (YT921X_UCAST_QUEUE_NUM * (port) + (queue))
+#define YT921X_MCAST_QUEUE_ID(port, queue) \
+ (YT921X_UCAST_QUEUE_NUM * YT921X_PORT_NUM + \
+ YT921X_MCAST_QUEUE_NUM * (port) + (queue))
#define yt921x_port_is_internal(port) ((port) < 8)
#define yt921x_port_is_external(port) (8 <= (port) && (port) < 9)
@@ -655,6 +716,8 @@ struct yt921x_priv {
const struct yt921x_info *info;
unsigned int meter_slot_ns;
+ unsigned int port_shape_slot_ns;
+ unsigned int queue_shape_slot_ns;
/* cache of dsa_cpu_ports(ds) */
u16 cpu_ports_mask;
unsigned char cycle_ns;
--
2.53.0
next prev parent reply other threads:[~2026-04-09 17:12 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-09 17:12 [PATCH net-next v4 0/4] net: dsa: yt921x: Add port police/tbf support David Yang
2026-04-09 17:12 ` [PATCH net-next v4 1/4] net: dsa: pass extack to user tc policers David Yang
2026-04-09 17:12 ` [PATCH net-next v4 2/4] net: dsa: yt921x: Refactor long register helpers David Yang
2026-04-09 17:12 ` [PATCH net-next v4 3/4] net: dsa: yt921x: Add port police support David Yang
2026-04-09 17:12 ` David Yang [this message]
2026-04-13 22:32 ` [PATCH net-next v4 4/4] net: dsa: yt921x: Add port qdisc tbf support Jakub Kicinski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260409171209.2575583-5-mmyangfl@gmail.com \
--to=mmyangfl@gmail.com \
--cc=andrew@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=olteanv@gmail.com \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.