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