1 // SPDX-License-Identifier: GPL-2.0+
3 #include "lan966x_main.h"
5 #define VLANACCESS_CMD_IDLE 0
6 #define VLANACCESS_CMD_READ 1
7 #define VLANACCESS_CMD_WRITE 2
8 #define VLANACCESS_CMD_INIT 3
10 static int lan966x_vlan_get_status(struct lan966x *lan966x)
12 return lan_rd(lan966x, ANA_VLANACCESS);
15 static int lan966x_vlan_wait_for_completion(struct lan966x *lan966x)
19 return readx_poll_timeout(lan966x_vlan_get_status,
21 (val & ANA_VLANACCESS_VLAN_TBL_CMD) ==
23 TABLE_UPDATE_SLEEP_US, TABLE_UPDATE_TIMEOUT_US);
26 static void lan966x_vlan_set_mask(struct lan966x *lan966x, u16 vid)
28 u16 mask = lan966x->vlan_mask[vid];
31 cpu_dis = !(mask & BIT(CPU_PORT));
33 /* Set flags and the VID to configure */
34 lan_rmw(ANA_VLANTIDX_VLAN_PGID_CPU_DIS_SET(cpu_dis) |
35 ANA_VLANTIDX_V_INDEX_SET(vid),
36 ANA_VLANTIDX_VLAN_PGID_CPU_DIS |
38 lan966x, ANA_VLANTIDX);
40 /* Set the vlan port members mask */
41 lan_rmw(ANA_VLAN_PORT_MASK_VLAN_PORT_MASK_SET(mask),
42 ANA_VLAN_PORT_MASK_VLAN_PORT_MASK,
43 lan966x, ANA_VLAN_PORT_MASK);
45 /* Issue a write command */
46 lan_rmw(ANA_VLANACCESS_VLAN_TBL_CMD_SET(VLANACCESS_CMD_WRITE),
47 ANA_VLANACCESS_VLAN_TBL_CMD,
48 lan966x, ANA_VLANACCESS);
50 if (lan966x_vlan_wait_for_completion(lan966x))
51 dev_err(lan966x->dev, "Vlan set mask failed\n");
54 static void lan966x_vlan_port_add_vlan_mask(struct lan966x_port *port, u16 vid)
56 struct lan966x *lan966x = port->lan966x;
57 u8 p = port->chip_port;
59 lan966x->vlan_mask[vid] |= BIT(p);
60 lan966x_vlan_set_mask(lan966x, vid);
63 static void lan966x_vlan_port_del_vlan_mask(struct lan966x_port *port, u16 vid)
65 struct lan966x *lan966x = port->lan966x;
66 u8 p = port->chip_port;
68 lan966x->vlan_mask[vid] &= ~BIT(p);
69 lan966x_vlan_set_mask(lan966x, vid);
72 static bool lan966x_vlan_port_any_vlan_mask(struct lan966x *lan966x, u16 vid)
74 return !!(lan966x->vlan_mask[vid] & ~BIT(CPU_PORT));
77 static void lan966x_vlan_cpu_add_vlan_mask(struct lan966x *lan966x, u16 vid)
79 lan966x->vlan_mask[vid] |= BIT(CPU_PORT);
80 lan966x_vlan_set_mask(lan966x, vid);
83 static void lan966x_vlan_cpu_del_vlan_mask(struct lan966x *lan966x, u16 vid)
85 lan966x->vlan_mask[vid] &= ~BIT(CPU_PORT);
86 lan966x_vlan_set_mask(lan966x, vid);
89 static void lan966x_vlan_cpu_add_cpu_vlan_mask(struct lan966x *lan966x, u16 vid)
91 __set_bit(vid, lan966x->cpu_vlan_mask);
94 static void lan966x_vlan_cpu_del_cpu_vlan_mask(struct lan966x *lan966x, u16 vid)
96 __clear_bit(vid, lan966x->cpu_vlan_mask);
99 bool lan966x_vlan_cpu_member_cpu_vlan_mask(struct lan966x *lan966x, u16 vid)
101 return test_bit(vid, lan966x->cpu_vlan_mask);
104 static u16 lan966x_vlan_port_get_pvid(struct lan966x_port *port)
106 struct lan966x *lan966x = port->lan966x;
108 if (!(lan966x->bridge_mask & BIT(port->chip_port)))
111 return port->vlan_aware ? port->pvid : UNAWARE_PVID;
114 int lan966x_vlan_port_set_vid(struct lan966x_port *port, u16 vid,
115 bool pvid, bool untagged)
117 struct lan966x *lan966x = port->lan966x;
119 /* Egress vlan classification */
120 if (untagged && port->vid != vid) {
122 dev_err(lan966x->dev,
123 "Port already has a native VLAN: %d\n",
130 /* Default ingress vlan classification */
137 static void lan966x_vlan_port_remove_vid(struct lan966x_port *port, u16 vid)
139 if (port->pvid == vid)
142 if (port->vid == vid)
146 void lan966x_vlan_port_set_vlan_aware(struct lan966x_port *port,
149 port->vlan_aware = vlan_aware;
152 void lan966x_vlan_port_apply(struct lan966x_port *port)
154 struct lan966x *lan966x = port->lan966x;
158 pvid = lan966x_vlan_port_get_pvid(port);
160 /* Ingress classification (ANA_PORT_VLAN_CFG) */
161 /* Default vlan to classify for untagged frames (may be zero) */
162 val = ANA_VLAN_CFG_VLAN_VID_SET(pvid);
163 if (port->vlan_aware)
164 val |= ANA_VLAN_CFG_VLAN_AWARE_ENA_SET(1) |
165 ANA_VLAN_CFG_VLAN_POP_CNT_SET(1);
168 ANA_VLAN_CFG_VLAN_VID | ANA_VLAN_CFG_VLAN_AWARE_ENA |
169 ANA_VLAN_CFG_VLAN_POP_CNT,
170 lan966x, ANA_VLAN_CFG(port->chip_port));
172 lan_rmw(DEV_MAC_TAGS_CFG_VLAN_AWR_ENA_SET(port->vlan_aware) |
173 DEV_MAC_TAGS_CFG_VLAN_DBL_AWR_ENA_SET(port->vlan_aware),
174 DEV_MAC_TAGS_CFG_VLAN_AWR_ENA |
175 DEV_MAC_TAGS_CFG_VLAN_DBL_AWR_ENA,
176 lan966x, DEV_MAC_TAGS_CFG(port->chip_port));
178 /* Drop frames with multicast source address */
179 val = ANA_DROP_CFG_DROP_MC_SMAC_ENA_SET(1);
180 if (port->vlan_aware && !pvid)
181 /* If port is vlan-aware and tagged, drop untagged and priority
184 val |= ANA_DROP_CFG_DROP_UNTAGGED_ENA_SET(1) |
185 ANA_DROP_CFG_DROP_PRIO_S_TAGGED_ENA_SET(1) |
186 ANA_DROP_CFG_DROP_PRIO_C_TAGGED_ENA_SET(1);
188 lan_wr(val, lan966x, ANA_DROP_CFG(port->chip_port));
190 /* Egress configuration (REW_TAG_CFG): VLAN tag type to 8021Q */
191 val = REW_TAG_CFG_TAG_TPID_CFG_SET(0);
192 if (port->vlan_aware) {
194 /* Tag all frames except when VID == DEFAULT_VLAN */
195 val |= REW_TAG_CFG_TAG_CFG_SET(1);
197 val |= REW_TAG_CFG_TAG_CFG_SET(3);
200 /* Update only some bits in the register */
202 REW_TAG_CFG_TAG_TPID_CFG | REW_TAG_CFG_TAG_CFG,
203 lan966x, REW_TAG_CFG(port->chip_port));
205 /* Set default VLAN and tag type to 8021Q */
206 lan_rmw(REW_PORT_VLAN_CFG_PORT_TPID_SET(ETH_P_8021Q) |
207 REW_PORT_VLAN_CFG_PORT_VID_SET(port->vid),
208 REW_PORT_VLAN_CFG_PORT_TPID |
209 REW_PORT_VLAN_CFG_PORT_VID,
210 lan966x, REW_PORT_VLAN_CFG(port->chip_port));
213 void lan966x_vlan_port_add_vlan(struct lan966x_port *port,
218 struct lan966x *lan966x = port->lan966x;
220 /* If the CPU(br) is already part of the vlan then add the fdb
221 * entries in MAC table to copy the frames to the CPU(br).
222 * If the CPU(br) is not part of the vlan then it would
223 * just drop the frames.
225 if (lan966x_vlan_cpu_member_cpu_vlan_mask(lan966x, vid)) {
226 lan966x_vlan_cpu_add_vlan_mask(lan966x, vid);
227 lan966x_fdb_write_entries(lan966x, vid);
228 lan966x_mdb_write_entries(lan966x, vid);
231 lan966x_vlan_port_set_vid(port, vid, pvid, untagged);
232 lan966x_vlan_port_add_vlan_mask(port, vid);
233 lan966x_vlan_port_apply(port);
236 void lan966x_vlan_port_del_vlan(struct lan966x_port *port, u16 vid)
238 struct lan966x *lan966x = port->lan966x;
240 lan966x_vlan_port_remove_vid(port, vid);
241 lan966x_vlan_port_del_vlan_mask(port, vid);
242 lan966x_vlan_port_apply(port);
244 /* In case there are no other ports in vlan then remove the CPU from
245 * that vlan but still keep it in the mask because it may be needed
246 * again then another port gets added in that vlan
248 if (!lan966x_vlan_port_any_vlan_mask(lan966x, vid)) {
249 lan966x_vlan_cpu_del_vlan_mask(lan966x, vid);
250 lan966x_fdb_erase_entries(lan966x, vid);
251 lan966x_mdb_erase_entries(lan966x, vid);
255 void lan966x_vlan_cpu_add_vlan(struct lan966x *lan966x, u16 vid)
257 /* Add an entry in the MAC table for the CPU
258 * Add the CPU part of the vlan only if there is another port in that
259 * vlan otherwise all the broadcast frames in that vlan will go to CPU
260 * even if none of the ports are in the vlan and then the CPU will just
261 * need to discard these frames. It is required to store this
262 * information so when a front port is added then it would add also the
265 if (lan966x_vlan_port_any_vlan_mask(lan966x, vid)) {
266 lan966x_vlan_cpu_add_vlan_mask(lan966x, vid);
267 lan966x_mdb_write_entries(lan966x, vid);
270 lan966x_vlan_cpu_add_cpu_vlan_mask(lan966x, vid);
271 lan966x_fdb_write_entries(lan966x, vid);
274 void lan966x_vlan_cpu_del_vlan(struct lan966x *lan966x, u16 vid)
276 /* Remove the CPU part of the vlan */
277 lan966x_vlan_cpu_del_cpu_vlan_mask(lan966x, vid);
278 lan966x_vlan_cpu_del_vlan_mask(lan966x, vid);
279 lan966x_fdb_erase_entries(lan966x, vid);
280 lan966x_mdb_erase_entries(lan966x, vid);
283 void lan966x_vlan_init(struct lan966x *lan966x)
287 /* Clear VLAN table, by default all ports are members of all VLANS */
288 lan_rmw(ANA_VLANACCESS_VLAN_TBL_CMD_SET(VLANACCESS_CMD_INIT),
289 ANA_VLANACCESS_VLAN_TBL_CMD,
290 lan966x, ANA_VLANACCESS);
291 lan966x_vlan_wait_for_completion(lan966x);
293 for (vid = 1; vid < VLAN_N_VID; vid++) {
294 lan966x->vlan_mask[vid] = 0;
295 lan966x_vlan_set_mask(lan966x, vid);
298 /* Set all the ports + cpu to be part of HOST_PVID and UNAWARE_PVID */
299 lan966x->vlan_mask[HOST_PVID] =
300 GENMASK(lan966x->num_phys_ports - 1, 0) | BIT(CPU_PORT);
301 lan966x_vlan_set_mask(lan966x, HOST_PVID);
303 lan966x->vlan_mask[UNAWARE_PVID] =
304 GENMASK(lan966x->num_phys_ports - 1, 0) | BIT(CPU_PORT);
305 lan966x_vlan_set_mask(lan966x, UNAWARE_PVID);
307 lan966x_vlan_cpu_add_cpu_vlan_mask(lan966x, UNAWARE_PVID);
309 /* Configure the CPU port to be vlan aware */
310 lan_wr(ANA_VLAN_CFG_VLAN_VID_SET(0) |
311 ANA_VLAN_CFG_VLAN_AWARE_ENA_SET(1) |
312 ANA_VLAN_CFG_VLAN_POP_CNT_SET(1),
313 lan966x, ANA_VLAN_CFG(CPU_PORT));
315 /* Set vlan ingress filter mask to all ports */
316 lan_wr(GENMASK(lan966x->num_phys_ports, 0),
317 lan966x, ANA_VLANMASK);
319 for (port = 0; port < lan966x->num_phys_ports; port++) {
320 lan_wr(0, lan966x, REW_PORT_VLAN_CFG(port));
321 lan_wr(0, lan966x, REW_TAG_CFG(port));