kernel: fix mtk_eth_soc throughput regressions on gigabit PHY ports
[openwrt/openwrt.git] / target / linux / generic / backport-5.15 / 771-v6.0-10-net-dsa-qca8k-move-port-FDB-MDB-function-to-common-c.patch
1 From 2e5bd96eea86a246b4de3bf756f7a11b43e6187d Mon Sep 17 00:00:00 2001
2 From: Christian Marangi <ansuelsmth@gmail.com>
3 Date: Wed, 27 Jul 2022 13:35:19 +0200
4 Subject: [PATCH 10/14] net: dsa: qca8k: move port FDB/MDB function to common
5 code
6
7 The same port FDB/MDB function 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 bulk read/write functions and make them 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 | 306 -----------------------------
17 drivers/net/dsa/qca/qca8k-common.c | 297 +++++++++++++++++++++++++++-
18 drivers/net/dsa/qca/qca8k.h | 25 ++-
19 3 files changed, 317 insertions(+), 311 deletions(-)
20
21 --- a/drivers/net/dsa/qca/qca8k-8xxx.c
22 +++ b/drivers/net/dsa/qca/qca8k-8xxx.c
23 @@ -442,217 +442,6 @@ static struct regmap_config qca8k_regmap
24 };
25
26 static int
27 -qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb)
28 -{
29 - u32 reg[3];
30 - int ret;
31 -
32 - /* load the ARL table into an array */
33 - ret = qca8k_bulk_read(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg));
34 - if (ret)
35 - return ret;
36 -
37 - /* vid - 83:72 */
38 - fdb->vid = FIELD_GET(QCA8K_ATU_VID_MASK, reg[2]);
39 - /* aging - 67:64 */
40 - fdb->aging = FIELD_GET(QCA8K_ATU_STATUS_MASK, reg[2]);
41 - /* portmask - 54:48 */
42 - fdb->port_mask = FIELD_GET(QCA8K_ATU_PORT_MASK, reg[1]);
43 - /* mac - 47:0 */
44 - fdb->mac[0] = FIELD_GET(QCA8K_ATU_ADDR0_MASK, reg[1]);
45 - fdb->mac[1] = FIELD_GET(QCA8K_ATU_ADDR1_MASK, reg[1]);
46 - fdb->mac[2] = FIELD_GET(QCA8K_ATU_ADDR2_MASK, reg[0]);
47 - fdb->mac[3] = FIELD_GET(QCA8K_ATU_ADDR3_MASK, reg[0]);
48 - fdb->mac[4] = FIELD_GET(QCA8K_ATU_ADDR4_MASK, reg[0]);
49 - fdb->mac[5] = FIELD_GET(QCA8K_ATU_ADDR5_MASK, reg[0]);
50 -
51 - return 0;
52 -}
53 -
54 -static void
55 -qca8k_fdb_write(struct qca8k_priv *priv, u16 vid, u8 port_mask, const u8 *mac,
56 - u8 aging)
57 -{
58 - u32 reg[3] = { 0 };
59 -
60 - /* vid - 83:72 */
61 - reg[2] = FIELD_PREP(QCA8K_ATU_VID_MASK, vid);
62 - /* aging - 67:64 */
63 - reg[2] |= FIELD_PREP(QCA8K_ATU_STATUS_MASK, aging);
64 - /* portmask - 54:48 */
65 - reg[1] = FIELD_PREP(QCA8K_ATU_PORT_MASK, port_mask);
66 - /* mac - 47:0 */
67 - reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR0_MASK, mac[0]);
68 - reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR1_MASK, mac[1]);
69 - reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR2_MASK, mac[2]);
70 - reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR3_MASK, mac[3]);
71 - reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR4_MASK, mac[4]);
72 - reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR5_MASK, mac[5]);
73 -
74 - /* load the array into the ARL table */
75 - qca8k_bulk_write(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg));
76 -}
77 -
78 -static int
79 -qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd, int port)
80 -{
81 - u32 reg;
82 - int ret;
83 -
84 - /* Set the command and FDB index */
85 - reg = QCA8K_ATU_FUNC_BUSY;
86 - reg |= cmd;
87 - if (port >= 0) {
88 - reg |= QCA8K_ATU_FUNC_PORT_EN;
89 - reg |= FIELD_PREP(QCA8K_ATU_FUNC_PORT_MASK, port);
90 - }
91 -
92 - /* Write the function register triggering the table access */
93 - ret = qca8k_write(priv, QCA8K_REG_ATU_FUNC, reg);
94 - if (ret)
95 - return ret;
96 -
97 - /* wait for completion */
98 - ret = qca8k_busy_wait(priv, QCA8K_REG_ATU_FUNC, QCA8K_ATU_FUNC_BUSY);
99 - if (ret)
100 - return ret;
101 -
102 - /* Check for table full violation when adding an entry */
103 - if (cmd == QCA8K_FDB_LOAD) {
104 - ret = qca8k_read(priv, QCA8K_REG_ATU_FUNC, &reg);
105 - if (ret < 0)
106 - return ret;
107 - if (reg & QCA8K_ATU_FUNC_FULL)
108 - return -1;
109 - }
110 -
111 - return 0;
112 -}
113 -
114 -static int
115 -qca8k_fdb_next(struct qca8k_priv *priv, struct qca8k_fdb *fdb, int port)
116 -{
117 - int ret;
118 -
119 - qca8k_fdb_write(priv, fdb->vid, fdb->port_mask, fdb->mac, fdb->aging);
120 - ret = qca8k_fdb_access(priv, QCA8K_FDB_NEXT, port);
121 - if (ret < 0)
122 - return ret;
123 -
124 - return qca8k_fdb_read(priv, fdb);
125 -}
126 -
127 -static int
128 -qca8k_fdb_add(struct qca8k_priv *priv, const u8 *mac, u16 port_mask,
129 - u16 vid, u8 aging)
130 -{
131 - int ret;
132 -
133 - mutex_lock(&priv->reg_mutex);
134 - qca8k_fdb_write(priv, vid, port_mask, mac, aging);
135 - ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1);
136 - mutex_unlock(&priv->reg_mutex);
137 -
138 - return ret;
139 -}
140 -
141 -static int
142 -qca8k_fdb_del(struct qca8k_priv *priv, const u8 *mac, u16 port_mask, u16 vid)
143 -{
144 - int ret;
145 -
146 - mutex_lock(&priv->reg_mutex);
147 - qca8k_fdb_write(priv, vid, port_mask, mac, 0);
148 - ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1);
149 - mutex_unlock(&priv->reg_mutex);
150 -
151 - return ret;
152 -}
153 -
154 -static void
155 -qca8k_fdb_flush(struct qca8k_priv *priv)
156 -{
157 - mutex_lock(&priv->reg_mutex);
158 - qca8k_fdb_access(priv, QCA8K_FDB_FLUSH, -1);
159 - mutex_unlock(&priv->reg_mutex);
160 -}
161 -
162 -static int
163 -qca8k_fdb_search_and_insert(struct qca8k_priv *priv, u8 port_mask,
164 - const u8 *mac, u16 vid)
165 -{
166 - struct qca8k_fdb fdb = { 0 };
167 - int ret;
168 -
169 - mutex_lock(&priv->reg_mutex);
170 -
171 - qca8k_fdb_write(priv, vid, 0, mac, 0);
172 - ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1);
173 - if (ret < 0)
174 - goto exit;
175 -
176 - ret = qca8k_fdb_read(priv, &fdb);
177 - if (ret < 0)
178 - goto exit;
179 -
180 - /* Rule exist. Delete first */
181 - if (!fdb.aging) {
182 - ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1);
183 - if (ret)
184 - goto exit;
185 - }
186 -
187 - /* Add port to fdb portmask */
188 - fdb.port_mask |= port_mask;
189 -
190 - qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging);
191 - ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1);
192 -
193 -exit:
194 - mutex_unlock(&priv->reg_mutex);
195 - return ret;
196 -}
197 -
198 -static int
199 -qca8k_fdb_search_and_del(struct qca8k_priv *priv, u8 port_mask,
200 - const u8 *mac, u16 vid)
201 -{
202 - struct qca8k_fdb fdb = { 0 };
203 - int ret;
204 -
205 - mutex_lock(&priv->reg_mutex);
206 -
207 - qca8k_fdb_write(priv, vid, 0, mac, 0);
208 - ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1);
209 - if (ret < 0)
210 - goto exit;
211 -
212 - /* Rule doesn't exist. Why delete? */
213 - if (!fdb.aging) {
214 - ret = -EINVAL;
215 - goto exit;
216 - }
217 -
218 - ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1);
219 - if (ret)
220 - goto exit;
221 -
222 - /* Only port in the rule is this port. Don't re insert */
223 - if (fdb.port_mask == port_mask)
224 - goto exit;
225 -
226 - /* Remove port from port mask */
227 - fdb.port_mask &= ~port_mask;
228 -
229 - qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging);
230 - ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1);
231 -
232 -exit:
233 - mutex_unlock(&priv->reg_mutex);
234 - return ret;
235 -}
236 -
237 -static int
238 qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid)
239 {
240 u32 reg;
241 @@ -2048,97 +1837,6 @@ exit:
242 return ret;
243 }
244
245 -static void
246 -qca8k_port_fast_age(struct dsa_switch *ds, int port)
247 -{
248 - struct qca8k_priv *priv = ds->priv;
249 -
250 - mutex_lock(&priv->reg_mutex);
251 - qca8k_fdb_access(priv, QCA8K_FDB_FLUSH_PORT, port);
252 - mutex_unlock(&priv->reg_mutex);
253 -}
254 -
255 -static int
256 -qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr,
257 - u16 port_mask, u16 vid)
258 -{
259 - /* Set the vid to the port vlan id if no vid is set */
260 - if (!vid)
261 - vid = QCA8K_PORT_VID_DEF;
262 -
263 - return qca8k_fdb_add(priv, addr, port_mask, vid,
264 - QCA8K_ATU_STATUS_STATIC);
265 -}
266 -
267 -static int
268 -qca8k_port_fdb_add(struct dsa_switch *ds, int port,
269 - const unsigned char *addr, u16 vid)
270 -{
271 - struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
272 - u16 port_mask = BIT(port);
273 -
274 - return qca8k_port_fdb_insert(priv, addr, port_mask, vid);
275 -}
276 -
277 -static int
278 -qca8k_port_fdb_del(struct dsa_switch *ds, int port,
279 - const unsigned char *addr, u16 vid)
280 -{
281 - struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
282 - u16 port_mask = BIT(port);
283 -
284 - if (!vid)
285 - vid = QCA8K_PORT_VID_DEF;
286 -
287 - return qca8k_fdb_del(priv, addr, port_mask, vid);
288 -}
289 -
290 -static int
291 -qca8k_port_fdb_dump(struct dsa_switch *ds, int port,
292 - dsa_fdb_dump_cb_t *cb, void *data)
293 -{
294 - struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
295 - struct qca8k_fdb _fdb = { 0 };
296 - int cnt = QCA8K_NUM_FDB_RECORDS;
297 - bool is_static;
298 - int ret = 0;
299 -
300 - mutex_lock(&priv->reg_mutex);
301 - while (cnt-- && !qca8k_fdb_next(priv, &_fdb, port)) {
302 - if (!_fdb.aging)
303 - break;
304 - is_static = (_fdb.aging == QCA8K_ATU_STATUS_STATIC);
305 - ret = cb(_fdb.mac, _fdb.vid, is_static, data);
306 - if (ret)
307 - break;
308 - }
309 - mutex_unlock(&priv->reg_mutex);
310 -
311 - return 0;
312 -}
313 -
314 -static int
315 -qca8k_port_mdb_add(struct dsa_switch *ds, int port,
316 - const struct switchdev_obj_port_mdb *mdb)
317 -{
318 - struct qca8k_priv *priv = ds->priv;
319 - const u8 *addr = mdb->addr;
320 - u16 vid = mdb->vid;
321 -
322 - return qca8k_fdb_search_and_insert(priv, BIT(port), addr, vid);
323 -}
324 -
325 -static int
326 -qca8k_port_mdb_del(struct dsa_switch *ds, int port,
327 - const struct switchdev_obj_port_mdb *mdb)
328 -{
329 - struct qca8k_priv *priv = ds->priv;
330 - const u8 *addr = mdb->addr;
331 - u16 vid = mdb->vid;
332 -
333 - return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid);
334 -}
335 -
336 static int
337 qca8k_port_mirror_add(struct dsa_switch *ds, int port,
338 struct dsa_mall_mirror_tc_entry *mirror,
339 --- a/drivers/net/dsa/qca/qca8k-common.c
340 +++ b/drivers/net/dsa/qca/qca8k-common.c
341 @@ -103,7 +103,7 @@ const struct regmap_access_table qca8k_r
342 };
343
344 /* TODO: remove these extra ops when we can support regmap bulk read/write */
345 -int qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
346 +static int qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
347 {
348 int i, count = len / sizeof(u32), ret;
349
350 @@ -121,7 +121,7 @@ int qca8k_bulk_read(struct qca8k_priv *p
351 }
352
353 /* TODO: remove these extra ops when we can support regmap bulk read/write */
354 -int qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
355 +static int qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
356 {
357 int i, count = len / sizeof(u32), ret;
358 u32 tmp;
359 @@ -149,6 +149,211 @@ int qca8k_busy_wait(struct qca8k_priv *p
360 QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC);
361 }
362
363 +static int qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb)
364 +{
365 + u32 reg[3];
366 + int ret;
367 +
368 + /* load the ARL table into an array */
369 + ret = qca8k_bulk_read(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg));
370 + if (ret)
371 + return ret;
372 +
373 + /* vid - 83:72 */
374 + fdb->vid = FIELD_GET(QCA8K_ATU_VID_MASK, reg[2]);
375 + /* aging - 67:64 */
376 + fdb->aging = FIELD_GET(QCA8K_ATU_STATUS_MASK, reg[2]);
377 + /* portmask - 54:48 */
378 + fdb->port_mask = FIELD_GET(QCA8K_ATU_PORT_MASK, reg[1]);
379 + /* mac - 47:0 */
380 + fdb->mac[0] = FIELD_GET(QCA8K_ATU_ADDR0_MASK, reg[1]);
381 + fdb->mac[1] = FIELD_GET(QCA8K_ATU_ADDR1_MASK, reg[1]);
382 + fdb->mac[2] = FIELD_GET(QCA8K_ATU_ADDR2_MASK, reg[0]);
383 + fdb->mac[3] = FIELD_GET(QCA8K_ATU_ADDR3_MASK, reg[0]);
384 + fdb->mac[4] = FIELD_GET(QCA8K_ATU_ADDR4_MASK, reg[0]);
385 + fdb->mac[5] = FIELD_GET(QCA8K_ATU_ADDR5_MASK, reg[0]);
386 +
387 + return 0;
388 +}
389 +
390 +static void qca8k_fdb_write(struct qca8k_priv *priv, u16 vid, u8 port_mask,
391 + const u8 *mac, u8 aging)
392 +{
393 + u32 reg[3] = { 0 };
394 +
395 + /* vid - 83:72 */
396 + reg[2] = FIELD_PREP(QCA8K_ATU_VID_MASK, vid);
397 + /* aging - 67:64 */
398 + reg[2] |= FIELD_PREP(QCA8K_ATU_STATUS_MASK, aging);
399 + /* portmask - 54:48 */
400 + reg[1] = FIELD_PREP(QCA8K_ATU_PORT_MASK, port_mask);
401 + /* mac - 47:0 */
402 + reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR0_MASK, mac[0]);
403 + reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR1_MASK, mac[1]);
404 + reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR2_MASK, mac[2]);
405 + reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR3_MASK, mac[3]);
406 + reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR4_MASK, mac[4]);
407 + reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR5_MASK, mac[5]);
408 +
409 + /* load the array into the ARL table */
410 + qca8k_bulk_write(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg));
411 +}
412 +
413 +static int qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd,
414 + int port)
415 +{
416 + u32 reg;
417 + int ret;
418 +
419 + /* Set the command and FDB index */
420 + reg = QCA8K_ATU_FUNC_BUSY;
421 + reg |= cmd;
422 + if (port >= 0) {
423 + reg |= QCA8K_ATU_FUNC_PORT_EN;
424 + reg |= FIELD_PREP(QCA8K_ATU_FUNC_PORT_MASK, port);
425 + }
426 +
427 + /* Write the function register triggering the table access */
428 + ret = qca8k_write(priv, QCA8K_REG_ATU_FUNC, reg);
429 + if (ret)
430 + return ret;
431 +
432 + /* wait for completion */
433 + ret = qca8k_busy_wait(priv, QCA8K_REG_ATU_FUNC, QCA8K_ATU_FUNC_BUSY);
434 + if (ret)
435 + return ret;
436 +
437 + /* Check for table full violation when adding an entry */
438 + if (cmd == QCA8K_FDB_LOAD) {
439 + ret = qca8k_read(priv, QCA8K_REG_ATU_FUNC, &reg);
440 + if (ret < 0)
441 + return ret;
442 + if (reg & QCA8K_ATU_FUNC_FULL)
443 + return -1;
444 + }
445 +
446 + return 0;
447 +}
448 +
449 +static int qca8k_fdb_next(struct qca8k_priv *priv, struct qca8k_fdb *fdb,
450 + int port)
451 +{
452 + int ret;
453 +
454 + qca8k_fdb_write(priv, fdb->vid, fdb->port_mask, fdb->mac, fdb->aging);
455 + ret = qca8k_fdb_access(priv, QCA8K_FDB_NEXT, port);
456 + if (ret < 0)
457 + return ret;
458 +
459 + return qca8k_fdb_read(priv, fdb);
460 +}
461 +
462 +static int qca8k_fdb_add(struct qca8k_priv *priv, const u8 *mac,
463 + u16 port_mask, u16 vid, u8 aging)
464 +{
465 + int ret;
466 +
467 + mutex_lock(&priv->reg_mutex);
468 + qca8k_fdb_write(priv, vid, port_mask, mac, aging);
469 + ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1);
470 + mutex_unlock(&priv->reg_mutex);
471 +
472 + return ret;
473 +}
474 +
475 +static int qca8k_fdb_del(struct qca8k_priv *priv, const u8 *mac,
476 + u16 port_mask, u16 vid)
477 +{
478 + int ret;
479 +
480 + mutex_lock(&priv->reg_mutex);
481 + qca8k_fdb_write(priv, vid, port_mask, mac, 0);
482 + ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1);
483 + mutex_unlock(&priv->reg_mutex);
484 +
485 + return ret;
486 +}
487 +
488 +void qca8k_fdb_flush(struct qca8k_priv *priv)
489 +{
490 + mutex_lock(&priv->reg_mutex);
491 + qca8k_fdb_access(priv, QCA8K_FDB_FLUSH, -1);
492 + mutex_unlock(&priv->reg_mutex);
493 +}
494 +
495 +static int qca8k_fdb_search_and_insert(struct qca8k_priv *priv, u8 port_mask,
496 + const u8 *mac, u16 vid)
497 +{
498 + struct qca8k_fdb fdb = { 0 };
499 + int ret;
500 +
501 + mutex_lock(&priv->reg_mutex);
502 +
503 + qca8k_fdb_write(priv, vid, 0, mac, 0);
504 + ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1);
505 + if (ret < 0)
506 + goto exit;
507 +
508 + ret = qca8k_fdb_read(priv, &fdb);
509 + if (ret < 0)
510 + goto exit;
511 +
512 + /* Rule exist. Delete first */
513 + if (!fdb.aging) {
514 + ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1);
515 + if (ret)
516 + goto exit;
517 + }
518 +
519 + /* Add port to fdb portmask */
520 + fdb.port_mask |= port_mask;
521 +
522 + qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging);
523 + ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1);
524 +
525 +exit:
526 + mutex_unlock(&priv->reg_mutex);
527 + return ret;
528 +}
529 +
530 +static int qca8k_fdb_search_and_del(struct qca8k_priv *priv, u8 port_mask,
531 + const u8 *mac, u16 vid)
532 +{
533 + struct qca8k_fdb fdb = { 0 };
534 + int ret;
535 +
536 + mutex_lock(&priv->reg_mutex);
537 +
538 + qca8k_fdb_write(priv, vid, 0, mac, 0);
539 + ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1);
540 + if (ret < 0)
541 + goto exit;
542 +
543 + /* Rule doesn't exist. Why delete? */
544 + if (!fdb.aging) {
545 + ret = -EINVAL;
546 + goto exit;
547 + }
548 +
549 + ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1);
550 + if (ret)
551 + goto exit;
552 +
553 + /* Only port in the rule is this port. Don't re insert */
554 + if (fdb.port_mask == port_mask)
555 + goto exit;
556 +
557 + /* Remove port from port mask */
558 + fdb.port_mask &= ~port_mask;
559 +
560 + qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging);
561 + ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1);
562 +
563 +exit:
564 + mutex_unlock(&priv->reg_mutex);
565 + return ret;
566 +}
567 +
568 int qca8k_mib_init(struct qca8k_priv *priv)
569 {
570 int ret;
571 @@ -368,6 +573,15 @@ void qca8k_port_bridge_leave(struct dsa_
572 QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port));
573 }
574
575 +void qca8k_port_fast_age(struct dsa_switch *ds, int port)
576 +{
577 + struct qca8k_priv *priv = ds->priv;
578 +
579 + mutex_lock(&priv->reg_mutex);
580 + qca8k_fdb_access(priv, QCA8K_FDB_FLUSH_PORT, port);
581 + mutex_unlock(&priv->reg_mutex);
582 +}
583 +
584 int qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)
585 {
586 struct qca8k_priv *priv = ds->priv;
587 @@ -452,3 +666,78 @@ int qca8k_port_max_mtu(struct dsa_switch
588 {
589 return QCA8K_MAX_MTU;
590 }
591 +
592 +int qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr,
593 + u16 port_mask, u16 vid)
594 +{
595 + /* Set the vid to the port vlan id if no vid is set */
596 + if (!vid)
597 + vid = QCA8K_PORT_VID_DEF;
598 +
599 + return qca8k_fdb_add(priv, addr, port_mask, vid,
600 + QCA8K_ATU_STATUS_STATIC);
601 +}
602 +
603 +int qca8k_port_fdb_add(struct dsa_switch *ds, int port,
604 + const unsigned char *addr, u16 vid)
605 +{
606 + struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
607 + u16 port_mask = BIT(port);
608 +
609 + return qca8k_port_fdb_insert(priv, addr, port_mask, vid);
610 +}
611 +
612 +int qca8k_port_fdb_del(struct dsa_switch *ds, int port,
613 + const unsigned char *addr, u16 vid)
614 +{
615 + struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
616 + u16 port_mask = BIT(port);
617 +
618 + if (!vid)
619 + vid = QCA8K_PORT_VID_DEF;
620 +
621 + return qca8k_fdb_del(priv, addr, port_mask, vid);
622 +}
623 +
624 +int qca8k_port_fdb_dump(struct dsa_switch *ds, int port,
625 + dsa_fdb_dump_cb_t *cb, void *data)
626 +{
627 + struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
628 + struct qca8k_fdb _fdb = { 0 };
629 + int cnt = QCA8K_NUM_FDB_RECORDS;
630 + bool is_static;
631 + int ret = 0;
632 +
633 + mutex_lock(&priv->reg_mutex);
634 + while (cnt-- && !qca8k_fdb_next(priv, &_fdb, port)) {
635 + if (!_fdb.aging)
636 + break;
637 + is_static = (_fdb.aging == QCA8K_ATU_STATUS_STATIC);
638 + ret = cb(_fdb.mac, _fdb.vid, is_static, data);
639 + if (ret)
640 + break;
641 + }
642 + mutex_unlock(&priv->reg_mutex);
643 +
644 + return 0;
645 +}
646 +
647 +int qca8k_port_mdb_add(struct dsa_switch *ds, int port,
648 + const struct switchdev_obj_port_mdb *mdb)
649 +{
650 + struct qca8k_priv *priv = ds->priv;
651 + const u8 *addr = mdb->addr;
652 + u16 vid = mdb->vid;
653 +
654 + return qca8k_fdb_search_and_insert(priv, BIT(port), addr, vid);
655 +}
656 +
657 +int qca8k_port_mdb_del(struct dsa_switch *ds, int port,
658 + const struct switchdev_obj_port_mdb *mdb)
659 +{
660 + struct qca8k_priv *priv = ds->priv;
661 + const u8 *addr = mdb->addr;
662 + u16 vid = mdb->vid;
663 +
664 + return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid);
665 +}
666 --- a/drivers/net/dsa/qca/qca8k.h
667 +++ b/drivers/net/dsa/qca/qca8k.h
668 @@ -430,11 +430,9 @@ int qca8k_read(struct qca8k_priv *priv,
669 int qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val);
670 int qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val);
671
672 -int qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len);
673 -int qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len);
674 -
675 /* Common ops function */
676 int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask);
677 +void qca8k_fdb_flush(struct qca8k_priv *priv);
678
679 /* Common ethtool stats function */
680 void qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data);
681 @@ -463,6 +461,23 @@ int qca8k_port_change_mtu(struct dsa_swi
682 int qca8k_port_max_mtu(struct dsa_switch *ds, int port);
683
684 /* Common fast age function */
685 +void qca8k_port_fast_age(struct dsa_switch *ds, int port);
686 int qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs);
687
688 +/* Common FDB function */
689 +int qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr,
690 + u16 port_mask, u16 vid);
691 +int qca8k_port_fdb_add(struct dsa_switch *ds, int port,
692 + const unsigned char *addr, u16 vid);
693 +int qca8k_port_fdb_del(struct dsa_switch *ds, int port,
694 + const unsigned char *addr, u16 vid);
695 +int qca8k_port_fdb_dump(struct dsa_switch *ds, int port,
696 + dsa_fdb_dump_cb_t *cb, void *data);
697 +
698 +/* Common MDB function */
699 +int qca8k_port_mdb_add(struct dsa_switch *ds, int port,
700 + const struct switchdev_obj_port_mdb *mdb);
701 +int qca8k_port_mdb_del(struct dsa_switch *ds, int port,
702 + const struct switchdev_obj_port_mdb *mdb);
703 +
704 #endif /* __QCA8K_H */