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