1 From ef07df397a621707903ef0d294a7df11f80cf206 Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari@gmail.com>
3 Date: Sat, 14 Jun 2025 09:59:48 +0200
4 Subject: [PATCH] net: dsa: tag_brcm: add support for legacy FCS tags
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
9 Add support for legacy Broadcom FCS tags, which are similar to
10 DSA_TAG_PROTO_BRCM_LEGACY.
11 BCM5325 and BCM5365 switches require including the original FCS value and
12 length, as opposed to BCM63xx switches.
13 Adding the original FCS value and length to DSA_TAG_PROTO_BRCM_LEGACY would
14 impact performance of BCM63xx switches, so it's better to create a new tag.
16 Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
17 Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
18 Link: https://patch.msgid.link/20250614080000.1884236-3-noltari@gmail.com
19 Signed-off-by: Jakub Kicinski <kuba@kernel.org>
21 include/net/dsa.h | 2 ++
22 net/dsa/Kconfig | 16 ++++++++--
23 net/dsa/tag_brcm.c | 73 +++++++++++++++++++++++++++++++++++++++++++++-
24 3 files changed, 88 insertions(+), 3 deletions(-)
26 --- a/include/net/dsa.h
27 +++ b/include/net/dsa.h
28 @@ -54,11 +54,13 @@ struct tc_action;
29 #define DSA_TAG_PROTO_RZN1_A5PSW_VALUE 26
30 #define DSA_TAG_PROTO_LAN937X_VALUE 27
31 #define DSA_TAG_PROTO_VSC73XX_8021Q_VALUE 28
32 +#define DSA_TAG_PROTO_BRCM_LEGACY_FCS_VALUE 29
34 enum dsa_tag_protocol {
35 DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE,
36 DSA_TAG_PROTO_BRCM = DSA_TAG_PROTO_BRCM_VALUE,
37 DSA_TAG_PROTO_BRCM_LEGACY = DSA_TAG_PROTO_BRCM_LEGACY_VALUE,
38 + DSA_TAG_PROTO_BRCM_LEGACY_FCS = DSA_TAG_PROTO_BRCM_LEGACY_FCS_VALUE,
39 DSA_TAG_PROTO_BRCM_PREPEND = DSA_TAG_PROTO_BRCM_PREPEND_VALUE,
40 DSA_TAG_PROTO_DSA = DSA_TAG_PROTO_DSA_VALUE,
41 DSA_TAG_PROTO_EDSA = DSA_TAG_PROTO_EDSA_VALUE,
44 @@ -42,12 +42,24 @@ config NET_DSA_TAG_BRCM
45 Broadcom switches which place the tag after the MAC source address.
47 config NET_DSA_TAG_BRCM_LEGACY
48 - tristate "Tag driver for Broadcom legacy switches using in-frame headers"
49 + tristate "Tag driver for BCM63xx legacy switches using in-frame headers"
50 select NET_DSA_TAG_BRCM_COMMON
52 Say Y if you want to enable support for tagging frames for the
53 - Broadcom legacy switches which place the tag after the MAC source
54 + BCM63xx legacy switches which place the tag after the MAC source
56 + This tag is used in BCM63xx legacy switches which work without the
57 + original FCS and length before the tag insertion.
59 +config NET_DSA_TAG_BRCM_LEGACY_FCS
60 + tristate "Tag driver for BCM53xx legacy switches using in-frame headers"
61 + select NET_DSA_TAG_BRCM_COMMON
63 + Say Y if you want to enable support for tagging frames for the
64 + BCM53xx legacy switches which place the tag after the MAC source
66 + This tag is used in BCM53xx legacy switches which expect original
67 + FCS and length before the tag insertion to be present.
69 config NET_DSA_TAG_BRCM_PREPEND
70 tristate "Tag driver for Broadcom switches using prepended headers"
71 --- a/net/dsa/tag_brcm.c
72 +++ b/net/dsa/tag_brcm.c
75 #define BRCM_NAME "brcm"
76 #define BRCM_LEGACY_NAME "brcm-legacy"
77 +#define BRCM_LEGACY_FCS_NAME "brcm-legacy-fcs"
78 #define BRCM_PREPEND_NAME "brcm-prepend"
80 /* Legacy Broadcom tag (6 bytes) */
82 #define BRCM_LEG_MULTICAST (1 << 5)
83 #define BRCM_LEG_EGRESS (2 << 5)
84 #define BRCM_LEG_INGRESS (3 << 5)
85 +#define BRCM_LEG_LEN_HI(x) (((x) >> 8) & 0x7)
87 +/* 4th byte in the tag */
88 +#define BRCM_LEG_LEN_LO(x) ((x) & 0xff)
90 /* 6th byte in the tag */
91 #define BRCM_LEG_PORT_ID (0xf)
92 @@ -212,7 +217,8 @@ DSA_TAG_DRIVER(brcm_netdev_ops);
93 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM, BRCM_NAME);
96 -#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY)
97 +#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY) || \
98 + IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS)
99 static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb,
100 struct net_device *dev)
102 @@ -244,7 +250,9 @@ static struct sk_buff *brcm_leg_tag_rcv(
106 +#endif /* CONFIG_NET_DSA_TAG_BRCM_LEGACY || CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS */
108 +#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY)
109 static struct sk_buff *brcm_leg_tag_xmit(struct sk_buff *skb,
110 struct net_device *dev)
112 @@ -294,6 +302,66 @@ DSA_TAG_DRIVER(brcm_legacy_netdev_ops);
113 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM_LEGACY, BRCM_LEGACY_NAME);
114 #endif /* CONFIG_NET_DSA_TAG_BRCM_LEGACY */
116 +#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS)
117 +static struct sk_buff *brcm_leg_fcs_tag_xmit(struct sk_buff *skb,
118 + struct net_device *dev)
120 + struct dsa_port *dp = dsa_user_to_port(dev);
121 + unsigned int fcs_len;
125 + /* The Ethernet switch we are interfaced with needs packets to be at
126 + * least 64 bytes (including FCS) otherwise they will be discarded when
127 + * they enter the switch port logic. When Broadcom tags are enabled, we
128 + * need to make sure that packets are at least 70 bytes (including FCS
129 + * and tag) because the length verification is done after the Broadcom
130 + * tag is stripped off the ingress packet.
132 + * Let dsa_user_xmit() free the SKB.
134 + if (__skb_put_padto(skb, ETH_ZLEN + BRCM_LEG_TAG_LEN, false))
137 + fcs_len = skb->len;
138 + fcs_val = cpu_to_le32(crc32_le(~0, skb->data, fcs_len) ^ ~0);
140 + skb_push(skb, BRCM_LEG_TAG_LEN);
142 + dsa_alloc_etype_header(skb, BRCM_LEG_TAG_LEN);
144 + brcm_tag = skb->data + 2 * ETH_ALEN;
146 + /* Broadcom tag type */
147 + brcm_tag[0] = BRCM_LEG_TYPE_HI;
148 + brcm_tag[1] = BRCM_LEG_TYPE_LO;
150 + /* Broadcom tag value */
151 + brcm_tag[2] = BRCM_LEG_EGRESS | BRCM_LEG_LEN_HI(fcs_len);
152 + brcm_tag[3] = BRCM_LEG_LEN_LO(fcs_len);
154 + brcm_tag[5] = dp->index & BRCM_LEG_PORT_ID;
156 + /* Original FCS value */
157 + if (__skb_pad(skb, ETH_FCS_LEN, false))
159 + skb_put_data(skb, &fcs_val, ETH_FCS_LEN);
164 +static const struct dsa_device_ops brcm_legacy_fcs_netdev_ops = {
165 + .name = BRCM_LEGACY_FCS_NAME,
166 + .proto = DSA_TAG_PROTO_BRCM_LEGACY_FCS,
167 + .xmit = brcm_leg_fcs_tag_xmit,
168 + .rcv = brcm_leg_tag_rcv,
169 + .needed_headroom = BRCM_LEG_TAG_LEN,
172 +DSA_TAG_DRIVER(brcm_legacy_fcs_netdev_ops);
173 +MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM_LEGACY_FCS, BRCM_LEGACY_FCS_NAME);
174 +#endif /* CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS */
176 #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_PREPEND)
177 static struct sk_buff *brcm_tag_xmit_prepend(struct sk_buff *skb,
178 struct net_device *dev)
179 @@ -328,6 +396,9 @@ static struct dsa_tag_driver *dsa_tag_dr
180 #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY)
181 &DSA_TAG_DRIVER_NAME(brcm_legacy_netdev_ops),
183 +#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS)
184 + &DSA_TAG_DRIVER_NAME(brcm_legacy_fcs_netdev_ops),
186 #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_PREPEND)
187 &DSA_TAG_DRIVER_NAME(brcm_prepend_netdev_ops),