spectrum_fid.c (33092B)
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2/* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */ 3 4#include <linux/kernel.h> 5#include <linux/bitops.h> 6#include <linux/if_vlan.h> 7#include <linux/if_bridge.h> 8#include <linux/netdevice.h> 9#include <linux/rhashtable.h> 10#include <linux/rtnetlink.h> 11#include <linux/refcount.h> 12 13#include "spectrum.h" 14#include "reg.h" 15 16struct mlxsw_sp_fid_family; 17 18struct mlxsw_sp_fid_core { 19 struct rhashtable fid_ht; 20 struct rhashtable vni_ht; 21 struct mlxsw_sp_fid_family *fid_family_arr[MLXSW_SP_FID_TYPE_MAX]; 22 unsigned int *port_fid_mappings; 23}; 24 25struct mlxsw_sp_fid { 26 struct list_head list; 27 struct mlxsw_sp_rif *rif; 28 refcount_t ref_count; 29 u16 fid_index; 30 struct mlxsw_sp_fid_family *fid_family; 31 struct rhash_head ht_node; 32 33 struct rhash_head vni_ht_node; 34 enum mlxsw_sp_nve_type nve_type; 35 __be32 vni; 36 u32 nve_flood_index; 37 int nve_ifindex; 38 u8 vni_valid:1, 39 nve_flood_index_valid:1; 40}; 41 42struct mlxsw_sp_fid_8021q { 43 struct mlxsw_sp_fid common; 44 u16 vid; 45}; 46 47struct mlxsw_sp_fid_8021d { 48 struct mlxsw_sp_fid common; 49 int br_ifindex; 50}; 51 52static const struct rhashtable_params mlxsw_sp_fid_ht_params = { 53 .key_len = sizeof_field(struct mlxsw_sp_fid, fid_index), 54 .key_offset = offsetof(struct mlxsw_sp_fid, fid_index), 55 .head_offset = offsetof(struct mlxsw_sp_fid, ht_node), 56}; 57 58static const struct rhashtable_params mlxsw_sp_fid_vni_ht_params = { 59 .key_len = sizeof_field(struct mlxsw_sp_fid, vni), 60 .key_offset = offsetof(struct mlxsw_sp_fid, vni), 61 .head_offset = offsetof(struct mlxsw_sp_fid, vni_ht_node), 62}; 63 64struct mlxsw_sp_flood_table { 65 enum mlxsw_sp_flood_type packet_type; 66 enum mlxsw_reg_sfgc_bridge_type bridge_type; 67 enum mlxsw_flood_table_type table_type; 68 int table_index; 69}; 70 71struct mlxsw_sp_fid_ops { 72 void (*setup)(struct mlxsw_sp_fid *fid, const void *arg); 73 int (*configure)(struct mlxsw_sp_fid *fid); 74 void (*deconfigure)(struct mlxsw_sp_fid *fid); 75 int (*index_alloc)(struct mlxsw_sp_fid *fid, const void *arg, 76 u16 *p_fid_index); 77 bool (*compare)(const struct mlxsw_sp_fid *fid, 78 const void *arg); 79 u16 (*flood_index)(const struct mlxsw_sp_fid *fid); 80 int (*port_vid_map)(struct mlxsw_sp_fid *fid, 81 struct mlxsw_sp_port *port, u16 vid); 82 void (*port_vid_unmap)(struct mlxsw_sp_fid *fid, 83 struct mlxsw_sp_port *port, u16 vid); 84 int (*vni_set)(struct mlxsw_sp_fid *fid, __be32 vni); 85 void (*vni_clear)(struct mlxsw_sp_fid *fid); 86 int (*nve_flood_index_set)(struct mlxsw_sp_fid *fid, 87 u32 nve_flood_index); 88 void (*nve_flood_index_clear)(struct mlxsw_sp_fid *fid); 89 void (*fdb_clear_offload)(const struct mlxsw_sp_fid *fid, 90 const struct net_device *nve_dev); 91}; 92 93struct mlxsw_sp_fid_family { 94 enum mlxsw_sp_fid_type type; 95 size_t fid_size; 96 u16 start_index; 97 u16 end_index; 98 struct list_head fids_list; 99 unsigned long *fids_bitmap; 100 const struct mlxsw_sp_flood_table *flood_tables; 101 int nr_flood_tables; 102 enum mlxsw_sp_rif_type rif_type; 103 const struct mlxsw_sp_fid_ops *ops; 104 struct mlxsw_sp *mlxsw_sp; 105 u8 lag_vid_valid:1; 106}; 107 108static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { 109 [MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST] = 1, 110}; 111 112static const int mlxsw_sp_sfgc_bc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { 113 [MLXSW_REG_SFGC_TYPE_BROADCAST] = 1, 114 [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP] = 1, 115 [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL] = 1, 116 [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST] = 1, 117 [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1, 118}; 119 120static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { 121 [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1, 122}; 123 124static const int *mlxsw_sp_packet_type_sfgc_types[] = { 125 [MLXSW_SP_FLOOD_TYPE_UC] = mlxsw_sp_sfgc_uc_packet_types, 126 [MLXSW_SP_FLOOD_TYPE_BC] = mlxsw_sp_sfgc_bc_packet_types, 127 [MLXSW_SP_FLOOD_TYPE_MC] = mlxsw_sp_sfgc_mc_packet_types, 128}; 129 130bool mlxsw_sp_fid_is_dummy(struct mlxsw_sp *mlxsw_sp, u16 fid_index) 131{ 132 enum mlxsw_sp_fid_type fid_type = MLXSW_SP_FID_TYPE_DUMMY; 133 struct mlxsw_sp_fid_family *fid_family; 134 135 fid_family = mlxsw_sp->fid_core->fid_family_arr[fid_type]; 136 137 return fid_family->start_index == fid_index; 138} 139 140bool mlxsw_sp_fid_lag_vid_valid(const struct mlxsw_sp_fid *fid) 141{ 142 return fid->fid_family->lag_vid_valid; 143} 144 145struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp, 146 u16 fid_index) 147{ 148 struct mlxsw_sp_fid *fid; 149 150 fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->fid_ht, &fid_index, 151 mlxsw_sp_fid_ht_params); 152 if (fid) 153 refcount_inc(&fid->ref_count); 154 155 return fid; 156} 157 158int mlxsw_sp_fid_nve_ifindex(const struct mlxsw_sp_fid *fid, int *nve_ifindex) 159{ 160 if (!fid->vni_valid) 161 return -EINVAL; 162 163 *nve_ifindex = fid->nve_ifindex; 164 165 return 0; 166} 167 168int mlxsw_sp_fid_nve_type(const struct mlxsw_sp_fid *fid, 169 enum mlxsw_sp_nve_type *p_type) 170{ 171 if (!fid->vni_valid) 172 return -EINVAL; 173 174 *p_type = fid->nve_type; 175 176 return 0; 177} 178 179struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_vni(struct mlxsw_sp *mlxsw_sp, 180 __be32 vni) 181{ 182 struct mlxsw_sp_fid *fid; 183 184 fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->vni_ht, &vni, 185 mlxsw_sp_fid_vni_ht_params); 186 if (fid) 187 refcount_inc(&fid->ref_count); 188 189 return fid; 190} 191 192int mlxsw_sp_fid_vni(const struct mlxsw_sp_fid *fid, __be32 *vni) 193{ 194 if (!fid->vni_valid) 195 return -EINVAL; 196 197 *vni = fid->vni; 198 199 return 0; 200} 201 202int mlxsw_sp_fid_nve_flood_index_set(struct mlxsw_sp_fid *fid, 203 u32 nve_flood_index) 204{ 205 struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 206 const struct mlxsw_sp_fid_ops *ops = fid_family->ops; 207 int err; 208 209 if (WARN_ON(!ops->nve_flood_index_set || fid->nve_flood_index_valid)) 210 return -EINVAL; 211 212 err = ops->nve_flood_index_set(fid, nve_flood_index); 213 if (err) 214 return err; 215 216 fid->nve_flood_index = nve_flood_index; 217 fid->nve_flood_index_valid = true; 218 219 return 0; 220} 221 222void mlxsw_sp_fid_nve_flood_index_clear(struct mlxsw_sp_fid *fid) 223{ 224 struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 225 const struct mlxsw_sp_fid_ops *ops = fid_family->ops; 226 227 if (WARN_ON(!ops->nve_flood_index_clear || !fid->nve_flood_index_valid)) 228 return; 229 230 fid->nve_flood_index_valid = false; 231 ops->nve_flood_index_clear(fid); 232} 233 234bool mlxsw_sp_fid_nve_flood_index_is_set(const struct mlxsw_sp_fid *fid) 235{ 236 return fid->nve_flood_index_valid; 237} 238 239int mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid *fid, enum mlxsw_sp_nve_type type, 240 __be32 vni, int nve_ifindex) 241{ 242 struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 243 const struct mlxsw_sp_fid_ops *ops = fid_family->ops; 244 struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; 245 int err; 246 247 if (WARN_ON(!ops->vni_set || fid->vni_valid)) 248 return -EINVAL; 249 250 fid->nve_type = type; 251 fid->nve_ifindex = nve_ifindex; 252 fid->vni = vni; 253 err = rhashtable_lookup_insert_fast(&mlxsw_sp->fid_core->vni_ht, 254 &fid->vni_ht_node, 255 mlxsw_sp_fid_vni_ht_params); 256 if (err) 257 return err; 258 259 err = ops->vni_set(fid, vni); 260 if (err) 261 goto err_vni_set; 262 263 fid->vni_valid = true; 264 265 return 0; 266 267err_vni_set: 268 rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node, 269 mlxsw_sp_fid_vni_ht_params); 270 return err; 271} 272 273void mlxsw_sp_fid_vni_clear(struct mlxsw_sp_fid *fid) 274{ 275 struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 276 const struct mlxsw_sp_fid_ops *ops = fid_family->ops; 277 struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; 278 279 if (WARN_ON(!ops->vni_clear || !fid->vni_valid)) 280 return; 281 282 fid->vni_valid = false; 283 ops->vni_clear(fid); 284 rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node, 285 mlxsw_sp_fid_vni_ht_params); 286} 287 288bool mlxsw_sp_fid_vni_is_set(const struct mlxsw_sp_fid *fid) 289{ 290 return fid->vni_valid; 291} 292 293void mlxsw_sp_fid_fdb_clear_offload(const struct mlxsw_sp_fid *fid, 294 const struct net_device *nve_dev) 295{ 296 struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 297 const struct mlxsw_sp_fid_ops *ops = fid_family->ops; 298 299 if (ops->fdb_clear_offload) 300 ops->fdb_clear_offload(fid, nve_dev); 301} 302 303static const struct mlxsw_sp_flood_table * 304mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid, 305 enum mlxsw_sp_flood_type packet_type) 306{ 307 struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 308 int i; 309 310 for (i = 0; i < fid_family->nr_flood_tables; i++) { 311 if (fid_family->flood_tables[i].packet_type != packet_type) 312 continue; 313 return &fid_family->flood_tables[i]; 314 } 315 316 return NULL; 317} 318 319int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid, 320 enum mlxsw_sp_flood_type packet_type, u16 local_port, 321 bool member) 322{ 323 struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 324 const struct mlxsw_sp_fid_ops *ops = fid_family->ops; 325 const struct mlxsw_sp_flood_table *flood_table; 326 char *sftr2_pl; 327 int err; 328 329 if (WARN_ON(!fid_family->flood_tables || !ops->flood_index)) 330 return -EINVAL; 331 332 flood_table = mlxsw_sp_fid_flood_table_lookup(fid, packet_type); 333 if (!flood_table) 334 return -ESRCH; 335 336 sftr2_pl = kmalloc(MLXSW_REG_SFTR2_LEN, GFP_KERNEL); 337 if (!sftr2_pl) 338 return -ENOMEM; 339 340 mlxsw_reg_sftr2_pack(sftr2_pl, flood_table->table_index, 341 ops->flood_index(fid), flood_table->table_type, 1, 342 local_port, member); 343 err = mlxsw_reg_write(fid_family->mlxsw_sp->core, MLXSW_REG(sftr2), 344 sftr2_pl); 345 kfree(sftr2_pl); 346 return err; 347} 348 349int mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid *fid, 350 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) 351{ 352 if (WARN_ON(!fid->fid_family->ops->port_vid_map)) 353 return -EINVAL; 354 return fid->fid_family->ops->port_vid_map(fid, mlxsw_sp_port, vid); 355} 356 357void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid, 358 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) 359{ 360 fid->fid_family->ops->port_vid_unmap(fid, mlxsw_sp_port, vid); 361} 362 363u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid) 364{ 365 return fid->fid_index; 366} 367 368enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid) 369{ 370 return fid->fid_family->type; 371} 372 373void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif) 374{ 375 fid->rif = rif; 376} 377 378struct mlxsw_sp_rif *mlxsw_sp_fid_rif(const struct mlxsw_sp_fid *fid) 379{ 380 return fid->rif; 381} 382 383enum mlxsw_sp_rif_type 384mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp, 385 enum mlxsw_sp_fid_type type) 386{ 387 struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core; 388 389 return fid_core->fid_family_arr[type]->rif_type; 390} 391 392static struct mlxsw_sp_fid_8021q * 393mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid) 394{ 395 return container_of(fid, struct mlxsw_sp_fid_8021q, common); 396} 397 398u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid) 399{ 400 return mlxsw_sp_fid_8021q_fid(fid)->vid; 401} 402 403static void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg) 404{ 405 u16 vid = *(u16 *) arg; 406 407 mlxsw_sp_fid_8021q_fid(fid)->vid = vid; 408} 409 410static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid) 411{ 412 return valid ? MLXSW_REG_SFMR_OP_CREATE_FID : 413 MLXSW_REG_SFMR_OP_DESTROY_FID; 414} 415 416static int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index, 417 u16 fid_offset, bool valid) 418{ 419 char sfmr_pl[MLXSW_REG_SFMR_LEN]; 420 421 mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid_index, 422 fid_offset); 423 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl); 424} 425 426static int mlxsw_sp_fid_vni_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index, 427 __be32 vni, bool vni_valid, u32 nve_flood_index, 428 bool nve_flood_index_valid) 429{ 430 char sfmr_pl[MLXSW_REG_SFMR_LEN]; 431 432 mlxsw_reg_sfmr_pack(sfmr_pl, MLXSW_REG_SFMR_OP_CREATE_FID, fid_index, 433 0); 434 mlxsw_reg_sfmr_vv_set(sfmr_pl, vni_valid); 435 mlxsw_reg_sfmr_vni_set(sfmr_pl, be32_to_cpu(vni)); 436 mlxsw_reg_sfmr_vtfp_set(sfmr_pl, nve_flood_index_valid); 437 mlxsw_reg_sfmr_nve_tunnel_flood_ptr_set(sfmr_pl, nve_flood_index); 438 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl); 439} 440 441static int __mlxsw_sp_fid_port_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index, 442 u16 local_port, u16 vid, bool valid) 443{ 444 enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; 445 char svfa_pl[MLXSW_REG_SVFA_LEN]; 446 447 mlxsw_reg_svfa_pack(svfa_pl, local_port, mt, valid, fid_index, vid); 448 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl); 449} 450 451static struct mlxsw_sp_fid_8021d * 452mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid) 453{ 454 return container_of(fid, struct mlxsw_sp_fid_8021d, common); 455} 456 457static void mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg) 458{ 459 int br_ifindex = *(int *) arg; 460 461 mlxsw_sp_fid_8021d_fid(fid)->br_ifindex = br_ifindex; 462} 463 464static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid) 465{ 466 struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 467 468 return mlxsw_sp_fid_op(fid_family->mlxsw_sp, fid->fid_index, 0, true); 469} 470 471static void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid *fid) 472{ 473 if (fid->vni_valid) 474 mlxsw_sp_nve_fid_disable(fid->fid_family->mlxsw_sp, fid); 475 mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false); 476} 477 478static int mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid *fid, 479 const void *arg, u16 *p_fid_index) 480{ 481 struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 482 u16 nr_fids, fid_index; 483 484 nr_fids = fid_family->end_index - fid_family->start_index + 1; 485 fid_index = find_first_zero_bit(fid_family->fids_bitmap, nr_fids); 486 if (fid_index == nr_fids) 487 return -ENOBUFS; 488 *p_fid_index = fid_family->start_index + fid_index; 489 490 return 0; 491} 492 493static bool 494mlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid *fid, const void *arg) 495{ 496 int br_ifindex = *(int *) arg; 497 498 return mlxsw_sp_fid_8021d_fid(fid)->br_ifindex == br_ifindex; 499} 500 501static u16 mlxsw_sp_fid_8021d_flood_index(const struct mlxsw_sp_fid *fid) 502{ 503 return fid->fid_index - VLAN_N_VID; 504} 505 506static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) 507{ 508 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 509 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; 510 int err; 511 512 list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list, 513 list) { 514 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; 515 u16 vid = mlxsw_sp_port_vlan->vid; 516 517 if (!fid) 518 continue; 519 520 err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, 521 mlxsw_sp_port->local_port, 522 vid, true); 523 if (err) 524 goto err_fid_port_vid_map; 525 } 526 527 err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true); 528 if (err) 529 goto err_port_vp_mode_set; 530 531 return 0; 532 533err_port_vp_mode_set: 534err_fid_port_vid_map: 535 list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan, 536 &mlxsw_sp_port->vlans_list, list) { 537 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; 538 u16 vid = mlxsw_sp_port_vlan->vid; 539 540 if (!fid) 541 continue; 542 543 __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, 544 mlxsw_sp_port->local_port, vid, 545 false); 546 } 547 return err; 548} 549 550static void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) 551{ 552 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 553 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; 554 555 mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); 556 557 list_for_each_entry_reverse(mlxsw_sp_port_vlan, 558 &mlxsw_sp_port->vlans_list, list) { 559 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; 560 u16 vid = mlxsw_sp_port_vlan->vid; 561 562 if (!fid) 563 continue; 564 565 __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, 566 mlxsw_sp_port->local_port, vid, 567 false); 568 } 569} 570 571static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid, 572 struct mlxsw_sp_port *mlxsw_sp_port, 573 u16 vid) 574{ 575 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 576 u16 local_port = mlxsw_sp_port->local_port; 577 int err; 578 579 err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, 580 mlxsw_sp_port->local_port, vid, true); 581 if (err) 582 return err; 583 584 if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) { 585 err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port); 586 if (err) 587 goto err_port_vp_mode_trans; 588 } 589 590 return 0; 591 592err_port_vp_mode_trans: 593 mlxsw_sp->fid_core->port_fid_mappings[local_port]--; 594 __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, 595 mlxsw_sp_port->local_port, vid, false); 596 return err; 597} 598 599static void 600mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid, 601 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) 602{ 603 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 604 u16 local_port = mlxsw_sp_port->local_port; 605 606 if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1) 607 mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); 608 mlxsw_sp->fid_core->port_fid_mappings[local_port]--; 609 __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, 610 mlxsw_sp_port->local_port, vid, false); 611} 612 613static int mlxsw_sp_fid_8021d_vni_set(struct mlxsw_sp_fid *fid, __be32 vni) 614{ 615 struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 616 617 return mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, vni, 618 true, fid->nve_flood_index, 619 fid->nve_flood_index_valid); 620} 621 622static void mlxsw_sp_fid_8021d_vni_clear(struct mlxsw_sp_fid *fid) 623{ 624 struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 625 626 mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, 0, false, 627 fid->nve_flood_index, fid->nve_flood_index_valid); 628} 629 630static int mlxsw_sp_fid_8021d_nve_flood_index_set(struct mlxsw_sp_fid *fid, 631 u32 nve_flood_index) 632{ 633 struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 634 635 return mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, 636 fid->vni, fid->vni_valid, nve_flood_index, 637 true); 638} 639 640static void mlxsw_sp_fid_8021d_nve_flood_index_clear(struct mlxsw_sp_fid *fid) 641{ 642 struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 643 644 mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, fid->vni, 645 fid->vni_valid, 0, false); 646} 647 648static void 649mlxsw_sp_fid_8021d_fdb_clear_offload(const struct mlxsw_sp_fid *fid, 650 const struct net_device *nve_dev) 651{ 652 br_fdb_clear_offload(nve_dev, 0); 653} 654 655static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = { 656 .setup = mlxsw_sp_fid_8021d_setup, 657 .configure = mlxsw_sp_fid_8021d_configure, 658 .deconfigure = mlxsw_sp_fid_8021d_deconfigure, 659 .index_alloc = mlxsw_sp_fid_8021d_index_alloc, 660 .compare = mlxsw_sp_fid_8021d_compare, 661 .flood_index = mlxsw_sp_fid_8021d_flood_index, 662 .port_vid_map = mlxsw_sp_fid_8021d_port_vid_map, 663 .port_vid_unmap = mlxsw_sp_fid_8021d_port_vid_unmap, 664 .vni_set = mlxsw_sp_fid_8021d_vni_set, 665 .vni_clear = mlxsw_sp_fid_8021d_vni_clear, 666 .nve_flood_index_set = mlxsw_sp_fid_8021d_nve_flood_index_set, 667 .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear, 668 .fdb_clear_offload = mlxsw_sp_fid_8021d_fdb_clear_offload, 669}; 670 671static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = { 672 { 673 .packet_type = MLXSW_SP_FLOOD_TYPE_UC, 674 .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID, 675 .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID, 676 .table_index = 0, 677 }, 678 { 679 .packet_type = MLXSW_SP_FLOOD_TYPE_MC, 680 .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID, 681 .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID, 682 .table_index = 1, 683 }, 684 { 685 .packet_type = MLXSW_SP_FLOOD_TYPE_BC, 686 .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID, 687 .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID, 688 .table_index = 2, 689 }, 690}; 691 692/* Range and flood configuration must match mlxsw_config_profile */ 693static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021d_family = { 694 .type = MLXSW_SP_FID_TYPE_8021D, 695 .fid_size = sizeof(struct mlxsw_sp_fid_8021d), 696 .start_index = VLAN_N_VID, 697 .end_index = VLAN_N_VID + MLXSW_SP_FID_8021D_MAX - 1, 698 .flood_tables = mlxsw_sp_fid_8021d_flood_tables, 699 .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), 700 .rif_type = MLXSW_SP_RIF_TYPE_FID, 701 .ops = &mlxsw_sp_fid_8021d_ops, 702 .lag_vid_valid = 1, 703}; 704 705static bool 706mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg) 707{ 708 u16 vid = *(u16 *) arg; 709 710 return mlxsw_sp_fid_8021q_fid(fid)->vid == vid; 711} 712 713static void 714mlxsw_sp_fid_8021q_fdb_clear_offload(const struct mlxsw_sp_fid *fid, 715 const struct net_device *nve_dev) 716{ 717 br_fdb_clear_offload(nve_dev, mlxsw_sp_fid_8021q_vid(fid)); 718} 719 720static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_emu_ops = { 721 .setup = mlxsw_sp_fid_8021q_setup, 722 .configure = mlxsw_sp_fid_8021d_configure, 723 .deconfigure = mlxsw_sp_fid_8021d_deconfigure, 724 .index_alloc = mlxsw_sp_fid_8021d_index_alloc, 725 .compare = mlxsw_sp_fid_8021q_compare, 726 .flood_index = mlxsw_sp_fid_8021d_flood_index, 727 .port_vid_map = mlxsw_sp_fid_8021d_port_vid_map, 728 .port_vid_unmap = mlxsw_sp_fid_8021d_port_vid_unmap, 729 .vni_set = mlxsw_sp_fid_8021d_vni_set, 730 .vni_clear = mlxsw_sp_fid_8021d_vni_clear, 731 .nve_flood_index_set = mlxsw_sp_fid_8021d_nve_flood_index_set, 732 .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear, 733 .fdb_clear_offload = mlxsw_sp_fid_8021q_fdb_clear_offload, 734}; 735 736/* There are 4K-2 emulated 802.1Q FIDs, starting right after the 802.1D FIDs */ 737#define MLXSW_SP_FID_8021Q_EMU_START (VLAN_N_VID + MLXSW_SP_FID_8021D_MAX) 738#define MLXSW_SP_FID_8021Q_EMU_END (MLXSW_SP_FID_8021Q_EMU_START + \ 739 VLAN_VID_MASK - 2) 740 741/* Range and flood configuration must match mlxsw_config_profile */ 742static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021q_emu_family = { 743 .type = MLXSW_SP_FID_TYPE_8021Q, 744 .fid_size = sizeof(struct mlxsw_sp_fid_8021q), 745 .start_index = MLXSW_SP_FID_8021Q_EMU_START, 746 .end_index = MLXSW_SP_FID_8021Q_EMU_END, 747 .flood_tables = mlxsw_sp_fid_8021d_flood_tables, 748 .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), 749 .rif_type = MLXSW_SP_RIF_TYPE_VLAN, 750 .ops = &mlxsw_sp_fid_8021q_emu_ops, 751 .lag_vid_valid = 1, 752}; 753 754static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid) 755{ 756 /* rFIDs are allocated by the device during init */ 757 return 0; 758} 759 760static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid) 761{ 762} 763 764static int mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid *fid, 765 const void *arg, u16 *p_fid_index) 766{ 767 u16 rif_index = *(u16 *) arg; 768 769 *p_fid_index = fid->fid_family->start_index + rif_index; 770 771 return 0; 772} 773 774static bool mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid *fid, 775 const void *arg) 776{ 777 u16 rif_index = *(u16 *) arg; 778 779 return fid->fid_index == rif_index + fid->fid_family->start_index; 780} 781 782static int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid, 783 struct mlxsw_sp_port *mlxsw_sp_port, 784 u16 vid) 785{ 786 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 787 u16 local_port = mlxsw_sp_port->local_port; 788 int err; 789 790 /* We only need to transition the port to virtual mode since 791 * {Port, VID} => FID is done by the firmware upon RIF creation. 792 */ 793 if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) { 794 err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port); 795 if (err) 796 goto err_port_vp_mode_trans; 797 } 798 799 return 0; 800 801err_port_vp_mode_trans: 802 mlxsw_sp->fid_core->port_fid_mappings[local_port]--; 803 return err; 804} 805 806static void 807mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid *fid, 808 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) 809{ 810 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 811 u16 local_port = mlxsw_sp_port->local_port; 812 813 if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1) 814 mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); 815 mlxsw_sp->fid_core->port_fid_mappings[local_port]--; 816} 817 818static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = { 819 .configure = mlxsw_sp_fid_rfid_configure, 820 .deconfigure = mlxsw_sp_fid_rfid_deconfigure, 821 .index_alloc = mlxsw_sp_fid_rfid_index_alloc, 822 .compare = mlxsw_sp_fid_rfid_compare, 823 .port_vid_map = mlxsw_sp_fid_rfid_port_vid_map, 824 .port_vid_unmap = mlxsw_sp_fid_rfid_port_vid_unmap, 825}; 826 827#define MLXSW_SP_RFID_BASE (15 * 1024) 828#define MLXSW_SP_RFID_MAX 1024 829 830static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family = { 831 .type = MLXSW_SP_FID_TYPE_RFID, 832 .fid_size = sizeof(struct mlxsw_sp_fid), 833 .start_index = MLXSW_SP_RFID_BASE, 834 .end_index = MLXSW_SP_RFID_BASE + MLXSW_SP_RFID_MAX - 1, 835 .rif_type = MLXSW_SP_RIF_TYPE_SUBPORT, 836 .ops = &mlxsw_sp_fid_rfid_ops, 837}; 838 839static int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid *fid) 840{ 841 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; 842 843 return mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, true); 844} 845 846static void mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid *fid) 847{ 848 mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false); 849} 850 851static int mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid *fid, 852 const void *arg, u16 *p_fid_index) 853{ 854 *p_fid_index = fid->fid_family->start_index; 855 856 return 0; 857} 858 859static bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid, 860 const void *arg) 861{ 862 return true; 863} 864 865static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = { 866 .configure = mlxsw_sp_fid_dummy_configure, 867 .deconfigure = mlxsw_sp_fid_dummy_deconfigure, 868 .index_alloc = mlxsw_sp_fid_dummy_index_alloc, 869 .compare = mlxsw_sp_fid_dummy_compare, 870}; 871 872static const struct mlxsw_sp_fid_family mlxsw_sp_fid_dummy_family = { 873 .type = MLXSW_SP_FID_TYPE_DUMMY, 874 .fid_size = sizeof(struct mlxsw_sp_fid), 875 .start_index = VLAN_N_VID - 1, 876 .end_index = VLAN_N_VID - 1, 877 .ops = &mlxsw_sp_fid_dummy_ops, 878}; 879 880static const struct mlxsw_sp_fid_family *mlxsw_sp_fid_family_arr[] = { 881 [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp_fid_8021q_emu_family, 882 [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp_fid_8021d_family, 883 [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family, 884 [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp_fid_dummy_family, 885}; 886 887static struct mlxsw_sp_fid *mlxsw_sp_fid_lookup(struct mlxsw_sp *mlxsw_sp, 888 enum mlxsw_sp_fid_type type, 889 const void *arg) 890{ 891 struct mlxsw_sp_fid_family *fid_family; 892 struct mlxsw_sp_fid *fid; 893 894 fid_family = mlxsw_sp->fid_core->fid_family_arr[type]; 895 list_for_each_entry(fid, &fid_family->fids_list, list) { 896 if (!fid->fid_family->ops->compare(fid, arg)) 897 continue; 898 refcount_inc(&fid->ref_count); 899 return fid; 900 } 901 902 return NULL; 903} 904 905static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp, 906 enum mlxsw_sp_fid_type type, 907 const void *arg) 908{ 909 struct mlxsw_sp_fid_family *fid_family; 910 struct mlxsw_sp_fid *fid; 911 u16 fid_index; 912 int err; 913 914 fid = mlxsw_sp_fid_lookup(mlxsw_sp, type, arg); 915 if (fid) 916 return fid; 917 918 fid_family = mlxsw_sp->fid_core->fid_family_arr[type]; 919 fid = kzalloc(fid_family->fid_size, GFP_KERNEL); 920 if (!fid) 921 return ERR_PTR(-ENOMEM); 922 fid->fid_family = fid_family; 923 924 err = fid->fid_family->ops->index_alloc(fid, arg, &fid_index); 925 if (err) 926 goto err_index_alloc; 927 fid->fid_index = fid_index; 928 __set_bit(fid_index - fid_family->start_index, fid_family->fids_bitmap); 929 930 if (fid->fid_family->ops->setup) 931 fid->fid_family->ops->setup(fid, arg); 932 933 err = fid->fid_family->ops->configure(fid); 934 if (err) 935 goto err_configure; 936 937 err = rhashtable_insert_fast(&mlxsw_sp->fid_core->fid_ht, &fid->ht_node, 938 mlxsw_sp_fid_ht_params); 939 if (err) 940 goto err_rhashtable_insert; 941 942 list_add(&fid->list, &fid_family->fids_list); 943 refcount_set(&fid->ref_count, 1); 944 return fid; 945 946err_rhashtable_insert: 947 fid->fid_family->ops->deconfigure(fid); 948err_configure: 949 __clear_bit(fid_index - fid_family->start_index, 950 fid_family->fids_bitmap); 951err_index_alloc: 952 kfree(fid); 953 return ERR_PTR(err); 954} 955 956void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid) 957{ 958 struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 959 struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; 960 961 if (!refcount_dec_and_test(&fid->ref_count)) 962 return; 963 964 list_del(&fid->list); 965 rhashtable_remove_fast(&mlxsw_sp->fid_core->fid_ht, 966 &fid->ht_node, mlxsw_sp_fid_ht_params); 967 fid->fid_family->ops->deconfigure(fid); 968 __clear_bit(fid->fid_index - fid_family->start_index, 969 fid_family->fids_bitmap); 970 kfree(fid); 971} 972 973struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid) 974{ 975 return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid); 976} 977 978struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp, 979 int br_ifindex) 980{ 981 return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, &br_ifindex); 982} 983 984struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_lookup(struct mlxsw_sp *mlxsw_sp, 985 u16 vid) 986{ 987 return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid); 988} 989 990struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_lookup(struct mlxsw_sp *mlxsw_sp, 991 int br_ifindex) 992{ 993 return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, 994 &br_ifindex); 995} 996 997struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp, 998 u16 rif_index) 999{ 1000 return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_RFID, &rif_index); 1001} 1002 1003struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp) 1004{ 1005 return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_DUMMY, NULL); 1006} 1007 1008static int 1009mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family, 1010 const struct mlxsw_sp_flood_table *flood_table) 1011{ 1012 enum mlxsw_sp_flood_type packet_type = flood_table->packet_type; 1013 const int *sfgc_packet_types; 1014 int i; 1015 1016 sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type]; 1017 for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) { 1018 struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; 1019 char sfgc_pl[MLXSW_REG_SFGC_LEN]; 1020 int err; 1021 1022 if (!sfgc_packet_types[i]) 1023 continue; 1024 mlxsw_reg_sfgc_pack(sfgc_pl, i, flood_table->bridge_type, 1025 flood_table->table_type, 1026 flood_table->table_index); 1027 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl); 1028 if (err) 1029 return err; 1030 } 1031 1032 return 0; 1033} 1034 1035static int 1036mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family) 1037{ 1038 int i; 1039 1040 for (i = 0; i < fid_family->nr_flood_tables; i++) { 1041 const struct mlxsw_sp_flood_table *flood_table; 1042 int err; 1043 1044 flood_table = &fid_family->flood_tables[i]; 1045 err = mlxsw_sp_fid_flood_table_init(fid_family, flood_table); 1046 if (err) 1047 return err; 1048 } 1049 1050 return 0; 1051} 1052 1053static int mlxsw_sp_fid_family_register(struct mlxsw_sp *mlxsw_sp, 1054 const struct mlxsw_sp_fid_family *tmpl) 1055{ 1056 u16 nr_fids = tmpl->end_index - tmpl->start_index + 1; 1057 struct mlxsw_sp_fid_family *fid_family; 1058 int err; 1059 1060 fid_family = kmemdup(tmpl, sizeof(*fid_family), GFP_KERNEL); 1061 if (!fid_family) 1062 return -ENOMEM; 1063 1064 fid_family->mlxsw_sp = mlxsw_sp; 1065 INIT_LIST_HEAD(&fid_family->fids_list); 1066 fid_family->fids_bitmap = bitmap_zalloc(nr_fids, GFP_KERNEL); 1067 if (!fid_family->fids_bitmap) { 1068 err = -ENOMEM; 1069 goto err_alloc_fids_bitmap; 1070 } 1071 1072 if (fid_family->flood_tables) { 1073 err = mlxsw_sp_fid_flood_tables_init(fid_family); 1074 if (err) 1075 goto err_fid_flood_tables_init; 1076 } 1077 1078 mlxsw_sp->fid_core->fid_family_arr[tmpl->type] = fid_family; 1079 1080 return 0; 1081 1082err_fid_flood_tables_init: 1083 bitmap_free(fid_family->fids_bitmap); 1084err_alloc_fids_bitmap: 1085 kfree(fid_family); 1086 return err; 1087} 1088 1089static void 1090mlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp, 1091 struct mlxsw_sp_fid_family *fid_family) 1092{ 1093 mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL; 1094 bitmap_free(fid_family->fids_bitmap); 1095 WARN_ON_ONCE(!list_empty(&fid_family->fids_list)); 1096 kfree(fid_family); 1097} 1098 1099int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port) 1100{ 1101 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 1102 1103 /* Track number of FIDs configured on the port with mapping type 1104 * PORT_VID_TO_FID, so that we know when to transition the port 1105 * back to non-virtual (VLAN) mode. 1106 */ 1107 mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0; 1108 1109 return mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); 1110} 1111 1112void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port) 1113{ 1114 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 1115 1116 mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0; 1117} 1118 1119int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp) 1120{ 1121 unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core); 1122 struct mlxsw_sp_fid_core *fid_core; 1123 int err, i; 1124 1125 fid_core = kzalloc(sizeof(*mlxsw_sp->fid_core), GFP_KERNEL); 1126 if (!fid_core) 1127 return -ENOMEM; 1128 mlxsw_sp->fid_core = fid_core; 1129 1130 err = rhashtable_init(&fid_core->fid_ht, &mlxsw_sp_fid_ht_params); 1131 if (err) 1132 goto err_rhashtable_fid_init; 1133 1134 err = rhashtable_init(&fid_core->vni_ht, &mlxsw_sp_fid_vni_ht_params); 1135 if (err) 1136 goto err_rhashtable_vni_init; 1137 1138 fid_core->port_fid_mappings = kcalloc(max_ports, sizeof(unsigned int), 1139 GFP_KERNEL); 1140 if (!fid_core->port_fid_mappings) { 1141 err = -ENOMEM; 1142 goto err_alloc_port_fid_mappings; 1143 } 1144 1145 for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) { 1146 err = mlxsw_sp_fid_family_register(mlxsw_sp, 1147 mlxsw_sp_fid_family_arr[i]); 1148 1149 if (err) 1150 goto err_fid_ops_register; 1151 } 1152 1153 return 0; 1154 1155err_fid_ops_register: 1156 for (i--; i >= 0; i--) { 1157 struct mlxsw_sp_fid_family *fid_family; 1158 1159 fid_family = fid_core->fid_family_arr[i]; 1160 mlxsw_sp_fid_family_unregister(mlxsw_sp, fid_family); 1161 } 1162 kfree(fid_core->port_fid_mappings); 1163err_alloc_port_fid_mappings: 1164 rhashtable_destroy(&fid_core->vni_ht); 1165err_rhashtable_vni_init: 1166 rhashtable_destroy(&fid_core->fid_ht); 1167err_rhashtable_fid_init: 1168 kfree(fid_core); 1169 return err; 1170} 1171 1172void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp) 1173{ 1174 struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core; 1175 int i; 1176 1177 for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) 1178 mlxsw_sp_fid_family_unregister(mlxsw_sp, 1179 fid_core->fid_family_arr[i]); 1180 kfree(fid_core->port_fid_mappings); 1181 rhashtable_destroy(&fid_core->vni_ht); 1182 rhashtable_destroy(&fid_core->fid_ht); 1183 kfree(fid_core); 1184}