1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
3 
4 #include <linux/kernel.h>
5 #include <linux/bitops.h>
6 #include <linux/if_vlan.h>
7 #include <linux/if_bridge.h>
8 #include <linux/netdevice.h>
9 #include <linux/rtnetlink.h>
10 
11 #include "spectrum.h"
12 #include "reg.h"
13 
14 struct mlxsw_sp_fid_family;
15 
16 struct mlxsw_sp_fid_core {
17 	struct mlxsw_sp_fid_family *fid_family_arr[MLXSW_SP_FID_TYPE_MAX];
18 	unsigned int *port_fid_mappings;
19 };
20 
21 struct mlxsw_sp_fid {
22 	struct list_head list;
23 	struct mlxsw_sp_rif *rif;
24 	unsigned int ref_count;
25 	u16 fid_index;
26 	struct mlxsw_sp_fid_family *fid_family;
27 };
28 
29 struct mlxsw_sp_fid_8021q {
30 	struct mlxsw_sp_fid common;
31 	u16 vid;
32 };
33 
34 struct mlxsw_sp_fid_8021d {
35 	struct mlxsw_sp_fid common;
36 	int br_ifindex;
37 };
38 
39 struct mlxsw_sp_flood_table {
40 	enum mlxsw_sp_flood_type packet_type;
41 	enum mlxsw_reg_sfgc_bridge_type bridge_type;
42 	enum mlxsw_flood_table_type table_type;
43 	int table_index;
44 };
45 
46 struct mlxsw_sp_fid_ops {
47 	void (*setup)(struct mlxsw_sp_fid *fid, const void *arg);
48 	int (*configure)(struct mlxsw_sp_fid *fid);
49 	void (*deconfigure)(struct mlxsw_sp_fid *fid);
50 	int (*index_alloc)(struct mlxsw_sp_fid *fid, const void *arg,
51 			   u16 *p_fid_index);
52 	bool (*compare)(const struct mlxsw_sp_fid *fid,
53 			const void *arg);
54 	u16 (*flood_index)(const struct mlxsw_sp_fid *fid);
55 	int (*port_vid_map)(struct mlxsw_sp_fid *fid,
56 			    struct mlxsw_sp_port *port, u16 vid);
57 	void (*port_vid_unmap)(struct mlxsw_sp_fid *fid,
58 			       struct mlxsw_sp_port *port, u16 vid);
59 };
60 
61 struct mlxsw_sp_fid_family {
62 	enum mlxsw_sp_fid_type type;
63 	size_t fid_size;
64 	u16 start_index;
65 	u16 end_index;
66 	struct list_head fids_list;
67 	unsigned long *fids_bitmap;
68 	const struct mlxsw_sp_flood_table *flood_tables;
69 	int nr_flood_tables;
70 	enum mlxsw_sp_rif_type rif_type;
71 	const struct mlxsw_sp_fid_ops *ops;
72 	struct mlxsw_sp *mlxsw_sp;
73 };
74 
75 static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
76 	[MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST]			= 1,
77 };
78 
79 static const int mlxsw_sp_sfgc_bc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
80 	[MLXSW_REG_SFGC_TYPE_BROADCAST]				= 1,
81 	[MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP]	= 1,
82 	[MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL]			= 1,
83 	[MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST]			= 1,
84 	[MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6]	= 1,
85 };
86 
87 static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
88 	[MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4]	= 1,
89 };
90 
91 static const int *mlxsw_sp_packet_type_sfgc_types[] = {
92 	[MLXSW_SP_FLOOD_TYPE_UC]	= mlxsw_sp_sfgc_uc_packet_types,
93 	[MLXSW_SP_FLOOD_TYPE_BC]	= mlxsw_sp_sfgc_bc_packet_types,
94 	[MLXSW_SP_FLOOD_TYPE_MC]	= mlxsw_sp_sfgc_mc_packet_types,
95 };
96 
97 static const struct mlxsw_sp_flood_table *
98 mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid,
99 				enum mlxsw_sp_flood_type packet_type)
100 {
101 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
102 	int i;
103 
104 	for (i = 0; i < fid_family->nr_flood_tables; i++) {
105 		if (fid_family->flood_tables[i].packet_type != packet_type)
106 			continue;
107 		return &fid_family->flood_tables[i];
108 	}
109 
110 	return NULL;
111 }
112 
113 int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid,
114 			   enum mlxsw_sp_flood_type packet_type, u8 local_port,
115 			   bool member)
116 {
117 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
118 	const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
119 	const struct mlxsw_sp_flood_table *flood_table;
120 	char *sftr_pl;
121 	int err;
122 
123 	if (WARN_ON(!fid_family->flood_tables || !ops->flood_index))
124 		return -EINVAL;
125 
126 	flood_table = mlxsw_sp_fid_flood_table_lookup(fid, packet_type);
127 	if (!flood_table)
128 		return -ESRCH;
129 
130 	sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL);
131 	if (!sftr_pl)
132 		return -ENOMEM;
133 
134 	mlxsw_reg_sftr_pack(sftr_pl, flood_table->table_index,
135 			    ops->flood_index(fid), flood_table->table_type, 1,
136 			    local_port, member);
137 	err = mlxsw_reg_write(fid_family->mlxsw_sp->core, MLXSW_REG(sftr),
138 			      sftr_pl);
139 	kfree(sftr_pl);
140 	return err;
141 }
142 
143 int mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid *fid,
144 			      struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
145 {
146 	if (WARN_ON(!fid->fid_family->ops->port_vid_map))
147 		return -EINVAL;
148 	return fid->fid_family->ops->port_vid_map(fid, mlxsw_sp_port, vid);
149 }
150 
151 void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid,
152 				 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
153 {
154 	fid->fid_family->ops->port_vid_unmap(fid, mlxsw_sp_port, vid);
155 }
156 
157 enum mlxsw_sp_rif_type mlxsw_sp_fid_rif_type(const struct mlxsw_sp_fid *fid)
158 {
159 	return fid->fid_family->rif_type;
160 }
161 
162 u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid)
163 {
164 	return fid->fid_index;
165 }
166 
167 enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid)
168 {
169 	return fid->fid_family->type;
170 }
171 
172 void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif)
173 {
174 	fid->rif = rif;
175 }
176 
177 enum mlxsw_sp_rif_type
178 mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp,
179 			   enum mlxsw_sp_fid_type type)
180 {
181 	struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
182 
183 	return fid_core->fid_family_arr[type]->rif_type;
184 }
185 
186 static struct mlxsw_sp_fid_8021q *
187 mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid)
188 {
189 	return container_of(fid, struct mlxsw_sp_fid_8021q, common);
190 }
191 
192 u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid)
193 {
194 	return mlxsw_sp_fid_8021q_fid(fid)->vid;
195 }
196 
197 static void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg)
198 {
199 	u16 vid = *(u16 *) arg;
200 
201 	mlxsw_sp_fid_8021q_fid(fid)->vid = vid;
202 }
203 
204 static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid)
205 {
206 	return valid ? MLXSW_REG_SFMR_OP_CREATE_FID :
207 		       MLXSW_REG_SFMR_OP_DESTROY_FID;
208 }
209 
210 static int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
211 			   u16 fid_offset, bool valid)
212 {
213 	char sfmr_pl[MLXSW_REG_SFMR_LEN];
214 
215 	mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid_index,
216 			    fid_offset);
217 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
218 }
219 
220 static int mlxsw_sp_fid_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
221 				u16 vid, bool valid)
222 {
223 	enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_VID_TO_FID;
224 	char svfa_pl[MLXSW_REG_SVFA_LEN];
225 
226 	mlxsw_reg_svfa_pack(svfa_pl, 0, mt, valid, fid_index, vid);
227 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
228 }
229 
230 static int __mlxsw_sp_fid_port_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
231 				       u8 local_port, u16 vid, bool valid)
232 {
233 	enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID;
234 	char svfa_pl[MLXSW_REG_SVFA_LEN];
235 
236 	mlxsw_reg_svfa_pack(svfa_pl, local_port, mt, valid, fid_index, vid);
237 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
238 }
239 
240 static int mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid *fid)
241 {
242 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
243 	struct mlxsw_sp_fid_8021q *fid_8021q;
244 	int err;
245 
246 	err = mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, fid->fid_index, true);
247 	if (err)
248 		return err;
249 
250 	fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
251 	err = mlxsw_sp_fid_vid_map(mlxsw_sp, fid->fid_index, fid_8021q->vid,
252 				   true);
253 	if (err)
254 		goto err_fid_map;
255 
256 	return 0;
257 
258 err_fid_map:
259 	mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, false);
260 	return err;
261 }
262 
263 static void mlxsw_sp_fid_8021q_deconfigure(struct mlxsw_sp_fid *fid)
264 {
265 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
266 	struct mlxsw_sp_fid_8021q *fid_8021q;
267 
268 	fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
269 	mlxsw_sp_fid_vid_map(mlxsw_sp, fid->fid_index, fid_8021q->vid, false);
270 	mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, false);
271 }
272 
273 static int mlxsw_sp_fid_8021q_index_alloc(struct mlxsw_sp_fid *fid,
274 					  const void *arg, u16 *p_fid_index)
275 {
276 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
277 	u16 vid = *(u16 *) arg;
278 
279 	/* Use 1:1 mapping for simplicity although not a must */
280 	if (vid < fid_family->start_index || vid > fid_family->end_index)
281 		return -EINVAL;
282 	*p_fid_index = vid;
283 
284 	return 0;
285 }
286 
287 static bool
288 mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg)
289 {
290 	u16 vid = *(u16 *) arg;
291 
292 	return mlxsw_sp_fid_8021q_fid(fid)->vid == vid;
293 }
294 
295 static u16 mlxsw_sp_fid_8021q_flood_index(const struct mlxsw_sp_fid *fid)
296 {
297 	return fid->fid_index;
298 }
299 
300 static int mlxsw_sp_fid_8021q_port_vid_map(struct mlxsw_sp_fid *fid,
301 					   struct mlxsw_sp_port *mlxsw_sp_port,
302 					   u16 vid)
303 {
304 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
305 	u8 local_port = mlxsw_sp_port->local_port;
306 
307 	/* In case there are no {Port, VID} => FID mappings on the port,
308 	 * we can use the global VID => FID mapping we created when the
309 	 * FID was configured.
310 	 */
311 	if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 0)
312 		return 0;
313 	return __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, local_port,
314 					   vid, true);
315 }
316 
317 static void
318 mlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid *fid,
319 				  struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
320 {
321 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
322 	u8 local_port = mlxsw_sp_port->local_port;
323 
324 	if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 0)
325 		return;
326 	__mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, local_port, vid,
327 				    false);
328 }
329 
330 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops = {
331 	.setup			= mlxsw_sp_fid_8021q_setup,
332 	.configure		= mlxsw_sp_fid_8021q_configure,
333 	.deconfigure		= mlxsw_sp_fid_8021q_deconfigure,
334 	.index_alloc		= mlxsw_sp_fid_8021q_index_alloc,
335 	.compare		= mlxsw_sp_fid_8021q_compare,
336 	.flood_index		= mlxsw_sp_fid_8021q_flood_index,
337 	.port_vid_map		= mlxsw_sp_fid_8021q_port_vid_map,
338 	.port_vid_unmap		= mlxsw_sp_fid_8021q_port_vid_unmap,
339 };
340 
341 static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021q_flood_tables[] = {
342 	{
343 		.packet_type	= MLXSW_SP_FLOOD_TYPE_UC,
344 		.bridge_type	= MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID,
345 		.table_type	= MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
346 		.table_index	= 0,
347 	},
348 	{
349 		.packet_type	= MLXSW_SP_FLOOD_TYPE_MC,
350 		.bridge_type	= MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID,
351 		.table_type	= MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
352 		.table_index	= 1,
353 	},
354 	{
355 		.packet_type	= MLXSW_SP_FLOOD_TYPE_BC,
356 		.bridge_type	= MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID,
357 		.table_type	= MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
358 		.table_index	= 2,
359 	},
360 };
361 
362 /* Range and flood configuration must match mlxsw_config_profile */
363 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021q_family = {
364 	.type			= MLXSW_SP_FID_TYPE_8021Q,
365 	.fid_size		= sizeof(struct mlxsw_sp_fid_8021q),
366 	.start_index		= 1,
367 	.end_index		= VLAN_VID_MASK,
368 	.flood_tables		= mlxsw_sp_fid_8021q_flood_tables,
369 	.nr_flood_tables	= ARRAY_SIZE(mlxsw_sp_fid_8021q_flood_tables),
370 	.rif_type		= MLXSW_SP_RIF_TYPE_VLAN,
371 	.ops			= &mlxsw_sp_fid_8021q_ops,
372 };
373 
374 static struct mlxsw_sp_fid_8021d *
375 mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid)
376 {
377 	return container_of(fid, struct mlxsw_sp_fid_8021d, common);
378 }
379 
380 static void mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg)
381 {
382 	int br_ifindex = *(int *) arg;
383 
384 	mlxsw_sp_fid_8021d_fid(fid)->br_ifindex = br_ifindex;
385 }
386 
387 static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid)
388 {
389 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
390 
391 	return mlxsw_sp_fid_op(fid_family->mlxsw_sp, fid->fid_index, 0, true);
392 }
393 
394 static void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid *fid)
395 {
396 	mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false);
397 }
398 
399 static int mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid *fid,
400 					  const void *arg, u16 *p_fid_index)
401 {
402 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
403 	u16 nr_fids, fid_index;
404 
405 	nr_fids = fid_family->end_index - fid_family->start_index + 1;
406 	fid_index = find_first_zero_bit(fid_family->fids_bitmap, nr_fids);
407 	if (fid_index == nr_fids)
408 		return -ENOBUFS;
409 	*p_fid_index = fid_family->start_index + fid_index;
410 
411 	return 0;
412 }
413 
414 static bool
415 mlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid *fid, const void *arg)
416 {
417 	int br_ifindex = *(int *) arg;
418 
419 	return mlxsw_sp_fid_8021d_fid(fid)->br_ifindex == br_ifindex;
420 }
421 
422 static u16 mlxsw_sp_fid_8021d_flood_index(const struct mlxsw_sp_fid *fid)
423 {
424 	return fid->fid_index - fid->fid_family->start_index;
425 }
426 
427 static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
428 {
429 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
430 	struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
431 	int err;
432 
433 	list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list,
434 			    list) {
435 		struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
436 		u16 vid = mlxsw_sp_port_vlan->vid;
437 
438 		if (!fid)
439 			continue;
440 
441 		err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
442 						  mlxsw_sp_port->local_port,
443 						  vid, true);
444 		if (err)
445 			goto err_fid_port_vid_map;
446 	}
447 
448 	err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true);
449 	if (err)
450 		goto err_port_vp_mode_set;
451 
452 	return 0;
453 
454 err_port_vp_mode_set:
455 err_fid_port_vid_map:
456 	list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan,
457 					     &mlxsw_sp_port->vlans_list, list) {
458 		struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
459 		u16 vid = mlxsw_sp_port_vlan->vid;
460 
461 		if (!fid)
462 			continue;
463 
464 		__mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
465 					    mlxsw_sp_port->local_port, vid,
466 					    false);
467 	}
468 	return err;
469 }
470 
471 static void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
472 {
473 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
474 	struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
475 
476 	mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
477 
478 	list_for_each_entry_reverse(mlxsw_sp_port_vlan,
479 				    &mlxsw_sp_port->vlans_list, list) {
480 		struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
481 		u16 vid = mlxsw_sp_port_vlan->vid;
482 
483 		if (!fid)
484 			continue;
485 
486 		__mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
487 					    mlxsw_sp_port->local_port, vid,
488 					    false);
489 	}
490 }
491 
492 static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid,
493 					   struct mlxsw_sp_port *mlxsw_sp_port,
494 					   u16 vid)
495 {
496 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
497 	u8 local_port = mlxsw_sp_port->local_port;
498 	int err;
499 
500 	err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
501 					  mlxsw_sp_port->local_port, vid, true);
502 	if (err)
503 		return err;
504 
505 	if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
506 		err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
507 		if (err)
508 			goto err_port_vp_mode_trans;
509 	}
510 
511 	return 0;
512 
513 err_port_vp_mode_trans:
514 	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
515 	__mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
516 				    mlxsw_sp_port->local_port, vid, false);
517 	return err;
518 }
519 
520 static void
521 mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid,
522 				  struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
523 {
524 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
525 	u8 local_port = mlxsw_sp_port->local_port;
526 
527 	if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
528 		mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
529 	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
530 	__mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
531 				    mlxsw_sp_port->local_port, vid, false);
532 }
533 
534 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = {
535 	.setup			= mlxsw_sp_fid_8021d_setup,
536 	.configure		= mlxsw_sp_fid_8021d_configure,
537 	.deconfigure		= mlxsw_sp_fid_8021d_deconfigure,
538 	.index_alloc		= mlxsw_sp_fid_8021d_index_alloc,
539 	.compare		= mlxsw_sp_fid_8021d_compare,
540 	.flood_index		= mlxsw_sp_fid_8021d_flood_index,
541 	.port_vid_map		= mlxsw_sp_fid_8021d_port_vid_map,
542 	.port_vid_unmap		= mlxsw_sp_fid_8021d_port_vid_unmap,
543 };
544 
545 static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = {
546 	{
547 		.packet_type	= MLXSW_SP_FLOOD_TYPE_UC,
548 		.bridge_type	= MLXSW_REG_SFGC_BRIDGE_TYPE_VFID,
549 		.table_type	= MLXSW_REG_SFGC_TABLE_TYPE_FID,
550 		.table_index	= 0,
551 	},
552 	{
553 		.packet_type	= MLXSW_SP_FLOOD_TYPE_MC,
554 		.bridge_type	= MLXSW_REG_SFGC_BRIDGE_TYPE_VFID,
555 		.table_type	= MLXSW_REG_SFGC_TABLE_TYPE_FID,
556 		.table_index	= 1,
557 	},
558 	{
559 		.packet_type	= MLXSW_SP_FLOOD_TYPE_BC,
560 		.bridge_type	= MLXSW_REG_SFGC_BRIDGE_TYPE_VFID,
561 		.table_type	= MLXSW_REG_SFGC_TABLE_TYPE_FID,
562 		.table_index	= 2,
563 	},
564 };
565 
566 /* Range and flood configuration must match mlxsw_config_profile */
567 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021d_family = {
568 	.type			= MLXSW_SP_FID_TYPE_8021D,
569 	.fid_size		= sizeof(struct mlxsw_sp_fid_8021d),
570 	.start_index		= VLAN_N_VID,
571 	.end_index		= VLAN_N_VID + MLXSW_SP_FID_8021D_MAX - 1,
572 	.flood_tables		= mlxsw_sp_fid_8021d_flood_tables,
573 	.nr_flood_tables	= ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
574 	.rif_type		= MLXSW_SP_RIF_TYPE_FID,
575 	.ops			= &mlxsw_sp_fid_8021d_ops,
576 };
577 
578 static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid)
579 {
580 	/* rFIDs are allocated by the device during init */
581 	return 0;
582 }
583 
584 static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid)
585 {
586 }
587 
588 static int mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid *fid,
589 					 const void *arg, u16 *p_fid_index)
590 {
591 	u16 rif_index = *(u16 *) arg;
592 
593 	*p_fid_index = fid->fid_family->start_index + rif_index;
594 
595 	return 0;
596 }
597 
598 static bool mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid *fid,
599 				      const void *arg)
600 {
601 	u16 rif_index = *(u16 *) arg;
602 
603 	return fid->fid_index == rif_index + fid->fid_family->start_index;
604 }
605 
606 static int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid,
607 					  struct mlxsw_sp_port *mlxsw_sp_port,
608 					  u16 vid)
609 {
610 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
611 	u8 local_port = mlxsw_sp_port->local_port;
612 	int err;
613 
614 	/* We only need to transition the port to virtual mode since
615 	 * {Port, VID} => FID is done by the firmware upon RIF creation.
616 	 */
617 	if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
618 		err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
619 		if (err)
620 			goto err_port_vp_mode_trans;
621 	}
622 
623 	return 0;
624 
625 err_port_vp_mode_trans:
626 	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
627 	return err;
628 }
629 
630 static void
631 mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid *fid,
632 				 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
633 {
634 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
635 	u8 local_port = mlxsw_sp_port->local_port;
636 
637 	if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
638 		mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
639 	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
640 }
641 
642 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = {
643 	.configure		= mlxsw_sp_fid_rfid_configure,
644 	.deconfigure		= mlxsw_sp_fid_rfid_deconfigure,
645 	.index_alloc		= mlxsw_sp_fid_rfid_index_alloc,
646 	.compare		= mlxsw_sp_fid_rfid_compare,
647 	.port_vid_map		= mlxsw_sp_fid_rfid_port_vid_map,
648 	.port_vid_unmap		= mlxsw_sp_fid_rfid_port_vid_unmap,
649 };
650 
651 #define MLXSW_SP_RFID_BASE	(15 * 1024)
652 #define MLXSW_SP_RFID_MAX	1024
653 
654 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family = {
655 	.type			= MLXSW_SP_FID_TYPE_RFID,
656 	.fid_size		= sizeof(struct mlxsw_sp_fid),
657 	.start_index		= MLXSW_SP_RFID_BASE,
658 	.end_index		= MLXSW_SP_RFID_BASE + MLXSW_SP_RFID_MAX - 1,
659 	.rif_type		= MLXSW_SP_RIF_TYPE_SUBPORT,
660 	.ops			= &mlxsw_sp_fid_rfid_ops,
661 };
662 
663 static int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid *fid)
664 {
665 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
666 
667 	return mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, true);
668 }
669 
670 static void mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid *fid)
671 {
672 	mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false);
673 }
674 
675 static int mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid *fid,
676 					  const void *arg, u16 *p_fid_index)
677 {
678 	*p_fid_index = fid->fid_family->start_index;
679 
680 	return 0;
681 }
682 
683 static bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid,
684 				       const void *arg)
685 {
686 	return true;
687 }
688 
689 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = {
690 	.configure		= mlxsw_sp_fid_dummy_configure,
691 	.deconfigure		= mlxsw_sp_fid_dummy_deconfigure,
692 	.index_alloc		= mlxsw_sp_fid_dummy_index_alloc,
693 	.compare		= mlxsw_sp_fid_dummy_compare,
694 };
695 
696 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_dummy_family = {
697 	.type			= MLXSW_SP_FID_TYPE_DUMMY,
698 	.fid_size		= sizeof(struct mlxsw_sp_fid),
699 	.start_index		= MLXSW_SP_RFID_BASE - 1,
700 	.end_index		= MLXSW_SP_RFID_BASE - 1,
701 	.ops			= &mlxsw_sp_fid_dummy_ops,
702 };
703 
704 static const struct mlxsw_sp_fid_family *mlxsw_sp_fid_family_arr[] = {
705 	[MLXSW_SP_FID_TYPE_8021Q]	= &mlxsw_sp_fid_8021q_family,
706 	[MLXSW_SP_FID_TYPE_8021D]	= &mlxsw_sp_fid_8021d_family,
707 	[MLXSW_SP_FID_TYPE_RFID]	= &mlxsw_sp_fid_rfid_family,
708 	[MLXSW_SP_FID_TYPE_DUMMY]	= &mlxsw_sp_fid_dummy_family,
709 };
710 
711 static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp,
712 					     enum mlxsw_sp_fid_type type,
713 					     const void *arg)
714 {
715 	struct mlxsw_sp_fid_family *fid_family;
716 	struct mlxsw_sp_fid *fid;
717 	u16 fid_index;
718 	int err;
719 
720 	fid_family = mlxsw_sp->fid_core->fid_family_arr[type];
721 	list_for_each_entry(fid, &fid_family->fids_list, list) {
722 		if (!fid->fid_family->ops->compare(fid, arg))
723 			continue;
724 		fid->ref_count++;
725 		return fid;
726 	}
727 
728 	fid = kzalloc(fid_family->fid_size, GFP_KERNEL);
729 	if (!fid)
730 		return ERR_PTR(-ENOMEM);
731 	fid->fid_family = fid_family;
732 
733 	err = fid->fid_family->ops->index_alloc(fid, arg, &fid_index);
734 	if (err)
735 		goto err_index_alloc;
736 	fid->fid_index = fid_index;
737 	__set_bit(fid_index - fid_family->start_index, fid_family->fids_bitmap);
738 
739 	if (fid->fid_family->ops->setup)
740 		fid->fid_family->ops->setup(fid, arg);
741 
742 	err = fid->fid_family->ops->configure(fid);
743 	if (err)
744 		goto err_configure;
745 
746 	list_add(&fid->list, &fid_family->fids_list);
747 	fid->ref_count++;
748 	return fid;
749 
750 err_configure:
751 	__clear_bit(fid_index - fid_family->start_index,
752 		    fid_family->fids_bitmap);
753 err_index_alloc:
754 	kfree(fid);
755 	return ERR_PTR(err);
756 }
757 
758 void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid)
759 {
760 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
761 
762 	if (--fid->ref_count == 1 && fid->rif) {
763 		/* Destroy the associated RIF and let it drop the last
764 		 * reference on the FID.
765 		 */
766 		return mlxsw_sp_rif_destroy(fid->rif);
767 	} else if (fid->ref_count == 0) {
768 		list_del(&fid->list);
769 		fid->fid_family->ops->deconfigure(fid);
770 		__clear_bit(fid->fid_index - fid_family->start_index,
771 			    fid_family->fids_bitmap);
772 		kfree(fid);
773 	}
774 }
775 
776 struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid)
777 {
778 	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid);
779 }
780 
781 struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp,
782 					    int br_ifindex)
783 {
784 	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, &br_ifindex);
785 }
786 
787 struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp,
788 					   u16 rif_index)
789 {
790 	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_RFID, &rif_index);
791 }
792 
793 struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp)
794 {
795 	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_DUMMY, NULL);
796 }
797 
798 static int
799 mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family,
800 			      const struct mlxsw_sp_flood_table *flood_table)
801 {
802 	enum mlxsw_sp_flood_type packet_type = flood_table->packet_type;
803 	const int *sfgc_packet_types;
804 	int i;
805 
806 	sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type];
807 	for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) {
808 		struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
809 		char sfgc_pl[MLXSW_REG_SFGC_LEN];
810 		int err;
811 
812 		if (!sfgc_packet_types[i])
813 			continue;
814 		mlxsw_reg_sfgc_pack(sfgc_pl, i, flood_table->bridge_type,
815 				    flood_table->table_type,
816 				    flood_table->table_index);
817 		err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl);
818 		if (err)
819 			return err;
820 	}
821 
822 	return 0;
823 }
824 
825 static int
826 mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family)
827 {
828 	int i;
829 
830 	for (i = 0; i < fid_family->nr_flood_tables; i++) {
831 		const struct mlxsw_sp_flood_table *flood_table;
832 		int err;
833 
834 		flood_table = &fid_family->flood_tables[i];
835 		err = mlxsw_sp_fid_flood_table_init(fid_family, flood_table);
836 		if (err)
837 			return err;
838 	}
839 
840 	return 0;
841 }
842 
843 static int mlxsw_sp_fid_family_register(struct mlxsw_sp *mlxsw_sp,
844 					const struct mlxsw_sp_fid_family *tmpl)
845 {
846 	u16 nr_fids = tmpl->end_index - tmpl->start_index + 1;
847 	struct mlxsw_sp_fid_family *fid_family;
848 	int err;
849 
850 	fid_family = kmemdup(tmpl, sizeof(*fid_family), GFP_KERNEL);
851 	if (!fid_family)
852 		return -ENOMEM;
853 
854 	fid_family->mlxsw_sp = mlxsw_sp;
855 	INIT_LIST_HEAD(&fid_family->fids_list);
856 	fid_family->fids_bitmap = kcalloc(BITS_TO_LONGS(nr_fids),
857 					  sizeof(unsigned long), GFP_KERNEL);
858 	if (!fid_family->fids_bitmap) {
859 		err = -ENOMEM;
860 		goto err_alloc_fids_bitmap;
861 	}
862 
863 	if (fid_family->flood_tables) {
864 		err = mlxsw_sp_fid_flood_tables_init(fid_family);
865 		if (err)
866 			goto err_fid_flood_tables_init;
867 	}
868 
869 	mlxsw_sp->fid_core->fid_family_arr[tmpl->type] = fid_family;
870 
871 	return 0;
872 
873 err_fid_flood_tables_init:
874 	kfree(fid_family->fids_bitmap);
875 err_alloc_fids_bitmap:
876 	kfree(fid_family);
877 	return err;
878 }
879 
880 static void
881 mlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp,
882 			       struct mlxsw_sp_fid_family *fid_family)
883 {
884 	mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL;
885 	kfree(fid_family->fids_bitmap);
886 	WARN_ON_ONCE(!list_empty(&fid_family->fids_list));
887 	kfree(fid_family);
888 }
889 
890 int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port)
891 {
892 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
893 
894 	/* Track number of FIDs configured on the port with mapping type
895 	 * PORT_VID_TO_FID, so that we know when to transition the port
896 	 * back to non-virtual (VLAN) mode.
897 	 */
898 	mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
899 
900 	return mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
901 }
902 
903 void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port)
904 {
905 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
906 
907 	mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
908 }
909 
910 int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp)
911 {
912 	unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
913 	struct mlxsw_sp_fid_core *fid_core;
914 	int err, i;
915 
916 	fid_core = kzalloc(sizeof(*mlxsw_sp->fid_core), GFP_KERNEL);
917 	if (!fid_core)
918 		return -ENOMEM;
919 	mlxsw_sp->fid_core = fid_core;
920 
921 	fid_core->port_fid_mappings = kcalloc(max_ports, sizeof(unsigned int),
922 					      GFP_KERNEL);
923 	if (!fid_core->port_fid_mappings) {
924 		err = -ENOMEM;
925 		goto err_alloc_port_fid_mappings;
926 	}
927 
928 	for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) {
929 		err = mlxsw_sp_fid_family_register(mlxsw_sp,
930 						   mlxsw_sp_fid_family_arr[i]);
931 
932 		if (err)
933 			goto err_fid_ops_register;
934 	}
935 
936 	return 0;
937 
938 err_fid_ops_register:
939 	for (i--; i >= 0; i--) {
940 		struct mlxsw_sp_fid_family *fid_family;
941 
942 		fid_family = fid_core->fid_family_arr[i];
943 		mlxsw_sp_fid_family_unregister(mlxsw_sp, fid_family);
944 	}
945 	kfree(fid_core->port_fid_mappings);
946 err_alloc_port_fid_mappings:
947 	kfree(fid_core);
948 	return err;
949 }
950 
951 void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp)
952 {
953 	struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
954 	int i;
955 
956 	for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++)
957 		mlxsw_sp_fid_family_unregister(mlxsw_sp,
958 					       fid_core->fid_family_arr[i]);
959 	kfree(fid_core->port_fid_mappings);
960 	kfree(fid_core);
961 }
962