898010f9509606a11ab7967f99b5de86589872ea
[openwrt/staging/ansuel.git] /
1 From c5290f636624b98e76a82bd63ffec0a8a9daa620 Mon Sep 17 00:00:00 2001
2 From: Christian Marangi <ansuelsmth@gmail.com>
3 Date: Wed, 27 Jul 2022 13:35:21 +0200
4 Subject: [PATCH 12/14] net: dsa: qca8k: move port VLAN functions to common
5 code
6
7 The same port VLAN functions are used by drivers based on qca8k family
8 switch. Move them to common code to make them accessible also by other
9 drivers.
10 Also drop exposing busy_wait and make it static.
11
12 Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
13 Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
14 Signed-off-by: Jakub Kicinski <kuba@kernel.org>
15 ---
16 drivers/net/dsa/qca/qca8k-8xxx.c | 182 -----------------------------
17 drivers/net/dsa/qca/qca8k-common.c | 179 +++++++++++++++++++++++++++-
18 drivers/net/dsa/qca/qca8k.h | 10 +-
19 3 files changed, 187 insertions(+), 184 deletions(-)
20
21 --- a/drivers/net/dsa/qca/qca8k-8xxx.c
22 +++ b/drivers/net/dsa/qca/qca8k-8xxx.c
23 @@ -15,7 +15,6 @@
24 #include <linux/of_net.h>
25 #include <linux/of_mdio.h>
26 #include <linux/of_platform.h>
27 -#include <linux/if_bridge.h>
28 #include <linux/mdio.h>
29 #include <linux/phylink.h>
30 #include <linux/gpio/consumer.h>
31 @@ -442,122 +441,6 @@ static struct regmap_config qca8k_regmap
32 };
33
34 static int
35 -qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid)
36 -{
37 - u32 reg;
38 - int ret;
39 -
40 - /* Set the command and VLAN index */
41 - reg = QCA8K_VTU_FUNC1_BUSY;
42 - reg |= cmd;
43 - reg |= FIELD_PREP(QCA8K_VTU_FUNC1_VID_MASK, vid);
44 -
45 - /* Write the function register triggering the table access */
46 - ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg);
47 - if (ret)
48 - return ret;
49 -
50 - /* wait for completion */
51 - ret = qca8k_busy_wait(priv, QCA8K_REG_VTU_FUNC1, QCA8K_VTU_FUNC1_BUSY);
52 - if (ret)
53 - return ret;
54 -
55 - /* Check for table full violation when adding an entry */
56 - if (cmd == QCA8K_VLAN_LOAD) {
57 - ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC1, &reg);
58 - if (ret < 0)
59 - return ret;
60 - if (reg & QCA8K_VTU_FUNC1_FULL)
61 - return -ENOMEM;
62 - }
63 -
64 - return 0;
65 -}
66 -
67 -static int
68 -qca8k_vlan_add(struct qca8k_priv *priv, u8 port, u16 vid, bool untagged)
69 -{
70 - u32 reg;
71 - int ret;
72 -
73 - /*
74 - We do the right thing with VLAN 0 and treat it as untagged while
75 - preserving the tag on egress.
76 - */
77 - if (vid == 0)
78 - return 0;
79 -
80 - mutex_lock(&priv->reg_mutex);
81 - ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid);
82 - if (ret < 0)
83 - goto out;
84 -
85 - ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, &reg);
86 - if (ret < 0)
87 - goto out;
88 - reg |= QCA8K_VTU_FUNC0_VALID | QCA8K_VTU_FUNC0_IVL_EN;
89 - reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port);
90 - if (untagged)
91 - reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(port);
92 - else
93 - reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(port);
94 -
95 - ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg);
96 - if (ret)
97 - goto out;
98 - ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid);
99 -
100 -out:
101 - mutex_unlock(&priv->reg_mutex);
102 -
103 - return ret;
104 -}
105 -
106 -static int
107 -qca8k_vlan_del(struct qca8k_priv *priv, u8 port, u16 vid)
108 -{
109 - u32 reg, mask;
110 - int ret, i;
111 - bool del;
112 -
113 - mutex_lock(&priv->reg_mutex);
114 - ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid);
115 - if (ret < 0)
116 - goto out;
117 -
118 - ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, &reg);
119 - if (ret < 0)
120 - goto out;
121 - reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port);
122 - reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(port);
123 -
124 - /* Check if we're the last member to be removed */
125 - del = true;
126 - for (i = 0; i < QCA8K_NUM_PORTS; i++) {
127 - mask = QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(i);
128 -
129 - if ((reg & mask) != mask) {
130 - del = false;
131 - break;
132 - }
133 - }
134 -
135 - if (del) {
136 - ret = qca8k_vlan_access(priv, QCA8K_VLAN_PURGE, vid);
137 - } else {
138 - ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg);
139 - if (ret)
140 - goto out;
141 - ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid);
142 - }
143 -
144 -out:
145 - mutex_unlock(&priv->reg_mutex);
146 -
147 - return ret;
148 -}
149 -
150 -static int
151 qca8k_phy_eth_busy_wait(struct qca8k_mgmt_eth_data *mgmt_eth_data,
152 struct sk_buff *read_skb, u32 *val)
153 {
154 @@ -1836,71 +1719,6 @@ exit:
155
156 return ret;
157 }
158 -
159 -static int
160 -qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
161 - struct netlink_ext_ack *extack)
162 -{
163 - struct qca8k_priv *priv = ds->priv;
164 - int ret;
165 -
166 - if (vlan_filtering) {
167 - ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
168 - QCA8K_PORT_LOOKUP_VLAN_MODE_MASK,
169 - QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE);
170 - } else {
171 - ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
172 - QCA8K_PORT_LOOKUP_VLAN_MODE_MASK,
173 - QCA8K_PORT_LOOKUP_VLAN_MODE_NONE);
174 - }
175 -
176 - return ret;
177 -}
178 -
179 -static int
180 -qca8k_port_vlan_add(struct dsa_switch *ds, int port,
181 - const struct switchdev_obj_port_vlan *vlan,
182 - struct netlink_ext_ack *extack)
183 -{
184 - bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
185 - bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
186 - struct qca8k_priv *priv = ds->priv;
187 - int ret;
188 -
189 - ret = qca8k_vlan_add(priv, port, vlan->vid, untagged);
190 - if (ret) {
191 - dev_err(priv->dev, "Failed to add VLAN to port %d (%d)", port, ret);
192 - return ret;
193 - }
194 -
195 - if (pvid) {
196 - ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port),
197 - QCA8K_EGREES_VLAN_PORT_MASK(port),
198 - QCA8K_EGREES_VLAN_PORT(port, vlan->vid));
199 - if (ret)
200 - return ret;
201 -
202 - ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port),
203 - QCA8K_PORT_VLAN_CVID(vlan->vid) |
204 - QCA8K_PORT_VLAN_SVID(vlan->vid));
205 - }
206 -
207 - return ret;
208 -}
209 -
210 -static int
211 -qca8k_port_vlan_del(struct dsa_switch *ds, int port,
212 - const struct switchdev_obj_port_vlan *vlan)
213 -{
214 - struct qca8k_priv *priv = ds->priv;
215 - int ret;
216 -
217 - ret = qca8k_vlan_del(priv, port, vlan->vid);
218 - if (ret)
219 - dev_err(priv->dev, "Failed to delete VLAN from port %d (%d)", port, ret);
220 -
221 - return ret;
222 -}
223
224 static u32 qca8k_get_phy_flags(struct dsa_switch *ds, int port)
225 {
226 --- a/drivers/net/dsa/qca/qca8k-common.c
227 +++ b/drivers/net/dsa/qca/qca8k-common.c
228 @@ -141,7 +141,7 @@ static int qca8k_bulk_write(struct qca8k
229 return 0;
230 }
231
232 -int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask)
233 +static int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask)
234 {
235 u32 val;
236
237 @@ -354,6 +354,120 @@ exit:
238 return ret;
239 }
240
241 +static int qca8k_vlan_access(struct qca8k_priv *priv,
242 + enum qca8k_vlan_cmd cmd, u16 vid)
243 +{
244 + u32 reg;
245 + int ret;
246 +
247 + /* Set the command and VLAN index */
248 + reg = QCA8K_VTU_FUNC1_BUSY;
249 + reg |= cmd;
250 + reg |= FIELD_PREP(QCA8K_VTU_FUNC1_VID_MASK, vid);
251 +
252 + /* Write the function register triggering the table access */
253 + ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg);
254 + if (ret)
255 + return ret;
256 +
257 + /* wait for completion */
258 + ret = qca8k_busy_wait(priv, QCA8K_REG_VTU_FUNC1, QCA8K_VTU_FUNC1_BUSY);
259 + if (ret)
260 + return ret;
261 +
262 + /* Check for table full violation when adding an entry */
263 + if (cmd == QCA8K_VLAN_LOAD) {
264 + ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC1, &reg);
265 + if (ret < 0)
266 + return ret;
267 + if (reg & QCA8K_VTU_FUNC1_FULL)
268 + return -ENOMEM;
269 + }
270 +
271 + return 0;
272 +}
273 +
274 +static int qca8k_vlan_add(struct qca8k_priv *priv, u8 port, u16 vid,
275 + bool untagged)
276 +{
277 + u32 reg;
278 + int ret;
279 +
280 + /* We do the right thing with VLAN 0 and treat it as untagged while
281 + * preserving the tag on egress.
282 + */
283 + if (vid == 0)
284 + return 0;
285 +
286 + mutex_lock(&priv->reg_mutex);
287 + ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid);
288 + if (ret < 0)
289 + goto out;
290 +
291 + ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, &reg);
292 + if (ret < 0)
293 + goto out;
294 + reg |= QCA8K_VTU_FUNC0_VALID | QCA8K_VTU_FUNC0_IVL_EN;
295 + reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port);
296 + if (untagged)
297 + reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(port);
298 + else
299 + reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(port);
300 +
301 + ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg);
302 + if (ret)
303 + goto out;
304 + ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid);
305 +
306 +out:
307 + mutex_unlock(&priv->reg_mutex);
308 +
309 + return ret;
310 +}
311 +
312 +static int qca8k_vlan_del(struct qca8k_priv *priv, u8 port, u16 vid)
313 +{
314 + u32 reg, mask;
315 + int ret, i;
316 + bool del;
317 +
318 + mutex_lock(&priv->reg_mutex);
319 + ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid);
320 + if (ret < 0)
321 + goto out;
322 +
323 + ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, &reg);
324 + if (ret < 0)
325 + goto out;
326 + reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port);
327 + reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(port);
328 +
329 + /* Check if we're the last member to be removed */
330 + del = true;
331 + for (i = 0; i < QCA8K_NUM_PORTS; i++) {
332 + mask = QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(i);
333 +
334 + if ((reg & mask) != mask) {
335 + del = false;
336 + break;
337 + }
338 + }
339 +
340 + if (del) {
341 + ret = qca8k_vlan_access(priv, QCA8K_VLAN_PURGE, vid);
342 + } else {
343 + ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg);
344 + if (ret)
345 + goto out;
346 + ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid);
347 + }
348 +
349 +out:
350 + mutex_unlock(&priv->reg_mutex);
351 +
352 + return ret;
353 +}
354 +
355 int qca8k_mib_init(struct qca8k_priv *priv)
356 {
357 int ret;
358 @@ -832,3 +946,66 @@ void qca8k_port_mirror_del(struct dsa_sw
359 err:
360 dev_err(priv->dev, "Failed to del mirror port from %d", port);
361 }
362 +
363 +int qca8k_port_vlan_filtering(struct dsa_switch *ds, int port,
364 + bool vlan_filtering,
365 + struct netlink_ext_ack *extack)
366 +{
367 + struct qca8k_priv *priv = ds->priv;
368 + int ret;
369 +
370 + if (vlan_filtering) {
371 + ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
372 + QCA8K_PORT_LOOKUP_VLAN_MODE_MASK,
373 + QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE);
374 + } else {
375 + ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
376 + QCA8K_PORT_LOOKUP_VLAN_MODE_MASK,
377 + QCA8K_PORT_LOOKUP_VLAN_MODE_NONE);
378 + }
379 +
380 + return ret;
381 +}
382 +
383 +int qca8k_port_vlan_add(struct dsa_switch *ds, int port,
384 + const struct switchdev_obj_port_vlan *vlan,
385 + struct netlink_ext_ack *extack)
386 +{
387 + bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
388 + bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
389 + struct qca8k_priv *priv = ds->priv;
390 + int ret;
391 +
392 + ret = qca8k_vlan_add(priv, port, vlan->vid, untagged);
393 + if (ret) {
394 + dev_err(priv->dev, "Failed to add VLAN to port %d (%d)", port, ret);
395 + return ret;
396 + }
397 +
398 + if (pvid) {
399 + ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port),
400 + QCA8K_EGREES_VLAN_PORT_MASK(port),
401 + QCA8K_EGREES_VLAN_PORT(port, vlan->vid));
402 + if (ret)
403 + return ret;
404 +
405 + ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port),
406 + QCA8K_PORT_VLAN_CVID(vlan->vid) |
407 + QCA8K_PORT_VLAN_SVID(vlan->vid));
408 + }
409 +
410 + return ret;
411 +}
412 +
413 +int qca8k_port_vlan_del(struct dsa_switch *ds, int port,
414 + const struct switchdev_obj_port_vlan *vlan)
415 +{
416 + struct qca8k_priv *priv = ds->priv;
417 + int ret;
418 +
419 + ret = qca8k_vlan_del(priv, port, vlan->vid);
420 + if (ret)
421 + dev_err(priv->dev, "Failed to delete VLAN from port %d (%d)", port, ret);
422 +
423 + return ret;
424 +}
425 --- a/drivers/net/dsa/qca/qca8k.h
426 +++ b/drivers/net/dsa/qca/qca8k.h
427 @@ -431,7 +431,6 @@ int qca8k_write(struct qca8k_priv *priv,
428 int qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val);
429
430 /* Common ops function */
431 -int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask);
432 void qca8k_fdb_flush(struct qca8k_priv *priv);
433
434 /* Common ethtool stats function */
435 @@ -487,4 +486,13 @@ int qca8k_port_mirror_add(struct dsa_swi
436 void qca8k_port_mirror_del(struct dsa_switch *ds, int port,
437 struct dsa_mall_mirror_tc_entry *mirror);
438
439 +/* Common port VLAN function */
440 +int qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
441 + struct netlink_ext_ack *extack);
442 +int qca8k_port_vlan_add(struct dsa_switch *ds, int port,
443 + const struct switchdev_obj_port_vlan *vlan,
444 + struct netlink_ext_ack *extack);
445 +int qca8k_port_vlan_del(struct dsa_switch *ds, int port,
446 + const struct switchdev_obj_port_vlan *vlan);
447 +
448 #endif /* __QCA8K_H */