1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
3
4 #include <linux/kernel.h>
5 #include <linux/bitops.h>
6 #include <linux/if_vlan.h>
7 #include <linux/if_bridge.h>
8 #include <linux/netdevice.h>
9 #include <linux/rhashtable.h>
10 #include <linux/rtnetlink.h>
11 #include <linux/refcount.h>
12
13 #include "spectrum.h"
14 #include "reg.h"
15
16 struct mlxsw_sp_fid_family;
17
18 struct mlxsw_sp_fid_core {
19 struct rhashtable fid_ht;
20 struct rhashtable vni_ht;
21 struct mlxsw_sp_fid_family *fid_family_arr[MLXSW_SP_FID_TYPE_MAX];
22 unsigned int *port_fid_mappings;
23 };
24
25 struct mlxsw_sp_fid_port_vid {
26 struct list_head list;
27 u16 local_port;
28 u16 vid;
29 };
30
31 struct mlxsw_sp_fid {
32 struct list_head list;
33 struct mlxsw_sp_rif *rif;
34 refcount_t ref_count;
35 u16 fid_index;
36 u16 fid_offset;
37 struct mlxsw_sp_fid_family *fid_family;
38 struct rhash_head ht_node;
39
40 struct rhash_head vni_ht_node;
41 enum mlxsw_sp_nve_type nve_type;
42 __be32 vni;
43 u32 nve_flood_index;
44 int nve_ifindex;
45 u8 vni_valid:1,
46 nve_flood_index_valid:1;
47 struct list_head port_vid_list; /* Ordered by local port. */
48 };
49
50 struct mlxsw_sp_fid_8021q {
51 struct mlxsw_sp_fid common;
52 u16 vid;
53 };
54
55 struct mlxsw_sp_fid_8021d {
56 struct mlxsw_sp_fid common;
57 int br_ifindex;
58 };
59
60 static const struct rhashtable_params mlxsw_sp_fid_ht_params = {
61 .key_len = sizeof_field(struct mlxsw_sp_fid, fid_index),
62 .key_offset = offsetof(struct mlxsw_sp_fid, fid_index),
63 .head_offset = offsetof(struct mlxsw_sp_fid, ht_node),
64 };
65
66 static const struct rhashtable_params mlxsw_sp_fid_vni_ht_params = {
67 .key_len = sizeof_field(struct mlxsw_sp_fid, vni),
68 .key_offset = offsetof(struct mlxsw_sp_fid, vni),
69 .head_offset = offsetof(struct mlxsw_sp_fid, vni_ht_node),
70 };
71
72 struct mlxsw_sp_flood_table {
73 enum mlxsw_sp_flood_type packet_type;
74 enum mlxsw_flood_table_type table_type;
75 int table_index;
76 };
77
78 struct mlxsw_sp_fid_ops {
79 void (*setup)(struct mlxsw_sp_fid *fid, const void *arg);
80 int (*configure)(struct mlxsw_sp_fid *fid);
81 void (*deconfigure)(struct mlxsw_sp_fid *fid);
82 int (*index_alloc)(struct mlxsw_sp_fid *fid, const void *arg,
83 u16 *p_fid_index);
84 bool (*compare)(const struct mlxsw_sp_fid *fid,
85 const void *arg);
86 int (*port_vid_map)(struct mlxsw_sp_fid *fid,
87 struct mlxsw_sp_port *port, u16 vid);
88 void (*port_vid_unmap)(struct mlxsw_sp_fid *fid,
89 struct mlxsw_sp_port *port, u16 vid);
90 int (*vni_set)(struct mlxsw_sp_fid *fid);
91 void (*vni_clear)(struct mlxsw_sp_fid *fid);
92 int (*nve_flood_index_set)(struct mlxsw_sp_fid *fid);
93 void (*nve_flood_index_clear)(struct mlxsw_sp_fid *fid);
94 void (*fdb_clear_offload)(const struct mlxsw_sp_fid *fid,
95 const struct net_device *nve_dev);
96 int (*vid_to_fid_rif_update)(const struct mlxsw_sp_fid *fid,
97 const struct mlxsw_sp_rif *rif);
98 };
99
100 struct mlxsw_sp_fid_family {
101 enum mlxsw_sp_fid_type type;
102 size_t fid_size;
103 u16 start_index;
104 u16 end_index;
105 struct list_head fids_list;
106 unsigned long *fids_bitmap;
107 const struct mlxsw_sp_flood_table *flood_tables;
108 int nr_flood_tables;
109 enum mlxsw_sp_rif_type rif_type;
110 const struct mlxsw_sp_fid_ops *ops;
111 struct mlxsw_sp *mlxsw_sp;
112 bool flood_rsp;
113 enum mlxsw_reg_bridge_type bridge_type;
114 u16 pgt_base;
115 bool smpe_index_valid;
116 };
117
118 static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
119 [MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST] = 1,
120 };
121
122 static const int mlxsw_sp_sfgc_bc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
123 [MLXSW_REG_SFGC_TYPE_BROADCAST] = 1,
124 [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP] = 1,
125 [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL] = 1,
126 [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST] = 1,
127 [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1,
128 };
129
130 static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
131 [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1,
132 };
133
134 static const int *mlxsw_sp_packet_type_sfgc_types[] = {
135 [MLXSW_SP_FLOOD_TYPE_UC] = mlxsw_sp_sfgc_uc_packet_types,
136 [MLXSW_SP_FLOOD_TYPE_BC] = mlxsw_sp_sfgc_bc_packet_types,
137 [MLXSW_SP_FLOOD_TYPE_MC] = mlxsw_sp_sfgc_mc_packet_types,
138 };
139
mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp * mlxsw_sp,u16 fid_index)140 struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp,
141 u16 fid_index)
142 {
143 struct mlxsw_sp_fid *fid;
144
145 fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->fid_ht, &fid_index,
146 mlxsw_sp_fid_ht_params);
147 if (fid)
148 refcount_inc(&fid->ref_count);
149
150 return fid;
151 }
152
mlxsw_sp_fid_nve_ifindex(const struct mlxsw_sp_fid * fid,int * nve_ifindex)153 int mlxsw_sp_fid_nve_ifindex(const struct mlxsw_sp_fid *fid, int *nve_ifindex)
154 {
155 if (!fid->vni_valid)
156 return -EINVAL;
157
158 *nve_ifindex = fid->nve_ifindex;
159
160 return 0;
161 }
162
mlxsw_sp_fid_nve_type(const struct mlxsw_sp_fid * fid,enum mlxsw_sp_nve_type * p_type)163 int mlxsw_sp_fid_nve_type(const struct mlxsw_sp_fid *fid,
164 enum mlxsw_sp_nve_type *p_type)
165 {
166 if (!fid->vni_valid)
167 return -EINVAL;
168
169 *p_type = fid->nve_type;
170
171 return 0;
172 }
173
mlxsw_sp_fid_lookup_by_vni(struct mlxsw_sp * mlxsw_sp,__be32 vni)174 struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_vni(struct mlxsw_sp *mlxsw_sp,
175 __be32 vni)
176 {
177 struct mlxsw_sp_fid *fid;
178
179 fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->vni_ht, &vni,
180 mlxsw_sp_fid_vni_ht_params);
181 if (fid)
182 refcount_inc(&fid->ref_count);
183
184 return fid;
185 }
186
mlxsw_sp_fid_vni(const struct mlxsw_sp_fid * fid,__be32 * vni)187 int mlxsw_sp_fid_vni(const struct mlxsw_sp_fid *fid, __be32 *vni)
188 {
189 if (!fid->vni_valid)
190 return -EINVAL;
191
192 *vni = fid->vni;
193
194 return 0;
195 }
196
mlxsw_sp_fid_nve_flood_index_set(struct mlxsw_sp_fid * fid,u32 nve_flood_index)197 int mlxsw_sp_fid_nve_flood_index_set(struct mlxsw_sp_fid *fid,
198 u32 nve_flood_index)
199 {
200 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
201 const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
202 int err;
203
204 if (WARN_ON(fid->nve_flood_index_valid))
205 return -EINVAL;
206
207 fid->nve_flood_index = nve_flood_index;
208 fid->nve_flood_index_valid = true;
209 err = ops->nve_flood_index_set(fid);
210 if (err)
211 goto err_nve_flood_index_set;
212
213 return 0;
214
215 err_nve_flood_index_set:
216 fid->nve_flood_index_valid = false;
217 return err;
218 }
219
mlxsw_sp_fid_nve_flood_index_clear(struct mlxsw_sp_fid * fid)220 void mlxsw_sp_fid_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
221 {
222 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
223 const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
224
225 if (WARN_ON(!fid->nve_flood_index_valid))
226 return;
227
228 fid->nve_flood_index_valid = false;
229 ops->nve_flood_index_clear(fid);
230 }
231
mlxsw_sp_fid_nve_flood_index_is_set(const struct mlxsw_sp_fid * fid)232 bool mlxsw_sp_fid_nve_flood_index_is_set(const struct mlxsw_sp_fid *fid)
233 {
234 return fid->nve_flood_index_valid;
235 }
236
mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid * fid,enum mlxsw_sp_nve_type type,__be32 vni,int nve_ifindex)237 int mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid *fid, enum mlxsw_sp_nve_type type,
238 __be32 vni, int nve_ifindex)
239 {
240 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
241 const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
242 struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
243 int err;
244
245 if (WARN_ON(fid->vni_valid))
246 return -EINVAL;
247
248 fid->nve_type = type;
249 fid->nve_ifindex = nve_ifindex;
250 fid->vni = vni;
251 err = rhashtable_lookup_insert_fast(&mlxsw_sp->fid_core->vni_ht,
252 &fid->vni_ht_node,
253 mlxsw_sp_fid_vni_ht_params);
254 if (err)
255 return err;
256
257 fid->vni_valid = true;
258 err = ops->vni_set(fid);
259 if (err)
260 goto err_vni_set;
261
262 return 0;
263
264 err_vni_set:
265 fid->vni_valid = false;
266 rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node,
267 mlxsw_sp_fid_vni_ht_params);
268 return err;
269 }
270
mlxsw_sp_fid_vni_clear(struct mlxsw_sp_fid * fid)271 void mlxsw_sp_fid_vni_clear(struct mlxsw_sp_fid *fid)
272 {
273 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
274 const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
275 struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
276
277 if (WARN_ON(!fid->vni_valid))
278 return;
279
280 fid->vni_valid = false;
281 ops->vni_clear(fid);
282 rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node,
283 mlxsw_sp_fid_vni_ht_params);
284 }
285
mlxsw_sp_fid_vni_is_set(const struct mlxsw_sp_fid * fid)286 bool mlxsw_sp_fid_vni_is_set(const struct mlxsw_sp_fid *fid)
287 {
288 return fid->vni_valid;
289 }
290
mlxsw_sp_fid_fdb_clear_offload(const struct mlxsw_sp_fid * fid,const struct net_device * nve_dev)291 void mlxsw_sp_fid_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
292 const struct net_device *nve_dev)
293 {
294 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
295 const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
296
297 if (ops->fdb_clear_offload)
298 ops->fdb_clear_offload(fid, nve_dev);
299 }
300
301 static const struct mlxsw_sp_flood_table *
mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid * fid,enum mlxsw_sp_flood_type packet_type)302 mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid,
303 enum mlxsw_sp_flood_type packet_type)
304 {
305 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
306 int i;
307
308 for (i = 0; i < fid_family->nr_flood_tables; i++) {
309 if (fid_family->flood_tables[i].packet_type != packet_type)
310 continue;
311 return &fid_family->flood_tables[i];
312 }
313
314 return NULL;
315 }
316
317 static u16
mlxsw_sp_fid_family_num_fids(const struct mlxsw_sp_fid_family * fid_family)318 mlxsw_sp_fid_family_num_fids(const struct mlxsw_sp_fid_family *fid_family)
319 {
320 return fid_family->end_index - fid_family->start_index + 1;
321 }
322
323 static u16
mlxsw_sp_fid_flood_table_mid(const struct mlxsw_sp_fid_family * fid_family,const struct mlxsw_sp_flood_table * flood_table,u16 fid_offset)324 mlxsw_sp_fid_flood_table_mid(const struct mlxsw_sp_fid_family *fid_family,
325 const struct mlxsw_sp_flood_table *flood_table,
326 u16 fid_offset)
327 {
328 u16 num_fids;
329
330 num_fids = mlxsw_sp_fid_family_num_fids(fid_family);
331 return fid_family->pgt_base + num_fids * flood_table->table_index +
332 fid_offset;
333 }
334
mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid * fid,enum mlxsw_sp_flood_type packet_type,u16 local_port,bool member)335 int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid,
336 enum mlxsw_sp_flood_type packet_type, u16 local_port,
337 bool member)
338 {
339 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
340 const struct mlxsw_sp_flood_table *flood_table;
341 u16 mid_index;
342
343 if (WARN_ON(!fid_family->flood_tables))
344 return -EINVAL;
345
346 flood_table = mlxsw_sp_fid_flood_table_lookup(fid, packet_type);
347 if (!flood_table)
348 return -ESRCH;
349
350 mid_index = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table,
351 fid->fid_offset);
352 return mlxsw_sp_pgt_entry_port_set(fid_family->mlxsw_sp, mid_index,
353 fid->fid_index, local_port, member);
354 }
355
mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)356 int mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid *fid,
357 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
358 {
359 if (WARN_ON(!fid->fid_family->ops->port_vid_map))
360 return -EINVAL;
361 return fid->fid_family->ops->port_vid_map(fid, mlxsw_sp_port, vid);
362 }
363
mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)364 void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid,
365 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
366 {
367 fid->fid_family->ops->port_vid_unmap(fid, mlxsw_sp_port, vid);
368 }
369
mlxsw_sp_fid_index(const struct mlxsw_sp_fid * fid)370 u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid)
371 {
372 return fid->fid_index;
373 }
374
mlxsw_sp_fid_type(const struct mlxsw_sp_fid * fid)375 enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid)
376 {
377 return fid->fid_family->type;
378 }
379
mlxsw_sp_fid_rif(const struct mlxsw_sp_fid * fid)380 struct mlxsw_sp_rif *mlxsw_sp_fid_rif(const struct mlxsw_sp_fid *fid)
381 {
382 return fid->rif;
383 }
384
385 enum mlxsw_sp_rif_type
mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp * mlxsw_sp,enum mlxsw_sp_fid_type type)386 mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp,
387 enum mlxsw_sp_fid_type type)
388 {
389 struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
390
391 return fid_core->fid_family_arr[type]->rif_type;
392 }
393
394 static struct mlxsw_sp_fid_8021q *
mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid * fid)395 mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid)
396 {
397 return container_of(fid, struct mlxsw_sp_fid_8021q, common);
398 }
399
mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid * fid)400 u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid)
401 {
402 return mlxsw_sp_fid_8021q_fid(fid)->vid;
403 }
404
mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid * fid,const void * arg)405 static void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg)
406 {
407 u16 vid = *(u16 *) arg;
408
409 mlxsw_sp_fid_8021q_fid(fid)->vid = vid;
410 fid->fid_offset = fid->fid_index - fid->fid_family->start_index;
411 }
412
mlxsw_sp_sfmr_op(bool valid)413 static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid)
414 {
415 return valid ? MLXSW_REG_SFMR_OP_CREATE_FID :
416 MLXSW_REG_SFMR_OP_DESTROY_FID;
417 }
418
mlxsw_sp_fid_op(const struct mlxsw_sp_fid * fid,bool valid)419 static int mlxsw_sp_fid_op(const struct mlxsw_sp_fid *fid, bool valid)
420 {
421 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
422 char sfmr_pl[MLXSW_REG_SFMR_LEN];
423 u16 smpe;
424
425 smpe = fid->fid_family->smpe_index_valid ? fid->fid_index : 0;
426
427 mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid->fid_index,
428 fid->fid_offset, fid->fid_family->flood_rsp,
429 fid->fid_family->bridge_type,
430 fid->fid_family->smpe_index_valid, smpe);
431 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
432 }
433
mlxsw_sp_fid_edit_op(const struct mlxsw_sp_fid * fid,const struct mlxsw_sp_rif * rif)434 static int mlxsw_sp_fid_edit_op(const struct mlxsw_sp_fid *fid,
435 const struct mlxsw_sp_rif *rif)
436 {
437 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
438 char sfmr_pl[MLXSW_REG_SFMR_LEN];
439 u16 smpe;
440
441 smpe = fid->fid_family->smpe_index_valid ? fid->fid_index : 0;
442
443 mlxsw_reg_sfmr_pack(sfmr_pl, MLXSW_REG_SFMR_OP_CREATE_FID,
444 fid->fid_index, fid->fid_offset,
445 fid->fid_family->flood_rsp,
446 fid->fid_family->bridge_type,
447 fid->fid_family->smpe_index_valid, smpe);
448 mlxsw_reg_sfmr_vv_set(sfmr_pl, fid->vni_valid);
449 mlxsw_reg_sfmr_vni_set(sfmr_pl, be32_to_cpu(fid->vni));
450 mlxsw_reg_sfmr_vtfp_set(sfmr_pl, fid->nve_flood_index_valid);
451 mlxsw_reg_sfmr_nve_tunnel_flood_ptr_set(sfmr_pl, fid->nve_flood_index);
452
453 if (rif) {
454 mlxsw_reg_sfmr_irif_v_set(sfmr_pl, true);
455 mlxsw_reg_sfmr_irif_set(sfmr_pl, mlxsw_sp_rif_index(rif));
456 }
457
458 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
459 }
460
mlxsw_sp_fid_vni_to_fid_map(const struct mlxsw_sp_fid * fid,const struct mlxsw_sp_rif * rif,bool valid)461 static int mlxsw_sp_fid_vni_to_fid_map(const struct mlxsw_sp_fid *fid,
462 const struct mlxsw_sp_rif *rif,
463 bool valid)
464 {
465 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
466 char svfa_pl[MLXSW_REG_SVFA_LEN];
467 bool irif_valid;
468 u16 irif_index;
469
470 irif_valid = !!rif;
471 irif_index = rif ? mlxsw_sp_rif_index(rif) : 0;
472
473 mlxsw_reg_svfa_vni_pack(svfa_pl, valid, fid->fid_index,
474 be32_to_cpu(fid->vni), irif_valid, irif_index);
475 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
476 }
477
mlxsw_sp_fid_to_fid_rif_update(const struct mlxsw_sp_fid * fid,const struct mlxsw_sp_rif * rif)478 static int mlxsw_sp_fid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
479 const struct mlxsw_sp_rif *rif)
480 {
481 return mlxsw_sp_fid_edit_op(fid, rif);
482 }
483
mlxsw_sp_fid_vni_to_fid_rif_update(const struct mlxsw_sp_fid * fid,const struct mlxsw_sp_rif * rif)484 static int mlxsw_sp_fid_vni_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
485 const struct mlxsw_sp_rif *rif)
486 {
487 if (!fid->vni_valid)
488 return 0;
489
490 return mlxsw_sp_fid_vni_to_fid_map(fid, rif, fid->vni_valid);
491 }
492
493 static int
mlxsw_sp_fid_vid_to_fid_map(const struct mlxsw_sp_fid * fid,u16 vid,bool valid,const struct mlxsw_sp_rif * rif)494 mlxsw_sp_fid_vid_to_fid_map(const struct mlxsw_sp_fid *fid, u16 vid, bool valid,
495 const struct mlxsw_sp_rif *rif)
496 {
497 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
498 char svfa_pl[MLXSW_REG_SVFA_LEN];
499 bool irif_valid;
500 u16 irif_index;
501
502 irif_valid = !!rif;
503 irif_index = rif ? mlxsw_sp_rif_index(rif) : 0;
504
505 mlxsw_reg_svfa_vid_pack(svfa_pl, valid, fid->fid_index, vid, irif_valid,
506 irif_index);
507 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
508 }
509
510 static int
mlxsw_sp_fid_8021q_vid_to_fid_rif_update(const struct mlxsw_sp_fid * fid,const struct mlxsw_sp_rif * rif)511 mlxsw_sp_fid_8021q_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
512 const struct mlxsw_sp_rif *rif)
513 {
514 struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
515
516 /* Update the global VID => FID mapping we created when the FID was
517 * configured.
518 */
519 return mlxsw_sp_fid_vid_to_fid_map(fid, fid_8021q->vid, true, rif);
520 }
521
522 static int
mlxsw_sp_fid_port_vid_to_fid_rif_update_one(const struct mlxsw_sp_fid * fid,struct mlxsw_sp_fid_port_vid * pv,bool irif_valid,u16 irif_index)523 mlxsw_sp_fid_port_vid_to_fid_rif_update_one(const struct mlxsw_sp_fid *fid,
524 struct mlxsw_sp_fid_port_vid *pv,
525 bool irif_valid, u16 irif_index)
526 {
527 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
528 char svfa_pl[MLXSW_REG_SVFA_LEN];
529
530 mlxsw_reg_svfa_port_vid_pack(svfa_pl, pv->local_port, true,
531 fid->fid_index, pv->vid, irif_valid,
532 irif_index);
533
534 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
535 }
536
mlxsw_sp_fid_vid_to_fid_rif_set(const struct mlxsw_sp_fid * fid,const struct mlxsw_sp_rif * rif)537 static int mlxsw_sp_fid_vid_to_fid_rif_set(const struct mlxsw_sp_fid *fid,
538 const struct mlxsw_sp_rif *rif)
539 {
540 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
541 struct mlxsw_sp_fid_port_vid *pv;
542 u16 irif_index;
543 int err;
544
545 err = fid->fid_family->ops->vid_to_fid_rif_update(fid, rif);
546 if (err)
547 return err;
548
549 irif_index = mlxsw_sp_rif_index(rif);
550
551 list_for_each_entry(pv, &fid->port_vid_list, list) {
552 /* If port is not in virtual mode, then it does not have any
553 * {Port, VID}->FID mappings that need to be updated with the
554 * ingress RIF.
555 */
556 if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port])
557 continue;
558
559 err = mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv,
560 true,
561 irif_index);
562 if (err)
563 goto err_port_vid_to_fid_rif_update_one;
564 }
565
566 return 0;
567
568 err_port_vid_to_fid_rif_update_one:
569 list_for_each_entry_continue_reverse(pv, &fid->port_vid_list, list) {
570 if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port])
571 continue;
572
573 mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv, false, 0);
574 }
575
576 fid->fid_family->ops->vid_to_fid_rif_update(fid, NULL);
577 return err;
578 }
579
mlxsw_sp_fid_vid_to_fid_rif_unset(const struct mlxsw_sp_fid * fid)580 static void mlxsw_sp_fid_vid_to_fid_rif_unset(const struct mlxsw_sp_fid *fid)
581 {
582 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
583 struct mlxsw_sp_fid_port_vid *pv;
584
585 list_for_each_entry(pv, &fid->port_vid_list, list) {
586 /* If port is not in virtual mode, then it does not have any
587 * {Port, VID}->FID mappings that need to be updated.
588 */
589 if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port])
590 continue;
591
592 mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv, false, 0);
593 }
594
595 fid->fid_family->ops->vid_to_fid_rif_update(fid, NULL);
596 }
597
mlxsw_sp_fid_reiv_handle(struct mlxsw_sp_fid * fid,u16 rif_index,bool valid,u8 port_page)598 static int mlxsw_sp_fid_reiv_handle(struct mlxsw_sp_fid *fid, u16 rif_index,
599 bool valid, u8 port_page)
600 {
601 u16 local_port_end = (port_page + 1) * MLXSW_REG_REIV_REC_MAX_COUNT - 1;
602 u16 local_port_start = port_page * MLXSW_REG_REIV_REC_MAX_COUNT;
603 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
604 struct mlxsw_sp_fid_port_vid *port_vid;
605 u8 rec_num, entries_num = 0;
606 char *reiv_pl;
607 int err;
608
609 reiv_pl = kmalloc(MLXSW_REG_REIV_LEN, GFP_KERNEL);
610 if (!reiv_pl)
611 return -ENOMEM;
612
613 mlxsw_reg_reiv_pack(reiv_pl, port_page, rif_index);
614
615 list_for_each_entry(port_vid, &fid->port_vid_list, list) {
616 /* port_vid_list is sorted by local_port. */
617 if (port_vid->local_port < local_port_start)
618 continue;
619
620 if (port_vid->local_port > local_port_end)
621 break;
622
623 rec_num = port_vid->local_port % MLXSW_REG_REIV_REC_MAX_COUNT;
624 mlxsw_reg_reiv_rec_update_set(reiv_pl, rec_num, true);
625 mlxsw_reg_reiv_rec_evid_set(reiv_pl, rec_num,
626 valid ? port_vid->vid : 0);
627 entries_num++;
628 }
629
630 if (!entries_num) {
631 kfree(reiv_pl);
632 return 0;
633 }
634
635 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(reiv), reiv_pl);
636 if (err)
637 goto err_reg_write;
638
639 kfree(reiv_pl);
640 return 0;
641
642 err_reg_write:
643 kfree(reiv_pl);
644 return err;
645 }
646
mlxsw_sp_fid_erif_eport_to_vid_map(struct mlxsw_sp_fid * fid,u16 rif_index,bool valid)647 static int mlxsw_sp_fid_erif_eport_to_vid_map(struct mlxsw_sp_fid *fid,
648 u16 rif_index, bool valid)
649 {
650 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
651 u8 num_port_pages;
652 int err, i;
653
654 num_port_pages = mlxsw_core_max_ports(mlxsw_sp->core) /
655 MLXSW_REG_REIV_REC_MAX_COUNT + 1;
656
657 for (i = 0; i < num_port_pages; i++) {
658 err = mlxsw_sp_fid_reiv_handle(fid, rif_index, valid, i);
659 if (err)
660 goto err_reiv_handle;
661 }
662
663 return 0;
664
665 err_reiv_handle:
666 for (; i >= 0; i--)
667 mlxsw_sp_fid_reiv_handle(fid, rif_index, !valid, i);
668 return err;
669 }
670
mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid * fid,struct mlxsw_sp_rif * rif)671 int mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif)
672 {
673 u16 rif_index = mlxsw_sp_rif_index(rif);
674 int err;
675
676 err = mlxsw_sp_fid_to_fid_rif_update(fid, rif);
677 if (err)
678 return err;
679
680 err = mlxsw_sp_fid_vni_to_fid_rif_update(fid, rif);
681 if (err)
682 goto err_vni_to_fid_rif_update;
683
684 err = mlxsw_sp_fid_vid_to_fid_rif_set(fid, rif);
685 if (err)
686 goto err_vid_to_fid_rif_set;
687
688 err = mlxsw_sp_fid_erif_eport_to_vid_map(fid, rif_index, true);
689 if (err)
690 goto err_erif_eport_to_vid_map;
691
692 fid->rif = rif;
693 return 0;
694
695 err_erif_eport_to_vid_map:
696 mlxsw_sp_fid_vid_to_fid_rif_unset(fid);
697 err_vid_to_fid_rif_set:
698 mlxsw_sp_fid_vni_to_fid_rif_update(fid, NULL);
699 err_vni_to_fid_rif_update:
700 mlxsw_sp_fid_to_fid_rif_update(fid, NULL);
701 return err;
702 }
703
mlxsw_sp_fid_rif_unset(struct mlxsw_sp_fid * fid)704 void mlxsw_sp_fid_rif_unset(struct mlxsw_sp_fid *fid)
705 {
706 u16 rif_index;
707
708 if (!fid->rif)
709 return;
710
711 rif_index = mlxsw_sp_rif_index(fid->rif);
712 fid->rif = NULL;
713
714 mlxsw_sp_fid_erif_eport_to_vid_map(fid, rif_index, false);
715 mlxsw_sp_fid_vid_to_fid_rif_unset(fid);
716 mlxsw_sp_fid_vni_to_fid_rif_update(fid, NULL);
717 mlxsw_sp_fid_to_fid_rif_update(fid, NULL);
718 }
719
mlxsw_sp_fid_vni_op(const struct mlxsw_sp_fid * fid)720 static int mlxsw_sp_fid_vni_op(const struct mlxsw_sp_fid *fid)
721 {
722 int err;
723
724 err = mlxsw_sp_fid_vni_to_fid_map(fid, fid->rif, fid->vni_valid);
725 if (err)
726 return err;
727
728 err = mlxsw_sp_fid_edit_op(fid, fid->rif);
729 if (err)
730 goto err_fid_edit_op;
731
732 return 0;
733
734 err_fid_edit_op:
735 mlxsw_sp_fid_vni_to_fid_map(fid, fid->rif, !fid->vni_valid);
736 return err;
737 }
738
__mlxsw_sp_fid_port_vid_map(const struct mlxsw_sp_fid * fid,u16 local_port,u16 vid,bool valid)739 static int __mlxsw_sp_fid_port_vid_map(const struct mlxsw_sp_fid *fid,
740 u16 local_port, u16 vid, bool valid)
741 {
742 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
743 char svfa_pl[MLXSW_REG_SVFA_LEN];
744 bool irif_valid = false;
745 u16 irif_index = 0;
746
747 if (fid->rif) {
748 irif_valid = true;
749 irif_index = mlxsw_sp_rif_index(fid->rif);
750 }
751
752 mlxsw_reg_svfa_port_vid_pack(svfa_pl, local_port, valid, fid->fid_index,
753 vid, irif_valid, irif_index);
754 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
755 }
756
757 static struct mlxsw_sp_fid_8021d *
mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid * fid)758 mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid)
759 {
760 return container_of(fid, struct mlxsw_sp_fid_8021d, common);
761 }
762
mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid * fid,const void * arg)763 static void mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg)
764 {
765 int br_ifindex = *(int *) arg;
766
767 mlxsw_sp_fid_8021d_fid(fid)->br_ifindex = br_ifindex;
768 fid->fid_offset = fid->fid_index - fid->fid_family->start_index;
769 }
770
mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid * fid)771 static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid)
772 {
773 return mlxsw_sp_fid_op(fid, true);
774 }
775
mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid * fid)776 static void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid *fid)
777 {
778 if (fid->vni_valid)
779 mlxsw_sp_nve_fid_disable(fid->fid_family->mlxsw_sp, fid);
780 mlxsw_sp_fid_op(fid, false);
781 }
782
mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid * fid,const void * arg,u16 * p_fid_index)783 static int mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid *fid,
784 const void *arg, u16 *p_fid_index)
785 {
786 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
787 u16 nr_fids, fid_index;
788
789 nr_fids = fid_family->end_index - fid_family->start_index + 1;
790 fid_index = find_first_zero_bit(fid_family->fids_bitmap, nr_fids);
791 if (fid_index == nr_fids)
792 return -ENOBUFS;
793 *p_fid_index = fid_family->start_index + fid_index;
794
795 return 0;
796 }
797
798 static bool
mlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid * fid,const void * arg)799 mlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid *fid, const void *arg)
800 {
801 int br_ifindex = *(int *) arg;
802
803 return mlxsw_sp_fid_8021d_fid(fid)->br_ifindex == br_ifindex;
804 }
805
mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port * mlxsw_sp_port)806 static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
807 {
808 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
809 int err;
810
811 list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list,
812 list) {
813 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
814 u16 vid = mlxsw_sp_port_vlan->vid;
815
816 if (!fid)
817 continue;
818
819 err = __mlxsw_sp_fid_port_vid_map(fid,
820 mlxsw_sp_port->local_port,
821 vid, true);
822 if (err)
823 goto err_fid_port_vid_map;
824 }
825
826 err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true);
827 if (err)
828 goto err_port_vp_mode_set;
829
830 return 0;
831
832 err_port_vp_mode_set:
833 err_fid_port_vid_map:
834 list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan,
835 &mlxsw_sp_port->vlans_list, list) {
836 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
837 u16 vid = mlxsw_sp_port_vlan->vid;
838
839 if (!fid)
840 continue;
841
842 __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,
843 false);
844 }
845 return err;
846 }
847
mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port * mlxsw_sp_port)848 static void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
849 {
850 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
851
852 mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
853
854 list_for_each_entry_reverse(mlxsw_sp_port_vlan,
855 &mlxsw_sp_port->vlans_list, list) {
856 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
857 u16 vid = mlxsw_sp_port_vlan->vid;
858
859 if (!fid)
860 continue;
861
862 __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,
863 false);
864 }
865 }
866
867 static int
mlxsw_sp_fid_port_vid_list_add(struct mlxsw_sp_fid * fid,u16 local_port,u16 vid)868 mlxsw_sp_fid_port_vid_list_add(struct mlxsw_sp_fid *fid, u16 local_port,
869 u16 vid)
870 {
871 struct mlxsw_sp_fid_port_vid *port_vid, *tmp_port_vid;
872
873 port_vid = kzalloc(sizeof(*port_vid), GFP_KERNEL);
874 if (!port_vid)
875 return -ENOMEM;
876
877 port_vid->local_port = local_port;
878 port_vid->vid = vid;
879
880 list_for_each_entry(tmp_port_vid, &fid->port_vid_list, list) {
881 if (tmp_port_vid->local_port > local_port)
882 break;
883 }
884
885 list_add_tail(&port_vid->list, &tmp_port_vid->list);
886 return 0;
887 }
888
889 static void
mlxsw_sp_fid_port_vid_list_del(struct mlxsw_sp_fid * fid,u16 local_port,u16 vid)890 mlxsw_sp_fid_port_vid_list_del(struct mlxsw_sp_fid *fid, u16 local_port,
891 u16 vid)
892 {
893 struct mlxsw_sp_fid_port_vid *port_vid, *tmp;
894
895 list_for_each_entry_safe(port_vid, tmp, &fid->port_vid_list, list) {
896 if (port_vid->local_port != local_port || port_vid->vid != vid)
897 continue;
898
899 list_del(&port_vid->list);
900 kfree(port_vid);
901 return;
902 }
903 }
904
905 static int
mlxsw_sp_fid_mpe_table_map(const struct mlxsw_sp_fid * fid,u16 local_port,u16 vid,bool valid)906 mlxsw_sp_fid_mpe_table_map(const struct mlxsw_sp_fid *fid, u16 local_port,
907 u16 vid, bool valid)
908 {
909 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
910 char smpe_pl[MLXSW_REG_SMPE_LEN];
911
912 mlxsw_reg_smpe_pack(smpe_pl, local_port, fid->fid_index,
913 valid ? vid : 0);
914 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(smpe), smpe_pl);
915 }
916
917 static int
mlxsw_sp_fid_erif_eport_to_vid_map_one(const struct mlxsw_sp_fid * fid,u16 local_port,u16 vid,bool valid)918 mlxsw_sp_fid_erif_eport_to_vid_map_one(const struct mlxsw_sp_fid *fid,
919 u16 local_port, u16 vid, bool valid)
920 {
921 u8 port_page = local_port / MLXSW_REG_REIV_REC_MAX_COUNT;
922 u8 rec_num = local_port % MLXSW_REG_REIV_REC_MAX_COUNT;
923 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
924 u16 rif_index = mlxsw_sp_rif_index(fid->rif);
925 char *reiv_pl;
926 int err;
927
928 reiv_pl = kmalloc(MLXSW_REG_REIV_LEN, GFP_KERNEL);
929 if (!reiv_pl)
930 return -ENOMEM;
931
932 mlxsw_reg_reiv_pack(reiv_pl, port_page, rif_index);
933 mlxsw_reg_reiv_rec_update_set(reiv_pl, rec_num, true);
934 mlxsw_reg_reiv_rec_evid_set(reiv_pl, rec_num, valid ? vid : 0);
935 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(reiv), reiv_pl);
936 kfree(reiv_pl);
937 return err;
938 }
939
mlxsw_sp_fid_evid_map(const struct mlxsw_sp_fid * fid,u16 local_port,u16 vid,bool valid)940 static int mlxsw_sp_fid_evid_map(const struct mlxsw_sp_fid *fid, u16 local_port,
941 u16 vid, bool valid)
942 {
943 int err;
944
945 err = mlxsw_sp_fid_mpe_table_map(fid, local_port, vid, valid);
946 if (err)
947 return err;
948
949 if (!fid->rif)
950 return 0;
951
952 err = mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, vid,
953 valid);
954 if (err)
955 goto err_erif_eport_to_vid_map_one;
956
957 return 0;
958
959 err_erif_eport_to_vid_map_one:
960 mlxsw_sp_fid_mpe_table_map(fid, local_port, vid, !valid);
961 return err;
962 }
963
mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)964 static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid,
965 struct mlxsw_sp_port *mlxsw_sp_port,
966 u16 vid)
967 {
968 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
969 u16 local_port = mlxsw_sp_port->local_port;
970 int err;
971
972 err = __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,
973 true);
974 if (err)
975 return err;
976
977 err = mlxsw_sp_fid_evid_map(fid, local_port, vid, true);
978 if (err)
979 goto err_fid_evid_map;
980
981 err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port,
982 vid);
983 if (err)
984 goto err_port_vid_list_add;
985
986 if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
987 err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
988 if (err)
989 goto err_port_vp_mode_trans;
990 }
991
992 return 0;
993
994 err_port_vp_mode_trans:
995 mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
996 mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
997 err_port_vid_list_add:
998 mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
999 err_fid_evid_map:
1000 __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);
1001 return err;
1002 }
1003
1004 static void
mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)1005 mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid,
1006 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
1007 {
1008 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1009 u16 local_port = mlxsw_sp_port->local_port;
1010
1011 if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
1012 mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
1013 mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
1014 mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
1015 mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
1016 __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);
1017 }
1018
mlxsw_sp_fid_8021d_vni_set(struct mlxsw_sp_fid * fid)1019 static int mlxsw_sp_fid_8021d_vni_set(struct mlxsw_sp_fid *fid)
1020 {
1021 return mlxsw_sp_fid_vni_op(fid);
1022 }
1023
mlxsw_sp_fid_8021d_vni_clear(struct mlxsw_sp_fid * fid)1024 static void mlxsw_sp_fid_8021d_vni_clear(struct mlxsw_sp_fid *fid)
1025 {
1026 mlxsw_sp_fid_vni_op(fid);
1027 }
1028
mlxsw_sp_fid_8021d_nve_flood_index_set(struct mlxsw_sp_fid * fid)1029 static int mlxsw_sp_fid_8021d_nve_flood_index_set(struct mlxsw_sp_fid *fid)
1030 {
1031 return mlxsw_sp_fid_edit_op(fid, fid->rif);
1032 }
1033
mlxsw_sp_fid_8021d_nve_flood_index_clear(struct mlxsw_sp_fid * fid)1034 static void mlxsw_sp_fid_8021d_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
1035 {
1036 mlxsw_sp_fid_edit_op(fid, fid->rif);
1037 }
1038
1039 static void
mlxsw_sp_fid_8021d_fdb_clear_offload(const struct mlxsw_sp_fid * fid,const struct net_device * nve_dev)1040 mlxsw_sp_fid_8021d_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
1041 const struct net_device *nve_dev)
1042 {
1043 br_fdb_clear_offload(nve_dev, 0);
1044 }
1045
1046 static int
mlxsw_sp_fid_8021d_vid_to_fid_rif_update(const struct mlxsw_sp_fid * fid,const struct mlxsw_sp_rif * rif)1047 mlxsw_sp_fid_8021d_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
1048 const struct mlxsw_sp_rif *rif)
1049 {
1050 return 0;
1051 }
1052
1053 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = {
1054 .setup = mlxsw_sp_fid_8021d_setup,
1055 .configure = mlxsw_sp_fid_8021d_configure,
1056 .deconfigure = mlxsw_sp_fid_8021d_deconfigure,
1057 .index_alloc = mlxsw_sp_fid_8021d_index_alloc,
1058 .compare = mlxsw_sp_fid_8021d_compare,
1059 .port_vid_map = mlxsw_sp_fid_8021d_port_vid_map,
1060 .port_vid_unmap = mlxsw_sp_fid_8021d_port_vid_unmap,
1061 .vni_set = mlxsw_sp_fid_8021d_vni_set,
1062 .vni_clear = mlxsw_sp_fid_8021d_vni_clear,
1063 .nve_flood_index_set = mlxsw_sp_fid_8021d_nve_flood_index_set,
1064 .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear,
1065 .fdb_clear_offload = mlxsw_sp_fid_8021d_fdb_clear_offload,
1066 .vid_to_fid_rif_update = mlxsw_sp_fid_8021d_vid_to_fid_rif_update,
1067 };
1068
1069 #define MLXSW_SP_FID_8021Q_MAX (VLAN_N_VID - 2)
1070 #define MLXSW_SP_FID_RFID_MAX (11 * 1024)
1071 #define MLXSW_SP_FID_8021Q_PGT_BASE 0
1072 #define MLXSW_SP_FID_8021D_PGT_BASE (3 * MLXSW_SP_FID_8021Q_MAX)
1073
1074 static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = {
1075 {
1076 .packet_type = MLXSW_SP_FLOOD_TYPE_UC,
1077 .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
1078 .table_index = 0,
1079 },
1080 {
1081 .packet_type = MLXSW_SP_FLOOD_TYPE_MC,
1082 .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
1083 .table_index = 1,
1084 },
1085 {
1086 .packet_type = MLXSW_SP_FLOOD_TYPE_BC,
1087 .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
1088 .table_index = 2,
1089 },
1090 };
1091
1092 static bool
mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid * fid,const void * arg)1093 mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg)
1094 {
1095 u16 vid = *(u16 *) arg;
1096
1097 return mlxsw_sp_fid_8021q_fid(fid)->vid == vid;
1098 }
1099
1100 static void
mlxsw_sp_fid_8021q_fdb_clear_offload(const struct mlxsw_sp_fid * fid,const struct net_device * nve_dev)1101 mlxsw_sp_fid_8021q_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
1102 const struct net_device *nve_dev)
1103 {
1104 br_fdb_clear_offload(nve_dev, mlxsw_sp_fid_8021q_vid(fid));
1105 }
1106
mlxsw_sp_fid_rfid_setup(struct mlxsw_sp_fid * fid,const void * arg)1107 static void mlxsw_sp_fid_rfid_setup(struct mlxsw_sp_fid *fid, const void *arg)
1108 {
1109 fid->fid_offset = 0;
1110 }
1111
mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid * fid)1112 static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid)
1113 {
1114 return mlxsw_sp_fid_op(fid, true);
1115 }
1116
mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid * fid)1117 static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid)
1118 {
1119 mlxsw_sp_fid_op(fid, false);
1120 }
1121
mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid * fid,const void * arg,u16 * p_fid_index)1122 static int mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid *fid,
1123 const void *arg, u16 *p_fid_index)
1124 {
1125 u16 rif_index = *(u16 *) arg;
1126
1127 *p_fid_index = fid->fid_family->start_index + rif_index;
1128
1129 return 0;
1130 }
1131
mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid * fid,const void * arg)1132 static bool mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid *fid,
1133 const void *arg)
1134 {
1135 u16 rif_index = *(u16 *) arg;
1136
1137 return fid->fid_index == rif_index + fid->fid_family->start_index;
1138 }
1139
mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)1140 static int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid,
1141 struct mlxsw_sp_port *mlxsw_sp_port,
1142 u16 vid)
1143 {
1144 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1145 u16 local_port = mlxsw_sp_port->local_port;
1146 int err;
1147
1148 err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port,
1149 vid);
1150 if (err)
1151 return err;
1152
1153 /* Using legacy bridge model, we only need to transition the port to
1154 * virtual mode since {Port, VID} => FID is done by the firmware upon
1155 * RIF creation. Using unified bridge model, we need to map
1156 * {Port, VID} => FID and map egress VID.
1157 */
1158 err = __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,
1159 true);
1160 if (err)
1161 goto err_port_vid_map;
1162
1163 if (fid->rif) {
1164 err = mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port,
1165 vid, true);
1166 if (err)
1167 goto err_erif_eport_to_vid_map_one;
1168 }
1169
1170 if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
1171 err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
1172 if (err)
1173 goto err_port_vp_mode_trans;
1174 }
1175
1176 return 0;
1177
1178 err_port_vp_mode_trans:
1179 mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
1180 if (fid->rif)
1181 mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, vid,
1182 false);
1183 err_erif_eport_to_vid_map_one:
1184 __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);
1185 err_port_vid_map:
1186 mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
1187 return err;
1188 }
1189
1190 static void
mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)1191 mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid *fid,
1192 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
1193 {
1194 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1195 u16 local_port = mlxsw_sp_port->local_port;
1196
1197 if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
1198 mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
1199 mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
1200
1201 if (fid->rif)
1202 mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, vid,
1203 false);
1204 __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);
1205 mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
1206 }
1207
mlxsw_sp_fid_rfid_vni_set(struct mlxsw_sp_fid * fid)1208 static int mlxsw_sp_fid_rfid_vni_set(struct mlxsw_sp_fid *fid)
1209 {
1210 return -EOPNOTSUPP;
1211 }
1212
mlxsw_sp_fid_rfid_vni_clear(struct mlxsw_sp_fid * fid)1213 static void mlxsw_sp_fid_rfid_vni_clear(struct mlxsw_sp_fid *fid)
1214 {
1215 WARN_ON_ONCE(1);
1216 }
1217
mlxsw_sp_fid_rfid_nve_flood_index_set(struct mlxsw_sp_fid * fid)1218 static int mlxsw_sp_fid_rfid_nve_flood_index_set(struct mlxsw_sp_fid *fid)
1219 {
1220 return -EOPNOTSUPP;
1221 }
1222
mlxsw_sp_fid_rfid_nve_flood_index_clear(struct mlxsw_sp_fid * fid)1223 static void mlxsw_sp_fid_rfid_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
1224 {
1225 WARN_ON_ONCE(1);
1226 }
1227
1228 static int
mlxsw_sp_fid_rfid_vid_to_fid_rif_update(const struct mlxsw_sp_fid * fid,const struct mlxsw_sp_rif * rif)1229 mlxsw_sp_fid_rfid_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
1230 const struct mlxsw_sp_rif *rif)
1231 {
1232 return 0;
1233 }
1234
1235 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = {
1236 .setup = mlxsw_sp_fid_rfid_setup,
1237 .configure = mlxsw_sp_fid_rfid_configure,
1238 .deconfigure = mlxsw_sp_fid_rfid_deconfigure,
1239 .index_alloc = mlxsw_sp_fid_rfid_index_alloc,
1240 .compare = mlxsw_sp_fid_rfid_compare,
1241 .port_vid_map = mlxsw_sp_fid_rfid_port_vid_map,
1242 .port_vid_unmap = mlxsw_sp_fid_rfid_port_vid_unmap,
1243 .vni_set = mlxsw_sp_fid_rfid_vni_set,
1244 .vni_clear = mlxsw_sp_fid_rfid_vni_clear,
1245 .nve_flood_index_set = mlxsw_sp_fid_rfid_nve_flood_index_set,
1246 .nve_flood_index_clear = mlxsw_sp_fid_rfid_nve_flood_index_clear,
1247 .vid_to_fid_rif_update = mlxsw_sp_fid_rfid_vid_to_fid_rif_update,
1248 };
1249
mlxsw_sp_fid_dummy_setup(struct mlxsw_sp_fid * fid,const void * arg)1250 static void mlxsw_sp_fid_dummy_setup(struct mlxsw_sp_fid *fid, const void *arg)
1251 {
1252 fid->fid_offset = 0;
1253 }
1254
mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid * fid)1255 static int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid *fid)
1256 {
1257 return mlxsw_sp_fid_op(fid, true);
1258 }
1259
mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid * fid)1260 static void mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid *fid)
1261 {
1262 mlxsw_sp_fid_op(fid, false);
1263 }
1264
mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid * fid,const void * arg,u16 * p_fid_index)1265 static int mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid *fid,
1266 const void *arg, u16 *p_fid_index)
1267 {
1268 *p_fid_index = fid->fid_family->start_index;
1269
1270 return 0;
1271 }
1272
mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid * fid,const void * arg)1273 static bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid,
1274 const void *arg)
1275 {
1276 return true;
1277 }
1278
mlxsw_sp_fid_dummy_vni_set(struct mlxsw_sp_fid * fid)1279 static int mlxsw_sp_fid_dummy_vni_set(struct mlxsw_sp_fid *fid)
1280 {
1281 return -EOPNOTSUPP;
1282 }
1283
mlxsw_sp_fid_dummy_vni_clear(struct mlxsw_sp_fid * fid)1284 static void mlxsw_sp_fid_dummy_vni_clear(struct mlxsw_sp_fid *fid)
1285 {
1286 WARN_ON_ONCE(1);
1287 }
1288
mlxsw_sp_fid_dummy_nve_flood_index_set(struct mlxsw_sp_fid * fid)1289 static int mlxsw_sp_fid_dummy_nve_flood_index_set(struct mlxsw_sp_fid *fid)
1290 {
1291 return -EOPNOTSUPP;
1292 }
1293
mlxsw_sp_fid_dummy_nve_flood_index_clear(struct mlxsw_sp_fid * fid)1294 static void mlxsw_sp_fid_dummy_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
1295 {
1296 WARN_ON_ONCE(1);
1297 }
1298
1299 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = {
1300 .setup = mlxsw_sp_fid_dummy_setup,
1301 .configure = mlxsw_sp_fid_dummy_configure,
1302 .deconfigure = mlxsw_sp_fid_dummy_deconfigure,
1303 .index_alloc = mlxsw_sp_fid_dummy_index_alloc,
1304 .compare = mlxsw_sp_fid_dummy_compare,
1305 .vni_set = mlxsw_sp_fid_dummy_vni_set,
1306 .vni_clear = mlxsw_sp_fid_dummy_vni_clear,
1307 .nve_flood_index_set = mlxsw_sp_fid_dummy_nve_flood_index_set,
1308 .nve_flood_index_clear = mlxsw_sp_fid_dummy_nve_flood_index_clear,
1309 };
1310
mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid * fid)1311 static int mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid *fid)
1312 {
1313 struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
1314 int err;
1315
1316 err = mlxsw_sp_fid_op(fid, true);
1317 if (err)
1318 return err;
1319
1320 err = mlxsw_sp_fid_vid_to_fid_map(fid, fid_8021q->vid, true, fid->rif);
1321 if (err)
1322 goto err_vid_to_fid_map;
1323
1324 return 0;
1325
1326 err_vid_to_fid_map:
1327 mlxsw_sp_fid_op(fid, false);
1328 return err;
1329 }
1330
mlxsw_sp_fid_8021q_deconfigure(struct mlxsw_sp_fid * fid)1331 static void mlxsw_sp_fid_8021q_deconfigure(struct mlxsw_sp_fid *fid)
1332 {
1333 struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
1334
1335 if (fid->vni_valid)
1336 mlxsw_sp_nve_fid_disable(fid->fid_family->mlxsw_sp, fid);
1337
1338 mlxsw_sp_fid_vid_to_fid_map(fid, fid_8021q->vid, false, NULL);
1339 mlxsw_sp_fid_op(fid, false);
1340 }
1341
mlxsw_sp_fid_8021q_port_vid_map(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)1342 static int mlxsw_sp_fid_8021q_port_vid_map(struct mlxsw_sp_fid *fid,
1343 struct mlxsw_sp_port *mlxsw_sp_port,
1344 u16 vid)
1345 {
1346 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1347 u16 local_port = mlxsw_sp_port->local_port;
1348 int err;
1349
1350 /* In case there are no {Port, VID} => FID mappings on the port,
1351 * we can use the global VID => FID mapping we created when the
1352 * FID was configured, otherwise, configure new mapping.
1353 */
1354 if (mlxsw_sp->fid_core->port_fid_mappings[local_port]) {
1355 err = __mlxsw_sp_fid_port_vid_map(fid, local_port, vid, true);
1356 if (err)
1357 return err;
1358 }
1359
1360 err = mlxsw_sp_fid_evid_map(fid, local_port, vid, true);
1361 if (err)
1362 goto err_fid_evid_map;
1363
1364 err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port,
1365 vid);
1366 if (err)
1367 goto err_port_vid_list_add;
1368
1369 return 0;
1370
1371 err_port_vid_list_add:
1372 mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
1373 err_fid_evid_map:
1374 if (mlxsw_sp->fid_core->port_fid_mappings[local_port])
1375 __mlxsw_sp_fid_port_vid_map(fid, local_port, vid, false);
1376 return err;
1377 }
1378
1379 static void
mlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)1380 mlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid *fid,
1381 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
1382 {
1383 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1384 u16 local_port = mlxsw_sp_port->local_port;
1385
1386 mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
1387 mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
1388 if (mlxsw_sp->fid_core->port_fid_mappings[local_port])
1389 __mlxsw_sp_fid_port_vid_map(fid, local_port, vid, false);
1390 }
1391
1392 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops = {
1393 .setup = mlxsw_sp_fid_8021q_setup,
1394 .configure = mlxsw_sp_fid_8021q_configure,
1395 .deconfigure = mlxsw_sp_fid_8021q_deconfigure,
1396 .index_alloc = mlxsw_sp_fid_8021d_index_alloc,
1397 .compare = mlxsw_sp_fid_8021q_compare,
1398 .port_vid_map = mlxsw_sp_fid_8021q_port_vid_map,
1399 .port_vid_unmap = mlxsw_sp_fid_8021q_port_vid_unmap,
1400 .vni_set = mlxsw_sp_fid_8021d_vni_set,
1401 .vni_clear = mlxsw_sp_fid_8021d_vni_clear,
1402 .nve_flood_index_set = mlxsw_sp_fid_8021d_nve_flood_index_set,
1403 .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear,
1404 .fdb_clear_offload = mlxsw_sp_fid_8021q_fdb_clear_offload,
1405 .vid_to_fid_rif_update = mlxsw_sp_fid_8021q_vid_to_fid_rif_update,
1406 };
1407
1408 /* There are 4K-2 802.1Q FIDs */
1409 #define MLXSW_SP_FID_8021Q_START 1 /* FID 0 is reserved. */
1410 #define MLXSW_SP_FID_8021Q_END (MLXSW_SP_FID_8021Q_START + \
1411 MLXSW_SP_FID_8021Q_MAX - 1)
1412
1413 /* There are 1K 802.1D FIDs */
1414 #define MLXSW_SP_FID_8021D_START (MLXSW_SP_FID_8021Q_END + 1)
1415 #define MLXSW_SP_FID_8021D_END (MLXSW_SP_FID_8021D_START + \
1416 MLXSW_SP_FID_8021D_MAX - 1)
1417
1418 /* There is one dummy FID */
1419 #define MLXSW_SP_FID_DUMMY (MLXSW_SP_FID_8021D_END + 1)
1420
1421 /* There are 11K rFIDs */
1422 #define MLXSW_SP_RFID_START (MLXSW_SP_FID_DUMMY + 1)
1423 #define MLXSW_SP_RFID_END (MLXSW_SP_RFID_START + \
1424 MLXSW_SP_FID_RFID_MAX - 1)
1425
1426 static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021q_family = {
1427 .type = MLXSW_SP_FID_TYPE_8021Q,
1428 .fid_size = sizeof(struct mlxsw_sp_fid_8021q),
1429 .start_index = MLXSW_SP_FID_8021Q_START,
1430 .end_index = MLXSW_SP_FID_8021Q_END,
1431 .flood_tables = mlxsw_sp_fid_8021d_flood_tables,
1432 .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
1433 .rif_type = MLXSW_SP_RIF_TYPE_VLAN,
1434 .ops = &mlxsw_sp_fid_8021q_ops,
1435 .flood_rsp = false,
1436 .bridge_type = MLXSW_REG_BRIDGE_TYPE_0,
1437 .pgt_base = MLXSW_SP_FID_8021Q_PGT_BASE,
1438 .smpe_index_valid = false,
1439 };
1440
1441 static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021d_family = {
1442 .type = MLXSW_SP_FID_TYPE_8021D,
1443 .fid_size = sizeof(struct mlxsw_sp_fid_8021d),
1444 .start_index = MLXSW_SP_FID_8021D_START,
1445 .end_index = MLXSW_SP_FID_8021D_END,
1446 .flood_tables = mlxsw_sp_fid_8021d_flood_tables,
1447 .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
1448 .rif_type = MLXSW_SP_RIF_TYPE_FID,
1449 .ops = &mlxsw_sp_fid_8021d_ops,
1450 .bridge_type = MLXSW_REG_BRIDGE_TYPE_1,
1451 .pgt_base = MLXSW_SP_FID_8021D_PGT_BASE,
1452 .smpe_index_valid = false,
1453 };
1454
1455 static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_dummy_family = {
1456 .type = MLXSW_SP_FID_TYPE_DUMMY,
1457 .fid_size = sizeof(struct mlxsw_sp_fid),
1458 .start_index = MLXSW_SP_FID_DUMMY,
1459 .end_index = MLXSW_SP_FID_DUMMY,
1460 .ops = &mlxsw_sp_fid_dummy_ops,
1461 .smpe_index_valid = false,
1462 };
1463
1464 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family = {
1465 .type = MLXSW_SP_FID_TYPE_RFID,
1466 .fid_size = sizeof(struct mlxsw_sp_fid),
1467 .start_index = MLXSW_SP_RFID_START,
1468 .end_index = MLXSW_SP_RFID_END,
1469 .rif_type = MLXSW_SP_RIF_TYPE_SUBPORT,
1470 .ops = &mlxsw_sp_fid_rfid_ops,
1471 .flood_rsp = true,
1472 .smpe_index_valid = false,
1473 };
1474
1475 const struct mlxsw_sp_fid_family *mlxsw_sp1_fid_family_arr[] = {
1476 [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp1_fid_8021q_family,
1477 [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp1_fid_8021d_family,
1478 [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp1_fid_dummy_family,
1479 [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family,
1480 };
1481
1482 static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021q_family = {
1483 .type = MLXSW_SP_FID_TYPE_8021Q,
1484 .fid_size = sizeof(struct mlxsw_sp_fid_8021q),
1485 .start_index = MLXSW_SP_FID_8021Q_START,
1486 .end_index = MLXSW_SP_FID_8021Q_END,
1487 .flood_tables = mlxsw_sp_fid_8021d_flood_tables,
1488 .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
1489 .rif_type = MLXSW_SP_RIF_TYPE_VLAN,
1490 .ops = &mlxsw_sp_fid_8021q_ops,
1491 .flood_rsp = false,
1492 .bridge_type = MLXSW_REG_BRIDGE_TYPE_0,
1493 .pgt_base = MLXSW_SP_FID_8021Q_PGT_BASE,
1494 .smpe_index_valid = true,
1495 };
1496
1497 static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021d_family = {
1498 .type = MLXSW_SP_FID_TYPE_8021D,
1499 .fid_size = sizeof(struct mlxsw_sp_fid_8021d),
1500 .start_index = MLXSW_SP_FID_8021D_START,
1501 .end_index = MLXSW_SP_FID_8021D_END,
1502 .flood_tables = mlxsw_sp_fid_8021d_flood_tables,
1503 .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
1504 .rif_type = MLXSW_SP_RIF_TYPE_FID,
1505 .ops = &mlxsw_sp_fid_8021d_ops,
1506 .bridge_type = MLXSW_REG_BRIDGE_TYPE_1,
1507 .pgt_base = MLXSW_SP_FID_8021D_PGT_BASE,
1508 .smpe_index_valid = true,
1509 };
1510
1511 static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_dummy_family = {
1512 .type = MLXSW_SP_FID_TYPE_DUMMY,
1513 .fid_size = sizeof(struct mlxsw_sp_fid),
1514 .start_index = MLXSW_SP_FID_DUMMY,
1515 .end_index = MLXSW_SP_FID_DUMMY,
1516 .ops = &mlxsw_sp_fid_dummy_ops,
1517 .smpe_index_valid = false,
1518 };
1519
1520 const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr[] = {
1521 [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp2_fid_8021q_family,
1522 [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp2_fid_8021d_family,
1523 [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp2_fid_dummy_family,
1524 [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family,
1525 };
1526
mlxsw_sp_fid_lookup(struct mlxsw_sp * mlxsw_sp,enum mlxsw_sp_fid_type type,const void * arg)1527 static struct mlxsw_sp_fid *mlxsw_sp_fid_lookup(struct mlxsw_sp *mlxsw_sp,
1528 enum mlxsw_sp_fid_type type,
1529 const void *arg)
1530 {
1531 struct mlxsw_sp_fid_family *fid_family;
1532 struct mlxsw_sp_fid *fid;
1533
1534 fid_family = mlxsw_sp->fid_core->fid_family_arr[type];
1535 list_for_each_entry(fid, &fid_family->fids_list, list) {
1536 if (!fid->fid_family->ops->compare(fid, arg))
1537 continue;
1538 refcount_inc(&fid->ref_count);
1539 return fid;
1540 }
1541
1542 return NULL;
1543 }
1544
mlxsw_sp_fid_get(struct mlxsw_sp * mlxsw_sp,enum mlxsw_sp_fid_type type,const void * arg)1545 static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp,
1546 enum mlxsw_sp_fid_type type,
1547 const void *arg)
1548 {
1549 struct mlxsw_sp_fid_family *fid_family;
1550 struct mlxsw_sp_fid *fid;
1551 u16 fid_index;
1552 int err;
1553
1554 fid = mlxsw_sp_fid_lookup(mlxsw_sp, type, arg);
1555 if (fid)
1556 return fid;
1557
1558 fid_family = mlxsw_sp->fid_core->fid_family_arr[type];
1559 fid = kzalloc(fid_family->fid_size, GFP_KERNEL);
1560 if (!fid)
1561 return ERR_PTR(-ENOMEM);
1562
1563 INIT_LIST_HEAD(&fid->port_vid_list);
1564 fid->fid_family = fid_family;
1565
1566 err = fid->fid_family->ops->index_alloc(fid, arg, &fid_index);
1567 if (err)
1568 goto err_index_alloc;
1569 fid->fid_index = fid_index;
1570 __set_bit(fid_index - fid_family->start_index, fid_family->fids_bitmap);
1571
1572 fid->fid_family->ops->setup(fid, arg);
1573
1574 err = fid->fid_family->ops->configure(fid);
1575 if (err)
1576 goto err_configure;
1577
1578 err = rhashtable_insert_fast(&mlxsw_sp->fid_core->fid_ht, &fid->ht_node,
1579 mlxsw_sp_fid_ht_params);
1580 if (err)
1581 goto err_rhashtable_insert;
1582
1583 list_add(&fid->list, &fid_family->fids_list);
1584 refcount_set(&fid->ref_count, 1);
1585 return fid;
1586
1587 err_rhashtable_insert:
1588 fid->fid_family->ops->deconfigure(fid);
1589 err_configure:
1590 __clear_bit(fid_index - fid_family->start_index,
1591 fid_family->fids_bitmap);
1592 err_index_alloc:
1593 kfree(fid);
1594 return ERR_PTR(err);
1595 }
1596
mlxsw_sp_fid_put(struct mlxsw_sp_fid * fid)1597 void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid)
1598 {
1599 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
1600 struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
1601
1602 if (!refcount_dec_and_test(&fid->ref_count))
1603 return;
1604
1605 list_del(&fid->list);
1606 rhashtable_remove_fast(&mlxsw_sp->fid_core->fid_ht,
1607 &fid->ht_node, mlxsw_sp_fid_ht_params);
1608 fid->fid_family->ops->deconfigure(fid);
1609 __clear_bit(fid->fid_index - fid_family->start_index,
1610 fid_family->fids_bitmap);
1611 WARN_ON_ONCE(!list_empty(&fid->port_vid_list));
1612 kfree(fid);
1613 }
1614
mlxsw_sp_fid_8021q_get(struct mlxsw_sp * mlxsw_sp,u16 vid)1615 struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid)
1616 {
1617 return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid);
1618 }
1619
mlxsw_sp_fid_8021d_get(struct mlxsw_sp * mlxsw_sp,int br_ifindex)1620 struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp,
1621 int br_ifindex)
1622 {
1623 return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, &br_ifindex);
1624 }
1625
mlxsw_sp_fid_8021q_lookup(struct mlxsw_sp * mlxsw_sp,u16 vid)1626 struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_lookup(struct mlxsw_sp *mlxsw_sp,
1627 u16 vid)
1628 {
1629 return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid);
1630 }
1631
mlxsw_sp_fid_8021d_lookup(struct mlxsw_sp * mlxsw_sp,int br_ifindex)1632 struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_lookup(struct mlxsw_sp *mlxsw_sp,
1633 int br_ifindex)
1634 {
1635 return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D,
1636 &br_ifindex);
1637 }
1638
mlxsw_sp_fid_rfid_get(struct mlxsw_sp * mlxsw_sp,u16 rif_index)1639 struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp,
1640 u16 rif_index)
1641 {
1642 return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_RFID, &rif_index);
1643 }
1644
mlxsw_sp_fid_dummy_get(struct mlxsw_sp * mlxsw_sp)1645 struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp)
1646 {
1647 return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_DUMMY, NULL);
1648 }
1649
1650 static int
mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family * fid_family,const struct mlxsw_sp_flood_table * flood_table)1651 mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family,
1652 const struct mlxsw_sp_flood_table *flood_table)
1653 {
1654 enum mlxsw_sp_flood_type packet_type = flood_table->packet_type;
1655 struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
1656 const int *sfgc_packet_types;
1657 u16 num_fids, mid_base;
1658 int err, i;
1659
1660 mid_base = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table, 0);
1661 num_fids = mlxsw_sp_fid_family_num_fids(fid_family);
1662 err = mlxsw_sp_pgt_mid_alloc_range(mlxsw_sp, mid_base, num_fids);
1663 if (err)
1664 return err;
1665
1666 sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type];
1667 for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) {
1668 char sfgc_pl[MLXSW_REG_SFGC_LEN];
1669
1670 if (!sfgc_packet_types[i])
1671 continue;
1672
1673 mlxsw_reg_sfgc_pack(sfgc_pl, i, fid_family->bridge_type,
1674 flood_table->table_type, 0, mid_base);
1675
1676 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl);
1677 if (err)
1678 goto err_reg_write;
1679 }
1680
1681 return 0;
1682
1683 err_reg_write:
1684 mlxsw_sp_pgt_mid_free_range(mlxsw_sp, mid_base, num_fids);
1685 return err;
1686 }
1687
1688 static void
mlxsw_sp_fid_flood_table_fini(struct mlxsw_sp_fid_family * fid_family,const struct mlxsw_sp_flood_table * flood_table)1689 mlxsw_sp_fid_flood_table_fini(struct mlxsw_sp_fid_family *fid_family,
1690 const struct mlxsw_sp_flood_table *flood_table)
1691 {
1692 struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
1693 u16 num_fids, mid_base;
1694
1695 mid_base = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table, 0);
1696 num_fids = mlxsw_sp_fid_family_num_fids(fid_family);
1697 mlxsw_sp_pgt_mid_free_range(mlxsw_sp, mid_base, num_fids);
1698 }
1699
1700 static int
mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family * fid_family)1701 mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family)
1702 {
1703 int i;
1704
1705 for (i = 0; i < fid_family->nr_flood_tables; i++) {
1706 const struct mlxsw_sp_flood_table *flood_table;
1707 int err;
1708
1709 flood_table = &fid_family->flood_tables[i];
1710 err = mlxsw_sp_fid_flood_table_init(fid_family, flood_table);
1711 if (err)
1712 return err;
1713 }
1714
1715 return 0;
1716 }
1717
1718 static void
mlxsw_sp_fid_flood_tables_fini(struct mlxsw_sp_fid_family * fid_family)1719 mlxsw_sp_fid_flood_tables_fini(struct mlxsw_sp_fid_family *fid_family)
1720 {
1721 int i;
1722
1723 for (i = 0; i < fid_family->nr_flood_tables; i++) {
1724 const struct mlxsw_sp_flood_table *flood_table;
1725
1726 flood_table = &fid_family->flood_tables[i];
1727 mlxsw_sp_fid_flood_table_fini(fid_family, flood_table);
1728 }
1729 }
1730
mlxsw_sp_fid_family_register(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_fid_family * tmpl)1731 static int mlxsw_sp_fid_family_register(struct mlxsw_sp *mlxsw_sp,
1732 const struct mlxsw_sp_fid_family *tmpl)
1733 {
1734 u16 nr_fids = tmpl->end_index - tmpl->start_index + 1;
1735 struct mlxsw_sp_fid_family *fid_family;
1736 int err;
1737
1738 fid_family = kmemdup(tmpl, sizeof(*fid_family), GFP_KERNEL);
1739 if (!fid_family)
1740 return -ENOMEM;
1741
1742 fid_family->mlxsw_sp = mlxsw_sp;
1743 INIT_LIST_HEAD(&fid_family->fids_list);
1744 fid_family->fids_bitmap = bitmap_zalloc(nr_fids, GFP_KERNEL);
1745 if (!fid_family->fids_bitmap) {
1746 err = -ENOMEM;
1747 goto err_alloc_fids_bitmap;
1748 }
1749
1750 if (fid_family->flood_tables) {
1751 err = mlxsw_sp_fid_flood_tables_init(fid_family);
1752 if (err)
1753 goto err_fid_flood_tables_init;
1754 }
1755
1756 mlxsw_sp->fid_core->fid_family_arr[tmpl->type] = fid_family;
1757
1758 return 0;
1759
1760 err_fid_flood_tables_init:
1761 bitmap_free(fid_family->fids_bitmap);
1762 err_alloc_fids_bitmap:
1763 kfree(fid_family);
1764 return err;
1765 }
1766
1767 static void
mlxsw_sp_fid_family_unregister(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fid_family * fid_family)1768 mlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp,
1769 struct mlxsw_sp_fid_family *fid_family)
1770 {
1771 mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL;
1772
1773 if (fid_family->flood_tables)
1774 mlxsw_sp_fid_flood_tables_fini(fid_family);
1775
1776 bitmap_free(fid_family->fids_bitmap);
1777 WARN_ON_ONCE(!list_empty(&fid_family->fids_list));
1778 kfree(fid_family);
1779 }
1780
mlxsw_sp_port_fids_init(struct mlxsw_sp_port * mlxsw_sp_port)1781 int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port)
1782 {
1783 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1784
1785 /* Track number of FIDs configured on the port with mapping type
1786 * PORT_VID_TO_FID, so that we know when to transition the port
1787 * back to non-virtual (VLAN) mode.
1788 */
1789 mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
1790
1791 return mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
1792 }
1793
mlxsw_sp_port_fids_fini(struct mlxsw_sp_port * mlxsw_sp_port)1794 void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port)
1795 {
1796 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1797
1798 mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
1799 }
1800
mlxsw_sp_fids_init(struct mlxsw_sp * mlxsw_sp)1801 int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp)
1802 {
1803 unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
1804 struct mlxsw_sp_fid_core *fid_core;
1805 int err, i;
1806
1807 fid_core = kzalloc(sizeof(*mlxsw_sp->fid_core), GFP_KERNEL);
1808 if (!fid_core)
1809 return -ENOMEM;
1810 mlxsw_sp->fid_core = fid_core;
1811
1812 err = rhashtable_init(&fid_core->fid_ht, &mlxsw_sp_fid_ht_params);
1813 if (err)
1814 goto err_rhashtable_fid_init;
1815
1816 err = rhashtable_init(&fid_core->vni_ht, &mlxsw_sp_fid_vni_ht_params);
1817 if (err)
1818 goto err_rhashtable_vni_init;
1819
1820 fid_core->port_fid_mappings = kcalloc(max_ports, sizeof(unsigned int),
1821 GFP_KERNEL);
1822 if (!fid_core->port_fid_mappings) {
1823 err = -ENOMEM;
1824 goto err_alloc_port_fid_mappings;
1825 }
1826
1827 for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) {
1828 err = mlxsw_sp_fid_family_register(mlxsw_sp,
1829 mlxsw_sp->fid_family_arr[i]);
1830
1831 if (err)
1832 goto err_fid_ops_register;
1833 }
1834
1835 return 0;
1836
1837 err_fid_ops_register:
1838 for (i--; i >= 0; i--) {
1839 struct mlxsw_sp_fid_family *fid_family;
1840
1841 fid_family = fid_core->fid_family_arr[i];
1842 mlxsw_sp_fid_family_unregister(mlxsw_sp, fid_family);
1843 }
1844 kfree(fid_core->port_fid_mappings);
1845 err_alloc_port_fid_mappings:
1846 rhashtable_destroy(&fid_core->vni_ht);
1847 err_rhashtable_vni_init:
1848 rhashtable_destroy(&fid_core->fid_ht);
1849 err_rhashtable_fid_init:
1850 kfree(fid_core);
1851 return err;
1852 }
1853
mlxsw_sp_fids_fini(struct mlxsw_sp * mlxsw_sp)1854 void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp)
1855 {
1856 struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
1857 int i;
1858
1859 for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++)
1860 mlxsw_sp_fid_family_unregister(mlxsw_sp,
1861 fid_core->fid_family_arr[i]);
1862 kfree(fid_core->port_fid_mappings);
1863 rhashtable_destroy(&fid_core->vni_ht);
1864 rhashtable_destroy(&fid_core->fid_ht);
1865 kfree(fid_core);
1866 }
1867