1// SPDX-License-Identifier: GPL-2.0+
2
3#include "lan966x_main.h"
4
5#define VLANACCESS_CMD_IDLE		0
6#define VLANACCESS_CMD_READ		1
7#define VLANACCESS_CMD_WRITE		2
8#define VLANACCESS_CMD_INIT		3
9
10static int lan966x_vlan_get_status(struct lan966x *lan966x)
11{
12	return lan_rd(lan966x, ANA_VLANACCESS);
13}
14
15static int lan966x_vlan_wait_for_completion(struct lan966x *lan966x)
16{
17	u32 val;
18
19	return readx_poll_timeout(lan966x_vlan_get_status,
20		lan966x, val,
21		(val & ANA_VLANACCESS_VLAN_TBL_CMD) ==
22		VLANACCESS_CMD_IDLE,
23		TABLE_UPDATE_SLEEP_US, TABLE_UPDATE_TIMEOUT_US);
24}
25
26static void lan966x_vlan_set_mask(struct lan966x *lan966x, u16 vid)
27{
28	u16 mask = lan966x->vlan_mask[vid];
29	bool cpu_dis;
30
31	cpu_dis = !(mask & BIT(CPU_PORT));
32
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 |
37		ANA_VLANTIDX_V_INDEX,
38		lan966x, ANA_VLANTIDX);
39
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);
44
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);
49
50	if (lan966x_vlan_wait_for_completion(lan966x))
51		dev_err(lan966x->dev, "Vlan set mask failed\n");
52}
53
54static void lan966x_vlan_port_add_vlan_mask(struct lan966x_port *port, u16 vid)
55{
56	struct lan966x *lan966x = port->lan966x;
57	u8 p = port->chip_port;
58
59	lan966x->vlan_mask[vid] |= BIT(p);
60	lan966x_vlan_set_mask(lan966x, vid);
61}
62
63static void lan966x_vlan_port_del_vlan_mask(struct lan966x_port *port, u16 vid)
64{
65	struct lan966x *lan966x = port->lan966x;
66	u8 p = port->chip_port;
67
68	lan966x->vlan_mask[vid] &= ~BIT(p);
69	lan966x_vlan_set_mask(lan966x, vid);
70}
71
72static bool lan966x_vlan_port_any_vlan_mask(struct lan966x *lan966x, u16 vid)
73{
74	return !!(lan966x->vlan_mask[vid] & ~BIT(CPU_PORT));
75}
76
77static void lan966x_vlan_cpu_add_vlan_mask(struct lan966x *lan966x, u16 vid)
78{
79	lan966x->vlan_mask[vid] |= BIT(CPU_PORT);
80	lan966x_vlan_set_mask(lan966x, vid);
81}
82
83static void lan966x_vlan_cpu_del_vlan_mask(struct lan966x *lan966x, u16 vid)
84{
85	lan966x->vlan_mask[vid] &= ~BIT(CPU_PORT);
86	lan966x_vlan_set_mask(lan966x, vid);
87}
88
89static void lan966x_vlan_cpu_add_cpu_vlan_mask(struct lan966x *lan966x, u16 vid)
90{
91	__set_bit(vid, lan966x->cpu_vlan_mask);
92}
93
94static void lan966x_vlan_cpu_del_cpu_vlan_mask(struct lan966x *lan966x, u16 vid)
95{
96	__clear_bit(vid, lan966x->cpu_vlan_mask);
97}
98
99bool lan966x_vlan_cpu_member_cpu_vlan_mask(struct lan966x *lan966x, u16 vid)
100{
101	return test_bit(vid, lan966x->cpu_vlan_mask);
102}
103
104static u16 lan966x_vlan_port_get_pvid(struct lan966x_port *port)
105{
106	struct lan966x *lan966x = port->lan966x;
107
108	if (!(lan966x->bridge_mask & BIT(port->chip_port)))
109		return HOST_PVID;
110
111	return port->vlan_aware ? port->pvid : UNAWARE_PVID;
112}
113
114int lan966x_vlan_port_set_vid(struct lan966x_port *port, u16 vid,
115			      bool pvid, bool untagged)
116{
117	struct lan966x *lan966x = port->lan966x;
118
119	/* Egress vlan classification */
120	if (untagged && port->vid != vid) {
121		if (port->vid) {
122			dev_err(lan966x->dev,
123				"Port already has a native VLAN: %d\n",
124				port->vid);
125			return -EBUSY;
126		}
127		port->vid = vid;
128	}
129
130	/* Default ingress vlan classification */
131	if (pvid)
132		port->pvid = vid;
133
134	return 0;
135}
136
137static void lan966x_vlan_port_remove_vid(struct lan966x_port *port, u16 vid)
138{
139	if (port->pvid == vid)
140		port->pvid = 0;
141
142	if (port->vid == vid)
143		port->vid = 0;
144}
145
146void lan966x_vlan_port_set_vlan_aware(struct lan966x_port *port,
147				      bool vlan_aware)
148{
149	port->vlan_aware = vlan_aware;
150}
151
152void lan966x_vlan_port_apply(struct lan966x_port *port)
153{
154	struct lan966x *lan966x = port->lan966x;
155	u16 pvid;
156	u32 val;
157
158	pvid = lan966x_vlan_port_get_pvid(port);
159
160	/* Ingress clasification (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);
166
167	lan_rmw(val,
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));
171
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));
177
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
182		 * tagged frames.
183		 */
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);
187
188	lan_wr(val, lan966x, ANA_DROP_CFG(port->chip_port));
189
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) {
193		if (port->vid)
194			/* Tag all frames except when VID == DEFAULT_VLAN */
195			val |= REW_TAG_CFG_TAG_CFG_SET(1);
196		else
197			val |= REW_TAG_CFG_TAG_CFG_SET(3);
198	}
199
200	/* Update only some bits in the register */
201	lan_rmw(val,
202		REW_TAG_CFG_TAG_TPID_CFG | REW_TAG_CFG_TAG_CFG,
203		lan966x, REW_TAG_CFG(port->chip_port));
204
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));
211}
212
213void lan966x_vlan_port_add_vlan(struct lan966x_port *port,
214				u16 vid,
215				bool pvid,
216				bool untagged)
217{
218	struct lan966x *lan966x = port->lan966x;
219
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.
224	 */
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);
229	}
230
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);
234}
235
236void lan966x_vlan_port_del_vlan(struct lan966x_port *port, u16 vid)
237{
238	struct lan966x *lan966x = port->lan966x;
239
240	lan966x_vlan_port_remove_vid(port, vid);
241	lan966x_vlan_port_del_vlan_mask(port, vid);
242	lan966x_vlan_port_apply(port);
243
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
247	 */
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);
252	}
253}
254
255void lan966x_vlan_cpu_add_vlan(struct lan966x *lan966x, u16 vid)
256{
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
263	 * CPU port.
264	 */
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);
268	}
269
270	lan966x_vlan_cpu_add_cpu_vlan_mask(lan966x, vid);
271	lan966x_fdb_write_entries(lan966x, vid);
272}
273
274void lan966x_vlan_cpu_del_vlan(struct lan966x *lan966x, u16 vid)
275{
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);
281}
282
283void lan966x_vlan_init(struct lan966x *lan966x)
284{
285	u16 port, vid;
286
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);
292
293	for (vid = 1; vid < VLAN_N_VID; vid++) {
294		lan966x->vlan_mask[vid] = 0;
295		lan966x_vlan_set_mask(lan966x, vid);
296	}
297
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);
302
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);
306
307	lan966x_vlan_cpu_add_cpu_vlan_mask(lan966x, UNAWARE_PVID);
308
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));
314
315	/* Set vlan ingress filter mask to all ports */
316	lan_wr(GENMASK(lan966x->num_phys_ports, 0),
317	       lan966x, ANA_VLANMASK);
318
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));
322	}
323}
324