Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[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 #include "rdma.h"
41 #include "en.h"
42 #include "fs_core.h"
43 #include "lib/devcom.h"
44 #include "lib/eq.h"
45
46 /* There are two match-all miss flows, one for unicast dst mac and
47  * one for multicast.
48  */
49 #define MLX5_ESW_MISS_FLOWS (2)
50
51 #define fdb_prio_table(esw, chain, prio, level) \
52         (esw)->fdb_table.offloads.fdb_prio[(chain)][(prio)][(level)]
53
54 #define UPLINK_REP_INDEX 0
55
56 static struct mlx5_eswitch_rep *mlx5_eswitch_get_rep(struct mlx5_eswitch *esw,
57                                                      u16 vport_num)
58 {
59         int idx = mlx5_eswitch_vport_num_to_index(esw, vport_num);
60
61         WARN_ON(idx > esw->total_vports - 1);
62         return &esw->offloads.vport_reps[idx];
63 }
64
65 static struct mlx5_flow_table *
66 esw_get_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level);
67 static void
68 esw_put_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level);
69
70 bool mlx5_eswitch_prios_supported(struct mlx5_eswitch *esw)
71 {
72         return (!!(esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED));
73 }
74
75 u32 mlx5_eswitch_get_chain_range(struct mlx5_eswitch *esw)
76 {
77         if (esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED)
78                 return FDB_MAX_CHAIN;
79
80         return 0;
81 }
82
83 u16 mlx5_eswitch_get_prio_range(struct mlx5_eswitch *esw)
84 {
85         if (esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED)
86                 return FDB_MAX_PRIO;
87
88         return 1;
89 }
90
91 static void
92 mlx5_eswitch_set_rule_source_port(struct mlx5_eswitch *esw,
93                                   struct mlx5_flow_spec *spec,
94                                   struct mlx5_esw_flow_attr *attr)
95 {
96         void *misc2;
97         void *misc;
98
99         /* Use metadata matching because vport is not represented by single
100          * VHCA in dual-port RoCE mode, and matching on source vport may fail.
101          */
102         if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
103                 misc2 = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters_2);
104                 MLX5_SET(fte_match_set_misc2, misc2, metadata_reg_c_0,
105                          mlx5_eswitch_get_vport_metadata_for_match(attr->in_mdev->priv.eswitch,
106                                                                    attr->in_rep->vport));
107
108                 misc2 = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters_2);
109                 MLX5_SET_TO_ONES(fte_match_set_misc2, misc2, metadata_reg_c_0);
110
111                 spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;
112                 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
113                 if (memchr_inv(misc, 0, MLX5_ST_SZ_BYTES(fte_match_set_misc)))
114                         spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS;
115         } else {
116                 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
117                 MLX5_SET(fte_match_set_misc, misc, source_port, attr->in_rep->vport);
118
119                 if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
120                         MLX5_SET(fte_match_set_misc, misc,
121                                  source_eswitch_owner_vhca_id,
122                                  MLX5_CAP_GEN(attr->in_mdev, vhca_id));
123
124                 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
125                 MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
126                 if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
127                         MLX5_SET_TO_ONES(fte_match_set_misc, misc,
128                                          source_eswitch_owner_vhca_id);
129
130                 spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS;
131         }
132
133         if (MLX5_CAP_ESW_FLOWTABLE(esw->dev, flow_source) &&
134             attr->in_rep->vport == MLX5_VPORT_UPLINK)
135                 spec->flow_context.flow_source = MLX5_FLOW_CONTEXT_FLOW_SOURCE_UPLINK;
136 }
137
138 struct mlx5_flow_handle *
139 mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
140                                 struct mlx5_flow_spec *spec,
141                                 struct mlx5_esw_flow_attr *attr)
142 {
143         struct mlx5_flow_destination dest[MLX5_MAX_FLOW_FWD_VPORTS + 1] = {};
144         struct mlx5_flow_act flow_act = { .flags = FLOW_ACT_NO_APPEND, };
145         bool split = !!(attr->split_count);
146         struct mlx5_flow_handle *rule;
147         struct mlx5_flow_table *fdb;
148         int j, i = 0;
149
150         if (esw->mode != MLX5_ESWITCH_OFFLOADS)
151                 return ERR_PTR(-EOPNOTSUPP);
152
153         flow_act.action = attr->action;
154         /* if per flow vlan pop/push is emulated, don't set that into the firmware */
155         if (!mlx5_eswitch_vlan_actions_supported(esw->dev, 1))
156                 flow_act.action &= ~(MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH |
157                                      MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
158         else if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH) {
159                 flow_act.vlan[0].ethtype = ntohs(attr->vlan_proto[0]);
160                 flow_act.vlan[0].vid = attr->vlan_vid[0];
161                 flow_act.vlan[0].prio = attr->vlan_prio[0];
162                 if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2) {
163                         flow_act.vlan[1].ethtype = ntohs(attr->vlan_proto[1]);
164                         flow_act.vlan[1].vid = attr->vlan_vid[1];
165                         flow_act.vlan[1].prio = attr->vlan_prio[1];
166                 }
167         }
168
169         if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
170                 if (attr->dest_chain) {
171                         struct mlx5_flow_table *ft;
172
173                         ft = esw_get_prio_table(esw, attr->dest_chain, 1, 0);
174                         if (IS_ERR(ft)) {
175                                 rule = ERR_CAST(ft);
176                                 goto err_create_goto_table;
177                         }
178
179                         dest[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
180                         dest[i].ft = ft;
181                         i++;
182                 } else {
183                         for (j = attr->split_count; j < attr->out_count; j++) {
184                                 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
185                                 dest[i].vport.num = attr->dests[j].rep->vport;
186                                 dest[i].vport.vhca_id =
187                                         MLX5_CAP_GEN(attr->dests[j].mdev, vhca_id);
188                                 if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
189                                         dest[i].vport.flags |=
190                                                 MLX5_FLOW_DEST_VPORT_VHCA_ID;
191                                 if (attr->dests[j].flags & MLX5_ESW_DEST_ENCAP) {
192                                         flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
193                                         flow_act.reformat_id = attr->dests[j].encap_id;
194                                         dest[i].vport.flags |= MLX5_FLOW_DEST_VPORT_REFORMAT_ID;
195                                         dest[i].vport.reformat_id =
196                                                 attr->dests[j].encap_id;
197                                 }
198                                 i++;
199                         }
200                 }
201         }
202         if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
203                 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
204                 dest[i].counter_id = mlx5_fc_id(attr->counter);
205                 i++;
206         }
207
208         mlx5_eswitch_set_rule_source_port(esw, spec, attr);
209
210         if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_DECAP) {
211                 if (attr->tunnel_match_level != MLX5_MATCH_NONE)
212                         spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
213                 if (attr->match_level != MLX5_MATCH_NONE)
214                         spec->match_criteria_enable |= MLX5_MATCH_INNER_HEADERS;
215         } else if (attr->match_level != MLX5_MATCH_NONE) {
216                 spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
217         }
218
219         if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
220                 flow_act.modify_id = attr->mod_hdr_id;
221
222         fdb = esw_get_prio_table(esw, attr->chain, attr->prio, !!split);
223         if (IS_ERR(fdb)) {
224                 rule = ERR_CAST(fdb);
225                 goto err_esw_get;
226         }
227
228         if (mlx5_eswitch_termtbl_required(esw, &flow_act, spec))
229                 rule = mlx5_eswitch_add_termtbl_rule(esw, fdb, spec, attr,
230                                                      &flow_act, dest, i);
231         else
232                 rule = mlx5_add_flow_rules(fdb, spec, &flow_act, dest, i);
233         if (IS_ERR(rule))
234                 goto err_add_rule;
235         else
236                 esw->offloads.num_flows++;
237
238         return rule;
239
240 err_add_rule:
241         esw_put_prio_table(esw, attr->chain, attr->prio, !!split);
242 err_esw_get:
243         if (attr->dest_chain)
244                 esw_put_prio_table(esw, attr->dest_chain, 1, 0);
245 err_create_goto_table:
246         return rule;
247 }
248
249 struct mlx5_flow_handle *
250 mlx5_eswitch_add_fwd_rule(struct mlx5_eswitch *esw,
251                           struct mlx5_flow_spec *spec,
252                           struct mlx5_esw_flow_attr *attr)
253 {
254         struct mlx5_flow_destination dest[MLX5_MAX_FLOW_FWD_VPORTS + 1] = {};
255         struct mlx5_flow_act flow_act = { .flags = FLOW_ACT_NO_APPEND, };
256         struct mlx5_flow_table *fast_fdb;
257         struct mlx5_flow_table *fwd_fdb;
258         struct mlx5_flow_handle *rule;
259         int i;
260
261         fast_fdb = esw_get_prio_table(esw, attr->chain, attr->prio, 0);
262         if (IS_ERR(fast_fdb)) {
263                 rule = ERR_CAST(fast_fdb);
264                 goto err_get_fast;
265         }
266
267         fwd_fdb = esw_get_prio_table(esw, attr->chain, attr->prio, 1);
268         if (IS_ERR(fwd_fdb)) {
269                 rule = ERR_CAST(fwd_fdb);
270                 goto err_get_fwd;
271         }
272
273         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
274         for (i = 0; i < attr->split_count; i++) {
275                 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
276                 dest[i].vport.num = attr->dests[i].rep->vport;
277                 dest[i].vport.vhca_id =
278                         MLX5_CAP_GEN(attr->dests[i].mdev, vhca_id);
279                 if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
280                         dest[i].vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
281                 if (attr->dests[i].flags & MLX5_ESW_DEST_ENCAP) {
282                         dest[i].vport.flags |= MLX5_FLOW_DEST_VPORT_REFORMAT_ID;
283                         dest[i].vport.reformat_id = attr->dests[i].encap_id;
284                 }
285         }
286         dest[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
287         dest[i].ft = fwd_fdb,
288         i++;
289
290         mlx5_eswitch_set_rule_source_port(esw, spec, attr);
291
292         spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS;
293         if (attr->match_level != MLX5_MATCH_NONE)
294                 spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
295
296         rule = mlx5_add_flow_rules(fast_fdb, spec, &flow_act, dest, i);
297
298         if (IS_ERR(rule))
299                 goto add_err;
300
301         esw->offloads.num_flows++;
302
303         return rule;
304 add_err:
305         esw_put_prio_table(esw, attr->chain, attr->prio, 1);
306 err_get_fwd:
307         esw_put_prio_table(esw, attr->chain, attr->prio, 0);
308 err_get_fast:
309         return rule;
310 }
311
312 static void
313 __mlx5_eswitch_del_rule(struct mlx5_eswitch *esw,
314                         struct mlx5_flow_handle *rule,
315                         struct mlx5_esw_flow_attr *attr,
316                         bool fwd_rule)
317 {
318         bool split = (attr->split_count > 0);
319         int i;
320
321         mlx5_del_flow_rules(rule);
322
323         /* unref the term table */
324         for (i = 0; i < MLX5_MAX_FLOW_FWD_VPORTS; i++) {
325                 if (attr->dests[i].termtbl)
326                         mlx5_eswitch_termtbl_put(esw, attr->dests[i].termtbl);
327         }
328
329         esw->offloads.num_flows--;
330
331         if (fwd_rule)  {
332                 esw_put_prio_table(esw, attr->chain, attr->prio, 1);
333                 esw_put_prio_table(esw, attr->chain, attr->prio, 0);
334         } else {
335                 esw_put_prio_table(esw, attr->chain, attr->prio, !!split);
336                 if (attr->dest_chain)
337                         esw_put_prio_table(esw, attr->dest_chain, 1, 0);
338         }
339 }
340
341 void
342 mlx5_eswitch_del_offloaded_rule(struct mlx5_eswitch *esw,
343                                 struct mlx5_flow_handle *rule,
344                                 struct mlx5_esw_flow_attr *attr)
345 {
346         __mlx5_eswitch_del_rule(esw, rule, attr, false);
347 }
348
349 void
350 mlx5_eswitch_del_fwd_rule(struct mlx5_eswitch *esw,
351                           struct mlx5_flow_handle *rule,
352                           struct mlx5_esw_flow_attr *attr)
353 {
354         __mlx5_eswitch_del_rule(esw, rule, attr, true);
355 }
356
357 static int esw_set_global_vlan_pop(struct mlx5_eswitch *esw, u8 val)
358 {
359         struct mlx5_eswitch_rep *rep;
360         int i, err = 0;
361
362         esw_debug(esw->dev, "%s applying global %s policy\n", __func__, val ? "pop" : "none");
363         mlx5_esw_for_each_host_func_rep(esw, i, rep, esw->esw_funcs.num_vfs) {
364                 if (atomic_read(&rep->rep_data[REP_ETH].state) != REP_LOADED)
365                         continue;
366
367                 err = __mlx5_eswitch_set_vport_vlan(esw, rep->vport, 0, 0, val);
368                 if (err)
369                         goto out;
370         }
371
372 out:
373         return err;
374 }
375
376 static struct mlx5_eswitch_rep *
377 esw_vlan_action_get_vport(struct mlx5_esw_flow_attr *attr, bool push, bool pop)
378 {
379         struct mlx5_eswitch_rep *in_rep, *out_rep, *vport = NULL;
380
381         in_rep  = attr->in_rep;
382         out_rep = attr->dests[0].rep;
383
384         if (push)
385                 vport = in_rep;
386         else if (pop)
387                 vport = out_rep;
388         else
389                 vport = in_rep;
390
391         return vport;
392 }
393
394 static int esw_add_vlan_action_check(struct mlx5_esw_flow_attr *attr,
395                                      bool push, bool pop, bool fwd)
396 {
397         struct mlx5_eswitch_rep *in_rep, *out_rep;
398
399         if ((push || pop) && !fwd)
400                 goto out_notsupp;
401
402         in_rep  = attr->in_rep;
403         out_rep = attr->dests[0].rep;
404
405         if (push && in_rep->vport == MLX5_VPORT_UPLINK)
406                 goto out_notsupp;
407
408         if (pop && out_rep->vport == MLX5_VPORT_UPLINK)
409                 goto out_notsupp;
410
411         /* vport has vlan push configured, can't offload VF --> wire rules w.o it */
412         if (!push && !pop && fwd)
413                 if (in_rep->vlan && out_rep->vport == MLX5_VPORT_UPLINK)
414                         goto out_notsupp;
415
416         /* protects against (1) setting rules with different vlans to push and
417          * (2) setting rules w.o vlans (attr->vlan = 0) && w. vlans to push (!= 0)
418          */
419         if (push && in_rep->vlan_refcount && (in_rep->vlan != attr->vlan_vid[0]))
420                 goto out_notsupp;
421
422         return 0;
423
424 out_notsupp:
425         return -EOPNOTSUPP;
426 }
427
428 int mlx5_eswitch_add_vlan_action(struct mlx5_eswitch *esw,
429                                  struct mlx5_esw_flow_attr *attr)
430 {
431         struct offloads_fdb *offloads = &esw->fdb_table.offloads;
432         struct mlx5_eswitch_rep *vport = NULL;
433         bool push, pop, fwd;
434         int err = 0;
435
436         /* nop if we're on the vlan push/pop non emulation mode */
437         if (mlx5_eswitch_vlan_actions_supported(esw->dev, 1))
438                 return 0;
439
440         push = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH);
441         pop  = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
442         fwd  = !!((attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) &&
443                    !attr->dest_chain);
444
445         err = esw_add_vlan_action_check(attr, push, pop, fwd);
446         if (err)
447                 return err;
448
449         attr->vlan_handled = false;
450
451         vport = esw_vlan_action_get_vport(attr, push, pop);
452
453         if (!push && !pop && fwd) {
454                 /* tracks VF --> wire rules without vlan push action */
455                 if (attr->dests[0].rep->vport == MLX5_VPORT_UPLINK) {
456                         vport->vlan_refcount++;
457                         attr->vlan_handled = true;
458                 }
459
460                 return 0;
461         }
462
463         if (!push && !pop)
464                 return 0;
465
466         if (!(offloads->vlan_push_pop_refcount)) {
467                 /* it's the 1st vlan rule, apply global vlan pop policy */
468                 err = esw_set_global_vlan_pop(esw, SET_VLAN_STRIP);
469                 if (err)
470                         goto out;
471         }
472         offloads->vlan_push_pop_refcount++;
473
474         if (push) {
475                 if (vport->vlan_refcount)
476                         goto skip_set_push;
477
478                 err = __mlx5_eswitch_set_vport_vlan(esw, vport->vport, attr->vlan_vid[0], 0,
479                                                     SET_VLAN_INSERT | SET_VLAN_STRIP);
480                 if (err)
481                         goto out;
482                 vport->vlan = attr->vlan_vid[0];
483 skip_set_push:
484                 vport->vlan_refcount++;
485         }
486 out:
487         if (!err)
488                 attr->vlan_handled = true;
489         return err;
490 }
491
492 int mlx5_eswitch_del_vlan_action(struct mlx5_eswitch *esw,
493                                  struct mlx5_esw_flow_attr *attr)
494 {
495         struct offloads_fdb *offloads = &esw->fdb_table.offloads;
496         struct mlx5_eswitch_rep *vport = NULL;
497         bool push, pop, fwd;
498         int err = 0;
499
500         /* nop if we're on the vlan push/pop non emulation mode */
501         if (mlx5_eswitch_vlan_actions_supported(esw->dev, 1))
502                 return 0;
503
504         if (!attr->vlan_handled)
505                 return 0;
506
507         push = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH);
508         pop  = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
509         fwd  = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST);
510
511         vport = esw_vlan_action_get_vport(attr, push, pop);
512
513         if (!push && !pop && fwd) {
514                 /* tracks VF --> wire rules without vlan push action */
515                 if (attr->dests[0].rep->vport == MLX5_VPORT_UPLINK)
516                         vport->vlan_refcount--;
517
518                 return 0;
519         }
520
521         if (push) {
522                 vport->vlan_refcount--;
523                 if (vport->vlan_refcount)
524                         goto skip_unset_push;
525
526                 vport->vlan = 0;
527                 err = __mlx5_eswitch_set_vport_vlan(esw, vport->vport,
528                                                     0, 0, SET_VLAN_STRIP);
529                 if (err)
530                         goto out;
531         }
532
533 skip_unset_push:
534         offloads->vlan_push_pop_refcount--;
535         if (offloads->vlan_push_pop_refcount)
536                 return 0;
537
538         /* no more vlan rules, stop global vlan pop policy */
539         err = esw_set_global_vlan_pop(esw, 0);
540
541 out:
542         return err;
543 }
544
545 struct mlx5_flow_handle *
546 mlx5_eswitch_add_send_to_vport_rule(struct mlx5_eswitch *esw, u16 vport,
547                                     u32 sqn)
548 {
549         struct mlx5_flow_act flow_act = {0};
550         struct mlx5_flow_destination dest = {};
551         struct mlx5_flow_handle *flow_rule;
552         struct mlx5_flow_spec *spec;
553         void *misc;
554
555         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
556         if (!spec) {
557                 flow_rule = ERR_PTR(-ENOMEM);
558                 goto out;
559         }
560
561         misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
562         MLX5_SET(fte_match_set_misc, misc, source_sqn, sqn);
563         /* source vport is the esw manager */
564         MLX5_SET(fte_match_set_misc, misc, source_port, esw->manager_vport);
565
566         misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
567         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_sqn);
568         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
569
570         spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
571         dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
572         dest.vport.num = vport;
573         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
574
575         flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb, spec,
576                                         &flow_act, &dest, 1);
577         if (IS_ERR(flow_rule))
578                 esw_warn(esw->dev, "FDB: Failed to add send to vport rule err %ld\n", PTR_ERR(flow_rule));
579 out:
580         kvfree(spec);
581         return flow_rule;
582 }
583 EXPORT_SYMBOL(mlx5_eswitch_add_send_to_vport_rule);
584
585 void mlx5_eswitch_del_send_to_vport_rule(struct mlx5_flow_handle *rule)
586 {
587         mlx5_del_flow_rules(rule);
588 }
589
590 static int mlx5_eswitch_enable_passing_vport_metadata(struct mlx5_eswitch *esw)
591 {
592         u32 out[MLX5_ST_SZ_DW(query_esw_vport_context_out)] = {};
593         u32 in[MLX5_ST_SZ_DW(modify_esw_vport_context_in)] = {};
594         u8 fdb_to_vport_reg_c_id;
595         int err;
596
597         err = mlx5_eswitch_query_esw_vport_context(esw, esw->manager_vport,
598                                                    out, sizeof(out));
599         if (err)
600                 return err;
601
602         fdb_to_vport_reg_c_id = MLX5_GET(query_esw_vport_context_out, out,
603                                          esw_vport_context.fdb_to_vport_reg_c_id);
604
605         fdb_to_vport_reg_c_id |= MLX5_FDB_TO_VPORT_REG_C_0;
606         MLX5_SET(modify_esw_vport_context_in, in,
607                  esw_vport_context.fdb_to_vport_reg_c_id, fdb_to_vport_reg_c_id);
608
609         MLX5_SET(modify_esw_vport_context_in, in,
610                  field_select.fdb_to_vport_reg_c_id, 1);
611
612         return mlx5_eswitch_modify_esw_vport_context(esw, esw->manager_vport,
613                                                      in, sizeof(in));
614 }
615
616 static int mlx5_eswitch_disable_passing_vport_metadata(struct mlx5_eswitch *esw)
617 {
618         u32 out[MLX5_ST_SZ_DW(query_esw_vport_context_out)] = {};
619         u32 in[MLX5_ST_SZ_DW(modify_esw_vport_context_in)] = {};
620         u8 fdb_to_vport_reg_c_id;
621         int err;
622
623         err = mlx5_eswitch_query_esw_vport_context(esw, esw->manager_vport,
624                                                    out, sizeof(out));
625         if (err)
626                 return err;
627
628         fdb_to_vport_reg_c_id = MLX5_GET(query_esw_vport_context_out, out,
629                                          esw_vport_context.fdb_to_vport_reg_c_id);
630
631         fdb_to_vport_reg_c_id &= ~MLX5_FDB_TO_VPORT_REG_C_0;
632
633         MLX5_SET(modify_esw_vport_context_in, in,
634                  esw_vport_context.fdb_to_vport_reg_c_id, fdb_to_vport_reg_c_id);
635
636         MLX5_SET(modify_esw_vport_context_in, in,
637                  field_select.fdb_to_vport_reg_c_id, 1);
638
639         return mlx5_eswitch_modify_esw_vport_context(esw, esw->manager_vport,
640                                                      in, sizeof(in));
641 }
642
643 static void peer_miss_rules_setup(struct mlx5_eswitch *esw,
644                                   struct mlx5_core_dev *peer_dev,
645                                   struct mlx5_flow_spec *spec,
646                                   struct mlx5_flow_destination *dest)
647 {
648         void *misc;
649
650         if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
651                 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
652                                     misc_parameters_2);
653                 MLX5_SET_TO_ONES(fte_match_set_misc2, misc, metadata_reg_c_0);
654
655                 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS_2;
656         } else {
657                 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
658                                     misc_parameters);
659
660                 MLX5_SET(fte_match_set_misc, misc, source_eswitch_owner_vhca_id,
661                          MLX5_CAP_GEN(peer_dev, vhca_id));
662
663                 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
664
665                 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
666                                     misc_parameters);
667                 MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
668                 MLX5_SET_TO_ONES(fte_match_set_misc, misc,
669                                  source_eswitch_owner_vhca_id);
670         }
671
672         dest->type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
673         dest->vport.num = peer_dev->priv.eswitch->manager_vport;
674         dest->vport.vhca_id = MLX5_CAP_GEN(peer_dev, vhca_id);
675         dest->vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
676 }
677
678 static void esw_set_peer_miss_rule_source_port(struct mlx5_eswitch *esw,
679                                                struct mlx5_eswitch *peer_esw,
680                                                struct mlx5_flow_spec *spec,
681                                                u16 vport)
682 {
683         void *misc;
684
685         if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
686                 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
687                                     misc_parameters_2);
688                 MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0,
689                          mlx5_eswitch_get_vport_metadata_for_match(peer_esw,
690                                                                    vport));
691         } else {
692                 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
693                                     misc_parameters);
694                 MLX5_SET(fte_match_set_misc, misc, source_port, vport);
695         }
696 }
697
698 static int esw_add_fdb_peer_miss_rules(struct mlx5_eswitch *esw,
699                                        struct mlx5_core_dev *peer_dev)
700 {
701         struct mlx5_flow_destination dest = {};
702         struct mlx5_flow_act flow_act = {0};
703         struct mlx5_flow_handle **flows;
704         struct mlx5_flow_handle *flow;
705         struct mlx5_flow_spec *spec;
706         /* total vports is the same for both e-switches */
707         int nvports = esw->total_vports;
708         void *misc;
709         int err, i;
710
711         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
712         if (!spec)
713                 return -ENOMEM;
714
715         peer_miss_rules_setup(esw, peer_dev, spec, &dest);
716
717         flows = kvzalloc(nvports * sizeof(*flows), GFP_KERNEL);
718         if (!flows) {
719                 err = -ENOMEM;
720                 goto alloc_flows_err;
721         }
722
723         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
724         misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
725                             misc_parameters);
726
727         if (mlx5_core_is_ecpf_esw_manager(esw->dev)) {
728                 esw_set_peer_miss_rule_source_port(esw, peer_dev->priv.eswitch,
729                                                    spec, MLX5_VPORT_PF);
730
731                 flow = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb,
732                                            spec, &flow_act, &dest, 1);
733                 if (IS_ERR(flow)) {
734                         err = PTR_ERR(flow);
735                         goto add_pf_flow_err;
736                 }
737                 flows[MLX5_VPORT_PF] = flow;
738         }
739
740         if (mlx5_ecpf_vport_exists(esw->dev)) {
741                 MLX5_SET(fte_match_set_misc, misc, source_port, MLX5_VPORT_ECPF);
742                 flow = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb,
743                                            spec, &flow_act, &dest, 1);
744                 if (IS_ERR(flow)) {
745                         err = PTR_ERR(flow);
746                         goto add_ecpf_flow_err;
747                 }
748                 flows[mlx5_eswitch_ecpf_idx(esw)] = flow;
749         }
750
751         mlx5_esw_for_each_vf_vport_num(esw, i, mlx5_core_max_vfs(esw->dev)) {
752                 esw_set_peer_miss_rule_source_port(esw,
753                                                    peer_dev->priv.eswitch,
754                                                    spec, i);
755
756                 flow = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb,
757                                            spec, &flow_act, &dest, 1);
758                 if (IS_ERR(flow)) {
759                         err = PTR_ERR(flow);
760                         goto add_vf_flow_err;
761                 }
762                 flows[i] = flow;
763         }
764
765         esw->fdb_table.offloads.peer_miss_rules = flows;
766
767         kvfree(spec);
768         return 0;
769
770 add_vf_flow_err:
771         nvports = --i;
772         mlx5_esw_for_each_vf_vport_num_reverse(esw, i, nvports)
773                 mlx5_del_flow_rules(flows[i]);
774
775         if (mlx5_ecpf_vport_exists(esw->dev))
776                 mlx5_del_flow_rules(flows[mlx5_eswitch_ecpf_idx(esw)]);
777 add_ecpf_flow_err:
778         if (mlx5_core_is_ecpf_esw_manager(esw->dev))
779                 mlx5_del_flow_rules(flows[MLX5_VPORT_PF]);
780 add_pf_flow_err:
781         esw_warn(esw->dev, "FDB: Failed to add peer miss flow rule err %d\n", err);
782         kvfree(flows);
783 alloc_flows_err:
784         kvfree(spec);
785         return err;
786 }
787
788 static void esw_del_fdb_peer_miss_rules(struct mlx5_eswitch *esw)
789 {
790         struct mlx5_flow_handle **flows;
791         int i;
792
793         flows = esw->fdb_table.offloads.peer_miss_rules;
794
795         mlx5_esw_for_each_vf_vport_num_reverse(esw, i,
796                                                mlx5_core_max_vfs(esw->dev))
797                 mlx5_del_flow_rules(flows[i]);
798
799         if (mlx5_ecpf_vport_exists(esw->dev))
800                 mlx5_del_flow_rules(flows[mlx5_eswitch_ecpf_idx(esw)]);
801
802         if (mlx5_core_is_ecpf_esw_manager(esw->dev))
803                 mlx5_del_flow_rules(flows[MLX5_VPORT_PF]);
804
805         kvfree(flows);
806 }
807
808 static int esw_add_fdb_miss_rule(struct mlx5_eswitch *esw)
809 {
810         struct mlx5_flow_act flow_act = {0};
811         struct mlx5_flow_destination dest = {};
812         struct mlx5_flow_handle *flow_rule = NULL;
813         struct mlx5_flow_spec *spec;
814         void *headers_c;
815         void *headers_v;
816         int err = 0;
817         u8 *dmac_c;
818         u8 *dmac_v;
819
820         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
821         if (!spec) {
822                 err = -ENOMEM;
823                 goto out;
824         }
825
826         spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
827         headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
828                                  outer_headers);
829         dmac_c = MLX5_ADDR_OF(fte_match_param, headers_c,
830                               outer_headers.dmac_47_16);
831         dmac_c[0] = 0x01;
832
833         dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
834         dest.vport.num = esw->manager_vport;
835         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
836
837         flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb, spec,
838                                         &flow_act, &dest, 1);
839         if (IS_ERR(flow_rule)) {
840                 err = PTR_ERR(flow_rule);
841                 esw_warn(esw->dev,  "FDB: Failed to add unicast miss flow rule err %d\n", err);
842                 goto out;
843         }
844
845         esw->fdb_table.offloads.miss_rule_uni = flow_rule;
846
847         headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
848                                  outer_headers);
849         dmac_v = MLX5_ADDR_OF(fte_match_param, headers_v,
850                               outer_headers.dmac_47_16);
851         dmac_v[0] = 0x01;
852         flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb, spec,
853                                         &flow_act, &dest, 1);
854         if (IS_ERR(flow_rule)) {
855                 err = PTR_ERR(flow_rule);
856                 esw_warn(esw->dev, "FDB: Failed to add multicast miss flow rule err %d\n", err);
857                 mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_uni);
858                 goto out;
859         }
860
861         esw->fdb_table.offloads.miss_rule_multi = flow_rule;
862
863 out:
864         kvfree(spec);
865         return err;
866 }
867
868 #define ESW_OFFLOADS_NUM_GROUPS  4
869
870 /* Firmware currently has 4 pool of 4 sizes that it supports (ESW_POOLS),
871  * and a virtual memory region of 16M (ESW_SIZE), this region is duplicated
872  * for each flow table pool. We can allocate up to 16M of each pool,
873  * and we keep track of how much we used via put/get_sz_to_pool.
874  * Firmware doesn't report any of this for now.
875  * ESW_POOL is expected to be sorted from large to small
876  */
877 #define ESW_SIZE (16 * 1024 * 1024)
878 const unsigned int ESW_POOLS[4] = { 4 * 1024 * 1024, 1 * 1024 * 1024,
879                                     64 * 1024, 4 * 1024 };
880
881 static int
882 get_sz_from_pool(struct mlx5_eswitch *esw)
883 {
884         int sz = 0, i;
885
886         for (i = 0; i < ARRAY_SIZE(ESW_POOLS); i++) {
887                 if (esw->fdb_table.offloads.fdb_left[i]) {
888                         --esw->fdb_table.offloads.fdb_left[i];
889                         sz = ESW_POOLS[i];
890                         break;
891                 }
892         }
893
894         return sz;
895 }
896
897 static void
898 put_sz_to_pool(struct mlx5_eswitch *esw, int sz)
899 {
900         int i;
901
902         for (i = 0; i < ARRAY_SIZE(ESW_POOLS); i++) {
903                 if (sz >= ESW_POOLS[i]) {
904                         ++esw->fdb_table.offloads.fdb_left[i];
905                         break;
906                 }
907         }
908 }
909
910 static struct mlx5_flow_table *
911 create_next_size_table(struct mlx5_eswitch *esw,
912                        struct mlx5_flow_namespace *ns,
913                        u16 table_prio,
914                        int level,
915                        u32 flags)
916 {
917         struct mlx5_flow_table *fdb;
918         int sz;
919
920         sz = get_sz_from_pool(esw);
921         if (!sz)
922                 return ERR_PTR(-ENOSPC);
923
924         fdb = mlx5_create_auto_grouped_flow_table(ns,
925                                                   table_prio,
926                                                   sz,
927                                                   ESW_OFFLOADS_NUM_GROUPS,
928                                                   level,
929                                                   flags);
930         if (IS_ERR(fdb)) {
931                 esw_warn(esw->dev, "Failed to create FDB Table err %d (table prio: %d, level: %d, size: %d)\n",
932                          (int)PTR_ERR(fdb), table_prio, level, sz);
933                 put_sz_to_pool(esw, sz);
934         }
935
936         return fdb;
937 }
938
939 static struct mlx5_flow_table *
940 esw_get_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level)
941 {
942         struct mlx5_core_dev *dev = esw->dev;
943         struct mlx5_flow_table *fdb = NULL;
944         struct mlx5_flow_namespace *ns;
945         int table_prio, l = 0;
946         u32 flags = 0;
947
948         if (chain == FDB_SLOW_PATH_CHAIN)
949                 return esw->fdb_table.offloads.slow_fdb;
950
951         mutex_lock(&esw->fdb_table.offloads.fdb_prio_lock);
952
953         fdb = fdb_prio_table(esw, chain, prio, level).fdb;
954         if (fdb) {
955                 /* take ref on earlier levels as well */
956                 while (level >= 0)
957                         fdb_prio_table(esw, chain, prio, level--).num_rules++;
958                 mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock);
959                 return fdb;
960         }
961
962         ns = mlx5_get_fdb_sub_ns(dev, chain);
963         if (!ns) {
964                 esw_warn(dev, "Failed to get FDB sub namespace\n");
965                 mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock);
966                 return ERR_PTR(-EOPNOTSUPP);
967         }
968
969         if (esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE)
970                 flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT |
971                           MLX5_FLOW_TABLE_TUNNEL_EN_DECAP);
972
973         table_prio = (chain * FDB_MAX_PRIO) + prio - 1;
974
975         /* create earlier levels for correct fs_core lookup when
976          * connecting tables
977          */
978         for (l = 0; l <= level; l++) {
979                 if (fdb_prio_table(esw, chain, prio, l).fdb) {
980                         fdb_prio_table(esw, chain, prio, l).num_rules++;
981                         continue;
982                 }
983
984                 fdb = create_next_size_table(esw, ns, table_prio, l, flags);
985                 if (IS_ERR(fdb)) {
986                         l--;
987                         goto err_create_fdb;
988                 }
989
990                 fdb_prio_table(esw, chain, prio, l).fdb = fdb;
991                 fdb_prio_table(esw, chain, prio, l).num_rules = 1;
992         }
993
994         mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock);
995         return fdb;
996
997 err_create_fdb:
998         mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock);
999         if (l >= 0)
1000                 esw_put_prio_table(esw, chain, prio, l);
1001
1002         return fdb;
1003 }
1004
1005 static void
1006 esw_put_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level)
1007 {
1008         int l;
1009
1010         if (chain == FDB_SLOW_PATH_CHAIN)
1011                 return;
1012
1013         mutex_lock(&esw->fdb_table.offloads.fdb_prio_lock);
1014
1015         for (l = level; l >= 0; l--) {
1016                 if (--(fdb_prio_table(esw, chain, prio, l).num_rules) > 0)
1017                         continue;
1018
1019                 put_sz_to_pool(esw, fdb_prio_table(esw, chain, prio, l).fdb->max_fte);
1020                 mlx5_destroy_flow_table(fdb_prio_table(esw, chain, prio, l).fdb);
1021                 fdb_prio_table(esw, chain, prio, l).fdb = NULL;
1022         }
1023
1024         mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock);
1025 }
1026
1027 static void esw_destroy_offloads_fast_fdb_tables(struct mlx5_eswitch *esw)
1028 {
1029         /* If lazy creation isn't supported, deref the fast path tables */
1030         if (!(esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED)) {
1031                 esw_put_prio_table(esw, 0, 1, 1);
1032                 esw_put_prio_table(esw, 0, 1, 0);
1033         }
1034 }
1035
1036 #define MAX_PF_SQ 256
1037 #define MAX_SQ_NVPORTS 32
1038
1039 static void esw_set_flow_group_source_port(struct mlx5_eswitch *esw,
1040                                            u32 *flow_group_in)
1041 {
1042         void *match_criteria = MLX5_ADDR_OF(create_flow_group_in,
1043                                             flow_group_in,
1044                                             match_criteria);
1045
1046         if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
1047                 MLX5_SET(create_flow_group_in, flow_group_in,
1048                          match_criteria_enable,
1049                          MLX5_MATCH_MISC_PARAMETERS_2);
1050
1051                 MLX5_SET_TO_ONES(fte_match_param, match_criteria,
1052                                  misc_parameters_2.metadata_reg_c_0);
1053         } else {
1054                 MLX5_SET(create_flow_group_in, flow_group_in,
1055                          match_criteria_enable,
1056                          MLX5_MATCH_MISC_PARAMETERS);
1057
1058                 MLX5_SET_TO_ONES(fte_match_param, match_criteria,
1059                                  misc_parameters.source_port);
1060         }
1061 }
1062
1063 static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw, int nvports)
1064 {
1065         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
1066         struct mlx5_flow_table_attr ft_attr = {};
1067         struct mlx5_core_dev *dev = esw->dev;
1068         u32 *flow_group_in, max_flow_counter;
1069         struct mlx5_flow_namespace *root_ns;
1070         struct mlx5_flow_table *fdb = NULL;
1071         int table_size, ix, err = 0, i;
1072         struct mlx5_flow_group *g;
1073         u32 flags = 0, fdb_max;
1074         void *match_criteria;
1075         u8 *dmac;
1076
1077         esw_debug(esw->dev, "Create offloads FDB Tables\n");
1078         flow_group_in = kvzalloc(inlen, GFP_KERNEL);
1079         if (!flow_group_in)
1080                 return -ENOMEM;
1081
1082         root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
1083         if (!root_ns) {
1084                 esw_warn(dev, "Failed to get FDB flow namespace\n");
1085                 err = -EOPNOTSUPP;
1086                 goto ns_err;
1087         }
1088
1089         max_flow_counter = (MLX5_CAP_GEN(dev, max_flow_counter_31_16) << 16) |
1090                             MLX5_CAP_GEN(dev, max_flow_counter_15_0);
1091         fdb_max = 1 << MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size);
1092
1093         esw_debug(dev, "Create offloads FDB table, min (max esw size(2^%d), max counters(%d), groups(%d), max flow table size(2^%d))\n",
1094                   MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size),
1095                   max_flow_counter, ESW_OFFLOADS_NUM_GROUPS,
1096                   fdb_max);
1097
1098         for (i = 0; i < ARRAY_SIZE(ESW_POOLS); i++)
1099                 esw->fdb_table.offloads.fdb_left[i] =
1100                         ESW_POOLS[i] <= fdb_max ? ESW_SIZE / ESW_POOLS[i] : 0;
1101
1102         table_size = nvports * MAX_SQ_NVPORTS + MAX_PF_SQ +
1103                 MLX5_ESW_MISS_FLOWS + esw->total_vports;
1104
1105         /* create the slow path fdb with encap set, so further table instances
1106          * can be created at run time while VFs are probed if the FW allows that.
1107          */
1108         if (esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE)
1109                 flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT |
1110                           MLX5_FLOW_TABLE_TUNNEL_EN_DECAP);
1111
1112         ft_attr.flags = flags;
1113         ft_attr.max_fte = table_size;
1114         ft_attr.prio = FDB_SLOW_PATH;
1115
1116         fdb = mlx5_create_flow_table(root_ns, &ft_attr);
1117         if (IS_ERR(fdb)) {
1118                 err = PTR_ERR(fdb);
1119                 esw_warn(dev, "Failed to create slow path FDB Table err %d\n", err);
1120                 goto slow_fdb_err;
1121         }
1122         esw->fdb_table.offloads.slow_fdb = fdb;
1123
1124         /* If lazy creation isn't supported, open the fast path tables now */
1125         if (!MLX5_CAP_ESW_FLOWTABLE(esw->dev, multi_fdb_encap) &&
1126             esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE) {
1127                 esw->fdb_table.flags &= ~ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED;
1128                 esw_warn(dev, "Lazy creation of flow tables isn't supported, ignoring priorities\n");
1129                 esw_get_prio_table(esw, 0, 1, 0);
1130                 esw_get_prio_table(esw, 0, 1, 1);
1131         } else {
1132                 esw_debug(dev, "Lazy creation of flow tables supported, deferring table opening\n");
1133                 esw->fdb_table.flags |= ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED;
1134         }
1135
1136         /* create send-to-vport group */
1137         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
1138                  MLX5_MATCH_MISC_PARAMETERS);
1139
1140         match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
1141
1142         MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_sqn);
1143         MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_port);
1144
1145         ix = nvports * MAX_SQ_NVPORTS + MAX_PF_SQ;
1146         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
1147         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, ix - 1);
1148
1149         g = mlx5_create_flow_group(fdb, flow_group_in);
1150         if (IS_ERR(g)) {
1151                 err = PTR_ERR(g);
1152                 esw_warn(dev, "Failed to create send-to-vport flow group err(%d)\n", err);
1153                 goto send_vport_err;
1154         }
1155         esw->fdb_table.offloads.send_to_vport_grp = g;
1156
1157         /* create peer esw miss group */
1158         memset(flow_group_in, 0, inlen);
1159
1160         esw_set_flow_group_source_port(esw, flow_group_in);
1161
1162         if (!mlx5_eswitch_vport_match_metadata_enabled(esw)) {
1163                 match_criteria = MLX5_ADDR_OF(create_flow_group_in,
1164                                               flow_group_in,
1165                                               match_criteria);
1166
1167                 MLX5_SET_TO_ONES(fte_match_param, match_criteria,
1168                                  misc_parameters.source_eswitch_owner_vhca_id);
1169
1170                 MLX5_SET(create_flow_group_in, flow_group_in,
1171                          source_eswitch_owner_vhca_id_valid, 1);
1172         }
1173
1174         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ix);
1175         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index,
1176                  ix + esw->total_vports - 1);
1177         ix += esw->total_vports;
1178
1179         g = mlx5_create_flow_group(fdb, flow_group_in);
1180         if (IS_ERR(g)) {
1181                 err = PTR_ERR(g);
1182                 esw_warn(dev, "Failed to create peer miss flow group err(%d)\n", err);
1183                 goto peer_miss_err;
1184         }
1185         esw->fdb_table.offloads.peer_miss_grp = g;
1186
1187         /* create miss group */
1188         memset(flow_group_in, 0, inlen);
1189         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
1190                  MLX5_MATCH_OUTER_HEADERS);
1191         match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in,
1192                                       match_criteria);
1193         dmac = MLX5_ADDR_OF(fte_match_param, match_criteria,
1194                             outer_headers.dmac_47_16);
1195         dmac[0] = 0x01;
1196
1197         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ix);
1198         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index,
1199                  ix + MLX5_ESW_MISS_FLOWS);
1200
1201         g = mlx5_create_flow_group(fdb, flow_group_in);
1202         if (IS_ERR(g)) {
1203                 err = PTR_ERR(g);
1204                 esw_warn(dev, "Failed to create miss flow group err(%d)\n", err);
1205                 goto miss_err;
1206         }
1207         esw->fdb_table.offloads.miss_grp = g;
1208
1209         err = esw_add_fdb_miss_rule(esw);
1210         if (err)
1211                 goto miss_rule_err;
1212
1213         esw->nvports = nvports;
1214         kvfree(flow_group_in);
1215         return 0;
1216
1217 miss_rule_err:
1218         mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
1219 miss_err:
1220         mlx5_destroy_flow_group(esw->fdb_table.offloads.peer_miss_grp);
1221 peer_miss_err:
1222         mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
1223 send_vport_err:
1224         esw_destroy_offloads_fast_fdb_tables(esw);
1225         mlx5_destroy_flow_table(esw->fdb_table.offloads.slow_fdb);
1226 slow_fdb_err:
1227 ns_err:
1228         kvfree(flow_group_in);
1229         return err;
1230 }
1231
1232 static void esw_destroy_offloads_fdb_tables(struct mlx5_eswitch *esw)
1233 {
1234         if (!esw->fdb_table.offloads.slow_fdb)
1235                 return;
1236
1237         esw_debug(esw->dev, "Destroy offloads FDB Tables\n");
1238         mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_multi);
1239         mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_uni);
1240         mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
1241         mlx5_destroy_flow_group(esw->fdb_table.offloads.peer_miss_grp);
1242         mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
1243
1244         mlx5_destroy_flow_table(esw->fdb_table.offloads.slow_fdb);
1245         esw_destroy_offloads_fast_fdb_tables(esw);
1246 }
1247
1248 static int esw_create_offloads_table(struct mlx5_eswitch *esw, int nvports)
1249 {
1250         struct mlx5_flow_table_attr ft_attr = {};
1251         struct mlx5_core_dev *dev = esw->dev;
1252         struct mlx5_flow_table *ft_offloads;
1253         struct mlx5_flow_namespace *ns;
1254         int err = 0;
1255
1256         ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_OFFLOADS);
1257         if (!ns) {
1258                 esw_warn(esw->dev, "Failed to get offloads flow namespace\n");
1259                 return -EOPNOTSUPP;
1260         }
1261
1262         ft_attr.max_fte = nvports + MLX5_ESW_MISS_FLOWS;
1263
1264         ft_offloads = mlx5_create_flow_table(ns, &ft_attr);
1265         if (IS_ERR(ft_offloads)) {
1266                 err = PTR_ERR(ft_offloads);
1267                 esw_warn(esw->dev, "Failed to create offloads table, err %d\n", err);
1268                 return err;
1269         }
1270
1271         esw->offloads.ft_offloads = ft_offloads;
1272         return 0;
1273 }
1274
1275 static void esw_destroy_offloads_table(struct mlx5_eswitch *esw)
1276 {
1277         struct mlx5_esw_offload *offloads = &esw->offloads;
1278
1279         mlx5_destroy_flow_table(offloads->ft_offloads);
1280 }
1281
1282 static int esw_create_vport_rx_group(struct mlx5_eswitch *esw, int nvports)
1283 {
1284         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
1285         struct mlx5_flow_group *g;
1286         u32 *flow_group_in;
1287         int err = 0;
1288
1289         nvports = nvports + MLX5_ESW_MISS_FLOWS;
1290         flow_group_in = kvzalloc(inlen, GFP_KERNEL);
1291         if (!flow_group_in)
1292                 return -ENOMEM;
1293
1294         /* create vport rx group */
1295         esw_set_flow_group_source_port(esw, flow_group_in);
1296
1297         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
1298         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, nvports - 1);
1299
1300         g = mlx5_create_flow_group(esw->offloads.ft_offloads, flow_group_in);
1301
1302         if (IS_ERR(g)) {
1303                 err = PTR_ERR(g);
1304                 mlx5_core_warn(esw->dev, "Failed to create vport rx group err %d\n", err);
1305                 goto out;
1306         }
1307
1308         esw->offloads.vport_rx_group = g;
1309 out:
1310         kvfree(flow_group_in);
1311         return err;
1312 }
1313
1314 static void esw_destroy_vport_rx_group(struct mlx5_eswitch *esw)
1315 {
1316         mlx5_destroy_flow_group(esw->offloads.vport_rx_group);
1317 }
1318
1319 struct mlx5_flow_handle *
1320 mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, u16 vport,
1321                                   struct mlx5_flow_destination *dest)
1322 {
1323         struct mlx5_flow_act flow_act = {0};
1324         struct mlx5_flow_handle *flow_rule;
1325         struct mlx5_flow_spec *spec;
1326         void *misc;
1327
1328         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1329         if (!spec) {
1330                 flow_rule = ERR_PTR(-ENOMEM);
1331                 goto out;
1332         }
1333
1334         if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
1335                 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters_2);
1336                 MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0,
1337                          mlx5_eswitch_get_vport_metadata_for_match(esw, vport));
1338
1339                 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters_2);
1340                 MLX5_SET_TO_ONES(fte_match_set_misc2, misc, metadata_reg_c_0);
1341
1342                 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS_2;
1343         } else {
1344                 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
1345                 MLX5_SET(fte_match_set_misc, misc, source_port, vport);
1346
1347                 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
1348                 MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
1349
1350                 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
1351         }
1352
1353         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
1354         flow_rule = mlx5_add_flow_rules(esw->offloads.ft_offloads, spec,
1355                                         &flow_act, dest, 1);
1356         if (IS_ERR(flow_rule)) {
1357                 esw_warn(esw->dev, "fs offloads: Failed to add vport rx rule err %ld\n", PTR_ERR(flow_rule));
1358                 goto out;
1359         }
1360
1361 out:
1362         kvfree(spec);
1363         return flow_rule;
1364 }
1365
1366 static int esw_offloads_start(struct mlx5_eswitch *esw,
1367                               struct netlink_ext_ack *extack)
1368 {
1369         int err, err1;
1370
1371         if (esw->mode != MLX5_ESWITCH_LEGACY &&
1372             !mlx5_core_is_ecpf_esw_manager(esw->dev)) {
1373                 NL_SET_ERR_MSG_MOD(extack,
1374                                    "Can't set offloads mode, SRIOV legacy not enabled");
1375                 return -EINVAL;
1376         }
1377
1378         mlx5_eswitch_disable(esw);
1379         mlx5_eswitch_update_num_of_vfs(esw, esw->dev->priv.sriov.num_vfs);
1380         err = mlx5_eswitch_enable(esw, MLX5_ESWITCH_OFFLOADS);
1381         if (err) {
1382                 NL_SET_ERR_MSG_MOD(extack,
1383                                    "Failed setting eswitch to offloads");
1384                 err1 = mlx5_eswitch_enable(esw, MLX5_ESWITCH_LEGACY);
1385                 if (err1) {
1386                         NL_SET_ERR_MSG_MOD(extack,
1387                                            "Failed setting eswitch back to legacy");
1388                 }
1389         }
1390         if (esw->offloads.inline_mode == MLX5_INLINE_MODE_NONE) {
1391                 if (mlx5_eswitch_inline_mode_get(esw,
1392                                                  &esw->offloads.inline_mode)) {
1393                         esw->offloads.inline_mode = MLX5_INLINE_MODE_L2;
1394                         NL_SET_ERR_MSG_MOD(extack,
1395                                            "Inline mode is different between vports");
1396                 }
1397         }
1398         return err;
1399 }
1400
1401 void esw_offloads_cleanup_reps(struct mlx5_eswitch *esw)
1402 {
1403         kfree(esw->offloads.vport_reps);
1404 }
1405
1406 int esw_offloads_init_reps(struct mlx5_eswitch *esw)
1407 {
1408         int total_vports = esw->total_vports;
1409         struct mlx5_core_dev *dev = esw->dev;
1410         struct mlx5_eswitch_rep *rep;
1411         u8 hw_id[ETH_ALEN], rep_type;
1412         int vport_index;
1413
1414         esw->offloads.vport_reps = kcalloc(total_vports,
1415                                            sizeof(struct mlx5_eswitch_rep),
1416                                            GFP_KERNEL);
1417         if (!esw->offloads.vport_reps)
1418                 return -ENOMEM;
1419
1420         mlx5_query_mac_address(dev, hw_id);
1421
1422         mlx5_esw_for_all_reps(esw, vport_index, rep) {
1423                 rep->vport = mlx5_eswitch_index_to_vport_num(esw, vport_index);
1424                 rep->vport_index = vport_index;
1425                 ether_addr_copy(rep->hw_id, hw_id);
1426
1427                 for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++)
1428                         atomic_set(&rep->rep_data[rep_type].state,
1429                                    REP_UNREGISTERED);
1430         }
1431
1432         return 0;
1433 }
1434
1435 static void __esw_offloads_unload_rep(struct mlx5_eswitch *esw,
1436                                       struct mlx5_eswitch_rep *rep, u8 rep_type)
1437 {
1438         if (atomic_cmpxchg(&rep->rep_data[rep_type].state,
1439                            REP_LOADED, REP_REGISTERED) == REP_LOADED)
1440                 esw->offloads.rep_ops[rep_type]->unload(rep);
1441 }
1442
1443 static void __unload_reps_special_vport(struct mlx5_eswitch *esw, u8 rep_type)
1444 {
1445         struct mlx5_eswitch_rep *rep;
1446
1447         if (mlx5_ecpf_vport_exists(esw->dev)) {
1448                 rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_ECPF);
1449                 __esw_offloads_unload_rep(esw, rep, rep_type);
1450         }
1451
1452         if (mlx5_core_is_ecpf_esw_manager(esw->dev)) {
1453                 rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_PF);
1454                 __esw_offloads_unload_rep(esw, rep, rep_type);
1455         }
1456
1457         rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_UPLINK);
1458         __esw_offloads_unload_rep(esw, rep, rep_type);
1459 }
1460
1461 static void __unload_reps_vf_vport(struct mlx5_eswitch *esw, int nvports,
1462                                    u8 rep_type)
1463 {
1464         struct mlx5_eswitch_rep *rep;
1465         int i;
1466
1467         mlx5_esw_for_each_vf_rep_reverse(esw, i, rep, nvports)
1468                 __esw_offloads_unload_rep(esw, rep, rep_type);
1469 }
1470
1471 static void esw_offloads_unload_vf_reps(struct mlx5_eswitch *esw, int nvports)
1472 {
1473         u8 rep_type = NUM_REP_TYPES;
1474
1475         while (rep_type-- > 0)
1476                 __unload_reps_vf_vport(esw, nvports, rep_type);
1477 }
1478
1479 static void __unload_reps_all_vport(struct mlx5_eswitch *esw, u8 rep_type)
1480 {
1481         __unload_reps_vf_vport(esw, esw->esw_funcs.num_vfs, rep_type);
1482
1483         /* Special vports must be the last to unload. */
1484         __unload_reps_special_vport(esw, rep_type);
1485 }
1486
1487 static void esw_offloads_unload_all_reps(struct mlx5_eswitch *esw)
1488 {
1489         u8 rep_type = NUM_REP_TYPES;
1490
1491         while (rep_type-- > 0)
1492                 __unload_reps_all_vport(esw, rep_type);
1493 }
1494
1495 static int __esw_offloads_load_rep(struct mlx5_eswitch *esw,
1496                                    struct mlx5_eswitch_rep *rep, u8 rep_type)
1497 {
1498         int err = 0;
1499
1500         if (atomic_cmpxchg(&rep->rep_data[rep_type].state,
1501                            REP_REGISTERED, REP_LOADED) == REP_REGISTERED) {
1502                 err = esw->offloads.rep_ops[rep_type]->load(esw->dev, rep);
1503                 if (err)
1504                         atomic_set(&rep->rep_data[rep_type].state,
1505                                    REP_REGISTERED);
1506         }
1507
1508         return err;
1509 }
1510
1511 static int __load_reps_special_vport(struct mlx5_eswitch *esw, u8 rep_type)
1512 {
1513         struct mlx5_eswitch_rep *rep;
1514         int err;
1515
1516         rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_UPLINK);
1517         err = __esw_offloads_load_rep(esw, rep, rep_type);
1518         if (err)
1519                 return err;
1520
1521         if (mlx5_core_is_ecpf_esw_manager(esw->dev)) {
1522                 rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_PF);
1523                 err = __esw_offloads_load_rep(esw, rep, rep_type);
1524                 if (err)
1525                         goto err_pf;
1526         }
1527
1528         if (mlx5_ecpf_vport_exists(esw->dev)) {
1529                 rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_ECPF);
1530                 err = __esw_offloads_load_rep(esw, rep, rep_type);
1531                 if (err)
1532                         goto err_ecpf;
1533         }
1534
1535         return 0;
1536
1537 err_ecpf:
1538         if (mlx5_core_is_ecpf_esw_manager(esw->dev)) {
1539                 rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_PF);
1540                 __esw_offloads_unload_rep(esw, rep, rep_type);
1541         }
1542
1543 err_pf:
1544         rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_UPLINK);
1545         __esw_offloads_unload_rep(esw, rep, rep_type);
1546         return err;
1547 }
1548
1549 static int __load_reps_vf_vport(struct mlx5_eswitch *esw, int nvports,
1550                                 u8 rep_type)
1551 {
1552         struct mlx5_eswitch_rep *rep;
1553         int err, i;
1554
1555         mlx5_esw_for_each_vf_rep(esw, i, rep, nvports) {
1556                 err = __esw_offloads_load_rep(esw, rep, rep_type);
1557                 if (err)
1558                         goto err_vf;
1559         }
1560
1561         return 0;
1562
1563 err_vf:
1564         __unload_reps_vf_vport(esw, --i, rep_type);
1565         return err;
1566 }
1567
1568 static int __load_reps_all_vport(struct mlx5_eswitch *esw, u8 rep_type)
1569 {
1570         int err;
1571
1572         /* Special vports must be loaded first, uplink rep creates mdev resource. */
1573         err = __load_reps_special_vport(esw, rep_type);
1574         if (err)
1575                 return err;
1576
1577         err = __load_reps_vf_vport(esw, esw->esw_funcs.num_vfs, rep_type);
1578         if (err)
1579                 goto err_vfs;
1580
1581         return 0;
1582
1583 err_vfs:
1584         __unload_reps_special_vport(esw, rep_type);
1585         return err;
1586 }
1587
1588 static int esw_offloads_load_vf_reps(struct mlx5_eswitch *esw, int nvports)
1589 {
1590         u8 rep_type = 0;
1591         int err;
1592
1593         for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++) {
1594                 err = __load_reps_vf_vport(esw, nvports, rep_type);
1595                 if (err)
1596                         goto err_reps;
1597         }
1598
1599         return err;
1600
1601 err_reps:
1602         while (rep_type-- > 0)
1603                 __unload_reps_vf_vport(esw, nvports, rep_type);
1604         return err;
1605 }
1606
1607 static int esw_offloads_load_all_reps(struct mlx5_eswitch *esw)
1608 {
1609         u8 rep_type = 0;
1610         int err;
1611
1612         for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++) {
1613                 err = __load_reps_all_vport(esw, rep_type);
1614                 if (err)
1615                         goto err_reps;
1616         }
1617
1618         return err;
1619
1620 err_reps:
1621         while (rep_type-- > 0)
1622                 __unload_reps_all_vport(esw, rep_type);
1623         return err;
1624 }
1625
1626 #define ESW_OFFLOADS_DEVCOM_PAIR        (0)
1627 #define ESW_OFFLOADS_DEVCOM_UNPAIR      (1)
1628
1629 static int mlx5_esw_offloads_pair(struct mlx5_eswitch *esw,
1630                                   struct mlx5_eswitch *peer_esw)
1631 {
1632         int err;
1633
1634         err = esw_add_fdb_peer_miss_rules(esw, peer_esw->dev);
1635         if (err)
1636                 return err;
1637
1638         return 0;
1639 }
1640
1641 static void mlx5_esw_offloads_unpair(struct mlx5_eswitch *esw)
1642 {
1643         mlx5e_tc_clean_fdb_peer_flows(esw);
1644         esw_del_fdb_peer_miss_rules(esw);
1645 }
1646
1647 static int mlx5_esw_offloads_devcom_event(int event,
1648                                           void *my_data,
1649                                           void *event_data)
1650 {
1651         struct mlx5_eswitch *esw = my_data;
1652         struct mlx5_eswitch *peer_esw = event_data;
1653         struct mlx5_devcom *devcom = esw->dev->priv.devcom;
1654         int err;
1655
1656         switch (event) {
1657         case ESW_OFFLOADS_DEVCOM_PAIR:
1658                 if (mlx5_eswitch_vport_match_metadata_enabled(esw) !=
1659                     mlx5_eswitch_vport_match_metadata_enabled(peer_esw))
1660                         break;
1661
1662                 err = mlx5_esw_offloads_pair(esw, peer_esw);
1663                 if (err)
1664                         goto err_out;
1665
1666                 err = mlx5_esw_offloads_pair(peer_esw, esw);
1667                 if (err)
1668                         goto err_pair;
1669
1670                 mlx5_devcom_set_paired(devcom, MLX5_DEVCOM_ESW_OFFLOADS, true);
1671                 break;
1672
1673         case ESW_OFFLOADS_DEVCOM_UNPAIR:
1674                 if (!mlx5_devcom_is_paired(devcom, MLX5_DEVCOM_ESW_OFFLOADS))
1675                         break;
1676
1677                 mlx5_devcom_set_paired(devcom, MLX5_DEVCOM_ESW_OFFLOADS, false);
1678                 mlx5_esw_offloads_unpair(peer_esw);
1679                 mlx5_esw_offloads_unpair(esw);
1680                 break;
1681         }
1682
1683         return 0;
1684
1685 err_pair:
1686         mlx5_esw_offloads_unpair(esw);
1687
1688 err_out:
1689         mlx5_core_err(esw->dev, "esw offloads devcom event failure, event %u err %d",
1690                       event, err);
1691         return err;
1692 }
1693
1694 static void esw_offloads_devcom_init(struct mlx5_eswitch *esw)
1695 {
1696         struct mlx5_devcom *devcom = esw->dev->priv.devcom;
1697
1698         INIT_LIST_HEAD(&esw->offloads.peer_flows);
1699         mutex_init(&esw->offloads.peer_mutex);
1700
1701         if (!MLX5_CAP_ESW(esw->dev, merged_eswitch))
1702                 return;
1703
1704         mlx5_devcom_register_component(devcom,
1705                                        MLX5_DEVCOM_ESW_OFFLOADS,
1706                                        mlx5_esw_offloads_devcom_event,
1707                                        esw);
1708
1709         mlx5_devcom_send_event(devcom,
1710                                MLX5_DEVCOM_ESW_OFFLOADS,
1711                                ESW_OFFLOADS_DEVCOM_PAIR, esw);
1712 }
1713
1714 static void esw_offloads_devcom_cleanup(struct mlx5_eswitch *esw)
1715 {
1716         struct mlx5_devcom *devcom = esw->dev->priv.devcom;
1717
1718         if (!MLX5_CAP_ESW(esw->dev, merged_eswitch))
1719                 return;
1720
1721         mlx5_devcom_send_event(devcom, MLX5_DEVCOM_ESW_OFFLOADS,
1722                                ESW_OFFLOADS_DEVCOM_UNPAIR, esw);
1723
1724         mlx5_devcom_unregister_component(devcom, MLX5_DEVCOM_ESW_OFFLOADS);
1725 }
1726
1727 static int esw_vport_ingress_prio_tag_config(struct mlx5_eswitch *esw,
1728                                              struct mlx5_vport *vport)
1729 {
1730         struct mlx5_flow_act flow_act = {0};
1731         struct mlx5_flow_spec *spec;
1732         int err = 0;
1733
1734         /* For prio tag mode, there is only 1 FTEs:
1735          * 1) Untagged packets - push prio tag VLAN and modify metadata if
1736          * required, allow
1737          * Unmatched traffic is allowed by default
1738          */
1739
1740         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1741         if (!spec) {
1742                 err = -ENOMEM;
1743                 goto out_no_mem;
1744         }
1745
1746         /* Untagged packets - push prio tag VLAN, allow */
1747         MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.cvlan_tag);
1748         MLX5_SET(fte_match_param, spec->match_value, outer_headers.cvlan_tag, 0);
1749         spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
1750         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH |
1751                           MLX5_FLOW_CONTEXT_ACTION_ALLOW;
1752         flow_act.vlan[0].ethtype = ETH_P_8021Q;
1753         flow_act.vlan[0].vid = 0;
1754         flow_act.vlan[0].prio = 0;
1755
1756         if (vport->ingress.modify_metadata_rule) {
1757                 flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
1758                 flow_act.modify_id = vport->ingress.modify_metadata_id;
1759         }
1760
1761         vport->ingress.allow_rule =
1762                 mlx5_add_flow_rules(vport->ingress.acl, spec,
1763                                     &flow_act, NULL, 0);
1764         if (IS_ERR(vport->ingress.allow_rule)) {
1765                 err = PTR_ERR(vport->ingress.allow_rule);
1766                 esw_warn(esw->dev,
1767                          "vport[%d] configure ingress untagged allow rule, err(%d)\n",
1768                          vport->vport, err);
1769                 vport->ingress.allow_rule = NULL;
1770                 goto out;
1771         }
1772
1773 out:
1774         kvfree(spec);
1775 out_no_mem:
1776         if (err)
1777                 esw_vport_cleanup_ingress_rules(esw, vport);
1778         return err;
1779 }
1780
1781 static int esw_vport_add_ingress_acl_modify_metadata(struct mlx5_eswitch *esw,
1782                                                      struct mlx5_vport *vport)
1783 {
1784         u8 action[MLX5_UN_SZ_BYTES(set_action_in_add_action_in_auto)] = {};
1785         static const struct mlx5_flow_spec spec = {};
1786         struct mlx5_flow_act flow_act = {};
1787         int err = 0;
1788
1789         MLX5_SET(set_action_in, action, action_type, MLX5_ACTION_TYPE_SET);
1790         MLX5_SET(set_action_in, action, field, MLX5_ACTION_IN_FIELD_METADATA_REG_C_0);
1791         MLX5_SET(set_action_in, action, data,
1792                  mlx5_eswitch_get_vport_metadata_for_match(esw, vport->vport));
1793
1794         err = mlx5_modify_header_alloc(esw->dev, MLX5_FLOW_NAMESPACE_ESW_INGRESS,
1795                                        1, action, &vport->ingress.modify_metadata_id);
1796         if (err) {
1797                 esw_warn(esw->dev,
1798                          "failed to alloc modify header for vport %d ingress acl (%d)\n",
1799                          vport->vport, err);
1800                 return err;
1801         }
1802
1803         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_MOD_HDR | MLX5_FLOW_CONTEXT_ACTION_ALLOW;
1804         flow_act.modify_id = vport->ingress.modify_metadata_id;
1805         vport->ingress.modify_metadata_rule = mlx5_add_flow_rules(vport->ingress.acl,
1806                                                                   &spec, &flow_act, NULL, 0);
1807         if (IS_ERR(vport->ingress.modify_metadata_rule)) {
1808                 err = PTR_ERR(vport->ingress.modify_metadata_rule);
1809                 esw_warn(esw->dev,
1810                          "failed to add setting metadata rule for vport %d ingress acl, err(%d)\n",
1811                          vport->vport, err);
1812                 vport->ingress.modify_metadata_rule = NULL;
1813                 goto out;
1814         }
1815
1816 out:
1817         if (err)
1818                 mlx5_modify_header_dealloc(esw->dev, vport->ingress.modify_metadata_id);
1819         return err;
1820 }
1821
1822 void esw_vport_del_ingress_acl_modify_metadata(struct mlx5_eswitch *esw,
1823                                                struct mlx5_vport *vport)
1824 {
1825         if (vport->ingress.modify_metadata_rule) {
1826                 mlx5_del_flow_rules(vport->ingress.modify_metadata_rule);
1827                 mlx5_modify_header_dealloc(esw->dev, vport->ingress.modify_metadata_id);
1828
1829                 vport->ingress.modify_metadata_rule = NULL;
1830         }
1831 }
1832
1833 static int esw_vport_egress_prio_tag_config(struct mlx5_eswitch *esw,
1834                                             struct mlx5_vport *vport)
1835 {
1836         struct mlx5_flow_act flow_act = {0};
1837         struct mlx5_flow_spec *spec;
1838         int err = 0;
1839
1840         if (!MLX5_CAP_GEN(esw->dev, prio_tag_required))
1841                 return 0;
1842
1843         /* For prio tag mode, there is only 1 FTEs:
1844          * 1) prio tag packets - pop the prio tag VLAN, allow
1845          * Unmatched traffic is allowed by default
1846          */
1847
1848         esw_vport_cleanup_egress_rules(esw, vport);
1849
1850         err = esw_vport_enable_egress_acl(esw, vport);
1851         if (err) {
1852                 mlx5_core_warn(esw->dev,
1853                                "failed to enable egress acl (%d) on vport[%d]\n",
1854                                err, vport->vport);
1855                 return err;
1856         }
1857
1858         esw_debug(esw->dev,
1859                   "vport[%d] configure prio tag egress rules\n", vport->vport);
1860
1861         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1862         if (!spec) {
1863                 err = -ENOMEM;
1864                 goto out_no_mem;
1865         }
1866
1867         /* prio tag vlan rule - pop it so VF receives untagged packets */
1868         MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.cvlan_tag);
1869         MLX5_SET_TO_ONES(fte_match_param, spec->match_value, outer_headers.cvlan_tag);
1870         MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.first_vid);
1871         MLX5_SET(fte_match_param, spec->match_value, outer_headers.first_vid, 0);
1872
1873         spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
1874         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_VLAN_POP |
1875                           MLX5_FLOW_CONTEXT_ACTION_ALLOW;
1876         vport->egress.allowed_vlan =
1877                 mlx5_add_flow_rules(vport->egress.acl, spec,
1878                                     &flow_act, NULL, 0);
1879         if (IS_ERR(vport->egress.allowed_vlan)) {
1880                 err = PTR_ERR(vport->egress.allowed_vlan);
1881                 esw_warn(esw->dev,
1882                          "vport[%d] configure egress pop prio tag vlan rule failed, err(%d)\n",
1883                          vport->vport, err);
1884                 vport->egress.allowed_vlan = NULL;
1885                 goto out;
1886         }
1887
1888 out:
1889         kvfree(spec);
1890 out_no_mem:
1891         if (err)
1892                 esw_vport_cleanup_egress_rules(esw, vport);
1893         return err;
1894 }
1895
1896 static int esw_vport_ingress_common_config(struct mlx5_eswitch *esw,
1897                                            struct mlx5_vport *vport)
1898 {
1899         int err;
1900
1901         if (!mlx5_eswitch_vport_match_metadata_enabled(esw) &&
1902             !MLX5_CAP_GEN(esw->dev, prio_tag_required))
1903                 return 0;
1904
1905         esw_vport_cleanup_ingress_rules(esw, vport);
1906
1907         err = esw_vport_enable_ingress_acl(esw, vport);
1908         if (err) {
1909                 esw_warn(esw->dev,
1910                          "failed to enable ingress acl (%d) on vport[%d]\n",
1911                          err, vport->vport);
1912                 return err;
1913         }
1914
1915         esw_debug(esw->dev,
1916                   "vport[%d] configure ingress rules\n", vport->vport);
1917
1918         if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
1919                 err = esw_vport_add_ingress_acl_modify_metadata(esw, vport);
1920                 if (err)
1921                         goto out;
1922         }
1923
1924         if (MLX5_CAP_GEN(esw->dev, prio_tag_required) &&
1925             mlx5_eswitch_is_vf_vport(esw, vport->vport)) {
1926                 err = esw_vport_ingress_prio_tag_config(esw, vport);
1927                 if (err)
1928                         goto out;
1929         }
1930
1931 out:
1932         if (err)
1933                 esw_vport_disable_ingress_acl(esw, vport);
1934         return err;
1935 }
1936
1937 static bool
1938 esw_check_vport_match_metadata_supported(const struct mlx5_eswitch *esw)
1939 {
1940         if (!MLX5_CAP_ESW(esw->dev, esw_uplink_ingress_acl))
1941                 return false;
1942
1943         if (!(MLX5_CAP_ESW_FLOWTABLE(esw->dev, fdb_to_vport_reg_c_id) &
1944               MLX5_FDB_TO_VPORT_REG_C_0))
1945                 return false;
1946
1947         if (!MLX5_CAP_ESW_FLOWTABLE(esw->dev, flow_source))
1948                 return false;
1949
1950         if (mlx5_core_is_ecpf_esw_manager(esw->dev) ||
1951             mlx5_ecpf_vport_exists(esw->dev))
1952                 return false;
1953
1954         return true;
1955 }
1956
1957 static int esw_create_offloads_acl_tables(struct mlx5_eswitch *esw)
1958 {
1959         struct mlx5_vport *vport;
1960         int i, j;
1961         int err;
1962
1963         if (esw_check_vport_match_metadata_supported(esw))
1964                 esw->flags |= MLX5_ESWITCH_VPORT_MATCH_METADATA;
1965
1966         mlx5_esw_for_all_vports(esw, i, vport) {
1967                 err = esw_vport_ingress_common_config(esw, vport);
1968                 if (err)
1969                         goto err_ingress;
1970
1971                 if (mlx5_eswitch_is_vf_vport(esw, vport->vport)) {
1972                         err = esw_vport_egress_prio_tag_config(esw, vport);
1973                         if (err)
1974                                 goto err_egress;
1975                 }
1976         }
1977
1978         if (mlx5_eswitch_vport_match_metadata_enabled(esw))
1979                 esw_info(esw->dev, "Use metadata reg_c as source vport to match\n");
1980
1981         return 0;
1982
1983 err_egress:
1984         esw_vport_disable_ingress_acl(esw, vport);
1985 err_ingress:
1986         for (j = MLX5_VPORT_PF; j < i; j++) {
1987                 vport = &esw->vports[j];
1988                 esw_vport_disable_egress_acl(esw, vport);
1989                 esw_vport_disable_ingress_acl(esw, vport);
1990         }
1991
1992         return err;
1993 }
1994
1995 static void esw_destroy_offloads_acl_tables(struct mlx5_eswitch *esw)
1996 {
1997         struct mlx5_vport *vport;
1998         int i;
1999
2000         mlx5_esw_for_all_vports(esw, i, vport) {
2001                 esw_vport_disable_egress_acl(esw, vport);
2002                 esw_vport_disable_ingress_acl(esw, vport);
2003         }
2004
2005         esw->flags &= ~MLX5_ESWITCH_VPORT_MATCH_METADATA;
2006 }
2007
2008 static int esw_offloads_steering_init(struct mlx5_eswitch *esw)
2009 {
2010         int num_vfs = esw->esw_funcs.num_vfs;
2011         int total_vports;
2012         int err;
2013
2014         if (mlx5_core_is_ecpf_esw_manager(esw->dev))
2015                 total_vports = esw->total_vports;
2016         else
2017                 total_vports = num_vfs + MLX5_SPECIAL_VPORTS(esw->dev);
2018
2019         memset(&esw->fdb_table.offloads, 0, sizeof(struct offloads_fdb));
2020         mutex_init(&esw->fdb_table.offloads.fdb_prio_lock);
2021
2022         err = esw_create_offloads_acl_tables(esw);
2023         if (err)
2024                 return err;
2025
2026         err = esw_create_offloads_fdb_tables(esw, total_vports);
2027         if (err)
2028                 goto create_fdb_err;
2029
2030         err = esw_create_offloads_table(esw, total_vports);
2031         if (err)
2032                 goto create_ft_err;
2033
2034         err = esw_create_vport_rx_group(esw, total_vports);
2035         if (err)
2036                 goto create_fg_err;
2037
2038         return 0;
2039
2040 create_fg_err:
2041         esw_destroy_offloads_table(esw);
2042
2043 create_ft_err:
2044         esw_destroy_offloads_fdb_tables(esw);
2045
2046 create_fdb_err:
2047         esw_destroy_offloads_acl_tables(esw);
2048
2049         return err;
2050 }
2051
2052 static void esw_offloads_steering_cleanup(struct mlx5_eswitch *esw)
2053 {
2054         esw_destroy_vport_rx_group(esw);
2055         esw_destroy_offloads_table(esw);
2056         esw_destroy_offloads_fdb_tables(esw);
2057         esw_destroy_offloads_acl_tables(esw);
2058 }
2059
2060 static void
2061 esw_vfs_changed_event_handler(struct mlx5_eswitch *esw, const u32 *out)
2062 {
2063         bool host_pf_disabled;
2064         u16 new_num_vfs;
2065
2066         new_num_vfs = MLX5_GET(query_esw_functions_out, out,
2067                                host_params_context.host_num_of_vfs);
2068         host_pf_disabled = MLX5_GET(query_esw_functions_out, out,
2069                                     host_params_context.host_pf_disabled);
2070
2071         if (new_num_vfs == esw->esw_funcs.num_vfs || host_pf_disabled)
2072                 return;
2073
2074         /* Number of VFs can only change from "0 to x" or "x to 0". */
2075         if (esw->esw_funcs.num_vfs > 0) {
2076                 esw_offloads_unload_vf_reps(esw, esw->esw_funcs.num_vfs);
2077         } else {
2078                 int err;
2079
2080                 err = esw_offloads_load_vf_reps(esw, new_num_vfs);
2081                 if (err)
2082                         return;
2083         }
2084         esw->esw_funcs.num_vfs = new_num_vfs;
2085 }
2086
2087 static void esw_functions_changed_event_handler(struct work_struct *work)
2088 {
2089         struct mlx5_host_work *host_work;
2090         struct mlx5_eswitch *esw;
2091         const u32 *out;
2092
2093         host_work = container_of(work, struct mlx5_host_work, work);
2094         esw = host_work->esw;
2095
2096         out = mlx5_esw_query_functions(esw->dev);
2097         if (IS_ERR(out))
2098                 goto out;
2099
2100         esw_vfs_changed_event_handler(esw, out);
2101         kvfree(out);
2102 out:
2103         kfree(host_work);
2104 }
2105
2106 int mlx5_esw_funcs_changed_handler(struct notifier_block *nb, unsigned long type, void *data)
2107 {
2108         struct mlx5_esw_functions *esw_funcs;
2109         struct mlx5_host_work *host_work;
2110         struct mlx5_eswitch *esw;
2111
2112         host_work = kzalloc(sizeof(*host_work), GFP_ATOMIC);
2113         if (!host_work)
2114                 return NOTIFY_DONE;
2115
2116         esw_funcs = mlx5_nb_cof(nb, struct mlx5_esw_functions, nb);
2117         esw = container_of(esw_funcs, struct mlx5_eswitch, esw_funcs);
2118
2119         host_work->esw = esw;
2120
2121         INIT_WORK(&host_work->work, esw_functions_changed_event_handler);
2122         queue_work(esw->work_queue, &host_work->work);
2123
2124         return NOTIFY_OK;
2125 }
2126
2127 int esw_offloads_init(struct mlx5_eswitch *esw)
2128 {
2129         int err;
2130
2131         if (MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, reformat) &&
2132             MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, decap))
2133                 esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_BASIC;
2134         else
2135                 esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_NONE;
2136
2137         err = esw_offloads_steering_init(esw);
2138         if (err)
2139                 return err;
2140
2141         if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
2142                 err = mlx5_eswitch_enable_passing_vport_metadata(esw);
2143                 if (err)
2144                         goto err_vport_metadata;
2145         }
2146
2147         err = esw_offloads_load_all_reps(esw);
2148         if (err)
2149                 goto err_reps;
2150
2151         esw_offloads_devcom_init(esw);
2152         mutex_init(&esw->offloads.termtbl_mutex);
2153
2154         mlx5_rdma_enable_roce(esw->dev);
2155
2156         return 0;
2157
2158 err_reps:
2159         if (mlx5_eswitch_vport_match_metadata_enabled(esw))
2160                 mlx5_eswitch_disable_passing_vport_metadata(esw);
2161 err_vport_metadata:
2162         esw_offloads_steering_cleanup(esw);
2163         return err;
2164 }
2165
2166 static int esw_offloads_stop(struct mlx5_eswitch *esw,
2167                              struct netlink_ext_ack *extack)
2168 {
2169         int err, err1;
2170
2171         mlx5_eswitch_disable(esw);
2172         err = mlx5_eswitch_enable(esw, MLX5_ESWITCH_LEGACY);
2173         if (err) {
2174                 NL_SET_ERR_MSG_MOD(extack, "Failed setting eswitch to legacy");
2175                 err1 = mlx5_eswitch_enable(esw, MLX5_ESWITCH_OFFLOADS);
2176                 if (err1) {
2177                         NL_SET_ERR_MSG_MOD(extack,
2178                                            "Failed setting eswitch back to offloads");
2179                 }
2180         }
2181
2182         return err;
2183 }
2184
2185 void esw_offloads_cleanup(struct mlx5_eswitch *esw)
2186 {
2187         mlx5_rdma_disable_roce(esw->dev);
2188         esw_offloads_devcom_cleanup(esw);
2189         esw_offloads_unload_all_reps(esw);
2190         if (mlx5_eswitch_vport_match_metadata_enabled(esw))
2191                 mlx5_eswitch_disable_passing_vport_metadata(esw);
2192         esw_offloads_steering_cleanup(esw);
2193         esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_NONE;
2194 }
2195
2196 static int esw_mode_from_devlink(u16 mode, u16 *mlx5_mode)
2197 {
2198         switch (mode) {
2199         case DEVLINK_ESWITCH_MODE_LEGACY:
2200                 *mlx5_mode = MLX5_ESWITCH_LEGACY;
2201                 break;
2202         case DEVLINK_ESWITCH_MODE_SWITCHDEV:
2203                 *mlx5_mode = MLX5_ESWITCH_OFFLOADS;
2204                 break;
2205         default:
2206                 return -EINVAL;
2207         }
2208
2209         return 0;
2210 }
2211
2212 static int esw_mode_to_devlink(u16 mlx5_mode, u16 *mode)
2213 {
2214         switch (mlx5_mode) {
2215         case MLX5_ESWITCH_LEGACY:
2216                 *mode = DEVLINK_ESWITCH_MODE_LEGACY;
2217                 break;
2218         case MLX5_ESWITCH_OFFLOADS:
2219                 *mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
2220                 break;
2221         default:
2222                 return -EINVAL;
2223         }
2224
2225         return 0;
2226 }
2227
2228 static int esw_inline_mode_from_devlink(u8 mode, u8 *mlx5_mode)
2229 {
2230         switch (mode) {
2231         case DEVLINK_ESWITCH_INLINE_MODE_NONE:
2232                 *mlx5_mode = MLX5_INLINE_MODE_NONE;
2233                 break;
2234         case DEVLINK_ESWITCH_INLINE_MODE_LINK:
2235                 *mlx5_mode = MLX5_INLINE_MODE_L2;
2236                 break;
2237         case DEVLINK_ESWITCH_INLINE_MODE_NETWORK:
2238                 *mlx5_mode = MLX5_INLINE_MODE_IP;
2239                 break;
2240         case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT:
2241                 *mlx5_mode = MLX5_INLINE_MODE_TCP_UDP;
2242                 break;
2243         default:
2244                 return -EINVAL;
2245         }
2246
2247         return 0;
2248 }
2249
2250 static int esw_inline_mode_to_devlink(u8 mlx5_mode, u8 *mode)
2251 {
2252         switch (mlx5_mode) {
2253         case MLX5_INLINE_MODE_NONE:
2254                 *mode = DEVLINK_ESWITCH_INLINE_MODE_NONE;
2255                 break;
2256         case MLX5_INLINE_MODE_L2:
2257                 *mode = DEVLINK_ESWITCH_INLINE_MODE_LINK;
2258                 break;
2259         case MLX5_INLINE_MODE_IP:
2260                 *mode = DEVLINK_ESWITCH_INLINE_MODE_NETWORK;
2261                 break;
2262         case MLX5_INLINE_MODE_TCP_UDP:
2263                 *mode = DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT;
2264                 break;
2265         default:
2266                 return -EINVAL;
2267         }
2268
2269         return 0;
2270 }
2271
2272 static int mlx5_devlink_eswitch_check(struct devlink *devlink)
2273 {
2274         struct mlx5_core_dev *dev = devlink_priv(devlink);
2275
2276         if (MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
2277                 return -EOPNOTSUPP;
2278
2279         if(!MLX5_ESWITCH_MANAGER(dev))
2280                 return -EPERM;
2281
2282         if (dev->priv.eswitch->mode == MLX5_ESWITCH_NONE &&
2283             !mlx5_core_is_ecpf_esw_manager(dev))
2284                 return -EOPNOTSUPP;
2285
2286         return 0;
2287 }
2288
2289 int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
2290                                   struct netlink_ext_ack *extack)
2291 {
2292         struct mlx5_core_dev *dev = devlink_priv(devlink);
2293         u16 cur_mlx5_mode, mlx5_mode = 0;
2294         int err;
2295
2296         err = mlx5_devlink_eswitch_check(devlink);
2297         if (err)
2298                 return err;
2299
2300         cur_mlx5_mode = dev->priv.eswitch->mode;
2301
2302         if (esw_mode_from_devlink(mode, &mlx5_mode))
2303                 return -EINVAL;
2304
2305         if (cur_mlx5_mode == mlx5_mode)
2306                 return 0;
2307
2308         if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV)
2309                 return esw_offloads_start(dev->priv.eswitch, extack);
2310         else if (mode == DEVLINK_ESWITCH_MODE_LEGACY)
2311                 return esw_offloads_stop(dev->priv.eswitch, extack);
2312         else
2313                 return -EINVAL;
2314 }
2315
2316 int mlx5_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
2317 {
2318         struct mlx5_core_dev *dev = devlink_priv(devlink);
2319         int err;
2320
2321         err = mlx5_devlink_eswitch_check(devlink);
2322         if (err)
2323                 return err;
2324
2325         return esw_mode_to_devlink(dev->priv.eswitch->mode, mode);
2326 }
2327
2328 int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode,
2329                                          struct netlink_ext_ack *extack)
2330 {
2331         struct mlx5_core_dev *dev = devlink_priv(devlink);
2332         struct mlx5_eswitch *esw = dev->priv.eswitch;
2333         int err, vport, num_vport;
2334         u8 mlx5_mode;
2335
2336         err = mlx5_devlink_eswitch_check(devlink);
2337         if (err)
2338                 return err;
2339
2340         switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
2341         case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
2342                 if (mode == DEVLINK_ESWITCH_INLINE_MODE_NONE)
2343                         return 0;
2344                 /* fall through */
2345         case MLX5_CAP_INLINE_MODE_L2:
2346                 NL_SET_ERR_MSG_MOD(extack, "Inline mode can't be set");
2347                 return -EOPNOTSUPP;
2348         case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
2349                 break;
2350         }
2351
2352         if (esw->offloads.num_flows > 0) {
2353                 NL_SET_ERR_MSG_MOD(extack,
2354                                    "Can't set inline mode when flows are configured");
2355                 return -EOPNOTSUPP;
2356         }
2357
2358         err = esw_inline_mode_from_devlink(mode, &mlx5_mode);
2359         if (err)
2360                 goto out;
2361
2362         mlx5_esw_for_each_host_func_vport(esw, vport, esw->esw_funcs.num_vfs) {
2363                 err = mlx5_modify_nic_vport_min_inline(dev, vport, mlx5_mode);
2364                 if (err) {
2365                         NL_SET_ERR_MSG_MOD(extack,
2366                                            "Failed to set min inline on vport");
2367                         goto revert_inline_mode;
2368                 }
2369         }
2370
2371         esw->offloads.inline_mode = mlx5_mode;
2372         return 0;
2373
2374 revert_inline_mode:
2375         num_vport = --vport;
2376         mlx5_esw_for_each_host_func_vport_reverse(esw, vport, num_vport)
2377                 mlx5_modify_nic_vport_min_inline(dev,
2378                                                  vport,
2379                                                  esw->offloads.inline_mode);
2380 out:
2381         return err;
2382 }
2383
2384 int mlx5_devlink_eswitch_inline_mode_get(struct devlink *devlink, u8 *mode)
2385 {
2386         struct mlx5_core_dev *dev = devlink_priv(devlink);
2387         struct mlx5_eswitch *esw = dev->priv.eswitch;
2388         int err;
2389
2390         err = mlx5_devlink_eswitch_check(devlink);
2391         if (err)
2392                 return err;
2393
2394         return esw_inline_mode_to_devlink(esw->offloads.inline_mode, mode);
2395 }
2396
2397 int mlx5_eswitch_inline_mode_get(struct mlx5_eswitch *esw, u8 *mode)
2398 {
2399         u8 prev_mlx5_mode, mlx5_mode = MLX5_INLINE_MODE_L2;
2400         struct mlx5_core_dev *dev = esw->dev;
2401         int vport;
2402
2403         if (!MLX5_CAP_GEN(dev, vport_group_manager))
2404                 return -EOPNOTSUPP;
2405
2406         if (esw->mode == MLX5_ESWITCH_NONE)
2407                 return -EOPNOTSUPP;
2408
2409         switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
2410         case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
2411                 mlx5_mode = MLX5_INLINE_MODE_NONE;
2412                 goto out;
2413         case MLX5_CAP_INLINE_MODE_L2:
2414                 mlx5_mode = MLX5_INLINE_MODE_L2;
2415                 goto out;
2416         case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
2417                 goto query_vports;
2418         }
2419
2420 query_vports:
2421         mlx5_query_nic_vport_min_inline(dev, esw->first_host_vport, &prev_mlx5_mode);
2422         mlx5_esw_for_each_host_func_vport(esw, vport, esw->esw_funcs.num_vfs) {
2423                 mlx5_query_nic_vport_min_inline(dev, vport, &mlx5_mode);
2424                 if (prev_mlx5_mode != mlx5_mode)
2425                         return -EINVAL;
2426                 prev_mlx5_mode = mlx5_mode;
2427         }
2428
2429 out:
2430         *mode = mlx5_mode;
2431         return 0;
2432 }
2433
2434 int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink,
2435                                         enum devlink_eswitch_encap_mode encap,
2436                                         struct netlink_ext_ack *extack)
2437 {
2438         struct mlx5_core_dev *dev = devlink_priv(devlink);
2439         struct mlx5_eswitch *esw = dev->priv.eswitch;
2440         int err;
2441
2442         err = mlx5_devlink_eswitch_check(devlink);
2443         if (err)
2444                 return err;
2445
2446         if (encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE &&
2447             (!MLX5_CAP_ESW_FLOWTABLE_FDB(dev, reformat) ||
2448              !MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap)))
2449                 return -EOPNOTSUPP;
2450
2451         if (encap && encap != DEVLINK_ESWITCH_ENCAP_MODE_BASIC)
2452                 return -EOPNOTSUPP;
2453
2454         if (esw->mode == MLX5_ESWITCH_LEGACY) {
2455                 esw->offloads.encap = encap;
2456                 return 0;
2457         }
2458
2459         if (esw->offloads.encap == encap)
2460                 return 0;
2461
2462         if (esw->offloads.num_flows > 0) {
2463                 NL_SET_ERR_MSG_MOD(extack,
2464                                    "Can't set encapsulation when flows are configured");
2465                 return -EOPNOTSUPP;
2466         }
2467
2468         esw_destroy_offloads_fdb_tables(esw);
2469
2470         esw->offloads.encap = encap;
2471
2472         err = esw_create_offloads_fdb_tables(esw, esw->nvports);
2473
2474         if (err) {
2475                 NL_SET_ERR_MSG_MOD(extack,
2476                                    "Failed re-creating fast FDB table");
2477                 esw->offloads.encap = !encap;
2478                 (void)esw_create_offloads_fdb_tables(esw, esw->nvports);
2479         }
2480
2481         return err;
2482 }
2483
2484 int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink,
2485                                         enum devlink_eswitch_encap_mode *encap)
2486 {
2487         struct mlx5_core_dev *dev = devlink_priv(devlink);
2488         struct mlx5_eswitch *esw = dev->priv.eswitch;
2489         int err;
2490
2491         err = mlx5_devlink_eswitch_check(devlink);
2492         if (err)
2493                 return err;
2494
2495         *encap = esw->offloads.encap;
2496         return 0;
2497 }
2498
2499 void mlx5_eswitch_register_vport_reps(struct mlx5_eswitch *esw,
2500                                       const struct mlx5_eswitch_rep_ops *ops,
2501                                       u8 rep_type)
2502 {
2503         struct mlx5_eswitch_rep_data *rep_data;
2504         struct mlx5_eswitch_rep *rep;
2505         int i;
2506
2507         esw->offloads.rep_ops[rep_type] = ops;
2508         mlx5_esw_for_all_reps(esw, i, rep) {
2509                 rep_data = &rep->rep_data[rep_type];
2510                 atomic_set(&rep_data->state, REP_REGISTERED);
2511         }
2512 }
2513 EXPORT_SYMBOL(mlx5_eswitch_register_vport_reps);
2514
2515 void mlx5_eswitch_unregister_vport_reps(struct mlx5_eswitch *esw, u8 rep_type)
2516 {
2517         struct mlx5_eswitch_rep *rep;
2518         int i;
2519
2520         if (esw->mode == MLX5_ESWITCH_OFFLOADS)
2521                 __unload_reps_all_vport(esw, rep_type);
2522
2523         mlx5_esw_for_all_reps(esw, i, rep)
2524                 atomic_set(&rep->rep_data[rep_type].state, REP_UNREGISTERED);
2525 }
2526 EXPORT_SYMBOL(mlx5_eswitch_unregister_vport_reps);
2527
2528 void *mlx5_eswitch_get_uplink_priv(struct mlx5_eswitch *esw, u8 rep_type)
2529 {
2530         struct mlx5_eswitch_rep *rep;
2531
2532         rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_UPLINK);
2533         return rep->rep_data[rep_type].priv;
2534 }
2535
2536 void *mlx5_eswitch_get_proto_dev(struct mlx5_eswitch *esw,
2537                                  u16 vport,
2538                                  u8 rep_type)
2539 {
2540         struct mlx5_eswitch_rep *rep;
2541
2542         rep = mlx5_eswitch_get_rep(esw, vport);
2543
2544         if (atomic_read(&rep->rep_data[rep_type].state) == REP_LOADED &&
2545             esw->offloads.rep_ops[rep_type]->get_proto_dev)
2546                 return esw->offloads.rep_ops[rep_type]->get_proto_dev(rep);
2547         return NULL;
2548 }
2549 EXPORT_SYMBOL(mlx5_eswitch_get_proto_dev);
2550
2551 void *mlx5_eswitch_uplink_get_proto_dev(struct mlx5_eswitch *esw, u8 rep_type)
2552 {
2553         return mlx5_eswitch_get_proto_dev(esw, MLX5_VPORT_UPLINK, rep_type);
2554 }
2555 EXPORT_SYMBOL(mlx5_eswitch_uplink_get_proto_dev);
2556
2557 struct mlx5_eswitch_rep *mlx5_eswitch_vport_rep(struct mlx5_eswitch *esw,
2558                                                 u16 vport)
2559 {
2560         return mlx5_eswitch_get_rep(esw, vport);
2561 }
2562 EXPORT_SYMBOL(mlx5_eswitch_vport_rep);
2563
2564 bool mlx5_eswitch_is_vf_vport(const struct mlx5_eswitch *esw, u16 vport_num)
2565 {
2566         return vport_num >= MLX5_VPORT_FIRST_VF &&
2567                vport_num <= esw->dev->priv.sriov.max_vfs;
2568 }
2569
2570 bool mlx5_eswitch_vport_match_metadata_enabled(const struct mlx5_eswitch *esw)
2571 {
2572         return !!(esw->flags & MLX5_ESWITCH_VPORT_MATCH_METADATA);
2573 }
2574 EXPORT_SYMBOL(mlx5_eswitch_vport_match_metadata_enabled);
2575
2576 u32 mlx5_eswitch_get_vport_metadata_for_match(const struct mlx5_eswitch *esw,
2577                                               u16 vport_num)
2578 {
2579         return ((MLX5_CAP_GEN(esw->dev, vhca_id) & 0xffff) << 16) | vport_num;
2580 }
2581 EXPORT_SYMBOL(mlx5_eswitch_get_vport_metadata_for_match);