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