2 * Copyright (c) 2016, Mellanox Technologies. All rights reserved.
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * OpenIB.org BSD license below:
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33 #include <linux/etherdevice.h>
34 #include <linux/mlx5/driver.h>
35 #include <linux/mlx5/mlx5_ifc.h>
36 #include <linux/mlx5/vport.h>
37 #include <linux/mlx5/fs.h>
38 #include "mlx5_core.h"
46 struct mlx5_flow_handle *
47 mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
48 struct mlx5_flow_spec *spec,
49 struct mlx5_esw_flow_attr *attr)
51 struct mlx5_flow_destination dest[MLX5_MAX_FLOW_FWD_VPORTS + 1] = {};
52 struct mlx5_flow_act flow_act = {0};
53 struct mlx5_fc *counter = NULL;
54 struct mlx5_flow_handle *rule;
58 if (esw->mode != SRIOV_OFFLOADS)
59 return ERR_PTR(-EOPNOTSUPP);
61 flow_act.action = attr->action;
62 /* if per flow vlan pop/push is emulated, don't set that into the firmware */
63 if (!mlx5_eswitch_vlan_actions_supported(esw->dev))
64 flow_act.action &= ~(MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH |
65 MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
66 else if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH) {
67 flow_act.vlan.ethtype = ntohs(attr->vlan_proto);
68 flow_act.vlan.vid = attr->vlan_vid;
69 flow_act.vlan.prio = attr->vlan_prio;
72 if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
73 for (j = attr->mirror_count; j < attr->out_count; j++) {
74 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
75 dest[i].vport.num = attr->out_rep[j]->vport;
76 if (MLX5_CAP_ESW(esw->dev, merged_eswitch)) {
77 dest[i].vport.vhca_id =
78 MLX5_CAP_GEN(attr->out_mdev[j], vhca_id);
79 dest[i].vport.vhca_id_valid = 1;
84 if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
85 counter = mlx5_fc_create(esw->dev, true);
86 if (IS_ERR(counter)) {
87 rule = ERR_CAST(counter);
88 goto err_counter_alloc;
90 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
91 dest[i].counter = counter;
95 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
96 MLX5_SET(fte_match_set_misc, misc, source_port, attr->in_rep->vport);
98 if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
99 MLX5_SET(fte_match_set_misc, misc,
100 source_eswitch_owner_vhca_id,
101 MLX5_CAP_GEN(attr->in_mdev, vhca_id));
103 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
104 MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
105 if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
106 MLX5_SET_TO_ONES(fte_match_set_misc, misc,
107 source_eswitch_owner_vhca_id);
109 if (attr->match_level == MLX5_MATCH_NONE)
110 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
112 spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS |
113 MLX5_MATCH_MISC_PARAMETERS;
115 if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_DECAP)
116 spec->match_criteria_enable |= MLX5_MATCH_INNER_HEADERS;
118 if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
119 flow_act.modify_id = attr->mod_hdr_id;
121 if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_ENCAP)
122 flow_act.encap_id = attr->encap_id;
124 rule = mlx5_add_flow_rules((struct mlx5_flow_table *)esw->fdb_table.offloads.fast_fdb,
125 spec, &flow_act, dest, i);
129 esw->offloads.num_flows++;
134 mlx5_fc_destroy(esw->dev, counter);
140 mlx5_eswitch_del_offloaded_rule(struct mlx5_eswitch *esw,
141 struct mlx5_flow_handle *rule,
142 struct mlx5_esw_flow_attr *attr)
144 struct mlx5_fc *counter = NULL;
146 counter = mlx5_flow_rule_counter(rule);
147 mlx5_del_flow_rules(rule);
148 mlx5_fc_destroy(esw->dev, counter);
149 esw->offloads.num_flows--;
152 static int esw_set_global_vlan_pop(struct mlx5_eswitch *esw, u8 val)
154 struct mlx5_eswitch_rep *rep;
155 int vf_vport, err = 0;
157 esw_debug(esw->dev, "%s applying global %s policy\n", __func__, val ? "pop" : "none");
158 for (vf_vport = 1; vf_vport < esw->enabled_vports; vf_vport++) {
159 rep = &esw->offloads.vport_reps[vf_vport];
160 if (!rep->rep_if[REP_ETH].valid)
163 err = __mlx5_eswitch_set_vport_vlan(esw, rep->vport, 0, 0, val);
172 static struct mlx5_eswitch_rep *
173 esw_vlan_action_get_vport(struct mlx5_esw_flow_attr *attr, bool push, bool pop)
175 struct mlx5_eswitch_rep *in_rep, *out_rep, *vport = NULL;
177 in_rep = attr->in_rep;
178 out_rep = attr->out_rep[0];
190 static int esw_add_vlan_action_check(struct mlx5_esw_flow_attr *attr,
191 bool push, bool pop, bool fwd)
193 struct mlx5_eswitch_rep *in_rep, *out_rep;
195 if ((push || pop) && !fwd)
198 in_rep = attr->in_rep;
199 out_rep = attr->out_rep[0];
201 if (push && in_rep->vport == FDB_UPLINK_VPORT)
204 if (pop && out_rep->vport == FDB_UPLINK_VPORT)
207 /* vport has vlan push configured, can't offload VF --> wire rules w.o it */
208 if (!push && !pop && fwd)
209 if (in_rep->vlan && out_rep->vport == FDB_UPLINK_VPORT)
212 /* protects against (1) setting rules with different vlans to push and
213 * (2) setting rules w.o vlans (attr->vlan = 0) && w. vlans to push (!= 0)
215 if (push && in_rep->vlan_refcount && (in_rep->vlan != attr->vlan_vid))
224 int mlx5_eswitch_add_vlan_action(struct mlx5_eswitch *esw,
225 struct mlx5_esw_flow_attr *attr)
227 struct offloads_fdb *offloads = &esw->fdb_table.offloads;
228 struct mlx5_eswitch_rep *vport = NULL;
232 /* nop if we're on the vlan push/pop non emulation mode */
233 if (mlx5_eswitch_vlan_actions_supported(esw->dev))
236 push = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH);
237 pop = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
238 fwd = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST);
240 err = esw_add_vlan_action_check(attr, push, pop, fwd);
244 attr->vlan_handled = false;
246 vport = esw_vlan_action_get_vport(attr, push, pop);
248 if (!push && !pop && fwd) {
249 /* tracks VF --> wire rules without vlan push action */
250 if (attr->out_rep[0]->vport == FDB_UPLINK_VPORT) {
251 vport->vlan_refcount++;
252 attr->vlan_handled = true;
261 if (!(offloads->vlan_push_pop_refcount)) {
262 /* it's the 1st vlan rule, apply global vlan pop policy */
263 err = esw_set_global_vlan_pop(esw, SET_VLAN_STRIP);
267 offloads->vlan_push_pop_refcount++;
270 if (vport->vlan_refcount)
273 err = __mlx5_eswitch_set_vport_vlan(esw, vport->vport, attr->vlan_vid, 0,
274 SET_VLAN_INSERT | SET_VLAN_STRIP);
277 vport->vlan = attr->vlan_vid;
279 vport->vlan_refcount++;
283 attr->vlan_handled = true;
287 int mlx5_eswitch_del_vlan_action(struct mlx5_eswitch *esw,
288 struct mlx5_esw_flow_attr *attr)
290 struct offloads_fdb *offloads = &esw->fdb_table.offloads;
291 struct mlx5_eswitch_rep *vport = NULL;
295 /* nop if we're on the vlan push/pop non emulation mode */
296 if (mlx5_eswitch_vlan_actions_supported(esw->dev))
299 if (!attr->vlan_handled)
302 push = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH);
303 pop = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
304 fwd = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST);
306 vport = esw_vlan_action_get_vport(attr, push, pop);
308 if (!push && !pop && fwd) {
309 /* tracks VF --> wire rules without vlan push action */
310 if (attr->out_rep[0]->vport == FDB_UPLINK_VPORT)
311 vport->vlan_refcount--;
317 vport->vlan_refcount--;
318 if (vport->vlan_refcount)
319 goto skip_unset_push;
322 err = __mlx5_eswitch_set_vport_vlan(esw, vport->vport,
323 0, 0, SET_VLAN_STRIP);
329 offloads->vlan_push_pop_refcount--;
330 if (offloads->vlan_push_pop_refcount)
333 /* no more vlan rules, stop global vlan pop policy */
334 err = esw_set_global_vlan_pop(esw, 0);
340 struct mlx5_flow_handle *
341 mlx5_eswitch_add_send_to_vport_rule(struct mlx5_eswitch *esw, int vport, u32 sqn)
343 struct mlx5_flow_act flow_act = {0};
344 struct mlx5_flow_destination dest = {};
345 struct mlx5_flow_handle *flow_rule;
346 struct mlx5_flow_spec *spec;
349 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
351 flow_rule = ERR_PTR(-ENOMEM);
355 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
356 MLX5_SET(fte_match_set_misc, misc, source_sqn, sqn);
357 MLX5_SET(fte_match_set_misc, misc, source_port, 0x0); /* source vport is 0 */
359 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
360 MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_sqn);
361 MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
363 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
364 dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
365 dest.vport.num = vport;
366 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
368 flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb, spec,
369 &flow_act, &dest, 1);
370 if (IS_ERR(flow_rule))
371 esw_warn(esw->dev, "FDB: Failed to add send to vport rule err %ld\n", PTR_ERR(flow_rule));
376 EXPORT_SYMBOL(mlx5_eswitch_add_send_to_vport_rule);
378 void mlx5_eswitch_del_send_to_vport_rule(struct mlx5_flow_handle *rule)
380 mlx5_del_flow_rules(rule);
383 static int esw_add_fdb_miss_rule(struct mlx5_eswitch *esw)
385 struct mlx5_flow_act flow_act = {0};
386 struct mlx5_flow_destination dest = {};
387 struct mlx5_flow_handle *flow_rule = NULL;
388 struct mlx5_flow_spec *spec;
395 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
401 spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
402 headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
404 dmac_c = MLX5_ADDR_OF(fte_match_param, headers_c,
405 outer_headers.dmac_47_16);
408 dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
410 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
412 flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb, spec,
413 &flow_act, &dest, 1);
414 if (IS_ERR(flow_rule)) {
415 err = PTR_ERR(flow_rule);
416 esw_warn(esw->dev, "FDB: Failed to add unicast miss flow rule err %d\n", err);
420 esw->fdb_table.offloads.miss_rule_uni = flow_rule;
422 headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
424 dmac_v = MLX5_ADDR_OF(fte_match_param, headers_v,
425 outer_headers.dmac_47_16);
427 flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb, spec,
428 &flow_act, &dest, 1);
429 if (IS_ERR(flow_rule)) {
430 err = PTR_ERR(flow_rule);
431 esw_warn(esw->dev, "FDB: Failed to add multicast miss flow rule err %d\n", err);
432 mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_uni);
436 esw->fdb_table.offloads.miss_rule_multi = flow_rule;
443 #define ESW_OFFLOADS_NUM_GROUPS 4
445 static int esw_create_offloads_fast_fdb_table(struct mlx5_eswitch *esw)
447 struct mlx5_core_dev *dev = esw->dev;
448 struct mlx5_flow_namespace *root_ns;
449 struct mlx5_flow_table *fdb = NULL;
450 int esw_size, err = 0;
452 u32 max_flow_counter = (MLX5_CAP_GEN(dev, max_flow_counter_31_16) << 16) |
453 MLX5_CAP_GEN(dev, max_flow_counter_15_0);
455 root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
457 esw_warn(dev, "Failed to get FDB flow namespace\n");
462 esw_debug(dev, "Create offloads FDB table, min (max esw size(2^%d), max counters(%d)*groups(%d))\n",
463 MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size),
464 max_flow_counter, ESW_OFFLOADS_NUM_GROUPS);
466 esw_size = min_t(int, max_flow_counter * ESW_OFFLOADS_NUM_GROUPS,
467 1 << MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size));
469 if (mlx5_esw_has_fwd_fdb(dev))
472 if (esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE)
473 flags |= MLX5_FLOW_TABLE_TUNNEL_EN;
475 fdb = mlx5_create_auto_grouped_flow_table(root_ns, FDB_FAST_PATH,
477 ESW_OFFLOADS_NUM_GROUPS, 0,
481 esw_warn(dev, "Failed to create Fast path FDB Table err %d\n", err);
484 esw->fdb_table.offloads.fast_fdb = fdb;
486 if (!mlx5_esw_has_fwd_fdb(dev))
489 fdb = mlx5_create_auto_grouped_flow_table(root_ns, FDB_FAST_PATH,
491 ESW_OFFLOADS_NUM_GROUPS, 1,
495 esw_warn(dev, "Failed to create fwd table err %d\n", err);
498 esw->fdb_table.offloads.fwd_fdb = fdb;
503 mlx5_destroy_flow_table(esw->fdb_table.offloads.fast_fdb);
508 static void esw_destroy_offloads_fast_fdb_table(struct mlx5_eswitch *esw)
510 if (mlx5_esw_has_fwd_fdb(esw->dev))
511 mlx5_destroy_flow_table(esw->fdb_table.offloads.fwd_fdb);
512 mlx5_destroy_flow_table(esw->fdb_table.offloads.fast_fdb);
515 #define MAX_PF_SQ 256
516 #define MAX_SQ_NVPORTS 32
518 static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw, int nvports)
520 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
521 struct mlx5_flow_table_attr ft_attr = {};
522 struct mlx5_core_dev *dev = esw->dev;
523 struct mlx5_flow_namespace *root_ns;
524 struct mlx5_flow_table *fdb = NULL;
525 int table_size, ix, err = 0;
526 struct mlx5_flow_group *g;
527 void *match_criteria;
531 esw_debug(esw->dev, "Create offloads FDB Tables\n");
532 flow_group_in = kvzalloc(inlen, GFP_KERNEL);
536 root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
538 esw_warn(dev, "Failed to get FDB flow namespace\n");
543 err = esw_create_offloads_fast_fdb_table(esw);
547 table_size = nvports * MAX_SQ_NVPORTS + MAX_PF_SQ + 2;
549 ft_attr.max_fte = table_size;
550 ft_attr.prio = FDB_SLOW_PATH;
552 fdb = mlx5_create_flow_table(root_ns, &ft_attr);
555 esw_warn(dev, "Failed to create slow path FDB Table err %d\n", err);
558 esw->fdb_table.offloads.slow_fdb = fdb;
560 /* create send-to-vport group */
561 memset(flow_group_in, 0, inlen);
562 MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
563 MLX5_MATCH_MISC_PARAMETERS);
565 match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
567 MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_sqn);
568 MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_port);
570 ix = nvports * MAX_SQ_NVPORTS + MAX_PF_SQ;
571 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
572 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, ix - 1);
574 g = mlx5_create_flow_group(fdb, flow_group_in);
577 esw_warn(dev, "Failed to create send-to-vport flow group err(%d)\n", err);
580 esw->fdb_table.offloads.send_to_vport_grp = g;
582 /* create miss group */
583 memset(flow_group_in, 0, inlen);
584 MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
585 MLX5_MATCH_OUTER_HEADERS);
586 match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in,
588 dmac = MLX5_ADDR_OF(fte_match_param, match_criteria,
589 outer_headers.dmac_47_16);
592 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ix);
593 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, ix + 2);
595 g = mlx5_create_flow_group(fdb, flow_group_in);
598 esw_warn(dev, "Failed to create miss flow group err(%d)\n", err);
601 esw->fdb_table.offloads.miss_grp = g;
603 err = esw_add_fdb_miss_rule(esw);
610 mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
612 mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
614 mlx5_destroy_flow_table(esw->fdb_table.offloads.slow_fdb);
616 esw_destroy_offloads_fast_fdb_table(esw);
619 kvfree(flow_group_in);
623 static void esw_destroy_offloads_fdb_tables(struct mlx5_eswitch *esw)
625 if (!esw->fdb_table.offloads.fast_fdb)
628 esw_debug(esw->dev, "Destroy offloads FDB Tables\n");
629 mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_multi);
630 mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_uni);
631 mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
632 mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
634 mlx5_destroy_flow_table(esw->fdb_table.offloads.slow_fdb);
635 esw_destroy_offloads_fast_fdb_table(esw);
638 static int esw_create_offloads_table(struct mlx5_eswitch *esw)
640 struct mlx5_flow_table_attr ft_attr = {};
641 struct mlx5_core_dev *dev = esw->dev;
642 struct mlx5_flow_table *ft_offloads;
643 struct mlx5_flow_namespace *ns;
646 ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_OFFLOADS);
648 esw_warn(esw->dev, "Failed to get offloads flow namespace\n");
652 ft_attr.max_fte = dev->priv.sriov.num_vfs + 2;
654 ft_offloads = mlx5_create_flow_table(ns, &ft_attr);
655 if (IS_ERR(ft_offloads)) {
656 err = PTR_ERR(ft_offloads);
657 esw_warn(esw->dev, "Failed to create offloads table, err %d\n", err);
661 esw->offloads.ft_offloads = ft_offloads;
665 static void esw_destroy_offloads_table(struct mlx5_eswitch *esw)
667 struct mlx5_esw_offload *offloads = &esw->offloads;
669 mlx5_destroy_flow_table(offloads->ft_offloads);
672 static int esw_create_vport_rx_group(struct mlx5_eswitch *esw)
674 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
675 struct mlx5_flow_group *g;
676 struct mlx5_priv *priv = &esw->dev->priv;
678 void *match_criteria, *misc;
680 int nvports = priv->sriov.num_vfs + 2;
682 flow_group_in = kvzalloc(inlen, GFP_KERNEL);
686 /* create vport rx group */
687 memset(flow_group_in, 0, inlen);
688 MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
689 MLX5_MATCH_MISC_PARAMETERS);
691 match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
692 misc = MLX5_ADDR_OF(fte_match_param, match_criteria, misc_parameters);
693 MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
695 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
696 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, nvports - 1);
698 g = mlx5_create_flow_group(esw->offloads.ft_offloads, flow_group_in);
702 mlx5_core_warn(esw->dev, "Failed to create vport rx group err %d\n", err);
706 esw->offloads.vport_rx_group = g;
708 kvfree(flow_group_in);
712 static void esw_destroy_vport_rx_group(struct mlx5_eswitch *esw)
714 mlx5_destroy_flow_group(esw->offloads.vport_rx_group);
717 struct mlx5_flow_handle *
718 mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, int vport, u32 tirn)
720 struct mlx5_flow_act flow_act = {0};
721 struct mlx5_flow_destination dest = {};
722 struct mlx5_flow_handle *flow_rule;
723 struct mlx5_flow_spec *spec;
726 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
728 flow_rule = ERR_PTR(-ENOMEM);
732 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
733 MLX5_SET(fte_match_set_misc, misc, source_port, vport);
735 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
736 MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
738 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
739 dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR;
742 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
743 flow_rule = mlx5_add_flow_rules(esw->offloads.ft_offloads, spec,
744 &flow_act, &dest, 1);
745 if (IS_ERR(flow_rule)) {
746 esw_warn(esw->dev, "fs offloads: Failed to add vport rx rule err %ld\n", PTR_ERR(flow_rule));
755 static int esw_offloads_start(struct mlx5_eswitch *esw)
757 int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs;
759 if (esw->mode != SRIOV_LEGACY) {
760 esw_warn(esw->dev, "Can't set offloads mode, SRIOV legacy not enabled\n");
764 mlx5_eswitch_disable_sriov(esw);
765 err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_OFFLOADS);
767 esw_warn(esw->dev, "Failed setting eswitch to offloads, err %d\n", err);
768 err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
770 esw_warn(esw->dev, "Failed setting eswitch back to legacy, err %d\n", err1);
772 if (esw->offloads.inline_mode == MLX5_INLINE_MODE_NONE) {
773 if (mlx5_eswitch_inline_mode_get(esw,
775 &esw->offloads.inline_mode)) {
776 esw->offloads.inline_mode = MLX5_INLINE_MODE_L2;
777 esw_warn(esw->dev, "Inline mode is different between vports\n");
783 void esw_offloads_cleanup_reps(struct mlx5_eswitch *esw)
785 kfree(esw->offloads.vport_reps);
788 int esw_offloads_init_reps(struct mlx5_eswitch *esw)
790 int total_vfs = MLX5_TOTAL_VPORTS(esw->dev);
791 struct mlx5_core_dev *dev = esw->dev;
792 struct mlx5_esw_offload *offloads;
793 struct mlx5_eswitch_rep *rep;
797 esw->offloads.vport_reps = kcalloc(total_vfs,
798 sizeof(struct mlx5_eswitch_rep),
800 if (!esw->offloads.vport_reps)
803 offloads = &esw->offloads;
804 mlx5_query_nic_vport_mac_address(dev, 0, hw_id);
806 for (vport = 0; vport < total_vfs; vport++) {
807 rep = &offloads->vport_reps[vport];
810 ether_addr_copy(rep->hw_id, hw_id);
813 offloads->vport_reps[0].vport = FDB_UPLINK_VPORT;
818 static void esw_offloads_unload_reps_type(struct mlx5_eswitch *esw, int nvports,
821 struct mlx5_eswitch_rep *rep;
824 for (vport = nvports - 1; vport >= 0; vport--) {
825 rep = &esw->offloads.vport_reps[vport];
826 if (!rep->rep_if[rep_type].valid)
829 rep->rep_if[rep_type].unload(rep);
833 static void esw_offloads_unload_reps(struct mlx5_eswitch *esw, int nvports)
835 u8 rep_type = NUM_REP_TYPES;
837 while (rep_type-- > 0)
838 esw_offloads_unload_reps_type(esw, nvports, rep_type);
841 static int esw_offloads_load_reps_type(struct mlx5_eswitch *esw, int nvports,
844 struct mlx5_eswitch_rep *rep;
848 for (vport = 0; vport < nvports; vport++) {
849 rep = &esw->offloads.vport_reps[vport];
850 if (!rep->rep_if[rep_type].valid)
853 err = rep->rep_if[rep_type].load(esw->dev, rep);
861 esw_offloads_unload_reps_type(esw, vport, rep_type);
865 static int esw_offloads_load_reps(struct mlx5_eswitch *esw, int nvports)
870 for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++) {
871 err = esw_offloads_load_reps_type(esw, nvports, rep_type);
879 while (rep_type-- > 0)
880 esw_offloads_unload_reps_type(esw, nvports, rep_type);
884 int esw_offloads_init(struct mlx5_eswitch *esw, int nvports)
888 err = esw_create_offloads_fdb_tables(esw, nvports);
892 err = esw_create_offloads_table(esw);
896 err = esw_create_vport_rx_group(esw);
900 err = esw_offloads_load_reps(esw, nvports);
907 esw_destroy_vport_rx_group(esw);
910 esw_destroy_offloads_table(esw);
913 esw_destroy_offloads_fdb_tables(esw);
918 static int esw_offloads_stop(struct mlx5_eswitch *esw)
920 int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs;
922 mlx5_eswitch_disable_sriov(esw);
923 err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
925 esw_warn(esw->dev, "Failed setting eswitch to legacy, err %d\n", err);
926 err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_OFFLOADS);
928 esw_warn(esw->dev, "Failed setting eswitch back to offloads, err %d\n", err);
931 /* enable back PF RoCE */
932 mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
937 void esw_offloads_cleanup(struct mlx5_eswitch *esw, int nvports)
939 esw_offloads_unload_reps(esw, nvports);
940 esw_destroy_vport_rx_group(esw);
941 esw_destroy_offloads_table(esw);
942 esw_destroy_offloads_fdb_tables(esw);
945 static int esw_mode_from_devlink(u16 mode, u16 *mlx5_mode)
948 case DEVLINK_ESWITCH_MODE_LEGACY:
949 *mlx5_mode = SRIOV_LEGACY;
951 case DEVLINK_ESWITCH_MODE_SWITCHDEV:
952 *mlx5_mode = SRIOV_OFFLOADS;
961 static int esw_mode_to_devlink(u16 mlx5_mode, u16 *mode)
965 *mode = DEVLINK_ESWITCH_MODE_LEGACY;
968 *mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
977 static int esw_inline_mode_from_devlink(u8 mode, u8 *mlx5_mode)
980 case DEVLINK_ESWITCH_INLINE_MODE_NONE:
981 *mlx5_mode = MLX5_INLINE_MODE_NONE;
983 case DEVLINK_ESWITCH_INLINE_MODE_LINK:
984 *mlx5_mode = MLX5_INLINE_MODE_L2;
986 case DEVLINK_ESWITCH_INLINE_MODE_NETWORK:
987 *mlx5_mode = MLX5_INLINE_MODE_IP;
989 case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT:
990 *mlx5_mode = MLX5_INLINE_MODE_TCP_UDP;
999 static int esw_inline_mode_to_devlink(u8 mlx5_mode, u8 *mode)
1001 switch (mlx5_mode) {
1002 case MLX5_INLINE_MODE_NONE:
1003 *mode = DEVLINK_ESWITCH_INLINE_MODE_NONE;
1005 case MLX5_INLINE_MODE_L2:
1006 *mode = DEVLINK_ESWITCH_INLINE_MODE_LINK;
1008 case MLX5_INLINE_MODE_IP:
1009 *mode = DEVLINK_ESWITCH_INLINE_MODE_NETWORK;
1011 case MLX5_INLINE_MODE_TCP_UDP:
1012 *mode = DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT;
1021 static int mlx5_devlink_eswitch_check(struct devlink *devlink)
1023 struct mlx5_core_dev *dev = devlink_priv(devlink);
1025 if (MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
1028 if (!MLX5_CAP_GEN(dev, vport_group_manager))
1031 if (dev->priv.eswitch->mode == SRIOV_NONE)
1037 int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode)
1039 struct mlx5_core_dev *dev = devlink_priv(devlink);
1040 u16 cur_mlx5_mode, mlx5_mode = 0;
1043 err = mlx5_devlink_eswitch_check(devlink);
1047 cur_mlx5_mode = dev->priv.eswitch->mode;
1049 if (esw_mode_from_devlink(mode, &mlx5_mode))
1052 if (cur_mlx5_mode == mlx5_mode)
1055 if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV)
1056 return esw_offloads_start(dev->priv.eswitch);
1057 else if (mode == DEVLINK_ESWITCH_MODE_LEGACY)
1058 return esw_offloads_stop(dev->priv.eswitch);
1063 int mlx5_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
1065 struct mlx5_core_dev *dev = devlink_priv(devlink);
1068 err = mlx5_devlink_eswitch_check(devlink);
1072 return esw_mode_to_devlink(dev->priv.eswitch->mode, mode);
1075 int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode)
1077 struct mlx5_core_dev *dev = devlink_priv(devlink);
1078 struct mlx5_eswitch *esw = dev->priv.eswitch;
1082 err = mlx5_devlink_eswitch_check(devlink);
1086 switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
1087 case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
1088 if (mode == DEVLINK_ESWITCH_INLINE_MODE_NONE)
1091 case MLX5_CAP_INLINE_MODE_L2:
1092 esw_warn(dev, "Inline mode can't be set\n");
1094 case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
1098 if (esw->offloads.num_flows > 0) {
1099 esw_warn(dev, "Can't set inline mode when flows are configured\n");
1103 err = esw_inline_mode_from_devlink(mode, &mlx5_mode);
1107 for (vport = 1; vport < esw->enabled_vports; vport++) {
1108 err = mlx5_modify_nic_vport_min_inline(dev, vport, mlx5_mode);
1110 esw_warn(dev, "Failed to set min inline on vport %d\n",
1112 goto revert_inline_mode;
1116 esw->offloads.inline_mode = mlx5_mode;
1121 mlx5_modify_nic_vport_min_inline(dev,
1123 esw->offloads.inline_mode);
1128 int mlx5_devlink_eswitch_inline_mode_get(struct devlink *devlink, u8 *mode)
1130 struct mlx5_core_dev *dev = devlink_priv(devlink);
1131 struct mlx5_eswitch *esw = dev->priv.eswitch;
1134 err = mlx5_devlink_eswitch_check(devlink);
1138 return esw_inline_mode_to_devlink(esw->offloads.inline_mode, mode);
1141 int mlx5_eswitch_inline_mode_get(struct mlx5_eswitch *esw, int nvfs, u8 *mode)
1143 u8 prev_mlx5_mode, mlx5_mode = MLX5_INLINE_MODE_L2;
1144 struct mlx5_core_dev *dev = esw->dev;
1147 if (!MLX5_CAP_GEN(dev, vport_group_manager))
1150 if (esw->mode == SRIOV_NONE)
1153 switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
1154 case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
1155 mlx5_mode = MLX5_INLINE_MODE_NONE;
1157 case MLX5_CAP_INLINE_MODE_L2:
1158 mlx5_mode = MLX5_INLINE_MODE_L2;
1160 case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
1165 for (vport = 1; vport <= nvfs; vport++) {
1166 mlx5_query_nic_vport_min_inline(dev, vport, &mlx5_mode);
1167 if (vport > 1 && prev_mlx5_mode != mlx5_mode)
1169 prev_mlx5_mode = mlx5_mode;
1177 int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap)
1179 struct mlx5_core_dev *dev = devlink_priv(devlink);
1180 struct mlx5_eswitch *esw = dev->priv.eswitch;
1183 err = mlx5_devlink_eswitch_check(devlink);
1187 if (encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE &&
1188 (!MLX5_CAP_ESW_FLOWTABLE_FDB(dev, encap) ||
1189 !MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap)))
1192 if (encap && encap != DEVLINK_ESWITCH_ENCAP_MODE_BASIC)
1195 if (esw->mode == SRIOV_LEGACY) {
1196 esw->offloads.encap = encap;
1200 if (esw->offloads.encap == encap)
1203 if (esw->offloads.num_flows > 0) {
1204 esw_warn(dev, "Can't set encapsulation when flows are configured\n");
1208 esw_destroy_offloads_fast_fdb_table(esw);
1210 esw->offloads.encap = encap;
1211 err = esw_create_offloads_fast_fdb_table(esw);
1213 esw_warn(esw->dev, "Failed re-creating fast FDB table, err %d\n", err);
1214 esw->offloads.encap = !encap;
1215 (void)esw_create_offloads_fast_fdb_table(esw);
1220 int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink, u8 *encap)
1222 struct mlx5_core_dev *dev = devlink_priv(devlink);
1223 struct mlx5_eswitch *esw = dev->priv.eswitch;
1226 err = mlx5_devlink_eswitch_check(devlink);
1230 *encap = esw->offloads.encap;
1234 void mlx5_eswitch_register_vport_rep(struct mlx5_eswitch *esw,
1236 struct mlx5_eswitch_rep_if *__rep_if,
1239 struct mlx5_esw_offload *offloads = &esw->offloads;
1240 struct mlx5_eswitch_rep_if *rep_if;
1242 rep_if = &offloads->vport_reps[vport_index].rep_if[rep_type];
1244 rep_if->load = __rep_if->load;
1245 rep_if->unload = __rep_if->unload;
1246 rep_if->get_proto_dev = __rep_if->get_proto_dev;
1247 rep_if->priv = __rep_if->priv;
1249 rep_if->valid = true;
1251 EXPORT_SYMBOL(mlx5_eswitch_register_vport_rep);
1253 void mlx5_eswitch_unregister_vport_rep(struct mlx5_eswitch *esw,
1254 int vport_index, u8 rep_type)
1256 struct mlx5_esw_offload *offloads = &esw->offloads;
1257 struct mlx5_eswitch_rep *rep;
1259 rep = &offloads->vport_reps[vport_index];
1261 if (esw->mode == SRIOV_OFFLOADS && esw->vports[vport_index].enabled)
1262 rep->rep_if[rep_type].unload(rep);
1264 rep->rep_if[rep_type].valid = false;
1266 EXPORT_SYMBOL(mlx5_eswitch_unregister_vport_rep);
1268 void *mlx5_eswitch_get_uplink_priv(struct mlx5_eswitch *esw, u8 rep_type)
1270 #define UPLINK_REP_INDEX 0
1271 struct mlx5_esw_offload *offloads = &esw->offloads;
1272 struct mlx5_eswitch_rep *rep;
1274 rep = &offloads->vport_reps[UPLINK_REP_INDEX];
1275 return rep->rep_if[rep_type].priv;
1278 void *mlx5_eswitch_get_proto_dev(struct mlx5_eswitch *esw,
1282 struct mlx5_esw_offload *offloads = &esw->offloads;
1283 struct mlx5_eswitch_rep *rep;
1285 if (vport == FDB_UPLINK_VPORT)
1286 vport = UPLINK_REP_INDEX;
1288 rep = &offloads->vport_reps[vport];
1290 if (rep->rep_if[rep_type].valid &&
1291 rep->rep_if[rep_type].get_proto_dev)
1292 return rep->rep_if[rep_type].get_proto_dev(rep);
1295 EXPORT_SYMBOL(mlx5_eswitch_get_proto_dev);
1297 void *mlx5_eswitch_uplink_get_proto_dev(struct mlx5_eswitch *esw, u8 rep_type)
1299 return mlx5_eswitch_get_proto_dev(esw, UPLINK_REP_INDEX, rep_type);
1301 EXPORT_SYMBOL(mlx5_eswitch_uplink_get_proto_dev);
1303 struct mlx5_eswitch_rep *mlx5_eswitch_vport_rep(struct mlx5_eswitch *esw,
1306 return &esw->offloads.vport_reps[vport];
1308 EXPORT_SYMBOL(mlx5_eswitch_vport_rep);