GNU Linux-libre 4.19.286-gnu1
[releases.git] / drivers / net / ethernet / mellanox / mlxsw / spectrum_fid.c
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/rtnetlink.h>
10
11 #include "spectrum.h"
12 #include "reg.h"
13
14 struct mlxsw_sp_fid_family;
15
16 struct 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
21 struct 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
29 struct mlxsw_sp_fid_8021q {
30         struct mlxsw_sp_fid common;
31         u16 vid;
32 };
33
34 struct mlxsw_sp_fid_8021d {
35         struct mlxsw_sp_fid common;
36         int br_ifindex;
37 };
38
39 struct 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
46 struct 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
61 struct 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
75 static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
76         [MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST]                   = 1,
77 };
78
79 static 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
87 static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
88         [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4]       = 1,
89 };
90
91 static 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
97 static const struct mlxsw_sp_flood_table *
98 mlxsw_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
113 int 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
143 int 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
151 void 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
157 enum 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
162 u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid)
163 {
164         return fid->fid_index;
165 }
166
167 enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid)
168 {
169         return fid->fid_family->type;
170 }
171
172 void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif)
173 {
174         fid->rif = rif;
175 }
176
177 enum mlxsw_sp_rif_type
178 mlxsw_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
186 static struct mlxsw_sp_fid_8021q *
187 mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid)
188 {
189         return container_of(fid, struct mlxsw_sp_fid_8021q, common);
190 }
191
192 u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid)
193 {
194         return mlxsw_sp_fid_8021q_fid(fid)->vid;
195 }
196
197 static 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
204 static 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
210 static 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
220 static 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
230 static 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
240 static 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
258 err_fid_map:
259         mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, false);
260         return err;
261 }
262
263 static 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
273 static 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         /* Use 1:1 mapping for simplicity although not a must */
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
287 static bool
288 mlxsw_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
295 static u16 mlxsw_sp_fid_8021q_flood_index(const struct mlxsw_sp_fid *fid)
296 {
297         return fid->fid_index;
298 }
299
300 static 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         /* In case there are no {Port, VID} => FID mappings on the port,
308          * we can use the global VID => FID mapping we created when the
309          * FID was configured.
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
317 static void
318 mlxsw_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
330 static 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
341 static 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 /* Range and flood configuration must match mlxsw_config_profile */
363 static 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
374 static struct mlxsw_sp_fid_8021d *
375 mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid)
376 {
377         return container_of(fid, struct mlxsw_sp_fid_8021d, common);
378 }
379
380 static 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
387 static 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
394 static 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
399 static 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
414 static bool
415 mlxsw_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
422 static 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
427 static 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
454 err_port_vp_mode_set:
455 err_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
471 static 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
492 static 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
513 err_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
520 static void
521 mlxsw_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
534 static 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
545 static 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 /* Range and flood configuration must match mlxsw_config_profile */
567 static 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
578 static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid)
579 {
580         /* rFIDs are allocated by the device during init */
581         return 0;
582 }
583
584 static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid)
585 {
586 }
587
588 static 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
598 static 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
606 static 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         /* We only need to transition the port to virtual mode since
615          * {Port, VID} => FID is done by the firmware upon RIF creation.
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
625 err_port_vp_mode_trans:
626         mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
627         return err;
628 }
629
630 static void
631 mlxsw_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
642 static 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
654 static 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
663 static 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
670 static 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
675 static 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
683 static bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid,
684                                        const void *arg)
685 {
686         return true;
687 }
688
689 static 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
696 static 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            = VLAN_N_VID - 1,
700         .end_index              = VLAN_N_VID - 1,
701         .ops                    = &mlxsw_sp_fid_dummy_ops,
702 };
703
704 static 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
711 static 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
750 err_configure:
751         __clear_bit(fid_index - fid_family->start_index,
752                     fid_family->fids_bitmap);
753 err_index_alloc:
754         kfree(fid);
755         return ERR_PTR(err);
756 }
757
758 void 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                 /* Destroy the associated RIF and let it drop the last
764                  * reference on the FID.
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
776 struct 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
781 struct 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
787 struct 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
793 struct 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
798 static int
799 mlxsw_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
825 static int
826 mlxsw_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
843 static 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
873 err_fid_flood_tables_init:
874         kfree(fid_family->fids_bitmap);
875 err_alloc_fids_bitmap:
876         kfree(fid_family);
877         return err;
878 }
879
880 static void
881 mlxsw_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
890 int 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         /* Track number of FIDs configured on the port with mapping type
895          * PORT_VID_TO_FID, so that we know when to transition the port
896          * back to non-virtual (VLAN) mode.
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
903 void 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
910 int 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
938 err_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);
946 err_alloc_port_fid_mappings:
947         kfree(fid_core);
948         return err;
949 }
950
951 void 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 }