xref: /linux/drivers/net/dsa/realtek/rtl8365mb_vlan.c (revision 9da2c8672f77108a1f09232320f22225ab53dde9)
1 // SPDX-License-Identifier: GPL-2.0
2 /* VLAN configuration interface for the rtl8365mb switch family
3  *
4  * Copyright (C) 2022 Alvin Šipraga <alsi@bang-olufsen.dk>
5  *
6  * VLAN configuration takes place in two separate domains of the switch: the
7  * VLAN4k table and the VLAN membership configuration (MC) database. While the
8  * VLAN4k table is exhaustive and can be fully populated with 4096 VLAN
9  * configurations, the same does not hold for the VLAN membership configuration
10  * database, which is limited to 32 entries.
11  *
12  * The switch will normally only use the VLAN4k table when making forwarding
13  * decisions. The VLAN membership configuration database is a vestigial ASIC
14  * design and is only used for a few specific features in the rtl8365mb
15  * family. This means that the limit of 32 entries should not hinder us in
16  * programming a huge number of VLANs into the switch.
17  *
18  * One necessary use of the VLAN membership configuration database is for the
19  * programming of a port-based VLAN ID (PVID). The PVID is programmed on a
20  * per-port basis via register field, which refers to a specific VLAN membership
21  * configuration via an index 0~31. In order to maintain coherent behaviour on a
22  * port with a PVID, it is necessary to keep the VLAN configuration synchronized
23  * between the VLAN4k table and the VLAN membership configuration database.
24  *
25  * Since VLAN membership configs are a scarce resource, it will only be used
26  * when strictly needed (i.e. a VLAN with members using PVID). Otherwise, the
27  * VLAN4k will be enough.
28  *
29  * With some exceptions, the entries in both the VLAN4k table and the VLAN
30  * membership configuration database offer the same configuration options. The
31  * differences are as follows:
32  *
33  * 1. VLAN4k entries can specify whether to use Independent or Shared VLAN
34  *    Learning (IVL or SVL respectively). VLAN membership config entries
35  *    cannot. This underscores the fact that VLAN membership configs are not
36  *    involved in the learning process of the ASIC.
37  *
38  * 2. VLAN membership config entries use an "enhanced VLAN ID" (efid), which has
39  *    a range 0~8191 compared with the standard 0~4095 range of the VLAN4k
40  *    table. This underscores the fact that VLAN membership configs can be used
41  *    to group ports on a layer beyond the standard VLAN configuration, which
42  *    may be useful for ACL rules which specify alternative forwarding
43  *    decisions.
44  *
45  * VLANMC index 0 is reserved as a neutral PVID, used for standalone ports.
46  *
47  */
48 
49 #include "rtl8365mb_vlan.h"
50 #include "rtl8365mb_table.h"
51 #include <linux/if_bridge.h>
52 #include <linux/lockdep.h>
53 #include <linux/regmap.h>
54 
55 /* CVLAN (i.e. VLAN4k) table entry layout, u16[3] */
56 #define RTL8365MB_CVLAN_ENTRY_SIZE			3 /* 48-bits */
57 #define RTL8365MB_CVLAN_ENTRY_D0_MBR_MASK		GENMASK(7, 0)
58 #define   RTL8365MB_CVLAN_MBR_LO_MASK			GENMASK(7, 0)
59 #define RTL8365MB_CVLAN_ENTRY_D0_UNTAG_MASK		GENMASK(15, 8)
60 #define   RTL8365MB_CVLAN_UNTAG_LO_MASK			GENMASK(7, 0)
61 #define RTL8365MB_CVLAN_ENTRY_D1_FID_MASK		GENMASK(3, 0)
62 #define RTL8365MB_CVLAN_ENTRY_D1_VBPEN_MASK		GENMASK(4, 4)
63 #define RTL8365MB_CVLAN_ENTRY_D1_VBPRI_MASK		GENMASK(7, 5)
64 #define RTL8365MB_CVLAN_ENTRY_D1_ENVLANPOL_MASK		GENMASK(8, 8)
65 #define RTL8365MB_CVLAN_ENTRY_D1_METERIDX_MASK		GENMASK(13, 9)
66 #define   RTL8365MB_CVLAN_METERIDX_LO_MASK		GENMASK(4, 0)
67 #define RTL8365MB_CVLAN_ENTRY_D1_IVL_SVL_MASK		GENMASK(14, 14)
68 /* extends RTL8365MB_CVLAN_ENTRY_D0_MBR_MASK */
69 #define RTL8365MB_CVLAN_ENTRY_D2_MBR_EXT_MASK		GENMASK(2, 0)
70 #define   RTL8365MB_CVLAN_MBR_HI_MASK			GENMASK(10, 8)
71 /* extends RTL8365MB_CVLAN_ENTRY_D0_UNTAG_MASK */
72 #define RTL8365MB_CVLAN_ENTRY_D2_UNTAG_EXT_MASK		GENMASK(5, 3)
73 #define   RTL8365MB_CVLAN_UNTAG_HI_MASK			GENMASK(10, 8)
74 /* extends RTL8365MB_CVLAN_ENTRY_D1_METERIDX_MASK */
75 #define RTL8365MB_CVLAN_ENTRY_D2_METERIDX_EXT_MASK	GENMASK(6, 6)
76 #define   RTL8365MB_CVLAN_METERIDX_HI_MASK		GENMASK(5, 5)
77 
78 /* VLAN member configuration registers 0~31, u16[3] */
79 #define RTL8365MB_VLAN_MC_BASE				0x0728
80 #define RTL8365MB_VLAN_MC_ENTRY_SIZE			4 /* 64-bit */
81 #define RTL8365MB_VLAN_MC_REG(index) \
82 		(RTL8365MB_VLAN_MC_BASE + \
83 		 (RTL8365MB_VLAN_MC_ENTRY_SIZE * (index)))
84 #define   RTL8365MB_VLAN_MC_D0_MBR_MASK			GENMASK(10, 0)
85 #define   RTL8365MB_VLAN_MC_D1_FID_MASK			GENMASK(3, 0)
86 
87 #define   RTL8365MB_VLAN_MC_D2_VBPEN_MASK		GENMASK(0, 0)
88 #define   RTL8365MB_VLAN_MC_D2_VBPRI_MASK		GENMASK(3, 1)
89 #define   RTL8365MB_VLAN_MC_D2_ENVLANPOL_MASK		GENMASK(4, 4)
90 #define   RTL8365MB_VLAN_MC_D2_METERIDX_MASK		GENMASK(10, 5)
91 #define   RTL8365MB_VLAN_MC_D3_EVID_MASK		GENMASK(12, 0)
92 
93 /* Some limits for VLAN4k/VLAN membership config entries */
94 #define RTL8365MB_PRIORITYMAX	7
95 #define RTL8365MB_FIDMAX	15
96 #define RTL8365MB_METERMAX	63
97 #define RTL8365MB_VLAN_MCMAX	31
98 
99 /* RTL8367S supports 4k vlans (vid<=4095) and 32 enhanced vlans
100  * for VIDs up to 8191
101  */
102 #define RTL8365MB_MAX_4K_VID	0x0FFF /* 4095 */
103 #define RTL8365MB_MAX_MC_VID	0x1FFF /* 8191 */
104 
105  /* Port-based VID registers 0~5 - each one holds an MC index for two ports */
106 #define RTL8365MB_VLAN_PVID_CTRL_BASE			0x0700
107 #define RTL8365MB_VLAN_PVID_CTRL_REG(_p) \
108 		(RTL8365MB_VLAN_PVID_CTRL_BASE + ((_p) >> 1))
109 #define   RTL8365MB_VLAN_PVID_CTRL_PORT0_MCIDX_MASK	0x001F
110 #define   RTL8365MB_VLAN_PVID_CTRL_PORT1_MCIDX_MASK	0x1F00
111 #define   RTL8365MB_VLAN_PVID_CTRL_PORT_MCIDX_OFFSET(_p) \
112 		(((_p) & 1) << 3)
113 #define   RTL8365MB_VLAN_PVID_CTRL_PORT_MCIDX_MASK(_p) \
114 		(0x1F << RTL8365MB_VLAN_PVID_CTRL_PORT_MCIDX_OFFSET(_p))
115 
116 /* Frame type filtering registers */
117 #define RTL8365MB_VLAN_ACCEPT_FRAME_TYPE_BASE	0x07aa
118 #define RTL8365MB_VLAN_ACCEPT_FRAME_TYPE_REG(port) \
119 		(RTL8365MB_VLAN_ACCEPT_FRAME_TYPE_BASE + ((port) >> 3))
120 /* required as FIELD_PREP cannot use non-constant masks */
121 #define RTL8365MB_VLAN_ACCEPT_FRAME_TYPE_MASK(port) \
122 		(0x3 << RTL8365MB_VLAN_ACCEPT_FRAME_TYPE_OFFSET(port))
123 #define RTL8365MB_VLAN_ACCEPT_FRAME_TYPE_OFFSET(port) \
124 		(((port) & 0x7) << 1)
125 
126 /*
127  * struct rtl8365mb_vlan4k - VLAN4k table entry
128  * @vid: VLAN ID (0~4095)
129  * @member: port mask of ports in this VLAN
130  * @untag: port mask of ports which untag on egress
131  * @fid: filter ID - only used with SVL (unused)
132  * @priority: priority classification (unused)
133  * @priority_en: enable priority (unused)
134  * @policing_en: enable policing (unused)
135  * @ivl_en: enable IVL instead of default SVL
136  * @meteridx: metering index (unused)
137  *
138  * This structure is used to get/set entries in the VLAN4k table. The
139  * VLAN4k table dictates the VLAN configuration for the switch for the
140  * vast majority of features.
141  */
142 struct rtl8365mb_vlan4k {
143 	u16 vid;
144 	u16 member;
145 	u16 untag;
146 	u8 fid : 4;
147 	u8 priority : 3;
148 	u8 priority_en : 1;
149 	u8 policing_en : 1;
150 	u8 ivl_en : 1;
151 	u8 meteridx : 6;
152 };
153 
154 /*
155  * struct rtl8365mb_vlanmc - VLAN membership config
156  * @evid: Enhanced VLAN ID (0~8191)
157  * @member: port mask of ports in this VLAN
158  * @fid: filter ID - only used with SVL (unused)
159  * @priority: priority classification (unused)
160  * @priority_en: enable priority (unused)
161  * @policing_en: enable policing (unused)
162  * @meteridx: metering index (unused)
163  *
164  * This structure is used to get/set entries in the VLAN membership
165  * configuration database. This feature is largely vestigial, but
166  * still needed for at least the following features:
167  *   - PVID configuration
168  *   - ACL configuration
169  *   - selection of VLAN by the CPU tag when VSEL=1, although the switch
170  *     can also select VLAN based on the VLAN tag if VSEL=0
171  *
172  * This is a low-level structure and it is recommended to interface with
173  * the VLAN membership config database via &struct rtl8365mb_vlanmc_entry.
174  */
175 struct rtl8365mb_vlanmc {
176 	u16 evid;
177 	u16 member;
178 	u8 fid : 4;
179 	u8 priority : 3;
180 	u8 priority_en : 1;
181 	u8 policing_en : 1;
182 	u8 meteridx : 6;
183 };
184 
185 static int rtl8365mb_vlan_4k_read(struct realtek_priv *priv, u16 vid,
186 				  struct rtl8365mb_vlan4k *vlan4k)
187 {
188 	u16 data[RTL8365MB_CVLAN_ENTRY_SIZE];
189 	int val;
190 	int ret;
191 
192 	ret = rtl8365mb_table_query(priv, RTL8365MB_TABLE_CVLAN,
193 				    RTL8365MB_TABLE_OP_READ, &vid, 0, 0,
194 				    data, ARRAY_SIZE(data));
195 	if (ret)
196 		return ret;
197 
198 	/* Unpack table entry */
199 	memset(vlan4k, 0, sizeof(*vlan4k));
200 	vlan4k->vid = vid;
201 
202 	val = FIELD_GET(RTL8365MB_CVLAN_ENTRY_D0_MBR_MASK, data[0]);
203 	vlan4k->member = FIELD_PREP(RTL8365MB_CVLAN_MBR_LO_MASK, val);
204 	val = FIELD_GET(RTL8365MB_CVLAN_ENTRY_D2_MBR_EXT_MASK, data[2]);
205 	vlan4k->member |= FIELD_PREP(RTL8365MB_CVLAN_MBR_HI_MASK, val);
206 
207 	val = FIELD_GET(RTL8365MB_CVLAN_ENTRY_D0_UNTAG_MASK, data[0]);
208 	vlan4k->untag = FIELD_PREP(RTL8365MB_CVLAN_UNTAG_LO_MASK, val);
209 	val = FIELD_GET(RTL8365MB_CVLAN_ENTRY_D2_UNTAG_EXT_MASK, data[2]);
210 	vlan4k->untag |= FIELD_PREP(RTL8365MB_CVLAN_UNTAG_HI_MASK, val);
211 
212 	vlan4k->fid = FIELD_GET(RTL8365MB_CVLAN_ENTRY_D1_FID_MASK, data[1]);
213 	vlan4k->priority_en =
214 		FIELD_GET(RTL8365MB_CVLAN_ENTRY_D1_VBPEN_MASK, data[1]);
215 	vlan4k->priority =
216 		FIELD_GET(RTL8365MB_CVLAN_ENTRY_D1_VBPRI_MASK, data[1]);
217 	vlan4k->policing_en =
218 		FIELD_GET(RTL8365MB_CVLAN_ENTRY_D1_ENVLANPOL_MASK, data[1]);
219 
220 	val = FIELD_GET(RTL8365MB_CVLAN_ENTRY_D1_METERIDX_MASK, data[1]);
221 	val = FIELD_PREP(RTL8365MB_CVLAN_METERIDX_LO_MASK, val);
222 	vlan4k->meteridx = val;
223 	val = FIELD_GET(RTL8365MB_CVLAN_ENTRY_D2_METERIDX_EXT_MASK, data[2]);
224 	val = FIELD_PREP(RTL8365MB_CVLAN_METERIDX_HI_MASK, val);
225 	vlan4k->meteridx |= val;
226 
227 	vlan4k->ivl_en =
228 		FIELD_GET(RTL8365MB_CVLAN_ENTRY_D1_IVL_SVL_MASK, data[1]);
229 
230 	return 0;
231 }
232 
233 static int rtl8365mb_vlan_4k_write(struct realtek_priv *priv,
234 				   const struct rtl8365mb_vlan4k *vlan4k)
235 {
236 	u16 data[RTL8365MB_CVLAN_ENTRY_SIZE] = { 0 };
237 	u16 vid;
238 	int val;
239 
240 	/* Pack table entry value */
241 	val = FIELD_GET(RTL8365MB_CVLAN_MBR_LO_MASK, vlan4k->member);
242 	data[0] |= FIELD_PREP(RTL8365MB_CVLAN_ENTRY_D0_MBR_MASK, val);
243 
244 	val = FIELD_GET(RTL8365MB_CVLAN_UNTAG_LO_MASK, vlan4k->untag);
245 	data[0] |= FIELD_PREP(RTL8365MB_CVLAN_ENTRY_D0_UNTAG_MASK, val);
246 
247 	data[1] |= FIELD_PREP(RTL8365MB_CVLAN_ENTRY_D1_FID_MASK, vlan4k->fid);
248 	data[1] |= FIELD_PREP(RTL8365MB_CVLAN_ENTRY_D1_VBPEN_MASK,
249 			      vlan4k->priority_en);
250 	data[1] |= FIELD_PREP(RTL8365MB_CVLAN_ENTRY_D1_VBPRI_MASK,
251 			      vlan4k->priority);
252 	data[1] |= FIELD_PREP(RTL8365MB_CVLAN_ENTRY_D1_ENVLANPOL_MASK,
253 			      vlan4k->policing_en);
254 
255 	/* FIELD_* does not play nice with struct bitfield. */
256 	val = vlan4k->meteridx;
257 	val = FIELD_GET(RTL8365MB_CVLAN_METERIDX_LO_MASK, val);
258 	data[1] |= FIELD_PREP(RTL8365MB_CVLAN_ENTRY_D1_METERIDX_MASK, val);
259 
260 	data[1] |= FIELD_PREP(RTL8365MB_CVLAN_ENTRY_D1_IVL_SVL_MASK,
261 			      vlan4k->ivl_en);
262 
263 	val = FIELD_GET(RTL8365MB_CVLAN_MBR_HI_MASK, vlan4k->member);
264 	data[2] |= FIELD_PREP(RTL8365MB_CVLAN_ENTRY_D2_MBR_EXT_MASK, val);
265 
266 	val = FIELD_GET(RTL8365MB_CVLAN_UNTAG_HI_MASK, vlan4k->untag);
267 	data[2] |= FIELD_PREP(RTL8365MB_CVLAN_ENTRY_D2_UNTAG_EXT_MASK, val);
268 
269 	val = vlan4k->meteridx;
270 	val = FIELD_GET(RTL8365MB_CVLAN_METERIDX_HI_MASK, val);
271 	data[2] |= FIELD_PREP(RTL8365MB_CVLAN_ENTRY_D2_METERIDX_EXT_MASK, val);
272 
273 	vid = vlan4k->vid;
274 	return rtl8365mb_table_query(priv, RTL8365MB_TABLE_CVLAN,
275 				     RTL8365MB_TABLE_OP_WRITE, &vid, 0, 0,
276 				     data, ARRAY_SIZE(data));
277 }
278 
279 static int
280 rtl8365mb_vlan_4k_port_set(struct dsa_switch *ds, int port,
281 			   const struct switchdev_obj_port_vlan *vlan,
282 			   struct netlink_ext_ack *extack,
283 			   bool include)
284 {
285 	struct realtek_priv *priv = ds->priv;
286 	struct rtl8365mb_vlan4k vlan4k = {0};
287 	int ret;
288 
289 	dev_dbg(priv->dev, "%s VLAN %d 4K on port %d\n",
290 		include ? "add" : "del",
291 		vlan->vid, port);
292 
293 	if (vlan->vid > RTL8365MB_MAX_4K_VID) {
294 		NL_SET_ERR_MSG_MOD(extack, "VLAN ID greater than "
295 				   __stringify(RTL8365MB_MAX_4K_VID));
296 		return -EINVAL;
297 	}
298 
299 	ret = rtl8365mb_vlan_4k_read(priv, vlan->vid, &vlan4k);
300 	if (ret) {
301 		dev_err(priv->dev, "Failed to read VLAN 4k table\n");
302 		return ret;
303 	}
304 
305 	if (include)
306 		vlan4k.member |= BIT(port);
307 	else
308 		vlan4k.member &= ~BIT(port);
309 
310 	if (include && (vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED))
311 		vlan4k.untag |= BIT(port);
312 	else
313 		vlan4k.untag &= ~BIT(port);
314 	vlan4k.ivl_en = true; /* always use Independent VLAN Learning */
315 
316 	ret = rtl8365mb_vlan_4k_write(priv, &vlan4k);
317 	if (ret) {
318 		dev_err(priv->dev, "Failed to write VLAN 4k table\n");
319 		return ret;
320 	}
321 
322 	return 0;
323 }
324 
325 /*
326  * rtl8365mb_vlan_4k_port_add() - Add a port to a VLAN 4K table entry
327  * @ds: dsa switch instance
328  * @port: port index
329  * @vlan: switchdev VLAN object containing the target VID and flags
330  * @extack: netlink extended ACK for error reporting
331  *
332  * Adds the specified port to the hardware VLAN 4K membership table.
333  *
334  * Context: Can sleep. Must be called with &priv->vlan_lock held.
335  * Takes and releases &priv->map_lock.
336  * Return: 0 on success, or a negative error code on failure.
337  */
338 int rtl8365mb_vlan_4k_port_add(struct dsa_switch *ds, int port,
339 			       const struct switchdev_obj_port_vlan *vlan,
340 			       struct netlink_ext_ack *extack)
341 {
342 	struct realtek_priv *priv = ds->priv;
343 
344 	lockdep_assert_held(&priv->vlan_lock);
345 
346 	return rtl8365mb_vlan_4k_port_set(ds, port, vlan, extack, true);
347 }
348 
349 /*
350  * rtl8365mb_vlan_4k_port_del() - Remove a port from a VLAN 4K table entry
351  * @ds: dsa switch instance
352  * @port: port index
353  * @vlan: switchdev VLAN object containing the target VID
354  *
355  * Removes the specified port from the hardware VLAN 4K membership table.
356  *
357  * Context: Can sleep. Must be called with &priv->vlan_lock held.
358  * Takes and releases &priv->map_lock.
359  * Return: 0 on success, or a negative error code on failure.
360  */
361 int rtl8365mb_vlan_4k_port_del(struct dsa_switch *ds, int port,
362 			       const struct switchdev_obj_port_vlan *vlan)
363 {
364 	struct realtek_priv *priv = ds->priv;
365 
366 	lockdep_assert_held(&priv->vlan_lock);
367 
368 	return rtl8365mb_vlan_4k_port_set(ds, port, vlan, NULL, false);
369 }
370 
371 static int rtl8365mb_vlan_mc_read(struct realtek_priv *priv, u32 index,
372 				  struct rtl8365mb_vlanmc *vlanmc)
373 {
374 	u16 data[RTL8365MB_VLAN_MC_ENTRY_SIZE];
375 	int ret;
376 
377 	ret = regmap_bulk_read(priv->map, RTL8365MB_VLAN_MC_REG(index), &data,
378 			       RTL8365MB_VLAN_MC_ENTRY_SIZE);
379 	if (ret)
380 		return ret;
381 
382 	vlanmc->member = FIELD_GET(RTL8365MB_VLAN_MC_D0_MBR_MASK, data[0]);
383 	vlanmc->fid = FIELD_GET(RTL8365MB_VLAN_MC_D1_FID_MASK, data[1]);
384 	vlanmc->meteridx = FIELD_GET(RTL8365MB_VLAN_MC_D2_METERIDX_MASK,
385 				     data[2]);
386 	vlanmc->policing_en = FIELD_GET(RTL8365MB_VLAN_MC_D2_ENVLANPOL_MASK,
387 					data[2]);
388 	vlanmc->priority = FIELD_GET(RTL8365MB_VLAN_MC_D2_VBPRI_MASK, data[2]);
389 	vlanmc->priority_en = FIELD_GET(RTL8365MB_VLAN_MC_D2_VBPEN_MASK,
390 					data[2]);
391 	vlanmc->evid = FIELD_GET(RTL8365MB_VLAN_MC_D3_EVID_MASK, data[3]);
392 
393 	return 0;
394 }
395 
396 static int rtl8365mb_vlan_mc_write(struct realtek_priv *priv, u32 index,
397 				   const struct rtl8365mb_vlanmc *vlanmc)
398 {
399 	u16 data[RTL8365MB_VLAN_MC_ENTRY_SIZE] = { 0 };
400 	int ret;
401 
402 	data[0] |= FIELD_PREP(RTL8365MB_VLAN_MC_D0_MBR_MASK, vlanmc->member);
403 	data[1] |= FIELD_PREP(RTL8365MB_VLAN_MC_D1_FID_MASK, vlanmc->fid);
404 	data[2] |= FIELD_PREP(RTL8365MB_VLAN_MC_D2_METERIDX_MASK,
405 			      vlanmc->meteridx);
406 	data[2] |= FIELD_PREP(RTL8365MB_VLAN_MC_D2_ENVLANPOL_MASK,
407 			      vlanmc->policing_en);
408 	data[2] |=
409 		FIELD_PREP(RTL8365MB_VLAN_MC_D2_VBPRI_MASK, vlanmc->priority);
410 	data[2] |= FIELD_PREP(RTL8365MB_VLAN_MC_D2_VBPEN_MASK,
411 			      vlanmc->priority_en);
412 	data[3] |= FIELD_PREP(RTL8365MB_VLAN_MC_D3_EVID_MASK, vlanmc->evid);
413 
414 	ret = regmap_bulk_write(priv->map, RTL8365MB_VLAN_MC_REG(index), &data,
415 				RTL8365MB_VLAN_MC_ENTRY_SIZE);
416 
417 	return ret;
418 }
419 
420 static int rtl8365mb_vlan_mc_erase(struct realtek_priv *priv, u32 index)
421 {
422 	u16 data[RTL8365MB_VLAN_MC_ENTRY_SIZE] = { 0 };
423 	int ret;
424 
425 	ret = regmap_bulk_write(priv->map, RTL8365MB_VLAN_MC_REG(index), &data,
426 				RTL8365MB_VLAN_MC_ENTRY_SIZE);
427 
428 	return ret;
429 }
430 
431 /*
432  * rtl8365mb_vlan_mc_find() - find VLANMC index by VID or the first free index
433  *
434  * @priv: realtek_priv pointer
435  * @vid: VLAN ID
436  * @index: found index
437  * @first_free: found free index
438  *
439  * If a VLAN MC entry using @vid was found, @index will return the matched index
440  * and @first_free is undefined. If not found, @index will return 0 and
441  * @first_free will return the first found free index in VLAN MC or 0 if the
442  * table is full.
443  *
444  * Although 0 is a valid VLAN MC index, it is reserved for ports without PVID,
445  * including standalone, non-member ports. It uses VID == 0.
446  *
447  * Both @index and @first_free will be in the * 1..@RTL8365MB_VLAN_MCMAX range.
448  *
449  * Return: Returns 0 on success, a negative error on failure.
450  */
451 static int rtl8365mb_vlan_mc_find(struct realtek_priv *priv, u16 vid,
452 				  u8 *index, u8 *first_free)
453 {
454 	u32 vlan_entry_d3;
455 	u8 vlanmc_idx;
456 	u16 evid;
457 	int ret;
458 
459 	*index = 0;
460 	*first_free = 0;
461 
462 	/* look for existing entry or an empty one */
463 	/* By design, VlanMC[0] is reserved as a neutral PVID value for
464 	 * standalone ports. It always has EVID == 0. That way, we assume that
465 	 * all entries after index 0 with VID == 0 are empty.
466 	 **/
467 	for (vlanmc_idx = 1; vlanmc_idx <= RTL8365MB_VLAN_MCMAX; vlanmc_idx++) {
468 		/* just read the 4th word, where the evid is */
469 		ret = regmap_read(priv->map,
470 				  RTL8365MB_VLAN_MC_REG(vlanmc_idx) + 3,
471 				  &vlan_entry_d3);
472 		if (ret)
473 			return ret;
474 
475 		evid = FIELD_GET(RTL8365MB_VLAN_MC_D3_EVID_MASK, vlan_entry_d3);
476 
477 		if (evid == vid) {
478 			*index = vlanmc_idx;
479 			return 0;
480 		}
481 
482 		if (evid == 0x0 && *first_free < 1)
483 			*first_free = vlanmc_idx;
484 	}
485 	return 0;
486 }
487 
488 static int rtl8365mb_vlan_port_get_pvid_idx(struct realtek_priv *priv,
489 					    int port, u8 *vlanmc_idx)
490 {
491 	u32 data;
492 	int ret;
493 
494 	ret = regmap_read(priv->map, RTL8365MB_VLAN_PVID_CTRL_REG(port), &data);
495 	if (ret)
496 		return ret;
497 
498 	*vlanmc_idx = (data & RTL8365MB_VLAN_PVID_CTRL_PORT_MCIDX_MASK(port))
499 		      >> RTL8365MB_VLAN_PVID_CTRL_PORT_MCIDX_OFFSET(port);
500 
501 	return 0;
502 }
503 
504 /*
505  * rtl8365mb_vlan_mc_port_set() - include or exclude a port from VlanMC
506  * @ds: dsa switch
507  * @port: the port number
508  * @vid: the vlan VID to include/exclude @port
509  * @pvid: inform if vid is used as pvid in @port
510  * @extack: optional extack to return errors
511  * @include: whether to include or exclude @port
512  *
513  * This function is used to include/exclude ports to the VlanMC table.
514  *
515  * VlanMC stands for VLAN membership config and it is used exclusively for
516  * PVID. If @vlan members are not using PVID, this function will either
517  * remove or not create a new VlanMC entry.
518  *
519  * VlanMC members are used as a reference port map, cleaning the entry once
520  * no port is using it.
521  *
522  * Port PVID and accepted frame type are updated as well.
523  *
524  * Context: Can sleep. Must be called with &priv->vlan_lock held.
525  * Takes and releases &priv->map_lock.
526  * Return: Returns 0 on success, a negative error on failure.
527  */
528 static
529 int rtl8365mb_vlan_mc_port_set(struct dsa_switch *ds, int port,
530 			       u16 vid, bool pvid,
531 			       struct netlink_ext_ack *extack,
532 			       bool include)
533 {
534 	struct realtek_priv *priv = ds->priv;
535 	struct rtl8365mb_vlanmc vlanmc = {0};
536 	u8 first_unused = 0;
537 	u8 vlanmc_idx = 0;
538 	int ret;
539 
540 	dev_dbg(priv->dev, "%s VLAN %d MC on port %d\n",
541 		include ? "add" : "del",
542 		vid, port);
543 
544 	if (vid > RTL8365MB_MAX_MC_VID) {
545 		NL_SET_ERR_MSG_MOD(extack, "VLAN ID greater than "
546 				   __stringify(RTL8365MB_MAX_MC_VID));
547 		return -EINVAL;
548 	}
549 
550 	/* look for existing entry or an empty slot */
551 	ret = rtl8365mb_vlan_mc_find(priv, vid, &vlanmc_idx,
552 				     &first_unused);
553 	if (ret) {
554 		dev_err(priv->dev, "Failed to find a VLAN MC table index\n");
555 		return ret;
556 	}
557 
558 	if (vlanmc_idx) {
559 		ret = rtl8365mb_vlan_mc_read(priv, vlanmc_idx, &vlanmc);
560 		if (ret) {
561 			dev_err(priv->dev, "Failed to read VLAN MC table\n");
562 			return ret;
563 		}
564 	} else if (include) {
565 		/* for now, vlan_mc is only required for PVID. Defer allocation
566 		 * until at least one port uses PVID.
567 		 */
568 		if (!pvid) {
569 			dev_dbg(priv->dev,
570 				"Not creating VlanMC for vlan %d until a port uses PVID (%d does not)\n",
571 				vid, port);
572 			return 0;
573 		}
574 
575 		if (!first_unused) {
576 			NL_SET_ERR_MSG_MOD(extack, "All VLAN MC entries (0.."
577 					   __stringify(RTL8365MB_VLAN_MCMAX)
578 					   ") are in use.");
579 			return -ENOSPC;
580 		}
581 
582 		vlanmc_idx = first_unused;
583 		vlanmc.evid = vid;
584 
585 	} else /* excluding and VLANMC not found */ {
586 		return 0;
587 	}
588 
589 	dev_dbg(priv->dev,
590 		"VLAN %d (idx: %d) PVID curr members: %08x\n",
591 		vid, vlanmc_idx, vlanmc.member);
592 
593 	/* here we either have an existing VLANMC (with PVID members) or the
594 	 * added port is using this VLAN as PVID
595 	 */
596 	if (include)
597 		vlanmc.member |= BIT(port);
598 	else
599 		vlanmc.member &= ~BIT(port);
600 
601 	/* just like we don't need to create a VLAN_MC when there is no port
602 	 * using it as PVID, we can erase it when there is no more port using
603 	 * it as PVID.
604 	 */
605 	if (!vlanmc.member) {
606 		dev_dbg(priv->dev,
607 			"Clearing VlanMC index %d previously used by VID %d\n",
608 			vlanmc_idx, vid);
609 		ret = rtl8365mb_vlan_mc_erase(priv, vlanmc_idx);
610 	} else {
611 		dev_dbg(priv->dev,
612 			"Saving VlanMC index %d with VID %d\n",
613 			vlanmc_idx, vid);
614 		ret = rtl8365mb_vlan_mc_write(priv, vlanmc_idx, &vlanmc);
615 	}
616 	if (ret) {
617 		dev_err(priv->dev, "Failed to write vlan MC entry\n");
618 		return ret;
619 	}
620 
621 	return 0;
622 }
623 
624 static int rtl8365mb_vlan_port_set_pvid(struct realtek_priv *priv,
625 					int port, u16 vlanmc_idx)
626 {
627 	int ret;
628 	u32 val;
629 
630 	dev_dbg(priv->dev, "set PVID IDX %d on port %d\n", vlanmc_idx, port);
631 
632 	val = vlanmc_idx << RTL8365MB_VLAN_PVID_CTRL_PORT_MCIDX_OFFSET(port);
633 	ret = regmap_update_bits(priv->map,
634 				 RTL8365MB_VLAN_PVID_CTRL_REG(port),
635 				 RTL8365MB_VLAN_PVID_CTRL_PORT_MCIDX_MASK(port),
636 				 val);
637 	if (ret)
638 		return ret;
639 
640 	return 0;
641 }
642 
643 static int rtl8365mb_vlan_get_pvid_mc(struct realtek_priv *priv,
644 				      int port, u8 *vlanmc_idx,
645 				      struct rtl8365mb_vlanmc *vlanmc)
646 {
647 	int ret;
648 
649 	ret = rtl8365mb_vlan_port_get_pvid_idx(priv, port, vlanmc_idx);
650 	if (ret)
651 		return ret;
652 
653 	memset(vlanmc, 0, sizeof(*vlanmc));
654 
655 	if (!*vlanmc_idx)
656 		return 0;
657 
658 	ret = rtl8365mb_vlan_mc_read(priv, *vlanmc_idx, vlanmc);
659 	if (ret)
660 		return ret;
661 
662 	return 0;
663 }
664 
665 /*
666  * rtl8365mb_vlan_port_get_pvid - Retrieve the port PVID
667  * @priv: realtek switch private structure
668  * @port: port index
669  * @pvid: pointer to store the retrieved VLAN ID
670  *
671  * Returns the port PVID if defined or 0 if not.
672  *
673  * Context: Can sleep. Takes and releases &priv->map_lock.
674  * Return: 0 on success or a negative error code on failure.
675  */
676 int rtl8365mb_vlan_port_get_pvid(struct realtek_priv *priv, int port, u16 *pvid)
677 {
678 	struct rtl8365mb_vlanmc vlanmc;
679 	u8 vlanmc_idx;
680 	int ret;
681 
682 	ret = rtl8365mb_vlan_get_pvid_mc(priv, port, &vlanmc_idx, &vlanmc);
683 	if (ret)
684 		return ret;
685 
686 	*pvid = vlanmc.evid;
687 	return 0;
688 }
689 
690 /*
691  * rtl8365mb_vlan_port_get_framefilter() - Get the ingress frame filtering mode
692  * for a port
693  * @priv: realtek switch private structure
694  * @port: port index
695  * @frame_type: pointer to store the retrieved ingress frame filter type
696  *
697  * Context: Can sleep. Takes and releases &priv->map_lock.
698  * Return: 0 on success, or a negative error code on failure.
699  */
700 int
701 rtl8365mb_vlan_port_get_framefilter(struct realtek_priv *priv,
702 				    int port,
703 				    enum rtl8365mb_frame_ingress *frame_type)
704 {
705 	u32 val;
706 	int ret;
707 
708 	/* Even if ACCEPT_FRAME_TYPE_ANY, the switch will still check if the
709 	 * port is a member of vlan PVID
710 	 */
711 
712 	ret = regmap_read(priv->map, RTL8365MB_VLAN_ACCEPT_FRAME_TYPE_REG(port),
713 			  &val);
714 	if (ret)
715 		return ret;
716 
717 	*frame_type = field_get(RTL8365MB_VLAN_ACCEPT_FRAME_TYPE_MASK(port),
718 				val);
719 
720 	return 0;
721 }
722 
723 /*
724  * rtl8365mb_vlan_port_set_framefilter() - Set the ingress frame filtering mode
725  * for a port
726  * @priv: realtek switch private structure
727  * @port: port index
728  * @frame_type: the ingress frame filter type to configure
729  *
730  * Context: Can sleep. Takes and releases &priv->map_lock.
731  * Return: 0 on success, or a negative error code on failure.
732  */
733 int
734 rtl8365mb_vlan_port_set_framefilter(struct realtek_priv *priv,
735 				    int port,
736 				    enum rtl8365mb_frame_ingress frame_type)
737 {
738 	u32 val;
739 
740 	/* Even if ACCEPT_FRAME_TYPE_ANY, the switch will still check if the
741 	 * port is a member of vlan PVID
742 	 */
743 	val = frame_type << RTL8365MB_VLAN_ACCEPT_FRAME_TYPE_OFFSET(port);
744 
745 	return regmap_update_bits(priv->map,
746 				  RTL8365MB_VLAN_ACCEPT_FRAME_TYPE_REG(port),
747 				  RTL8365MB_VLAN_ACCEPT_FRAME_TYPE_MASK(port),
748 				  val);
749 }
750 
751 /*
752  * rtl8365mb_vlan_pvid_port_set() - Configure a port's PVID and associated
753  * VLANMC entry
754  * @ds: dsa switch instance
755  * @port: port index
756  * @vid: target VID
757  * @extack: netlink extended ACK for error reporting
758  *
759  * Allocates or reuses a hardware VLANMC entry to map the given port to its new
760  * PVID. Gracefully unwinds and restores previous configuration if a hardware
761  * write operation fails during execution.
762  *
763  * Context: Can sleep. Must be called with &priv->vlan_lock held.
764  * Takes and releases &priv->map_lock.
765  * Return: 0 on success, or a negative error code on failure.
766  */
767 int rtl8365mb_vlan_pvid_port_set(struct dsa_switch *ds, int port, u16 vid,
768 				 struct netlink_ext_ack *extack)
769 {
770 	enum rtl8365mb_frame_ingress accepted_frame, prev_accepted_frame;
771 	struct realtek_priv *priv = ds->priv;
772 	struct rtl8365mb_vlanmc prev_vlanmc = {0};
773 	u8 _unused_first_free_idx;
774 	u8 prev_vlanmc_idx;
775 	u8 vlanmc_idx;
776 	int ret;
777 
778 	lockdep_assert_held(&priv->vlan_lock);
779 
780 	/* Read the old PVID exclusively to undo in case of error */
781 	ret = rtl8365mb_vlan_get_pvid_mc(priv, port, &prev_vlanmc_idx,
782 					 &prev_vlanmc);
783 	if (ret) {
784 		dev_err(priv->dev, "Failed to read current VLAN MC\n");
785 		return ret;
786 	}
787 
788 	ret = rtl8365mb_vlan_port_get_framefilter(priv, port,
789 						  &prev_accepted_frame);
790 	if (ret) {
791 		dev_err(priv->dev, "Failed to get current framefilter\n");
792 		return ret;
793 	}
794 
795 	/* Find or allocate a new vlan MC and add port to members,
796 	 * although members are not checked by the HW in vlan MC.
797 	 */
798 	ret = rtl8365mb_vlan_mc_port_set(ds, port, vid, true, extack, true);
799 	if (ret)
800 		return ret;
801 
802 	/* look for existing entry */
803 	ret = rtl8365mb_vlan_mc_find(priv, vid, &vlanmc_idx,
804 				     &_unused_first_free_idx);
805 	if (ret) {
806 		dev_err(priv->dev, "Failed to find a VLAN MC table index\n");
807 		goto undo_vlan_mc_port_set;
808 	}
809 
810 	if (!vlanmc_idx) {
811 		dev_err(priv->dev, "VLAN should already exist in VLAN MC\n");
812 		ret = -ENOENT;
813 		goto undo_vlan_mc_port_set;
814 	}
815 
816 	ret = rtl8365mb_vlan_port_set_pvid(priv, port, vlanmc_idx);
817 	if (ret) {
818 		dev_err(priv->dev, "Failed to set port PVID\n");
819 		goto undo_vlan_mc_port_set;
820 	}
821 
822 	/* Changing accept frame is what enables PVID (if not enabled before) */
823 	accepted_frame = RTL8365MB_FRAME_TYPE_ANY_FRAME;
824 	ret = rtl8365mb_vlan_port_set_framefilter(priv, port, accepted_frame);
825 	if (ret) {
826 		dev_err(priv->dev, "Failed to set port frame filter\n");
827 		goto undo_vlan_port_set_pvid;
828 	}
829 
830 	/* A VLAN can be added with PVID without removing from the old
831 	 * PVID VLAN. Clear PVID from the old VLAN MC (if needed).
832 	 */
833 	if (prev_vlanmc_idx && (prev_vlanmc.evid != vid)) {
834 		ret = rtl8365mb_vlan_mc_port_set(ds, port, prev_vlanmc.evid,
835 						 false, NULL, false);
836 		if (ret) {
837 			dev_err(priv->dev, "Failed to clear old VLAN MC\n");
838 			goto undo_set_framefilter;
839 		}
840 	}
841 
842 	return 0;
843 
844 undo_set_framefilter:
845 	(void)rtl8365mb_vlan_port_set_framefilter(priv, port,
846 						  prev_accepted_frame);
847 
848 undo_vlan_port_set_pvid:
849 	(void)rtl8365mb_vlan_port_set_pvid(priv, port, prev_vlanmc_idx);
850 
851 undo_vlan_mc_port_set:
852 	if (prev_vlanmc.evid != vid)
853 		(void)rtl8365mb_vlan_mc_port_set(ds, port, vid, false, NULL,
854 						 false);
855 
856 	return ret;
857 }
858 
859 /*
860  * rtl8365mb_vlan_pvid_port_clear() - Remove a port's PVID configuration
861  * @ds: dsa switch instance
862  * @port: port index
863  * @vid:  VLAN VID for PVID
864  *
865  * Resets the target port's hardware PVID allocation to 0. Cleans up and frees
866  * the associated VLANMC entry if no other ports are referencing it.
867  *
868  * Context: Can sleep. Must be called with &priv->vlan_lock held.
869  * Takes and releases &priv->map_lock.
870  * Return: 0 on success, or a negative error code on failure.
871  */
872 int rtl8365mb_vlan_pvid_port_clear(struct dsa_switch *ds, int port, u16 vid)
873 {
874 	enum rtl8365mb_frame_ingress accepted_frame, prev_accepted_frame;
875 	struct realtek_priv *priv = ds->priv;
876 	struct rtl8365mb_vlanmc vlanmc = {0};
877 	u8 vlanmc_idx;
878 	int ret;
879 
880 	lockdep_assert_held(&priv->vlan_lock);
881 
882 	ret = rtl8365mb_vlan_get_pvid_mc(priv, port, &vlanmc_idx,
883 					 &vlanmc);
884 	if (ret) {
885 		dev_err(priv->dev, "Failed to read current VLAN MC\n");
886 		return ret;
887 	}
888 
889 	/* Port is not using PVID. Nothing to remove. */
890 	if (!vlanmc_idx)
891 		return 0;
892 
893 	/* We are leaving a non PVID vlan, Nothing to remove. */
894 	if (vlanmc.evid != vid)
895 		return 0;
896 
897 	ret = rtl8365mb_vlan_port_get_framefilter(priv, port,
898 						  &prev_accepted_frame);
899 	if (ret) {
900 		dev_err(priv->dev, "Failed to get current framefilter\n");
901 		return ret;
902 	}
903 
904 	/* Changing accept frame is what really removes PVID. But only do
905 	 * that if we are filtering vlan
906 	 */
907 	if (dsa_port_is_vlan_filtering(dsa_to_port(ds, port))) {
908 		accepted_frame = RTL8365MB_FRAME_TYPE_TAGGED_ONLY;
909 
910 		ret = rtl8365mb_vlan_port_set_framefilter(priv, port,
911 							  accepted_frame);
912 		if (ret) {
913 			dev_err(priv->dev, "Failed to set port frame filter\n");
914 			return ret;
915 		}
916 	} else {
917 		/* skip undo_set_framefilter */
918 		accepted_frame = prev_accepted_frame;
919 	}
920 
921 	ret = rtl8365mb_vlan_port_set_pvid(priv, port, 0);
922 	if (ret) {
923 		dev_err(priv->dev, "Failed to set port PVID to 0\n");
924 		goto undo_set_framefilter;
925 	}
926 
927 	/* Clears the VLAN MC membership and maybe VLAN MC entry if empty */
928 	ret = rtl8365mb_vlan_mc_port_set(ds, port, vlanmc.evid,
929 					 false, NULL, false);
930 	if (ret)
931 		goto undo_port_set_pvid;
932 
933 	return 0;
934 
935 undo_port_set_pvid:
936 	(void)rtl8365mb_vlan_port_set_pvid(priv, port, vlanmc_idx);
937 
938 undo_set_framefilter:
939 	if (prev_accepted_frame != accepted_frame)
940 		(void)rtl8365mb_vlan_port_set_framefilter(priv, port,
941 							  prev_accepted_frame);
942 
943 	return ret;
944 }
945