9f6b71ff6480a8437bfe4c6bdc995f5977f823f5
[openwrt/openwrt.git] /
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
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
8
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.
15
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>
20 ---
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(-)
25
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
33
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,
42 --- a/net/dsa/Kconfig
43 +++ b/net/dsa/Kconfig
44 @@ -42,12 +42,24 @@ config NET_DSA_TAG_BRCM
45 Broadcom switches which place the tag after the MAC source address.
46
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
51 help
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
55 address.
56 + This tag is used in BCM63xx legacy switches which work without the
57 + original FCS and length before the tag insertion.
58 +
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
62 + help
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
65 + address.
66 + This tag is used in BCM53xx legacy switches which expect original
67 + FCS and length before the tag insertion to be present.
68
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
73 @@ -15,6 +15,7 @@
74
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"
79
80 /* Legacy Broadcom tag (6 bytes) */
81 @@ -32,6 +33,10 @@
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)
86 +
87 +/* 4th byte in the tag */
88 +#define BRCM_LEG_LEN_LO(x) ((x) & 0xff)
89
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);
94 #endif
95
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)
101 {
102 @@ -244,7 +250,9 @@ static struct sk_buff *brcm_leg_tag_rcv(
103
104 return skb;
105 }
106 +#endif /* CONFIG_NET_DSA_TAG_BRCM_LEGACY || CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS */
107
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)
111 {
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 */
115
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)
119 +{
120 + struct dsa_port *dp = dsa_user_to_port(dev);
121 + unsigned int fcs_len;
122 + __le32 fcs_val;
123 + u8 *brcm_tag;
124 +
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.
131 + *
132 + * Let dsa_user_xmit() free the SKB.
133 + */
134 + if (__skb_put_padto(skb, ETH_ZLEN + BRCM_LEG_TAG_LEN, false))
135 + return NULL;
136 +
137 + fcs_len = skb->len;
138 + fcs_val = cpu_to_le32(crc32_le(~0, skb->data, fcs_len) ^ ~0);
139 +
140 + skb_push(skb, BRCM_LEG_TAG_LEN);
141 +
142 + dsa_alloc_etype_header(skb, BRCM_LEG_TAG_LEN);
143 +
144 + brcm_tag = skb->data + 2 * ETH_ALEN;
145 +
146 + /* Broadcom tag type */
147 + brcm_tag[0] = BRCM_LEG_TYPE_HI;
148 + brcm_tag[1] = BRCM_LEG_TYPE_LO;
149 +
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);
153 + brcm_tag[4] = 0;
154 + brcm_tag[5] = dp->index & BRCM_LEG_PORT_ID;
155 +
156 + /* Original FCS value */
157 + if (__skb_pad(skb, ETH_FCS_LEN, false))
158 + return NULL;
159 + skb_put_data(skb, &fcs_val, ETH_FCS_LEN);
160 +
161 + return skb;
162 +}
163 +
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,
170 +};
171 +
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 */
175 +
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),
182 #endif
183 +#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS)
184 + &DSA_TAG_DRIVER_NAME(brcm_legacy_fcs_netdev_ops),
185 +#endif
186 #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_PREPEND)
187 &DSA_TAG_DRIVER_NAME(brcm_prepend_netdev_ops),
188 #endif