1 /*-
2 * Copyright (c) 2013-2017, Mellanox Technologies, Ltd. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26 #include "opt_rss.h"
27 #include "opt_ratelimit.h"
28
29 #include <linux/etherdevice.h>
30 #include <dev/mlx5/driver.h>
31 #include <dev/mlx5/mlx5_ifc.h>
32 #include <dev/mlx5/vport.h>
33 #include <dev/mlx5/fs.h>
34 #include <dev/mlx5/mpfs.h>
35 #include <dev/mlx5/mlx5_core/mlx5_core.h>
36 #include <dev/mlx5/mlx5_core/eswitch.h>
37
38 #define UPLINK_VPORT 0xFFFF
39
40 #define MLX5_DEBUG_ESWITCH_MASK BIT(3)
41
42 #define esw_info(dev, format, ...) \
43 printf("mlx5_core: INFO: ""(%s): E-Switch: " format, (dev)->priv.name, ##__VA_ARGS__)
44
45 #define esw_warn(dev, format, ...) \
46 printf("mlx5_core: WARN: ""(%s): E-Switch: " format, (dev)->priv.name, ##__VA_ARGS__)
47
48 #define esw_debug(dev, format, ...) \
49 mlx5_core_dbg_mask(dev, MLX5_DEBUG_ESWITCH_MASK, format, ##__VA_ARGS__)
50
51 enum {
52 MLX5_ACTION_NONE = 0,
53 MLX5_ACTION_ADD = 1,
54 MLX5_ACTION_DEL = 2,
55 };
56
57 /* E-Switch UC L2 table hash node */
58 struct esw_uc_addr {
59 struct l2addr_node node;
60 u32 table_index;
61 u32 vport;
62 };
63
64 /* E-Switch MC FDB table hash node */
65 struct esw_mc_addr { /* SRIOV only */
66 struct l2addr_node node;
67 struct mlx5_flow_rule *uplink_rule; /* Forward to uplink rule */
68 u32 refcnt;
69 };
70
71 /* Vport UC/MC hash node */
72 struct vport_addr {
73 struct l2addr_node node;
74 u8 action;
75 u32 vport;
76 struct mlx5_flow_rule *flow_rule; /* SRIOV only */
77 };
78
79 enum {
80 UC_ADDR_CHANGE = BIT(0),
81 MC_ADDR_CHANGE = BIT(1),
82 };
83
84 /* Vport context events */
85 #define SRIOV_VPORT_EVENTS (UC_ADDR_CHANGE | \
86 MC_ADDR_CHANGE)
87
arm_vport_context_events_cmd(struct mlx5_core_dev * dev,u16 vport,u32 events_mask)88 static int arm_vport_context_events_cmd(struct mlx5_core_dev *dev, u16 vport,
89 u32 events_mask)
90 {
91 int in[MLX5_ST_SZ_DW(modify_nic_vport_context_in)] = {0};
92 int out[MLX5_ST_SZ_DW(modify_nic_vport_context_out)] = {0};
93 void *nic_vport_ctx;
94
95 MLX5_SET(modify_nic_vport_context_in, in,
96 opcode, MLX5_CMD_OP_MODIFY_NIC_VPORT_CONTEXT);
97 MLX5_SET(modify_nic_vport_context_in, in, field_select.change_event, 1);
98 MLX5_SET(modify_nic_vport_context_in, in, vport_number, vport);
99 if (vport)
100 MLX5_SET(modify_nic_vport_context_in, in, other_vport, 1);
101 nic_vport_ctx = MLX5_ADDR_OF(modify_nic_vport_context_in,
102 in, nic_vport_context);
103
104 MLX5_SET(nic_vport_context, nic_vport_ctx, arm_change_event, 1);
105
106 if (events_mask & UC_ADDR_CHANGE)
107 MLX5_SET(nic_vport_context, nic_vport_ctx,
108 event_on_uc_address_change, 1);
109 if (events_mask & MC_ADDR_CHANGE)
110 MLX5_SET(nic_vport_context, nic_vport_ctx,
111 event_on_mc_address_change, 1);
112
113 return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
114 }
115
116 /* E-Switch vport context HW commands */
query_esw_vport_context_cmd(struct mlx5_core_dev * mdev,u32 vport,u32 * out,int outlen)117 static int query_esw_vport_context_cmd(struct mlx5_core_dev *mdev, u32 vport,
118 u32 *out, int outlen)
119 {
120 u32 in[MLX5_ST_SZ_DW(query_esw_vport_context_in)] = {0};
121
122 MLX5_SET(query_nic_vport_context_in, in, opcode,
123 MLX5_CMD_OP_QUERY_ESW_VPORT_CONTEXT);
124
125 MLX5_SET(query_esw_vport_context_in, in, vport_number, vport);
126 if (vport)
127 MLX5_SET(query_esw_vport_context_in, in, other_vport, 1);
128
129 return mlx5_cmd_exec(mdev, in, sizeof(in), out, outlen);
130 }
131
query_esw_vport_cvlan(struct mlx5_core_dev * dev,u32 vport,u16 * vlan,u8 * qos)132 static int query_esw_vport_cvlan(struct mlx5_core_dev *dev, u32 vport,
133 u16 *vlan, u8 *qos)
134 {
135 u32 out[MLX5_ST_SZ_DW(query_esw_vport_context_out)] = {0};
136 int err;
137 bool cvlan_strip;
138 bool cvlan_insert;
139
140 *vlan = 0;
141 *qos = 0;
142
143 if (!MLX5_CAP_ESW(dev, vport_cvlan_strip) ||
144 !MLX5_CAP_ESW(dev, vport_cvlan_insert_if_not_exist))
145 return -ENOTSUPP;
146
147 err = query_esw_vport_context_cmd(dev, vport, out, sizeof(out));
148 if (err)
149 goto out;
150
151 cvlan_strip = MLX5_GET(query_esw_vport_context_out, out,
152 esw_vport_context.vport_cvlan_strip);
153
154 cvlan_insert = MLX5_GET(query_esw_vport_context_out, out,
155 esw_vport_context.vport_cvlan_insert);
156
157 if (cvlan_strip || cvlan_insert) {
158 *vlan = MLX5_GET(query_esw_vport_context_out, out,
159 esw_vport_context.cvlan_id);
160 *qos = MLX5_GET(query_esw_vport_context_out, out,
161 esw_vport_context.cvlan_pcp);
162 }
163
164 esw_debug(dev, "Query Vport[%d] cvlan: VLAN %d qos=%d\n",
165 vport, *vlan, *qos);
166 out:
167 return err;
168 }
169
modify_esw_vport_context_cmd(struct mlx5_core_dev * dev,u16 vport,void * in,int inlen)170 static int modify_esw_vport_context_cmd(struct mlx5_core_dev *dev, u16 vport,
171 void *in, int inlen)
172 {
173 u32 out[MLX5_ST_SZ_DW(modify_esw_vport_context_out)] = {0};
174
175 MLX5_SET(modify_esw_vport_context_in, in, vport_number, vport);
176 if (vport)
177 MLX5_SET(modify_esw_vport_context_in, in, other_vport, 1);
178
179 MLX5_SET(modify_esw_vport_context_in, in, opcode,
180 MLX5_CMD_OP_MODIFY_ESW_VPORT_CONTEXT);
181
182 return mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
183 }
184
modify_esw_vport_cvlan(struct mlx5_core_dev * dev,u32 vport,u16 vlan,u8 qos,bool set)185 static int modify_esw_vport_cvlan(struct mlx5_core_dev *dev, u32 vport,
186 u16 vlan, u8 qos, bool set)
187 {
188 u32 in[MLX5_ST_SZ_DW(modify_esw_vport_context_in)] = {0};
189
190 if (!MLX5_CAP_ESW(dev, vport_cvlan_strip) ||
191 !MLX5_CAP_ESW(dev, vport_cvlan_insert_if_not_exist))
192 return -ENOTSUPP;
193
194 esw_debug(dev, "Set Vport[%d] VLAN %d qos %d set=%d\n",
195 vport, vlan, qos, set);
196
197 if (set) {
198 MLX5_SET(modify_esw_vport_context_in, in,
199 esw_vport_context.vport_cvlan_strip, 1);
200 /* insert only if no vlan in packet */
201 MLX5_SET(modify_esw_vport_context_in, in,
202 esw_vport_context.vport_cvlan_insert, 1);
203 MLX5_SET(modify_esw_vport_context_in, in,
204 esw_vport_context.cvlan_pcp, qos);
205 MLX5_SET(modify_esw_vport_context_in, in,
206 esw_vport_context.cvlan_id, vlan);
207 }
208
209 MLX5_SET(modify_esw_vport_context_in, in,
210 field_select.vport_cvlan_strip, 1);
211 MLX5_SET(modify_esw_vport_context_in, in,
212 field_select.vport_cvlan_insert, 1);
213
214 return modify_esw_vport_context_cmd(dev, vport, in, sizeof(in));
215 }
216
217 /* E-Switch FDB */
218 static struct mlx5_flow_rule *
esw_fdb_set_vport_rule(struct mlx5_eswitch * esw,u8 mac[ETH_ALEN],u32 vport)219 esw_fdb_set_vport_rule(struct mlx5_eswitch *esw, u8 mac[ETH_ALEN], u32 vport)
220 {
221 int match_header = MLX5_MATCH_OUTER_HEADERS;
222 struct mlx5_flow_destination dest;
223 struct mlx5_flow_rule *flow_rule = NULL;
224 struct mlx5_flow_act flow_act = {};
225 u32 *match_v;
226 u32 *match_c;
227 u8 *dmac_v;
228 u8 *dmac_c;
229
230 match_v = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
231 match_c = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
232 if (!match_v || !match_c) {
233 printf("mlx5_core: WARN: ""FDB: Failed to alloc match parameters\n");
234 goto out;
235 }
236 dmac_v = MLX5_ADDR_OF(fte_match_param, match_v,
237 outer_headers.dmac_47_16);
238 dmac_c = MLX5_ADDR_OF(fte_match_param, match_c,
239 outer_headers.dmac_47_16);
240
241 ether_addr_copy(dmac_v, mac);
242 /* Match criteria mask */
243 memset(dmac_c, 0xff, 6);
244
245 dest.type = MLX5_FLOW_CONTEXT_DEST_TYPE_VPORT;
246 dest.vport_num = vport;
247
248 esw_debug(esw->dev,
249 "\tFDB add rule dmac_v(%pM) dmac_c(%pM) -> vport(%d)\n",
250 dmac_v, dmac_c, vport);
251 flow_rule =
252 mlx5_add_flow_rule(esw->fdb_table.fdb,
253 match_header,
254 match_c,
255 match_v,
256 MLX5_FLOW_RULE_FWD_ACTION_DEST,
257 &flow_act, &dest);
258 if (IS_ERR_OR_NULL(flow_rule)) {
259 printf("mlx5_core: WARN: ""FDB: Failed to add flow rule: dmac_v(%pM) dmac_c(%pM) -> vport(%d), err(%ld)\n", dmac_v, dmac_c, vport, PTR_ERR(flow_rule));
260 flow_rule = NULL;
261 }
262 out:
263 kfree(match_v);
264 kfree(match_c);
265 return flow_rule;
266 }
267
esw_create_fdb_table(struct mlx5_eswitch * esw)268 static int esw_create_fdb_table(struct mlx5_eswitch *esw)
269 {
270 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
271 struct mlx5_core_dev *dev = esw->dev;
272 struct mlx5_flow_namespace *root_ns;
273 struct mlx5_flow_table *fdb;
274 struct mlx5_flow_group *g;
275 void *match_criteria;
276 int table_size;
277 u32 *flow_group_in;
278 u8 *dmac;
279 int err = 0;
280
281 esw_debug(dev, "Create FDB log_max_size(%d)\n",
282 MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size));
283
284 root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
285 if (!root_ns) {
286 esw_warn(dev, "Failed to get FDB flow namespace\n");
287 return -ENOMEM;
288 }
289
290 flow_group_in = mlx5_vzalloc(inlen);
291 if (!flow_group_in)
292 return -ENOMEM;
293 memset(flow_group_in, 0, inlen);
294
295 /* (-2) Since MaorG said so .. */
296 table_size = BIT(MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size)) - 2;
297
298 fdb = mlx5_create_flow_table(root_ns, 0, "FDB", table_size);
299 if (IS_ERR_OR_NULL(fdb)) {
300 err = PTR_ERR(fdb);
301 esw_warn(dev, "Failed to create FDB Table err %d\n", err);
302 goto out;
303 }
304
305 MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
306 MLX5_MATCH_OUTER_HEADERS);
307 match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
308 dmac = MLX5_ADDR_OF(fte_match_param, match_criteria, outer_headers.dmac_47_16);
309 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
310 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, table_size - 1);
311 eth_broadcast_addr(dmac);
312
313 g = mlx5_create_flow_group(fdb, flow_group_in);
314 if (IS_ERR_OR_NULL(g)) {
315 err = PTR_ERR(g);
316 esw_warn(dev, "Failed to create flow group err(%d)\n", err);
317 goto out;
318 }
319
320 esw->fdb_table.addr_grp = g;
321 esw->fdb_table.fdb = fdb;
322 out:
323 kfree(flow_group_in);
324 if (err && !IS_ERR_OR_NULL(fdb))
325 mlx5_destroy_flow_table(fdb);
326 return err;
327 }
328
esw_destroy_fdb_table(struct mlx5_eswitch * esw)329 static void esw_destroy_fdb_table(struct mlx5_eswitch *esw)
330 {
331 if (!esw->fdb_table.fdb)
332 return;
333
334 esw_debug(esw->dev, "Destroy FDB Table\n");
335 mlx5_destroy_flow_group(esw->fdb_table.addr_grp);
336 mlx5_destroy_flow_table(esw->fdb_table.fdb);
337 esw->fdb_table.fdb = NULL;
338 esw->fdb_table.addr_grp = NULL;
339 }
340
341 /* E-Switch vport UC/MC lists management */
342 typedef int (*vport_addr_action)(struct mlx5_eswitch *esw,
343 struct vport_addr *vaddr);
344
esw_add_uc_addr(struct mlx5_eswitch * esw,struct vport_addr * vaddr)345 static int esw_add_uc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
346 {
347 struct hlist_head *hash = esw->l2_table.l2_hash;
348 struct esw_uc_addr *esw_uc;
349 u8 *mac = vaddr->node.addr;
350 u32 vport = vaddr->vport;
351 int err;
352
353 esw_uc = l2addr_hash_find(hash, mac, struct esw_uc_addr);
354 if (esw_uc) {
355 esw_warn(esw->dev,
356 "Failed to set L2 mac(%pM) for vport(%d), mac is already in use by vport(%d)\n",
357 mac, vport, esw_uc->vport);
358 return -EEXIST;
359 }
360
361 esw_uc = l2addr_hash_add(hash, mac, struct esw_uc_addr, GFP_KERNEL);
362 if (!esw_uc)
363 return -ENOMEM;
364 esw_uc->vport = vport;
365
366 err = mlx5_mpfs_add_mac(esw->dev, &esw_uc->table_index, mac, 0, 0);
367 if (err)
368 goto abort;
369
370 if (esw->fdb_table.fdb) /* SRIOV is enabled: Forward UC MAC to vport */
371 vaddr->flow_rule = esw_fdb_set_vport_rule(esw, mac, vport);
372
373 esw_debug(esw->dev, "\tADDED UC MAC: vport[%d] %pM index:%d fr(%p)\n",
374 vport, mac, esw_uc->table_index, vaddr->flow_rule);
375 return err;
376 abort:
377 l2addr_hash_del(esw_uc);
378 return err;
379 }
380
esw_del_uc_addr(struct mlx5_eswitch * esw,struct vport_addr * vaddr)381 static int esw_del_uc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
382 {
383 struct hlist_head *hash = esw->l2_table.l2_hash;
384 struct esw_uc_addr *esw_uc;
385 u8 *mac = vaddr->node.addr;
386 u32 vport = vaddr->vport;
387
388 esw_uc = l2addr_hash_find(hash, mac, struct esw_uc_addr);
389 if (!esw_uc || esw_uc->vport != vport) {
390 esw_debug(esw->dev,
391 "MAC(%pM) doesn't belong to vport (%d)\n",
392 mac, vport);
393 return -EINVAL;
394 }
395 esw_debug(esw->dev, "\tDELETE UC MAC: vport[%d] %pM index:%d fr(%p)\n",
396 vport, mac, esw_uc->table_index, vaddr->flow_rule);
397
398 mlx5_mpfs_del_mac(esw->dev, esw_uc->table_index);
399
400 mlx5_del_flow_rule(&vaddr->flow_rule);
401
402 l2addr_hash_del(esw_uc);
403 return 0;
404 }
405
esw_add_mc_addr(struct mlx5_eswitch * esw,struct vport_addr * vaddr)406 static int esw_add_mc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
407 {
408 struct hlist_head *hash = esw->mc_table;
409 struct esw_mc_addr *esw_mc;
410 u8 *mac = vaddr->node.addr;
411 u32 vport = vaddr->vport;
412
413 if (!esw->fdb_table.fdb)
414 return 0;
415
416 esw_mc = l2addr_hash_find(hash, mac, struct esw_mc_addr);
417 if (esw_mc)
418 goto add;
419
420 esw_mc = l2addr_hash_add(hash, mac, struct esw_mc_addr, GFP_KERNEL);
421 if (!esw_mc)
422 return -ENOMEM;
423
424 esw_mc->uplink_rule = /* Forward MC MAC to Uplink */
425 esw_fdb_set_vport_rule(esw, mac, UPLINK_VPORT);
426 add:
427 esw_mc->refcnt++;
428 /* Forward MC MAC to vport */
429 vaddr->flow_rule = esw_fdb_set_vport_rule(esw, mac, vport);
430 esw_debug(esw->dev,
431 "\tADDED MC MAC: vport[%d] %pM fr(%p) refcnt(%d) uplinkfr(%p)\n",
432 vport, mac, vaddr->flow_rule,
433 esw_mc->refcnt, esw_mc->uplink_rule);
434 return 0;
435 }
436
esw_del_mc_addr(struct mlx5_eswitch * esw,struct vport_addr * vaddr)437 static int esw_del_mc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
438 {
439 struct hlist_head *hash = esw->mc_table;
440 struct esw_mc_addr *esw_mc;
441 u8 *mac = vaddr->node.addr;
442 u32 vport = vaddr->vport;
443
444 if (!esw->fdb_table.fdb)
445 return 0;
446
447 esw_mc = l2addr_hash_find(hash, mac, struct esw_mc_addr);
448 if (!esw_mc) {
449 esw_warn(esw->dev,
450 "Failed to find eswitch MC addr for MAC(%pM) vport(%d)",
451 mac, vport);
452 return -EINVAL;
453 }
454 esw_debug(esw->dev,
455 "\tDELETE MC MAC: vport[%d] %pM fr(%p) refcnt(%d) uplinkfr(%p)\n",
456 vport, mac, vaddr->flow_rule, esw_mc->refcnt,
457 esw_mc->uplink_rule);
458
459 mlx5_del_flow_rule(&vaddr->flow_rule);
460
461 if (--esw_mc->refcnt)
462 return 0;
463
464 mlx5_del_flow_rule(&esw_mc->uplink_rule);
465
466 l2addr_hash_del(esw_mc);
467 return 0;
468 }
469
470 /* Apply vport UC/MC list to HW l2 table and FDB table */
esw_apply_vport_addr_list(struct mlx5_eswitch * esw,u32 vport_num,int list_type)471 static void esw_apply_vport_addr_list(struct mlx5_eswitch *esw,
472 u32 vport_num, int list_type)
473 {
474 struct mlx5_vport *vport = &esw->vports[vport_num];
475 bool is_uc = list_type == MLX5_NIC_VPORT_LIST_TYPE_UC;
476 vport_addr_action vport_addr_add;
477 vport_addr_action vport_addr_del;
478 struct vport_addr *addr;
479 struct l2addr_node *node;
480 struct hlist_head *hash;
481 struct hlist_node *tmp;
482 int hi;
483
484 vport_addr_add = is_uc ? esw_add_uc_addr :
485 esw_add_mc_addr;
486 vport_addr_del = is_uc ? esw_del_uc_addr :
487 esw_del_mc_addr;
488
489 hash = is_uc ? vport->uc_list : vport->mc_list;
490 for_each_l2hash_node(node, tmp, hash, hi) {
491 addr = container_of(node, struct vport_addr, node);
492 switch (addr->action) {
493 case MLX5_ACTION_ADD:
494 vport_addr_add(esw, addr);
495 addr->action = MLX5_ACTION_NONE;
496 break;
497 case MLX5_ACTION_DEL:
498 vport_addr_del(esw, addr);
499 l2addr_hash_del(addr);
500 break;
501 }
502 }
503 }
504
505 /* Sync vport UC/MC list from vport context */
esw_update_vport_addr_list(struct mlx5_eswitch * esw,u32 vport_num,int list_type)506 static void esw_update_vport_addr_list(struct mlx5_eswitch *esw,
507 u32 vport_num, int list_type)
508 {
509 struct mlx5_vport *vport = &esw->vports[vport_num];
510 bool is_uc = list_type == MLX5_NIC_VPORT_LIST_TYPE_UC;
511 u8 (*mac_list)[ETH_ALEN];
512 struct l2addr_node *node;
513 struct vport_addr *addr;
514 struct hlist_head *hash;
515 struct hlist_node *tmp;
516 int size;
517 int err;
518 int hi;
519 int i;
520
521 size = is_uc ? MLX5_MAX_UC_PER_VPORT(esw->dev) :
522 MLX5_MAX_MC_PER_VPORT(esw->dev);
523
524 mac_list = kcalloc(size, ETH_ALEN, GFP_KERNEL);
525 if (!mac_list)
526 return;
527
528 hash = is_uc ? vport->uc_list : vport->mc_list;
529
530 for_each_l2hash_node(node, tmp, hash, hi) {
531 addr = container_of(node, struct vport_addr, node);
532 addr->action = MLX5_ACTION_DEL;
533 }
534
535 err = mlx5_query_nic_vport_mac_list(esw->dev, vport_num, list_type,
536 mac_list, &size);
537 if (err)
538 return;
539 esw_debug(esw->dev, "vport[%d] context update %s list size (%d)\n",
540 vport_num, is_uc ? "UC" : "MC", size);
541
542 for (i = 0; i < size; i++) {
543 if (is_uc && !is_valid_ether_addr(mac_list[i]))
544 continue;
545
546 if (!is_uc && !is_multicast_ether_addr(mac_list[i]))
547 continue;
548
549 addr = l2addr_hash_find(hash, mac_list[i], struct vport_addr);
550 if (addr) {
551 addr->action = MLX5_ACTION_NONE;
552 continue;
553 }
554
555 addr = l2addr_hash_add(hash, mac_list[i], struct vport_addr,
556 GFP_KERNEL);
557 if (!addr) {
558 esw_warn(esw->dev,
559 "Failed to add MAC(%pM) to vport[%d] DB\n",
560 mac_list[i], vport_num);
561 continue;
562 }
563 addr->vport = vport_num;
564 addr->action = MLX5_ACTION_ADD;
565 }
566 kfree(mac_list);
567 }
568
esw_vport_change_handler(struct work_struct * work)569 static void esw_vport_change_handler(struct work_struct *work)
570 {
571 struct mlx5_vport *vport =
572 container_of(work, struct mlx5_vport, vport_change_handler);
573 struct mlx5_core_dev *dev = vport->dev;
574 struct mlx5_eswitch *esw = dev->priv.eswitch;
575 u8 mac[ETH_ALEN];
576
577 mlx5_query_nic_vport_mac_address(dev, vport->vport, mac);
578 esw_debug(dev, "vport[%d] Context Changed: perm mac: %pM\n",
579 vport->vport, mac);
580
581 if (vport->enabled_events & UC_ADDR_CHANGE) {
582 esw_update_vport_addr_list(esw, vport->vport,
583 MLX5_NIC_VPORT_LIST_TYPE_UC);
584 esw_apply_vport_addr_list(esw, vport->vport,
585 MLX5_NIC_VPORT_LIST_TYPE_UC);
586 }
587
588 if (vport->enabled_events & MC_ADDR_CHANGE) {
589 esw_update_vport_addr_list(esw, vport->vport,
590 MLX5_NIC_VPORT_LIST_TYPE_MC);
591 esw_apply_vport_addr_list(esw, vport->vport,
592 MLX5_NIC_VPORT_LIST_TYPE_MC);
593 }
594
595 esw_debug(esw->dev, "vport[%d] Context Changed: Done\n", vport->vport);
596 if (vport->enabled)
597 arm_vport_context_events_cmd(dev, vport->vport,
598 vport->enabled_events);
599 }
600
esw_vport_enable_egress_acl(struct mlx5_eswitch * esw,struct mlx5_vport * vport)601 static void esw_vport_enable_egress_acl(struct mlx5_eswitch *esw,
602 struct mlx5_vport *vport)
603 {
604 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
605 struct mlx5_flow_group *vlan_grp = NULL;
606 struct mlx5_flow_group *drop_grp = NULL;
607 struct mlx5_core_dev *dev = esw->dev;
608 struct mlx5_flow_namespace *root_ns;
609 struct mlx5_flow_table *acl;
610 void *match_criteria;
611 char table_name[32];
612 u32 *flow_group_in;
613 int table_size = 2;
614 int err = 0;
615
616 if (!MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support))
617 return;
618
619 esw_debug(dev, "Create vport[%d] egress ACL log_max_size(%d)\n",
620 vport->vport, MLX5_CAP_ESW_EGRESS_ACL(dev, log_max_ft_size));
621
622 root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_EGRESS);
623 if (!root_ns) {
624 esw_warn(dev, "Failed to get E-Switch egress flow namespace\n");
625 return;
626 }
627
628 flow_group_in = mlx5_vzalloc(inlen);
629 if (!flow_group_in)
630 return;
631
632 snprintf(table_name, 32, "egress_%d", vport->vport);
633 acl = mlx5_create_vport_flow_table(root_ns, vport->vport, 0, table_name, table_size);
634 if (IS_ERR_OR_NULL(acl)) {
635 err = PTR_ERR(acl);
636 esw_warn(dev, "Failed to create E-Switch vport[%d] egress flow Table, err(%d)\n",
637 vport->vport, err);
638 goto out;
639 }
640
641 MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
642 match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
643 MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.cvlan_tag);
644 MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.first_vid);
645 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
646 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 0);
647
648 vlan_grp = mlx5_create_flow_group(acl, flow_group_in);
649 if (IS_ERR_OR_NULL(vlan_grp)) {
650 err = PTR_ERR(vlan_grp);
651 esw_warn(dev, "Failed to create E-Switch vport[%d] egress allowed vlans flow group, err(%d)\n",
652 vport->vport, err);
653 goto out;
654 }
655
656 memset(flow_group_in, 0, inlen);
657 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 1);
658 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 1);
659 drop_grp = mlx5_create_flow_group(acl, flow_group_in);
660 if (IS_ERR_OR_NULL(drop_grp)) {
661 err = PTR_ERR(drop_grp);
662 esw_warn(dev, "Failed to create E-Switch vport[%d] egress drop flow group, err(%d)\n",
663 vport->vport, err);
664 goto out;
665 }
666
667 vport->egress.acl = acl;
668 vport->egress.drop_grp = drop_grp;
669 vport->egress.allowed_vlans_grp = vlan_grp;
670 out:
671 kfree(flow_group_in);
672 if (err && !IS_ERR_OR_NULL(vlan_grp))
673 mlx5_destroy_flow_group(vlan_grp);
674 if (err && !IS_ERR_OR_NULL(acl))
675 mlx5_destroy_flow_table(acl);
676 }
677
esw_vport_cleanup_egress_rules(struct mlx5_eswitch * esw,struct mlx5_vport * vport)678 static void esw_vport_cleanup_egress_rules(struct mlx5_eswitch *esw,
679 struct mlx5_vport *vport)
680 {
681 mlx5_del_flow_rule(&vport->egress.allowed_vlan);
682 mlx5_del_flow_rule(&vport->egress.drop_rule);
683 }
684
esw_vport_disable_egress_acl(struct mlx5_eswitch * esw,struct mlx5_vport * vport)685 static void esw_vport_disable_egress_acl(struct mlx5_eswitch *esw,
686 struct mlx5_vport *vport)
687 {
688 if (IS_ERR_OR_NULL(vport->egress.acl))
689 return;
690
691 esw_debug(esw->dev, "Destroy vport[%d] E-Switch egress ACL\n", vport->vport);
692
693 esw_vport_cleanup_egress_rules(esw, vport);
694 mlx5_destroy_flow_group(vport->egress.allowed_vlans_grp);
695 mlx5_destroy_flow_group(vport->egress.drop_grp);
696 mlx5_destroy_flow_table(vport->egress.acl);
697 vport->egress.allowed_vlans_grp = NULL;
698 vport->egress.drop_grp = NULL;
699 vport->egress.acl = NULL;
700 }
701
esw_vport_enable_ingress_acl(struct mlx5_eswitch * esw,struct mlx5_vport * vport)702 static void esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw,
703 struct mlx5_vport *vport)
704 {
705 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
706 struct mlx5_core_dev *dev = esw->dev;
707 struct mlx5_flow_namespace *root_ns;
708 struct mlx5_flow_table *acl;
709 struct mlx5_flow_group *g;
710 void *match_criteria;
711 char table_name[32];
712 u32 *flow_group_in;
713 int table_size = 1;
714 int err = 0;
715
716 if (!MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support))
717 return;
718
719 esw_debug(dev, "Create vport[%d] ingress ACL log_max_size(%d)\n",
720 vport->vport, MLX5_CAP_ESW_INGRESS_ACL(dev, log_max_ft_size));
721
722 root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_INGRESS);
723 if (!root_ns) {
724 esw_warn(dev, "Failed to get E-Switch ingress flow namespace\n");
725 return;
726 }
727
728 flow_group_in = mlx5_vzalloc(inlen);
729 if (!flow_group_in)
730 return;
731
732 snprintf(table_name, 32, "ingress_%d", vport->vport);
733 acl = mlx5_create_vport_flow_table(root_ns, vport->vport, 0, table_name, table_size);
734 if (IS_ERR_OR_NULL(acl)) {
735 err = PTR_ERR(acl);
736 esw_warn(dev, "Failed to create E-Switch vport[%d] ingress flow Table, err(%d)\n",
737 vport->vport, err);
738 goto out;
739 }
740
741 MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
742 match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
743 MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.cvlan_tag);
744 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
745 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 0);
746
747 g = mlx5_create_flow_group(acl, flow_group_in);
748 if (IS_ERR_OR_NULL(g)) {
749 err = PTR_ERR(g);
750 esw_warn(dev, "Failed to create E-Switch vport[%d] ingress flow group, err(%d)\n",
751 vport->vport, err);
752 goto out;
753 }
754
755 vport->ingress.acl = acl;
756 vport->ingress.drop_grp = g;
757 out:
758 kfree(flow_group_in);
759 if (err && !IS_ERR_OR_NULL(acl))
760 mlx5_destroy_flow_table(acl);
761 }
762
esw_vport_cleanup_ingress_rules(struct mlx5_eswitch * esw,struct mlx5_vport * vport)763 static void esw_vport_cleanup_ingress_rules(struct mlx5_eswitch *esw,
764 struct mlx5_vport *vport)
765 {
766 mlx5_del_flow_rule(&vport->ingress.drop_rule);
767 }
768
esw_vport_disable_ingress_acl(struct mlx5_eswitch * esw,struct mlx5_vport * vport)769 static void esw_vport_disable_ingress_acl(struct mlx5_eswitch *esw,
770 struct mlx5_vport *vport)
771 {
772 if (IS_ERR_OR_NULL(vport->ingress.acl))
773 return;
774
775 esw_debug(esw->dev, "Destroy vport[%d] E-Switch ingress ACL\n", vport->vport);
776
777 esw_vport_cleanup_ingress_rules(esw, vport);
778 mlx5_destroy_flow_group(vport->ingress.drop_grp);
779 mlx5_destroy_flow_table(vport->ingress.acl);
780 vport->ingress.acl = NULL;
781 vport->ingress.drop_grp = NULL;
782 }
783
esw_vport_ingress_config(struct mlx5_eswitch * esw,struct mlx5_vport * vport)784 static int esw_vport_ingress_config(struct mlx5_eswitch *esw,
785 struct mlx5_vport *vport)
786 {
787 struct mlx5_flow_act flow_act = {};
788 struct mlx5_flow_destination dest;
789 u32 *match_v;
790 u32 *match_c;
791 int err = 0;
792
793 if (IS_ERR_OR_NULL(vport->ingress.acl)) {
794 esw_warn(esw->dev,
795 "vport[%d] configure ingress rules failed, ingress acl is not initialized!\n",
796 vport->vport);
797 return -EPERM;
798 }
799
800 esw_vport_cleanup_ingress_rules(esw, vport);
801
802 if (!vport->vlan && !vport->qos)
803 return 0;
804
805 esw_debug(esw->dev,
806 "vport[%d] configure ingress rules, vlan(%d) qos(%d)\n",
807 vport->vport, vport->vlan, vport->qos);
808
809 match_v = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
810 match_c = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
811 if (!match_v || !match_c) {
812 err = -ENOMEM;
813 esw_warn(esw->dev, "vport[%d] configure ingress rules failed, err(%d)\n",
814 vport->vport, err);
815 goto out;
816 }
817 MLX5_SET_TO_ONES(fte_match_param, match_c, outer_headers.cvlan_tag);
818 MLX5_SET_TO_ONES(fte_match_param, match_v, outer_headers.cvlan_tag);
819
820 dest.type = MLX5_FLOW_CONTEXT_DEST_TYPE_VPORT;
821 dest.vport_num = vport->vport;
822
823 vport->ingress.drop_rule =
824 mlx5_add_flow_rule(vport->ingress.acl,
825 MLX5_MATCH_OUTER_HEADERS,
826 match_c,
827 match_v,
828 MLX5_FLOW_RULE_FWD_ACTION_DROP,
829 &flow_act, &dest);
830 if (IS_ERR_OR_NULL(vport->ingress.drop_rule)) {
831 err = PTR_ERR(vport->ingress.drop_rule);
832 printf("mlx5_core: WARN: ""vport[%d] configure ingress rules, err(%d)\n", vport->vport, err);
833 vport->ingress.drop_rule = NULL;
834 }
835 out:
836 kfree(match_v);
837 kfree(match_c);
838 return err;
839 }
840
esw_vport_egress_config(struct mlx5_eswitch * esw,struct mlx5_vport * vport)841 static int esw_vport_egress_config(struct mlx5_eswitch *esw,
842 struct mlx5_vport *vport)
843 {
844 struct mlx5_flow_act flow_act = {};
845 struct mlx5_flow_destination dest;
846 u32 *match_v;
847 u32 *match_c;
848 int err = 0;
849
850 if (IS_ERR_OR_NULL(vport->egress.acl)) {
851 esw_warn(esw->dev, "vport[%d] configure rgress rules failed, egress acl is not initialized!\n",
852 vport->vport);
853 return -EPERM;
854 }
855
856 esw_vport_cleanup_egress_rules(esw, vport);
857
858 if (!vport->vlan && !vport->qos)
859 return 0;
860
861 esw_debug(esw->dev,
862 "vport[%d] configure egress rules, vlan(%d) qos(%d)\n",
863 vport->vport, vport->vlan, vport->qos);
864
865 match_v = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
866 match_c = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
867 if (!match_v || !match_c) {
868 err = -ENOMEM;
869 esw_warn(esw->dev, "vport[%d] configure egress rules failed, err(%d)\n",
870 vport->vport, err);
871 goto out;
872 }
873
874 /* Allowed vlan rule */
875 MLX5_SET_TO_ONES(fte_match_param, match_c, outer_headers.cvlan_tag);
876 MLX5_SET_TO_ONES(fte_match_param, match_v, outer_headers.cvlan_tag);
877 MLX5_SET_TO_ONES(fte_match_param, match_c, outer_headers.first_vid);
878 MLX5_SET(fte_match_param, match_v, outer_headers.first_vid, vport->vlan);
879
880 dest.type = MLX5_FLOW_CONTEXT_DEST_TYPE_VPORT;
881 dest.vport_num = vport->vport;
882
883 vport->egress.allowed_vlan =
884 mlx5_add_flow_rule(vport->egress.acl,
885 MLX5_MATCH_OUTER_HEADERS,
886 match_c,
887 match_v,
888 MLX5_FLOW_RULE_FWD_ACTION_ALLOW,
889 &flow_act, &dest);
890 if (IS_ERR_OR_NULL(vport->egress.allowed_vlan)) {
891 err = PTR_ERR(vport->egress.allowed_vlan);
892 printf("mlx5_core: WARN: ""vport[%d] configure egress allowed vlan rule failed, err(%d)\n", vport->vport, err);
893 vport->egress.allowed_vlan = NULL;
894 goto out;
895 }
896
897 /* Drop others rule (star rule) */
898 memset(match_c, 0, MLX5_ST_SZ_BYTES(fte_match_param));
899 memset(match_v, 0, MLX5_ST_SZ_BYTES(fte_match_param));
900 vport->egress.drop_rule =
901 mlx5_add_flow_rule(vport->egress.acl,
902 0,
903 match_c,
904 match_v,
905 MLX5_FLOW_RULE_FWD_ACTION_DROP,
906 &flow_act, &dest);
907 if (IS_ERR_OR_NULL(vport->egress.drop_rule)) {
908 err = PTR_ERR(vport->egress.drop_rule);
909 printf("mlx5_core: WARN: ""vport[%d] configure egress drop rule failed, err(%d)\n", vport->vport, err);
910 vport->egress.drop_rule = NULL;
911 }
912 out:
913 kfree(match_v);
914 kfree(match_c);
915 return err;
916 }
917
esw_enable_vport(struct mlx5_eswitch * esw,int vport_num,int enable_events)918 static void esw_enable_vport(struct mlx5_eswitch *esw, int vport_num,
919 int enable_events)
920 {
921 struct mlx5_vport *vport = &esw->vports[vport_num];
922 unsigned long flags;
923
924 mutex_lock(&vport->state_lock);
925 WARN_ON(vport->enabled);
926
927 esw_debug(esw->dev, "Enabling VPORT(%d)\n", vport_num);
928
929 if (vport_num) { /* Only VFs need ACLs for VST and spoofchk filtering */
930 esw_vport_enable_ingress_acl(esw, vport);
931 esw_vport_enable_egress_acl(esw, vport);
932 esw_vport_ingress_config(esw, vport);
933 esw_vport_egress_config(esw, vport);
934 }
935
936 mlx5_modify_vport_admin_state(esw->dev,
937 MLX5_QUERY_VPORT_STATE_IN_OP_MOD_ESW_VPORT,
938 vport_num,
939 MLX5_ESW_VPORT_ADMIN_STATE_AUTO);
940
941 /* Sync with current vport context */
942 vport->enabled_events = enable_events;
943 esw_vport_change_handler(&vport->vport_change_handler);
944
945 spin_lock_irqsave(&vport->lock, flags);
946 vport->enabled = true;
947 spin_unlock_irqrestore(&vport->lock, flags);
948
949 arm_vport_context_events_cmd(esw->dev, vport_num, enable_events);
950
951 esw->enabled_vports++;
952 esw_debug(esw->dev, "Enabled VPORT(%d)\n", vport_num);
953 mutex_unlock(&vport->state_lock);
954 }
955
esw_cleanup_vport(struct mlx5_eswitch * esw,u16 vport_num)956 static void esw_cleanup_vport(struct mlx5_eswitch *esw, u16 vport_num)
957 {
958 struct mlx5_vport *vport = &esw->vports[vport_num];
959 struct l2addr_node *node;
960 struct vport_addr *addr;
961 struct hlist_node *tmp;
962 int hi;
963
964 for_each_l2hash_node(node, tmp, vport->uc_list, hi) {
965 addr = container_of(node, struct vport_addr, node);
966 addr->action = MLX5_ACTION_DEL;
967 }
968 esw_apply_vport_addr_list(esw, vport_num, MLX5_NIC_VPORT_LIST_TYPE_UC);
969
970 for_each_l2hash_node(node, tmp, vport->mc_list, hi) {
971 addr = container_of(node, struct vport_addr, node);
972 addr->action = MLX5_ACTION_DEL;
973 }
974 esw_apply_vport_addr_list(esw, vport_num, MLX5_NIC_VPORT_LIST_TYPE_MC);
975 }
976
esw_disable_vport(struct mlx5_eswitch * esw,int vport_num)977 static void esw_disable_vport(struct mlx5_eswitch *esw, int vport_num)
978 {
979 struct mlx5_vport *vport = &esw->vports[vport_num];
980 unsigned long flags;
981
982 mutex_lock(&vport->state_lock);
983 if (!vport->enabled) {
984 mutex_unlock(&vport->state_lock);
985 return;
986 }
987
988 esw_debug(esw->dev, "Disabling vport(%d)\n", vport_num);
989 /* Mark this vport as disabled to discard new events */
990 spin_lock_irqsave(&vport->lock, flags);
991 vport->enabled = false;
992 vport->enabled_events = 0;
993 spin_unlock_irqrestore(&vport->lock, flags);
994
995 mlx5_modify_vport_admin_state(esw->dev,
996 MLX5_QUERY_VPORT_STATE_IN_OP_MOD_ESW_VPORT,
997 vport_num,
998 MLX5_ESW_VPORT_ADMIN_STATE_DOWN);
999 /* Wait for current already scheduled events to complete */
1000 flush_workqueue(esw->work_queue);
1001 /* Disable events from this vport */
1002 arm_vport_context_events_cmd(esw->dev, vport->vport, 0);
1003 /* We don't assume VFs will cleanup after themselves */
1004 esw_cleanup_vport(esw, vport_num);
1005 if (vport_num) {
1006 esw_vport_disable_egress_acl(esw, vport);
1007 esw_vport_disable_ingress_acl(esw, vport);
1008 }
1009 esw->enabled_vports--;
1010 mutex_unlock(&vport->state_lock);
1011 }
1012
1013 /* Public E-Switch API */
mlx5_eswitch_enable_sriov(struct mlx5_eswitch * esw,int nvfs)1014 int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs)
1015 {
1016 int err;
1017 int i;
1018
1019 if (!esw || !MLX5_CAP_GEN(esw->dev, vport_group_manager) ||
1020 MLX5_CAP_GEN(esw->dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
1021 return 0;
1022
1023 if (!MLX5_CAP_GEN(esw->dev, eswitch_flow_table) ||
1024 !MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, ft_support)) {
1025 esw_warn(esw->dev, "E-Switch FDB is not supported, aborting ...\n");
1026 return -ENOTSUPP;
1027 }
1028
1029 if (!MLX5_CAP_ESW_INGRESS_ACL(esw->dev, ft_support))
1030 esw_warn(esw->dev, "E-Switch ingress ACL is not supported by FW\n");
1031
1032 if (!MLX5_CAP_ESW_EGRESS_ACL(esw->dev, ft_support))
1033 esw_warn(esw->dev, "E-Switch engress ACL is not supported by FW\n");
1034
1035 esw_info(esw->dev, "E-Switch enable SRIOV: nvfs(%d)\n", nvfs);
1036
1037 esw_disable_vport(esw, 0);
1038
1039 err = esw_create_fdb_table(esw);
1040 if (err)
1041 goto abort;
1042
1043 for (i = 0; i <= nvfs; i++)
1044 esw_enable_vport(esw, i, SRIOV_VPORT_EVENTS);
1045
1046 esw_info(esw->dev, "SRIOV enabled: active vports(%d)\n",
1047 esw->enabled_vports);
1048 return 0;
1049
1050 abort:
1051 esw_enable_vport(esw, 0, UC_ADDR_CHANGE);
1052 return err;
1053 }
1054
mlx5_eswitch_disable_sriov(struct mlx5_eswitch * esw)1055 void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw)
1056 {
1057 int i;
1058
1059 if (!esw || !MLX5_CAP_GEN(esw->dev, vport_group_manager) ||
1060 MLX5_CAP_GEN(esw->dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
1061 return;
1062
1063 esw_info(esw->dev, "disable SRIOV: active vports(%d)\n",
1064 esw->enabled_vports);
1065
1066 for (i = 0; i < esw->total_vports; i++)
1067 esw_disable_vport(esw, i);
1068
1069 esw_destroy_fdb_table(esw);
1070
1071 /* VPORT 0 (PF) must be enabled back with non-sriov configuration */
1072 esw_enable_vport(esw, 0, UC_ADDR_CHANGE);
1073 }
1074
mlx5_eswitch_init(struct mlx5_core_dev * dev,int total_vports)1075 int mlx5_eswitch_init(struct mlx5_core_dev *dev, int total_vports)
1076 {
1077 int l2_table_size = 1 << MLX5_CAP_GEN(dev, log_max_l2_table);
1078 struct mlx5_eswitch *esw;
1079 int vport_num;
1080 int err;
1081
1082 if (!MLX5_CAP_GEN(dev, vport_group_manager) ||
1083 MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
1084 return 0;
1085
1086 esw_info(dev,
1087 "Total vports %d, l2 table size(%d), per vport: max uc(%d) max mc(%d)\n",
1088 total_vports, l2_table_size,
1089 MLX5_MAX_UC_PER_VPORT(dev),
1090 MLX5_MAX_MC_PER_VPORT(dev));
1091
1092 esw = kzalloc(sizeof(*esw), GFP_KERNEL);
1093 if (!esw)
1094 return -ENOMEM;
1095
1096 esw->dev = dev;
1097
1098 esw->l2_table.bitmap = kcalloc(BITS_TO_LONGS(l2_table_size),
1099 sizeof(uintptr_t), GFP_KERNEL);
1100 if (!esw->l2_table.bitmap) {
1101 err = -ENOMEM;
1102 goto abort;
1103 }
1104 esw->l2_table.size = l2_table_size;
1105
1106 esw->work_queue = create_singlethread_workqueue("mlx5_esw_wq");
1107 if (!esw->work_queue) {
1108 err = -ENOMEM;
1109 goto abort;
1110 }
1111
1112 esw->vports = kcalloc(total_vports, sizeof(struct mlx5_vport),
1113 GFP_KERNEL);
1114 if (!esw->vports) {
1115 err = -ENOMEM;
1116 goto abort;
1117 }
1118
1119 for (vport_num = 0; vport_num < total_vports; vport_num++) {
1120 struct mlx5_vport *vport = &esw->vports[vport_num];
1121
1122 vport->vport = vport_num;
1123 vport->dev = dev;
1124 INIT_WORK(&vport->vport_change_handler,
1125 esw_vport_change_handler);
1126 spin_lock_init(&vport->lock);
1127 mutex_init(&vport->state_lock);
1128 }
1129
1130 esw->total_vports = total_vports;
1131 esw->enabled_vports = 0;
1132
1133 dev->priv.eswitch = esw;
1134 esw_enable_vport(esw, 0, UC_ADDR_CHANGE);
1135 /* VF Vports will be enabled when SRIOV is enabled */
1136 return 0;
1137 abort:
1138 if (esw->work_queue)
1139 destroy_workqueue(esw->work_queue);
1140 kfree(esw->l2_table.bitmap);
1141 kfree(esw->vports);
1142 kfree(esw);
1143 return err;
1144 }
1145
mlx5_eswitch_cleanup(struct mlx5_eswitch * esw)1146 void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw)
1147 {
1148 if (!esw || !MLX5_CAP_GEN(esw->dev, vport_group_manager) ||
1149 MLX5_CAP_GEN(esw->dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
1150 return;
1151
1152 esw_info(esw->dev, "cleanup\n");
1153 esw_disable_vport(esw, 0);
1154
1155 esw->dev->priv.eswitch = NULL;
1156 destroy_workqueue(esw->work_queue);
1157 kfree(esw->l2_table.bitmap);
1158 kfree(esw->vports);
1159 kfree(esw);
1160 }
1161
mlx5_eswitch_vport_event(struct mlx5_eswitch * esw,struct mlx5_eqe * eqe)1162 void mlx5_eswitch_vport_event(struct mlx5_eswitch *esw, struct mlx5_eqe *eqe)
1163 {
1164 struct mlx5_eqe_vport_change *vc_eqe = &eqe->data.vport_change;
1165 u16 vport_num = be16_to_cpu(vc_eqe->vport_num);
1166 struct mlx5_vport *vport;
1167
1168 if (!esw) {
1169 printf("mlx5_core: WARN: ""MLX5 E-Switch: vport %d got an event while eswitch is not initialized\n", vport_num);
1170 return;
1171 }
1172
1173 vport = &esw->vports[vport_num];
1174 spin_lock(&vport->lock);
1175 if (vport->enabled)
1176 queue_work(esw->work_queue, &vport->vport_change_handler);
1177 spin_unlock(&vport->lock);
1178 }
1179
1180 /* Vport Administration */
1181 #define ESW_ALLOWED(esw) \
1182 (esw && MLX5_CAP_GEN(esw->dev, vport_group_manager) && mlx5_core_is_pf(esw->dev))
1183 #define LEGAL_VPORT(esw, vport) (vport >= 0 && vport < esw->total_vports)
1184
node_guid_gen_from_mac(u64 * node_guid,u8 mac[ETH_ALEN])1185 static void node_guid_gen_from_mac(u64 *node_guid, u8 mac[ETH_ALEN])
1186 {
1187 ((u8 *)node_guid)[7] = mac[0];
1188 ((u8 *)node_guid)[6] = mac[1];
1189 ((u8 *)node_guid)[5] = mac[2];
1190 ((u8 *)node_guid)[4] = 0xff;
1191 ((u8 *)node_guid)[3] = 0xfe;
1192 ((u8 *)node_guid)[2] = mac[3];
1193 ((u8 *)node_guid)[1] = mac[4];
1194 ((u8 *)node_guid)[0] = mac[5];
1195 }
1196
mlx5_eswitch_set_vport_mac(struct mlx5_eswitch * esw,int vport,u8 mac[ETH_ALEN])1197 int mlx5_eswitch_set_vport_mac(struct mlx5_eswitch *esw,
1198 int vport, u8 mac[ETH_ALEN])
1199 {
1200 int err = 0;
1201 u64 node_guid;
1202
1203 if (!ESW_ALLOWED(esw))
1204 return -EPERM;
1205 if (!LEGAL_VPORT(esw, vport))
1206 return -EINVAL;
1207
1208 err = mlx5_modify_nic_vport_mac_address(esw->dev, vport, mac);
1209 if (err) {
1210 mlx5_core_warn(esw->dev,
1211 "Failed to mlx5_modify_nic_vport_mac vport(%d) err=(%d)\n",
1212 vport, err);
1213 return err;
1214 }
1215
1216 node_guid_gen_from_mac(&node_guid, mac);
1217 err = mlx5_modify_nic_vport_node_guid(esw->dev, vport, node_guid);
1218 if (err) {
1219 mlx5_core_warn(esw->dev,
1220 "Failed to mlx5_modify_nic_vport_node_guid vport(%d) err=(%d)\n",
1221 vport, err);
1222 return err;
1223 }
1224
1225 return err;
1226 }
1227
mlx5_eswitch_set_vport_state(struct mlx5_eswitch * esw,int vport,int link_state)1228 int mlx5_eswitch_set_vport_state(struct mlx5_eswitch *esw,
1229 int vport, int link_state)
1230 {
1231 if (!ESW_ALLOWED(esw))
1232 return -EPERM;
1233 if (!LEGAL_VPORT(esw, vport))
1234 return -EINVAL;
1235
1236 return mlx5_modify_vport_admin_state(esw->dev,
1237 MLX5_QUERY_VPORT_STATE_IN_OP_MOD_ESW_VPORT,
1238 vport, link_state);
1239 }
1240
mlx5_eswitch_get_vport_config(struct mlx5_eswitch * esw,int vport,struct mlx5_esw_vport_info * ivi)1241 int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,
1242 int vport, struct mlx5_esw_vport_info *ivi)
1243 {
1244 u16 vlan;
1245 u8 qos;
1246
1247 if (!ESW_ALLOWED(esw))
1248 return -EPERM;
1249 if (!LEGAL_VPORT(esw, vport))
1250 return -EINVAL;
1251
1252 memset(ivi, 0, sizeof(*ivi));
1253 ivi->vf = vport - 1;
1254
1255 mlx5_query_nic_vport_mac_address(esw->dev, vport, ivi->mac);
1256 ivi->linkstate = mlx5_query_vport_admin_state(esw->dev,
1257 MLX5_QUERY_VPORT_STATE_IN_OP_MOD_ESW_VPORT,
1258 vport);
1259 query_esw_vport_cvlan(esw->dev, vport, &vlan, &qos);
1260 ivi->vlan = vlan;
1261 ivi->qos = qos;
1262 ivi->spoofchk = 0;
1263
1264 return 0;
1265 }
1266
mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch * esw,int vport,u16 vlan,u8 qos)1267 int mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw,
1268 int vport, u16 vlan, u8 qos)
1269 {
1270 struct mlx5_vport *evport;
1271 int err = 0;
1272 int set = 0;
1273
1274 if (!ESW_ALLOWED(esw))
1275 return -EPERM;
1276 if (!LEGAL_VPORT(esw, vport) || (vlan > 4095) || (qos > 7))
1277 return -EINVAL;
1278
1279 if (vlan || qos)
1280 set = 1;
1281
1282 evport = &esw->vports[vport];
1283
1284 err = modify_esw_vport_cvlan(esw->dev, vport, vlan, qos, set);
1285 if (err)
1286 return err;
1287
1288 mutex_lock(&evport->state_lock);
1289 evport->vlan = vlan;
1290 evport->qos = qos;
1291 if (evport->enabled) {
1292 esw_vport_ingress_config(esw, evport);
1293 esw_vport_egress_config(esw, evport);
1294 }
1295 mutex_unlock(&evport->state_lock);
1296 return err;
1297 }
1298
1299