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