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