net/mlx5e: E-Switch, Add extack messages to devlink callbacks
[sfrench/cifs-2.6.git] / drivers / net / ethernet / mellanox / mlx5 / core / eswitch_offloads.c
1 /*
2  * Copyright (c) 2016, Mellanox Technologies. All rights reserved.
3  *
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:
9  *
10  *     Redistribution and use in source and binary forms, with or
11  *     without modification, are permitted provided that the following
12  *     conditions are met:
13  *
14  *      - Redistributions of source code must retain the above
15  *        copyright notice, this list of conditions and the following
16  *        disclaimer.
17  *
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.
22  *
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
30  * SOFTWARE.
31  */
32
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"
39 #include "eswitch.h"
40
41 enum {
42         FDB_FAST_PATH = 0,
43         FDB_SLOW_PATH
44 };
45
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)
50 {
51         struct mlx5_flow_destination dest[MLX5_MAX_FLOW_FWD_VPORTS + 1] = {};
52         struct mlx5_flow_act flow_act = {0};
53         struct mlx5_flow_table *ft = NULL;
54         struct mlx5_fc *counter = NULL;
55         struct mlx5_flow_handle *rule;
56         int j, i = 0;
57         void *misc;
58
59         if (esw->mode != SRIOV_OFFLOADS)
60                 return ERR_PTR(-EOPNOTSUPP);
61
62         if (attr->mirror_count)
63                 ft = esw->fdb_table.offloads.fwd_fdb;
64         else
65                 ft = esw->fdb_table.offloads.fast_fdb;
66
67         flow_act.action = attr->action;
68         /* if per flow vlan pop/push is emulated, don't set that into the firmware */
69         if (!mlx5_eswitch_vlan_actions_supported(esw->dev, 1))
70                 flow_act.action &= ~(MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH |
71                                      MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
72         else if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH) {
73                 flow_act.vlan[0].ethtype = ntohs(attr->vlan_proto[0]);
74                 flow_act.vlan[0].vid = attr->vlan_vid[0];
75                 flow_act.vlan[0].prio = attr->vlan_prio[0];
76                 if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2) {
77                         flow_act.vlan[1].ethtype = ntohs(attr->vlan_proto[1]);
78                         flow_act.vlan[1].vid = attr->vlan_vid[1];
79                         flow_act.vlan[1].prio = attr->vlan_prio[1];
80                 }
81         }
82
83         if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
84                 for (j = attr->mirror_count; j < attr->out_count; j++) {
85                         dest[i].type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
86                         dest[i].vport.num = attr->out_rep[j]->vport;
87                         dest[i].vport.vhca_id =
88                                 MLX5_CAP_GEN(attr->out_mdev[j], vhca_id);
89                         dest[i].vport.vhca_id_valid = !!MLX5_CAP_ESW(esw->dev, merged_eswitch);
90                         i++;
91                 }
92         }
93         if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
94                 counter = mlx5_fc_create(esw->dev, true);
95                 if (IS_ERR(counter)) {
96                         rule = ERR_CAST(counter);
97                         goto err_counter_alloc;
98                 }
99                 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
100                 dest[i].counter = counter;
101                 i++;
102         }
103
104         misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
105         MLX5_SET(fte_match_set_misc, misc, source_port, attr->in_rep->vport);
106
107         if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
108                 MLX5_SET(fte_match_set_misc, misc,
109                          source_eswitch_owner_vhca_id,
110                          MLX5_CAP_GEN(attr->in_mdev, vhca_id));
111
112         misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
113         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
114         if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
115                 MLX5_SET_TO_ONES(fte_match_set_misc, misc,
116                                  source_eswitch_owner_vhca_id);
117
118         if (attr->match_level == MLX5_MATCH_NONE)
119                 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
120         else
121                 spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS |
122                                               MLX5_MATCH_MISC_PARAMETERS;
123
124         if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_DECAP)
125                 spec->match_criteria_enable |= MLX5_MATCH_INNER_HEADERS;
126
127         if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
128                 flow_act.modify_id = attr->mod_hdr_id;
129
130         if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_ENCAP)
131                 flow_act.encap_id = attr->encap_id;
132
133         rule = mlx5_add_flow_rules(ft, spec, &flow_act, dest, i);
134         if (IS_ERR(rule))
135                 goto err_add_rule;
136         else
137                 esw->offloads.num_flows++;
138
139         return rule;
140
141 err_add_rule:
142         mlx5_fc_destroy(esw->dev, counter);
143 err_counter_alloc:
144         return rule;
145 }
146
147 struct mlx5_flow_handle *
148 mlx5_eswitch_add_fwd_rule(struct mlx5_eswitch *esw,
149                           struct mlx5_flow_spec *spec,
150                           struct mlx5_esw_flow_attr *attr)
151 {
152         struct mlx5_flow_destination dest[MLX5_MAX_FLOW_FWD_VPORTS + 1] = {};
153         struct mlx5_flow_act flow_act = {0};
154         struct mlx5_flow_handle *rule;
155         void *misc;
156         int i;
157
158         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
159         for (i = 0; i < attr->mirror_count; i++) {
160                 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
161                 dest[i].vport.num = attr->out_rep[i]->vport;
162                 dest[i].vport.vhca_id =
163                         MLX5_CAP_GEN(attr->out_mdev[i], vhca_id);
164                 dest[i].vport.vhca_id_valid = !!MLX5_CAP_ESW(esw->dev, merged_eswitch);
165         }
166         dest[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
167         dest[i].ft = esw->fdb_table.offloads.fwd_fdb,
168         i++;
169
170         misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
171         MLX5_SET(fte_match_set_misc, misc, source_port, attr->in_rep->vport);
172
173         if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
174                 MLX5_SET(fte_match_set_misc, misc,
175                          source_eswitch_owner_vhca_id,
176                          MLX5_CAP_GEN(attr->in_mdev, vhca_id));
177
178         misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
179         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
180         if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
181                 MLX5_SET_TO_ONES(fte_match_set_misc, misc,
182                                  source_eswitch_owner_vhca_id);
183
184         if (attr->match_level == MLX5_MATCH_NONE)
185                 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
186         else
187                 spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS |
188                                               MLX5_MATCH_MISC_PARAMETERS;
189
190         rule = mlx5_add_flow_rules(esw->fdb_table.offloads.fast_fdb, spec, &flow_act, dest, i);
191
192         if (!IS_ERR(rule))
193                 esw->offloads.num_flows++;
194
195         return rule;
196 }
197
198 void
199 mlx5_eswitch_del_offloaded_rule(struct mlx5_eswitch *esw,
200                                 struct mlx5_flow_handle *rule,
201                                 struct mlx5_esw_flow_attr *attr)
202 {
203         struct mlx5_fc *counter = NULL;
204
205         counter = mlx5_flow_rule_counter(rule);
206         mlx5_del_flow_rules(rule);
207         mlx5_fc_destroy(esw->dev, counter);
208         esw->offloads.num_flows--;
209 }
210
211 static int esw_set_global_vlan_pop(struct mlx5_eswitch *esw, u8 val)
212 {
213         struct mlx5_eswitch_rep *rep;
214         int vf_vport, err = 0;
215
216         esw_debug(esw->dev, "%s applying global %s policy\n", __func__, val ? "pop" : "none");
217         for (vf_vport = 1; vf_vport < esw->enabled_vports; vf_vport++) {
218                 rep = &esw->offloads.vport_reps[vf_vport];
219                 if (!rep->rep_if[REP_ETH].valid)
220                         continue;
221
222                 err = __mlx5_eswitch_set_vport_vlan(esw, rep->vport, 0, 0, val);
223                 if (err)
224                         goto out;
225         }
226
227 out:
228         return err;
229 }
230
231 static struct mlx5_eswitch_rep *
232 esw_vlan_action_get_vport(struct mlx5_esw_flow_attr *attr, bool push, bool pop)
233 {
234         struct mlx5_eswitch_rep *in_rep, *out_rep, *vport = NULL;
235
236         in_rep  = attr->in_rep;
237         out_rep = attr->out_rep[0];
238
239         if (push)
240                 vport = in_rep;
241         else if (pop)
242                 vport = out_rep;
243         else
244                 vport = in_rep;
245
246         return vport;
247 }
248
249 static int esw_add_vlan_action_check(struct mlx5_esw_flow_attr *attr,
250                                      bool push, bool pop, bool fwd)
251 {
252         struct mlx5_eswitch_rep *in_rep, *out_rep;
253
254         if ((push || pop) && !fwd)
255                 goto out_notsupp;
256
257         in_rep  = attr->in_rep;
258         out_rep = attr->out_rep[0];
259
260         if (push && in_rep->vport == FDB_UPLINK_VPORT)
261                 goto out_notsupp;
262
263         if (pop && out_rep->vport == FDB_UPLINK_VPORT)
264                 goto out_notsupp;
265
266         /* vport has vlan push configured, can't offload VF --> wire rules w.o it */
267         if (!push && !pop && fwd)
268                 if (in_rep->vlan && out_rep->vport == FDB_UPLINK_VPORT)
269                         goto out_notsupp;
270
271         /* protects against (1) setting rules with different vlans to push and
272          * (2) setting rules w.o vlans (attr->vlan = 0) && w. vlans to push (!= 0)
273          */
274         if (push && in_rep->vlan_refcount && (in_rep->vlan != attr->vlan_vid[0]))
275                 goto out_notsupp;
276
277         return 0;
278
279 out_notsupp:
280         return -EOPNOTSUPP;
281 }
282
283 int mlx5_eswitch_add_vlan_action(struct mlx5_eswitch *esw,
284                                  struct mlx5_esw_flow_attr *attr)
285 {
286         struct offloads_fdb *offloads = &esw->fdb_table.offloads;
287         struct mlx5_eswitch_rep *vport = NULL;
288         bool push, pop, fwd;
289         int err = 0;
290
291         /* nop if we're on the vlan push/pop non emulation mode */
292         if (mlx5_eswitch_vlan_actions_supported(esw->dev, 1))
293                 return 0;
294
295         push = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH);
296         pop  = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
297         fwd  = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST);
298
299         err = esw_add_vlan_action_check(attr, push, pop, fwd);
300         if (err)
301                 return err;
302
303         attr->vlan_handled = false;
304
305         vport = esw_vlan_action_get_vport(attr, push, pop);
306
307         if (!push && !pop && fwd) {
308                 /* tracks VF --> wire rules without vlan push action */
309                 if (attr->out_rep[0]->vport == FDB_UPLINK_VPORT) {
310                         vport->vlan_refcount++;
311                         attr->vlan_handled = true;
312                 }
313
314                 return 0;
315         }
316
317         if (!push && !pop)
318                 return 0;
319
320         if (!(offloads->vlan_push_pop_refcount)) {
321                 /* it's the 1st vlan rule, apply global vlan pop policy */
322                 err = esw_set_global_vlan_pop(esw, SET_VLAN_STRIP);
323                 if (err)
324                         goto out;
325         }
326         offloads->vlan_push_pop_refcount++;
327
328         if (push) {
329                 if (vport->vlan_refcount)
330                         goto skip_set_push;
331
332                 err = __mlx5_eswitch_set_vport_vlan(esw, vport->vport, attr->vlan_vid[0], 0,
333                                                     SET_VLAN_INSERT | SET_VLAN_STRIP);
334                 if (err)
335                         goto out;
336                 vport->vlan = attr->vlan_vid[0];
337 skip_set_push:
338                 vport->vlan_refcount++;
339         }
340 out:
341         if (!err)
342                 attr->vlan_handled = true;
343         return err;
344 }
345
346 int mlx5_eswitch_del_vlan_action(struct mlx5_eswitch *esw,
347                                  struct mlx5_esw_flow_attr *attr)
348 {
349         struct offloads_fdb *offloads = &esw->fdb_table.offloads;
350         struct mlx5_eswitch_rep *vport = NULL;
351         bool push, pop, fwd;
352         int err = 0;
353
354         /* nop if we're on the vlan push/pop non emulation mode */
355         if (mlx5_eswitch_vlan_actions_supported(esw->dev, 1))
356                 return 0;
357
358         if (!attr->vlan_handled)
359                 return 0;
360
361         push = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH);
362         pop  = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
363         fwd  = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST);
364
365         vport = esw_vlan_action_get_vport(attr, push, pop);
366
367         if (!push && !pop && fwd) {
368                 /* tracks VF --> wire rules without vlan push action */
369                 if (attr->out_rep[0]->vport == FDB_UPLINK_VPORT)
370                         vport->vlan_refcount--;
371
372                 return 0;
373         }
374
375         if (push) {
376                 vport->vlan_refcount--;
377                 if (vport->vlan_refcount)
378                         goto skip_unset_push;
379
380                 vport->vlan = 0;
381                 err = __mlx5_eswitch_set_vport_vlan(esw, vport->vport,
382                                                     0, 0, SET_VLAN_STRIP);
383                 if (err)
384                         goto out;
385         }
386
387 skip_unset_push:
388         offloads->vlan_push_pop_refcount--;
389         if (offloads->vlan_push_pop_refcount)
390                 return 0;
391
392         /* no more vlan rules, stop global vlan pop policy */
393         err = esw_set_global_vlan_pop(esw, 0);
394
395 out:
396         return err;
397 }
398
399 struct mlx5_flow_handle *
400 mlx5_eswitch_add_send_to_vport_rule(struct mlx5_eswitch *esw, int vport, u32 sqn)
401 {
402         struct mlx5_flow_act flow_act = {0};
403         struct mlx5_flow_destination dest = {};
404         struct mlx5_flow_handle *flow_rule;
405         struct mlx5_flow_spec *spec;
406         void *misc;
407
408         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
409         if (!spec) {
410                 flow_rule = ERR_PTR(-ENOMEM);
411                 goto out;
412         }
413
414         misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
415         MLX5_SET(fte_match_set_misc, misc, source_sqn, sqn);
416         MLX5_SET(fte_match_set_misc, misc, source_port, 0x0); /* source vport is 0 */
417
418         misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
419         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_sqn);
420         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
421
422         spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
423         dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
424         dest.vport.num = vport;
425         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
426
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                 esw_warn(esw->dev, "FDB: Failed to add send to vport rule err %ld\n", PTR_ERR(flow_rule));
431 out:
432         kvfree(spec);
433         return flow_rule;
434 }
435 EXPORT_SYMBOL(mlx5_eswitch_add_send_to_vport_rule);
436
437 void mlx5_eswitch_del_send_to_vport_rule(struct mlx5_flow_handle *rule)
438 {
439         mlx5_del_flow_rules(rule);
440 }
441
442 static int esw_add_fdb_miss_rule(struct mlx5_eswitch *esw)
443 {
444         struct mlx5_flow_act flow_act = {0};
445         struct mlx5_flow_destination dest = {};
446         struct mlx5_flow_handle *flow_rule = NULL;
447         struct mlx5_flow_spec *spec;
448         void *headers_c;
449         void *headers_v;
450         int err = 0;
451         u8 *dmac_c;
452         u8 *dmac_v;
453
454         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
455         if (!spec) {
456                 err = -ENOMEM;
457                 goto out;
458         }
459
460         spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
461         headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
462                                  outer_headers);
463         dmac_c = MLX5_ADDR_OF(fte_match_param, headers_c,
464                               outer_headers.dmac_47_16);
465         dmac_c[0] = 0x01;
466
467         dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
468         dest.vport.num = 0;
469         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
470
471         flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb, spec,
472                                         &flow_act, &dest, 1);
473         if (IS_ERR(flow_rule)) {
474                 err = PTR_ERR(flow_rule);
475                 esw_warn(esw->dev,  "FDB: Failed to add unicast miss flow rule err %d\n", err);
476                 goto out;
477         }
478
479         esw->fdb_table.offloads.miss_rule_uni = flow_rule;
480
481         headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
482                                  outer_headers);
483         dmac_v = MLX5_ADDR_OF(fte_match_param, headers_v,
484                               outer_headers.dmac_47_16);
485         dmac_v[0] = 0x01;
486         flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb, spec,
487                                         &flow_act, &dest, 1);
488         if (IS_ERR(flow_rule)) {
489                 err = PTR_ERR(flow_rule);
490                 esw_warn(esw->dev, "FDB: Failed to add multicast miss flow rule err %d\n", err);
491                 mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_uni);
492                 goto out;
493         }
494
495         esw->fdb_table.offloads.miss_rule_multi = flow_rule;
496
497 out:
498         kvfree(spec);
499         return err;
500 }
501
502 #define ESW_OFFLOADS_NUM_GROUPS  4
503
504 static int esw_create_offloads_fast_fdb_table(struct mlx5_eswitch *esw)
505 {
506         struct mlx5_core_dev *dev = esw->dev;
507         struct mlx5_flow_namespace *root_ns;
508         struct mlx5_flow_table *fdb = NULL;
509         int esw_size, err = 0;
510         u32 flags = 0;
511         u32 max_flow_counter = (MLX5_CAP_GEN(dev, max_flow_counter_31_16) << 16) |
512                                 MLX5_CAP_GEN(dev, max_flow_counter_15_0);
513
514         root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
515         if (!root_ns) {
516                 esw_warn(dev, "Failed to get FDB flow namespace\n");
517                 err = -EOPNOTSUPP;
518                 goto out_namespace;
519         }
520
521         esw_debug(dev, "Create offloads FDB table, min (max esw size(2^%d), max counters(%d)*groups(%d))\n",
522                   MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size),
523                   max_flow_counter, ESW_OFFLOADS_NUM_GROUPS);
524
525         esw_size = min_t(int, max_flow_counter * ESW_OFFLOADS_NUM_GROUPS,
526                          1 << MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size));
527
528         if (mlx5_esw_has_fwd_fdb(dev))
529                 esw_size >>= 1;
530
531         if (esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE)
532                 flags |= MLX5_FLOW_TABLE_TUNNEL_EN;
533
534         fdb = mlx5_create_auto_grouped_flow_table(root_ns, FDB_FAST_PATH,
535                                                   esw_size,
536                                                   ESW_OFFLOADS_NUM_GROUPS, 0,
537                                                   flags);
538         if (IS_ERR(fdb)) {
539                 err = PTR_ERR(fdb);
540                 esw_warn(dev, "Failed to create Fast path FDB Table err %d\n", err);
541                 goto out_namespace;
542         }
543         esw->fdb_table.offloads.fast_fdb = fdb;
544
545         if (!mlx5_esw_has_fwd_fdb(dev))
546                 goto out_namespace;
547
548         fdb = mlx5_create_auto_grouped_flow_table(root_ns, FDB_FAST_PATH,
549                                                   esw_size,
550                                                   ESW_OFFLOADS_NUM_GROUPS, 1,
551                                                   flags);
552         if (IS_ERR(fdb)) {
553                 err = PTR_ERR(fdb);
554                 esw_warn(dev, "Failed to create fwd table err %d\n", err);
555                 goto out_ft;
556         }
557         esw->fdb_table.offloads.fwd_fdb = fdb;
558
559         return err;
560
561 out_ft:
562         mlx5_destroy_flow_table(esw->fdb_table.offloads.fast_fdb);
563 out_namespace:
564         return err;
565 }
566
567 static void esw_destroy_offloads_fast_fdb_table(struct mlx5_eswitch *esw)
568 {
569         if (mlx5_esw_has_fwd_fdb(esw->dev))
570                 mlx5_destroy_flow_table(esw->fdb_table.offloads.fwd_fdb);
571         mlx5_destroy_flow_table(esw->fdb_table.offloads.fast_fdb);
572 }
573
574 #define MAX_PF_SQ 256
575 #define MAX_SQ_NVPORTS 32
576
577 static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw, int nvports)
578 {
579         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
580         struct mlx5_flow_table_attr ft_attr = {};
581         struct mlx5_core_dev *dev = esw->dev;
582         struct mlx5_flow_namespace *root_ns;
583         struct mlx5_flow_table *fdb = NULL;
584         int table_size, ix, err = 0;
585         struct mlx5_flow_group *g;
586         void *match_criteria;
587         u32 *flow_group_in;
588         u8 *dmac;
589
590         esw_debug(esw->dev, "Create offloads FDB Tables\n");
591         flow_group_in = kvzalloc(inlen, GFP_KERNEL);
592         if (!flow_group_in)
593                 return -ENOMEM;
594
595         root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
596         if (!root_ns) {
597                 esw_warn(dev, "Failed to get FDB flow namespace\n");
598                 err = -EOPNOTSUPP;
599                 goto ns_err;
600         }
601
602         err = esw_create_offloads_fast_fdb_table(esw);
603         if (err)
604                 goto fast_fdb_err;
605
606         table_size = nvports * MAX_SQ_NVPORTS + MAX_PF_SQ + 2;
607
608         ft_attr.max_fte = table_size;
609         ft_attr.prio = FDB_SLOW_PATH;
610
611         fdb = mlx5_create_flow_table(root_ns, &ft_attr);
612         if (IS_ERR(fdb)) {
613                 err = PTR_ERR(fdb);
614                 esw_warn(dev, "Failed to create slow path FDB Table err %d\n", err);
615                 goto slow_fdb_err;
616         }
617         esw->fdb_table.offloads.slow_fdb = fdb;
618
619         /* create send-to-vport group */
620         memset(flow_group_in, 0, inlen);
621         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
622                  MLX5_MATCH_MISC_PARAMETERS);
623
624         match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
625
626         MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_sqn);
627         MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_port);
628
629         ix = nvports * MAX_SQ_NVPORTS + MAX_PF_SQ;
630         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
631         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, ix - 1);
632
633         g = mlx5_create_flow_group(fdb, flow_group_in);
634         if (IS_ERR(g)) {
635                 err = PTR_ERR(g);
636                 esw_warn(dev, "Failed to create send-to-vport flow group err(%d)\n", err);
637                 goto send_vport_err;
638         }
639         esw->fdb_table.offloads.send_to_vport_grp = g;
640
641         /* create miss group */
642         memset(flow_group_in, 0, inlen);
643         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
644                  MLX5_MATCH_OUTER_HEADERS);
645         match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in,
646                                       match_criteria);
647         dmac = MLX5_ADDR_OF(fte_match_param, match_criteria,
648                             outer_headers.dmac_47_16);
649         dmac[0] = 0x01;
650
651         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ix);
652         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, ix + 2);
653
654         g = mlx5_create_flow_group(fdb, flow_group_in);
655         if (IS_ERR(g)) {
656                 err = PTR_ERR(g);
657                 esw_warn(dev, "Failed to create miss flow group err(%d)\n", err);
658                 goto miss_err;
659         }
660         esw->fdb_table.offloads.miss_grp = g;
661
662         err = esw_add_fdb_miss_rule(esw);
663         if (err)
664                 goto miss_rule_err;
665
666         kvfree(flow_group_in);
667         return 0;
668
669 miss_rule_err:
670         mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
671 miss_err:
672         mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
673 send_vport_err:
674         mlx5_destroy_flow_table(esw->fdb_table.offloads.slow_fdb);
675 slow_fdb_err:
676         esw_destroy_offloads_fast_fdb_table(esw);
677 fast_fdb_err:
678 ns_err:
679         kvfree(flow_group_in);
680         return err;
681 }
682
683 static void esw_destroy_offloads_fdb_tables(struct mlx5_eswitch *esw)
684 {
685         if (!esw->fdb_table.offloads.fast_fdb)
686                 return;
687
688         esw_debug(esw->dev, "Destroy offloads FDB Tables\n");
689         mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_multi);
690         mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_uni);
691         mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
692         mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
693
694         mlx5_destroy_flow_table(esw->fdb_table.offloads.slow_fdb);
695         esw_destroy_offloads_fast_fdb_table(esw);
696 }
697
698 static int esw_create_offloads_table(struct mlx5_eswitch *esw)
699 {
700         struct mlx5_flow_table_attr ft_attr = {};
701         struct mlx5_core_dev *dev = esw->dev;
702         struct mlx5_flow_table *ft_offloads;
703         struct mlx5_flow_namespace *ns;
704         int err = 0;
705
706         ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_OFFLOADS);
707         if (!ns) {
708                 esw_warn(esw->dev, "Failed to get offloads flow namespace\n");
709                 return -EOPNOTSUPP;
710         }
711
712         ft_attr.max_fte = dev->priv.sriov.num_vfs + 2;
713
714         ft_offloads = mlx5_create_flow_table(ns, &ft_attr);
715         if (IS_ERR(ft_offloads)) {
716                 err = PTR_ERR(ft_offloads);
717                 esw_warn(esw->dev, "Failed to create offloads table, err %d\n", err);
718                 return err;
719         }
720
721         esw->offloads.ft_offloads = ft_offloads;
722         return 0;
723 }
724
725 static void esw_destroy_offloads_table(struct mlx5_eswitch *esw)
726 {
727         struct mlx5_esw_offload *offloads = &esw->offloads;
728
729         mlx5_destroy_flow_table(offloads->ft_offloads);
730 }
731
732 static int esw_create_vport_rx_group(struct mlx5_eswitch *esw)
733 {
734         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
735         struct mlx5_flow_group *g;
736         struct mlx5_priv *priv = &esw->dev->priv;
737         u32 *flow_group_in;
738         void *match_criteria, *misc;
739         int err = 0;
740         int nvports = priv->sriov.num_vfs + 2;
741
742         flow_group_in = kvzalloc(inlen, GFP_KERNEL);
743         if (!flow_group_in)
744                 return -ENOMEM;
745
746         /* create vport rx group */
747         memset(flow_group_in, 0, inlen);
748         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
749                  MLX5_MATCH_MISC_PARAMETERS);
750
751         match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
752         misc = MLX5_ADDR_OF(fte_match_param, match_criteria, misc_parameters);
753         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
754
755         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
756         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, nvports - 1);
757
758         g = mlx5_create_flow_group(esw->offloads.ft_offloads, flow_group_in);
759
760         if (IS_ERR(g)) {
761                 err = PTR_ERR(g);
762                 mlx5_core_warn(esw->dev, "Failed to create vport rx group err %d\n", err);
763                 goto out;
764         }
765
766         esw->offloads.vport_rx_group = g;
767 out:
768         kvfree(flow_group_in);
769         return err;
770 }
771
772 static void esw_destroy_vport_rx_group(struct mlx5_eswitch *esw)
773 {
774         mlx5_destroy_flow_group(esw->offloads.vport_rx_group);
775 }
776
777 struct mlx5_flow_handle *
778 mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, int vport,
779                                   struct mlx5_flow_destination *dest)
780 {
781         struct mlx5_flow_act flow_act = {0};
782         struct mlx5_flow_handle *flow_rule;
783         struct mlx5_flow_spec *spec;
784         void *misc;
785
786         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
787         if (!spec) {
788                 flow_rule = ERR_PTR(-ENOMEM);
789                 goto out;
790         }
791
792         misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
793         MLX5_SET(fte_match_set_misc, misc, source_port, vport);
794
795         misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
796         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
797
798         spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
799
800         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
801         flow_rule = mlx5_add_flow_rules(esw->offloads.ft_offloads, spec,
802                                         &flow_act, dest, 1);
803         if (IS_ERR(flow_rule)) {
804                 esw_warn(esw->dev, "fs offloads: Failed to add vport rx rule err %ld\n", PTR_ERR(flow_rule));
805                 goto out;
806         }
807
808 out:
809         kvfree(spec);
810         return flow_rule;
811 }
812
813 static int esw_offloads_start(struct mlx5_eswitch *esw,
814                               struct netlink_ext_ack *extack)
815 {
816         int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs;
817
818         if (esw->mode != SRIOV_LEGACY) {
819                 NL_SET_ERR_MSG_MOD(extack,
820                                    "Can't set offloads mode, SRIOV legacy not enabled");
821                 return -EINVAL;
822         }
823
824         mlx5_eswitch_disable_sriov(esw);
825         err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_OFFLOADS);
826         if (err) {
827                 NL_SET_ERR_MSG_MOD(extack,
828                                    "Failed setting eswitch to offloads");
829                 err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
830                 if (err1) {
831                         NL_SET_ERR_MSG_MOD(extack,
832                                            "Failed setting eswitch back to legacy");
833                 }
834         }
835         if (esw->offloads.inline_mode == MLX5_INLINE_MODE_NONE) {
836                 if (mlx5_eswitch_inline_mode_get(esw,
837                                                  num_vfs,
838                                                  &esw->offloads.inline_mode)) {
839                         esw->offloads.inline_mode = MLX5_INLINE_MODE_L2;
840                         NL_SET_ERR_MSG_MOD(extack,
841                                            "Inline mode is different between vports");
842                 }
843         }
844         return err;
845 }
846
847 void esw_offloads_cleanup_reps(struct mlx5_eswitch *esw)
848 {
849         kfree(esw->offloads.vport_reps);
850 }
851
852 int esw_offloads_init_reps(struct mlx5_eswitch *esw)
853 {
854         int total_vfs = MLX5_TOTAL_VPORTS(esw->dev);
855         struct mlx5_core_dev *dev = esw->dev;
856         struct mlx5_esw_offload *offloads;
857         struct mlx5_eswitch_rep *rep;
858         u8 hw_id[ETH_ALEN];
859         int vport;
860
861         esw->offloads.vport_reps = kcalloc(total_vfs,
862                                            sizeof(struct mlx5_eswitch_rep),
863                                            GFP_KERNEL);
864         if (!esw->offloads.vport_reps)
865                 return -ENOMEM;
866
867         offloads = &esw->offloads;
868         mlx5_query_nic_vport_mac_address(dev, 0, hw_id);
869
870         for (vport = 0; vport < total_vfs; vport++) {
871                 rep = &offloads->vport_reps[vport];
872
873                 rep->vport = vport;
874                 ether_addr_copy(rep->hw_id, hw_id);
875         }
876
877         offloads->vport_reps[0].vport = FDB_UPLINK_VPORT;
878
879         return 0;
880 }
881
882 static void esw_offloads_unload_reps_type(struct mlx5_eswitch *esw, int nvports,
883                                           u8 rep_type)
884 {
885         struct mlx5_eswitch_rep *rep;
886         int vport;
887
888         for (vport = nvports - 1; vport >= 0; vport--) {
889                 rep = &esw->offloads.vport_reps[vport];
890                 if (!rep->rep_if[rep_type].valid)
891                         continue;
892
893                 rep->rep_if[rep_type].unload(rep);
894         }
895 }
896
897 static void esw_offloads_unload_reps(struct mlx5_eswitch *esw, int nvports)
898 {
899         u8 rep_type = NUM_REP_TYPES;
900
901         while (rep_type-- > 0)
902                 esw_offloads_unload_reps_type(esw, nvports, rep_type);
903 }
904
905 static int esw_offloads_load_reps_type(struct mlx5_eswitch *esw, int nvports,
906                                        u8 rep_type)
907 {
908         struct mlx5_eswitch_rep *rep;
909         int vport;
910         int err;
911
912         for (vport = 0; vport < nvports; vport++) {
913                 rep = &esw->offloads.vport_reps[vport];
914                 if (!rep->rep_if[rep_type].valid)
915                         continue;
916
917                 err = rep->rep_if[rep_type].load(esw->dev, rep);
918                 if (err)
919                         goto err_reps;
920         }
921
922         return 0;
923
924 err_reps:
925         esw_offloads_unload_reps_type(esw, vport, rep_type);
926         return err;
927 }
928
929 static int esw_offloads_load_reps(struct mlx5_eswitch *esw, int nvports)
930 {
931         u8 rep_type = 0;
932         int err;
933
934         for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++) {
935                 err = esw_offloads_load_reps_type(esw, nvports, rep_type);
936                 if (err)
937                         goto err_reps;
938         }
939
940         return err;
941
942 err_reps:
943         while (rep_type-- > 0)
944                 esw_offloads_unload_reps_type(esw, nvports, rep_type);
945         return err;
946 }
947
948 int esw_offloads_init(struct mlx5_eswitch *esw, int nvports)
949 {
950         int err;
951
952         err = esw_create_offloads_fdb_tables(esw, nvports);
953         if (err)
954                 return err;
955
956         err = esw_create_offloads_table(esw);
957         if (err)
958                 goto create_ft_err;
959
960         err = esw_create_vport_rx_group(esw);
961         if (err)
962                 goto create_fg_err;
963
964         err = esw_offloads_load_reps(esw, nvports);
965         if (err)
966                 goto err_reps;
967
968         return 0;
969
970 err_reps:
971         esw_destroy_vport_rx_group(esw);
972
973 create_fg_err:
974         esw_destroy_offloads_table(esw);
975
976 create_ft_err:
977         esw_destroy_offloads_fdb_tables(esw);
978
979         return err;
980 }
981
982 static int esw_offloads_stop(struct mlx5_eswitch *esw,
983                              struct netlink_ext_ack *extack)
984 {
985         int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs;
986
987         mlx5_eswitch_disable_sriov(esw);
988         err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
989         if (err) {
990                 NL_SET_ERR_MSG_MOD(extack, "Failed setting eswitch to legacy");
991                 err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_OFFLOADS);
992                 if (err1) {
993                         NL_SET_ERR_MSG_MOD(extack,
994                                            "Failed setting eswitch back to offloads");
995                 }
996         }
997
998         /* enable back PF RoCE */
999         mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
1000
1001         return err;
1002 }
1003
1004 void esw_offloads_cleanup(struct mlx5_eswitch *esw, int nvports)
1005 {
1006         esw_offloads_unload_reps(esw, nvports);
1007         esw_destroy_vport_rx_group(esw);
1008         esw_destroy_offloads_table(esw);
1009         esw_destroy_offloads_fdb_tables(esw);
1010 }
1011
1012 static int esw_mode_from_devlink(u16 mode, u16 *mlx5_mode)
1013 {
1014         switch (mode) {
1015         case DEVLINK_ESWITCH_MODE_LEGACY:
1016                 *mlx5_mode = SRIOV_LEGACY;
1017                 break;
1018         case DEVLINK_ESWITCH_MODE_SWITCHDEV:
1019                 *mlx5_mode = SRIOV_OFFLOADS;
1020                 break;
1021         default:
1022                 return -EINVAL;
1023         }
1024
1025         return 0;
1026 }
1027
1028 static int esw_mode_to_devlink(u16 mlx5_mode, u16 *mode)
1029 {
1030         switch (mlx5_mode) {
1031         case SRIOV_LEGACY:
1032                 *mode = DEVLINK_ESWITCH_MODE_LEGACY;
1033                 break;
1034         case SRIOV_OFFLOADS:
1035                 *mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
1036                 break;
1037         default:
1038                 return -EINVAL;
1039         }
1040
1041         return 0;
1042 }
1043
1044 static int esw_inline_mode_from_devlink(u8 mode, u8 *mlx5_mode)
1045 {
1046         switch (mode) {
1047         case DEVLINK_ESWITCH_INLINE_MODE_NONE:
1048                 *mlx5_mode = MLX5_INLINE_MODE_NONE;
1049                 break;
1050         case DEVLINK_ESWITCH_INLINE_MODE_LINK:
1051                 *mlx5_mode = MLX5_INLINE_MODE_L2;
1052                 break;
1053         case DEVLINK_ESWITCH_INLINE_MODE_NETWORK:
1054                 *mlx5_mode = MLX5_INLINE_MODE_IP;
1055                 break;
1056         case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT:
1057                 *mlx5_mode = MLX5_INLINE_MODE_TCP_UDP;
1058                 break;
1059         default:
1060                 return -EINVAL;
1061         }
1062
1063         return 0;
1064 }
1065
1066 static int esw_inline_mode_to_devlink(u8 mlx5_mode, u8 *mode)
1067 {
1068         switch (mlx5_mode) {
1069         case MLX5_INLINE_MODE_NONE:
1070                 *mode = DEVLINK_ESWITCH_INLINE_MODE_NONE;
1071                 break;
1072         case MLX5_INLINE_MODE_L2:
1073                 *mode = DEVLINK_ESWITCH_INLINE_MODE_LINK;
1074                 break;
1075         case MLX5_INLINE_MODE_IP:
1076                 *mode = DEVLINK_ESWITCH_INLINE_MODE_NETWORK;
1077                 break;
1078         case MLX5_INLINE_MODE_TCP_UDP:
1079                 *mode = DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT;
1080                 break;
1081         default:
1082                 return -EINVAL;
1083         }
1084
1085         return 0;
1086 }
1087
1088 static int mlx5_devlink_eswitch_check(struct devlink *devlink)
1089 {
1090         struct mlx5_core_dev *dev = devlink_priv(devlink);
1091
1092         if (MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
1093                 return -EOPNOTSUPP;
1094
1095         if(!MLX5_ESWITCH_MANAGER(dev))
1096                 return -EPERM;
1097
1098         if (dev->priv.eswitch->mode == SRIOV_NONE)
1099                 return -EOPNOTSUPP;
1100
1101         return 0;
1102 }
1103
1104 int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
1105                                   struct netlink_ext_ack *extack)
1106 {
1107         struct mlx5_core_dev *dev = devlink_priv(devlink);
1108         u16 cur_mlx5_mode, mlx5_mode = 0;
1109         int err;
1110
1111         err = mlx5_devlink_eswitch_check(devlink);
1112         if (err)
1113                 return err;
1114
1115         cur_mlx5_mode = dev->priv.eswitch->mode;
1116
1117         if (esw_mode_from_devlink(mode, &mlx5_mode))
1118                 return -EINVAL;
1119
1120         if (cur_mlx5_mode == mlx5_mode)
1121                 return 0;
1122
1123         if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV)
1124                 return esw_offloads_start(dev->priv.eswitch, extack);
1125         else if (mode == DEVLINK_ESWITCH_MODE_LEGACY)
1126                 return esw_offloads_stop(dev->priv.eswitch, extack);
1127         else
1128                 return -EINVAL;
1129 }
1130
1131 int mlx5_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
1132 {
1133         struct mlx5_core_dev *dev = devlink_priv(devlink);
1134         int err;
1135
1136         err = mlx5_devlink_eswitch_check(devlink);
1137         if (err)
1138                 return err;
1139
1140         return esw_mode_to_devlink(dev->priv.eswitch->mode, mode);
1141 }
1142
1143 int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode,
1144                                          struct netlink_ext_ack *extack)
1145 {
1146         struct mlx5_core_dev *dev = devlink_priv(devlink);
1147         struct mlx5_eswitch *esw = dev->priv.eswitch;
1148         int err, vport;
1149         u8 mlx5_mode;
1150
1151         err = mlx5_devlink_eswitch_check(devlink);
1152         if (err)
1153                 return err;
1154
1155         switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
1156         case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
1157                 if (mode == DEVLINK_ESWITCH_INLINE_MODE_NONE)
1158                         return 0;
1159                 /* fall through */
1160         case MLX5_CAP_INLINE_MODE_L2:
1161                 NL_SET_ERR_MSG_MOD(extack, "Inline mode can't be set");
1162                 return -EOPNOTSUPP;
1163         case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
1164                 break;
1165         }
1166
1167         if (esw->offloads.num_flows > 0) {
1168                 NL_SET_ERR_MSG_MOD(extack,
1169                                    "Can't set inline mode when flows are configured");
1170                 return -EOPNOTSUPP;
1171         }
1172
1173         err = esw_inline_mode_from_devlink(mode, &mlx5_mode);
1174         if (err)
1175                 goto out;
1176
1177         for (vport = 1; vport < esw->enabled_vports; vport++) {
1178                 err = mlx5_modify_nic_vport_min_inline(dev, vport, mlx5_mode);
1179                 if (err) {
1180                         NL_SET_ERR_MSG_MOD(extack,
1181                                            "Failed to set min inline on vport");
1182                         goto revert_inline_mode;
1183                 }
1184         }
1185
1186         esw->offloads.inline_mode = mlx5_mode;
1187         return 0;
1188
1189 revert_inline_mode:
1190         while (--vport > 0)
1191                 mlx5_modify_nic_vport_min_inline(dev,
1192                                                  vport,
1193                                                  esw->offloads.inline_mode);
1194 out:
1195         return err;
1196 }
1197
1198 int mlx5_devlink_eswitch_inline_mode_get(struct devlink *devlink, u8 *mode)
1199 {
1200         struct mlx5_core_dev *dev = devlink_priv(devlink);
1201         struct mlx5_eswitch *esw = dev->priv.eswitch;
1202         int err;
1203
1204         err = mlx5_devlink_eswitch_check(devlink);
1205         if (err)
1206                 return err;
1207
1208         return esw_inline_mode_to_devlink(esw->offloads.inline_mode, mode);
1209 }
1210
1211 int mlx5_eswitch_inline_mode_get(struct mlx5_eswitch *esw, int nvfs, u8 *mode)
1212 {
1213         u8 prev_mlx5_mode, mlx5_mode = MLX5_INLINE_MODE_L2;
1214         struct mlx5_core_dev *dev = esw->dev;
1215         int vport;
1216
1217         if (!MLX5_CAP_GEN(dev, vport_group_manager))
1218                 return -EOPNOTSUPP;
1219
1220         if (esw->mode == SRIOV_NONE)
1221                 return -EOPNOTSUPP;
1222
1223         switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
1224         case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
1225                 mlx5_mode = MLX5_INLINE_MODE_NONE;
1226                 goto out;
1227         case MLX5_CAP_INLINE_MODE_L2:
1228                 mlx5_mode = MLX5_INLINE_MODE_L2;
1229                 goto out;
1230         case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
1231                 goto query_vports;
1232         }
1233
1234 query_vports:
1235         for (vport = 1; vport <= nvfs; vport++) {
1236                 mlx5_query_nic_vport_min_inline(dev, vport, &mlx5_mode);
1237                 if (vport > 1 && prev_mlx5_mode != mlx5_mode)
1238                         return -EINVAL;
1239                 prev_mlx5_mode = mlx5_mode;
1240         }
1241
1242 out:
1243         *mode = mlx5_mode;
1244         return 0;
1245 }
1246
1247 int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap,
1248                                         struct netlink_ext_ack *extack)
1249 {
1250         struct mlx5_core_dev *dev = devlink_priv(devlink);
1251         struct mlx5_eswitch *esw = dev->priv.eswitch;
1252         int err;
1253
1254         err = mlx5_devlink_eswitch_check(devlink);
1255         if (err)
1256                 return err;
1257
1258         if (encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE &&
1259             (!MLX5_CAP_ESW_FLOWTABLE_FDB(dev, encap) ||
1260              !MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap)))
1261                 return -EOPNOTSUPP;
1262
1263         if (encap && encap != DEVLINK_ESWITCH_ENCAP_MODE_BASIC)
1264                 return -EOPNOTSUPP;
1265
1266         if (esw->mode == SRIOV_LEGACY) {
1267                 esw->offloads.encap = encap;
1268                 return 0;
1269         }
1270
1271         if (esw->offloads.encap == encap)
1272                 return 0;
1273
1274         if (esw->offloads.num_flows > 0) {
1275                 NL_SET_ERR_MSG_MOD(extack,
1276                                    "Can't set encapsulation when flows are configured");
1277                 return -EOPNOTSUPP;
1278         }
1279
1280         esw_destroy_offloads_fast_fdb_table(esw);
1281
1282         esw->offloads.encap = encap;
1283         err = esw_create_offloads_fast_fdb_table(esw);
1284         if (err) {
1285                 NL_SET_ERR_MSG_MOD(extack,
1286                                    "Failed re-creating fast FDB table");
1287                 esw->offloads.encap = !encap;
1288                 (void)esw_create_offloads_fast_fdb_table(esw);
1289         }
1290         return err;
1291 }
1292
1293 int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink, u8 *encap)
1294 {
1295         struct mlx5_core_dev *dev = devlink_priv(devlink);
1296         struct mlx5_eswitch *esw = dev->priv.eswitch;
1297         int err;
1298
1299         err = mlx5_devlink_eswitch_check(devlink);
1300         if (err)
1301                 return err;
1302
1303         *encap = esw->offloads.encap;
1304         return 0;
1305 }
1306
1307 void mlx5_eswitch_register_vport_rep(struct mlx5_eswitch *esw,
1308                                      int vport_index,
1309                                      struct mlx5_eswitch_rep_if *__rep_if,
1310                                      u8 rep_type)
1311 {
1312         struct mlx5_esw_offload *offloads = &esw->offloads;
1313         struct mlx5_eswitch_rep_if *rep_if;
1314
1315         rep_if = &offloads->vport_reps[vport_index].rep_if[rep_type];
1316
1317         rep_if->load   = __rep_if->load;
1318         rep_if->unload = __rep_if->unload;
1319         rep_if->get_proto_dev = __rep_if->get_proto_dev;
1320         rep_if->priv = __rep_if->priv;
1321
1322         rep_if->valid = true;
1323 }
1324 EXPORT_SYMBOL(mlx5_eswitch_register_vport_rep);
1325
1326 void mlx5_eswitch_unregister_vport_rep(struct mlx5_eswitch *esw,
1327                                        int vport_index, u8 rep_type)
1328 {
1329         struct mlx5_esw_offload *offloads = &esw->offloads;
1330         struct mlx5_eswitch_rep *rep;
1331
1332         rep = &offloads->vport_reps[vport_index];
1333
1334         if (esw->mode == SRIOV_OFFLOADS && esw->vports[vport_index].enabled)
1335                 rep->rep_if[rep_type].unload(rep);
1336
1337         rep->rep_if[rep_type].valid = false;
1338 }
1339 EXPORT_SYMBOL(mlx5_eswitch_unregister_vport_rep);
1340
1341 void *mlx5_eswitch_get_uplink_priv(struct mlx5_eswitch *esw, u8 rep_type)
1342 {
1343 #define UPLINK_REP_INDEX 0
1344         struct mlx5_esw_offload *offloads = &esw->offloads;
1345         struct mlx5_eswitch_rep *rep;
1346
1347         rep = &offloads->vport_reps[UPLINK_REP_INDEX];
1348         return rep->rep_if[rep_type].priv;
1349 }
1350
1351 void *mlx5_eswitch_get_proto_dev(struct mlx5_eswitch *esw,
1352                                  int vport,
1353                                  u8 rep_type)
1354 {
1355         struct mlx5_esw_offload *offloads = &esw->offloads;
1356         struct mlx5_eswitch_rep *rep;
1357
1358         if (vport == FDB_UPLINK_VPORT)
1359                 vport = UPLINK_REP_INDEX;
1360
1361         rep = &offloads->vport_reps[vport];
1362
1363         if (rep->rep_if[rep_type].valid &&
1364             rep->rep_if[rep_type].get_proto_dev)
1365                 return rep->rep_if[rep_type].get_proto_dev(rep);
1366         return NULL;
1367 }
1368 EXPORT_SYMBOL(mlx5_eswitch_get_proto_dev);
1369
1370 void *mlx5_eswitch_uplink_get_proto_dev(struct mlx5_eswitch *esw, u8 rep_type)
1371 {
1372         return mlx5_eswitch_get_proto_dev(esw, UPLINK_REP_INDEX, rep_type);
1373 }
1374 EXPORT_SYMBOL(mlx5_eswitch_uplink_get_proto_dev);
1375
1376 struct mlx5_eswitch_rep *mlx5_eswitch_vport_rep(struct mlx5_eswitch *esw,
1377                                                 int vport)
1378 {
1379         return &esw->offloads.vport_reps[vport];
1380 }
1381 EXPORT_SYMBOL(mlx5_eswitch_vport_rep);