• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
lan966x_vlan_get_status(struct lan966x * lan966x)10 static int lan966x_vlan_get_status(struct lan966x *lan966x)
11 {
12 	return lan_rd(lan966x, ANA_VLANACCESS);
13 }
14 
lan966x_vlan_wait_for_completion(struct lan966x * lan966x)15 static 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 
lan966x_vlan_set_mask(struct lan966x * lan966x,u16 vid)26 static 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 
lan966x_vlan_port_add_vlan_mask(struct lan966x_port * port,u16 vid)54 static 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 
lan966x_vlan_port_del_vlan_mask(struct lan966x_port * port,u16 vid)63 static 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 
lan966x_vlan_port_any_vlan_mask(struct lan966x * lan966x,u16 vid)72 static bool lan966x_vlan_port_any_vlan_mask(struct lan966x *lan966x, u16 vid)
73 {
74 	return !!(lan966x->vlan_mask[vid] & ~BIT(CPU_PORT));
75 }
76 
lan966x_vlan_cpu_add_vlan_mask(struct lan966x * lan966x,u16 vid)77 static 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 
lan966x_vlan_cpu_del_vlan_mask(struct lan966x * lan966x,u16 vid)83 static 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 
lan966x_vlan_cpu_add_cpu_vlan_mask(struct lan966x * lan966x,u16 vid)89 static void lan966x_vlan_cpu_add_cpu_vlan_mask(struct lan966x *lan966x, u16 vid)
90 {
91 	__set_bit(vid, lan966x->cpu_vlan_mask);
92 }
93 
lan966x_vlan_cpu_del_cpu_vlan_mask(struct lan966x * lan966x,u16 vid)94 static void lan966x_vlan_cpu_del_cpu_vlan_mask(struct lan966x *lan966x, u16 vid)
95 {
96 	__clear_bit(vid, lan966x->cpu_vlan_mask);
97 }
98 
lan966x_vlan_cpu_member_cpu_vlan_mask(struct lan966x * lan966x,u16 vid)99 bool lan966x_vlan_cpu_member_cpu_vlan_mask(struct lan966x *lan966x, u16 vid)
100 {
101 	return test_bit(vid, lan966x->cpu_vlan_mask);
102 }
103 
lan966x_vlan_port_get_pvid(struct lan966x_port * port)104 static 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 
lan966x_vlan_port_set_vid(struct lan966x_port * port,u16 vid,bool pvid,bool untagged)114 int 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 
lan966x_vlan_port_remove_vid(struct lan966x_port * port,u16 vid)137 static 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 
lan966x_vlan_port_set_vlan_aware(struct lan966x_port * port,bool vlan_aware)146 void lan966x_vlan_port_set_vlan_aware(struct lan966x_port *port,
147 				      bool vlan_aware)
148 {
149 	port->vlan_aware = vlan_aware;
150 }
151 
lan966x_vlan_port_apply(struct lan966x_port * port)152 void 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 
lan966x_vlan_port_add_vlan(struct lan966x_port * port,u16 vid,bool pvid,bool untagged)213 void 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 
lan966x_vlan_port_del_vlan(struct lan966x_port * port,u16 vid)236 void 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 
lan966x_vlan_cpu_add_vlan(struct lan966x * lan966x,u16 vid)255 void 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 
lan966x_vlan_cpu_del_vlan(struct lan966x * lan966x,u16 vid)274 void 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 
lan966x_vlan_init(struct lan966x * lan966x)283 void 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