brintos

brintos / linux-shallow public Read only

0
0
Text · 68.4 KiB · 65562ab Raw
2497 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/* 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/rhashtable.h>10#include <linux/rtnetlink.h>11#include <linux/refcount.h>12 13#include "spectrum.h"14#include "spectrum_router.h"15#include "reg.h"16 17struct mlxsw_sp_fid_family;18 19struct mlxsw_sp_fid_core {20	struct rhashtable fid_ht;21	struct rhashtable vni_ht;22	struct mlxsw_sp_fid_family *fid_family_arr[MLXSW_SP_FID_TYPE_MAX];23	unsigned int *port_fid_mappings;24};25 26struct mlxsw_sp_fid_port_vid {27	struct list_head list;28	u16 local_port;29	u16 vid;30};31 32struct mlxsw_sp_fid {33	struct list_head list;34	struct mlxsw_sp_rif *rif;35	refcount_t ref_count;36	u16 fid_index;37	u16 fid_offset;38	struct mlxsw_sp_fid_family *fid_family;39	struct rhash_head ht_node;40 41	struct rhash_head vni_ht_node;42	enum mlxsw_sp_nve_type nve_type;43	__be32 vni;44	u32 nve_flood_index;45	int nve_ifindex;46	u8 vni_valid:1,47	   nve_flood_index_valid:1;48	struct list_head port_vid_list; /* Ordered by local port. */49};50 51struct mlxsw_sp_fid_8021q {52	struct mlxsw_sp_fid common;53	u16 vid;54};55 56struct mlxsw_sp_fid_8021d {57	struct mlxsw_sp_fid common;58	int br_ifindex;59};60 61static const struct rhashtable_params mlxsw_sp_fid_ht_params = {62	.key_len = sizeof_field(struct mlxsw_sp_fid, fid_index),63	.key_offset = offsetof(struct mlxsw_sp_fid, fid_index),64	.head_offset = offsetof(struct mlxsw_sp_fid, ht_node),65};66 67static const struct rhashtable_params mlxsw_sp_fid_vni_ht_params = {68	.key_len = sizeof_field(struct mlxsw_sp_fid, vni),69	.key_offset = offsetof(struct mlxsw_sp_fid, vni),70	.head_offset = offsetof(struct mlxsw_sp_fid, vni_ht_node),71};72 73struct mlxsw_sp_flood_table {74	enum mlxsw_sp_flood_type packet_type;75	enum mlxsw_flood_table_type table_type;	/* For flood_mode!=CFF. */76	int table_index;77};78 79struct mlxsw_sp_fid_ops {80	int (*setup)(struct mlxsw_sp_fid *fid, const void *arg);81	int (*configure)(struct mlxsw_sp_fid *fid);82	void (*deconfigure)(struct mlxsw_sp_fid *fid);83	int (*index_alloc)(struct mlxsw_sp_fid *fid, const void *arg,84			   u16 *p_fid_index);85	bool (*compare)(const struct mlxsw_sp_fid *fid,86			const void *arg);87	int (*port_vid_map)(struct mlxsw_sp_fid *fid,88			    struct mlxsw_sp_port *port, u16 vid);89	void (*port_vid_unmap)(struct mlxsw_sp_fid *fid,90			       struct mlxsw_sp_port *port, u16 vid);91	int (*vni_set)(struct mlxsw_sp_fid *fid);92	void (*vni_clear)(struct mlxsw_sp_fid *fid);93	int (*nve_flood_index_set)(struct mlxsw_sp_fid *fid);94	void (*nve_flood_index_clear)(struct mlxsw_sp_fid *fid);95	void (*fdb_clear_offload)(const struct mlxsw_sp_fid *fid,96				  const struct net_device *nve_dev);97	int (*vid_to_fid_rif_update)(const struct mlxsw_sp_fid *fid,98				     const struct mlxsw_sp_rif *rif);99	int (*flood_table_init)(struct mlxsw_sp_fid_family *fid_family,100				const struct mlxsw_sp_flood_table *flood_table);101	int (*pgt_size)(const struct mlxsw_sp_fid_family *fid_family,102			u16 *p_pgt_size);103	u16 (*fid_mid)(const struct mlxsw_sp_fid *fid,104		       const struct mlxsw_sp_flood_table *flood_table);105	void (*fid_pack)(char *sfmr_pl, const struct mlxsw_sp_fid *fid,106			 enum mlxsw_reg_sfmr_op op);107 108	/* These are specific to RFID families and we assume are only109	 * implemented by RFID families, if at all.110	 */111	int (*fid_port_init)(const struct mlxsw_sp_fid_family *fid_family,112			     const struct mlxsw_sp_port *mlxsw_sp_port);113	void (*fid_port_fini)(const struct mlxsw_sp_fid_family *fid_family,114			      const struct mlxsw_sp_port *mlxsw_sp_port);115};116 117enum mlxsw_sp_fid_flood_profile_id {118	MLXSW_SP_FID_FLOOD_PROFILE_ID_BRIDGE = 1,119	MLXSW_SP_FID_FLOOD_PROFILE_ID_RSP,120	MLXSW_SP_FID_FLOOD_PROFILE_ID_NVE,121};122 123struct mlxsw_sp_fid_flood_profile {124	const struct mlxsw_sp_flood_table *flood_tables;125	int nr_flood_tables;126	const enum mlxsw_sp_fid_flood_profile_id profile_id; /* For CFF mode. */127};128 129struct mlxsw_sp_fid_family {130	enum mlxsw_sp_fid_type type;131	size_t fid_size;132	u16 start_index;133	u16 end_index;134	struct list_head fids_list;135	unsigned long *fids_bitmap;136	const struct mlxsw_sp_fid_flood_profile *flood_profile;137	enum mlxsw_sp_rif_type rif_type;138	const struct mlxsw_sp_fid_ops *ops;139	struct mlxsw_sp *mlxsw_sp;140	bool flood_rsp;	/* For flood_mode!=CFF. */141	enum mlxsw_reg_bridge_type bridge_type;142	u16 pgt_base;143	bool smpe_index_valid;144};145 146static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {147	[MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST]			= 1,148};149 150static const int mlxsw_sp_sfgc_bc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {151	[MLXSW_REG_SFGC_TYPE_BROADCAST]				= 1,152	[MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP]	= 1,153	[MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL]			= 1,154	[MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST]			= 1,155	[MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6]	= 1,156};157 158static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {159	[MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4]	= 1,160};161 162static const int mlxsw_sp_sfgc_not_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {163	[MLXSW_REG_SFGC_TYPE_BROADCAST]				= 1,164	[MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP]	= 1,165	[MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL]			= 1,166	[MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST]			= 1,167	[MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6]	= 1,168	[MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4]	= 1,169};170 171static const int mlxsw_sp_sfgc_any_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {172	[MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST]			= 1,173	[MLXSW_REG_SFGC_TYPE_BROADCAST]				= 1,174	[MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP]	= 1,175	[MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL]			= 1,176	[MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST]			= 1,177	[MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6]	= 1,178	[MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4]	= 1,179};180 181static const int *mlxsw_sp_packet_type_sfgc_types[] = {182	[MLXSW_SP_FLOOD_TYPE_UC]	= mlxsw_sp_sfgc_uc_packet_types,183	[MLXSW_SP_FLOOD_TYPE_BC]	= mlxsw_sp_sfgc_bc_packet_types,184	[MLXSW_SP_FLOOD_TYPE_MC]	= mlxsw_sp_sfgc_mc_packet_types,185	[MLXSW_SP_FLOOD_TYPE_NOT_UC]	= mlxsw_sp_sfgc_not_uc_packet_types,186	[MLXSW_SP_FLOOD_TYPE_ANY]	= mlxsw_sp_sfgc_any_packet_types,187};188 189struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp,190						  u16 fid_index)191{192	struct mlxsw_sp_fid *fid;193 194	fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->fid_ht, &fid_index,195				     mlxsw_sp_fid_ht_params);196	if (fid)197		refcount_inc(&fid->ref_count);198 199	return fid;200}201 202int mlxsw_sp_fid_nve_ifindex(const struct mlxsw_sp_fid *fid, int *nve_ifindex)203{204	if (!fid->vni_valid)205		return -EINVAL;206 207	*nve_ifindex = fid->nve_ifindex;208 209	return 0;210}211 212int mlxsw_sp_fid_nve_type(const struct mlxsw_sp_fid *fid,213			  enum mlxsw_sp_nve_type *p_type)214{215	if (!fid->vni_valid)216		return -EINVAL;217 218	*p_type = fid->nve_type;219 220	return 0;221}222 223struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_vni(struct mlxsw_sp *mlxsw_sp,224						__be32 vni)225{226	struct mlxsw_sp_fid *fid;227 228	fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->vni_ht, &vni,229				     mlxsw_sp_fid_vni_ht_params);230	if (fid)231		refcount_inc(&fid->ref_count);232 233	return fid;234}235 236int mlxsw_sp_fid_vni(const struct mlxsw_sp_fid *fid, __be32 *vni)237{238	if (!fid->vni_valid)239		return -EINVAL;240 241	*vni = fid->vni;242 243	return 0;244}245 246int mlxsw_sp_fid_nve_flood_index_set(struct mlxsw_sp_fid *fid,247				     u32 nve_flood_index)248{249	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;250	const struct mlxsw_sp_fid_ops *ops = fid_family->ops;251	int err;252 253	if (WARN_ON(fid->nve_flood_index_valid))254		return -EINVAL;255 256	fid->nve_flood_index = nve_flood_index;257	fid->nve_flood_index_valid = true;258	err = ops->nve_flood_index_set(fid);259	if (err)260		goto err_nve_flood_index_set;261 262	return 0;263 264err_nve_flood_index_set:265	fid->nve_flood_index_valid = false;266	return err;267}268 269void mlxsw_sp_fid_nve_flood_index_clear(struct mlxsw_sp_fid *fid)270{271	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;272	const struct mlxsw_sp_fid_ops *ops = fid_family->ops;273 274	if (WARN_ON(!fid->nve_flood_index_valid))275		return;276 277	fid->nve_flood_index_valid = false;278	ops->nve_flood_index_clear(fid);279}280 281bool mlxsw_sp_fid_nve_flood_index_is_set(const struct mlxsw_sp_fid *fid)282{283	return fid->nve_flood_index_valid;284}285 286int mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid *fid, enum mlxsw_sp_nve_type type,287			 __be32 vni, int nve_ifindex)288{289	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;290	const struct mlxsw_sp_fid_ops *ops = fid_family->ops;291	struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;292	int err;293 294	if (WARN_ON(fid->vni_valid))295		return -EINVAL;296 297	fid->nve_type = type;298	fid->nve_ifindex = nve_ifindex;299	fid->vni = vni;300	err = rhashtable_lookup_insert_fast(&mlxsw_sp->fid_core->vni_ht,301					    &fid->vni_ht_node,302					    mlxsw_sp_fid_vni_ht_params);303	if (err)304		return err;305 306	fid->vni_valid = true;307	err = ops->vni_set(fid);308	if (err)309		goto err_vni_set;310 311	return 0;312 313err_vni_set:314	fid->vni_valid = false;315	rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node,316			       mlxsw_sp_fid_vni_ht_params);317	return err;318}319 320void mlxsw_sp_fid_vni_clear(struct mlxsw_sp_fid *fid)321{322	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;323	const struct mlxsw_sp_fid_ops *ops = fid_family->ops;324	struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;325 326	if (WARN_ON(!fid->vni_valid))327		return;328 329	fid->vni_valid = false;330	ops->vni_clear(fid);331	rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node,332			       mlxsw_sp_fid_vni_ht_params);333}334 335bool mlxsw_sp_fid_vni_is_set(const struct mlxsw_sp_fid *fid)336{337	return fid->vni_valid;338}339 340void mlxsw_sp_fid_fdb_clear_offload(const struct mlxsw_sp_fid *fid,341				    const struct net_device *nve_dev)342{343	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;344	const struct mlxsw_sp_fid_ops *ops = fid_family->ops;345 346	if (ops->fdb_clear_offload)347		ops->fdb_clear_offload(fid, nve_dev);348}349 350static const struct mlxsw_sp_flood_table *351mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid,352				enum mlxsw_sp_flood_type packet_type)353{354	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;355	int i;356 357	for (i = 0; i < fid_family->flood_profile->nr_flood_tables; i++) {358		const struct mlxsw_sp_flood_table *flood_table;359 360		flood_table = &fid_family->flood_profile->flood_tables[i];361		if (flood_table->packet_type != packet_type)362			continue;363		return flood_table;364	}365 366	return NULL;367}368 369static u16370mlxsw_sp_fid_family_num_fids(const struct mlxsw_sp_fid_family *fid_family)371{372	return fid_family->end_index - fid_family->start_index + 1;373}374 375static int376mlxsw_sp_fid_8021d_pgt_size(const struct mlxsw_sp_fid_family *fid_family,377			    u16 *p_pgt_size)378{379	u16 num_fids = mlxsw_sp_fid_family_num_fids(fid_family);380 381	*p_pgt_size = num_fids * fid_family->flood_profile->nr_flood_tables;382	return 0;383}384 385static unsigned int mlxsw_sp_fid_rfid_port_offset_cff(unsigned int local_port)386{387	/* Port 0 is the CPU port. Since we never create RIFs based off that388	 * port, we don't need to count it.389	 */390	return WARN_ON_ONCE(!local_port) ? 0 : local_port - 1;391}392 393static int394mlxsw_sp_fid_rfid_pgt_size_cff(const struct mlxsw_sp_fid_family *fid_family,395			       u16 *p_pgt_size)396{397	struct mlxsw_core *core = fid_family->mlxsw_sp->core;398	unsigned int max_ports;399	u16 pgt_size;400	u16 max_lags;401	int err;402 403	max_ports = mlxsw_core_max_ports(core);404 405	err = mlxsw_core_max_lag(core, &max_lags);406	if (err)407		return err;408 409	pgt_size = (mlxsw_sp_fid_rfid_port_offset_cff(max_ports) + max_lags) *410		   fid_family->flood_profile->nr_flood_tables;411	*p_pgt_size = pgt_size;412	return 0;413}414 415static u16416mlxsw_sp_fid_pgt_base_ctl(const struct mlxsw_sp_fid_family *fid_family,417			  const struct mlxsw_sp_flood_table *flood_table)418{419	u16 num_fids;420 421	num_fids = mlxsw_sp_fid_family_num_fids(fid_family);422	return fid_family->pgt_base + num_fids * flood_table->table_index;423}424 425static u16426mlxsw_sp_fid_fid_mid_ctl(const struct mlxsw_sp_fid *fid,427			 const struct mlxsw_sp_flood_table *flood_table)428{429	return mlxsw_sp_fid_pgt_base_ctl(fid->fid_family, flood_table) +430	       fid->fid_offset;431}432 433int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid,434			   enum mlxsw_sp_flood_type packet_type, u16 local_port,435			   bool member)436{437	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;438	const struct mlxsw_sp_flood_table *flood_table;439	u16 mid_index;440 441	if (WARN_ON(!fid_family->flood_profile))442		return -EINVAL;443 444	flood_table = mlxsw_sp_fid_flood_table_lookup(fid, packet_type);445	if (!flood_table)446		return -ESRCH;447 448	mid_index = fid_family->ops->fid_mid(fid, flood_table);449	return mlxsw_sp_pgt_entry_port_set(fid_family->mlxsw_sp, mid_index,450					   fid->fid_index, local_port, member);451}452 453int mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid *fid,454			      struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)455{456	if (WARN_ON(!fid->fid_family->ops->port_vid_map))457		return -EINVAL;458	return fid->fid_family->ops->port_vid_map(fid, mlxsw_sp_port, vid);459}460 461void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid,462				 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)463{464	fid->fid_family->ops->port_vid_unmap(fid, mlxsw_sp_port, vid);465}466 467u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid)468{469	return fid->fid_index;470}471 472enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid)473{474	return fid->fid_family->type;475}476 477struct mlxsw_sp_rif *mlxsw_sp_fid_rif(const struct mlxsw_sp_fid *fid)478{479	return fid->rif;480}481 482enum mlxsw_sp_rif_type483mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp,484			   enum mlxsw_sp_fid_type type)485{486	struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;487 488	return fid_core->fid_family_arr[type]->rif_type;489}490 491static struct mlxsw_sp_fid_8021q *492mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid)493{494	return container_of(fid, struct mlxsw_sp_fid_8021q, common);495}496 497u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid)498{499	return mlxsw_sp_fid_8021q_fid(fid)->vid;500}501 502static int mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg)503{504	u16 vid = *(u16 *) arg;505 506	mlxsw_sp_fid_8021q_fid(fid)->vid = vid;507	fid->fid_offset = fid->fid_index - fid->fid_family->start_index;508	return 0;509}510 511static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid)512{513	return valid ? MLXSW_REG_SFMR_OP_CREATE_FID :514		       MLXSW_REG_SFMR_OP_DESTROY_FID;515}516 517static void mlxsw_sp_fid_pack(char *sfmr_pl,518			      const struct mlxsw_sp_fid *fid,519			      enum mlxsw_reg_sfmr_op op)520{521	u16 smpe;522 523	smpe = fid->fid_family->smpe_index_valid ? fid->fid_index : 0;524 525	mlxsw_reg_sfmr_pack(sfmr_pl, op, fid->fid_index,526			    fid->fid_family->smpe_index_valid, smpe);527}528 529static void mlxsw_sp_fid_pack_ctl(char *sfmr_pl,530				  const struct mlxsw_sp_fid *fid,531				  enum mlxsw_reg_sfmr_op op)532{533	mlxsw_sp_fid_pack(sfmr_pl, fid, op);534	mlxsw_reg_sfmr_fid_offset_set(sfmr_pl, fid->fid_offset);535	mlxsw_reg_sfmr_flood_rsp_set(sfmr_pl, fid->fid_family->flood_rsp);536	mlxsw_reg_sfmr_flood_bridge_type_set(sfmr_pl,537					     fid->fid_family->bridge_type);538}539 540static u16541mlxsw_sp_fid_off_pgt_base_cff(const struct mlxsw_sp_fid_family *fid_family,542			      u16 fid_offset)543{544	return fid_family->pgt_base +545		fid_offset * fid_family->flood_profile->nr_flood_tables;546}547 548static u16 mlxsw_sp_fid_pgt_base_cff(const struct mlxsw_sp_fid *fid)549{550	return mlxsw_sp_fid_off_pgt_base_cff(fid->fid_family, fid->fid_offset);551}552 553static void mlxsw_sp_fid_fid_pack_cff(char *sfmr_pl,554				      const struct mlxsw_sp_fid *fid,555				      enum mlxsw_reg_sfmr_op op)556{557	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;558	u16 pgt_base = mlxsw_sp_fid_pgt_base_cff(fid);559 560	mlxsw_sp_fid_pack(sfmr_pl, fid, op);561	mlxsw_reg_sfmr_cff_mid_base_set(sfmr_pl, pgt_base);562	mlxsw_reg_sfmr_cff_prf_id_set(sfmr_pl,563				      fid_family->flood_profile->profile_id);564	mlxsw_reg_sfmr_nve_flood_prf_id_set(sfmr_pl,565					    MLXSW_SP_FID_FLOOD_PROFILE_ID_NVE);566}567 568static u16 mlxsw_sp_fid_rfid_fid_offset_cff(struct mlxsw_sp *mlxsw_sp,569					    u16 port_lag_id, bool is_lag)570{571	u16 max_ports = mlxsw_core_max_ports(mlxsw_sp->core);572 573	if (is_lag)574		return mlxsw_sp_fid_rfid_port_offset_cff(max_ports) +575		       port_lag_id;576	else577		return mlxsw_sp_fid_rfid_port_offset_cff(port_lag_id);578}579 580static int mlxsw_sp_fid_op(const struct mlxsw_sp_fid *fid, bool valid)581{582	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;583	char sfmr_pl[MLXSW_REG_SFMR_LEN];584 585	fid->fid_family->ops->fid_pack(sfmr_pl, fid,586				       mlxsw_sp_sfmr_op(valid));587	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);588}589 590static int mlxsw_sp_fid_edit_op(const struct mlxsw_sp_fid *fid,591				const struct mlxsw_sp_rif *rif)592{593	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;594	char sfmr_pl[MLXSW_REG_SFMR_LEN];595 596	fid->fid_family->ops->fid_pack(sfmr_pl, fid,597				       MLXSW_REG_SFMR_OP_CREATE_FID);598 599	mlxsw_reg_sfmr_vv_set(sfmr_pl, fid->vni_valid);600	mlxsw_reg_sfmr_vni_set(sfmr_pl, be32_to_cpu(fid->vni));601	mlxsw_reg_sfmr_vtfp_set(sfmr_pl, fid->nve_flood_index_valid);602	mlxsw_reg_sfmr_nve_tunnel_flood_ptr_set(sfmr_pl, fid->nve_flood_index);603 604	if (rif) {605		mlxsw_reg_sfmr_irif_v_set(sfmr_pl, true);606		mlxsw_reg_sfmr_irif_set(sfmr_pl, mlxsw_sp_rif_index(rif));607	}608 609	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);610}611 612static int mlxsw_sp_fid_vni_to_fid_map(const struct mlxsw_sp_fid *fid,613				       const struct mlxsw_sp_rif *rif,614				       bool valid)615{616	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;617	char svfa_pl[MLXSW_REG_SVFA_LEN];618	bool irif_valid;619	u16 irif_index;620 621	irif_valid = !!rif;622	irif_index = rif ? mlxsw_sp_rif_index(rif) : 0;623 624	mlxsw_reg_svfa_vni_pack(svfa_pl, valid, fid->fid_index,625				be32_to_cpu(fid->vni), irif_valid, irif_index);626	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);627}628 629static int mlxsw_sp_fid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,630					  const struct mlxsw_sp_rif *rif)631{632	return mlxsw_sp_fid_edit_op(fid, rif);633}634 635static int mlxsw_sp_fid_vni_to_fid_rif_update(const struct mlxsw_sp_fid *fid,636					      const struct mlxsw_sp_rif *rif)637{638	if (!fid->vni_valid)639		return 0;640 641	return mlxsw_sp_fid_vni_to_fid_map(fid, rif, fid->vni_valid);642}643 644static int645mlxsw_sp_fid_vid_to_fid_map(const struct mlxsw_sp_fid *fid, u16 vid, bool valid,646			    const struct mlxsw_sp_rif *rif)647{648	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;649	char svfa_pl[MLXSW_REG_SVFA_LEN];650	bool irif_valid;651	u16 irif_index;652 653	irif_valid = !!rif;654	irif_index = rif ? mlxsw_sp_rif_index(rif) : 0;655 656	mlxsw_reg_svfa_vid_pack(svfa_pl, valid, fid->fid_index, vid, irif_valid,657				irif_index);658	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);659}660 661static int662mlxsw_sp_fid_8021q_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,663					 const struct mlxsw_sp_rif *rif)664{665	struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid);666 667	/* Update the global VID => FID mapping we created when the FID was668	 * configured.669	 */670	return mlxsw_sp_fid_vid_to_fid_map(fid, fid_8021q->vid, true, rif);671}672 673static int674mlxsw_sp_fid_port_vid_to_fid_rif_update_one(const struct mlxsw_sp_fid *fid,675					    struct mlxsw_sp_fid_port_vid *pv,676					    bool irif_valid, u16 irif_index)677{678	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;679	char svfa_pl[MLXSW_REG_SVFA_LEN];680 681	mlxsw_reg_svfa_port_vid_pack(svfa_pl, pv->local_port, true,682				     fid->fid_index, pv->vid, irif_valid,683				     irif_index);684 685	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);686}687 688static int mlxsw_sp_fid_vid_to_fid_rif_set(const struct mlxsw_sp_fid *fid,689					   const struct mlxsw_sp_rif *rif)690{691	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;692	struct mlxsw_sp_fid_port_vid *pv;693	u16 irif_index;694	int err;695 696	err = fid->fid_family->ops->vid_to_fid_rif_update(fid, rif);697	if (err)698		return err;699 700	irif_index = mlxsw_sp_rif_index(rif);701 702	list_for_each_entry(pv, &fid->port_vid_list, list) {703		/* If port is not in virtual mode, then it does not have any704		 * {Port, VID}->FID mappings that need to be updated with the705		 * ingress RIF.706		 */707		if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port])708			continue;709 710		err = mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv,711								  true,712								  irif_index);713		if (err)714			goto err_port_vid_to_fid_rif_update_one;715	}716 717	return 0;718 719err_port_vid_to_fid_rif_update_one:720	list_for_each_entry_continue_reverse(pv, &fid->port_vid_list, list) {721		if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port])722			continue;723 724		mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv, false, 0);725	}726 727	fid->fid_family->ops->vid_to_fid_rif_update(fid, NULL);728	return err;729}730 731static void mlxsw_sp_fid_vid_to_fid_rif_unset(const struct mlxsw_sp_fid *fid)732{733	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;734	struct mlxsw_sp_fid_port_vid *pv;735 736	list_for_each_entry(pv, &fid->port_vid_list, list) {737		/* If port is not in virtual mode, then it does not have any738		 * {Port, VID}->FID mappings that need to be updated.739		 */740		if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port])741			continue;742 743		mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv, false, 0);744	}745 746	fid->fid_family->ops->vid_to_fid_rif_update(fid, NULL);747}748 749static int mlxsw_sp_fid_reiv_handle(struct mlxsw_sp_fid *fid, u16 rif_index,750				    bool valid, u8 port_page)751{752	u16 local_port_end = (port_page + 1) * MLXSW_REG_REIV_REC_MAX_COUNT - 1;753	u16 local_port_start = port_page * MLXSW_REG_REIV_REC_MAX_COUNT;754	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;755	struct mlxsw_sp_fid_port_vid *port_vid;756	u8 rec_num, entries_num = 0;757	char *reiv_pl;758	int err;759 760	reiv_pl = kmalloc(MLXSW_REG_REIV_LEN, GFP_KERNEL);761	if (!reiv_pl)762		return -ENOMEM;763 764	mlxsw_reg_reiv_pack(reiv_pl, port_page, rif_index);765 766	list_for_each_entry(port_vid, &fid->port_vid_list, list) {767		/* port_vid_list is sorted by local_port. */768		if (port_vid->local_port < local_port_start)769			continue;770 771		if (port_vid->local_port > local_port_end)772			break;773 774		rec_num = port_vid->local_port % MLXSW_REG_REIV_REC_MAX_COUNT;775		mlxsw_reg_reiv_rec_update_set(reiv_pl, rec_num, true);776		mlxsw_reg_reiv_rec_evid_set(reiv_pl, rec_num,777					    valid ? port_vid->vid : 0);778		entries_num++;779	}780 781	if (!entries_num) {782		kfree(reiv_pl);783		return 0;784	}785 786	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(reiv), reiv_pl);787	if (err)788		goto err_reg_write;789 790	kfree(reiv_pl);791	return 0;792 793err_reg_write:794	kfree(reiv_pl);795	return err;796}797 798static int mlxsw_sp_fid_erif_eport_to_vid_map(struct mlxsw_sp_fid *fid,799					      u16 rif_index, bool valid)800{801	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;802	u8 num_port_pages;803	int err, i;804 805	num_port_pages = mlxsw_core_max_ports(mlxsw_sp->core) /806			 MLXSW_REG_REIV_REC_MAX_COUNT + 1;807 808	for (i = 0; i < num_port_pages; i++) {809		err = mlxsw_sp_fid_reiv_handle(fid, rif_index, valid, i);810		if (err)811			goto err_reiv_handle;812	}813 814	return 0;815 816err_reiv_handle:817	for (; i >= 0; i--)818		mlxsw_sp_fid_reiv_handle(fid, rif_index, !valid, i);819	return err;820}821 822int mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif)823{824	u16 rif_index = mlxsw_sp_rif_index(rif);825	int err;826 827	err = mlxsw_sp_fid_to_fid_rif_update(fid, rif);828	if (err)829		return err;830 831	err = mlxsw_sp_fid_vni_to_fid_rif_update(fid, rif);832	if (err)833		goto err_vni_to_fid_rif_update;834 835	err = mlxsw_sp_fid_vid_to_fid_rif_set(fid, rif);836	if (err)837		goto err_vid_to_fid_rif_set;838 839	err = mlxsw_sp_fid_erif_eport_to_vid_map(fid, rif_index, true);840	if (err)841		goto err_erif_eport_to_vid_map;842 843	fid->rif = rif;844	return 0;845 846err_erif_eport_to_vid_map:847	mlxsw_sp_fid_vid_to_fid_rif_unset(fid);848err_vid_to_fid_rif_set:849	mlxsw_sp_fid_vni_to_fid_rif_update(fid, NULL);850err_vni_to_fid_rif_update:851	mlxsw_sp_fid_to_fid_rif_update(fid, NULL);852	return err;853}854 855void mlxsw_sp_fid_rif_unset(struct mlxsw_sp_fid *fid)856{857	u16 rif_index;858 859	if (!fid->rif)860		return;861 862	rif_index = mlxsw_sp_rif_index(fid->rif);863	fid->rif = NULL;864 865	mlxsw_sp_fid_erif_eport_to_vid_map(fid, rif_index, false);866	mlxsw_sp_fid_vid_to_fid_rif_unset(fid);867	mlxsw_sp_fid_vni_to_fid_rif_update(fid, NULL);868	mlxsw_sp_fid_to_fid_rif_update(fid, NULL);869}870 871static int mlxsw_sp_fid_vni_op(const struct mlxsw_sp_fid *fid)872{873	int err;874 875	err = mlxsw_sp_fid_vni_to_fid_map(fid, fid->rif, fid->vni_valid);876	if (err)877		return err;878 879	err = mlxsw_sp_fid_edit_op(fid, fid->rif);880	if (err)881		goto err_fid_edit_op;882 883	return 0;884 885err_fid_edit_op:886	mlxsw_sp_fid_vni_to_fid_map(fid, fid->rif, !fid->vni_valid);887	return err;888}889 890static int __mlxsw_sp_fid_port_vid_map(const struct mlxsw_sp_fid *fid,891				       u16 local_port, u16 vid, bool valid)892{893	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;894	char svfa_pl[MLXSW_REG_SVFA_LEN];895	bool irif_valid = false;896	u16 irif_index = 0;897 898	if (fid->rif) {899		irif_valid = true;900		irif_index = mlxsw_sp_rif_index(fid->rif);901	}902 903	mlxsw_reg_svfa_port_vid_pack(svfa_pl, local_port, valid, fid->fid_index,904				     vid, irif_valid, irif_index);905	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);906}907 908static struct mlxsw_sp_fid_8021d *909mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid)910{911	return container_of(fid, struct mlxsw_sp_fid_8021d, common);912}913 914static int mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg)915{916	int br_ifindex = *(int *) arg;917 918	mlxsw_sp_fid_8021d_fid(fid)->br_ifindex = br_ifindex;919	fid->fid_offset = fid->fid_index - fid->fid_family->start_index;920	return 0;921}922 923static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid)924{925	return mlxsw_sp_fid_op(fid, true);926}927 928static void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid *fid)929{930	if (fid->vni_valid)931		mlxsw_sp_nve_fid_disable(fid->fid_family->mlxsw_sp, fid);932	mlxsw_sp_fid_op(fid, false);933}934 935static int mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid *fid,936					  const void *arg, u16 *p_fid_index)937{938	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;939	u16 nr_fids, fid_index;940 941	nr_fids = fid_family->end_index - fid_family->start_index + 1;942	fid_index = find_first_zero_bit(fid_family->fids_bitmap, nr_fids);943	if (fid_index == nr_fids)944		return -ENOBUFS;945	*p_fid_index = fid_family->start_index + fid_index;946 947	return 0;948}949 950static bool951mlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid *fid, const void *arg)952{953	int br_ifindex = *(int *) arg;954 955	return mlxsw_sp_fid_8021d_fid(fid)->br_ifindex == br_ifindex;956}957 958static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)959{960	struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;961	int err;962 963	list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list,964			    list) {965		struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;966		u16 vid = mlxsw_sp_port_vlan->vid;967 968		if (!fid)969			continue;970 971		err = __mlxsw_sp_fid_port_vid_map(fid,972						  mlxsw_sp_port->local_port,973						  vid, true);974		if (err)975			goto err_fid_port_vid_map;976	}977 978	err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true);979	if (err)980		goto err_port_vp_mode_set;981 982	return 0;983 984err_port_vp_mode_set:985err_fid_port_vid_map:986	list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan,987					     &mlxsw_sp_port->vlans_list, list) {988		struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;989		u16 vid = mlxsw_sp_port_vlan->vid;990 991		if (!fid)992			continue;993 994		__mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,995					    false);996	}997	return err;998}999 1000static void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)1001{1002	struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;1003 1004	mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);1005 1006	list_for_each_entry_reverse(mlxsw_sp_port_vlan,1007				    &mlxsw_sp_port->vlans_list, list) {1008		struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;1009		u16 vid = mlxsw_sp_port_vlan->vid;1010 1011		if (!fid)1012			continue;1013 1014		__mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,1015					    false);1016	}1017}1018 1019static int1020mlxsw_sp_fid_port_vid_list_add(struct mlxsw_sp_fid *fid, u16 local_port,1021			       u16 vid)1022{1023	struct mlxsw_sp_fid_port_vid *port_vid, *tmp_port_vid;1024 1025	port_vid = kzalloc(sizeof(*port_vid), GFP_KERNEL);1026	if (!port_vid)1027		return -ENOMEM;1028 1029	port_vid->local_port = local_port;1030	port_vid->vid = vid;1031 1032	list_for_each_entry(tmp_port_vid, &fid->port_vid_list, list) {1033		if (tmp_port_vid->local_port > local_port)1034			break;1035	}1036 1037	list_add_tail(&port_vid->list, &tmp_port_vid->list);1038	return 0;1039}1040 1041static void1042mlxsw_sp_fid_port_vid_list_del(struct mlxsw_sp_fid *fid, u16 local_port,1043			       u16 vid)1044{1045	struct mlxsw_sp_fid_port_vid *port_vid, *tmp;1046 1047	list_for_each_entry_safe(port_vid, tmp, &fid->port_vid_list, list) {1048		if (port_vid->local_port != local_port || port_vid->vid != vid)1049			continue;1050 1051		list_del(&port_vid->list);1052		kfree(port_vid);1053		return;1054	}1055}1056 1057static int1058mlxsw_sp_fid_mpe_table_map(const struct mlxsw_sp_fid *fid, u16 local_port,1059			   u16 vid, bool valid)1060{1061	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;1062	char smpe_pl[MLXSW_REG_SMPE_LEN];1063 1064	mlxsw_reg_smpe_pack(smpe_pl, local_port, fid->fid_index,1065			    valid ? vid : 0);1066	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(smpe), smpe_pl);1067}1068 1069static int1070mlxsw_sp_fid_erif_eport_to_vid_map_one(const struct mlxsw_sp_fid *fid,1071				       u16 local_port, u16 vid, bool valid)1072{1073	u8 port_page = local_port / MLXSW_REG_REIV_REC_MAX_COUNT;1074	u8 rec_num = local_port % MLXSW_REG_REIV_REC_MAX_COUNT;1075	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;1076	u16 rif_index = mlxsw_sp_rif_index(fid->rif);1077	char *reiv_pl;1078	int err;1079 1080	reiv_pl = kmalloc(MLXSW_REG_REIV_LEN, GFP_KERNEL);1081	if (!reiv_pl)1082		return -ENOMEM;1083 1084	mlxsw_reg_reiv_pack(reiv_pl, port_page, rif_index);1085	mlxsw_reg_reiv_rec_update_set(reiv_pl, rec_num, true);1086	mlxsw_reg_reiv_rec_evid_set(reiv_pl, rec_num, valid ? vid : 0);1087	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(reiv), reiv_pl);1088	kfree(reiv_pl);1089	return err;1090}1091 1092static int mlxsw_sp_fid_evid_map(const struct mlxsw_sp_fid *fid, u16 local_port,1093				 u16 vid, bool valid)1094{1095	int err;1096 1097	err = mlxsw_sp_fid_mpe_table_map(fid, local_port, vid, valid);1098	if (err)1099		return err;1100 1101	if (!fid->rif)1102		return 0;1103 1104	err = mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, vid,1105						     valid);1106	if (err)1107		goto err_erif_eport_to_vid_map_one;1108 1109	return 0;1110 1111err_erif_eport_to_vid_map_one:1112	mlxsw_sp_fid_mpe_table_map(fid, local_port, vid, !valid);1113	return err;1114}1115 1116static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid,1117					   struct mlxsw_sp_port *mlxsw_sp_port,1118					   u16 vid)1119{1120	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;1121	u16 local_port = mlxsw_sp_port->local_port;1122	int err;1123 1124	err = __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,1125					  true);1126	if (err)1127		return err;1128 1129	err = mlxsw_sp_fid_evid_map(fid, local_port, vid, true);1130	if (err)1131		goto err_fid_evid_map;1132 1133	err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port,1134					     vid);1135	if (err)1136		goto err_port_vid_list_add;1137 1138	if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {1139		err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);1140		if (err)1141			goto err_port_vp_mode_trans;1142	}1143 1144	return 0;1145 1146err_port_vp_mode_trans:1147	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;1148	mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);1149err_port_vid_list_add:1150	mlxsw_sp_fid_evid_map(fid, local_port, vid, false);1151err_fid_evid_map:1152	__mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);1153	return err;1154}1155 1156static void1157mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid,1158				  struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)1159{1160	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;1161	u16 local_port = mlxsw_sp_port->local_port;1162 1163	if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)1164		mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);1165	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;1166	mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);1167	mlxsw_sp_fid_evid_map(fid, local_port, vid, false);1168	__mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);1169}1170 1171static int mlxsw_sp_fid_8021d_vni_set(struct mlxsw_sp_fid *fid)1172{1173	return mlxsw_sp_fid_vni_op(fid);1174}1175 1176static void mlxsw_sp_fid_8021d_vni_clear(struct mlxsw_sp_fid *fid)1177{1178	mlxsw_sp_fid_vni_op(fid);1179}1180 1181static int mlxsw_sp_fid_8021d_nve_flood_index_set(struct mlxsw_sp_fid *fid)1182{1183	return mlxsw_sp_fid_edit_op(fid, fid->rif);1184}1185 1186static void mlxsw_sp_fid_8021d_nve_flood_index_clear(struct mlxsw_sp_fid *fid)1187{1188	mlxsw_sp_fid_edit_op(fid, fid->rif);1189}1190 1191static void1192mlxsw_sp_fid_8021d_fdb_clear_offload(const struct mlxsw_sp_fid *fid,1193				     const struct net_device *nve_dev)1194{1195	br_fdb_clear_offload(nve_dev, 0);1196}1197 1198static int1199mlxsw_sp_fid_8021d_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,1200					 const struct mlxsw_sp_rif *rif)1201{1202	return 0;1203}1204 1205static int1206mlxsw_sp_fid_flood_table_init_ctl(struct mlxsw_sp_fid_family *fid_family,1207				  const struct mlxsw_sp_flood_table *flood_table)1208{1209	enum mlxsw_sp_flood_type packet_type = flood_table->packet_type;1210	struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;1211	const int *sfgc_packet_types;1212	u16 mid_base;1213	int err, i;1214 1215	mid_base = mlxsw_sp_fid_pgt_base_ctl(fid_family, flood_table);1216 1217	sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type];1218	for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) {1219		char sfgc_pl[MLXSW_REG_SFGC_LEN];1220 1221		if (!sfgc_packet_types[i])1222			continue;1223 1224		mlxsw_reg_sfgc_pack(sfgc_pl, i, fid_family->bridge_type,1225				    flood_table->table_type, 0, mid_base);1226 1227		err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl);1228		if (err)1229			return err;1230	}1231 1232	return 0;1233}1234 1235static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops_ctl = {1236	.setup			= mlxsw_sp_fid_8021d_setup,1237	.configure		= mlxsw_sp_fid_8021d_configure,1238	.deconfigure		= mlxsw_sp_fid_8021d_deconfigure,1239	.index_alloc		= mlxsw_sp_fid_8021d_index_alloc,1240	.compare		= mlxsw_sp_fid_8021d_compare,1241	.port_vid_map		= mlxsw_sp_fid_8021d_port_vid_map,1242	.port_vid_unmap		= mlxsw_sp_fid_8021d_port_vid_unmap,1243	.vni_set		= mlxsw_sp_fid_8021d_vni_set,1244	.vni_clear		= mlxsw_sp_fid_8021d_vni_clear,1245	.nve_flood_index_set	= mlxsw_sp_fid_8021d_nve_flood_index_set,1246	.nve_flood_index_clear	= mlxsw_sp_fid_8021d_nve_flood_index_clear,1247	.fdb_clear_offload	= mlxsw_sp_fid_8021d_fdb_clear_offload,1248	.vid_to_fid_rif_update  = mlxsw_sp_fid_8021d_vid_to_fid_rif_update,1249	.flood_table_init	= mlxsw_sp_fid_flood_table_init_ctl,1250	.pgt_size		= mlxsw_sp_fid_8021d_pgt_size,1251	.fid_mid		= mlxsw_sp_fid_fid_mid_ctl,1252	.fid_pack		= mlxsw_sp_fid_pack_ctl,1253};1254 1255static u161256mlxsw_sp_fid_fid_mid_cff(const struct mlxsw_sp_fid *fid,1257			 const struct mlxsw_sp_flood_table *flood_table)1258{1259	return mlxsw_sp_fid_pgt_base_cff(fid) + flood_table->table_index;1260}1261 1262static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops_cff = {1263	.setup			= mlxsw_sp_fid_8021d_setup,1264	.configure		= mlxsw_sp_fid_8021d_configure,1265	.deconfigure		= mlxsw_sp_fid_8021d_deconfigure,1266	.index_alloc		= mlxsw_sp_fid_8021d_index_alloc,1267	.compare		= mlxsw_sp_fid_8021d_compare,1268	.port_vid_map		= mlxsw_sp_fid_8021d_port_vid_map,1269	.port_vid_unmap		= mlxsw_sp_fid_8021d_port_vid_unmap,1270	.vni_set		= mlxsw_sp_fid_8021d_vni_set,1271	.vni_clear		= mlxsw_sp_fid_8021d_vni_clear,1272	.nve_flood_index_set	= mlxsw_sp_fid_8021d_nve_flood_index_set,1273	.nve_flood_index_clear	= mlxsw_sp_fid_8021d_nve_flood_index_clear,1274	.fdb_clear_offload	= mlxsw_sp_fid_8021d_fdb_clear_offload,1275	.vid_to_fid_rif_update	= mlxsw_sp_fid_8021d_vid_to_fid_rif_update,1276	.pgt_size		= mlxsw_sp_fid_8021d_pgt_size,1277	.fid_mid		= mlxsw_sp_fid_fid_mid_cff,1278	.fid_pack		= mlxsw_sp_fid_fid_pack_cff,1279};1280 1281#define MLXSW_SP_FID_8021Q_MAX (VLAN_N_VID - 2)1282#define MLXSW_SP_FID_RFID_MAX (11 * 1024)1283 1284static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = {1285	{1286		.packet_type	= MLXSW_SP_FLOOD_TYPE_UC,1287		.table_type	= MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,1288		.table_index	= 0,1289	},1290	{1291		.packet_type	= MLXSW_SP_FLOOD_TYPE_MC,1292		.table_type	= MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,1293		.table_index	= 1,1294	},1295	{1296		.packet_type	= MLXSW_SP_FLOOD_TYPE_BC,1297		.table_type	= MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,1298		.table_index	= 2,1299	},1300};1301 1302static const1303struct mlxsw_sp_fid_flood_profile mlxsw_sp_fid_8021d_flood_profile = {1304	.flood_tables		= mlxsw_sp_fid_8021d_flood_tables,1305	.nr_flood_tables	= ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),1306	.profile_id		= MLXSW_SP_FID_FLOOD_PROFILE_ID_BRIDGE,1307};1308 1309static const struct mlxsw_sp_flood_table mlxsw_sp_fid_rsp_flood_tables_cff[] = {1310	{1311		.packet_type	= MLXSW_SP_FLOOD_TYPE_UC,1312		.table_index	= 0,1313	},1314	{1315		.packet_type	= MLXSW_SP_FLOOD_TYPE_NOT_UC,1316		.table_index	= 1,1317	},1318};1319 1320static const1321struct mlxsw_sp_fid_flood_profile mlxsw_sp_fid_rsp_flood_profile_cff = {1322	.flood_tables		= mlxsw_sp_fid_rsp_flood_tables_cff,1323	.nr_flood_tables	= ARRAY_SIZE(mlxsw_sp_fid_rsp_flood_tables_cff),1324	.profile_id		= MLXSW_SP_FID_FLOOD_PROFILE_ID_RSP,1325};1326 1327static const struct mlxsw_sp_flood_table mlxsw_sp_fid_nve_flood_tables_cff[] = {1328	{1329		.packet_type	= MLXSW_SP_FLOOD_TYPE_ANY,1330		.table_index	= 0,1331	},1332};1333 1334static const1335struct mlxsw_sp_fid_flood_profile mlxsw_sp_fid_nve_flood_profile_cff = {1336	.flood_tables		= mlxsw_sp_fid_nve_flood_tables_cff,1337	.nr_flood_tables	= ARRAY_SIZE(mlxsw_sp_fid_nve_flood_tables_cff),1338	.profile_id		= MLXSW_SP_FID_FLOOD_PROFILE_ID_NVE,1339};1340 1341static bool1342mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg)1343{1344	u16 vid = *(u16 *) arg;1345 1346	return mlxsw_sp_fid_8021q_fid(fid)->vid == vid;1347}1348 1349static void1350mlxsw_sp_fid_8021q_fdb_clear_offload(const struct mlxsw_sp_fid *fid,1351				     const struct net_device *nve_dev)1352{1353	br_fdb_clear_offload(nve_dev, mlxsw_sp_fid_8021q_vid(fid));1354}1355 1356static int mlxsw_sp_fid_rfid_setup_ctl(struct mlxsw_sp_fid *fid,1357				       const void *arg)1358{1359	/* In controlled mode, the FW takes care of FID placement. */1360	fid->fid_offset = 0;1361	return 0;1362}1363 1364static int mlxsw_sp_fid_rfid_setup_cff(struct mlxsw_sp_fid *fid,1365				       const void *arg)1366{1367	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;1368	u16 rif_index = *(const u16 *)arg;1369	struct mlxsw_sp_rif *rif;1370	bool is_lag;1371	u16 port;1372	int err;1373 1374	rif = mlxsw_sp_rif_by_index(mlxsw_sp, rif_index);1375	if (!rif)1376		return -ENOENT;1377 1378	err = mlxsw_sp_rif_subport_port(rif, &port, &is_lag);1379	if (err)1380		return err;1381 1382	fid->fid_offset = mlxsw_sp_fid_rfid_fid_offset_cff(mlxsw_sp, port,1383							   is_lag);1384	return 0;1385}1386 1387static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid)1388{1389	return mlxsw_sp_fid_op(fid, true);1390}1391 1392static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid)1393{1394	mlxsw_sp_fid_op(fid, false);1395}1396 1397static int mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid *fid,1398					 const void *arg, u16 *p_fid_index)1399{1400	u16 rif_index = *(u16 *) arg;1401 1402	*p_fid_index = fid->fid_family->start_index + rif_index;1403 1404	return 0;1405}1406 1407static bool mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid *fid,1408				      const void *arg)1409{1410	u16 rif_index = *(u16 *) arg;1411 1412	return fid->fid_index == rif_index + fid->fid_family->start_index;1413}1414 1415static int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid,1416					  struct mlxsw_sp_port *mlxsw_sp_port,1417					  u16 vid)1418{1419	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;1420	u16 local_port = mlxsw_sp_port->local_port;1421	int err;1422 1423	err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port,1424					     vid);1425	if (err)1426		return err;1427 1428	/* Using legacy bridge model, we only need to transition the port to1429	 * virtual mode since {Port, VID} => FID is done by the firmware upon1430	 * RIF creation. Using unified bridge model, we need to map1431	 * {Port, VID} => FID and map egress VID.1432	 */1433	err = __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,1434					  true);1435	if (err)1436		goto err_port_vid_map;1437 1438	if (fid->rif) {1439		err = mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port,1440							     vid, true);1441		if (err)1442			goto err_erif_eport_to_vid_map_one;1443	}1444 1445	if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {1446		err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);1447		if (err)1448			goto err_port_vp_mode_trans;1449	}1450 1451	return 0;1452 1453err_port_vp_mode_trans:1454	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;1455	if (fid->rif)1456		mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, vid,1457						       false);1458err_erif_eport_to_vid_map_one:1459	__mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);1460err_port_vid_map:1461	mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);1462	return err;1463}1464 1465static void1466mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid *fid,1467				 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)1468{1469	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;1470	u16 local_port = mlxsw_sp_port->local_port;1471 1472	if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)1473		mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);1474	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;1475 1476	if (fid->rif)1477		mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, vid,1478						       false);1479	__mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);1480	mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);1481}1482 1483static int mlxsw_sp_fid_rfid_vni_set(struct mlxsw_sp_fid *fid)1484{1485	return -EOPNOTSUPP;1486}1487 1488static void mlxsw_sp_fid_rfid_vni_clear(struct mlxsw_sp_fid *fid)1489{1490	WARN_ON_ONCE(1);1491}1492 1493static int mlxsw_sp_fid_rfid_nve_flood_index_set(struct mlxsw_sp_fid *fid)1494{1495	return -EOPNOTSUPP;1496}1497 1498static void mlxsw_sp_fid_rfid_nve_flood_index_clear(struct mlxsw_sp_fid *fid)1499{1500	WARN_ON_ONCE(1);1501}1502 1503static int1504mlxsw_sp_fid_rfid_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,1505					const struct mlxsw_sp_rif *rif)1506{1507	return 0;1508}1509 1510static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops_ctl = {1511	.setup			= mlxsw_sp_fid_rfid_setup_ctl,1512	.configure		= mlxsw_sp_fid_rfid_configure,1513	.deconfigure		= mlxsw_sp_fid_rfid_deconfigure,1514	.index_alloc		= mlxsw_sp_fid_rfid_index_alloc,1515	.compare		= mlxsw_sp_fid_rfid_compare,1516	.port_vid_map		= mlxsw_sp_fid_rfid_port_vid_map,1517	.port_vid_unmap		= mlxsw_sp_fid_rfid_port_vid_unmap,1518	.vni_set                = mlxsw_sp_fid_rfid_vni_set,1519	.vni_clear		= mlxsw_sp_fid_rfid_vni_clear,1520	.nve_flood_index_set	= mlxsw_sp_fid_rfid_nve_flood_index_set,1521	.nve_flood_index_clear	= mlxsw_sp_fid_rfid_nve_flood_index_clear,1522	.vid_to_fid_rif_update  = mlxsw_sp_fid_rfid_vid_to_fid_rif_update,1523	.fid_pack		= mlxsw_sp_fid_pack_ctl,1524};1525 1526static int1527mlxsw_sp_fid_rfid_port_add_cff(struct mlxsw_sp *mlxsw_sp,1528			       const struct mlxsw_sp_flood_table *flood_table,1529			       u16 pgt_addr, u16 smpe, unsigned int local_port)1530{1531	int err;1532 1533	err = mlxsw_sp_pgt_entry_port_set(mlxsw_sp, pgt_addr, smpe,1534					  local_port, true);1535	if (err)1536		return err;1537 1538	if (flood_table->packet_type == MLXSW_SP_FLOOD_TYPE_NOT_UC) {1539		u16 router_port = mlxsw_sp_router_port(mlxsw_sp);1540 1541		err = mlxsw_sp_pgt_entry_port_set(mlxsw_sp, pgt_addr, smpe,1542						  router_port, true);1543		if (err)1544			goto err_entry_port_set;1545	}1546 1547	return 0;1548 1549err_entry_port_set:1550	mlxsw_sp_pgt_entry_port_set(mlxsw_sp, pgt_addr, smpe, local_port,1551				    false);1552	return err;1553}1554 1555static void1556mlxsw_sp_fid_rfid_port_del_cff(struct mlxsw_sp *mlxsw_sp,1557			       const struct mlxsw_sp_flood_table *flood_table,1558			       u16 pgt_addr, u16 smpe, u16 local_port)1559{1560	if (flood_table->packet_type == MLXSW_SP_FLOOD_TYPE_NOT_UC) {1561		u16 router_port = mlxsw_sp_router_port(mlxsw_sp);1562 1563		mlxsw_sp_pgt_entry_port_set(mlxsw_sp, pgt_addr, smpe,1564					    router_port, false);1565	}1566	mlxsw_sp_pgt_entry_port_set(mlxsw_sp, pgt_addr, smpe, local_port,1567				    false);1568}1569 1570static int1571mlxsw_sp_fid_rfid_port_memb_ft_cff(const struct mlxsw_sp_fid_family *fid_family,1572				   const struct mlxsw_sp_flood_table *flood_table,1573				   const struct mlxsw_sp_port *mlxsw_sp_port,1574				   bool member)1575{1576	struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;1577	u16 local_port = mlxsw_sp_port->local_port;1578	u16 fid_pgt_base;1579	u16 fid_offset;1580	u16 pgt_addr;1581	u16 smpe;1582	u16 port;1583 1584	/* In-PGT SMPE is only valid on Spectrum-1, CFF only on Spectrum>1. */1585	smpe = 0;1586 1587	port = mlxsw_sp_port->lagged ? mlxsw_sp_port->lag_id : local_port;1588	fid_offset = mlxsw_sp_fid_rfid_fid_offset_cff(mlxsw_sp, port,1589						      mlxsw_sp_port->lagged);1590	fid_pgt_base = mlxsw_sp_fid_off_pgt_base_cff(fid_family, fid_offset);1591	pgt_addr = fid_pgt_base + flood_table->table_index;1592 1593	if (member)1594		return mlxsw_sp_fid_rfid_port_add_cff(mlxsw_sp, flood_table,1595						      pgt_addr, smpe,1596						      local_port);1597 1598	mlxsw_sp_fid_rfid_port_del_cff(mlxsw_sp, flood_table, pgt_addr, smpe,1599				       local_port);1600	return 0;1601}1602 1603static int1604mlxsw_sp_fid_rfid_port_memb_cff(const struct mlxsw_sp_fid_family *fid_family,1605				const struct mlxsw_sp_port *mlxsw_sp_port,1606				bool member)1607{1608	int i;1609 1610	for (i = 0; i < fid_family->flood_profile->nr_flood_tables; i++) {1611		const struct mlxsw_sp_flood_table *flood_table =1612			&fid_family->flood_profile->flood_tables[i];1613		int err;1614 1615		err = mlxsw_sp_fid_rfid_port_memb_ft_cff(fid_family,1616							 flood_table,1617							 mlxsw_sp_port, member);1618		if (err)1619			return err;1620	}1621 1622	return 0;1623}1624 1625static int1626mlxsw_sp_fid_rfid_port_init_cff(const struct mlxsw_sp_fid_family *fid_family,1627				const struct mlxsw_sp_port *mlxsw_sp_port)1628{1629	return mlxsw_sp_fid_rfid_port_memb_cff(fid_family, mlxsw_sp_port, true);1630}1631 1632static void1633mlxsw_sp_fid_rfid_port_fini_cff(const struct mlxsw_sp_fid_family *fid_family,1634				const struct mlxsw_sp_port *mlxsw_sp_port)1635{1636	mlxsw_sp_fid_rfid_port_memb_cff(fid_family, mlxsw_sp_port, false);1637}1638 1639static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops_cff = {1640	.setup			= mlxsw_sp_fid_rfid_setup_cff,1641	.configure		= mlxsw_sp_fid_rfid_configure,1642	.deconfigure		= mlxsw_sp_fid_rfid_deconfigure,1643	.index_alloc		= mlxsw_sp_fid_rfid_index_alloc,1644	.compare		= mlxsw_sp_fid_rfid_compare,1645	.port_vid_map		= mlxsw_sp_fid_rfid_port_vid_map,1646	.port_vid_unmap		= mlxsw_sp_fid_rfid_port_vid_unmap,1647	.vni_set		= mlxsw_sp_fid_rfid_vni_set,1648	.vni_clear		= mlxsw_sp_fid_rfid_vni_clear,1649	.nve_flood_index_set	= mlxsw_sp_fid_rfid_nve_flood_index_set,1650	.nve_flood_index_clear	= mlxsw_sp_fid_rfid_nve_flood_index_clear,1651	.vid_to_fid_rif_update	= mlxsw_sp_fid_rfid_vid_to_fid_rif_update,1652	.pgt_size		= mlxsw_sp_fid_rfid_pgt_size_cff,1653	.fid_port_init		= mlxsw_sp_fid_rfid_port_init_cff,1654	.fid_port_fini		= mlxsw_sp_fid_rfid_port_fini_cff,1655	.fid_mid		= mlxsw_sp_fid_fid_mid_cff,1656	.fid_pack		= mlxsw_sp_fid_fid_pack_cff,1657};1658 1659static int mlxsw_sp_fid_dummy_setup(struct mlxsw_sp_fid *fid, const void *arg)1660{1661	fid->fid_offset = 0;1662	return 0;1663}1664 1665static int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid *fid)1666{1667	return mlxsw_sp_fid_op(fid, true);1668}1669 1670static void mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid *fid)1671{1672	mlxsw_sp_fid_op(fid, false);1673}1674 1675static int mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid *fid,1676					  const void *arg, u16 *p_fid_index)1677{1678	*p_fid_index = fid->fid_family->start_index;1679 1680	return 0;1681}1682 1683static bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid,1684				       const void *arg)1685{1686	return true;1687}1688 1689static int mlxsw_sp_fid_dummy_vni_set(struct mlxsw_sp_fid *fid)1690{1691	return -EOPNOTSUPP;1692}1693 1694static void mlxsw_sp_fid_dummy_vni_clear(struct mlxsw_sp_fid *fid)1695{1696	WARN_ON_ONCE(1);1697}1698 1699static int mlxsw_sp_fid_dummy_nve_flood_index_set(struct mlxsw_sp_fid *fid)1700{1701	return -EOPNOTSUPP;1702}1703 1704static void mlxsw_sp_fid_dummy_nve_flood_index_clear(struct mlxsw_sp_fid *fid)1705{1706	WARN_ON_ONCE(1);1707}1708 1709static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = {1710	.setup			= mlxsw_sp_fid_dummy_setup,1711	.configure		= mlxsw_sp_fid_dummy_configure,1712	.deconfigure		= mlxsw_sp_fid_dummy_deconfigure,1713	.index_alloc		= mlxsw_sp_fid_dummy_index_alloc,1714	.compare		= mlxsw_sp_fid_dummy_compare,1715	.vni_set                = mlxsw_sp_fid_dummy_vni_set,1716	.vni_clear		= mlxsw_sp_fid_dummy_vni_clear,1717	.nve_flood_index_set	= mlxsw_sp_fid_dummy_nve_flood_index_set,1718	.nve_flood_index_clear	= mlxsw_sp_fid_dummy_nve_flood_index_clear,1719	.fid_pack		= mlxsw_sp_fid_pack,1720};1721 1722static int mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid *fid)1723{1724	struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid);1725	int err;1726 1727	err = mlxsw_sp_fid_op(fid, true);1728	if (err)1729		return err;1730 1731	err = mlxsw_sp_fid_vid_to_fid_map(fid, fid_8021q->vid, true, fid->rif);1732	if (err)1733		goto err_vid_to_fid_map;1734 1735	return 0;1736 1737err_vid_to_fid_map:1738	mlxsw_sp_fid_op(fid, false);1739	return err;1740}1741 1742static void mlxsw_sp_fid_8021q_deconfigure(struct mlxsw_sp_fid *fid)1743{1744	struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid);1745 1746	if (fid->vni_valid)1747		mlxsw_sp_nve_fid_disable(fid->fid_family->mlxsw_sp, fid);1748 1749	mlxsw_sp_fid_vid_to_fid_map(fid, fid_8021q->vid, false, NULL);1750	mlxsw_sp_fid_op(fid, false);1751}1752 1753static int mlxsw_sp_fid_8021q_port_vid_map(struct mlxsw_sp_fid *fid,1754					   struct mlxsw_sp_port *mlxsw_sp_port,1755					   u16 vid)1756{1757	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;1758	u16 local_port = mlxsw_sp_port->local_port;1759	int err;1760 1761	/* In case there are no {Port, VID} => FID mappings on the port,1762	 * we can use the global VID => FID mapping we created when the1763	 * FID was configured, otherwise, configure new mapping.1764	 */1765	if (mlxsw_sp->fid_core->port_fid_mappings[local_port]) {1766		err =  __mlxsw_sp_fid_port_vid_map(fid, local_port, vid, true);1767		if (err)1768			return err;1769	}1770 1771	err = mlxsw_sp_fid_evid_map(fid, local_port, vid, true);1772	if (err)1773		goto err_fid_evid_map;1774 1775	err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port,1776					     vid);1777	if (err)1778		goto err_port_vid_list_add;1779 1780	return 0;1781 1782err_port_vid_list_add:1783	 mlxsw_sp_fid_evid_map(fid, local_port, vid, false);1784err_fid_evid_map:1785	if (mlxsw_sp->fid_core->port_fid_mappings[local_port])1786		__mlxsw_sp_fid_port_vid_map(fid, local_port, vid, false);1787	return err;1788}1789 1790static void1791mlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid *fid,1792				  struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)1793{1794	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;1795	u16 local_port = mlxsw_sp_port->local_port;1796 1797	mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);1798	mlxsw_sp_fid_evid_map(fid, local_port, vid, false);1799	if (mlxsw_sp->fid_core->port_fid_mappings[local_port])1800		__mlxsw_sp_fid_port_vid_map(fid, local_port, vid, false);1801}1802 1803static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops_ctl = {1804	.setup			= mlxsw_sp_fid_8021q_setup,1805	.configure		= mlxsw_sp_fid_8021q_configure,1806	.deconfigure		= mlxsw_sp_fid_8021q_deconfigure,1807	.index_alloc		= mlxsw_sp_fid_8021d_index_alloc,1808	.compare		= mlxsw_sp_fid_8021q_compare,1809	.port_vid_map		= mlxsw_sp_fid_8021q_port_vid_map,1810	.port_vid_unmap		= mlxsw_sp_fid_8021q_port_vid_unmap,1811	.vni_set		= mlxsw_sp_fid_8021d_vni_set,1812	.vni_clear		= mlxsw_sp_fid_8021d_vni_clear,1813	.nve_flood_index_set	= mlxsw_sp_fid_8021d_nve_flood_index_set,1814	.nve_flood_index_clear	= mlxsw_sp_fid_8021d_nve_flood_index_clear,1815	.fdb_clear_offload	= mlxsw_sp_fid_8021q_fdb_clear_offload,1816	.vid_to_fid_rif_update  = mlxsw_sp_fid_8021q_vid_to_fid_rif_update,1817	.flood_table_init	= mlxsw_sp_fid_flood_table_init_ctl,1818	.pgt_size		= mlxsw_sp_fid_8021d_pgt_size,1819	.fid_mid		= mlxsw_sp_fid_fid_mid_ctl,1820	.fid_pack		= mlxsw_sp_fid_pack_ctl,1821};1822 1823static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops_cff = {1824	.setup			= mlxsw_sp_fid_8021q_setup,1825	.configure		= mlxsw_sp_fid_8021q_configure,1826	.deconfigure		= mlxsw_sp_fid_8021q_deconfigure,1827	.index_alloc		= mlxsw_sp_fid_8021d_index_alloc,1828	.compare		= mlxsw_sp_fid_8021q_compare,1829	.port_vid_map		= mlxsw_sp_fid_8021q_port_vid_map,1830	.port_vid_unmap		= mlxsw_sp_fid_8021q_port_vid_unmap,1831	.vni_set		= mlxsw_sp_fid_8021d_vni_set,1832	.vni_clear		= mlxsw_sp_fid_8021d_vni_clear,1833	.nve_flood_index_set	= mlxsw_sp_fid_8021d_nve_flood_index_set,1834	.nve_flood_index_clear	= mlxsw_sp_fid_8021d_nve_flood_index_clear,1835	.fdb_clear_offload	= mlxsw_sp_fid_8021q_fdb_clear_offload,1836	.vid_to_fid_rif_update	= mlxsw_sp_fid_8021q_vid_to_fid_rif_update,1837	.pgt_size		= mlxsw_sp_fid_8021d_pgt_size,1838	.fid_mid		= mlxsw_sp_fid_fid_mid_cff,1839	.fid_pack		= mlxsw_sp_fid_fid_pack_cff,1840};1841 1842/* There are 4K-2 802.1Q FIDs */1843#define MLXSW_SP_FID_8021Q_START	1 /* FID 0 is reserved. */1844#define MLXSW_SP_FID_8021Q_END		(MLXSW_SP_FID_8021Q_START + \1845					 MLXSW_SP_FID_8021Q_MAX - 1)1846 1847/* There are 1K 802.1D FIDs */1848#define MLXSW_SP_FID_8021D_START	(MLXSW_SP_FID_8021Q_END + 1)1849#define MLXSW_SP_FID_8021D_END		(MLXSW_SP_FID_8021D_START + \1850					 MLXSW_SP_FID_8021D_MAX - 1)1851 1852/* There is one dummy FID */1853#define MLXSW_SP_FID_DUMMY		(MLXSW_SP_FID_8021D_END + 1)1854 1855/* There are 11K rFIDs */1856#define MLXSW_SP_RFID_START		(MLXSW_SP_FID_DUMMY + 1)1857#define MLXSW_SP_RFID_END		(MLXSW_SP_RFID_START + \1858					 MLXSW_SP_FID_RFID_MAX - 1)1859 1860static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021q_family = {1861	.type			= MLXSW_SP_FID_TYPE_8021Q,1862	.fid_size		= sizeof(struct mlxsw_sp_fid_8021q),1863	.start_index		= MLXSW_SP_FID_8021Q_START,1864	.end_index		= MLXSW_SP_FID_8021Q_END,1865	.flood_profile		= &mlxsw_sp_fid_8021d_flood_profile,1866	.rif_type		= MLXSW_SP_RIF_TYPE_VLAN,1867	.ops			= &mlxsw_sp_fid_8021q_ops_ctl,1868	.flood_rsp              = false,1869	.bridge_type            = MLXSW_REG_BRIDGE_TYPE_0,1870	.smpe_index_valid	= false,1871};1872 1873static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021d_family = {1874	.type			= MLXSW_SP_FID_TYPE_8021D,1875	.fid_size		= sizeof(struct mlxsw_sp_fid_8021d),1876	.start_index		= MLXSW_SP_FID_8021D_START,1877	.end_index		= MLXSW_SP_FID_8021D_END,1878	.flood_profile		= &mlxsw_sp_fid_8021d_flood_profile,1879	.rif_type		= MLXSW_SP_RIF_TYPE_FID,1880	.ops			= &mlxsw_sp_fid_8021d_ops_ctl,1881	.bridge_type            = MLXSW_REG_BRIDGE_TYPE_1,1882	.smpe_index_valid       = false,1883};1884 1885static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_dummy_family = {1886	.type			= MLXSW_SP_FID_TYPE_DUMMY,1887	.fid_size		= sizeof(struct mlxsw_sp_fid),1888	.start_index		= MLXSW_SP_FID_DUMMY,1889	.end_index		= MLXSW_SP_FID_DUMMY,1890	.ops			= &mlxsw_sp_fid_dummy_ops,1891	.smpe_index_valid       = false,1892};1893 1894static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family_ctl = {1895	.type			= MLXSW_SP_FID_TYPE_RFID,1896	.fid_size		= sizeof(struct mlxsw_sp_fid),1897	.start_index		= MLXSW_SP_RFID_START,1898	.end_index		= MLXSW_SP_RFID_END,1899	.rif_type		= MLXSW_SP_RIF_TYPE_SUBPORT,1900	.ops			= &mlxsw_sp_fid_rfid_ops_ctl,1901	.flood_rsp              = true,1902	.smpe_index_valid       = false,1903};1904 1905static const struct mlxsw_sp_fid_family *mlxsw_sp1_fid_family_arr[] = {1906	[MLXSW_SP_FID_TYPE_8021Q]	= &mlxsw_sp1_fid_8021q_family,1907	[MLXSW_SP_FID_TYPE_8021D]	= &mlxsw_sp1_fid_8021d_family,1908	[MLXSW_SP_FID_TYPE_DUMMY]	= &mlxsw_sp1_fid_dummy_family,1909	[MLXSW_SP_FID_TYPE_RFID]	= &mlxsw_sp_fid_rfid_family_ctl,1910};1911 1912static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021q_family_ctl = {1913	.type			= MLXSW_SP_FID_TYPE_8021Q,1914	.fid_size		= sizeof(struct mlxsw_sp_fid_8021q),1915	.start_index		= MLXSW_SP_FID_8021Q_START,1916	.end_index		= MLXSW_SP_FID_8021Q_END,1917	.flood_profile		= &mlxsw_sp_fid_8021d_flood_profile,1918	.rif_type		= MLXSW_SP_RIF_TYPE_VLAN,1919	.ops			= &mlxsw_sp_fid_8021q_ops_ctl,1920	.flood_rsp              = false,1921	.bridge_type            = MLXSW_REG_BRIDGE_TYPE_0,1922	.smpe_index_valid	= true,1923};1924 1925static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021d_family_ctl = {1926	.type			= MLXSW_SP_FID_TYPE_8021D,1927	.fid_size		= sizeof(struct mlxsw_sp_fid_8021d),1928	.start_index		= MLXSW_SP_FID_8021D_START,1929	.end_index		= MLXSW_SP_FID_8021D_END,1930	.flood_profile		= &mlxsw_sp_fid_8021d_flood_profile,1931	.rif_type		= MLXSW_SP_RIF_TYPE_FID,1932	.ops			= &mlxsw_sp_fid_8021d_ops_ctl,1933	.bridge_type            = MLXSW_REG_BRIDGE_TYPE_1,1934	.smpe_index_valid       = true,1935};1936 1937static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_dummy_family = {1938	.type			= MLXSW_SP_FID_TYPE_DUMMY,1939	.fid_size		= sizeof(struct mlxsw_sp_fid),1940	.start_index		= MLXSW_SP_FID_DUMMY,1941	.end_index		= MLXSW_SP_FID_DUMMY,1942	.ops			= &mlxsw_sp_fid_dummy_ops,1943	.smpe_index_valid       = false,1944};1945 1946static const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr_ctl[] = {1947	[MLXSW_SP_FID_TYPE_8021Q]	= &mlxsw_sp2_fid_8021q_family_ctl,1948	[MLXSW_SP_FID_TYPE_8021D]	= &mlxsw_sp2_fid_8021d_family_ctl,1949	[MLXSW_SP_FID_TYPE_DUMMY]	= &mlxsw_sp2_fid_dummy_family,1950	[MLXSW_SP_FID_TYPE_RFID]	= &mlxsw_sp_fid_rfid_family_ctl,1951};1952 1953static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021q_family_cff = {1954	.type			= MLXSW_SP_FID_TYPE_8021Q,1955	.fid_size		= sizeof(struct mlxsw_sp_fid_8021q),1956	.start_index		= MLXSW_SP_FID_8021Q_START,1957	.end_index		= MLXSW_SP_FID_8021Q_END,1958	.flood_profile		= &mlxsw_sp_fid_8021d_flood_profile,1959	.rif_type		= MLXSW_SP_RIF_TYPE_VLAN,1960	.ops			= &mlxsw_sp_fid_8021q_ops_cff,1961	.smpe_index_valid	= true,1962};1963 1964static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021d_family_cff = {1965	.type			= MLXSW_SP_FID_TYPE_8021D,1966	.fid_size		= sizeof(struct mlxsw_sp_fid_8021d),1967	.start_index		= MLXSW_SP_FID_8021D_START,1968	.end_index		= MLXSW_SP_FID_8021D_END,1969	.flood_profile		= &mlxsw_sp_fid_8021d_flood_profile,1970	.rif_type		= MLXSW_SP_RIF_TYPE_FID,1971	.ops			= &mlxsw_sp_fid_8021d_ops_cff,1972	.smpe_index_valid	= true,1973};1974 1975static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family_cff = {1976	.type			= MLXSW_SP_FID_TYPE_RFID,1977	.fid_size		= sizeof(struct mlxsw_sp_fid),1978	.start_index		= MLXSW_SP_RFID_START,1979	.end_index		= MLXSW_SP_RFID_END,1980	.flood_profile		= &mlxsw_sp_fid_rsp_flood_profile_cff,1981	.rif_type		= MLXSW_SP_RIF_TYPE_SUBPORT,1982	.ops			= &mlxsw_sp_fid_rfid_ops_cff,1983	.smpe_index_valid	= false,1984};1985 1986static const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr_cff[] = {1987	[MLXSW_SP_FID_TYPE_8021Q]	= &mlxsw_sp2_fid_8021q_family_cff,1988	[MLXSW_SP_FID_TYPE_8021D]	= &mlxsw_sp2_fid_8021d_family_cff,1989	[MLXSW_SP_FID_TYPE_DUMMY]	= &mlxsw_sp2_fid_dummy_family,1990	[MLXSW_SP_FID_TYPE_RFID]	= &mlxsw_sp_fid_rfid_family_cff,1991};1992 1993static struct mlxsw_sp_fid *mlxsw_sp_fid_lookup(struct mlxsw_sp *mlxsw_sp,1994						enum mlxsw_sp_fid_type type,1995						const void *arg)1996{1997	struct mlxsw_sp_fid_family *fid_family;1998	struct mlxsw_sp_fid *fid;1999 2000	fid_family = mlxsw_sp->fid_core->fid_family_arr[type];2001	list_for_each_entry(fid, &fid_family->fids_list, list) {2002		if (!fid->fid_family->ops->compare(fid, arg))2003			continue;2004		refcount_inc(&fid->ref_count);2005		return fid;2006	}2007 2008	return NULL;2009}2010 2011static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp,2012					     enum mlxsw_sp_fid_type type,2013					     const void *arg)2014{2015	struct mlxsw_sp_fid_family *fid_family;2016	struct mlxsw_sp_fid *fid;2017	u16 fid_index;2018	int err;2019 2020	fid = mlxsw_sp_fid_lookup(mlxsw_sp, type, arg);2021	if (fid)2022		return fid;2023 2024	fid_family = mlxsw_sp->fid_core->fid_family_arr[type];2025	fid = kzalloc(fid_family->fid_size, GFP_KERNEL);2026	if (!fid)2027		return ERR_PTR(-ENOMEM);2028 2029	INIT_LIST_HEAD(&fid->port_vid_list);2030	fid->fid_family = fid_family;2031 2032	err = fid->fid_family->ops->index_alloc(fid, arg, &fid_index);2033	if (err)2034		goto err_index_alloc;2035	fid->fid_index = fid_index;2036	__set_bit(fid_index - fid_family->start_index, fid_family->fids_bitmap);2037 2038	err = fid->fid_family->ops->setup(fid, arg);2039	if (err)2040		goto err_setup;2041 2042	err = fid->fid_family->ops->configure(fid);2043	if (err)2044		goto err_configure;2045 2046	err = rhashtable_insert_fast(&mlxsw_sp->fid_core->fid_ht, &fid->ht_node,2047				     mlxsw_sp_fid_ht_params);2048	if (err)2049		goto err_rhashtable_insert;2050 2051	list_add(&fid->list, &fid_family->fids_list);2052	refcount_set(&fid->ref_count, 1);2053	return fid;2054 2055err_rhashtable_insert:2056	fid->fid_family->ops->deconfigure(fid);2057err_configure:2058err_setup:2059	__clear_bit(fid_index - fid_family->start_index,2060		    fid_family->fids_bitmap);2061err_index_alloc:2062	kfree(fid);2063	return ERR_PTR(err);2064}2065 2066void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid)2067{2068	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;2069	struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;2070 2071	if (!refcount_dec_and_test(&fid->ref_count))2072		return;2073 2074	list_del(&fid->list);2075	rhashtable_remove_fast(&mlxsw_sp->fid_core->fid_ht,2076			       &fid->ht_node, mlxsw_sp_fid_ht_params);2077	fid->fid_family->ops->deconfigure(fid);2078	__clear_bit(fid->fid_index - fid_family->start_index,2079		    fid_family->fids_bitmap);2080	WARN_ON_ONCE(!list_empty(&fid->port_vid_list));2081	kfree(fid);2082}2083 2084struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid)2085{2086	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid);2087}2088 2089struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp,2090					    int br_ifindex)2091{2092	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, &br_ifindex);2093}2094 2095struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_lookup(struct mlxsw_sp *mlxsw_sp,2096					       u16 vid)2097{2098	return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid);2099}2100 2101struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_lookup(struct mlxsw_sp *mlxsw_sp,2102					       int br_ifindex)2103{2104	return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D,2105				   &br_ifindex);2106}2107 2108struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp,2109					   u16 rif_index)2110{2111	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_RFID, &rif_index);2112}2113 2114struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp)2115{2116	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_DUMMY, NULL);2117}2118 2119static int2120mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family)2121{2122	struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;2123	u16 pgt_size;2124	int err;2125	int i;2126 2127	err = fid_family->ops->pgt_size(fid_family, &pgt_size);2128	if (err)2129		return err;2130 2131	err = mlxsw_sp_pgt_mid_alloc_range(mlxsw_sp, &fid_family->pgt_base,2132					   pgt_size);2133	if (err)2134		return err;2135 2136	if (!fid_family->flood_profile)2137		return 0;2138 2139	for (i = 0; i < fid_family->flood_profile->nr_flood_tables; i++) {2140		const struct mlxsw_sp_flood_table *flood_table;2141 2142		flood_table = &fid_family->flood_profile->flood_tables[i];2143		if (fid_family->ops->flood_table_init) {2144			err = fid_family->ops->flood_table_init(fid_family,2145								flood_table);2146			if (err)2147				goto err_flood_table_init;2148		}2149	}2150 2151	return 0;2152 2153err_flood_table_init:2154	mlxsw_sp_pgt_mid_free_range(mlxsw_sp, fid_family->pgt_base, pgt_size);2155	return err;2156}2157 2158static void2159mlxsw_sp_fid_flood_tables_fini(struct mlxsw_sp_fid_family *fid_family)2160{2161	struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;2162	u16 pgt_size;2163	int err;2164 2165	err = fid_family->ops->pgt_size(fid_family, &pgt_size);2166	if (WARN_ON_ONCE(err))2167		return;2168 2169	mlxsw_sp_pgt_mid_free_range(mlxsw_sp, fid_family->pgt_base, pgt_size);2170}2171 2172static int mlxsw_sp_fid_family_register(struct mlxsw_sp *mlxsw_sp,2173					const struct mlxsw_sp_fid_family *tmpl)2174{2175	u16 nr_fids = tmpl->end_index - tmpl->start_index + 1;2176	struct mlxsw_sp_fid_family *fid_family;2177	int err;2178 2179	fid_family = kmemdup(tmpl, sizeof(*fid_family), GFP_KERNEL);2180	if (!fid_family)2181		return -ENOMEM;2182 2183	fid_family->mlxsw_sp = mlxsw_sp;2184	INIT_LIST_HEAD(&fid_family->fids_list);2185	fid_family->fids_bitmap = bitmap_zalloc(nr_fids, GFP_KERNEL);2186	if (!fid_family->fids_bitmap) {2187		err = -ENOMEM;2188		goto err_alloc_fids_bitmap;2189	}2190 2191	if (fid_family->flood_profile) {2192		err = mlxsw_sp_fid_flood_tables_init(fid_family);2193		if (err)2194			goto err_fid_flood_tables_init;2195	}2196 2197	mlxsw_sp->fid_core->fid_family_arr[tmpl->type] = fid_family;2198 2199	return 0;2200 2201err_fid_flood_tables_init:2202	bitmap_free(fid_family->fids_bitmap);2203err_alloc_fids_bitmap:2204	kfree(fid_family);2205	return err;2206}2207 2208static void2209mlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp,2210			       struct mlxsw_sp_fid_family *fid_family)2211{2212	mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL;2213 2214	if (fid_family->flood_profile)2215		mlxsw_sp_fid_flood_tables_fini(fid_family);2216 2217	bitmap_free(fid_family->fids_bitmap);2218	WARN_ON_ONCE(!list_empty(&fid_family->fids_list));2219	kfree(fid_family);2220}2221 2222static int mlxsw_sp_fid_port_init(const struct mlxsw_sp_port *mlxsw_sp_port)2223{2224	const enum mlxsw_sp_fid_type type_rfid = MLXSW_SP_FID_TYPE_RFID;2225	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;2226	struct mlxsw_sp_fid_family *rfid_family;2227 2228	rfid_family = mlxsw_sp->fid_core->fid_family_arr[type_rfid];2229	if (rfid_family->ops->fid_port_init)2230		return rfid_family->ops->fid_port_init(rfid_family,2231						       mlxsw_sp_port);2232	return 0;2233}2234 2235static void mlxsw_sp_fid_port_fini(const struct mlxsw_sp_port *mlxsw_sp_port)2236{2237	const enum mlxsw_sp_fid_type type_rfid = MLXSW_SP_FID_TYPE_RFID;2238	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;2239	struct mlxsw_sp_fid_family *rfid_family;2240 2241	rfid_family = mlxsw_sp->fid_core->fid_family_arr[type_rfid];2242	if (rfid_family->ops->fid_port_fini)2243		rfid_family->ops->fid_port_fini(rfid_family, mlxsw_sp_port);2244}2245 2246int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port)2247{2248	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;2249	int err;2250 2251	/* Track number of FIDs configured on the port with mapping type2252	 * PORT_VID_TO_FID, so that we know when to transition the port2253	 * back to non-virtual (VLAN) mode.2254	 */2255	mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;2256 2257	err = mlxsw_sp_fid_port_init(mlxsw_sp_port);2258	if (err)2259		return err;2260 2261	err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);2262	if (err)2263		goto err_vp_mode_set;2264 2265	return 0;2266 2267err_vp_mode_set:2268	mlxsw_sp_fid_port_fini(mlxsw_sp_port);2269	return err;2270}2271 2272void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port)2273{2274	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;2275 2276	mlxsw_sp_fid_port_fini(mlxsw_sp_port);2277	mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;2278}2279 2280int mlxsw_sp_fid_port_join_lag(const struct mlxsw_sp_port *mlxsw_sp_port)2281{2282	return mlxsw_sp_fid_port_init(mlxsw_sp_port);2283}2284 2285void mlxsw_sp_fid_port_leave_lag(const struct mlxsw_sp_port *mlxsw_sp_port)2286{2287	mlxsw_sp_fid_port_fini(mlxsw_sp_port);2288}2289 2290static int2291mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp,2292		   const struct mlxsw_sp_fid_family *fid_family_arr[])2293{2294	unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);2295	struct mlxsw_sp_fid_core *fid_core;2296	int err, i;2297 2298	fid_core = kzalloc(sizeof(*mlxsw_sp->fid_core), GFP_KERNEL);2299	if (!fid_core)2300		return -ENOMEM;2301	mlxsw_sp->fid_core = fid_core;2302 2303	err = rhashtable_init(&fid_core->fid_ht, &mlxsw_sp_fid_ht_params);2304	if (err)2305		goto err_rhashtable_fid_init;2306 2307	err = rhashtable_init(&fid_core->vni_ht, &mlxsw_sp_fid_vni_ht_params);2308	if (err)2309		goto err_rhashtable_vni_init;2310 2311	fid_core->port_fid_mappings = kcalloc(max_ports, sizeof(unsigned int),2312					      GFP_KERNEL);2313	if (!fid_core->port_fid_mappings) {2314		err = -ENOMEM;2315		goto err_alloc_port_fid_mappings;2316	}2317 2318	for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) {2319		err = mlxsw_sp_fid_family_register(mlxsw_sp, fid_family_arr[i]);2320 2321		if (err)2322			goto err_fid_ops_register;2323	}2324 2325	return 0;2326 2327err_fid_ops_register:2328	for (i--; i >= 0; i--) {2329		struct mlxsw_sp_fid_family *fid_family;2330 2331		fid_family = fid_core->fid_family_arr[i];2332		mlxsw_sp_fid_family_unregister(mlxsw_sp, fid_family);2333	}2334	kfree(fid_core->port_fid_mappings);2335err_alloc_port_fid_mappings:2336	rhashtable_destroy(&fid_core->vni_ht);2337err_rhashtable_vni_init:2338	rhashtable_destroy(&fid_core->fid_ht);2339err_rhashtable_fid_init:2340	kfree(fid_core);2341	return err;2342}2343 2344static void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp)2345{2346	struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;2347	int i;2348 2349	for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++)2350		mlxsw_sp_fid_family_unregister(mlxsw_sp,2351					       fid_core->fid_family_arr[i]);2352	kfree(fid_core->port_fid_mappings);2353	rhashtable_destroy(&fid_core->vni_ht);2354	rhashtable_destroy(&fid_core->fid_ht);2355	kfree(fid_core);2356}2357 2358static int mlxsw_sp1_fids_init(struct mlxsw_sp *mlxsw_sp)2359{2360	return mlxsw_sp_fids_init(mlxsw_sp, mlxsw_sp1_fid_family_arr);2361}2362 2363const struct mlxsw_sp_fid_core_ops mlxsw_sp1_fid_core_ops = {2364	.init = mlxsw_sp1_fids_init,2365	.fini = mlxsw_sp_fids_fini,2366};2367 2368static int mlxsw_sp_fid_check_flood_profile_id(struct mlxsw_sp *mlxsw_sp,2369					       int profile_id)2370{2371	u32 max_profiles;2372 2373	if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_NVE_FLOOD_PRF))2374		return -EIO;2375 2376	max_profiles = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_NVE_FLOOD_PRF);2377	if (WARN_ON_ONCE(!profile_id) ||2378	    WARN_ON_ONCE(profile_id >= max_profiles))2379		return -EINVAL;2380 2381	return 0;2382}2383 2384static int2385mlxsw_sp2_fids_init_flood_table(struct mlxsw_sp *mlxsw_sp,2386				enum mlxsw_sp_fid_flood_profile_id profile_id,2387				const struct mlxsw_sp_flood_table *flood_table)2388{2389	enum mlxsw_sp_flood_type packet_type = flood_table->packet_type;2390	const int *sfgc_packet_types;2391	int err;2392	int i;2393 2394	sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type];2395	for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) {2396		char sffp_pl[MLXSW_REG_SFFP_LEN];2397 2398		if (!sfgc_packet_types[i])2399			continue;2400 2401		mlxsw_reg_sffp_pack(sffp_pl, profile_id, i,2402				    flood_table->table_index);2403		err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sffp), sffp_pl);2404		if (err)2405			return err;2406	}2407 2408	return 0;2409}2410 2411static int2412mlxsw_sp2_fids_init_flood_profile(struct mlxsw_sp *mlxsw_sp,2413				  const struct mlxsw_sp_fid_flood_profile *2414					flood_profile)2415{2416	int err;2417	int i;2418 2419	err = mlxsw_sp_fid_check_flood_profile_id(mlxsw_sp,2420						  flood_profile->profile_id);2421	if (err)2422		return err;2423 2424	for (i = 0; i < flood_profile->nr_flood_tables; i++) {2425		const struct mlxsw_sp_flood_table *flood_table;2426 2427		flood_table = &flood_profile->flood_tables[i];2428		err = mlxsw_sp2_fids_init_flood_table(mlxsw_sp,2429						      flood_profile->profile_id,2430						      flood_table);2431		if (err)2432			return err;2433	}2434 2435	return 0;2436}2437 2438static const2439struct mlxsw_sp_fid_flood_profile *mlxsw_sp_fid_flood_profiles[] = {2440	&mlxsw_sp_fid_8021d_flood_profile,2441	&mlxsw_sp_fid_rsp_flood_profile_cff,2442	&mlxsw_sp_fid_nve_flood_profile_cff,2443};2444 2445static int2446mlxsw_sp2_fids_init_flood_profiles(struct mlxsw_sp *mlxsw_sp)2447{2448	int err;2449	int i;2450 2451	for (i = 0; i < ARRAY_SIZE(mlxsw_sp_fid_flood_profiles); i++) {2452		const struct mlxsw_sp_fid_flood_profile *flood_profile;2453 2454		flood_profile = mlxsw_sp_fid_flood_profiles[i];2455		err = mlxsw_sp2_fids_init_flood_profile(mlxsw_sp,2456							flood_profile);2457		if (err)2458			return err;2459	}2460 2461	return 0;2462}2463 2464static int mlxsw_sp2_fids_init_ctl(struct mlxsw_sp *mlxsw_sp)2465{2466	return mlxsw_sp_fids_init(mlxsw_sp, mlxsw_sp2_fid_family_arr_ctl);2467}2468 2469static int mlxsw_sp2_fids_init_cff(struct mlxsw_sp *mlxsw_sp)2470{2471	int err;2472 2473	err = mlxsw_sp2_fids_init_flood_profiles(mlxsw_sp);2474	if (err)2475		return err;2476 2477	return mlxsw_sp_fids_init(mlxsw_sp, mlxsw_sp2_fid_family_arr_cff);2478}2479 2480static int mlxsw_sp2_fids_init(struct mlxsw_sp *mlxsw_sp)2481{2482	switch (mlxsw_core_flood_mode(mlxsw_sp->core)) {2483	case MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CONTROLLED:2484		return mlxsw_sp2_fids_init_ctl(mlxsw_sp);2485	case MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CFF:2486		return mlxsw_sp2_fids_init_cff(mlxsw_sp);2487	default:2488		WARN_ON_ONCE(1);2489		return -EINVAL;2490	}2491}2492 2493const struct mlxsw_sp_fid_core_ops mlxsw_sp2_fid_core_ops = {2494	.init = mlxsw_sp2_fids_init,2495	.fini = mlxsw_sp_fids_fini,2496};2497