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 *
mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid * fid,enum mlxsw_sp_flood_type packet_type)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
mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid * fid,enum mlxsw_sp_flood_type packet_type,u8 local_port,bool member)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
mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)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
mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)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
mlxsw_sp_fid_rif_type(const struct mlxsw_sp_fid * fid)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
mlxsw_sp_fid_index(const struct mlxsw_sp_fid * fid)162 u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid)
163 {
164 return fid->fid_index;
165 }
166
mlxsw_sp_fid_type(const struct mlxsw_sp_fid * fid)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
mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid * fid,struct mlxsw_sp_rif * rif)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
mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp * mlxsw_sp,enum mlxsw_sp_fid_type 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 *
mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid * fid)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
mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid * fid)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
mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid * fid,const void * arg)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
mlxsw_sp_sfmr_op(bool valid)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
mlxsw_sp_fid_op(struct mlxsw_sp * mlxsw_sp,u16 fid_index,u16 fid_offset,bool valid)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
mlxsw_sp_fid_vid_map(struct mlxsw_sp * mlxsw_sp,u16 fid_index,u16 vid,bool valid)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
__mlxsw_sp_fid_port_vid_map(struct mlxsw_sp * mlxsw_sp,u16 fid_index,u8 local_port,u16 vid,bool valid)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
mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid * fid)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
mlxsw_sp_fid_8021q_deconfigure(struct mlxsw_sp_fid * fid)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
mlxsw_sp_fid_8021q_index_alloc(struct mlxsw_sp_fid * fid,const void * arg,u16 * p_fid_index)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
mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid * fid,const void * arg)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
mlxsw_sp_fid_8021q_flood_index(const struct mlxsw_sp_fid * fid)295 static u16 mlxsw_sp_fid_8021q_flood_index(const struct mlxsw_sp_fid *fid)
296 {
297 return fid->fid_index;
298 }
299
mlxsw_sp_fid_8021q_port_vid_map(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)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
mlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)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 *
mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid * fid)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
mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid * fid,const void * arg)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
mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid * fid)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
mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid * fid)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
mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid * fid,const void * arg,u16 * p_fid_index)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
mlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid * fid,const void * arg)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
mlxsw_sp_fid_8021d_flood_index(const struct mlxsw_sp_fid * fid)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
mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port * mlxsw_sp_port)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
mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port * mlxsw_sp_port)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
mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)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
mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)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
mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid * fid)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
mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid * fid)584 static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid)
585 {
586 }
587
mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid * fid,const void * arg,u16 * p_fid_index)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
mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid * fid,const void * arg)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
mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)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
mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)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
mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid * fid)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
mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid * fid)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
mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid * fid,const void * arg,u16 * p_fid_index)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
mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid * fid,const void * arg)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 = MLXSW_SP_RFID_BASE - 1,
700 .end_index = MLXSW_SP_RFID_BASE - 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
mlxsw_sp_fid_get(struct mlxsw_sp * mlxsw_sp,enum mlxsw_sp_fid_type type,const void * arg)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
mlxsw_sp_fid_put(struct mlxsw_sp_fid * fid)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
mlxsw_sp_fid_8021q_get(struct mlxsw_sp * mlxsw_sp,u16 vid)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
mlxsw_sp_fid_8021d_get(struct mlxsw_sp * mlxsw_sp,int br_ifindex)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
mlxsw_sp_fid_rfid_get(struct mlxsw_sp * mlxsw_sp,u16 rif_index)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
mlxsw_sp_fid_dummy_get(struct mlxsw_sp * mlxsw_sp)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
mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family * fid_family,const struct mlxsw_sp_flood_table * flood_table)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
mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family * fid_family)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
mlxsw_sp_fid_family_register(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_fid_family * tmpl)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
mlxsw_sp_fid_family_unregister(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fid_family * fid_family)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
mlxsw_sp_port_fids_init(struct mlxsw_sp_port * mlxsw_sp_port)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
mlxsw_sp_port_fids_fini(struct mlxsw_sp_port * mlxsw_sp_port)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
mlxsw_sp_fids_init(struct mlxsw_sp * mlxsw_sp)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
mlxsw_sp_fids_fini(struct mlxsw_sp * mlxsw_sp)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 }
962