Merge tag 'irqchip-4.19-2' of git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm...
[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         return 0;
667
668 miss_rule_err:
669         mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
670 miss_err:
671         mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
672 send_vport_err:
673         mlx5_destroy_flow_table(esw->fdb_table.offloads.slow_fdb);
674 slow_fdb_err:
675         esw_destroy_offloads_fast_fdb_table(esw);
676 fast_fdb_err:
677 ns_err:
678         kvfree(flow_group_in);
679         return err;
680 }
681
682 static void esw_destroy_offloads_fdb_tables(struct mlx5_eswitch *esw)
683 {
684         if (!esw->fdb_table.offloads.fast_fdb)
685                 return;
686
687         esw_debug(esw->dev, "Destroy offloads FDB Tables\n");
688         mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_multi);
689         mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_uni);
690         mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
691         mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
692
693         mlx5_destroy_flow_table(esw->fdb_table.offloads.slow_fdb);
694         esw_destroy_offloads_fast_fdb_table(esw);
695 }
696
697 static int esw_create_offloads_table(struct mlx5_eswitch *esw)
698 {
699         struct mlx5_flow_table_attr ft_attr = {};
700         struct mlx5_core_dev *dev = esw->dev;
701         struct mlx5_flow_table *ft_offloads;
702         struct mlx5_flow_namespace *ns;
703         int err = 0;
704
705         ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_OFFLOADS);
706         if (!ns) {
707                 esw_warn(esw->dev, "Failed to get offloads flow namespace\n");
708                 return -EOPNOTSUPP;
709         }
710
711         ft_attr.max_fte = dev->priv.sriov.num_vfs + 2;
712
713         ft_offloads = mlx5_create_flow_table(ns, &ft_attr);
714         if (IS_ERR(ft_offloads)) {
715                 err = PTR_ERR(ft_offloads);
716                 esw_warn(esw->dev, "Failed to create offloads table, err %d\n", err);
717                 return err;
718         }
719
720         esw->offloads.ft_offloads = ft_offloads;
721         return 0;
722 }
723
724 static void esw_destroy_offloads_table(struct mlx5_eswitch *esw)
725 {
726         struct mlx5_esw_offload *offloads = &esw->offloads;
727
728         mlx5_destroy_flow_table(offloads->ft_offloads);
729 }
730
731 static int esw_create_vport_rx_group(struct mlx5_eswitch *esw)
732 {
733         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
734         struct mlx5_flow_group *g;
735         struct mlx5_priv *priv = &esw->dev->priv;
736         u32 *flow_group_in;
737         void *match_criteria, *misc;
738         int err = 0;
739         int nvports = priv->sriov.num_vfs + 2;
740
741         flow_group_in = kvzalloc(inlen, GFP_KERNEL);
742         if (!flow_group_in)
743                 return -ENOMEM;
744
745         /* create vport rx group */
746         memset(flow_group_in, 0, inlen);
747         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
748                  MLX5_MATCH_MISC_PARAMETERS);
749
750         match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
751         misc = MLX5_ADDR_OF(fte_match_param, match_criteria, misc_parameters);
752         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
753
754         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
755         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, nvports - 1);
756
757         g = mlx5_create_flow_group(esw->offloads.ft_offloads, flow_group_in);
758
759         if (IS_ERR(g)) {
760                 err = PTR_ERR(g);
761                 mlx5_core_warn(esw->dev, "Failed to create vport rx group err %d\n", err);
762                 goto out;
763         }
764
765         esw->offloads.vport_rx_group = g;
766 out:
767         kvfree(flow_group_in);
768         return err;
769 }
770
771 static void esw_destroy_vport_rx_group(struct mlx5_eswitch *esw)
772 {
773         mlx5_destroy_flow_group(esw->offloads.vport_rx_group);
774 }
775
776 struct mlx5_flow_handle *
777 mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, int vport, u32 tirn)
778 {
779         struct mlx5_flow_act flow_act = {0};
780         struct mlx5_flow_destination dest = {};
781         struct mlx5_flow_handle *flow_rule;
782         struct mlx5_flow_spec *spec;
783         void *misc;
784
785         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
786         if (!spec) {
787                 flow_rule = ERR_PTR(-ENOMEM);
788                 goto out;
789         }
790
791         misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
792         MLX5_SET(fte_match_set_misc, misc, source_port, vport);
793
794         misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
795         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
796
797         spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
798         dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR;
799         dest.tir_num = tirn;
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 {
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 {
979         int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs;
980
981         mlx5_eswitch_disable_sriov(esw);
982         err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
983         if (err) {
984                 esw_warn(esw->dev, "Failed setting eswitch to legacy, err %d\n", err);
985                 err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_OFFLOADS);
986                 if (err1)
987                         esw_warn(esw->dev, "Failed setting eswitch back to offloads, err %d\n", err);
988         }
989
990         /* enable back PF RoCE */
991         mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
992
993         return err;
994 }
995
996 void esw_offloads_cleanup(struct mlx5_eswitch *esw, int nvports)
997 {
998         esw_offloads_unload_reps(esw, nvports);
999         esw_destroy_vport_rx_group(esw);
1000         esw_destroy_offloads_table(esw);
1001         esw_destroy_offloads_fdb_tables(esw);
1002 }
1003
1004 static int esw_mode_from_devlink(u16 mode, u16 *mlx5_mode)
1005 {
1006         switch (mode) {
1007         case DEVLINK_ESWITCH_MODE_LEGACY:
1008                 *mlx5_mode = SRIOV_LEGACY;
1009                 break;
1010         case DEVLINK_ESWITCH_MODE_SWITCHDEV:
1011                 *mlx5_mode = SRIOV_OFFLOADS;
1012                 break;
1013         default:
1014                 return -EINVAL;
1015         }
1016
1017         return 0;
1018 }
1019
1020 static int esw_mode_to_devlink(u16 mlx5_mode, u16 *mode)
1021 {
1022         switch (mlx5_mode) {
1023         case SRIOV_LEGACY:
1024                 *mode = DEVLINK_ESWITCH_MODE_LEGACY;
1025                 break;
1026         case SRIOV_OFFLOADS:
1027                 *mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
1028                 break;
1029         default:
1030                 return -EINVAL;
1031         }
1032
1033         return 0;
1034 }
1035
1036 static int esw_inline_mode_from_devlink(u8 mode, u8 *mlx5_mode)
1037 {
1038         switch (mode) {
1039         case DEVLINK_ESWITCH_INLINE_MODE_NONE:
1040                 *mlx5_mode = MLX5_INLINE_MODE_NONE;
1041                 break;
1042         case DEVLINK_ESWITCH_INLINE_MODE_LINK:
1043                 *mlx5_mode = MLX5_INLINE_MODE_L2;
1044                 break;
1045         case DEVLINK_ESWITCH_INLINE_MODE_NETWORK:
1046                 *mlx5_mode = MLX5_INLINE_MODE_IP;
1047                 break;
1048         case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT:
1049                 *mlx5_mode = MLX5_INLINE_MODE_TCP_UDP;
1050                 break;
1051         default:
1052                 return -EINVAL;
1053         }
1054
1055         return 0;
1056 }
1057
1058 static int esw_inline_mode_to_devlink(u8 mlx5_mode, u8 *mode)
1059 {
1060         switch (mlx5_mode) {
1061         case MLX5_INLINE_MODE_NONE:
1062                 *mode = DEVLINK_ESWITCH_INLINE_MODE_NONE;
1063                 break;
1064         case MLX5_INLINE_MODE_L2:
1065                 *mode = DEVLINK_ESWITCH_INLINE_MODE_LINK;
1066                 break;
1067         case MLX5_INLINE_MODE_IP:
1068                 *mode = DEVLINK_ESWITCH_INLINE_MODE_NETWORK;
1069                 break;
1070         case MLX5_INLINE_MODE_TCP_UDP:
1071                 *mode = DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT;
1072                 break;
1073         default:
1074                 return -EINVAL;
1075         }
1076
1077         return 0;
1078 }
1079
1080 static int mlx5_devlink_eswitch_check(struct devlink *devlink)
1081 {
1082         struct mlx5_core_dev *dev = devlink_priv(devlink);
1083
1084         if (MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
1085                 return -EOPNOTSUPP;
1086
1087         if(!MLX5_ESWITCH_MANAGER(dev))
1088                 return -EPERM;
1089
1090         if (dev->priv.eswitch->mode == SRIOV_NONE)
1091                 return -EOPNOTSUPP;
1092
1093         return 0;
1094 }
1095
1096 int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode)
1097 {
1098         struct mlx5_core_dev *dev = devlink_priv(devlink);
1099         u16 cur_mlx5_mode, mlx5_mode = 0;
1100         int err;
1101
1102         err = mlx5_devlink_eswitch_check(devlink);
1103         if (err)
1104                 return err;
1105
1106         cur_mlx5_mode = dev->priv.eswitch->mode;
1107
1108         if (esw_mode_from_devlink(mode, &mlx5_mode))
1109                 return -EINVAL;
1110
1111         if (cur_mlx5_mode == mlx5_mode)
1112                 return 0;
1113
1114         if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV)
1115                 return esw_offloads_start(dev->priv.eswitch);
1116         else if (mode == DEVLINK_ESWITCH_MODE_LEGACY)
1117                 return esw_offloads_stop(dev->priv.eswitch);
1118         else
1119                 return -EINVAL;
1120 }
1121
1122 int mlx5_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
1123 {
1124         struct mlx5_core_dev *dev = devlink_priv(devlink);
1125         int err;
1126
1127         err = mlx5_devlink_eswitch_check(devlink);
1128         if (err)
1129                 return err;
1130
1131         return esw_mode_to_devlink(dev->priv.eswitch->mode, mode);
1132 }
1133
1134 int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode)
1135 {
1136         struct mlx5_core_dev *dev = devlink_priv(devlink);
1137         struct mlx5_eswitch *esw = dev->priv.eswitch;
1138         int err, vport;
1139         u8 mlx5_mode;
1140
1141         err = mlx5_devlink_eswitch_check(devlink);
1142         if (err)
1143                 return err;
1144
1145         switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
1146         case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
1147                 if (mode == DEVLINK_ESWITCH_INLINE_MODE_NONE)
1148                         return 0;
1149                 /* fall through */
1150         case MLX5_CAP_INLINE_MODE_L2:
1151                 esw_warn(dev, "Inline mode can't be set\n");
1152                 return -EOPNOTSUPP;
1153         case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
1154                 break;
1155         }
1156
1157         if (esw->offloads.num_flows > 0) {
1158                 esw_warn(dev, "Can't set inline mode when flows are configured\n");
1159                 return -EOPNOTSUPP;
1160         }
1161
1162         err = esw_inline_mode_from_devlink(mode, &mlx5_mode);
1163         if (err)
1164                 goto out;
1165
1166         for (vport = 1; vport < esw->enabled_vports; vport++) {
1167                 err = mlx5_modify_nic_vport_min_inline(dev, vport, mlx5_mode);
1168                 if (err) {
1169                         esw_warn(dev, "Failed to set min inline on vport %d\n",
1170                                  vport);
1171                         goto revert_inline_mode;
1172                 }
1173         }
1174
1175         esw->offloads.inline_mode = mlx5_mode;
1176         return 0;
1177
1178 revert_inline_mode:
1179         while (--vport > 0)
1180                 mlx5_modify_nic_vport_min_inline(dev,
1181                                                  vport,
1182                                                  esw->offloads.inline_mode);
1183 out:
1184         return err;
1185 }
1186
1187 int mlx5_devlink_eswitch_inline_mode_get(struct devlink *devlink, u8 *mode)
1188 {
1189         struct mlx5_core_dev *dev = devlink_priv(devlink);
1190         struct mlx5_eswitch *esw = dev->priv.eswitch;
1191         int err;
1192
1193         err = mlx5_devlink_eswitch_check(devlink);
1194         if (err)
1195                 return err;
1196
1197         return esw_inline_mode_to_devlink(esw->offloads.inline_mode, mode);
1198 }
1199
1200 int mlx5_eswitch_inline_mode_get(struct mlx5_eswitch *esw, int nvfs, u8 *mode)
1201 {
1202         u8 prev_mlx5_mode, mlx5_mode = MLX5_INLINE_MODE_L2;
1203         struct mlx5_core_dev *dev = esw->dev;
1204         int vport;
1205
1206         if (!MLX5_CAP_GEN(dev, vport_group_manager))
1207                 return -EOPNOTSUPP;
1208
1209         if (esw->mode == SRIOV_NONE)
1210                 return -EOPNOTSUPP;
1211
1212         switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
1213         case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
1214                 mlx5_mode = MLX5_INLINE_MODE_NONE;
1215                 goto out;
1216         case MLX5_CAP_INLINE_MODE_L2:
1217                 mlx5_mode = MLX5_INLINE_MODE_L2;
1218                 goto out;
1219         case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
1220                 goto query_vports;
1221         }
1222
1223 query_vports:
1224         for (vport = 1; vport <= nvfs; vport++) {
1225                 mlx5_query_nic_vport_min_inline(dev, vport, &mlx5_mode);
1226                 if (vport > 1 && prev_mlx5_mode != mlx5_mode)
1227                         return -EINVAL;
1228                 prev_mlx5_mode = mlx5_mode;
1229         }
1230
1231 out:
1232         *mode = mlx5_mode;
1233         return 0;
1234 }
1235
1236 int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap)
1237 {
1238         struct mlx5_core_dev *dev = devlink_priv(devlink);
1239         struct mlx5_eswitch *esw = dev->priv.eswitch;
1240         int err;
1241
1242         err = mlx5_devlink_eswitch_check(devlink);
1243         if (err)
1244                 return err;
1245
1246         if (encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE &&
1247             (!MLX5_CAP_ESW_FLOWTABLE_FDB(dev, encap) ||
1248              !MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap)))
1249                 return -EOPNOTSUPP;
1250
1251         if (encap && encap != DEVLINK_ESWITCH_ENCAP_MODE_BASIC)
1252                 return -EOPNOTSUPP;
1253
1254         if (esw->mode == SRIOV_LEGACY) {
1255                 esw->offloads.encap = encap;
1256                 return 0;
1257         }
1258
1259         if (esw->offloads.encap == encap)
1260                 return 0;
1261
1262         if (esw->offloads.num_flows > 0) {
1263                 esw_warn(dev, "Can't set encapsulation when flows are configured\n");
1264                 return -EOPNOTSUPP;
1265         }
1266
1267         esw_destroy_offloads_fast_fdb_table(esw);
1268
1269         esw->offloads.encap = encap;
1270         err = esw_create_offloads_fast_fdb_table(esw);
1271         if (err) {
1272                 esw_warn(esw->dev, "Failed re-creating fast FDB table, err %d\n", err);
1273                 esw->offloads.encap = !encap;
1274                 (void)esw_create_offloads_fast_fdb_table(esw);
1275         }
1276         return err;
1277 }
1278
1279 int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink, u8 *encap)
1280 {
1281         struct mlx5_core_dev *dev = devlink_priv(devlink);
1282         struct mlx5_eswitch *esw = dev->priv.eswitch;
1283         int err;
1284
1285         err = mlx5_devlink_eswitch_check(devlink);
1286         if (err)
1287                 return err;
1288
1289         *encap = esw->offloads.encap;
1290         return 0;
1291 }
1292
1293 void mlx5_eswitch_register_vport_rep(struct mlx5_eswitch *esw,
1294                                      int vport_index,
1295                                      struct mlx5_eswitch_rep_if *__rep_if,
1296                                      u8 rep_type)
1297 {
1298         struct mlx5_esw_offload *offloads = &esw->offloads;
1299         struct mlx5_eswitch_rep_if *rep_if;
1300
1301         rep_if = &offloads->vport_reps[vport_index].rep_if[rep_type];
1302
1303         rep_if->load   = __rep_if->load;
1304         rep_if->unload = __rep_if->unload;
1305         rep_if->get_proto_dev = __rep_if->get_proto_dev;
1306         rep_if->priv = __rep_if->priv;
1307
1308         rep_if->valid = true;
1309 }
1310 EXPORT_SYMBOL(mlx5_eswitch_register_vport_rep);
1311
1312 void mlx5_eswitch_unregister_vport_rep(struct mlx5_eswitch *esw,
1313                                        int vport_index, u8 rep_type)
1314 {
1315         struct mlx5_esw_offload *offloads = &esw->offloads;
1316         struct mlx5_eswitch_rep *rep;
1317
1318         rep = &offloads->vport_reps[vport_index];
1319
1320         if (esw->mode == SRIOV_OFFLOADS && esw->vports[vport_index].enabled)
1321                 rep->rep_if[rep_type].unload(rep);
1322
1323         rep->rep_if[rep_type].valid = false;
1324 }
1325 EXPORT_SYMBOL(mlx5_eswitch_unregister_vport_rep);
1326
1327 void *mlx5_eswitch_get_uplink_priv(struct mlx5_eswitch *esw, u8 rep_type)
1328 {
1329 #define UPLINK_REP_INDEX 0
1330         struct mlx5_esw_offload *offloads = &esw->offloads;
1331         struct mlx5_eswitch_rep *rep;
1332
1333         rep = &offloads->vport_reps[UPLINK_REP_INDEX];
1334         return rep->rep_if[rep_type].priv;
1335 }
1336
1337 void *mlx5_eswitch_get_proto_dev(struct mlx5_eswitch *esw,
1338                                  int vport,
1339                                  u8 rep_type)
1340 {
1341         struct mlx5_esw_offload *offloads = &esw->offloads;
1342         struct mlx5_eswitch_rep *rep;
1343
1344         if (vport == FDB_UPLINK_VPORT)
1345                 vport = UPLINK_REP_INDEX;
1346
1347         rep = &offloads->vport_reps[vport];
1348
1349         if (rep->rep_if[rep_type].valid &&
1350             rep->rep_if[rep_type].get_proto_dev)
1351                 return rep->rep_if[rep_type].get_proto_dev(rep);
1352         return NULL;
1353 }
1354 EXPORT_SYMBOL(mlx5_eswitch_get_proto_dev);
1355
1356 void *mlx5_eswitch_uplink_get_proto_dev(struct mlx5_eswitch *esw, u8 rep_type)
1357 {
1358         return mlx5_eswitch_get_proto_dev(esw, UPLINK_REP_INDEX, rep_type);
1359 }
1360 EXPORT_SYMBOL(mlx5_eswitch_uplink_get_proto_dev);
1361
1362 struct mlx5_eswitch_rep *mlx5_eswitch_vport_rep(struct mlx5_eswitch *esw,
1363                                                 int vport)
1364 {
1365         return &esw->offloads.vport_reps[vport];
1366 }
1367 EXPORT_SYMBOL(mlx5_eswitch_vport_rep);