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