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