]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/net/dsa/mv88e6xxx/global1_vtu.c
treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 152
[mirror_ubuntu-jammy-kernel.git] / drivers / net / dsa / mv88e6xxx / global1_vtu.c
CommitLineData
2874c5fd 1// SPDX-License-Identifier: GPL-2.0-or-later
332aa5cc
VD
2/*
3 * Marvell 88E6xxx VLAN [Spanning Tree] Translation Unit (VTU [STU]) support
4 *
5 * Copyright (c) 2008 Marvell Semiconductor
6 * Copyright (c) 2015 CMC Electronics, Inc.
7 * Copyright (c) 2017 Savoir-faire Linux, Inc.
332aa5cc
VD
8 */
9
62eb1162
AL
10#include <linux/interrupt.h>
11#include <linux/irqdomain.h>
12
4d5f2ba7 13#include "chip.h"
332aa5cc
VD
14#include "global1.h"
15
8ee51f6b
VD
16/* Offset 0x02: VTU FID Register */
17
bf7d71c0
VD
18static int mv88e6xxx_g1_vtu_fid_read(struct mv88e6xxx_chip *chip,
19 struct mv88e6xxx_vtu_entry *entry)
8ee51f6b
VD
20{
21 u16 val;
22 int err;
23
7ec60d6e 24 err = mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_FID, &val);
8ee51f6b
VD
25 if (err)
26 return err;
27
7ec60d6e 28 entry->fid = val & MV88E6352_G1_VTU_FID_MASK;
8ee51f6b
VD
29
30 return 0;
31}
32
bf7d71c0
VD
33static int mv88e6xxx_g1_vtu_fid_write(struct mv88e6xxx_chip *chip,
34 struct mv88e6xxx_vtu_entry *entry)
8ee51f6b 35{
7ec60d6e 36 u16 val = entry->fid & MV88E6352_G1_VTU_FID_MASK;
8ee51f6b 37
7ec60d6e 38 return mv88e6xxx_g1_write(chip, MV88E6352_G1_VTU_FID, val);
8ee51f6b
VD
39}
40
d2ca1ea1
VD
41/* Offset 0x03: VTU SID Register */
42
bf7d71c0
VD
43static int mv88e6xxx_g1_vtu_sid_read(struct mv88e6xxx_chip *chip,
44 struct mv88e6xxx_vtu_entry *entry)
d2ca1ea1
VD
45{
46 u16 val;
47 int err;
48
7ec60d6e 49 err = mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID, &val);
d2ca1ea1
VD
50 if (err)
51 return err;
52
7ec60d6e 53 entry->sid = val & MV88E6352_G1_VTU_SID_MASK;
d2ca1ea1
VD
54
55 return 0;
56}
57
bf7d71c0
VD
58static int mv88e6xxx_g1_vtu_sid_write(struct mv88e6xxx_chip *chip,
59 struct mv88e6xxx_vtu_entry *entry)
d2ca1ea1 60{
7ec60d6e 61 u16 val = entry->sid & MV88E6352_G1_VTU_SID_MASK;
d2ca1ea1 62
7ec60d6e 63 return mv88e6xxx_g1_write(chip, MV88E6352_G1_VTU_SID, val);
d2ca1ea1
VD
64}
65
332aa5cc
VD
66/* Offset 0x05: VTU Operation Register */
67
bf7d71c0 68static int mv88e6xxx_g1_vtu_op_wait(struct mv88e6xxx_chip *chip)
332aa5cc 69{
7ec60d6e
VD
70 return mv88e6xxx_g1_wait(chip, MV88E6XXX_G1_VTU_OP,
71 MV88E6XXX_G1_VTU_OP_BUSY);
332aa5cc
VD
72}
73
bf7d71c0 74static int mv88e6xxx_g1_vtu_op(struct mv88e6xxx_chip *chip, u16 op)
332aa5cc
VD
75{
76 int err;
77
7ec60d6e
VD
78 err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_VTU_OP,
79 MV88E6XXX_G1_VTU_OP_BUSY | op);
332aa5cc
VD
80 if (err)
81 return err;
82
83 return mv88e6xxx_g1_vtu_op_wait(chip);
84}
b486d7c9 85
3afb4bde
VD
86/* Offset 0x06: VTU VID Register */
87
bf7d71c0
VD
88static int mv88e6xxx_g1_vtu_vid_read(struct mv88e6xxx_chip *chip,
89 struct mv88e6xxx_vtu_entry *entry)
3afb4bde
VD
90{
91 u16 val;
92 int err;
93
7ec60d6e 94 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID, &val);
3afb4bde
VD
95 if (err)
96 return err;
97
98 entry->vid = val & 0xfff;
1ac75864 99
7ec60d6e 100 if (val & MV88E6390_G1_VTU_VID_PAGE)
1ac75864
VD
101 entry->vid |= 0x1000;
102
7ec60d6e 103 entry->valid = !!(val & MV88E6XXX_G1_VTU_VID_VALID);
3afb4bde
VD
104
105 return 0;
106}
107
bf7d71c0
VD
108static int mv88e6xxx_g1_vtu_vid_write(struct mv88e6xxx_chip *chip,
109 struct mv88e6xxx_vtu_entry *entry)
3afb4bde
VD
110{
111 u16 val = entry->vid & 0xfff;
112
1ac75864 113 if (entry->vid & 0x1000)
7ec60d6e 114 val |= MV88E6390_G1_VTU_VID_PAGE;
1ac75864 115
3afb4bde 116 if (entry->valid)
7ec60d6e 117 val |= MV88E6XXX_G1_VTU_VID_VALID;
3afb4bde 118
7ec60d6e 119 return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_VTU_VID, val);
3afb4bde
VD
120}
121
c499a64f
VD
122/* Offset 0x07: VTU/STU Data Register 1
123 * Offset 0x08: VTU/STU Data Register 2
124 * Offset 0x09: VTU/STU Data Register 3
125 */
126
bf7d71c0
VD
127static int mv88e6185_g1_vtu_data_read(struct mv88e6xxx_chip *chip,
128 struct mv88e6xxx_vtu_entry *entry)
c499a64f
VD
129{
130 u16 regs[3];
131 int i;
132
133 /* Read all 3 VTU/STU Data registers */
134 for (i = 0; i < 3; ++i) {
135 u16 *reg = &regs[i];
136 int err;
137
7ec60d6e 138 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1 + i, reg);
c499a64f
VD
139 if (err)
140 return err;
141 }
142
143 /* Extract MemberTag and PortState data */
144 for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
145 unsigned int member_offset = (i % 4) * 4;
146 unsigned int state_offset = member_offset + 2;
147
148 entry->member[i] = (regs[i / 4] >> member_offset) & 0x3;
149 entry->state[i] = (regs[i / 4] >> state_offset) & 0x3;
150 }
151
152 return 0;
153}
154
bf7d71c0
VD
155static int mv88e6185_g1_vtu_data_write(struct mv88e6xxx_chip *chip,
156 struct mv88e6xxx_vtu_entry *entry)
c499a64f
VD
157{
158 u16 regs[3] = { 0 };
159 int i;
160
161 /* Insert MemberTag and PortState data */
162 for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
163 unsigned int member_offset = (i % 4) * 4;
164 unsigned int state_offset = member_offset + 2;
165
166 regs[i / 4] |= (entry->member[i] & 0x3) << member_offset;
167 regs[i / 4] |= (entry->state[i] & 0x3) << state_offset;
168 }
169
170 /* Write all 3 VTU/STU Data registers */
171 for (i = 0; i < 3; ++i) {
172 u16 reg = regs[i];
173 int err;
174
7ec60d6e 175 err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_VTU_DATA1 + i, reg);
c499a64f
VD
176 if (err)
177 return err;
178 }
179
180 return 0;
181}
182
931d1822
VD
183static int mv88e6390_g1_vtu_data_read(struct mv88e6xxx_chip *chip, u8 *data)
184{
185 u16 regs[2];
186 int i;
187
188 /* Read the 2 VTU/STU Data registers */
189 for (i = 0; i < 2; ++i) {
190 u16 *reg = &regs[i];
191 int err;
192
7ec60d6e 193 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1 + i, reg);
931d1822
VD
194 if (err)
195 return err;
196 }
197
198 /* Extract data */
199 for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
200 unsigned int offset = (i % 8) * 2;
201
202 data[i] = (regs[i / 8] >> offset) & 0x3;
203 }
204
205 return 0;
206}
207
208static int mv88e6390_g1_vtu_data_write(struct mv88e6xxx_chip *chip, u8 *data)
209{
210 u16 regs[2] = { 0 };
211 int i;
212
213 /* Insert data */
214 for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
215 unsigned int offset = (i % 8) * 2;
216
217 regs[i / 8] |= (data[i] & 0x3) << offset;
218 }
219
220 /* Write the 2 VTU/STU Data registers */
221 for (i = 0; i < 2; ++i) {
222 u16 reg = regs[i];
223 int err;
224
7ec60d6e 225 err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_VTU_DATA1 + i, reg);
931d1822
VD
226 if (err)
227 return err;
228 }
229
230 return 0;
231}
232
b486d7c9
VD
233/* VLAN Translation Unit Operations */
234
bf7d71c0
VD
235static int mv88e6xxx_g1_vtu_stu_getnext(struct mv88e6xxx_chip *chip,
236 struct mv88e6xxx_vtu_entry *entry)
66a8e1f9
VD
237{
238 int err;
239
240 err = mv88e6xxx_g1_vtu_sid_write(chip, entry);
241 if (err)
242 return err;
243
7ec60d6e 244 err = mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_STU_GET_NEXT);
66a8e1f9
VD
245 if (err)
246 return err;
247
248 err = mv88e6xxx_g1_vtu_sid_read(chip, entry);
249 if (err)
250 return err;
251
252 return mv88e6xxx_g1_vtu_vid_read(chip, entry);
253}
254
bf7d71c0
VD
255static int mv88e6xxx_g1_vtu_stu_get(struct mv88e6xxx_chip *chip,
256 struct mv88e6xxx_vtu_entry *vtu)
ef6fcea3
VD
257{
258 struct mv88e6xxx_vtu_entry stu;
259 int err;
260
261 err = mv88e6xxx_g1_vtu_sid_read(chip, vtu);
262 if (err)
263 return err;
264
265 stu.sid = vtu->sid - 1;
266
267 err = mv88e6xxx_g1_vtu_stu_getnext(chip, &stu);
268 if (err)
269 return err;
270
271 if (stu.sid != vtu->sid || !stu.valid)
272 return -EINVAL;
273
274 return 0;
275}
276
bf7d71c0
VD
277static int mv88e6xxx_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
278 struct mv88e6xxx_vtu_entry *entry)
f169e5ee
VD
279{
280 int err;
281
282 err = mv88e6xxx_g1_vtu_op_wait(chip);
283 if (err)
284 return err;
285
286 /* To get the next higher active VID, the VTU GetNext operation can be
287 * started again without setting the VID registers since it already
288 * contains the last VID.
289 *
290 * To save a few hardware accesses and abstract this to the caller,
291 * write the VID only once, when the entry is given as invalid.
292 */
293 if (!entry->valid) {
294 err = mv88e6xxx_g1_vtu_vid_write(chip, entry);
295 if (err)
296 return err;
297 }
298
7ec60d6e 299 err = mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_VTU_GET_NEXT);
f169e5ee
VD
300 if (err)
301 return err;
302
303 return mv88e6xxx_g1_vtu_vid_read(chip, entry);
304}
305
f1394b78
VD
306int mv88e6185_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
307 struct mv88e6xxx_vtu_entry *entry)
308{
309 u16 val;
310 int err;
311
312 err = mv88e6xxx_g1_vtu_getnext(chip, entry);
313 if (err)
314 return err;
315
316 if (entry->valid) {
317 err = mv88e6185_g1_vtu_data_read(chip, entry);
318 if (err)
319 return err;
320
321 /* VTU DBNum[3:0] are located in VTU Operation 3:0
322 * VTU DBNum[7:4] are located in VTU Operation 11:8
323 */
7ec60d6e 324 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_OP, &val);
f1394b78
VD
325 if (err)
326 return err;
327
328 entry->fid = val & 0x000f;
329 entry->fid |= (val & 0x0f00) >> 4;
330 }
331
332 return 0;
333}
334
335int mv88e6352_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
336 struct mv88e6xxx_vtu_entry *entry)
337{
338 int err;
339
340 /* Fetch VLAN MemberTag data from the VTU */
341 err = mv88e6xxx_g1_vtu_getnext(chip, entry);
342 if (err)
343 return err;
344
345 if (entry->valid) {
346 /* Fetch (and mask) VLAN PortState data from the STU */
347 err = mv88e6xxx_g1_vtu_stu_get(chip, entry);
348 if (err)
349 return err;
350
351 err = mv88e6185_g1_vtu_data_read(chip, entry);
352 if (err)
353 return err;
354
355 err = mv88e6xxx_g1_vtu_fid_read(chip, entry);
356 if (err)
357 return err;
358 }
359
360 return 0;
361}
362
931d1822
VD
363int mv88e6390_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
364 struct mv88e6xxx_vtu_entry *entry)
365{
366 int err;
367
368 /* Fetch VLAN MemberTag data from the VTU */
369 err = mv88e6xxx_g1_vtu_getnext(chip, entry);
370 if (err)
371 return err;
372
373 if (entry->valid) {
374 err = mv88e6390_g1_vtu_data_read(chip, entry->member);
375 if (err)
376 return err;
377
378 /* Fetch VLAN PortState data from the STU */
379 err = mv88e6xxx_g1_vtu_stu_get(chip, entry);
380 if (err)
381 return err;
382
383 err = mv88e6390_g1_vtu_data_read(chip, entry->state);
384 if (err)
385 return err;
386
387 err = mv88e6xxx_g1_vtu_fid_read(chip, entry);
388 if (err)
389 return err;
390 }
391
392 return 0;
393}
394
0ad5daf6
VD
395int mv88e6185_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip,
396 struct mv88e6xxx_vtu_entry *entry)
397{
7ec60d6e 398 u16 op = MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE;
0ad5daf6
VD
399 int err;
400
401 err = mv88e6xxx_g1_vtu_op_wait(chip);
402 if (err)
403 return err;
404
405 err = mv88e6xxx_g1_vtu_vid_write(chip, entry);
406 if (err)
407 return err;
408
409 if (entry->valid) {
410 err = mv88e6185_g1_vtu_data_write(chip, entry);
411 if (err)
412 return err;
413
414 /* VTU DBNum[3:0] are located in VTU Operation 3:0
415 * VTU DBNum[7:4] are located in VTU Operation 11:8
416 */
417 op |= entry->fid & 0x000f;
418 op |= (entry->fid & 0x00f0) << 8;
419 }
420
421 return mv88e6xxx_g1_vtu_op(chip, op);
422}
423
424int mv88e6352_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip,
425 struct mv88e6xxx_vtu_entry *entry)
426{
427 int err;
428
429 err = mv88e6xxx_g1_vtu_op_wait(chip);
430 if (err)
431 return err;
432
433 err = mv88e6xxx_g1_vtu_vid_write(chip, entry);
434 if (err)
435 return err;
436
437 if (entry->valid) {
438 /* Write MemberTag and PortState data */
439 err = mv88e6185_g1_vtu_data_write(chip, entry);
440 if (err)
441 return err;
442
443 err = mv88e6xxx_g1_vtu_sid_write(chip, entry);
444 if (err)
445 return err;
446
447 /* Load STU entry */
7ec60d6e
VD
448 err = mv88e6xxx_g1_vtu_op(chip,
449 MV88E6XXX_G1_VTU_OP_STU_LOAD_PURGE);
0ad5daf6
VD
450 if (err)
451 return err;
452
453 err = mv88e6xxx_g1_vtu_fid_write(chip, entry);
454 if (err)
455 return err;
456 }
457
458 /* Load/Purge VTU entry */
7ec60d6e 459 return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE);
0ad5daf6
VD
460}
461
931d1822
VD
462int mv88e6390_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip,
463 struct mv88e6xxx_vtu_entry *entry)
464{
465 int err;
466
467 err = mv88e6xxx_g1_vtu_op_wait(chip);
468 if (err)
469 return err;
470
471 err = mv88e6xxx_g1_vtu_vid_write(chip, entry);
472 if (err)
473 return err;
474
475 if (entry->valid) {
476 /* Write PortState data */
477 err = mv88e6390_g1_vtu_data_write(chip, entry->state);
478 if (err)
479 return err;
480
481 err = mv88e6xxx_g1_vtu_sid_write(chip, entry);
482 if (err)
483 return err;
484
485 /* Load STU entry */
7ec60d6e
VD
486 err = mv88e6xxx_g1_vtu_op(chip,
487 MV88E6XXX_G1_VTU_OP_STU_LOAD_PURGE);
931d1822
VD
488 if (err)
489 return err;
490
491 /* Write MemberTag data */
492 err = mv88e6390_g1_vtu_data_write(chip, entry->member);
493 if (err)
494 return err;
495
496 err = mv88e6xxx_g1_vtu_fid_write(chip, entry);
497 if (err)
498 return err;
499 }
500
501 /* Load/Purge VTU entry */
7ec60d6e 502 return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE);
931d1822
VD
503}
504
b486d7c9
VD
505int mv88e6xxx_g1_vtu_flush(struct mv88e6xxx_chip *chip)
506{
507 int err;
508
509 err = mv88e6xxx_g1_vtu_op_wait(chip);
510 if (err)
511 return err;
512
7ec60d6e 513 return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_FLUSH_ALL);
b486d7c9 514}
62eb1162
AL
515
516static irqreturn_t mv88e6xxx_g1_vtu_prob_irq_thread_fn(int irq, void *dev_id)
517{
518 struct mv88e6xxx_chip *chip = dev_id;
519 struct mv88e6xxx_vtu_entry entry;
520 int spid;
521 int err;
522 u16 val;
523
524 mutex_lock(&chip->reg_lock);
525
526 err = mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_GET_CLR_VIOLATION);
527 if (err)
528 goto out;
529
530 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_OP, &val);
531 if (err)
532 goto out;
533
534 err = mv88e6xxx_g1_vtu_vid_read(chip, &entry);
535 if (err)
536 goto out;
537
62eb1162
AL
538 spid = val & MV88E6XXX_G1_VTU_OP_SPID_MASK;
539
540 if (val & MV88E6XXX_G1_VTU_OP_MEMBER_VIOLATION) {
541 dev_err_ratelimited(chip->dev, "VTU member violation for vid %d, source port %d\n",
542 entry.vid, spid);
65f60e45 543 chip->ports[spid].vtu_member_violation++;
62eb1162
AL
544 }
545
65f60e45 546 if (val & MV88E6XXX_G1_VTU_OP_MISS_VIOLATION) {
7f20d834 547 dev_dbg_ratelimited(chip->dev, "VTU miss violation for vid %d, source port %d\n",
62eb1162 548 entry.vid, spid);
65f60e45
AL
549 chip->ports[spid].vtu_miss_violation++;
550 }
7f20d834 551
65f60e45 552 mutex_unlock(&chip->reg_lock);
62eb1162
AL
553
554 return IRQ_HANDLED;
555
556out:
557 mutex_unlock(&chip->reg_lock);
558
559 dev_err(chip->dev, "VTU problem: error %d while handling interrupt\n",
560 err);
561
562 return IRQ_HANDLED;
563}
564
565int mv88e6xxx_g1_vtu_prob_irq_setup(struct mv88e6xxx_chip *chip)
566{
567 int err;
568
569 chip->vtu_prob_irq = irq_find_mapping(chip->g1_irq.domain,
570 MV88E6XXX_G1_STS_IRQ_VTU_PROB);
571 if (chip->vtu_prob_irq < 0)
9b662a3e 572 return chip->vtu_prob_irq;
62eb1162
AL
573
574 err = request_threaded_irq(chip->vtu_prob_irq, NULL,
575 mv88e6xxx_g1_vtu_prob_irq_thread_fn,
576 IRQF_ONESHOT, "mv88e6xxx-g1-vtu-prob",
577 chip);
578 if (err)
579 irq_dispose_mapping(chip->vtu_prob_irq);
580
581 return err;
582}
583
584void mv88e6xxx_g1_vtu_prob_irq_free(struct mv88e6xxx_chip *chip)
585{
586 free_irq(chip->vtu_prob_irq, chip);
587 irq_dispose_mapping(chip->vtu_prob_irq);
588}