Merge remote-tracking branch 'asoc/topic/pcm5102a' into asoc-next
[linux-2.6-block.git] / drivers / net / ethernet / mellanox / mlxsw / spectrum_fid.c
CommitLineData
a1107487
IS
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
45struct mlxsw_sp_fid_family;
46
47struct 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
52struct 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
60struct mlxsw_sp_fid_8021q {
61 struct mlxsw_sp_fid common;
62 u16 vid;
63};
64
65struct mlxsw_sp_fid_8021d {
66 struct mlxsw_sp_fid common;
67 int br_ifindex;
68};
69
70struct 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
77struct 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
92struct 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
106static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
107 [MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST] = 1,
108};
109
110static const int mlxsw_sp_sfgc_bc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
111 [MLXSW_REG_SFGC_TYPE_BROADCAST] = 1,
a1107487
IS
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,
9d45deb0 115 [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1,
a1107487
IS
116};
117
118static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
119 [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1,
120};
121
122static 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
128static const struct mlxsw_sp_flood_table *
129mlxsw_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
144int 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
174int 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
182void 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
188enum 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
193u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid)
194{
195 return fid->fid_index;
196}
197
198enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid)
199{
200 return fid->fid_family->type;
201}
202
203void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif)
204{
205 fid->rif = rif;
206}
207
e4f3c1c1
IS
208enum mlxsw_sp_rif_type
209mlxsw_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
a1107487
IS
217static struct mlxsw_sp_fid_8021q *
218mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid)
219{
220 return container_of(fid, struct mlxsw_sp_fid_8021q, common);
221}
222
e4f3c1c1
IS
223u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid)
224{
225 return mlxsw_sp_fid_8021q_fid(fid)->vid;
226}
227
a1107487
IS
228static 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
235static 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
241static 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
251static 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
261static 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
271static 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
289err_fid_map:
290 mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, false);
291 return err;
292}
293
294static 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
304static 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
318static bool
319mlxsw_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
326static u16 mlxsw_sp_fid_8021q_flood_index(const struct mlxsw_sp_fid *fid)
327{
328 return fid->fid_index;
329}
330
331static 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
348static void
349mlxsw_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
361static 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
372static 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,
da0abcf9 376 .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
a1107487
IS
377 .table_index = 0,
378 },
379 {
380 .packet_type = MLXSW_SP_FLOOD_TYPE_MC,
381 .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID,
da0abcf9 382 .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
a1107487
IS
383 .table_index = 1,
384 },
385 {
386 .packet_type = MLXSW_SP_FLOOD_TYPE_BC,
387 .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID,
da0abcf9 388 .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
a1107487
IS
389 .table_index = 2,
390 },
391};
392
393/* Range and flood configuration must match mlxsw_config_profile */
394static 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
405static struct mlxsw_sp_fid_8021d *
406mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid)
407{
408 return container_of(fid, struct mlxsw_sp_fid_8021d, common);
409}
410
411static 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
418static 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
425static 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
430static 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
445static bool
446mlxsw_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
453static 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
458static 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
485err_port_vp_mode_set:
486err_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
502static 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
523static 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
544err_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
551static void
552mlxsw_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
565static 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
576static 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 */
598static 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
609static 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
615static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid)
616{
617}
618
619static 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
629static 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
637static 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
656err_port_vp_mode_trans:
657 mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
658 return err;
659}
660
661static void
662mlxsw_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
673static 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
685static 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
694static 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
701static 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
706static 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
714static bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid,
715 const void *arg)
716{
717 return true;
718}
719
720static 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
727static 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
735static 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
742static 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
781err_configure:
782 __clear_bit(fid_index - fid_family->start_index,
783 fid_family->fids_bitmap);
784err_index_alloc:
785 kfree(fid);
786 return ERR_PTR(err);
787}
788
789void 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 */
e4f3c1c1 797 return mlxsw_sp_rif_destroy(fid->rif);
a1107487
IS
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
807struct 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
812struct 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
818struct 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
824struct 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
829static int
830mlxsw_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
856static int
857mlxsw_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
874static 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
904err_fid_flood_tables_init:
905 kfree(fid_family->fids_bitmap);
906err_alloc_fids_bitmap:
907 kfree(fid_family);
908 return err;
909}
910
911static void
912mlxsw_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
921int 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
934void 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
941int 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
969err_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);
977err_alloc_port_fid_mappings:
978 kfree(fid_core);
979 return err;
980}
981
982void 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}