devlink: Add extack for eswitch operations
[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                 esw_warn(esw->dev, "Can't set offloads mode, SRIOV legacy not enabled\n");
820                 return -EINVAL;
821         }
822
823         mlx5_eswitch_disable_sriov(esw);
824         err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_OFFLOADS);
825         if (err) {
826                 esw_warn(esw->dev, "Failed setting eswitch to offloads, err %d\n", err);
827                 err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
828                 if (err1)
829                         esw_warn(esw->dev, "Failed setting eswitch back to legacy, err %d\n", err1);
830         }
831         if (esw->offloads.inline_mode == MLX5_INLINE_MODE_NONE) {
832                 if (mlx5_eswitch_inline_mode_get(esw,
833                                                  num_vfs,
834                                                  &esw->offloads.inline_mode)) {
835                         esw->offloads.inline_mode = MLX5_INLINE_MODE_L2;
836                         esw_warn(esw->dev, "Inline mode is different between vports\n");
837                 }
838         }
839         return err;
840 }
841
842 void esw_offloads_cleanup_reps(struct mlx5_eswitch *esw)
843 {
844         kfree(esw->offloads.vport_reps);
845 }
846
847 int esw_offloads_init_reps(struct mlx5_eswitch *esw)
848 {
849         int total_vfs = MLX5_TOTAL_VPORTS(esw->dev);
850         struct mlx5_core_dev *dev = esw->dev;
851         struct mlx5_esw_offload *offloads;
852         struct mlx5_eswitch_rep *rep;
853         u8 hw_id[ETH_ALEN];
854         int vport;
855
856         esw->offloads.vport_reps = kcalloc(total_vfs,
857                                            sizeof(struct mlx5_eswitch_rep),
858                                            GFP_KERNEL);
859         if (!esw->offloads.vport_reps)
860                 return -ENOMEM;
861
862         offloads = &esw->offloads;
863         mlx5_query_nic_vport_mac_address(dev, 0, hw_id);
864
865         for (vport = 0; vport < total_vfs; vport++) {
866                 rep = &offloads->vport_reps[vport];
867
868                 rep->vport = vport;
869                 ether_addr_copy(rep->hw_id, hw_id);
870         }
871
872         offloads->vport_reps[0].vport = FDB_UPLINK_VPORT;
873
874         return 0;
875 }
876
877 static void esw_offloads_unload_reps_type(struct mlx5_eswitch *esw, int nvports,
878                                           u8 rep_type)
879 {
880         struct mlx5_eswitch_rep *rep;
881         int vport;
882
883         for (vport = nvports - 1; vport >= 0; vport--) {
884                 rep = &esw->offloads.vport_reps[vport];
885                 if (!rep->rep_if[rep_type].valid)
886                         continue;
887
888                 rep->rep_if[rep_type].unload(rep);
889         }
890 }
891
892 static void esw_offloads_unload_reps(struct mlx5_eswitch *esw, int nvports)
893 {
894         u8 rep_type = NUM_REP_TYPES;
895
896         while (rep_type-- > 0)
897                 esw_offloads_unload_reps_type(esw, nvports, rep_type);
898 }
899
900 static int esw_offloads_load_reps_type(struct mlx5_eswitch *esw, int nvports,
901                                        u8 rep_type)
902 {
903         struct mlx5_eswitch_rep *rep;
904         int vport;
905         int err;
906
907         for (vport = 0; vport < nvports; vport++) {
908                 rep = &esw->offloads.vport_reps[vport];
909                 if (!rep->rep_if[rep_type].valid)
910                         continue;
911
912                 err = rep->rep_if[rep_type].load(esw->dev, rep);
913                 if (err)
914                         goto err_reps;
915         }
916
917         return 0;
918
919 err_reps:
920         esw_offloads_unload_reps_type(esw, vport, rep_type);
921         return err;
922 }
923
924 static int esw_offloads_load_reps(struct mlx5_eswitch *esw, int nvports)
925 {
926         u8 rep_type = 0;
927         int err;
928
929         for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++) {
930                 err = esw_offloads_load_reps_type(esw, nvports, rep_type);
931                 if (err)
932                         goto err_reps;
933         }
934
935         return err;
936
937 err_reps:
938         while (rep_type-- > 0)
939                 esw_offloads_unload_reps_type(esw, nvports, rep_type);
940         return err;
941 }
942
943 int esw_offloads_init(struct mlx5_eswitch *esw, int nvports)
944 {
945         int err;
946
947         err = esw_create_offloads_fdb_tables(esw, nvports);
948         if (err)
949                 return err;
950
951         err = esw_create_offloads_table(esw);
952         if (err)
953                 goto create_ft_err;
954
955         err = esw_create_vport_rx_group(esw);
956         if (err)
957                 goto create_fg_err;
958
959         err = esw_offloads_load_reps(esw, nvports);
960         if (err)
961                 goto err_reps;
962
963         return 0;
964
965 err_reps:
966         esw_destroy_vport_rx_group(esw);
967
968 create_fg_err:
969         esw_destroy_offloads_table(esw);
970
971 create_ft_err:
972         esw_destroy_offloads_fdb_tables(esw);
973
974         return err;
975 }
976
977 static int esw_offloads_stop(struct mlx5_eswitch *esw,
978                              struct netlink_ext_ack *extack)
979 {
980         int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs;
981
982         mlx5_eswitch_disable_sriov(esw);
983         err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
984         if (err) {
985                 esw_warn(esw->dev, "Failed setting eswitch to legacy, err %d\n", err);
986                 err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_OFFLOADS);
987                 if (err1)
988                         esw_warn(esw->dev, "Failed setting eswitch back to offloads, err %d\n", err);
989         }
990
991         /* enable back PF RoCE */
992         mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
993
994         return err;
995 }
996
997 void esw_offloads_cleanup(struct mlx5_eswitch *esw, int nvports)
998 {
999         esw_offloads_unload_reps(esw, nvports);
1000         esw_destroy_vport_rx_group(esw);
1001         esw_destroy_offloads_table(esw);
1002         esw_destroy_offloads_fdb_tables(esw);
1003 }
1004
1005 static int esw_mode_from_devlink(u16 mode, u16 *mlx5_mode)
1006 {
1007         switch (mode) {
1008         case DEVLINK_ESWITCH_MODE_LEGACY:
1009                 *mlx5_mode = SRIOV_LEGACY;
1010                 break;
1011         case DEVLINK_ESWITCH_MODE_SWITCHDEV:
1012                 *mlx5_mode = SRIOV_OFFLOADS;
1013                 break;
1014         default:
1015                 return -EINVAL;
1016         }
1017
1018         return 0;
1019 }
1020
1021 static int esw_mode_to_devlink(u16 mlx5_mode, u16 *mode)
1022 {
1023         switch (mlx5_mode) {
1024         case SRIOV_LEGACY:
1025                 *mode = DEVLINK_ESWITCH_MODE_LEGACY;
1026                 break;
1027         case SRIOV_OFFLOADS:
1028                 *mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
1029                 break;
1030         default:
1031                 return -EINVAL;
1032         }
1033
1034         return 0;
1035 }
1036
1037 static int esw_inline_mode_from_devlink(u8 mode, u8 *mlx5_mode)
1038 {
1039         switch (mode) {
1040         case DEVLINK_ESWITCH_INLINE_MODE_NONE:
1041                 *mlx5_mode = MLX5_INLINE_MODE_NONE;
1042                 break;
1043         case DEVLINK_ESWITCH_INLINE_MODE_LINK:
1044                 *mlx5_mode = MLX5_INLINE_MODE_L2;
1045                 break;
1046         case DEVLINK_ESWITCH_INLINE_MODE_NETWORK:
1047                 *mlx5_mode = MLX5_INLINE_MODE_IP;
1048                 break;
1049         case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT:
1050                 *mlx5_mode = MLX5_INLINE_MODE_TCP_UDP;
1051                 break;
1052         default:
1053                 return -EINVAL;
1054         }
1055
1056         return 0;
1057 }
1058
1059 static int esw_inline_mode_to_devlink(u8 mlx5_mode, u8 *mode)
1060 {
1061         switch (mlx5_mode) {
1062         case MLX5_INLINE_MODE_NONE:
1063                 *mode = DEVLINK_ESWITCH_INLINE_MODE_NONE;
1064                 break;
1065         case MLX5_INLINE_MODE_L2:
1066                 *mode = DEVLINK_ESWITCH_INLINE_MODE_LINK;
1067                 break;
1068         case MLX5_INLINE_MODE_IP:
1069                 *mode = DEVLINK_ESWITCH_INLINE_MODE_NETWORK;
1070                 break;
1071         case MLX5_INLINE_MODE_TCP_UDP:
1072                 *mode = DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT;
1073                 break;
1074         default:
1075                 return -EINVAL;
1076         }
1077
1078         return 0;
1079 }
1080
1081 static int mlx5_devlink_eswitch_check(struct devlink *devlink)
1082 {
1083         struct mlx5_core_dev *dev = devlink_priv(devlink);
1084
1085         if (MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
1086                 return -EOPNOTSUPP;
1087
1088         if(!MLX5_ESWITCH_MANAGER(dev))
1089                 return -EPERM;
1090
1091         if (dev->priv.eswitch->mode == SRIOV_NONE)
1092                 return -EOPNOTSUPP;
1093
1094         return 0;
1095 }
1096
1097 int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
1098                                   struct netlink_ext_ack *extack)
1099 {
1100         struct mlx5_core_dev *dev = devlink_priv(devlink);
1101         u16 cur_mlx5_mode, mlx5_mode = 0;
1102         int err;
1103
1104         err = mlx5_devlink_eswitch_check(devlink);
1105         if (err)
1106                 return err;
1107
1108         cur_mlx5_mode = dev->priv.eswitch->mode;
1109
1110         if (esw_mode_from_devlink(mode, &mlx5_mode))
1111                 return -EINVAL;
1112
1113         if (cur_mlx5_mode == mlx5_mode)
1114                 return 0;
1115
1116         if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV)
1117                 return esw_offloads_start(dev->priv.eswitch, extack);
1118         else if (mode == DEVLINK_ESWITCH_MODE_LEGACY)
1119                 return esw_offloads_stop(dev->priv.eswitch, extack);
1120         else
1121                 return -EINVAL;
1122 }
1123
1124 int mlx5_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
1125 {
1126         struct mlx5_core_dev *dev = devlink_priv(devlink);
1127         int err;
1128
1129         err = mlx5_devlink_eswitch_check(devlink);
1130         if (err)
1131                 return err;
1132
1133         return esw_mode_to_devlink(dev->priv.eswitch->mode, mode);
1134 }
1135
1136 int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode,
1137                                          struct netlink_ext_ack *extack)
1138 {
1139         struct mlx5_core_dev *dev = devlink_priv(devlink);
1140         struct mlx5_eswitch *esw = dev->priv.eswitch;
1141         int err, vport;
1142         u8 mlx5_mode;
1143
1144         err = mlx5_devlink_eswitch_check(devlink);
1145         if (err)
1146                 return err;
1147
1148         switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
1149         case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
1150                 if (mode == DEVLINK_ESWITCH_INLINE_MODE_NONE)
1151                         return 0;
1152                 /* fall through */
1153         case MLX5_CAP_INLINE_MODE_L2:
1154                 esw_warn(dev, "Inline mode can't be set\n");
1155                 return -EOPNOTSUPP;
1156         case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
1157                 break;
1158         }
1159
1160         if (esw->offloads.num_flows > 0) {
1161                 esw_warn(dev, "Can't set inline mode when flows are configured\n");
1162                 return -EOPNOTSUPP;
1163         }
1164
1165         err = esw_inline_mode_from_devlink(mode, &mlx5_mode);
1166         if (err)
1167                 goto out;
1168
1169         for (vport = 1; vport < esw->enabled_vports; vport++) {
1170                 err = mlx5_modify_nic_vport_min_inline(dev, vport, mlx5_mode);
1171                 if (err) {
1172                         esw_warn(dev, "Failed to set min inline on vport %d\n",
1173                                  vport);
1174                         goto revert_inline_mode;
1175                 }
1176         }
1177
1178         esw->offloads.inline_mode = mlx5_mode;
1179         return 0;
1180
1181 revert_inline_mode:
1182         while (--vport > 0)
1183                 mlx5_modify_nic_vport_min_inline(dev,
1184                                                  vport,
1185                                                  esw->offloads.inline_mode);
1186 out:
1187         return err;
1188 }
1189
1190 int mlx5_devlink_eswitch_inline_mode_get(struct devlink *devlink, u8 *mode)
1191 {
1192         struct mlx5_core_dev *dev = devlink_priv(devlink);
1193         struct mlx5_eswitch *esw = dev->priv.eswitch;
1194         int err;
1195
1196         err = mlx5_devlink_eswitch_check(devlink);
1197         if (err)
1198                 return err;
1199
1200         return esw_inline_mode_to_devlink(esw->offloads.inline_mode, mode);
1201 }
1202
1203 int mlx5_eswitch_inline_mode_get(struct mlx5_eswitch *esw, int nvfs, u8 *mode)
1204 {
1205         u8 prev_mlx5_mode, mlx5_mode = MLX5_INLINE_MODE_L2;
1206         struct mlx5_core_dev *dev = esw->dev;
1207         int vport;
1208
1209         if (!MLX5_CAP_GEN(dev, vport_group_manager))
1210                 return -EOPNOTSUPP;
1211
1212         if (esw->mode == SRIOV_NONE)
1213                 return -EOPNOTSUPP;
1214
1215         switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
1216         case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
1217                 mlx5_mode = MLX5_INLINE_MODE_NONE;
1218                 goto out;
1219         case MLX5_CAP_INLINE_MODE_L2:
1220                 mlx5_mode = MLX5_INLINE_MODE_L2;
1221                 goto out;
1222         case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
1223                 goto query_vports;
1224         }
1225
1226 query_vports:
1227         for (vport = 1; vport <= nvfs; vport++) {
1228                 mlx5_query_nic_vport_min_inline(dev, vport, &mlx5_mode);
1229                 if (vport > 1 && prev_mlx5_mode != mlx5_mode)
1230                         return -EINVAL;
1231                 prev_mlx5_mode = mlx5_mode;
1232         }
1233
1234 out:
1235         *mode = mlx5_mode;
1236         return 0;
1237 }
1238
1239 int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap,
1240                                         struct netlink_ext_ack *extack)
1241 {
1242         struct mlx5_core_dev *dev = devlink_priv(devlink);
1243         struct mlx5_eswitch *esw = dev->priv.eswitch;
1244         int err;
1245
1246         err = mlx5_devlink_eswitch_check(devlink);
1247         if (err)
1248                 return err;
1249
1250         if (encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE &&
1251             (!MLX5_CAP_ESW_FLOWTABLE_FDB(dev, encap) ||
1252              !MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap)))
1253                 return -EOPNOTSUPP;
1254
1255         if (encap && encap != DEVLINK_ESWITCH_ENCAP_MODE_BASIC)
1256                 return -EOPNOTSUPP;
1257
1258         if (esw->mode == SRIOV_LEGACY) {
1259                 esw->offloads.encap = encap;
1260                 return 0;
1261         }
1262
1263         if (esw->offloads.encap == encap)
1264                 return 0;
1265
1266         if (esw->offloads.num_flows > 0) {
1267                 esw_warn(dev, "Can't set encapsulation when flows are configured\n");
1268                 return -EOPNOTSUPP;
1269         }
1270
1271         esw_destroy_offloads_fast_fdb_table(esw);
1272
1273         esw->offloads.encap = encap;
1274         err = esw_create_offloads_fast_fdb_table(esw);
1275         if (err) {
1276                 esw_warn(esw->dev, "Failed re-creating fast FDB table, err %d\n", err);
1277                 esw->offloads.encap = !encap;
1278                 (void)esw_create_offloads_fast_fdb_table(esw);
1279         }
1280         return err;
1281 }
1282
1283 int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink, u8 *encap)
1284 {
1285         struct mlx5_core_dev *dev = devlink_priv(devlink);
1286         struct mlx5_eswitch *esw = dev->priv.eswitch;
1287         int err;
1288
1289         err = mlx5_devlink_eswitch_check(devlink);
1290         if (err)
1291                 return err;
1292
1293         *encap = esw->offloads.encap;
1294         return 0;
1295 }
1296
1297 void mlx5_eswitch_register_vport_rep(struct mlx5_eswitch *esw,
1298                                      int vport_index,
1299                                      struct mlx5_eswitch_rep_if *__rep_if,
1300                                      u8 rep_type)
1301 {
1302         struct mlx5_esw_offload *offloads = &esw->offloads;
1303         struct mlx5_eswitch_rep_if *rep_if;
1304
1305         rep_if = &offloads->vport_reps[vport_index].rep_if[rep_type];
1306
1307         rep_if->load   = __rep_if->load;
1308         rep_if->unload = __rep_if->unload;
1309         rep_if->get_proto_dev = __rep_if->get_proto_dev;
1310         rep_if->priv = __rep_if->priv;
1311
1312         rep_if->valid = true;
1313 }
1314 EXPORT_SYMBOL(mlx5_eswitch_register_vport_rep);
1315
1316 void mlx5_eswitch_unregister_vport_rep(struct mlx5_eswitch *esw,
1317                                        int vport_index, u8 rep_type)
1318 {
1319         struct mlx5_esw_offload *offloads = &esw->offloads;
1320         struct mlx5_eswitch_rep *rep;
1321
1322         rep = &offloads->vport_reps[vport_index];
1323
1324         if (esw->mode == SRIOV_OFFLOADS && esw->vports[vport_index].enabled)
1325                 rep->rep_if[rep_type].unload(rep);
1326
1327         rep->rep_if[rep_type].valid = false;
1328 }
1329 EXPORT_SYMBOL(mlx5_eswitch_unregister_vport_rep);
1330
1331 void *mlx5_eswitch_get_uplink_priv(struct mlx5_eswitch *esw, u8 rep_type)
1332 {
1333 #define UPLINK_REP_INDEX 0
1334         struct mlx5_esw_offload *offloads = &esw->offloads;
1335         struct mlx5_eswitch_rep *rep;
1336
1337         rep = &offloads->vport_reps[UPLINK_REP_INDEX];
1338         return rep->rep_if[rep_type].priv;
1339 }
1340
1341 void *mlx5_eswitch_get_proto_dev(struct mlx5_eswitch *esw,
1342                                  int vport,
1343                                  u8 rep_type)
1344 {
1345         struct mlx5_esw_offload *offloads = &esw->offloads;
1346         struct mlx5_eswitch_rep *rep;
1347
1348         if (vport == FDB_UPLINK_VPORT)
1349                 vport = UPLINK_REP_INDEX;
1350
1351         rep = &offloads->vport_reps[vport];
1352
1353         if (rep->rep_if[rep_type].valid &&
1354             rep->rep_if[rep_type].get_proto_dev)
1355                 return rep->rep_if[rep_type].get_proto_dev(rep);
1356         return NULL;
1357 }
1358 EXPORT_SYMBOL(mlx5_eswitch_get_proto_dev);
1359
1360 void *mlx5_eswitch_uplink_get_proto_dev(struct mlx5_eswitch *esw, u8 rep_type)
1361 {
1362         return mlx5_eswitch_get_proto_dev(esw, UPLINK_REP_INDEX, rep_type);
1363 }
1364 EXPORT_SYMBOL(mlx5_eswitch_uplink_get_proto_dev);
1365
1366 struct mlx5_eswitch_rep *mlx5_eswitch_vport_rep(struct mlx5_eswitch *esw,
1367                                                 int vport)
1368 {
1369         return &esw->offloads.vport_reps[vport];
1370 }
1371 EXPORT_SYMBOL(mlx5_eswitch_vport_rep);