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[2] = {};
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 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
74 dest[i].vport_num = attr->out_rep->vport;
77 if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
78 counter = mlx5_fc_create(esw->dev, true);
79 if (IS_ERR(counter)) {
80 rule = ERR_CAST(counter);
81 goto err_counter_alloc;
83 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
84 dest[i].counter = counter;
88 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
89 MLX5_SET(fte_match_set_misc, misc, source_port, attr->in_rep->vport);
91 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
92 MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
94 if (attr->match_level == MLX5_MATCH_NONE)
95 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
97 spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS |
98 MLX5_MATCH_MISC_PARAMETERS;
100 if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_DECAP)
101 spec->match_criteria_enable |= MLX5_MATCH_INNER_HEADERS;
103 if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
104 flow_act.modify_id = attr->mod_hdr_id;
106 if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_ENCAP)
107 flow_act.encap_id = attr->encap_id;
109 rule = mlx5_add_flow_rules((struct mlx5_flow_table *)esw->fdb_table.fdb,
110 spec, &flow_act, dest, i);
114 esw->offloads.num_flows++;
119 mlx5_fc_destroy(esw->dev, counter);
125 mlx5_eswitch_del_offloaded_rule(struct mlx5_eswitch *esw,
126 struct mlx5_flow_handle *rule,
127 struct mlx5_esw_flow_attr *attr)
129 struct mlx5_fc *counter = NULL;
131 counter = mlx5_flow_rule_counter(rule);
132 mlx5_del_flow_rules(rule);
133 mlx5_fc_destroy(esw->dev, counter);
134 esw->offloads.num_flows--;
137 static int esw_set_global_vlan_pop(struct mlx5_eswitch *esw, u8 val)
139 struct mlx5_eswitch_rep *rep;
140 int vf_vport, err = 0;
142 esw_debug(esw->dev, "%s applying global %s policy\n", __func__, val ? "pop" : "none");
143 for (vf_vport = 1; vf_vport < esw->enabled_vports; vf_vport++) {
144 rep = &esw->offloads.vport_reps[vf_vport];
145 if (!rep->rep_if[REP_ETH].valid)
148 err = __mlx5_eswitch_set_vport_vlan(esw, rep->vport, 0, 0, val);
157 static struct mlx5_eswitch_rep *
158 esw_vlan_action_get_vport(struct mlx5_esw_flow_attr *attr, bool push, bool pop)
160 struct mlx5_eswitch_rep *in_rep, *out_rep, *vport = NULL;
162 in_rep = attr->in_rep;
163 out_rep = attr->out_rep;
175 static int esw_add_vlan_action_check(struct mlx5_esw_flow_attr *attr,
176 bool push, bool pop, bool fwd)
178 struct mlx5_eswitch_rep *in_rep, *out_rep;
180 if ((push || pop) && !fwd)
183 in_rep = attr->in_rep;
184 out_rep = attr->out_rep;
186 if (push && in_rep->vport == FDB_UPLINK_VPORT)
189 if (pop && out_rep->vport == FDB_UPLINK_VPORT)
192 /* vport has vlan push configured, can't offload VF --> wire rules w.o it */
193 if (!push && !pop && fwd)
194 if (in_rep->vlan && out_rep->vport == FDB_UPLINK_VPORT)
197 /* protects against (1) setting rules with different vlans to push and
198 * (2) setting rules w.o vlans (attr->vlan = 0) && w. vlans to push (!= 0)
200 if (push && in_rep->vlan_refcount && (in_rep->vlan != attr->vlan_vid))
209 int mlx5_eswitch_add_vlan_action(struct mlx5_eswitch *esw,
210 struct mlx5_esw_flow_attr *attr)
212 struct offloads_fdb *offloads = &esw->fdb_table.offloads;
213 struct mlx5_eswitch_rep *vport = NULL;
217 /* nop if we're on the vlan push/pop non emulation mode */
218 if (mlx5_eswitch_vlan_actions_supported(esw->dev))
221 push = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH);
222 pop = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
223 fwd = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST);
225 err = esw_add_vlan_action_check(attr, push, pop, fwd);
229 attr->vlan_handled = false;
231 vport = esw_vlan_action_get_vport(attr, push, pop);
233 if (!push && !pop && fwd) {
234 /* tracks VF --> wire rules without vlan push action */
235 if (attr->out_rep->vport == FDB_UPLINK_VPORT) {
236 vport->vlan_refcount++;
237 attr->vlan_handled = true;
246 if (!(offloads->vlan_push_pop_refcount)) {
247 /* it's the 1st vlan rule, apply global vlan pop policy */
248 err = esw_set_global_vlan_pop(esw, SET_VLAN_STRIP);
252 offloads->vlan_push_pop_refcount++;
255 if (vport->vlan_refcount)
258 err = __mlx5_eswitch_set_vport_vlan(esw, vport->vport, attr->vlan_vid, 0,
259 SET_VLAN_INSERT | SET_VLAN_STRIP);
262 vport->vlan = attr->vlan_vid;
264 vport->vlan_refcount++;
268 attr->vlan_handled = true;
272 int mlx5_eswitch_del_vlan_action(struct mlx5_eswitch *esw,
273 struct mlx5_esw_flow_attr *attr)
275 struct offloads_fdb *offloads = &esw->fdb_table.offloads;
276 struct mlx5_eswitch_rep *vport = NULL;
280 /* nop if we're on the vlan push/pop non emulation mode */
281 if (mlx5_eswitch_vlan_actions_supported(esw->dev))
284 if (!attr->vlan_handled)
287 push = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH);
288 pop = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
289 fwd = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST);
291 vport = esw_vlan_action_get_vport(attr, push, pop);
293 if (!push && !pop && fwd) {
294 /* tracks VF --> wire rules without vlan push action */
295 if (attr->out_rep->vport == FDB_UPLINK_VPORT)
296 vport->vlan_refcount--;
302 vport->vlan_refcount--;
303 if (vport->vlan_refcount)
304 goto skip_unset_push;
307 err = __mlx5_eswitch_set_vport_vlan(esw, vport->vport,
308 0, 0, SET_VLAN_STRIP);
314 offloads->vlan_push_pop_refcount--;
315 if (offloads->vlan_push_pop_refcount)
318 /* no more vlan rules, stop global vlan pop policy */
319 err = esw_set_global_vlan_pop(esw, 0);
325 struct mlx5_flow_handle *
326 mlx5_eswitch_add_send_to_vport_rule(struct mlx5_eswitch *esw, int vport, u32 sqn)
328 struct mlx5_flow_act flow_act = {0};
329 struct mlx5_flow_destination dest = {};
330 struct mlx5_flow_handle *flow_rule;
331 struct mlx5_flow_spec *spec;
334 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
336 flow_rule = ERR_PTR(-ENOMEM);
340 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
341 MLX5_SET(fte_match_set_misc, misc, source_sqn, sqn);
342 MLX5_SET(fte_match_set_misc, misc, source_port, 0x0); /* source vport is 0 */
344 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
345 MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_sqn);
346 MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
348 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
349 dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
350 dest.vport_num = vport;
351 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
353 flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.fdb, spec,
354 &flow_act, &dest, 1);
355 if (IS_ERR(flow_rule))
356 esw_warn(esw->dev, "FDB: Failed to add send to vport rule err %ld\n", PTR_ERR(flow_rule));
361 EXPORT_SYMBOL(mlx5_eswitch_add_send_to_vport_rule);
363 void mlx5_eswitch_del_send_to_vport_rule(struct mlx5_flow_handle *rule)
365 mlx5_del_flow_rules(rule);
368 static int esw_add_fdb_miss_rule(struct mlx5_eswitch *esw)
370 struct mlx5_flow_act flow_act = {0};
371 struct mlx5_flow_destination dest = {};
372 struct mlx5_flow_handle *flow_rule = NULL;
373 struct mlx5_flow_spec *spec;
380 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
386 spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
387 headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
389 dmac_c = MLX5_ADDR_OF(fte_match_param, headers_c,
390 outer_headers.dmac_47_16);
393 dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
395 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
397 flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.fdb, spec,
398 &flow_act, &dest, 1);
399 if (IS_ERR(flow_rule)) {
400 err = PTR_ERR(flow_rule);
401 esw_warn(esw->dev, "FDB: Failed to add unicast miss flow rule err %d\n", err);
405 esw->fdb_table.offloads.miss_rule_uni = flow_rule;
407 headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
409 dmac_v = MLX5_ADDR_OF(fte_match_param, headers_v,
410 outer_headers.dmac_47_16);
412 flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.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 multicast miss flow rule err %d\n", err);
417 mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_uni);
421 esw->fdb_table.offloads.miss_rule_multi = flow_rule;
428 #define ESW_OFFLOADS_NUM_GROUPS 4
430 static int esw_create_offloads_fast_fdb_table(struct mlx5_eswitch *esw)
432 struct mlx5_core_dev *dev = esw->dev;
433 struct mlx5_flow_namespace *root_ns;
434 struct mlx5_flow_table *fdb = NULL;
435 int esw_size, err = 0;
437 u32 max_flow_counter = (MLX5_CAP_GEN(dev, max_flow_counter_31_16) << 16) |
438 MLX5_CAP_GEN(dev, max_flow_counter_15_0);
440 root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
442 esw_warn(dev, "Failed to get FDB flow namespace\n");
447 esw_debug(dev, "Create offloads FDB table, min (max esw size(2^%d), max counters(%d)*groups(%d))\n",
448 MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size),
449 max_flow_counter, ESW_OFFLOADS_NUM_GROUPS);
451 esw_size = min_t(int, max_flow_counter * ESW_OFFLOADS_NUM_GROUPS,
452 1 << MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size));
454 if (esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE)
455 flags |= MLX5_FLOW_TABLE_TUNNEL_EN;
457 fdb = mlx5_create_auto_grouped_flow_table(root_ns, FDB_FAST_PATH,
459 ESW_OFFLOADS_NUM_GROUPS, 0,
463 esw_warn(dev, "Failed to create Fast path FDB Table err %d\n", err);
466 esw->fdb_table.fdb = fdb;
472 static void esw_destroy_offloads_fast_fdb_table(struct mlx5_eswitch *esw)
474 mlx5_destroy_flow_table(esw->fdb_table.fdb);
477 #define MAX_PF_SQ 256
478 #define MAX_SQ_NVPORTS 32
480 static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw, int nvports)
482 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
483 struct mlx5_flow_table_attr ft_attr = {};
484 struct mlx5_core_dev *dev = esw->dev;
485 struct mlx5_flow_namespace *root_ns;
486 struct mlx5_flow_table *fdb = NULL;
487 int table_size, ix, err = 0;
488 struct mlx5_flow_group *g;
489 void *match_criteria;
493 esw_debug(esw->dev, "Create offloads FDB Tables\n");
494 flow_group_in = kvzalloc(inlen, GFP_KERNEL);
498 root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
500 esw_warn(dev, "Failed to get FDB flow namespace\n");
505 err = esw_create_offloads_fast_fdb_table(esw);
509 table_size = nvports * MAX_SQ_NVPORTS + MAX_PF_SQ + 2;
511 ft_attr.max_fte = table_size;
512 ft_attr.prio = FDB_SLOW_PATH;
514 fdb = mlx5_create_flow_table(root_ns, &ft_attr);
517 esw_warn(dev, "Failed to create slow path FDB Table err %d\n", err);
520 esw->fdb_table.offloads.fdb = fdb;
522 /* create send-to-vport group */
523 memset(flow_group_in, 0, inlen);
524 MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
525 MLX5_MATCH_MISC_PARAMETERS);
527 match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
529 MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_sqn);
530 MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_port);
532 ix = nvports * MAX_SQ_NVPORTS + MAX_PF_SQ;
533 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
534 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, ix - 1);
536 g = mlx5_create_flow_group(fdb, flow_group_in);
539 esw_warn(dev, "Failed to create send-to-vport flow group err(%d)\n", err);
542 esw->fdb_table.offloads.send_to_vport_grp = g;
544 /* create miss group */
545 memset(flow_group_in, 0, inlen);
546 MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
547 MLX5_MATCH_OUTER_HEADERS);
548 match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in,
550 dmac = MLX5_ADDR_OF(fte_match_param, match_criteria,
551 outer_headers.dmac_47_16);
554 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ix);
555 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, ix + 2);
557 g = mlx5_create_flow_group(fdb, flow_group_in);
560 esw_warn(dev, "Failed to create miss flow group err(%d)\n", err);
563 esw->fdb_table.offloads.miss_grp = g;
565 err = esw_add_fdb_miss_rule(esw);
572 mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
574 mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
576 mlx5_destroy_flow_table(esw->fdb_table.offloads.fdb);
578 mlx5_destroy_flow_table(esw->fdb_table.fdb);
581 kvfree(flow_group_in);
585 static void esw_destroy_offloads_fdb_tables(struct mlx5_eswitch *esw)
587 if (!esw->fdb_table.fdb)
590 esw_debug(esw->dev, "Destroy offloads FDB Tables\n");
591 mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_multi);
592 mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_uni);
593 mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
594 mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
596 mlx5_destroy_flow_table(esw->fdb_table.offloads.fdb);
597 esw_destroy_offloads_fast_fdb_table(esw);
600 static int esw_create_offloads_table(struct mlx5_eswitch *esw)
602 struct mlx5_flow_table_attr ft_attr = {};
603 struct mlx5_core_dev *dev = esw->dev;
604 struct mlx5_flow_table *ft_offloads;
605 struct mlx5_flow_namespace *ns;
608 ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_OFFLOADS);
610 esw_warn(esw->dev, "Failed to get offloads flow namespace\n");
614 ft_attr.max_fte = dev->priv.sriov.num_vfs + 2;
616 ft_offloads = mlx5_create_flow_table(ns, &ft_attr);
617 if (IS_ERR(ft_offloads)) {
618 err = PTR_ERR(ft_offloads);
619 esw_warn(esw->dev, "Failed to create offloads table, err %d\n", err);
623 esw->offloads.ft_offloads = ft_offloads;
627 static void esw_destroy_offloads_table(struct mlx5_eswitch *esw)
629 struct mlx5_esw_offload *offloads = &esw->offloads;
631 mlx5_destroy_flow_table(offloads->ft_offloads);
634 static int esw_create_vport_rx_group(struct mlx5_eswitch *esw)
636 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
637 struct mlx5_flow_group *g;
638 struct mlx5_priv *priv = &esw->dev->priv;
640 void *match_criteria, *misc;
642 int nvports = priv->sriov.num_vfs + 2;
644 flow_group_in = kvzalloc(inlen, GFP_KERNEL);
648 /* create vport rx group */
649 memset(flow_group_in, 0, inlen);
650 MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
651 MLX5_MATCH_MISC_PARAMETERS);
653 match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
654 misc = MLX5_ADDR_OF(fte_match_param, match_criteria, misc_parameters);
655 MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
657 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
658 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, nvports - 1);
660 g = mlx5_create_flow_group(esw->offloads.ft_offloads, flow_group_in);
664 mlx5_core_warn(esw->dev, "Failed to create vport rx group err %d\n", err);
668 esw->offloads.vport_rx_group = g;
670 kfree(flow_group_in);
674 static void esw_destroy_vport_rx_group(struct mlx5_eswitch *esw)
676 mlx5_destroy_flow_group(esw->offloads.vport_rx_group);
679 struct mlx5_flow_handle *
680 mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, int vport, u32 tirn)
682 struct mlx5_flow_act flow_act = {0};
683 struct mlx5_flow_destination dest = {};
684 struct mlx5_flow_handle *flow_rule;
685 struct mlx5_flow_spec *spec;
688 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
690 flow_rule = ERR_PTR(-ENOMEM);
694 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
695 MLX5_SET(fte_match_set_misc, misc, source_port, vport);
697 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
698 MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
700 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
701 dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR;
704 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
705 flow_rule = mlx5_add_flow_rules(esw->offloads.ft_offloads, spec,
706 &flow_act, &dest, 1);
707 if (IS_ERR(flow_rule)) {
708 esw_warn(esw->dev, "fs offloads: Failed to add vport rx rule err %ld\n", PTR_ERR(flow_rule));
717 static int esw_offloads_start(struct mlx5_eswitch *esw)
719 int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs;
721 if (esw->mode != SRIOV_LEGACY) {
722 esw_warn(esw->dev, "Can't set offloads mode, SRIOV legacy not enabled\n");
726 mlx5_eswitch_disable_sriov(esw);
727 err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_OFFLOADS);
729 esw_warn(esw->dev, "Failed setting eswitch to offloads, err %d\n", err);
730 err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
732 esw_warn(esw->dev, "Failed setting eswitch back to legacy, err %d\n", err1);
734 if (esw->offloads.inline_mode == MLX5_INLINE_MODE_NONE) {
735 if (mlx5_eswitch_inline_mode_get(esw,
737 &esw->offloads.inline_mode)) {
738 esw->offloads.inline_mode = MLX5_INLINE_MODE_L2;
739 esw_warn(esw->dev, "Inline mode is different between vports\n");
745 void esw_offloads_cleanup_reps(struct mlx5_eswitch *esw)
747 kfree(esw->offloads.vport_reps);
750 int esw_offloads_init_reps(struct mlx5_eswitch *esw)
752 int total_vfs = MLX5_TOTAL_VPORTS(esw->dev);
753 struct mlx5_core_dev *dev = esw->dev;
754 struct mlx5_esw_offload *offloads;
755 struct mlx5_eswitch_rep *rep;
759 esw->offloads.vport_reps = kcalloc(total_vfs,
760 sizeof(struct mlx5_eswitch_rep),
762 if (!esw->offloads.vport_reps)
765 offloads = &esw->offloads;
766 mlx5_query_nic_vport_mac_address(dev, 0, hw_id);
768 for (vport = 0; vport < total_vfs; vport++) {
769 rep = &offloads->vport_reps[vport];
772 ether_addr_copy(rep->hw_id, hw_id);
775 offloads->vport_reps[0].vport = FDB_UPLINK_VPORT;
780 static void esw_offloads_unload_reps_type(struct mlx5_eswitch *esw, int nvports,
783 struct mlx5_eswitch_rep *rep;
786 for (vport = nvports - 1; vport >= 0; vport--) {
787 rep = &esw->offloads.vport_reps[vport];
788 if (!rep->rep_if[rep_type].valid)
791 rep->rep_if[rep_type].unload(rep);
795 static void esw_offloads_unload_reps(struct mlx5_eswitch *esw, int nvports)
797 u8 rep_type = NUM_REP_TYPES;
799 while (rep_type-- > 0)
800 esw_offloads_unload_reps_type(esw, nvports, rep_type);
803 static int esw_offloads_load_reps_type(struct mlx5_eswitch *esw, int nvports,
806 struct mlx5_eswitch_rep *rep;
810 for (vport = 0; vport < nvports; vport++) {
811 rep = &esw->offloads.vport_reps[vport];
812 if (!rep->rep_if[rep_type].valid)
815 err = rep->rep_if[rep_type].load(esw->dev, rep);
823 esw_offloads_unload_reps_type(esw, vport, rep_type);
827 static int esw_offloads_load_reps(struct mlx5_eswitch *esw, int nvports)
832 for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++) {
833 err = esw_offloads_load_reps_type(esw, nvports, rep_type);
841 while (rep_type-- > 0)
842 esw_offloads_unload_reps_type(esw, nvports, rep_type);
846 int esw_offloads_init(struct mlx5_eswitch *esw, int nvports)
850 err = esw_create_offloads_fdb_tables(esw, nvports);
854 err = esw_create_offloads_table(esw);
858 err = esw_create_vport_rx_group(esw);
862 err = esw_offloads_load_reps(esw, nvports);
869 esw_destroy_vport_rx_group(esw);
872 esw_destroy_offloads_table(esw);
875 esw_destroy_offloads_fdb_tables(esw);
880 static int esw_offloads_stop(struct mlx5_eswitch *esw)
882 int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs;
884 mlx5_eswitch_disable_sriov(esw);
885 err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
887 esw_warn(esw->dev, "Failed setting eswitch to legacy, err %d\n", err);
888 err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_OFFLOADS);
890 esw_warn(esw->dev, "Failed setting eswitch back to offloads, err %d\n", err);
893 /* enable back PF RoCE */
894 mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
899 void esw_offloads_cleanup(struct mlx5_eswitch *esw, int nvports)
901 esw_offloads_unload_reps(esw, nvports);
902 esw_destroy_vport_rx_group(esw);
903 esw_destroy_offloads_table(esw);
904 esw_destroy_offloads_fdb_tables(esw);
907 static int esw_mode_from_devlink(u16 mode, u16 *mlx5_mode)
910 case DEVLINK_ESWITCH_MODE_LEGACY:
911 *mlx5_mode = SRIOV_LEGACY;
913 case DEVLINK_ESWITCH_MODE_SWITCHDEV:
914 *mlx5_mode = SRIOV_OFFLOADS;
923 static int esw_mode_to_devlink(u16 mlx5_mode, u16 *mode)
927 *mode = DEVLINK_ESWITCH_MODE_LEGACY;
930 *mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
939 static int esw_inline_mode_from_devlink(u8 mode, u8 *mlx5_mode)
942 case DEVLINK_ESWITCH_INLINE_MODE_NONE:
943 *mlx5_mode = MLX5_INLINE_MODE_NONE;
945 case DEVLINK_ESWITCH_INLINE_MODE_LINK:
946 *mlx5_mode = MLX5_INLINE_MODE_L2;
948 case DEVLINK_ESWITCH_INLINE_MODE_NETWORK:
949 *mlx5_mode = MLX5_INLINE_MODE_IP;
951 case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT:
952 *mlx5_mode = MLX5_INLINE_MODE_TCP_UDP;
961 static int esw_inline_mode_to_devlink(u8 mlx5_mode, u8 *mode)
964 case MLX5_INLINE_MODE_NONE:
965 *mode = DEVLINK_ESWITCH_INLINE_MODE_NONE;
967 case MLX5_INLINE_MODE_L2:
968 *mode = DEVLINK_ESWITCH_INLINE_MODE_LINK;
970 case MLX5_INLINE_MODE_IP:
971 *mode = DEVLINK_ESWITCH_INLINE_MODE_NETWORK;
973 case MLX5_INLINE_MODE_TCP_UDP:
974 *mode = DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT;
983 static int mlx5_devlink_eswitch_check(struct devlink *devlink)
985 struct mlx5_core_dev *dev = devlink_priv(devlink);
987 if (MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
990 if (!MLX5_CAP_GEN(dev, vport_group_manager))
993 if (dev->priv.eswitch->mode == SRIOV_NONE)
999 int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode)
1001 struct mlx5_core_dev *dev = devlink_priv(devlink);
1002 u16 cur_mlx5_mode, mlx5_mode = 0;
1005 err = mlx5_devlink_eswitch_check(devlink);
1009 cur_mlx5_mode = dev->priv.eswitch->mode;
1011 if (esw_mode_from_devlink(mode, &mlx5_mode))
1014 if (cur_mlx5_mode == mlx5_mode)
1017 if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV)
1018 return esw_offloads_start(dev->priv.eswitch);
1019 else if (mode == DEVLINK_ESWITCH_MODE_LEGACY)
1020 return esw_offloads_stop(dev->priv.eswitch);
1025 int mlx5_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
1027 struct mlx5_core_dev *dev = devlink_priv(devlink);
1030 err = mlx5_devlink_eswitch_check(devlink);
1034 return esw_mode_to_devlink(dev->priv.eswitch->mode, mode);
1037 int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode)
1039 struct mlx5_core_dev *dev = devlink_priv(devlink);
1040 struct mlx5_eswitch *esw = dev->priv.eswitch;
1044 err = mlx5_devlink_eswitch_check(devlink);
1048 switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
1049 case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
1050 if (mode == DEVLINK_ESWITCH_INLINE_MODE_NONE)
1053 case MLX5_CAP_INLINE_MODE_L2:
1054 esw_warn(dev, "Inline mode can't be set\n");
1056 case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
1060 if (esw->offloads.num_flows > 0) {
1061 esw_warn(dev, "Can't set inline mode when flows are configured\n");
1065 err = esw_inline_mode_from_devlink(mode, &mlx5_mode);
1069 for (vport = 1; vport < esw->enabled_vports; vport++) {
1070 err = mlx5_modify_nic_vport_min_inline(dev, vport, mlx5_mode);
1072 esw_warn(dev, "Failed to set min inline on vport %d\n",
1074 goto revert_inline_mode;
1078 esw->offloads.inline_mode = mlx5_mode;
1083 mlx5_modify_nic_vport_min_inline(dev,
1085 esw->offloads.inline_mode);
1090 int mlx5_devlink_eswitch_inline_mode_get(struct devlink *devlink, u8 *mode)
1092 struct mlx5_core_dev *dev = devlink_priv(devlink);
1093 struct mlx5_eswitch *esw = dev->priv.eswitch;
1096 err = mlx5_devlink_eswitch_check(devlink);
1100 return esw_inline_mode_to_devlink(esw->offloads.inline_mode, mode);
1103 int mlx5_eswitch_inline_mode_get(struct mlx5_eswitch *esw, int nvfs, u8 *mode)
1105 u8 prev_mlx5_mode, mlx5_mode = MLX5_INLINE_MODE_L2;
1106 struct mlx5_core_dev *dev = esw->dev;
1109 if (!MLX5_CAP_GEN(dev, vport_group_manager))
1112 if (esw->mode == SRIOV_NONE)
1115 switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
1116 case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
1117 mlx5_mode = MLX5_INLINE_MODE_NONE;
1119 case MLX5_CAP_INLINE_MODE_L2:
1120 mlx5_mode = MLX5_INLINE_MODE_L2;
1122 case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
1127 for (vport = 1; vport <= nvfs; vport++) {
1128 mlx5_query_nic_vport_min_inline(dev, vport, &mlx5_mode);
1129 if (vport > 1 && prev_mlx5_mode != mlx5_mode)
1131 prev_mlx5_mode = mlx5_mode;
1139 int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap)
1141 struct mlx5_core_dev *dev = devlink_priv(devlink);
1142 struct mlx5_eswitch *esw = dev->priv.eswitch;
1145 err = mlx5_devlink_eswitch_check(devlink);
1149 if (encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE &&
1150 (!MLX5_CAP_ESW_FLOWTABLE_FDB(dev, encap) ||
1151 !MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap)))
1154 if (encap && encap != DEVLINK_ESWITCH_ENCAP_MODE_BASIC)
1157 if (esw->mode == SRIOV_LEGACY) {
1158 esw->offloads.encap = encap;
1162 if (esw->offloads.encap == encap)
1165 if (esw->offloads.num_flows > 0) {
1166 esw_warn(dev, "Can't set encapsulation when flows are configured\n");
1170 esw_destroy_offloads_fast_fdb_table(esw);
1172 esw->offloads.encap = encap;
1173 err = esw_create_offloads_fast_fdb_table(esw);
1175 esw_warn(esw->dev, "Failed re-creating fast FDB table, err %d\n", err);
1176 esw->offloads.encap = !encap;
1177 (void)esw_create_offloads_fast_fdb_table(esw);
1182 int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink, u8 *encap)
1184 struct mlx5_core_dev *dev = devlink_priv(devlink);
1185 struct mlx5_eswitch *esw = dev->priv.eswitch;
1188 err = mlx5_devlink_eswitch_check(devlink);
1192 *encap = esw->offloads.encap;
1196 void mlx5_eswitch_register_vport_rep(struct mlx5_eswitch *esw,
1198 struct mlx5_eswitch_rep_if *__rep_if,
1201 struct mlx5_esw_offload *offloads = &esw->offloads;
1202 struct mlx5_eswitch_rep_if *rep_if;
1204 rep_if = &offloads->vport_reps[vport_index].rep_if[rep_type];
1206 rep_if->load = __rep_if->load;
1207 rep_if->unload = __rep_if->unload;
1208 rep_if->get_proto_dev = __rep_if->get_proto_dev;
1209 rep_if->priv = __rep_if->priv;
1211 rep_if->valid = true;
1213 EXPORT_SYMBOL(mlx5_eswitch_register_vport_rep);
1215 void mlx5_eswitch_unregister_vport_rep(struct mlx5_eswitch *esw,
1216 int vport_index, u8 rep_type)
1218 struct mlx5_esw_offload *offloads = &esw->offloads;
1219 struct mlx5_eswitch_rep *rep;
1221 rep = &offloads->vport_reps[vport_index];
1223 if (esw->mode == SRIOV_OFFLOADS && esw->vports[vport_index].enabled)
1224 rep->rep_if[rep_type].unload(rep);
1226 rep->rep_if[rep_type].valid = false;
1228 EXPORT_SYMBOL(mlx5_eswitch_unregister_vport_rep);
1230 void *mlx5_eswitch_get_uplink_priv(struct mlx5_eswitch *esw, u8 rep_type)
1232 #define UPLINK_REP_INDEX 0
1233 struct mlx5_esw_offload *offloads = &esw->offloads;
1234 struct mlx5_eswitch_rep *rep;
1236 rep = &offloads->vport_reps[UPLINK_REP_INDEX];
1237 return rep->rep_if[rep_type].priv;
1240 void *mlx5_eswitch_get_proto_dev(struct mlx5_eswitch *esw,
1244 struct mlx5_esw_offload *offloads = &esw->offloads;
1245 struct mlx5_eswitch_rep *rep;
1247 if (vport == FDB_UPLINK_VPORT)
1248 vport = UPLINK_REP_INDEX;
1250 rep = &offloads->vport_reps[vport];
1252 if (rep->rep_if[rep_type].valid &&
1253 rep->rep_if[rep_type].get_proto_dev)
1254 return rep->rep_if[rep_type].get_proto_dev(rep);
1257 EXPORT_SYMBOL(mlx5_eswitch_get_proto_dev);
1259 void *mlx5_eswitch_uplink_get_proto_dev(struct mlx5_eswitch *esw, u8 rep_type)
1261 return mlx5_eswitch_get_proto_dev(esw, UPLINK_REP_INDEX, rep_type);
1263 EXPORT_SYMBOL(mlx5_eswitch_uplink_get_proto_dev);
1265 struct mlx5_eswitch_rep *mlx5_eswitch_vport_rep(struct mlx5_eswitch *esw,
1268 return &esw->offloads.vport_reps[vport];
1270 EXPORT_SYMBOL(mlx5_eswitch_vport_rep);