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