Skip to content

Commit 3101f3e

Browse files
committed
Merge branch 'dsa-simple-hsr-offload'
Vladimir Oltean says: ==================== DSA simple HSR offload Provide a "simple" form of HSR offload for 8 DSA drivers (just the NETIF_F_HW_HSR_DUP feature) based on the fact that their taggers use the dsa_xmit_port_mask() function. This is in patches 6-13/15. The helpers per se are introduced in patch 5/15, and documented in patch 15/15. Patch 14/15 is another small (and related) documentation update. For HSR interlink ports the offloading rules are not quite so clear, and for now we completely reject the offload. We can revise that once we see a full offload implementation and understand what is needed. To reject the offload, we need to know the port type, and patch 2/15 helps with that. xrs700x is another driver which should have rejected offload based on port type (patch 4/15). This is a bug fix submitted through net-next due to the extra API required to fix it. If necessary, it could also be picked up separately for backporting. There is also patch 3/15, which makes the HSR offload like the others supported by DSA: if we fall back to the software implementation, don't call port_hsr_leave(), because by definition there won't be anything to do. A slightly unrelated change is patch 1/15, but I noticed this along the way, and if I were to submit it separately, it would conflict with this work (it would appear in patch 12/15's context). Most of the driver additions are trivial. By far the most complex was ocelot (which I could test). Microchip ksz (which I cannot test, and did not patch) would also have some complexity. Essentially, ksz_hsr_join() could fall back to a partial offload through the simple helpers, if the full offload is not possible. But keeping track of which offload kind was used is necessary later in ksz_hsr_leave(). This is left as homework for interested developers. With this patch set, one can observe a 50% reduction in transmitted traffic over HSR interfaces. ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents b4dcaee + 4e4c00f commit 3101f3e

File tree

18 files changed

+220
-12
lines changed

18 files changed

+220
-12
lines changed

Documentation/networking/dsa/dsa.rst

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,12 +1104,11 @@ health of the network and for discovery of other nodes.
11041104
In Linux, both HSR and PRP are implemented in the hsr driver, which
11051105
instantiates a virtual, stackable network interface with two member ports.
11061106
The driver only implements the basic roles of DANH (Doubly Attached Node
1107-
implementing HSR) and DANP (Doubly Attached Node implementing PRP); the roles
1108-
of RedBox and QuadBox are not implemented (therefore, bridging a hsr network
1109-
interface with a physical switch port does not produce the expected result).
1107+
implementing HSR), DANP (Doubly Attached Node implementing PRP) and RedBox
1108+
(allows non-HSR devices to connect to the ring via Interlink ports).
11101109

1111-
A driver which is able of offloading certain functions of a DANP or DANH should
1112-
declare the corresponding netdev features as indicated by the documentation at
1110+
A driver which is able of offloading certain functions should declare the
1111+
corresponding netdev features as indicated by the documentation at
11131112
``Documentation/networking/netdev-features.rst``. Additionally, the following
11141113
methods must be implemented:
11151114

@@ -1120,6 +1119,14 @@ methods must be implemented:
11201119
- ``port_hsr_leave``: function invoked when a given switch port leaves a
11211120
DANP/DANH and returns to normal operation as a standalone port.
11221121

1122+
Note that the ``NETIF_F_HW_HSR_DUP`` feature relies on transmission towards
1123+
multiple ports, which is generally available whenever the tagging protocol uses
1124+
the ``dsa_xmit_port_mask()`` helper function. If the helper is used, the HSR
1125+
offload feature should also be set. The ``dsa_port_simple_hsr_join()`` and
1126+
``dsa_port_simple_hsr_leave()`` methods can be used as generic implementations
1127+
of ``port_hsr_join`` and ``port_hsr_leave``, if this is the only supported
1128+
offload feature.
1129+
11231130
TODO
11241131
====
11251132

drivers/net/dsa/hirschmann/hellcreek.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1926,6 +1926,8 @@ static const struct dsa_switch_ops hellcreek_ds_ops = {
19261926
.port_vlan_filtering = hellcreek_vlan_filtering,
19271927
.setup = hellcreek_setup,
19281928
.teardown = hellcreek_teardown,
1929+
.port_hsr_join = dsa_port_simple_hsr_join,
1930+
.port_hsr_leave = dsa_port_simple_hsr_leave,
19291931
};
19301932

19311933
static int hellcreek_probe(struct platform_device *pdev)

drivers/net/dsa/lantiq/lantiq_gswip_common.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1652,6 +1652,8 @@ static const struct dsa_switch_ops gswip_switch_ops = {
16521652
.get_sset_count = gswip_get_sset_count,
16531653
.set_mac_eee = gswip_set_mac_eee,
16541654
.support_eee = gswip_support_eee,
1655+
.port_hsr_join = dsa_port_simple_hsr_join,
1656+
.port_hsr_leave = dsa_port_simple_hsr_leave,
16551657
};
16561658

