root/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mlxsw_sp_fid_is_dummy
  2. mlxsw_sp_fid_lag_vid_valid
  3. mlxsw_sp_fid_lookup_by_index
  4. mlxsw_sp_fid_nve_ifindex
  5. mlxsw_sp_fid_nve_type
  6. mlxsw_sp_fid_lookup_by_vni
  7. mlxsw_sp_fid_vni
  8. mlxsw_sp_fid_nve_flood_index_set
  9. mlxsw_sp_fid_nve_flood_index_clear
  10. mlxsw_sp_fid_nve_flood_index_is_set
  11. mlxsw_sp_fid_vni_set
  12. mlxsw_sp_fid_vni_clear
  13. mlxsw_sp_fid_vni_is_set
  14. mlxsw_sp_fid_fdb_clear_offload
  15. mlxsw_sp_fid_flood_table_lookup
  16. mlxsw_sp_fid_flood_set
  17. mlxsw_sp_fid_port_vid_map
  18. mlxsw_sp_fid_port_vid_unmap
  19. mlxsw_sp_fid_index
  20. mlxsw_sp_fid_rif_set
  21. mlxsw_sp_fid_rif
  22. mlxsw_sp_fid_type_rif_type
  23. mlxsw_sp_fid_8021q_fid
  24. mlxsw_sp_fid_8021q_vid
  25. mlxsw_sp_fid_8021q_setup
  26. mlxsw_sp_sfmr_op
  27. mlxsw_sp_fid_op
  28. mlxsw_sp_fid_vni_op
  29. mlxsw_sp_fid_vid_map
  30. __mlxsw_sp_fid_port_vid_map
  31. mlxsw_sp_fid_8021q_configure
  32. mlxsw_sp_fid_8021q_deconfigure
  33. mlxsw_sp_fid_8021q_index_alloc
  34. mlxsw_sp_fid_8021q_compare
  35. mlxsw_sp_fid_8021q_flood_index
  36. mlxsw_sp_fid_8021q_port_vid_map
  37. mlxsw_sp_fid_8021q_port_vid_unmap
  38. mlxsw_sp_fid_8021d_fid
  39. mlxsw_sp_fid_8021d_setup
  40. mlxsw_sp_fid_8021d_configure
  41. mlxsw_sp_fid_8021d_deconfigure
  42. mlxsw_sp_fid_8021d_index_alloc
  43. mlxsw_sp_fid_8021d_compare
  44. mlxsw_sp_fid_8021d_flood_index
  45. mlxsw_sp_port_vp_mode_trans
  46. mlxsw_sp_port_vlan_mode_trans
  47. mlxsw_sp_fid_8021d_port_vid_map
  48. mlxsw_sp_fid_8021d_port_vid_unmap
  49. mlxsw_sp_fid_8021d_vni_set
  50. mlxsw_sp_fid_8021d_vni_clear
  51. mlxsw_sp_fid_8021d_nve_flood_index_set
  52. mlxsw_sp_fid_8021d_nve_flood_index_clear
  53. mlxsw_sp_fid_8021d_fdb_clear_offload
  54. mlxsw_sp_fid_8021q_fdb_clear_offload
  55. mlxsw_sp_fid_rfid_configure
  56. mlxsw_sp_fid_rfid_deconfigure
  57. mlxsw_sp_fid_rfid_index_alloc
  58. mlxsw_sp_fid_rfid_compare
  59. mlxsw_sp_fid_rfid_port_vid_map
  60. mlxsw_sp_fid_rfid_port_vid_unmap
  61. mlxsw_sp_fid_dummy_configure
  62. mlxsw_sp_fid_dummy_deconfigure
  63. mlxsw_sp_fid_dummy_index_alloc
  64. mlxsw_sp_fid_dummy_compare
  65. mlxsw_sp_fid_lookup
  66. mlxsw_sp_fid_get
  67. mlxsw_sp_fid_put
  68. mlxsw_sp_fid_8021q_get
  69. mlxsw_sp_fid_8021d_get
  70. mlxsw_sp_fid_8021q_lookup
  71. mlxsw_sp_fid_8021d_lookup
  72. mlxsw_sp_fid_rfid_get
  73. mlxsw_sp_fid_dummy_get
  74. mlxsw_sp_fid_flood_table_init
  75. mlxsw_sp_fid_flood_tables_init
  76. mlxsw_sp_fid_family_register
  77. mlxsw_sp_fid_family_unregister
  78. mlxsw_sp_port_fids_init
  79. mlxsw_sp_port_fids_fini
  80. mlxsw_sp_fids_init
  81. mlxsw_sp_fids_fini

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

/* [<][>][^][v][top][bottom][index][help] */