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