Merge branch 'net-dsa-yt921x-add-port-tbf-support'

David Yang says:

====================
net: dsa: yt921x: Add port TBF support
====================

Link: https://patch.msgid.link/20260521010320.208138-1-mmyangfl@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2026-05-22 17:23:43 -07:00
commit 24822968aa
5 changed files with 114 additions and 3 deletions

View File

@ -24,6 +24,7 @@
#include <net/dsa.h>
#include <net/dscp.h>
#include <net/ieee8021q.h>
#include <net/pkt_cls.h>
#include "yt921x.h"
@ -1272,6 +1273,17 @@ 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, struct yt921x_priv *priv, int port,
struct netlink_ext_ack *extack)
{
return yt921x_marker_tfm(marker, rate, burst, flags,
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,
@ -1378,6 +1390,73 @@ yt921x_dsa_port_policer_add(struct dsa_switch *ds, int port,
return res;
}
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);
struct netlink_ext_ack *extack = qopt->extack;
u32 ctrls[2];
int res;
if (qopt->parent != TC_H_ROOT)
return -EOPNOTSUPP;
switch (qopt->command) {
case TC_TBF_STATS:
/* Unfortunately the convention for TC_*_STATS is a mess,
* neither 0 nor -EOPNOTSUPP is perfect here.
*/
return -EOPNOTSUPP;
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;
p = &qopt->replace_params;
res = yt921x_marker_tfm_shape(&marker, p->rate.rate_bytes_ps,
p->max_size,
YT921X_MARKER_SINGLE_BUCKET,
priv, port, extack);
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)
{
switch (type) {
case TC_SETUP_QDISC_TBF: {
const struct tc_tbf_qopt_offload *qopt = type_data;
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)
{
@ -3523,6 +3602,13 @@ 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;
return 0;
}
@ -3679,6 +3765,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,

View File

@ -531,6 +531,19 @@ 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_PORT_SHAPE_SLOT 0x34000c
#define YT921X_PORT_SHAPE_SLOT_SLOT_M GENMASK(11, 0)
#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_PORTn_SHAPE_STAT(port) (0x356000 + 4 * (port))
#define YT921X_EDATA_EXTMODE 0xfb
#define YT921X_EDATA_LEN 0x100
@ -556,6 +569,10 @@ 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_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
@ -652,6 +669,7 @@ struct yt921x_priv {
const struct yt921x_info *info;
unsigned int meter_slot_ns;
unsigned int port_shape_slot_ns;
/* cache of dsa_cpu_ports(ds) */
u16 cpu_ports_mask;
unsigned char cycle_ns;

View File

@ -1046,6 +1046,7 @@ struct tc_tbf_qopt_offload_replace_params {
};
struct tc_tbf_qopt_offload {
struct netlink_ext_ack *extack;
enum tc_tbf_command command;
u32 handle;
u32 parent;

View File

@ -859,7 +859,7 @@ void qdisc_offload_graft_helper(struct net_device *dev, struct Qdisc *sch,
any_qdisc_is_offloaded |= old && old->flags & TCQ_F_OFFLOADED;
if (any_qdisc_is_offloaded)
NL_SET_ERR_MSG(extack, "Offloading graft operation failed.");
NL_SET_ERR_MSG_WEAK(extack, "Offloading graft operation failed.");
}
EXPORT_SYMBOL(qdisc_offload_graft_helper);

View File

@ -139,7 +139,8 @@ static u64 psched_ns_t2l(const struct psched_ratecfg *r,
return len;
}
static void tbf_offload_change(struct Qdisc *sch)
static void tbf_offload_change(struct Qdisc *sch,
struct netlink_ext_ack *extack)
{
struct tbf_sched_data *q = qdisc_priv(sch);
struct net_device *dev = qdisc_dev(sch);
@ -148,6 +149,7 @@ static void tbf_offload_change(struct Qdisc *sch)
if (!tc_can_offload(dev) || !dev->netdev_ops->ndo_setup_tc)
return;
qopt.extack = extack;
qopt.command = TC_TBF_REPLACE;
qopt.handle = sch->handle;
qopt.parent = sch->parent;
@ -166,6 +168,7 @@ static void tbf_offload_destroy(struct Qdisc *sch)
if (!tc_can_offload(dev) || !dev->netdev_ops->ndo_setup_tc)
return;
qopt.extack = NULL;
qopt.command = TC_TBF_DESTROY;
qopt.handle = sch->handle;
qopt.parent = sch->parent;
@ -176,6 +179,7 @@ static int tbf_offload_dump(struct Qdisc *sch)
{
struct tc_tbf_qopt_offload qopt;
qopt.extack = NULL;
qopt.command = TC_TBF_STATS;
qopt.handle = sch->handle;
qopt.parent = sch->parent;
@ -193,6 +197,7 @@ static void tbf_offload_graft(struct Qdisc *sch, struct Qdisc *new,
.parent = sch->parent,
.child_handle = new->handle,
.command = TC_TBF_GRAFT,
.extack = extack,
};
qdisc_offload_graft_helper(qdisc_dev(sch), sch, new, old,
@ -477,7 +482,7 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt,
qdisc_put(old);
err = 0;
tbf_offload_change(sch);
tbf_offload_change(sch, extack);
done:
return err;
}