This source file includes following definitions.
- mlxsw_sp_fid_is_dummy
- mlxsw_sp_fid_lag_vid_valid
- mlxsw_sp_fid_lookup_by_index
- mlxsw_sp_fid_nve_ifindex
- mlxsw_sp_fid_nve_type
- mlxsw_sp_fid_lookup_by_vni
- mlxsw_sp_fid_vni
- mlxsw_sp_fid_nve_flood_index_set
- mlxsw_sp_fid_nve_flood_index_clear
- mlxsw_sp_fid_nve_flood_index_is_set
- mlxsw_sp_fid_vni_set
- mlxsw_sp_fid_vni_clear
- mlxsw_sp_fid_vni_is_set
- mlxsw_sp_fid_fdb_clear_offload
- mlxsw_sp_fid_flood_table_lookup
- mlxsw_sp_fid_flood_set
- mlxsw_sp_fid_port_vid_map
- mlxsw_sp_fid_port_vid_unmap
- mlxsw_sp_fid_index
- mlxsw_sp_fid_rif_set
- mlxsw_sp_fid_rif
- mlxsw_sp_fid_type_rif_type
- mlxsw_sp_fid_8021q_fid
- mlxsw_sp_fid_8021q_vid
- mlxsw_sp_fid_8021q_setup
- mlxsw_sp_sfmr_op
- mlxsw_sp_fid_op
- mlxsw_sp_fid_vni_op
- mlxsw_sp_fid_vid_map
- __mlxsw_sp_fid_port_vid_map
- mlxsw_sp_fid_8021q_configure
- mlxsw_sp_fid_8021q_deconfigure
- mlxsw_sp_fid_8021q_index_alloc
- mlxsw_sp_fid_8021q_compare
- mlxsw_sp_fid_8021q_flood_index
- mlxsw_sp_fid_8021q_port_vid_map
- mlxsw_sp_fid_8021q_port_vid_unmap
- mlxsw_sp_fid_8021d_fid
- mlxsw_sp_fid_8021d_setup
- mlxsw_sp_fid_8021d_configure
- mlxsw_sp_fid_8021d_deconfigure
- mlxsw_sp_fid_8021d_index_alloc
- mlxsw_sp_fid_8021d_compare
- mlxsw_sp_fid_8021d_flood_index
- mlxsw_sp_port_vp_mode_trans
- mlxsw_sp_port_vlan_mode_trans
- mlxsw_sp_fid_8021d_port_vid_map
- mlxsw_sp_fid_8021d_port_vid_unmap
- mlxsw_sp_fid_8021d_vni_set
- mlxsw_sp_fid_8021d_vni_clear
- mlxsw_sp_fid_8021d_nve_flood_index_set
- mlxsw_sp_fid_8021d_nve_flood_index_clear
- mlxsw_sp_fid_8021d_fdb_clear_offload
- mlxsw_sp_fid_8021q_fdb_clear_offload
- mlxsw_sp_fid_rfid_configure
- mlxsw_sp_fid_rfid_deconfigure
- mlxsw_sp_fid_rfid_index_alloc
- mlxsw_sp_fid_rfid_compare
- mlxsw_sp_fid_rfid_port_vid_map
- mlxsw_sp_fid_rfid_port_vid_unmap
- mlxsw_sp_fid_dummy_configure
- mlxsw_sp_fid_dummy_deconfigure
- mlxsw_sp_fid_dummy_index_alloc
- mlxsw_sp_fid_dummy_compare
- mlxsw_sp_fid_lookup
- mlxsw_sp_fid_get
- mlxsw_sp_fid_put
- mlxsw_sp_fid_8021q_get
- mlxsw_sp_fid_8021d_get
- mlxsw_sp_fid_8021q_lookup
- mlxsw_sp_fid_8021d_lookup
- mlxsw_sp_fid_rfid_get
- mlxsw_sp_fid_dummy_get
- mlxsw_sp_fid_flood_table_init
- mlxsw_sp_fid_flood_tables_init
- mlxsw_sp_fid_family_register
- mlxsw_sp_fid_family_unregister
- mlxsw_sp_port_fids_init
- mlxsw_sp_port_fids_fini
- mlxsw_sp_fids_init
- mlxsw_sp_fids_fini
1
2
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
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
528
529
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
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
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
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
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
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
926
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
1239
1240
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 }