Merge branch 'mlx5-next' of git://git.kernel.org/pub/scm/linux/kernel/git/mellanox...
[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_PACKET_REFORMAT)
131                 flow_act.reformat_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_REFORMAT |
533                           MLX5_FLOW_TABLE_TUNNEL_EN_DECAP);
534
535         fdb = mlx5_create_auto_grouped_flow_table(root_ns, FDB_FAST_PATH,
536                                                   esw_size,
537                                                   ESW_OFFLOADS_NUM_GROUPS, 0,
538                                                   flags);
539         if (IS_ERR(fdb)) {
540                 err = PTR_ERR(fdb);
541                 esw_warn(dev, "Failed to create Fast path FDB Table err %d\n", err);
542                 goto out_namespace;
543         }
544         esw->fdb_table.offloads.fast_fdb = fdb;
545
546         if (!mlx5_esw_has_fwd_fdb(dev))
547                 goto out_namespace;
548
549         fdb = mlx5_create_auto_grouped_flow_table(root_ns, FDB_FAST_PATH,
550                                                   esw_size,
551                                                   ESW_OFFLOADS_NUM_GROUPS, 1,
552                                                   flags);
553         if (IS_ERR(fdb)) {
554                 err = PTR_ERR(fdb);
555                 esw_warn(dev, "Failed to create fwd table err %d\n", err);
556                 goto out_ft;
557         }
558         esw->fdb_table.offloads.fwd_fdb = fdb;
559
560         return err;
561
562 out_ft:
563         mlx5_destroy_flow_table(esw->fdb_table.offloads.fast_fdb);
564 out_namespace:
565         return err;
566 }
567
568 static void esw_destroy_offloads_fast_fdb_table(struct mlx5_eswitch *esw)
569 {
570         if (mlx5_esw_has_fwd_fdb(esw->dev))
571                 mlx5_destroy_flow_table(esw->fdb_table.offloads.fwd_fdb);
572         mlx5_destroy_flow_table(esw->fdb_table.offloads.fast_fdb);
573 }
574
575 #define MAX_PF_SQ 256
576 #define MAX_SQ_NVPORTS 32
577
578 static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw, int nvports)
579 {
580         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
581         struct mlx5_flow_table_attr ft_attr = {};
582         struct mlx5_core_dev *dev = esw->dev;
583         struct mlx5_flow_namespace *root_ns;
584         struct mlx5_flow_table *fdb = NULL;
585         int table_size, ix, err = 0;
586         struct mlx5_flow_group *g;
587         void *match_criteria;
588         u32 *flow_group_in;
589         u8 *dmac;
590
591         esw_debug(esw->dev, "Create offloads FDB Tables\n");
592         flow_group_in = kvzalloc(inlen, GFP_KERNEL);
593         if (!flow_group_in)
594                 return -ENOMEM;
595
596         root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
597         if (!root_ns) {
598                 esw_warn(dev, "Failed to get FDB flow namespace\n");
599                 err = -EOPNOTSUPP;
600                 goto ns_err;
601         }
602
603         err = esw_create_offloads_fast_fdb_table(esw);
604         if (err)
605                 goto fast_fdb_err;
606
607         table_size = nvports * MAX_SQ_NVPORTS + MAX_PF_SQ + 2;
608
609         ft_attr.max_fte = table_size;
610         ft_attr.prio = FDB_SLOW_PATH;
611
612         fdb = mlx5_create_flow_table(root_ns, &ft_attr);
613         if (IS_ERR(fdb)) {
614                 err = PTR_ERR(fdb);
615                 esw_warn(dev, "Failed to create slow path FDB Table err %d\n", err);
616                 goto slow_fdb_err;
617         }
618         esw->fdb_table.offloads.slow_fdb = fdb;
619
620         /* create send-to-vport group */
621         memset(flow_group_in, 0, inlen);
622         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
623                  MLX5_MATCH_MISC_PARAMETERS);
624
625         match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
626
627         MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_sqn);
628         MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_port);
629
630         ix = nvports * MAX_SQ_NVPORTS + MAX_PF_SQ;
631         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
632         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, ix - 1);
633
634         g = mlx5_create_flow_group(fdb, flow_group_in);
635         if (IS_ERR(g)) {
636                 err = PTR_ERR(g);
637                 esw_warn(dev, "Failed to create send-to-vport flow group err(%d)\n", err);
638                 goto send_vport_err;
639         }
640         esw->fdb_table.offloads.send_to_vport_grp = g;
641
642         /* create miss group */
643         memset(flow_group_in, 0, inlen);
644         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
645                  MLX5_MATCH_OUTER_HEADERS);
646         match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in,
647                                       match_criteria);
648         dmac = MLX5_ADDR_OF(fte_match_param, match_criteria,
649                             outer_headers.dmac_47_16);
650         dmac[0] = 0x01;
651
652         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ix);
653         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, ix + 2);
654
655         g = mlx5_create_flow_group(fdb, flow_group_in);
656         if (IS_ERR(g)) {
657                 err = PTR_ERR(g);
658                 esw_warn(dev, "Failed to create miss flow group err(%d)\n", err);
659                 goto miss_err;
660         }
661         esw->fdb_table.offloads.miss_grp = g;
662
663         err = esw_add_fdb_miss_rule(esw);
664         if (err)
665                 goto miss_rule_err;
666
667         kvfree(flow_group_in);
668         return 0;
669
670 miss_rule_err:
671         mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
672 miss_err:
673         mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
674 send_vport_err:
675         mlx5_destroy_flow_table(esw->fdb_table.offloads.slow_fdb);
676 slow_fdb_err:
677         esw_destroy_offloads_fast_fdb_table(esw);
678 fast_fdb_err:
679 ns_err:
680         kvfree(flow_group_in);
681         return err;
682 }
683
684 static void esw_destroy_offloads_fdb_tables(struct mlx5_eswitch *esw)
685 {
686         if (!esw->fdb_table.offloads.fast_fdb)
687                 return;
688
689         esw_debug(esw->dev, "Destroy offloads FDB Tables\n");
690         mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_multi);
691         mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_uni);
692         mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
693         mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
694
695         mlx5_destroy_flow_table(esw->fdb_table.offloads.slow_fdb);
696         esw_destroy_offloads_fast_fdb_table(esw);
697 }
698
699 static int esw_create_offloads_table(struct mlx5_eswitch *esw)
700 {
701         struct mlx5_flow_table_attr ft_attr = {};
702         struct mlx5_core_dev *dev = esw->dev;
703         struct mlx5_flow_table *ft_offloads;
704         struct mlx5_flow_namespace *ns;
705         int err = 0;
706
707         ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_OFFLOADS);
708         if (!ns) {
709                 esw_warn(esw->dev, "Failed to get offloads flow namespace\n");
710                 return -EOPNOTSUPP;
711         }
712
713         ft_attr.max_fte = dev->priv.sriov.num_vfs + 2;
714
715         ft_offloads = mlx5_create_flow_table(ns, &ft_attr);
716         if (IS_ERR(ft_offloads)) {
717                 err = PTR_ERR(ft_offloads);
718                 esw_warn(esw->dev, "Failed to create offloads table, err %d\n", err);
719                 return err;
720         }
721
722         esw->offloads.ft_offloads = ft_offloads;
723         return 0;
724 }
725
726 static void esw_destroy_offloads_table(struct mlx5_eswitch *esw)
727 {
728         struct mlx5_esw_offload *offloads = &esw->offloads;
729
730         mlx5_destroy_flow_table(offloads->ft_offloads);
731 }
732
733 static int esw_create_vport_rx_group(struct mlx5_eswitch *esw)
734 {
735         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
736         struct mlx5_flow_group *g;
737         struct mlx5_priv *priv = &esw->dev->priv;
738         u32 *flow_group_in;
739         void *match_criteria, *misc;
740         int err = 0;
741         int nvports = priv->sriov.num_vfs + 2;
742
743         flow_group_in = kvzalloc(inlen, GFP_KERNEL);
744         if (!flow_group_in)
745                 return -ENOMEM;
746
747         /* create vport rx group */
748         memset(flow_group_in, 0, inlen);
749         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
750                  MLX5_MATCH_MISC_PARAMETERS);
751
752         match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
753         misc = MLX5_ADDR_OF(fte_match_param, match_criteria, misc_parameters);
754         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
755
756         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
757         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, nvports - 1);
758
759         g = mlx5_create_flow_group(esw->offloads.ft_offloads, flow_group_in);
760
761         if (IS_ERR(g)) {
762                 err = PTR_ERR(g);
763                 mlx5_core_warn(esw->dev, "Failed to create vport rx group err %d\n", err);
764                 goto out;
765         }
766
767         esw->offloads.vport_rx_group = g;
768 out:
769         kvfree(flow_group_in);
770         return err;
771 }
772
773 static void esw_destroy_vport_rx_group(struct mlx5_eswitch *esw)
774 {
775         mlx5_destroy_flow_group(esw->offloads.vport_rx_group);
776 }
777
778 struct mlx5_flow_handle *
779 mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, int vport,
780                                   struct mlx5_flow_destination *dest)
781 {
782         struct mlx5_flow_act flow_act = {0};
783         struct mlx5_flow_handle *flow_rule;
784         struct mlx5_flow_spec *spec;
785         void *misc;
786
787         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
788         if (!spec) {
789                 flow_rule = ERR_PTR(-ENOMEM);
790                 goto out;
791         }
792
793         misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
794         MLX5_SET(fte_match_set_misc, misc, source_port, vport);
795
796         misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
797         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
798
799         spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
800
801         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
802         flow_rule = mlx5_add_flow_rules(esw->offloads.ft_offloads, spec,
803                                         &flow_act, dest, 1);
804         if (IS_ERR(flow_rule)) {
805                 esw_warn(esw->dev, "fs offloads: Failed to add vport rx rule err %ld\n", PTR_ERR(flow_rule));
806                 goto out;
807         }
808
809 out:
810         kvfree(spec);
811         return flow_rule;
812 }
813
814 static int esw_offloads_start(struct mlx5_eswitch *esw,
815                               struct netlink_ext_ack *extack)
816 {
817         int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs;
818
819         if (esw->mode != SRIOV_LEGACY) {
820                 NL_SET_ERR_MSG_MOD(extack,
821                                    "Can't set offloads mode, SRIOV legacy not enabled");
822                 return -EINVAL;
823         }
824
825         mlx5_eswitch_disable_sriov(esw);
826         err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_OFFLOADS);
827         if (err) {
828                 NL_SET_ERR_MSG_MOD(extack,
829                                    "Failed setting eswitch to offloads");
830                 err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
831                 if (err1) {
832                         NL_SET_ERR_MSG_MOD(extack,
833                                            "Failed setting eswitch back to legacy");
834                 }
835         }
836         if (esw->offloads.inline_mode == MLX5_INLINE_MODE_NONE) {
837                 if (mlx5_eswitch_inline_mode_get(esw,
838                                                  num_vfs,
839                                                  &esw->offloads.inline_mode)) {
840                         esw->offloads.inline_mode = MLX5_INLINE_MODE_L2;
841                         NL_SET_ERR_MSG_MOD(extack,
842                                            "Inline mode is different between vports");
843                 }
844         }
845         return err;
846 }
847
848 void esw_offloads_cleanup_reps(struct mlx5_eswitch *esw)
849 {
850         kfree(esw->offloads.vport_reps);
851 }
852
853 int esw_offloads_init_reps(struct mlx5_eswitch *esw)
854 {
855         int total_vfs = MLX5_TOTAL_VPORTS(esw->dev);
856         struct mlx5_core_dev *dev = esw->dev;
857         struct mlx5_esw_offload *offloads;
858         struct mlx5_eswitch_rep *rep;
859         u8 hw_id[ETH_ALEN];
860         int vport;
861
862         esw->offloads.vport_reps = kcalloc(total_vfs,
863                                            sizeof(struct mlx5_eswitch_rep),
864                                            GFP_KERNEL);
865         if (!esw->offloads.vport_reps)
866                 return -ENOMEM;
867
868         offloads = &esw->offloads;
869         mlx5_query_nic_vport_mac_address(dev, 0, hw_id);
870
871         for (vport = 0; vport < total_vfs; vport++) {
872                 rep = &offloads->vport_reps[vport];
873
874                 rep->vport = vport;
875                 ether_addr_copy(rep->hw_id, hw_id);
876         }
877
878         offloads->vport_reps[0].vport = FDB_UPLINK_VPORT;
879
880         return 0;
881 }
882
883 static void esw_offloads_unload_reps_type(struct mlx5_eswitch *esw, int nvports,
884                                           u8 rep_type)
885 {
886         struct mlx5_eswitch_rep *rep;
887         int vport;
888
889         for (vport = nvports - 1; vport >= 0; vport--) {
890                 rep = &esw->offloads.vport_reps[vport];
891                 if (!rep->rep_if[rep_type].valid)
892                         continue;
893
894                 rep->rep_if[rep_type].unload(rep);
895         }
896 }
897
898 static void esw_offloads_unload_reps(struct mlx5_eswitch *esw, int nvports)
899 {
900         u8 rep_type = NUM_REP_TYPES;
901
902         while (rep_type-- > 0)
903                 esw_offloads_unload_reps_type(esw, nvports, rep_type);
904 }
905
906 static int esw_offloads_load_reps_type(struct mlx5_eswitch *esw, int nvports,
907                                        u8 rep_type)
908 {
909         struct mlx5_eswitch_rep *rep;
910         int vport;
911         int err;
912
913         for (vport = 0; vport < nvports; vport++) {
914                 rep = &esw->offloads.vport_reps[vport];
915                 if (!rep->rep_if[rep_type].valid)
916                         continue;
917
918                 err = rep->rep_if[rep_type].load(esw->dev, rep);
919                 if (err)
920                         goto err_reps;
921         }
922
923         return 0;
924
925 err_reps:
926         esw_offloads_unload_reps_type(esw, vport, rep_type);
927         return err;
928 }
929
930 static int esw_offloads_load_reps(struct mlx5_eswitch *esw, int nvports)
931 {
932         u8 rep_type = 0;
933         int err;
934
935         for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++) {
936                 err = esw_offloads_load_reps_type(esw, nvports, rep_type);
937                 if (err)
938                         goto err_reps;
939         }
940
941         return err;
942
943 err_reps:
944         while (rep_type-- > 0)
945                 esw_offloads_unload_reps_type(esw, nvports, rep_type);
946         return err;
947 }
948
949 int esw_offloads_init(struct mlx5_eswitch *esw, int nvports)
950 {
951         int err;
952
953         err = esw_create_offloads_fdb_tables(esw, nvports);
954         if (err)
955                 return err;
956
957         err = esw_create_offloads_table(esw);
958         if (err)
959                 goto create_ft_err;
960
961         err = esw_create_vport_rx_group(esw);
962         if (err)
963                 goto create_fg_err;
964
965         err = esw_offloads_load_reps(esw, nvports);
966         if (err)
967                 goto err_reps;
968
969         return 0;
970
971 err_reps:
972         esw_destroy_vport_rx_group(esw);
973
974 create_fg_err:
975         esw_destroy_offloads_table(esw);
976
977 create_ft_err:
978         esw_destroy_offloads_fdb_tables(esw);
979
980         return err;
981 }
982
983 static int esw_offloads_stop(struct mlx5_eswitch *esw,
984                              struct netlink_ext_ack *extack)
985 {
986         int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs;
987
988         mlx5_eswitch_disable_sriov(esw);
989         err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
990         if (err) {
991                 NL_SET_ERR_MSG_MOD(extack, "Failed setting eswitch to legacy");
992                 err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_OFFLOADS);
993                 if (err1) {
994                         NL_SET_ERR_MSG_MOD(extack,
995                                            "Failed setting eswitch back to offloads");
996                 }
997         }
998
999         /* enable back PF RoCE */
1000         mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
1001
1002         return err;
1003 }
1004
1005 void esw_offloads_cleanup(struct mlx5_eswitch *esw, int nvports)
1006 {
1007         esw_offloads_unload_reps(esw, nvports);
1008         esw_destroy_vport_rx_group(esw);
1009         esw_destroy_offloads_table(esw);
1010         esw_destroy_offloads_fdb_tables(esw);
1011 }
1012
1013 static int esw_mode_from_devlink(u16 mode, u16 *mlx5_mode)
1014 {
1015         switch (mode) {
1016         case DEVLINK_ESWITCH_MODE_LEGACY:
1017                 *mlx5_mode = SRIOV_LEGACY;
1018                 break;
1019         case DEVLINK_ESWITCH_MODE_SWITCHDEV:
1020                 *mlx5_mode = SRIOV_OFFLOADS;
1021                 break;
1022         default:
1023                 return -EINVAL;
1024         }
1025
1026         return 0;
1027 }
1028
1029 static int esw_mode_to_devlink(u16 mlx5_mode, u16 *mode)
1030 {
1031         switch (mlx5_mode) {
1032         case SRIOV_LEGACY:
1033                 *mode = DEVLINK_ESWITCH_MODE_LEGACY;
1034                 break;
1035         case SRIOV_OFFLOADS:
1036                 *mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
1037                 break;
1038         default:
1039                 return -EINVAL;
1040         }
1041
1042         return 0;
1043 }
1044
1045 static int esw_inline_mode_from_devlink(u8 mode, u8 *mlx5_mode)
1046 {
1047         switch (mode) {
1048         case DEVLINK_ESWITCH_INLINE_MODE_NONE:
1049                 *mlx5_mode = MLX5_INLINE_MODE_NONE;
1050                 break;
1051         case DEVLINK_ESWITCH_INLINE_MODE_LINK:
1052                 *mlx5_mode = MLX5_INLINE_MODE_L2;
1053                 break;
1054         case DEVLINK_ESWITCH_INLINE_MODE_NETWORK:
1055                 *mlx5_mode = MLX5_INLINE_MODE_IP;
1056                 break;
1057         case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT:
1058                 *mlx5_mode = MLX5_INLINE_MODE_TCP_UDP;
1059                 break;
1060         default:
1061                 return -EINVAL;
1062         }
1063
1064         return 0;
1065 }
1066
1067 static int esw_inline_mode_to_devlink(u8 mlx5_mode, u8 *mode)
1068 {
1069         switch (mlx5_mode) {
1070         case MLX5_INLINE_MODE_NONE:
1071                 *mode = DEVLINK_ESWITCH_INLINE_MODE_NONE;
1072                 break;
1073         case MLX5_INLINE_MODE_L2:
1074                 *mode = DEVLINK_ESWITCH_INLINE_MODE_LINK;
1075                 break;
1076         case MLX5_INLINE_MODE_IP:
1077                 *mode = DEVLINK_ESWITCH_INLINE_MODE_NETWORK;
1078                 break;
1079         case MLX5_INLINE_MODE_TCP_UDP:
1080                 *mode = DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT;
1081                 break;
1082         default:
1083                 return -EINVAL;
1084         }
1085
1086         return 0;
1087 }
1088
1089 static int mlx5_devlink_eswitch_check(struct devlink *devlink)
1090 {
1091         struct mlx5_core_dev *dev = devlink_priv(devlink);
1092
1093         if (MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
1094                 return -EOPNOTSUPP;
1095
1096         if(!MLX5_ESWITCH_MANAGER(dev))
1097                 return -EPERM;
1098
1099         if (dev->priv.eswitch->mode == SRIOV_NONE)
1100                 return -EOPNOTSUPP;
1101
1102         return 0;
1103 }
1104
1105 int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
1106                                   struct netlink_ext_ack *extack)
1107 {
1108         struct mlx5_core_dev *dev = devlink_priv(devlink);
1109         u16 cur_mlx5_mode, mlx5_mode = 0;
1110         int err;
1111
1112         err = mlx5_devlink_eswitch_check(devlink);
1113         if (err)
1114                 return err;
1115
1116         cur_mlx5_mode = dev->priv.eswitch->mode;
1117
1118         if (esw_mode_from_devlink(mode, &mlx5_mode))
1119                 return -EINVAL;
1120
1121         if (cur_mlx5_mode == mlx5_mode)
1122                 return 0;
1123
1124         if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV)
1125                 return esw_offloads_start(dev->priv.eswitch, extack);
1126         else if (mode == DEVLINK_ESWITCH_MODE_LEGACY)
1127                 return esw_offloads_stop(dev->priv.eswitch, extack);
1128         else
1129                 return -EINVAL;
1130 }
1131
1132 int mlx5_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
1133 {
1134         struct mlx5_core_dev *dev = devlink_priv(devlink);
1135         int err;
1136
1137         err = mlx5_devlink_eswitch_check(devlink);
1138         if (err)
1139                 return err;
1140
1141         return esw_mode_to_devlink(dev->priv.eswitch->mode, mode);
1142 }
1143
1144 int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode,
1145                                          struct netlink_ext_ack *extack)
1146 {
1147         struct mlx5_core_dev *dev = devlink_priv(devlink);
1148         struct mlx5_eswitch *esw = dev->priv.eswitch;
1149         int err, vport;
1150         u8 mlx5_mode;
1151
1152         err = mlx5_devlink_eswitch_check(devlink);
1153         if (err)
1154                 return err;
1155
1156         switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
1157         case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
1158                 if (mode == DEVLINK_ESWITCH_INLINE_MODE_NONE)
1159                         return 0;
1160                 /* fall through */
1161         case MLX5_CAP_INLINE_MODE_L2:
1162                 NL_SET_ERR_MSG_MOD(extack, "Inline mode can't be set");
1163                 return -EOPNOTSUPP;
1164         case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
1165                 break;
1166         }
1167
1168         if (esw->offloads.num_flows > 0) {
1169                 NL_SET_ERR_MSG_MOD(extack,
1170                                    "Can't set inline mode when flows are configured");
1171                 return -EOPNOTSUPP;
1172         }
1173
1174         err = esw_inline_mode_from_devlink(mode, &mlx5_mode);
1175         if (err)
1176                 goto out;
1177
1178         for (vport = 1; vport < esw->enabled_vports; vport++) {
1179                 err = mlx5_modify_nic_vport_min_inline(dev, vport, mlx5_mode);
1180                 if (err) {
1181                         NL_SET_ERR_MSG_MOD(extack,
1182                                            "Failed to set min inline on vport");
1183                         goto revert_inline_mode;
1184                 }
1185         }
1186
1187         esw->offloads.inline_mode = mlx5_mode;
1188         return 0;
1189
1190 revert_inline_mode:
1191         while (--vport > 0)
1192                 mlx5_modify_nic_vport_min_inline(dev,
1193                                                  vport,
1194                                                  esw->offloads.inline_mode);
1195 out:
1196         return err;
1197 }
1198
1199 int mlx5_devlink_eswitch_inline_mode_get(struct devlink *devlink, u8 *mode)
1200 {
1201         struct mlx5_core_dev *dev = devlink_priv(devlink);
1202         struct mlx5_eswitch *esw = dev->priv.eswitch;
1203         int err;
1204
1205         err = mlx5_devlink_eswitch_check(devlink);
1206         if (err)
1207                 return err;
1208
1209         return esw_inline_mode_to_devlink(esw->offloads.inline_mode, mode);
1210 }
1211
1212 int mlx5_eswitch_inline_mode_get(struct mlx5_eswitch *esw, int nvfs, u8 *mode)
1213 {
1214         u8 prev_mlx5_mode, mlx5_mode = MLX5_INLINE_MODE_L2;
1215         struct mlx5_core_dev *dev = esw->dev;
1216         int vport;
1217
1218         if (!MLX5_CAP_GEN(dev, vport_group_manager))
1219                 return -EOPNOTSUPP;
1220
1221         if (esw->mode == SRIOV_NONE)
1222                 return -EOPNOTSUPP;
1223
1224         switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
1225         case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
1226                 mlx5_mode = MLX5_INLINE_MODE_NONE;
1227                 goto out;
1228         case MLX5_CAP_INLINE_MODE_L2:
1229                 mlx5_mode = MLX5_INLINE_MODE_L2;
1230                 goto out;
1231         case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
1232                 goto query_vports;
1233         }
1234
1235 query_vports:
1236         for (vport = 1; vport <= nvfs; vport++) {
1237                 mlx5_query_nic_vport_min_inline(dev, vport, &mlx5_mode);
1238                 if (vport > 1 && prev_mlx5_mode != mlx5_mode)
1239                         return -EINVAL;
1240                 prev_mlx5_mode = mlx5_mode;
1241         }
1242
1243 out:
1244         *mode = mlx5_mode;
1245         return 0;
1246 }
1247
1248 int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap,
1249                                         struct netlink_ext_ack *extack)
1250 {
1251         struct mlx5_core_dev *dev = devlink_priv(devlink);
1252         struct mlx5_eswitch *esw = dev->priv.eswitch;
1253         int err;
1254
1255         err = mlx5_devlink_eswitch_check(devlink);
1256         if (err)
1257                 return err;
1258
1259         if (encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE &&
1260             (!MLX5_CAP_ESW_FLOWTABLE_FDB(dev, reformat) ||
1261              !MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap)))
1262                 return -EOPNOTSUPP;
1263
1264         if (encap && encap != DEVLINK_ESWITCH_ENCAP_MODE_BASIC)
1265                 return -EOPNOTSUPP;
1266
1267         if (esw->mode == SRIOV_LEGACY) {
1268                 esw->offloads.encap = encap;
1269                 return 0;
1270         }
1271
1272         if (esw->offloads.encap == encap)
1273                 return 0;
1274
1275         if (esw->offloads.num_flows > 0) {
1276                 NL_SET_ERR_MSG_MOD(extack,
1277                                    "Can't set encapsulation when flows are configured");
1278                 return -EOPNOTSUPP;
1279         }
1280
1281         esw_destroy_offloads_fast_fdb_table(esw);
1282
1283         esw->offloads.encap = encap;
1284         err = esw_create_offloads_fast_fdb_table(esw);
1285         if (err) {
1286                 NL_SET_ERR_MSG_MOD(extack,
1287                                    "Failed re-creating fast FDB table");
1288                 esw->offloads.encap = !encap;
1289                 (void)esw_create_offloads_fast_fdb_table(esw);
1290         }
1291         return err;
1292 }
1293
1294 int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink, u8 *encap)
1295 {
1296         struct mlx5_core_dev *dev = devlink_priv(devlink);
1297         struct mlx5_eswitch *esw = dev->priv.eswitch;
1298         int err;
1299
1300         err = mlx5_devlink_eswitch_check(devlink);
1301         if (err)
1302                 return err;
1303
1304         *encap = esw->offloads.encap;
1305         return 0;
1306 }
1307
1308 void mlx5_eswitch_register_vport_rep(struct mlx5_eswitch *esw,
1309                                      int vport_index,
1310                                      struct mlx5_eswitch_rep_if *__rep_if,
1311                                      u8 rep_type)
1312 {
1313         struct mlx5_esw_offload *offloads = &esw->offloads;
1314         struct mlx5_eswitch_rep_if *rep_if;
1315
1316         rep_if = &offloads->vport_reps[vport_index].rep_if[rep_type];
1317
1318         rep_if->load   = __rep_if->load;
1319         rep_if->unload = __rep_if->unload;
1320         rep_if->get_proto_dev = __rep_if->get_proto_dev;
1321         rep_if->priv = __rep_if->priv;
1322
1323         rep_if->valid = true;
1324 }
1325 EXPORT_SYMBOL(mlx5_eswitch_register_vport_rep);
1326
1327 void mlx5_eswitch_unregister_vport_rep(struct mlx5_eswitch *esw,
1328                                        int vport_index, u8 rep_type)
1329 {
1330         struct mlx5_esw_offload *offloads = &esw->offloads;
1331         struct mlx5_eswitch_rep *rep;
1332
1333         rep = &offloads->vport_reps[vport_index];
1334
1335         if (esw->mode == SRIOV_OFFLOADS && esw->vports[vport_index].enabled)
1336                 rep->rep_if[rep_type].unload(rep);
1337
1338         rep->rep_if[rep_type].valid = false;
1339 }
1340 EXPORT_SYMBOL(mlx5_eswitch_unregister_vport_rep);
1341
1342 void *mlx5_eswitch_get_uplink_priv(struct mlx5_eswitch *esw, u8 rep_type)
1343 {
1344 #define UPLINK_REP_INDEX 0
1345         struct mlx5_esw_offload *offloads = &esw->offloads;
1346         struct mlx5_eswitch_rep *rep;
1347
1348         rep = &offloads->vport_reps[UPLINK_REP_INDEX];
1349         return rep->rep_if[rep_type].priv;
1350 }
1351
1352 void *mlx5_eswitch_get_proto_dev(struct mlx5_eswitch *esw,
1353                                  int vport,
1354                                  u8 rep_type)
1355 {
1356         struct mlx5_esw_offload *offloads = &esw->offloads;
1357         struct mlx5_eswitch_rep *rep;
1358
1359         if (vport == FDB_UPLINK_VPORT)
1360                 vport = UPLINK_REP_INDEX;
1361
1362         rep = &offloads->vport_reps[vport];
1363
1364         if (rep->rep_if[rep_type].valid &&
1365             rep->rep_if[rep_type].get_proto_dev)
1366                 return rep->rep_if[rep_type].get_proto_dev(rep);
1367         return NULL;
1368 }
1369 EXPORT_SYMBOL(mlx5_eswitch_get_proto_dev);
1370
1371 void *mlx5_eswitch_uplink_get_proto_dev(struct mlx5_eswitch *esw, u8 rep_type)
1372 {
1373         return mlx5_eswitch_get_proto_dev(esw, UPLINK_REP_INDEX, rep_type);
1374 }
1375 EXPORT_SYMBOL(mlx5_eswitch_uplink_get_proto_dev);
1376
1377 struct mlx5_eswitch_rep *mlx5_eswitch_vport_rep(struct mlx5_eswitch *esw,
1378                                                 int vport)
1379 {
1380         return &esw->offloads.vport_reps[vport];
1381 }
1382 EXPORT_SYMBOL(mlx5_eswitch_vport_rep);