1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Marvell 88E6xxx VLAN [Spanning Tree] Translation Unit (VTU [STU]) support
5 * Copyright (c) 2008 Marvell Semiconductor
6 * Copyright (c) 2015 CMC Electronics, Inc.
7 * Copyright (c) 2017 Savoir-faire Linux, Inc.
10 #include <linux/bitfield.h>
11 #include <linux/interrupt.h>
12 #include <linux/irqdomain.h>
18 /* Offset 0x02: VTU FID Register */
20 static int mv88e6xxx_g1_vtu_fid_read(struct mv88e6xxx_chip
*chip
,
21 struct mv88e6xxx_vtu_entry
*entry
)
26 err
= mv88e6xxx_g1_read(chip
, MV88E6352_G1_VTU_FID
, &val
);
30 entry
->fid
= val
& MV88E6352_G1_VTU_FID_MASK
;
31 entry
->policy
= !!(val
& MV88E6352_G1_VTU_FID_VID_POLICY
);
35 static int mv88e6xxx_g1_vtu_fid_write(struct mv88e6xxx_chip
*chip
,
36 struct mv88e6xxx_vtu_entry
*entry
)
38 u16 val
= entry
->fid
& MV88E6352_G1_VTU_FID_MASK
;
41 val
|= MV88E6352_G1_VTU_FID_VID_POLICY
;
43 return mv88e6xxx_g1_write(chip
, MV88E6352_G1_VTU_FID
, val
);
46 /* Offset 0x03: VTU SID Register */
48 static int mv88e6xxx_g1_vtu_sid_read(struct mv88e6xxx_chip
*chip
, u8
*sid
)
53 err
= mv88e6xxx_g1_read(chip
, MV88E6352_G1_VTU_SID
, &val
);
57 *sid
= val
& MV88E6352_G1_VTU_SID_MASK
;
62 static int mv88e6xxx_g1_vtu_sid_write(struct mv88e6xxx_chip
*chip
, u8 sid
)
64 u16 val
= sid
& MV88E6352_G1_VTU_SID_MASK
;
66 return mv88e6xxx_g1_write(chip
, MV88E6352_G1_VTU_SID
, val
);
69 /* Offset 0x05: VTU Operation Register */
71 static int mv88e6xxx_g1_vtu_op_wait(struct mv88e6xxx_chip
*chip
)
73 int bit
= __bf_shf(MV88E6XXX_G1_VTU_OP_BUSY
);
75 return mv88e6xxx_g1_wait_bit(chip
, MV88E6XXX_G1_VTU_OP
, bit
, 0);
78 static int mv88e6xxx_g1_vtu_op(struct mv88e6xxx_chip
*chip
, u16 op
)
82 err
= mv88e6xxx_g1_write(chip
, MV88E6XXX_G1_VTU_OP
,
83 MV88E6XXX_G1_VTU_OP_BUSY
| op
);
87 return mv88e6xxx_g1_vtu_op_wait(chip
);
90 /* Offset 0x06: VTU VID Register */
92 static int mv88e6xxx_g1_vtu_vid_read(struct mv88e6xxx_chip
*chip
,
93 bool *valid
, u16
*vid
)
98 err
= mv88e6xxx_g1_read(chip
, MV88E6XXX_G1_VTU_VID
, &val
);
105 if (val
& MV88E6390_G1_VTU_VID_PAGE
)
110 *valid
= !!(val
& MV88E6XXX_G1_VTU_VID_VALID
);
115 static int mv88e6xxx_g1_vtu_vid_write(struct mv88e6xxx_chip
*chip
,
118 u16 val
= vid
& 0xfff;
121 val
|= MV88E6390_G1_VTU_VID_PAGE
;
124 val
|= MV88E6XXX_G1_VTU_VID_VALID
;
126 return mv88e6xxx_g1_write(chip
, MV88E6XXX_G1_VTU_VID
, val
);
129 /* Offset 0x07: VTU/STU Data Register 1
130 * Offset 0x08: VTU/STU Data Register 2
131 * Offset 0x09: VTU/STU Data Register 3
133 static int mv88e6185_g1_vtu_stu_data_read(struct mv88e6xxx_chip
*chip
,
138 /* Read all 3 VTU/STU Data registers */
139 for (i
= 0; i
< 3; ++i
) {
143 err
= mv88e6xxx_g1_read(chip
, MV88E6XXX_G1_VTU_DATA1
+ i
, reg
);
151 static int mv88e6185_g1_vtu_data_read(struct mv88e6xxx_chip
*chip
,
152 u8
*member
, u8
*state
)
158 err
= mv88e6185_g1_vtu_stu_data_read(chip
, regs
);
162 /* Extract MemberTag data */
163 for (i
= 0; i
< mv88e6xxx_num_ports(chip
); ++i
) {
164 unsigned int member_offset
= (i
% 4) * 4;
165 unsigned int state_offset
= member_offset
+ 2;
168 member
[i
] = (regs
[i
/ 4] >> member_offset
) & 0x3;
171 state
[i
] = (regs
[i
/ 4] >> state_offset
) & 0x3;
177 static int mv88e6185_g1_vtu_data_write(struct mv88e6xxx_chip
*chip
,
178 u8
*member
, u8
*state
)
183 /* Insert MemberTag and PortState data */
184 for (i
= 0; i
< mv88e6xxx_num_ports(chip
); ++i
) {
185 unsigned int member_offset
= (i
% 4) * 4;
186 unsigned int state_offset
= member_offset
+ 2;
189 regs
[i
/ 4] |= (member
[i
] & 0x3) << member_offset
;
192 regs
[i
/ 4] |= (state
[i
] & 0x3) << state_offset
;
195 /* Write all 3 VTU/STU Data registers */
196 for (i
= 0; i
< 3; ++i
) {
200 err
= mv88e6xxx_g1_write(chip
, MV88E6XXX_G1_VTU_DATA1
+ i
, reg
);
208 static int mv88e6390_g1_vtu_data_read(struct mv88e6xxx_chip
*chip
, u8
*data
)
213 /* Read the 2 VTU/STU Data registers */
214 for (i
= 0; i
< 2; ++i
) {
218 err
= mv88e6xxx_g1_read(chip
, MV88E6XXX_G1_VTU_DATA1
+ i
, reg
);
224 for (i
= 0; i
< mv88e6xxx_num_ports(chip
); ++i
) {
225 unsigned int offset
= (i
% 8) * 2;
227 data
[i
] = (regs
[i
/ 8] >> offset
) & 0x3;
233 static int mv88e6390_g1_vtu_data_write(struct mv88e6xxx_chip
*chip
, u8
*data
)
239 for (i
= 0; i
< mv88e6xxx_num_ports(chip
); ++i
) {
240 unsigned int offset
= (i
% 8) * 2;
242 regs
[i
/ 8] |= (data
[i
] & 0x3) << offset
;
245 /* Write the 2 VTU/STU Data registers */
246 for (i
= 0; i
< 2; ++i
) {
250 err
= mv88e6xxx_g1_write(chip
, MV88E6XXX_G1_VTU_DATA1
+ i
, reg
);
258 /* VLAN Translation Unit Operations */
260 int mv88e6xxx_g1_vtu_getnext(struct mv88e6xxx_chip
*chip
,
261 struct mv88e6xxx_vtu_entry
*entry
)
265 err
= mv88e6xxx_g1_vtu_op_wait(chip
);
269 /* To get the next higher active VID, the VTU GetNext operation can be
270 * started again without setting the VID registers since it already
271 * contains the last VID.
273 * To save a few hardware accesses and abstract this to the caller,
274 * write the VID only once, when the entry is given as invalid.
277 err
= mv88e6xxx_g1_vtu_vid_write(chip
, false, entry
->vid
);
282 err
= mv88e6xxx_g1_vtu_op(chip
, MV88E6XXX_G1_VTU_OP_VTU_GET_NEXT
);
286 return mv88e6xxx_g1_vtu_vid_read(chip
, &entry
->valid
, &entry
->vid
);
289 int mv88e6185_g1_vtu_getnext(struct mv88e6xxx_chip
*chip
,
290 struct mv88e6xxx_vtu_entry
*entry
)
295 err
= mv88e6xxx_g1_vtu_getnext(chip
, entry
);
300 err
= mv88e6185_g1_vtu_data_read(chip
, entry
->member
, entry
->state
);
304 /* VTU DBNum[3:0] are located in VTU Operation 3:0
305 * VTU DBNum[7:4] ([5:4] for 6250) are located in VTU Operation 11:8 (9:8)
307 err
= mv88e6xxx_g1_read(chip
, MV88E6XXX_G1_VTU_OP
, &val
);
311 entry
->fid
= val
& 0x000f;
312 entry
->fid
|= (val
& 0x0f00) >> 4;
313 entry
->fid
&= mv88e6xxx_num_databases(chip
) - 1;
319 int mv88e6352_g1_vtu_getnext(struct mv88e6xxx_chip
*chip
,
320 struct mv88e6xxx_vtu_entry
*entry
)
324 /* Fetch VLAN MemberTag data from the VTU */
325 err
= mv88e6xxx_g1_vtu_getnext(chip
, entry
);
330 err
= mv88e6185_g1_vtu_data_read(chip
, entry
->member
, NULL
);
334 err
= mv88e6xxx_g1_vtu_fid_read(chip
, entry
);
338 err
= mv88e6xxx_g1_vtu_sid_read(chip
, &entry
->sid
);
346 int mv88e6390_g1_vtu_getnext(struct mv88e6xxx_chip
*chip
,
347 struct mv88e6xxx_vtu_entry
*entry
)
351 /* Fetch VLAN MemberTag data from the VTU */
352 err
= mv88e6xxx_g1_vtu_getnext(chip
, entry
);
357 err
= mv88e6390_g1_vtu_data_read(chip
, entry
->member
);
361 err
= mv88e6xxx_g1_vtu_fid_read(chip
, entry
);
365 err
= mv88e6xxx_g1_vtu_sid_read(chip
, &entry
->sid
);
373 int mv88e6185_g1_vtu_loadpurge(struct mv88e6xxx_chip
*chip
,
374 struct mv88e6xxx_vtu_entry
*entry
)
376 u16 op
= MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE
;
379 err
= mv88e6xxx_g1_vtu_op_wait(chip
);
383 err
= mv88e6xxx_g1_vtu_vid_write(chip
, entry
->valid
, entry
->vid
);
388 err
= mv88e6185_g1_vtu_data_write(chip
, entry
->member
, entry
->state
);
392 /* VTU DBNum[3:0] are located in VTU Operation 3:0
393 * VTU DBNum[7:4] are located in VTU Operation 11:8
395 * For the 6250/6220, the latter are really [5:4] and
396 * 9:8, but in those cases bits 7:6 of entry->fid are
397 * 0 since they have num_databases = 64.
399 op
|= entry
->fid
& 0x000f;
400 op
|= (entry
->fid
& 0x00f0) << 4;
403 return mv88e6xxx_g1_vtu_op(chip
, op
);
406 int mv88e6352_g1_vtu_loadpurge(struct mv88e6xxx_chip
*chip
,
407 struct mv88e6xxx_vtu_entry
*entry
)
411 err
= mv88e6xxx_g1_vtu_op_wait(chip
);
415 err
= mv88e6xxx_g1_vtu_vid_write(chip
, entry
->valid
, entry
->vid
);
420 /* Write MemberTag data */
421 err
= mv88e6185_g1_vtu_data_write(chip
, entry
->member
, NULL
);
425 err
= mv88e6xxx_g1_vtu_fid_write(chip
, entry
);
429 err
= mv88e6xxx_g1_vtu_sid_write(chip
, entry
->sid
);
434 /* Load/Purge VTU entry */
435 return mv88e6xxx_g1_vtu_op(chip
, MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE
);
438 int mv88e6390_g1_vtu_loadpurge(struct mv88e6xxx_chip
*chip
,
439 struct mv88e6xxx_vtu_entry
*entry
)
443 err
= mv88e6xxx_g1_vtu_op_wait(chip
);
447 err
= mv88e6xxx_g1_vtu_vid_write(chip
, entry
->valid
, entry
->vid
);
452 /* Write MemberTag data */
453 err
= mv88e6390_g1_vtu_data_write(chip
, entry
->member
);
457 err
= mv88e6xxx_g1_vtu_fid_write(chip
, entry
);
461 err
= mv88e6xxx_g1_vtu_sid_write(chip
, entry
->sid
);
466 /* Load/Purge VTU entry */
467 return mv88e6xxx_g1_vtu_op(chip
, MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE
);
470 int mv88e6xxx_g1_vtu_flush(struct mv88e6xxx_chip
*chip
)
474 /* As part of the VTU flush, refresh FID map */
475 bitmap_zero(chip
->fid_bitmap
, MV88E6XXX_N_FID
);
477 err
= mv88e6xxx_g1_vtu_op_wait(chip
);
481 return mv88e6xxx_g1_vtu_op(chip
, MV88E6XXX_G1_VTU_OP_FLUSH_ALL
);
484 /* Spanning Tree Unit Operations */
486 int mv88e6xxx_g1_stu_getnext(struct mv88e6xxx_chip
*chip
,
487 struct mv88e6xxx_stu_entry
*entry
)
491 err
= mv88e6xxx_g1_vtu_op_wait(chip
);
495 /* To get the next higher active SID, the STU GetNext operation can be
496 * started again without setting the SID registers since it already
497 * contains the last SID.
499 * To save a few hardware accesses and abstract this to the caller,
500 * write the SID only once, when the entry is given as invalid.
503 err
= mv88e6xxx_g1_vtu_sid_write(chip
, entry
->sid
);
508 err
= mv88e6xxx_g1_vtu_op(chip
, MV88E6XXX_G1_VTU_OP_STU_GET_NEXT
);
512 err
= mv88e6xxx_g1_vtu_vid_read(chip
, &entry
->valid
, NULL
);
517 err
= mv88e6xxx_g1_vtu_sid_read(chip
, &entry
->sid
);
525 int mv88e6352_g1_stu_getnext(struct mv88e6xxx_chip
*chip
,
526 struct mv88e6xxx_stu_entry
*entry
)
530 err
= mv88e6xxx_g1_stu_getnext(chip
, entry
);
537 return mv88e6185_g1_vtu_data_read(chip
, NULL
, entry
->state
);
540 int mv88e6390_g1_stu_getnext(struct mv88e6xxx_chip
*chip
,
541 struct mv88e6xxx_stu_entry
*entry
)
545 err
= mv88e6xxx_g1_stu_getnext(chip
, entry
);
552 return mv88e6390_g1_vtu_data_read(chip
, entry
->state
);
555 int mv88e6352_g1_stu_loadpurge(struct mv88e6xxx_chip
*chip
,
556 struct mv88e6xxx_stu_entry
*entry
)
560 err
= mv88e6xxx_g1_vtu_op_wait(chip
);
564 err
= mv88e6xxx_g1_vtu_vid_write(chip
, entry
->valid
, 0);
568 err
= mv88e6xxx_g1_vtu_sid_write(chip
, entry
->sid
);
573 err
= mv88e6185_g1_vtu_data_write(chip
, NULL
, entry
->state
);
578 /* Load/Purge STU entry */
579 return mv88e6xxx_g1_vtu_op(chip
, MV88E6XXX_G1_VTU_OP_STU_LOAD_PURGE
);
582 int mv88e6390_g1_stu_loadpurge(struct mv88e6xxx_chip
*chip
,
583 struct mv88e6xxx_stu_entry
*entry
)
587 err
= mv88e6xxx_g1_vtu_op_wait(chip
);
591 err
= mv88e6xxx_g1_vtu_vid_write(chip
, entry
->valid
, 0);
595 err
= mv88e6xxx_g1_vtu_sid_write(chip
, entry
->sid
);
600 err
= mv88e6390_g1_vtu_data_write(chip
, entry
->state
);
605 /* Load/Purge STU entry */
606 return mv88e6xxx_g1_vtu_op(chip
, MV88E6XXX_G1_VTU_OP_STU_LOAD_PURGE
);
609 /* VTU Violation Management */
611 static irqreturn_t
mv88e6xxx_g1_vtu_prob_irq_thread_fn(int irq
, void *dev_id
)
613 struct mv88e6xxx_chip
*chip
= dev_id
;
618 mv88e6xxx_reg_lock(chip
);
620 err
= mv88e6xxx_g1_vtu_op(chip
, MV88E6XXX_G1_VTU_OP_GET_CLR_VIOLATION
);
624 err
= mv88e6xxx_g1_read(chip
, MV88E6XXX_G1_VTU_OP
, &val
);
628 err
= mv88e6xxx_g1_vtu_vid_read(chip
, NULL
, &vid
);
632 spid
= val
& MV88E6XXX_G1_VTU_OP_SPID_MASK
;
634 if (val
& MV88E6XXX_G1_VTU_OP_MEMBER_VIOLATION
) {
635 trace_mv88e6xxx_vtu_member_violation(chip
->dev
, spid
, vid
);
636 chip
->ports
[spid
].vtu_member_violation
++;
639 if (val
& MV88E6XXX_G1_VTU_OP_MISS_VIOLATION
) {
640 trace_mv88e6xxx_vtu_miss_violation(chip
->dev
, spid
, vid
);
641 chip
->ports
[spid
].vtu_miss_violation
++;
644 mv88e6xxx_reg_unlock(chip
);
649 mv88e6xxx_reg_unlock(chip
);
651 dev_err(chip
->dev
, "VTU problem: error %d while handling interrupt\n",
657 int mv88e6xxx_g1_vtu_prob_irq_setup(struct mv88e6xxx_chip
*chip
)
661 chip
->vtu_prob_irq
= irq_find_mapping(chip
->g1_irq
.domain
,
662 MV88E6XXX_G1_STS_IRQ_VTU_PROB
);
663 if (chip
->vtu_prob_irq
< 0)
664 return chip
->vtu_prob_irq
;
666 snprintf(chip
->vtu_prob_irq_name
, sizeof(chip
->vtu_prob_irq_name
),
667 "mv88e6xxx-%s-g1-vtu-prob", dev_name(chip
->dev
));
669 err
= request_threaded_irq(chip
->vtu_prob_irq
, NULL
,
670 mv88e6xxx_g1_vtu_prob_irq_thread_fn
,
671 IRQF_ONESHOT
, chip
->vtu_prob_irq_name
,
674 irq_dispose_mapping(chip
->vtu_prob_irq
);
679 void mv88e6xxx_g1_vtu_prob_irq_free(struct mv88e6xxx_chip
*chip
)
681 free_irq(chip
->vtu_prob_irq
, chip
);
682 irq_dispose_mapping(chip
->vtu_prob_irq
);