16571659
void gswip_disable_switch(struct gswip_priv *priv)

drivers/net/dsa/mt7530.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3254,7 +3254,7 @@ static int mt7988_setup(struct dsa_switch *ds)
32543254
return mt7531_setup_common(ds);
32553255
}
32563256

3257-
const struct dsa_switch_ops mt7530_switch_ops = {
3257+
static const struct dsa_switch_ops mt7530_switch_ops = {
32583258
.get_tag_protocol = mtk_get_tag_protocol,
32593259
.setup = mt753x_setup,
32603260
.preferred_default_local_cpu_port = mt753x_preferred_default_local_cpu_port,
@@ -3290,8 +3290,9 @@ const struct dsa_switch_ops mt7530_switch_ops = {
32903290
.set_mac_eee = mt753x_set_mac_eee,
32913291
.conduit_state_change = mt753x_conduit_state_change,
32923292
.port_setup_tc = mt753x_setup_tc,
3293+
.port_hsr_join = dsa_port_simple_hsr_join,
3294+
.port_hsr_leave = dsa_port_simple_hsr_leave,
32933295
};
3294-
EXPORT_SYMBOL_GPL(mt7530_switch_ops);
32953296

32963297
static const struct phylink_mac_ops mt753x_phylink_mac_ops = {
32973298
.mac_select_pcs = mt753x_phylink_mac_select_pcs,

drivers/net/dsa/mt7530.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -939,7 +939,6 @@ static inline void INIT_MT7530_DUMMY_POLL(struct mt7530_dummy_poll *p,
939939
int mt7530_probe_common(struct mt7530_priv *priv);
940940
void mt7530_remove_common(struct mt7530_priv *priv);
941941

942-
extern const struct dsa_switch_ops mt7530_switch_ops;
943942
extern const struct mt753x_info mt753x_table[];
944943

945944
#endif /* __MT7530_H */

drivers/net/dsa/mv88e6060.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,8 @@ static const struct dsa_switch_ops mv88e6060_switch_ops = {
297297
.phy_read = mv88e6060_phy_read,
298298
.phy_write = mv88e6060_phy_write,
299299
.phylink_get_caps = mv88e6060_phylink_get_caps,
300+
.port_hsr_join = dsa_port_simple_hsr_join,
301+
.port_hsr_leave = dsa_port_simple_hsr_leave,
300302
};
301303

302304
static int mv88e6060_probe(struct mdio_device *mdiodev)

drivers/net/dsa/ocelot/felix.c

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1233,6 +1233,7 @@ static int felix_port_enable(struct dsa_switch *ds, int port,
12331233
{
12341234
struct dsa_port *dp = dsa_to_port(ds, port);
12351235
struct ocelot *ocelot = ds->priv;
1236+
struct felix *felix = ocelot_to_felix(ocelot);
12361237

12371238
if (!dsa_port_is_user(dp))
12381239
return 0;
@@ -1246,7 +1247,25 @@ static int felix_port_enable(struct dsa_switch *ds, int port,
12461247
}
12471248
}
12481249

1249-
return 0;
1250+
if (!dp->hsr_dev || felix->tag_proto == DSA_TAG_PROTO_OCELOT_8021Q)
1251+
return 0;
1252+
1253+
return dsa_port_simple_hsr_join(ds, port, dp->hsr_dev, NULL);
1254+
}
1255+
1256+
static void felix_port_disable(struct dsa_switch *ds, int port)
1257+
{
1258+
struct dsa_port *dp = dsa_to_port(ds, port);
1259+
struct ocelot *ocelot = ds->priv;
1260+
struct felix *felix = ocelot_to_felix(ocelot);
1261+
1262+
if (!dsa_port_is_user(dp))
1263+
return;
1264+
1265+
if (!dp->hsr_dev || felix->tag_proto == DSA_TAG_PROTO_OCELOT_8021Q)
1266+
return;
1267+
1268+
dsa_port_simple_hsr_leave(ds, port, dp->hsr_dev);
12501269
}
12511270

12521271
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,
22322251
ocelot_port_get_mm_stats(ocelot, port, stats);
22332252
}
22342253

2254+
/* Depending on port type, we may be able to support the offload later (with
2255+
* the "ocelot"/"seville" tagging protocols), or never.
2256+
* If we return 0, the dp->hsr_dev reference is kept for later; if we return
2257+
* -EOPNOTSUPP, it is cleared (which helps to not bother
2258+
* dsa_port_simple_hsr_leave() with an offload that didn't pass validation).
2259+
*/
2260+
static int felix_port_hsr_join(struct dsa_switch *ds, int port,
2261+
struct net_device *hsr,
2262+
struct netlink_ext_ack *extack)
2263+
{
2264+
struct ocelot *ocelot = ds->priv;
2265+
struct felix *felix = ocelot_to_felix(ocelot);
2266+
2267+
if (felix->tag_proto == DSA_TAG_PROTO_OCELOT_8021Q) {
2268+
int err;
2269+
2270+
err = dsa_port_simple_hsr_validate(ds, port, hsr, extack);
2271+
if (err)
2272+
return err;
2273+
2274+
NL_SET_ERR_MSG_MOD(extack,
2275+
"Offloading not supported with \"ocelot-8021q\"");
2276+
return 0;
2277+
}
2278+
2279+
if (!(dsa_to_port(ds, port)->user->flags & IFF_UP))
2280+
return 0;
2281+
2282+
return dsa_port_simple_hsr_join(ds, port, hsr, extack);
2283+
}
2284+
2285+
static int felix_port_hsr_leave(struct dsa_switch *ds, int port,
2286+
struct net_device *hsr)
2287+
{
2288+
struct ocelot *ocelot = ds->priv;
2289+
struct felix *felix = ocelot_to_felix(ocelot);
2290+
2291+
if (felix->tag_proto == DSA_TAG_PROTO_OCELOT_8021Q)
2292+
return 0;
2293+
2294+
if (!(dsa_to_port(ds, port)->user->flags & IFF_UP))
2295+
return 0;
2296+
2297+
return dsa_port_simple_hsr_leave(ds, port, hsr);
2298+
}
2299+
22352300
static const struct phylink_mac_ops felix_phylink_mac_ops = {
22362301
.mac_select_pcs = felix_phylink_mac_select_pcs,
22372302
.mac_config = felix_phylink_mac_config,
@@ -2262,6 +2327,7 @@ static const struct dsa_switch_ops felix_switch_ops = {
22622327
.get_ts_info = felix_get_ts_info,
22632328
.phylink_get_caps = felix_phylink_get_caps,
22642329
.port_enable = felix_port_enable,
2330+
.port_disable = felix_port_disable,
22652331
.port_fast_age = felix_port_fast_age,
22662332
.port_fdb_dump = felix_fdb_dump,
22672333
.port_fdb_add = felix_fdb_add,
@@ -2318,6 +2384,8 @@ static const struct dsa_switch_ops felix_switch_ops = {
23182384
.port_del_dscp_prio = felix_port_del_dscp_prio,
23192385
.port_set_host_flood = felix_port_set_host_flood,
23202386
.port_change_conduit = felix_port_change_conduit,
2387+
.port_hsr_join = felix_port_hsr_join,
2388+
.port_hsr_leave = felix_port_hsr_leave,
23212389
};
23222390

23232391
int felix_register_switch(struct device *dev, resource_size_t switch_base,

drivers/net/dsa/realtek/rtl8365mb.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2134,6 +2134,8 @@ static const struct dsa_switch_ops rtl8365mb_switch_ops = {
21342134
.get_stats64 = rtl8365mb_get_stats64,
21352135
.port_change_mtu = rtl8365mb_port_change_mtu,
21362136
.port_max_mtu = rtl8365mb_port_max_mtu,
2137+
.port_hsr_join = dsa_port_simple_hsr_join,
2138+
.port_hsr_leave = dsa_port_simple_hsr_leave,
21372139
};
21382140

21392141
static const struct realtek_ops rtl8365mb_ops = {

drivers/net/dsa/realtek/rtl8366rb.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1815,6 +1815,8 @@ static const struct dsa_switch_ops rtl8366rb_switch_ops = {
18151815
.port_fast_age = rtl8366rb_port_fast_age,
18161816
.port_change_mtu = rtl8366rb_change_mtu,
18171817
.port_max_mtu = rtl8366rb_max_mtu,
1818+
.port_hsr_join = dsa_port_simple_hsr_join,
1819+
.port_hsr_leave = dsa_port_simple_hsr_leave,
18181820
};
18191821

18201822
static const struct realtek_ops rtl8366rb_ops = {

drivers/net/dsa/rzn1_a5psw.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,6 +1035,8 @@ static const struct dsa_switch_ops a5psw_switch_ops = {
10351035
.port_fdb_add = a5psw_port_fdb_add,
10361036
.port_fdb_del = a5psw_port_fdb_del,
10371037
.port_fdb_dump = a5psw_port_fdb_dump,
1038+
.port_hsr_join = dsa_port_simple_hsr_join,
1039+
.port_hsr_leave = dsa_port_simple_hsr_leave,
10381040
};
10391041

10401042
static int a5psw_mdio_wait_busy(struct a5psw *a5psw)

0 commit comments

Comments
 (0)