2 * Marvell 88E6xxx VLAN [Spanning Tree] Translation Unit (VTU [STU]) support
4 * Copyright (c) 2008 Marvell Semiconductor
5 * Copyright (c) 2015 CMC Electronics, Inc.
6 * Copyright (c) 2017 Savoir-faire Linux, Inc.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
14 #include "mv88e6xxx.h"
17 /* Offset 0x02: VTU FID Register */
19 int mv88e6xxx_g1_vtu_fid_read(struct mv88e6xxx_chip
*chip
,
20 struct mv88e6xxx_vtu_entry
*entry
)
25 err
= mv88e6xxx_g1_read(chip
, GLOBAL_VTU_FID
, &val
);
29 entry
->fid
= val
& GLOBAL_VTU_FID_MASK
;
34 int mv88e6xxx_g1_vtu_fid_write(struct mv88e6xxx_chip
*chip
,
35 struct mv88e6xxx_vtu_entry
*entry
)
37 u16 val
= entry
->fid
& GLOBAL_VTU_FID_MASK
;
39 return mv88e6xxx_g1_write(chip
, GLOBAL_VTU_FID
, val
);
42 /* Offset 0x03: VTU SID Register */
44 int mv88e6xxx_g1_vtu_sid_read(struct mv88e6xxx_chip
*chip
,
45 struct mv88e6xxx_vtu_entry
*entry
)
50 err
= mv88e6xxx_g1_read(chip
, GLOBAL_VTU_SID
, &val
);
54 entry
->sid
= val
& GLOBAL_VTU_SID_MASK
;
59 int mv88e6xxx_g1_vtu_sid_write(struct mv88e6xxx_chip
*chip
,
60 struct mv88e6xxx_vtu_entry
*entry
)
62 u16 val
= entry
->sid
& GLOBAL_VTU_SID_MASK
;
64 return mv88e6xxx_g1_write(chip
, GLOBAL_VTU_SID
, val
);
67 /* Offset 0x05: VTU Operation Register */
69 int mv88e6xxx_g1_vtu_op_wait(struct mv88e6xxx_chip
*chip
)
71 return mv88e6xxx_g1_wait(chip
, GLOBAL_VTU_OP
, GLOBAL_VTU_OP_BUSY
);
74 int mv88e6xxx_g1_vtu_op(struct mv88e6xxx_chip
*chip
, u16 op
)
78 err
= mv88e6xxx_g1_write(chip
, GLOBAL_VTU_OP
, op
);
82 return mv88e6xxx_g1_vtu_op_wait(chip
);
85 /* Offset 0x06: VTU VID Register */
87 int mv88e6xxx_g1_vtu_vid_read(struct mv88e6xxx_chip
*chip
,
88 struct mv88e6xxx_vtu_entry
*entry
)
93 err
= mv88e6xxx_g1_read(chip
, GLOBAL_VTU_VID
, &val
);
97 entry
->vid
= val
& 0xfff;
98 entry
->valid
= !!(val
& GLOBAL_VTU_VID_VALID
);
103 int mv88e6xxx_g1_vtu_vid_write(struct mv88e6xxx_chip
*chip
,
104 struct mv88e6xxx_vtu_entry
*entry
)
106 u16 val
= entry
->vid
& 0xfff;
109 val
|= GLOBAL_VTU_VID_VALID
;
111 return mv88e6xxx_g1_write(chip
, GLOBAL_VTU_VID
, val
);
114 /* Offset 0x07: VTU/STU Data Register 1
115 * Offset 0x08: VTU/STU Data Register 2
116 * Offset 0x09: VTU/STU Data Register 3
119 int mv88e6185_g1_vtu_data_read(struct mv88e6xxx_chip
*chip
,
120 struct mv88e6xxx_vtu_entry
*entry
)
125 /* Read all 3 VTU/STU Data registers */
126 for (i
= 0; i
< 3; ++i
) {
130 err
= mv88e6xxx_g1_read(chip
, GLOBAL_VTU_DATA_0_3
+ i
, reg
);
135 /* Extract MemberTag and PortState data */
136 for (i
= 0; i
< mv88e6xxx_num_ports(chip
); ++i
) {
137 unsigned int member_offset
= (i
% 4) * 4;
138 unsigned int state_offset
= member_offset
+ 2;
140 entry
->member
[i
] = (regs
[i
/ 4] >> member_offset
) & 0x3;
141 entry
->state
[i
] = (regs
[i
/ 4] >> state_offset
) & 0x3;
147 int mv88e6185_g1_vtu_data_write(struct mv88e6xxx_chip
*chip
,
148 struct mv88e6xxx_vtu_entry
*entry
)
153 /* Insert MemberTag and PortState data */
154 for (i
= 0; i
< mv88e6xxx_num_ports(chip
); ++i
) {
155 unsigned int member_offset
= (i
% 4) * 4;
156 unsigned int state_offset
= member_offset
+ 2;
158 regs
[i
/ 4] |= (entry
->member
[i
] & 0x3) << member_offset
;
159 regs
[i
/ 4] |= (entry
->state
[i
] & 0x3) << state_offset
;
162 /* Write all 3 VTU/STU Data registers */
163 for (i
= 0; i
< 3; ++i
) {
167 err
= mv88e6xxx_g1_write(chip
, GLOBAL_VTU_DATA_0_3
+ i
, reg
);
175 /* VLAN Translation Unit Operations */
177 int mv88e6xxx_g1_vtu_stu_getnext(struct mv88e6xxx_chip
*chip
,
178 struct mv88e6xxx_vtu_entry
*entry
)
182 err
= mv88e6xxx_g1_vtu_sid_write(chip
, entry
);
186 err
= mv88e6xxx_g1_vtu_op(chip
, GLOBAL_VTU_OP_STU_GET_NEXT
);
190 err
= mv88e6xxx_g1_vtu_sid_read(chip
, entry
);
194 return mv88e6xxx_g1_vtu_vid_read(chip
, entry
);
197 int mv88e6xxx_g1_vtu_getnext(struct mv88e6xxx_chip
*chip
,
198 struct mv88e6xxx_vtu_entry
*entry
)
202 err
= mv88e6xxx_g1_vtu_op_wait(chip
);
206 /* To get the next higher active VID, the VTU GetNext operation can be
207 * started again without setting the VID registers since it already
208 * contains the last VID.
210 * To save a few hardware accesses and abstract this to the caller,
211 * write the VID only once, when the entry is given as invalid.
214 err
= mv88e6xxx_g1_vtu_vid_write(chip
, entry
);
219 err
= mv88e6xxx_g1_vtu_op(chip
, GLOBAL_VTU_OP_VTU_GET_NEXT
);
223 return mv88e6xxx_g1_vtu_vid_read(chip
, entry
);
226 int mv88e6xxx_g1_vtu_flush(struct mv88e6xxx_chip
*chip
)
230 err
= mv88e6xxx_g1_vtu_op_wait(chip
);
234 return mv88e6xxx_g1_vtu_op(chip
, GLOBAL_VTU_OP_FLUSH_ALL
);