1 /* 2 * drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c 3 * Copyright (c) 2017 Mellanox Technologies. All rights reserved. 4 * Copyright (c) 2017 Ido Schimmel <idosch@mellanox.com> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the names of the copyright holders nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * Alternatively, this software may be distributed under the terms of the 19 * GNU General Public License ("GPL") version 2 as published by the Free 20 * Software Foundation. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include <linux/kernel.h> 36 #include <linux/bitops.h> 37 #include <linux/if_vlan.h> 38 #include <linux/if_bridge.h> 39 #include <linux/netdevice.h> 40 #include <linux/rtnetlink.h> 41 42 #include "spectrum.h" 43 #include "reg.h" 44 45 struct mlxsw_sp_fid_family; 46 47 struct mlxsw_sp_fid_core { 48 struct mlxsw_sp_fid_family *fid_family_arr[MLXSW_SP_FID_TYPE_MAX]; 49 unsigned int *port_fid_mappings; 50 }; 51 52 struct mlxsw_sp_fid { 53 struct list_head list; 54 struct mlxsw_sp_rif *rif; 55 unsigned int ref_count; 56 u16 fid_index; 57 struct mlxsw_sp_fid_family *fid_family; 58 }; 59 60 struct mlxsw_sp_fid_8021q { 61 struct mlxsw_sp_fid common; 62 u16 vid; 63 }; 64 65 struct mlxsw_sp_fid_8021d { 66 struct mlxsw_sp_fid common; 67 int br_ifindex; 68 }; 69 70 struct mlxsw_sp_flood_table { 71 enum mlxsw_sp_flood_type packet_type; 72 enum mlxsw_reg_sfgc_bridge_type bridge_type; 73 enum mlxsw_flood_table_type table_type; 74 int table_index; 75 }; 76 77 struct mlxsw_sp_fid_ops { 78 void (*setup)(struct mlxsw_sp_fid *fid, const void *arg); 79 int (*configure)(struct mlxsw_sp_fid *fid); 80 void (*deconfigure)(struct mlxsw_sp_fid *fid); 81 int (*index_alloc)(struct mlxsw_sp_fid *fid, const void *arg, 82 u16 *p_fid_index); 83 bool (*compare)(const struct mlxsw_sp_fid *fid, 84 const void *arg); 85 u16 (*flood_index)(const struct mlxsw_sp_fid *fid); 86 int (*port_vid_map)(struct mlxsw_sp_fid *fid, 87 struct mlxsw_sp_port *port, u16 vid); 88 void (*port_vid_unmap)(struct mlxsw_sp_fid *fid, 89 struct mlxsw_sp_port *port, u16 vid); 90 }; 91 92 struct mlxsw_sp_fid_family { 93 enum mlxsw_sp_fid_type type; 94 size_t fid_size; 95 u16 start_index; 96 u16 end_index; 97 struct list_head fids_list; 98 unsigned long *fids_bitmap; 99 const struct mlxsw_sp_flood_table *flood_tables; 100 int nr_flood_tables; 101 enum mlxsw_sp_rif_type rif_type; 102 const struct mlxsw_sp_fid_ops *ops; 103 struct mlxsw_sp *mlxsw_sp; 104 }; 105 106 static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { 107 [MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST] = 1, 108 }; 109 110 static const int mlxsw_sp_sfgc_bc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { 111 [MLXSW_REG_SFGC_TYPE_BROADCAST] = 1, 112 [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP] = 1, 113 [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL] = 1, 114 [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST] = 1, 115 }; 116 117 static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { 118 [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1, 119 [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1, 120 }; 121 122 static const int *mlxsw_sp_packet_type_sfgc_types[] = { 123 [MLXSW_SP_FLOOD_TYPE_UC] = mlxsw_sp_sfgc_uc_packet_types, 124 [MLXSW_SP_FLOOD_TYPE_BC] = mlxsw_sp_sfgc_bc_packet_types, 125 [MLXSW_SP_FLOOD_TYPE_MC] = mlxsw_sp_sfgc_mc_packet_types, 126 }; 127 128 static const struct mlxsw_sp_flood_table * 129 mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid, 130 enum mlxsw_sp_flood_type packet_type) 131 { 132 struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 133 int i; 134 135 for (i = 0; i < fid_family->nr_flood_tables; i++) { 136 if (fid_family->flood_tables[i].packet_type != packet_type) 137 continue; 138 return &fid_family->flood_tables[i]; 139 } 140 141 return NULL; 142 } 143 144 int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid, 145 enum mlxsw_sp_flood_type packet_type, u8 local_port, 146 bool member) 147 { 148 struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 149 const struct mlxsw_sp_fid_ops *ops = fid_family->ops; 150 const struct mlxsw_sp_flood_table *flood_table; 151 char *sftr_pl; 152 int err; 153 154 if (WARN_ON(!fid_family->flood_tables || !ops->flood_index)) 155 return -EINVAL; 156 157 flood_table = mlxsw_sp_fid_flood_table_lookup(fid, packet_type); 158 if (!flood_table) 159 return -ESRCH; 160 161 sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL); 162 if (!sftr_pl) 163 return -ENOMEM; 164 165 mlxsw_reg_sftr_pack(sftr_pl, flood_table->table_index, 166 ops->flood_index(fid), flood_table->table_type, 1, 167 local_port, member); 168 err = mlxsw_reg_write(fid_family->mlxsw_sp->core, MLXSW_REG(sftr), 169 sftr_pl); 170 kfree(sftr_pl); 171 return err; 172 } 173 174 int mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid *fid, 175 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) 176 { 177 if (WARN_ON(!fid->fid_family->ops->port_vid_map)) 178 return -EINVAL; 179 return fid->fid_family->ops->port_vid_map(fid, mlxsw_sp_port, vid); 180 } 181 182 void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid, 183 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) 184 { 185 fid->fid_family->ops->port_vid_unmap(fid, mlxsw_sp_port, vid); 186 } 187 188 enum mlxsw_sp_rif_type mlxsw_sp_fid_rif_type(const struct mlxsw_sp_fid *fid) 189 { 190 return fid->fid_family->rif_type; 191 } 192 193 u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid) 194 { 195 return fid->fid_index; 196 } 197 198 enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid) 199 { 200 return fid->fid_family->type; 201 } 202 203 void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif) 204 { 205 fid->rif = rif; 206 } 207 208 enum mlxsw_sp_rif_type 209 mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp, 210 enum mlxsw_sp_fid_type type) 211 { 212 struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core; 213 214 return fid_core->fid_family_arr[type]->rif_type; 215 } 216 217 static struct mlxsw_sp_fid_8021q * 218 mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid) 219 { 220 return container_of(fid, struct mlxsw_sp_fid_8021q, common); 221 } 222 223 u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid) 224 { 225 return mlxsw_sp_fid_8021q_fid(fid)->vid; 226 } 227 228 static void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg) 229 { 230 u16 vid = *(u16 *) arg; 231 232 mlxsw_sp_fid_8021q_fid(fid)->vid = vid; 233 } 234 235 static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid) 236 { 237 return valid ? MLXSW_REG_SFMR_OP_CREATE_FID : 238 MLXSW_REG_SFMR_OP_DESTROY_FID; 239 } 240 241 static int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index, 242 u16 fid_offset, bool valid) 243 { 244 char sfmr_pl[MLXSW_REG_SFMR_LEN]; 245 246 mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid_index, 247 fid_offset); 248 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl); 249 } 250 251 static int mlxsw_sp_fid_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index, 252 u16 vid, bool valid) 253 { 254 enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_VID_TO_FID; 255 char svfa_pl[MLXSW_REG_SVFA_LEN]; 256 257 mlxsw_reg_svfa_pack(svfa_pl, 0, mt, valid, fid_index, vid); 258 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl); 259 } 260 261 static int __mlxsw_sp_fid_port_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index, 262 u8 local_port, u16 vid, bool valid) 263 { 264 enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; 265 char svfa_pl[MLXSW_REG_SVFA_LEN]; 266 267 mlxsw_reg_svfa_pack(svfa_pl, local_port, mt, valid, fid_index, vid); 268 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl); 269 } 270 271 static int mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid *fid) 272 { 273 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; 274 struct mlxsw_sp_fid_8021q *fid_8021q; 275 int err; 276 277 err = mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, fid->fid_index, true); 278 if (err) 279 return err; 280 281 fid_8021q = mlxsw_sp_fid_8021q_fid(fid); 282 err = mlxsw_sp_fid_vid_map(mlxsw_sp, fid->fid_index, fid_8021q->vid, 283 true); 284 if (err) 285 goto err_fid_map; 286 287 return 0; 288 289 err_fid_map: 290 mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, false); 291 return err; 292 } 293 294 static void mlxsw_sp_fid_8021q_deconfigure(struct mlxsw_sp_fid *fid) 295 { 296 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; 297 struct mlxsw_sp_fid_8021q *fid_8021q; 298 299 fid_8021q = mlxsw_sp_fid_8021q_fid(fid); 300 mlxsw_sp_fid_vid_map(mlxsw_sp, fid->fid_index, fid_8021q->vid, false); 301 mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, false); 302 } 303 304 static int mlxsw_sp_fid_8021q_index_alloc(struct mlxsw_sp_fid *fid, 305 const void *arg, u16 *p_fid_index) 306 { 307 struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 308 u16 vid = *(u16 *) arg; 309 310 /* Use 1:1 mapping for simplicity although not a must */ 311 if (vid < fid_family->start_index || vid > fid_family->end_index) 312 return -EINVAL; 313 *p_fid_index = vid; 314 315 return 0; 316 } 317 318 static bool 319 mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg) 320 { 321 u16 vid = *(u16 *) arg; 322 323 return mlxsw_sp_fid_8021q_fid(fid)->vid == vid; 324 } 325 326 static u16 mlxsw_sp_fid_8021q_flood_index(const struct mlxsw_sp_fid *fid) 327 { 328 return fid->fid_index; 329 } 330 331 static int mlxsw_sp_fid_8021q_port_vid_map(struct mlxsw_sp_fid *fid, 332 struct mlxsw_sp_port *mlxsw_sp_port, 333 u16 vid) 334 { 335 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 336 u8 local_port = mlxsw_sp_port->local_port; 337 338 /* In case there are no {Port, VID} => FID mappings on the port, 339 * we can use the global VID => FID mapping we created when the 340 * FID was configured. 341 */ 342 if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 0) 343 return 0; 344 return __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, local_port, 345 vid, true); 346 } 347 348 static void 349 mlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid *fid, 350 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) 351 { 352 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 353 u8 local_port = mlxsw_sp_port->local_port; 354 355 if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 0) 356 return; 357 __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, local_port, vid, 358 false); 359 } 360 361 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops = { 362 .setup = mlxsw_sp_fid_8021q_setup, 363 .configure = mlxsw_sp_fid_8021q_configure, 364 .deconfigure = mlxsw_sp_fid_8021q_deconfigure, 365 .index_alloc = mlxsw_sp_fid_8021q_index_alloc, 366 .compare = mlxsw_sp_fid_8021q_compare, 367 .flood_index = mlxsw_sp_fid_8021q_flood_index, 368 .port_vid_map = mlxsw_sp_fid_8021q_port_vid_map, 369 .port_vid_unmap = mlxsw_sp_fid_8021q_port_vid_unmap, 370 }; 371 372 static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021q_flood_tables[] = { 373 { 374 .packet_type = MLXSW_SP_FLOOD_TYPE_UC, 375 .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID, 376 .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET, 377 .table_index = 0, 378 }, 379 { 380 .packet_type = MLXSW_SP_FLOOD_TYPE_MC, 381 .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID, 382 .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET, 383 .table_index = 1, 384 }, 385 { 386 .packet_type = MLXSW_SP_FLOOD_TYPE_BC, 387 .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID, 388 .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET, 389 .table_index = 2, 390 }, 391 }; 392 393 /* Range and flood configuration must match mlxsw_config_profile */ 394 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021q_family = { 395 .type = MLXSW_SP_FID_TYPE_8021Q, 396 .fid_size = sizeof(struct mlxsw_sp_fid_8021q), 397 .start_index = 1, 398 .end_index = VLAN_VID_MASK, 399 .flood_tables = mlxsw_sp_fid_8021q_flood_tables, 400 .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021q_flood_tables), 401 .rif_type = MLXSW_SP_RIF_TYPE_VLAN, 402 .ops = &mlxsw_sp_fid_8021q_ops, 403 }; 404 405 static struct mlxsw_sp_fid_8021d * 406 mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid) 407 { 408 return container_of(fid, struct mlxsw_sp_fid_8021d, common); 409 } 410 411 static void mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg) 412 { 413 int br_ifindex = *(int *) arg; 414 415 mlxsw_sp_fid_8021d_fid(fid)->br_ifindex = br_ifindex; 416 } 417 418 static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid) 419 { 420 struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 421 422 return mlxsw_sp_fid_op(fid_family->mlxsw_sp, fid->fid_index, 0, true); 423 } 424 425 static void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid *fid) 426 { 427 mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false); 428 } 429 430 static int mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid *fid, 431 const void *arg, u16 *p_fid_index) 432 { 433 struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 434 u16 nr_fids, fid_index; 435 436 nr_fids = fid_family->end_index - fid_family->start_index + 1; 437 fid_index = find_first_zero_bit(fid_family->fids_bitmap, nr_fids); 438 if (fid_index == nr_fids) 439 return -ENOBUFS; 440 *p_fid_index = fid_family->start_index + fid_index; 441 442 return 0; 443 } 444 445 static bool 446 mlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid *fid, const void *arg) 447 { 448 int br_ifindex = *(int *) arg; 449 450 return mlxsw_sp_fid_8021d_fid(fid)->br_ifindex == br_ifindex; 451 } 452 453 static u16 mlxsw_sp_fid_8021d_flood_index(const struct mlxsw_sp_fid *fid) 454 { 455 return fid->fid_index - fid->fid_family->start_index; 456 } 457 458 static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) 459 { 460 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 461 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; 462 int err; 463 464 list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list, 465 list) { 466 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; 467 u16 vid = mlxsw_sp_port_vlan->vid; 468 469 if (!fid) 470 continue; 471 472 err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, 473 mlxsw_sp_port->local_port, 474 vid, true); 475 if (err) 476 goto err_fid_port_vid_map; 477 } 478 479 err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true); 480 if (err) 481 goto err_port_vp_mode_set; 482 483 return 0; 484 485 err_port_vp_mode_set: 486 err_fid_port_vid_map: 487 list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan, 488 &mlxsw_sp_port->vlans_list, list) { 489 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; 490 u16 vid = mlxsw_sp_port_vlan->vid; 491 492 if (!fid) 493 continue; 494 495 __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, 496 mlxsw_sp_port->local_port, vid, 497 false); 498 } 499 return err; 500 } 501 502 static void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) 503 { 504 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 505 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; 506 507 mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); 508 509 list_for_each_entry_reverse(mlxsw_sp_port_vlan, 510 &mlxsw_sp_port->vlans_list, list) { 511 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; 512 u16 vid = mlxsw_sp_port_vlan->vid; 513 514 if (!fid) 515 continue; 516 517 __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, 518 mlxsw_sp_port->local_port, vid, 519 false); 520 } 521 } 522 523 static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid, 524 struct mlxsw_sp_port *mlxsw_sp_port, 525 u16 vid) 526 { 527 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 528 u8 local_port = mlxsw_sp_port->local_port; 529 int err; 530 531 err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, 532 mlxsw_sp_port->local_port, vid, true); 533 if (err) 534 return err; 535 536 if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) { 537 err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port); 538 if (err) 539 goto err_port_vp_mode_trans; 540 } 541 542 return 0; 543 544 err_port_vp_mode_trans: 545 mlxsw_sp->fid_core->port_fid_mappings[local_port]--; 546 __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, 547 mlxsw_sp_port->local_port, vid, false); 548 return err; 549 } 550 551 static void 552 mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid, 553 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) 554 { 555 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 556 u8 local_port = mlxsw_sp_port->local_port; 557 558 if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1) 559 mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); 560 mlxsw_sp->fid_core->port_fid_mappings[local_port]--; 561 __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, 562 mlxsw_sp_port->local_port, vid, false); 563 } 564 565 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = { 566 .setup = mlxsw_sp_fid_8021d_setup, 567 .configure = mlxsw_sp_fid_8021d_configure, 568 .deconfigure = mlxsw_sp_fid_8021d_deconfigure, 569 .index_alloc = mlxsw_sp_fid_8021d_index_alloc, 570 .compare = mlxsw_sp_fid_8021d_compare, 571 .flood_index = mlxsw_sp_fid_8021d_flood_index, 572 .port_vid_map = mlxsw_sp_fid_8021d_port_vid_map, 573 .port_vid_unmap = mlxsw_sp_fid_8021d_port_vid_unmap, 574 }; 575 576 static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = { 577 { 578 .packet_type = MLXSW_SP_FLOOD_TYPE_UC, 579 .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID, 580 .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID, 581 .table_index = 0, 582 }, 583 { 584 .packet_type = MLXSW_SP_FLOOD_TYPE_MC, 585 .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID, 586 .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID, 587 .table_index = 1, 588 }, 589 { 590 .packet_type = MLXSW_SP_FLOOD_TYPE_BC, 591 .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID, 592 .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID, 593 .table_index = 2, 594 }, 595 }; 596 597 /* Range and flood configuration must match mlxsw_config_profile */ 598 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021d_family = { 599 .type = MLXSW_SP_FID_TYPE_8021D, 600 .fid_size = sizeof(struct mlxsw_sp_fid_8021d), 601 .start_index = VLAN_N_VID, 602 .end_index = VLAN_N_VID + MLXSW_SP_FID_8021D_MAX - 1, 603 .flood_tables = mlxsw_sp_fid_8021d_flood_tables, 604 .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), 605 .rif_type = MLXSW_SP_RIF_TYPE_FID, 606 .ops = &mlxsw_sp_fid_8021d_ops, 607 }; 608 609 static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid) 610 { 611 /* rFIDs are allocated by the device during init */ 612 return 0; 613 } 614 615 static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid) 616 { 617 } 618 619 static int mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid *fid, 620 const void *arg, u16 *p_fid_index) 621 { 622 u16 rif_index = *(u16 *) arg; 623 624 *p_fid_index = fid->fid_family->start_index + rif_index; 625 626 return 0; 627 } 628 629 static bool mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid *fid, 630 const void *arg) 631 { 632 u16 rif_index = *(u16 *) arg; 633 634 return fid->fid_index == rif_index + fid->fid_family->start_index; 635 } 636 637 static int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid, 638 struct mlxsw_sp_port *mlxsw_sp_port, 639 u16 vid) 640 { 641 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 642 u8 local_port = mlxsw_sp_port->local_port; 643 int err; 644 645 /* We only need to transition the port to virtual mode since 646 * {Port, VID} => FID is done by the firmware upon RIF creation. 647 */ 648 if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) { 649 err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port); 650 if (err) 651 goto err_port_vp_mode_trans; 652 } 653 654 return 0; 655 656 err_port_vp_mode_trans: 657 mlxsw_sp->fid_core->port_fid_mappings[local_port]--; 658 return err; 659 } 660 661 static void 662 mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid *fid, 663 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) 664 { 665 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 666 u8 local_port = mlxsw_sp_port->local_port; 667 668 if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1) 669 mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); 670 mlxsw_sp->fid_core->port_fid_mappings[local_port]--; 671 } 672 673 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = { 674 .configure = mlxsw_sp_fid_rfid_configure, 675 .deconfigure = mlxsw_sp_fid_rfid_deconfigure, 676 .index_alloc = mlxsw_sp_fid_rfid_index_alloc, 677 .compare = mlxsw_sp_fid_rfid_compare, 678 .port_vid_map = mlxsw_sp_fid_rfid_port_vid_map, 679 .port_vid_unmap = mlxsw_sp_fid_rfid_port_vid_unmap, 680 }; 681 682 #define MLXSW_SP_RFID_BASE (15 * 1024) 683 #define MLXSW_SP_RFID_MAX 1024 684 685 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family = { 686 .type = MLXSW_SP_FID_TYPE_RFID, 687 .fid_size = sizeof(struct mlxsw_sp_fid), 688 .start_index = MLXSW_SP_RFID_BASE, 689 .end_index = MLXSW_SP_RFID_BASE + MLXSW_SP_RFID_MAX - 1, 690 .rif_type = MLXSW_SP_RIF_TYPE_SUBPORT, 691 .ops = &mlxsw_sp_fid_rfid_ops, 692 }; 693 694 static int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid *fid) 695 { 696 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; 697 698 return mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, true); 699 } 700 701 static void mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid *fid) 702 { 703 mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false); 704 } 705 706 static int mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid *fid, 707 const void *arg, u16 *p_fid_index) 708 { 709 *p_fid_index = fid->fid_family->start_index; 710 711 return 0; 712 } 713 714 static bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid, 715 const void *arg) 716 { 717 return true; 718 } 719 720 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = { 721 .configure = mlxsw_sp_fid_dummy_configure, 722 .deconfigure = mlxsw_sp_fid_dummy_deconfigure, 723 .index_alloc = mlxsw_sp_fid_dummy_index_alloc, 724 .compare = mlxsw_sp_fid_dummy_compare, 725 }; 726 727 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_dummy_family = { 728 .type = MLXSW_SP_FID_TYPE_DUMMY, 729 .fid_size = sizeof(struct mlxsw_sp_fid), 730 .start_index = MLXSW_SP_RFID_BASE - 1, 731 .end_index = MLXSW_SP_RFID_BASE - 1, 732 .ops = &mlxsw_sp_fid_dummy_ops, 733 }; 734 735 static const struct mlxsw_sp_fid_family *mlxsw_sp_fid_family_arr[] = { 736 [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp_fid_8021q_family, 737 [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp_fid_8021d_family, 738 [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family, 739 [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp_fid_dummy_family, 740 }; 741 742 static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp, 743 enum mlxsw_sp_fid_type type, 744 const void *arg) 745 { 746 struct mlxsw_sp_fid_family *fid_family; 747 struct mlxsw_sp_fid *fid; 748 u16 fid_index; 749 int err; 750 751 fid_family = mlxsw_sp->fid_core->fid_family_arr[type]; 752 list_for_each_entry(fid, &fid_family->fids_list, list) { 753 if (!fid->fid_family->ops->compare(fid, arg)) 754 continue; 755 fid->ref_count++; 756 return fid; 757 } 758 759 fid = kzalloc(fid_family->fid_size, GFP_KERNEL); 760 if (!fid) 761 return ERR_PTR(-ENOMEM); 762 fid->fid_family = fid_family; 763 764 err = fid->fid_family->ops->index_alloc(fid, arg, &fid_index); 765 if (err) 766 goto err_index_alloc; 767 fid->fid_index = fid_index; 768 __set_bit(fid_index - fid_family->start_index, fid_family->fids_bitmap); 769 770 if (fid->fid_family->ops->setup) 771 fid->fid_family->ops->setup(fid, arg); 772 773 err = fid->fid_family->ops->configure(fid); 774 if (err) 775 goto err_configure; 776 777 list_add(&fid->list, &fid_family->fids_list); 778 fid->ref_count++; 779 return fid; 780 781 err_configure: 782 __clear_bit(fid_index - fid_family->start_index, 783 fid_family->fids_bitmap); 784 err_index_alloc: 785 kfree(fid); 786 return ERR_PTR(err); 787 } 788 789 void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid) 790 { 791 struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 792 793 if (--fid->ref_count == 1 && fid->rif) { 794 /* Destroy the associated RIF and let it drop the last 795 * reference on the FID. 796 */ 797 return mlxsw_sp_rif_destroy(fid->rif); 798 } else if (fid->ref_count == 0) { 799 list_del(&fid->list); 800 fid->fid_family->ops->deconfigure(fid); 801 __clear_bit(fid->fid_index - fid_family->start_index, 802 fid_family->fids_bitmap); 803 kfree(fid); 804 } 805 } 806 807 struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid) 808 { 809 return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid); 810 } 811 812 struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp, 813 int br_ifindex) 814 { 815 return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, &br_ifindex); 816 } 817 818 struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp, 819 u16 rif_index) 820 { 821 return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_RFID, &rif_index); 822 } 823 824 struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp) 825 { 826 return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_DUMMY, NULL); 827 } 828 829 static int 830 mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family, 831 const struct mlxsw_sp_flood_table *flood_table) 832 { 833 enum mlxsw_sp_flood_type packet_type = flood_table->packet_type; 834 const int *sfgc_packet_types; 835 int i; 836 837 sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type]; 838 for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) { 839 struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; 840 char sfgc_pl[MLXSW_REG_SFGC_LEN]; 841 int err; 842 843 if (!sfgc_packet_types[i]) 844 continue; 845 mlxsw_reg_sfgc_pack(sfgc_pl, i, flood_table->bridge_type, 846 flood_table->table_type, 847 flood_table->table_index); 848 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl); 849 if (err) 850 return err; 851 } 852 853 return 0; 854 } 855 856 static int 857 mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family) 858 { 859 int i; 860 861 for (i = 0; i < fid_family->nr_flood_tables; i++) { 862 const struct mlxsw_sp_flood_table *flood_table; 863 int err; 864 865 flood_table = &fid_family->flood_tables[i]; 866 err = mlxsw_sp_fid_flood_table_init(fid_family, flood_table); 867 if (err) 868 return err; 869 } 870 871 return 0; 872 } 873 874 static int mlxsw_sp_fid_family_register(struct mlxsw_sp *mlxsw_sp, 875 const struct mlxsw_sp_fid_family *tmpl) 876 { 877 u16 nr_fids = tmpl->end_index - tmpl->start_index + 1; 878 struct mlxsw_sp_fid_family *fid_family; 879 int err; 880 881 fid_family = kmemdup(tmpl, sizeof(*fid_family), GFP_KERNEL); 882 if (!fid_family) 883 return -ENOMEM; 884 885 fid_family->mlxsw_sp = mlxsw_sp; 886 INIT_LIST_HEAD(&fid_family->fids_list); 887 fid_family->fids_bitmap = kcalloc(BITS_TO_LONGS(nr_fids), 888 sizeof(unsigned long), GFP_KERNEL); 889 if (!fid_family->fids_bitmap) { 890 err = -ENOMEM; 891 goto err_alloc_fids_bitmap; 892 } 893 894 if (fid_family->flood_tables) { 895 err = mlxsw_sp_fid_flood_tables_init(fid_family); 896 if (err) 897 goto err_fid_flood_tables_init; 898 } 899 900 mlxsw_sp->fid_core->fid_family_arr[tmpl->type] = fid_family; 901 902 return 0; 903 904 err_fid_flood_tables_init: 905 kfree(fid_family->fids_bitmap); 906 err_alloc_fids_bitmap: 907 kfree(fid_family); 908 return err; 909 } 910 911 static void 912 mlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp, 913 struct mlxsw_sp_fid_family *fid_family) 914 { 915 mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL; 916 kfree(fid_family->fids_bitmap); 917 WARN_ON_ONCE(!list_empty(&fid_family->fids_list)); 918 kfree(fid_family); 919 } 920 921 int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port) 922 { 923 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 924 925 /* Track number of FIDs configured on the port with mapping type 926 * PORT_VID_TO_FID, so that we know when to transition the port 927 * back to non-virtual (VLAN) mode. 928 */ 929 mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0; 930 931 return mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); 932 } 933 934 void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port) 935 { 936 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 937 938 mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0; 939 } 940 941 int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp) 942 { 943 unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core); 944 struct mlxsw_sp_fid_core *fid_core; 945 int err, i; 946 947 fid_core = kzalloc(sizeof(*mlxsw_sp->fid_core), GFP_KERNEL); 948 if (!fid_core) 949 return -ENOMEM; 950 mlxsw_sp->fid_core = fid_core; 951 952 fid_core->port_fid_mappings = kcalloc(max_ports, sizeof(unsigned int), 953 GFP_KERNEL); 954 if (!fid_core->port_fid_mappings) { 955 err = -ENOMEM; 956 goto err_alloc_port_fid_mappings; 957 } 958 959 for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) { 960 err = mlxsw_sp_fid_family_register(mlxsw_sp, 961 mlxsw_sp_fid_family_arr[i]); 962 963 if (err) 964 goto err_fid_ops_register; 965 } 966 967 return 0; 968 969 err_fid_ops_register: 970 for (i--; i >= 0; i--) { 971 struct mlxsw_sp_fid_family *fid_family; 972 973 fid_family = fid_core->fid_family_arr[i]; 974 mlxsw_sp_fid_family_unregister(mlxsw_sp, fid_family); 975 } 976 kfree(fid_core->port_fid_mappings); 977 err_alloc_port_fid_mappings: 978 kfree(fid_core); 979 return err; 980 } 981 982 void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp) 983 { 984 struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core; 985 int i; 986 987 for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) 988 mlxsw_sp_fid_family_unregister(mlxsw_sp, 989 fid_core->fid_family_arr[i]); 990 kfree(fid_core->port_fid_mappings); 991 kfree(fid_core); 992 } 993