diff options
| author | Vladimir Oltean <vladimir.oltean@nxp.com> | 2025-11-30 15:16:49 +0200 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2025-12-01 16:45:07 -0800 |
| commit | 4b65d445556d398b54fbeed8780ea9f07813f757 (patch) | |
| tree | 2e46e5a5e9fe142e34031a408d6ce697724f29ee /drivers | |
| parent | 42e63b1373a32bd136dc51325684727f3b9a4986 (diff) | |
| download | linux-4b65d445556d398b54fbeed8780ea9f07813f757.tar.gz | |
net: dsa: ocelot: use simple HSR offload helpers
Accelerate TX packet duplication with HSR rings.
This is only possible with the NPI-based "ocelot" tagging protocol, not
with "ocelot-8021q", because the latter does not use dsa_xmit_port_mask().
This has 2 implications:
- Depending on tagging protocol, we should set (or not set) the offload
feature flags. Switching tagging protocols is done with ports down, by
design. Additional calls to dsa_port_simple_hsr_join() can be put in
the ds->ops->change_tag_protocol() path, as I had originally tried,
but this would not work: dsa_user_setup_tagger() would later clear
the feature flag that we just set. So the additional call to
dsa_port_simple_hsr_join() should sit in the ds->ops->port_enable()
call.
- When joining a HSR ring and we are currently using "ocelot-8021q",
there are cases when we should return -EOPNOTSUPP (pessimistic) and
cases when we shouldn't (optimistic). In the pessimistic case, it is a
configuration that the port won't support even with the right tagging
protocol. Distinguishing between these 2 cases matters because if we
just return -EOPNOTSUPP regardless, we lose the dp->hsr_dev pointer
and can no longer replay the offload later for the optimistic case,
from felix_port_enable().
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Link: https://patch.msgid.link/20251130131657.65080-8-vladimir.oltean@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/net/dsa/ocelot/felix.c | 70 |
1 files changed, 69 insertions, 1 deletions
diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index 20ab558fde2476..9e5ede932b421f 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -1233,6 +1233,7 @@ static int felix_port_enable(struct dsa_switch *ds, int port, { struct dsa_port *dp = dsa_to_port(ds, port); struct ocelot *ocelot = ds->priv; + struct felix *felix = ocelot_to_felix(ocelot); if (!dsa_port_is_user(dp)) return 0; @@ -1246,7 +1247,25 @@ static int felix_port_enable(struct dsa_switch *ds, int port, } } - return 0; + if (!dp->hsr_dev || felix->tag_proto == DSA_TAG_PROTO_OCELOT_8021Q) + return 0; + + return dsa_port_simple_hsr_join(ds, port, dp->hsr_dev, NULL); +} + +static void felix_port_disable(struct dsa_switch *ds, int port) +{ + struct dsa_port *dp = dsa_to_port(ds, port); + struct ocelot *ocelot = ds->priv; + struct felix *felix = ocelot_to_felix(ocelot); + + if (!dsa_port_is_user(dp)) + return; + + if (!dp->hsr_dev || felix->tag_proto == DSA_TAG_PROTO_OCELOT_8021Q) + return; + + dsa_port_simple_hsr_leave(ds, port, dp->hsr_dev); } static void felix_port_qos_map_init(struct ocelot *ocelot, int port) @@ -2232,6 +2251,52 @@ static void felix_get_mm_stats(struct dsa_switch *ds, int port, ocelot_port_get_mm_stats(ocelot, port, stats); } +/* Depending on port type, we may be able to support the offload later (with + * the "ocelot"/"seville" tagging protocols), or never. + * If we return 0, the dp->hsr_dev reference is kept for later; if we return + * -EOPNOTSUPP, it is cleared (which helps to not bother + * dsa_port_simple_hsr_leave() with an offload that didn't pass validation). + */ +static int felix_port_hsr_join(struct dsa_switch *ds, int port, + struct net_device *hsr, + struct netlink_ext_ack *extack) +{ + struct ocelot *ocelot = ds->priv; + struct felix *felix = ocelot_to_felix(ocelot); + + if (felix->tag_proto == DSA_TAG_PROTO_OCELOT_8021Q) { + int err; + + err = dsa_port_simple_hsr_validate(ds, port, hsr, extack); + if (err) + return err; + + NL_SET_ERR_MSG_MOD(extack, + "Offloading not supported with \"ocelot-8021q\""); + return 0; + } + + if (!(dsa_to_port(ds, port)->user->flags & IFF_UP)) + return 0; + + return dsa_port_simple_hsr_join(ds, port, hsr, extack); +} + +static int felix_port_hsr_leave(struct dsa_switch *ds, int port, + struct net_device *hsr) +{ + struct ocelot *ocelot = ds->priv; + struct felix *felix = ocelot_to_felix(ocelot); + + if (felix->tag_proto == DSA_TAG_PROTO_OCELOT_8021Q) + return 0; + + if (!(dsa_to_port(ds, port)->user->flags & IFF_UP)) + return 0; + + return dsa_port_simple_hsr_leave(ds, port, hsr); +} + static const struct phylink_mac_ops felix_phylink_mac_ops = { .mac_select_pcs = felix_phylink_mac_select_pcs, .mac_config = felix_phylink_mac_config, @@ -2262,6 +2327,7 @@ static const struct dsa_switch_ops felix_switch_ops = { .get_ts_info = felix_get_ts_info, .phylink_get_caps = felix_phylink_get_caps, .port_enable = felix_port_enable, + .port_disable = felix_port_disable, .port_fast_age = felix_port_fast_age, .port_fdb_dump = felix_fdb_dump, .port_fdb_add = felix_fdb_add, @@ -2318,6 +2384,8 @@ static const struct dsa_switch_ops felix_switch_ops = { .port_del_dscp_prio = felix_port_del_dscp_prio, .port_set_host_flood = felix_port_set_host_flood, .port_change_conduit = felix_port_change_conduit, + .port_hsr_join = felix_port_hsr_join, + .port_hsr_leave = felix_port_hsr_leave, }; int felix_register_switch(struct device *dev, resource_size_t switch_base, |
