Merge branch 'mlxsw-Offload-TBF'
[linux-2.6-microblaze.git] / drivers / net / ethernet / mellanox / mlx5 / core / eswitch.c
1 /*
2  * Copyright (c) 2015, 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 "lib/eq.h"
40 #include "eswitch.h"
41 #include "fs_core.h"
42 #include "ecpf.h"
43
44 enum {
45         MLX5_ACTION_NONE = 0,
46         MLX5_ACTION_ADD  = 1,
47         MLX5_ACTION_DEL  = 2,
48 };
49
50 /* Vport UC/MC hash node */
51 struct vport_addr {
52         struct l2addr_node     node;
53         u8                     action;
54         u16                    vport;
55         struct mlx5_flow_handle *flow_rule;
56         bool mpfs; /* UC MAC was added to MPFs */
57         /* A flag indicating that mac was added due to mc promiscuous vport */
58         bool mc_promisc;
59 };
60
61 static void esw_destroy_legacy_fdb_table(struct mlx5_eswitch *esw);
62 static void esw_cleanup_vepa_rules(struct mlx5_eswitch *esw);
63
64 struct mlx5_vport *__must_check
65 mlx5_eswitch_get_vport(struct mlx5_eswitch *esw, u16 vport_num)
66 {
67         u16 idx;
68
69         if (!esw || !MLX5_CAP_GEN(esw->dev, vport_group_manager))
70                 return ERR_PTR(-EPERM);
71
72         idx = mlx5_eswitch_vport_num_to_index(esw, vport_num);
73
74         if (idx > esw->total_vports - 1) {
75                 esw_debug(esw->dev, "vport out of range: num(0x%x), idx(0x%x)\n",
76                           vport_num, idx);
77                 return ERR_PTR(-EINVAL);
78         }
79
80         return &esw->vports[idx];
81 }
82
83 static int arm_vport_context_events_cmd(struct mlx5_core_dev *dev, u16 vport,
84                                         u32 events_mask)
85 {
86         int in[MLX5_ST_SZ_DW(modify_nic_vport_context_in)]   = {0};
87         int out[MLX5_ST_SZ_DW(modify_nic_vport_context_out)] = {0};
88         void *nic_vport_ctx;
89
90         MLX5_SET(modify_nic_vport_context_in, in,
91                  opcode, MLX5_CMD_OP_MODIFY_NIC_VPORT_CONTEXT);
92         MLX5_SET(modify_nic_vport_context_in, in, field_select.change_event, 1);
93         MLX5_SET(modify_nic_vport_context_in, in, vport_number, vport);
94         MLX5_SET(modify_nic_vport_context_in, in, other_vport, 1);
95         nic_vport_ctx = MLX5_ADDR_OF(modify_nic_vport_context_in,
96                                      in, nic_vport_context);
97
98         MLX5_SET(nic_vport_context, nic_vport_ctx, arm_change_event, 1);
99
100         if (events_mask & MLX5_VPORT_UC_ADDR_CHANGE)
101                 MLX5_SET(nic_vport_context, nic_vport_ctx,
102                          event_on_uc_address_change, 1);
103         if (events_mask & MLX5_VPORT_MC_ADDR_CHANGE)
104                 MLX5_SET(nic_vport_context, nic_vport_ctx,
105                          event_on_mc_address_change, 1);
106         if (events_mask & MLX5_VPORT_PROMISC_CHANGE)
107                 MLX5_SET(nic_vport_context, nic_vport_ctx,
108                          event_on_promisc_change, 1);
109
110         return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
111 }
112
113 /* E-Switch vport context HW commands */
114 int mlx5_eswitch_modify_esw_vport_context(struct mlx5_core_dev *dev, u16 vport,
115                                           bool other_vport,
116                                           void *in, int inlen)
117 {
118         u32 out[MLX5_ST_SZ_DW(modify_esw_vport_context_out)] = {0};
119
120         MLX5_SET(modify_esw_vport_context_in, in, opcode,
121                  MLX5_CMD_OP_MODIFY_ESW_VPORT_CONTEXT);
122         MLX5_SET(modify_esw_vport_context_in, in, vport_number, vport);
123         MLX5_SET(modify_esw_vport_context_in, in, other_vport, other_vport);
124         return mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
125 }
126
127 int mlx5_eswitch_query_esw_vport_context(struct mlx5_core_dev *dev, u16 vport,
128                                          bool other_vport,
129                                          void *out, int outlen)
130 {
131         u32 in[MLX5_ST_SZ_DW(query_esw_vport_context_in)] = {};
132
133         MLX5_SET(query_esw_vport_context_in, in, opcode,
134                  MLX5_CMD_OP_QUERY_ESW_VPORT_CONTEXT);
135         MLX5_SET(modify_esw_vport_context_in, in, vport_number, vport);
136         MLX5_SET(modify_esw_vport_context_in, in, other_vport, other_vport);
137         return mlx5_cmd_exec(dev, in, sizeof(in), out, outlen);
138 }
139
140 static int modify_esw_vport_cvlan(struct mlx5_core_dev *dev, u16 vport,
141                                   u16 vlan, u8 qos, u8 set_flags)
142 {
143         u32 in[MLX5_ST_SZ_DW(modify_esw_vport_context_in)] = {0};
144
145         if (!MLX5_CAP_ESW(dev, vport_cvlan_strip) ||
146             !MLX5_CAP_ESW(dev, vport_cvlan_insert_if_not_exist))
147                 return -EOPNOTSUPP;
148
149         esw_debug(dev, "Set Vport[%d] VLAN %d qos %d set=%x\n",
150                   vport, vlan, qos, set_flags);
151
152         if (set_flags & SET_VLAN_STRIP)
153                 MLX5_SET(modify_esw_vport_context_in, in,
154                          esw_vport_context.vport_cvlan_strip, 1);
155
156         if (set_flags & SET_VLAN_INSERT) {
157                 /* insert only if no vlan in packet */
158                 MLX5_SET(modify_esw_vport_context_in, in,
159                          esw_vport_context.vport_cvlan_insert, 1);
160
161                 MLX5_SET(modify_esw_vport_context_in, in,
162                          esw_vport_context.cvlan_pcp, qos);
163                 MLX5_SET(modify_esw_vport_context_in, in,
164                          esw_vport_context.cvlan_id, vlan);
165         }
166
167         MLX5_SET(modify_esw_vport_context_in, in,
168                  field_select.vport_cvlan_strip, 1);
169         MLX5_SET(modify_esw_vport_context_in, in,
170                  field_select.vport_cvlan_insert, 1);
171
172         return mlx5_eswitch_modify_esw_vport_context(dev, vport, true,
173                                                      in, sizeof(in));
174 }
175
176 /* E-Switch FDB */
177 static struct mlx5_flow_handle *
178 __esw_fdb_set_vport_rule(struct mlx5_eswitch *esw, u16 vport, bool rx_rule,
179                          u8 mac_c[ETH_ALEN], u8 mac_v[ETH_ALEN])
180 {
181         int match_header = (is_zero_ether_addr(mac_c) ? 0 :
182                             MLX5_MATCH_OUTER_HEADERS);
183         struct mlx5_flow_handle *flow_rule = NULL;
184         struct mlx5_flow_act flow_act = {0};
185         struct mlx5_flow_destination dest = {};
186         struct mlx5_flow_spec *spec;
187         void *mv_misc = NULL;
188         void *mc_misc = NULL;
189         u8 *dmac_v = NULL;
190         u8 *dmac_c = NULL;
191
192         if (rx_rule)
193                 match_header |= MLX5_MATCH_MISC_PARAMETERS;
194
195         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
196         if (!spec)
197                 return NULL;
198
199         dmac_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
200                               outer_headers.dmac_47_16);
201         dmac_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
202                               outer_headers.dmac_47_16);
203
204         if (match_header & MLX5_MATCH_OUTER_HEADERS) {
205                 ether_addr_copy(dmac_v, mac_v);
206                 ether_addr_copy(dmac_c, mac_c);
207         }
208
209         if (match_header & MLX5_MATCH_MISC_PARAMETERS) {
210                 mv_misc  = MLX5_ADDR_OF(fte_match_param, spec->match_value,
211                                         misc_parameters);
212                 mc_misc  = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
213                                         misc_parameters);
214                 MLX5_SET(fte_match_set_misc, mv_misc, source_port, MLX5_VPORT_UPLINK);
215                 MLX5_SET_TO_ONES(fte_match_set_misc, mc_misc, source_port);
216         }
217
218         dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
219         dest.vport.num = vport;
220
221         esw_debug(esw->dev,
222                   "\tFDB add rule dmac_v(%pM) dmac_c(%pM) -> vport(%d)\n",
223                   dmac_v, dmac_c, vport);
224         spec->match_criteria_enable = match_header;
225         flow_act.action =  MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
226         flow_rule =
227                 mlx5_add_flow_rules(esw->fdb_table.legacy.fdb, spec,
228                                     &flow_act, &dest, 1);
229         if (IS_ERR(flow_rule)) {
230                 esw_warn(esw->dev,
231                          "FDB: Failed to add flow rule: dmac_v(%pM) dmac_c(%pM) -> vport(%d), err(%ld)\n",
232                          dmac_v, dmac_c, vport, PTR_ERR(flow_rule));
233                 flow_rule = NULL;
234         }
235
236         kvfree(spec);
237         return flow_rule;
238 }
239
240 static struct mlx5_flow_handle *
241 esw_fdb_set_vport_rule(struct mlx5_eswitch *esw, u8 mac[ETH_ALEN], u16 vport)
242 {
243         u8 mac_c[ETH_ALEN];
244
245         eth_broadcast_addr(mac_c);
246         return __esw_fdb_set_vport_rule(esw, vport, false, mac_c, mac);
247 }
248
249 static struct mlx5_flow_handle *
250 esw_fdb_set_vport_allmulti_rule(struct mlx5_eswitch *esw, u16 vport)
251 {
252         u8 mac_c[ETH_ALEN];
253         u8 mac_v[ETH_ALEN];
254
255         eth_zero_addr(mac_c);
256         eth_zero_addr(mac_v);
257         mac_c[0] = 0x01;
258         mac_v[0] = 0x01;
259         return __esw_fdb_set_vport_rule(esw, vport, false, mac_c, mac_v);
260 }
261
262 static struct mlx5_flow_handle *
263 esw_fdb_set_vport_promisc_rule(struct mlx5_eswitch *esw, u16 vport)
264 {
265         u8 mac_c[ETH_ALEN];
266         u8 mac_v[ETH_ALEN];
267
268         eth_zero_addr(mac_c);
269         eth_zero_addr(mac_v);
270         return __esw_fdb_set_vport_rule(esw, vport, true, mac_c, mac_v);
271 }
272
273 enum {
274         LEGACY_VEPA_PRIO = 0,
275         LEGACY_FDB_PRIO,
276 };
277
278 static int esw_create_legacy_vepa_table(struct mlx5_eswitch *esw)
279 {
280         struct mlx5_flow_table_attr ft_attr = {};
281         struct mlx5_core_dev *dev = esw->dev;
282         struct mlx5_flow_namespace *root_ns;
283         struct mlx5_flow_table *fdb;
284         int err;
285
286         root_ns = mlx5_get_fdb_sub_ns(dev, 0);
287         if (!root_ns) {
288                 esw_warn(dev, "Failed to get FDB flow namespace\n");
289                 return -EOPNOTSUPP;
290         }
291
292         /* num FTE 2, num FG 2 */
293         ft_attr.prio = LEGACY_VEPA_PRIO;
294         ft_attr.max_fte = 2;
295         ft_attr.autogroup.max_num_groups = 2;
296         fdb = mlx5_create_auto_grouped_flow_table(root_ns, &ft_attr);
297         if (IS_ERR(fdb)) {
298                 err = PTR_ERR(fdb);
299                 esw_warn(dev, "Failed to create VEPA FDB err %d\n", err);
300                 return err;
301         }
302         esw->fdb_table.legacy.vepa_fdb = fdb;
303
304         return 0;
305 }
306
307 static int esw_create_legacy_fdb_table(struct mlx5_eswitch *esw)
308 {
309         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
310         struct mlx5_flow_table_attr ft_attr = {};
311         struct mlx5_core_dev *dev = esw->dev;
312         struct mlx5_flow_namespace *root_ns;
313         struct mlx5_flow_table *fdb;
314         struct mlx5_flow_group *g;
315         void *match_criteria;
316         int table_size;
317         u32 *flow_group_in;
318         u8 *dmac;
319         int err = 0;
320
321         esw_debug(dev, "Create FDB log_max_size(%d)\n",
322                   MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size));
323
324         root_ns = mlx5_get_fdb_sub_ns(dev, 0);
325         if (!root_ns) {
326                 esw_warn(dev, "Failed to get FDB flow namespace\n");
327                 return -EOPNOTSUPP;
328         }
329
330         flow_group_in = kvzalloc(inlen, GFP_KERNEL);
331         if (!flow_group_in)
332                 return -ENOMEM;
333
334         table_size = BIT(MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size));
335         ft_attr.max_fte = table_size;
336         ft_attr.prio = LEGACY_FDB_PRIO;
337         fdb = mlx5_create_flow_table(root_ns, &ft_attr);
338         if (IS_ERR(fdb)) {
339                 err = PTR_ERR(fdb);
340                 esw_warn(dev, "Failed to create FDB Table err %d\n", err);
341                 goto out;
342         }
343         esw->fdb_table.legacy.fdb = fdb;
344
345         /* Addresses group : Full match unicast/multicast addresses */
346         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
347                  MLX5_MATCH_OUTER_HEADERS);
348         match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
349         dmac = MLX5_ADDR_OF(fte_match_param, match_criteria, outer_headers.dmac_47_16);
350         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
351         /* Preserve 2 entries for allmulti and promisc rules*/
352         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, table_size - 3);
353         eth_broadcast_addr(dmac);
354         g = mlx5_create_flow_group(fdb, flow_group_in);
355         if (IS_ERR(g)) {
356                 err = PTR_ERR(g);
357                 esw_warn(dev, "Failed to create flow group err(%d)\n", err);
358                 goto out;
359         }
360         esw->fdb_table.legacy.addr_grp = g;
361
362         /* Allmulti group : One rule that forwards any mcast traffic */
363         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
364                  MLX5_MATCH_OUTER_HEADERS);
365         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, table_size - 2);
366         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, table_size - 2);
367         eth_zero_addr(dmac);
368         dmac[0] = 0x01;
369         g = mlx5_create_flow_group(fdb, flow_group_in);
370         if (IS_ERR(g)) {
371                 err = PTR_ERR(g);
372                 esw_warn(dev, "Failed to create allmulti flow group err(%d)\n", err);
373                 goto out;
374         }
375         esw->fdb_table.legacy.allmulti_grp = g;
376
377         /* Promiscuous group :
378          * One rule that forward all unmatched traffic from previous groups
379          */
380         eth_zero_addr(dmac);
381         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
382                  MLX5_MATCH_MISC_PARAMETERS);
383         MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_port);
384         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, table_size - 1);
385         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, table_size - 1);
386         g = mlx5_create_flow_group(fdb, flow_group_in);
387         if (IS_ERR(g)) {
388                 err = PTR_ERR(g);
389                 esw_warn(dev, "Failed to create promisc flow group err(%d)\n", err);
390                 goto out;
391         }
392         esw->fdb_table.legacy.promisc_grp = g;
393
394 out:
395         if (err)
396                 esw_destroy_legacy_fdb_table(esw);
397
398         kvfree(flow_group_in);
399         return err;
400 }
401
402 static void esw_destroy_legacy_vepa_table(struct mlx5_eswitch *esw)
403 {
404         esw_debug(esw->dev, "Destroy VEPA Table\n");
405         if (!esw->fdb_table.legacy.vepa_fdb)
406                 return;
407
408         mlx5_destroy_flow_table(esw->fdb_table.legacy.vepa_fdb);
409         esw->fdb_table.legacy.vepa_fdb = NULL;
410 }
411
412 static void esw_destroy_legacy_fdb_table(struct mlx5_eswitch *esw)
413 {
414         esw_debug(esw->dev, "Destroy FDB Table\n");
415         if (!esw->fdb_table.legacy.fdb)
416                 return;
417
418         if (esw->fdb_table.legacy.promisc_grp)
419                 mlx5_destroy_flow_group(esw->fdb_table.legacy.promisc_grp);
420         if (esw->fdb_table.legacy.allmulti_grp)
421                 mlx5_destroy_flow_group(esw->fdb_table.legacy.allmulti_grp);
422         if (esw->fdb_table.legacy.addr_grp)
423                 mlx5_destroy_flow_group(esw->fdb_table.legacy.addr_grp);
424         mlx5_destroy_flow_table(esw->fdb_table.legacy.fdb);
425
426         esw->fdb_table.legacy.fdb = NULL;
427         esw->fdb_table.legacy.addr_grp = NULL;
428         esw->fdb_table.legacy.allmulti_grp = NULL;
429         esw->fdb_table.legacy.promisc_grp = NULL;
430 }
431
432 static int esw_create_legacy_table(struct mlx5_eswitch *esw)
433 {
434         int err;
435
436         memset(&esw->fdb_table.legacy, 0, sizeof(struct legacy_fdb));
437
438         err = esw_create_legacy_vepa_table(esw);
439         if (err)
440                 return err;
441
442         err = esw_create_legacy_fdb_table(esw);
443         if (err)
444                 esw_destroy_legacy_vepa_table(esw);
445
446         return err;
447 }
448
449 static void esw_destroy_legacy_table(struct mlx5_eswitch *esw)
450 {
451         esw_cleanup_vepa_rules(esw);
452         esw_destroy_legacy_fdb_table(esw);
453         esw_destroy_legacy_vepa_table(esw);
454 }
455
456 #define MLX5_LEGACY_SRIOV_VPORT_EVENTS (MLX5_VPORT_UC_ADDR_CHANGE | \
457                                         MLX5_VPORT_MC_ADDR_CHANGE | \
458                                         MLX5_VPORT_PROMISC_CHANGE)
459
460 static int esw_legacy_enable(struct mlx5_eswitch *esw)
461 {
462         int ret;
463
464         ret = esw_create_legacy_table(esw);
465         if (ret)
466                 return ret;
467
468         ret = mlx5_eswitch_enable_pf_vf_vports(esw, MLX5_LEGACY_SRIOV_VPORT_EVENTS);
469         if (ret)
470                 esw_destroy_legacy_table(esw);
471         return ret;
472 }
473
474 static void esw_legacy_disable(struct mlx5_eswitch *esw)
475 {
476         struct esw_mc_addr *mc_promisc;
477
478         mlx5_eswitch_disable_pf_vf_vports(esw);
479
480         mc_promisc = &esw->mc_promisc;
481         if (mc_promisc->uplink_rule)
482                 mlx5_del_flow_rules(mc_promisc->uplink_rule);
483
484         esw_destroy_legacy_table(esw);
485 }
486
487 /* E-Switch vport UC/MC lists management */
488 typedef int (*vport_addr_action)(struct mlx5_eswitch *esw,
489                                  struct vport_addr *vaddr);
490
491 static int esw_add_uc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
492 {
493         u8 *mac = vaddr->node.addr;
494         u16 vport = vaddr->vport;
495         int err;
496
497         /* Skip mlx5_mpfs_add_mac for eswitch_managers,
498          * it is already done by its netdev in mlx5e_execute_l2_action
499          */
500         if (mlx5_esw_is_manager_vport(esw, vport))
501                 goto fdb_add;
502
503         err = mlx5_mpfs_add_mac(esw->dev, mac);
504         if (err) {
505                 esw_warn(esw->dev,
506                          "Failed to add L2 table mac(%pM) for vport(0x%x), err(%d)\n",
507                          mac, vport, err);
508                 return err;
509         }
510         vaddr->mpfs = true;
511
512 fdb_add:
513         /* SRIOV is enabled: Forward UC MAC to vport */
514         if (esw->fdb_table.legacy.fdb && esw->mode == MLX5_ESWITCH_LEGACY)
515                 vaddr->flow_rule = esw_fdb_set_vport_rule(esw, mac, vport);
516
517         esw_debug(esw->dev, "\tADDED UC MAC: vport[%d] %pM fr(%p)\n",
518                   vport, mac, vaddr->flow_rule);
519
520         return 0;
521 }
522
523 static int esw_del_uc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
524 {
525         u8 *mac = vaddr->node.addr;
526         u16 vport = vaddr->vport;
527         int err = 0;
528
529         /* Skip mlx5_mpfs_del_mac for eswitch managers,
530          * it is already done by its netdev in mlx5e_execute_l2_action
531          */
532         if (!vaddr->mpfs || mlx5_esw_is_manager_vport(esw, vport))
533                 goto fdb_del;
534
535         err = mlx5_mpfs_del_mac(esw->dev, mac);
536         if (err)
537                 esw_warn(esw->dev,
538                          "Failed to del L2 table mac(%pM) for vport(%d), err(%d)\n",
539                          mac, vport, err);
540         vaddr->mpfs = false;
541
542 fdb_del:
543         if (vaddr->flow_rule)
544                 mlx5_del_flow_rules(vaddr->flow_rule);
545         vaddr->flow_rule = NULL;
546
547         return 0;
548 }
549
550 static void update_allmulti_vports(struct mlx5_eswitch *esw,
551                                    struct vport_addr *vaddr,
552                                    struct esw_mc_addr *esw_mc)
553 {
554         u8 *mac = vaddr->node.addr;
555         struct mlx5_vport *vport;
556         u16 i, vport_num;
557
558         mlx5_esw_for_all_vports(esw, i, vport) {
559                 struct hlist_head *vport_hash = vport->mc_list;
560                 struct vport_addr *iter_vaddr =
561                                         l2addr_hash_find(vport_hash,
562                                                          mac,
563                                                          struct vport_addr);
564                 vport_num = vport->vport;
565                 if (IS_ERR_OR_NULL(vport->allmulti_rule) ||
566                     vaddr->vport == vport_num)
567                         continue;
568                 switch (vaddr->action) {
569                 case MLX5_ACTION_ADD:
570                         if (iter_vaddr)
571                                 continue;
572                         iter_vaddr = l2addr_hash_add(vport_hash, mac,
573                                                      struct vport_addr,
574                                                      GFP_KERNEL);
575                         if (!iter_vaddr) {
576                                 esw_warn(esw->dev,
577                                          "ALL-MULTI: Failed to add MAC(%pM) to vport[%d] DB\n",
578                                          mac, vport_num);
579                                 continue;
580                         }
581                         iter_vaddr->vport = vport_num;
582                         iter_vaddr->flow_rule =
583                                         esw_fdb_set_vport_rule(esw,
584                                                                mac,
585                                                                vport_num);
586                         iter_vaddr->mc_promisc = true;
587                         break;
588                 case MLX5_ACTION_DEL:
589                         if (!iter_vaddr)
590                                 continue;
591                         mlx5_del_flow_rules(iter_vaddr->flow_rule);
592                         l2addr_hash_del(iter_vaddr);
593                         break;
594                 }
595         }
596 }
597
598 static int esw_add_mc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
599 {
600         struct hlist_head *hash = esw->mc_table;
601         struct esw_mc_addr *esw_mc;
602         u8 *mac = vaddr->node.addr;
603         u16 vport = vaddr->vport;
604
605         if (!esw->fdb_table.legacy.fdb)
606                 return 0;
607
608         esw_mc = l2addr_hash_find(hash, mac, struct esw_mc_addr);
609         if (esw_mc)
610                 goto add;
611
612         esw_mc = l2addr_hash_add(hash, mac, struct esw_mc_addr, GFP_KERNEL);
613         if (!esw_mc)
614                 return -ENOMEM;
615
616         esw_mc->uplink_rule = /* Forward MC MAC to Uplink */
617                 esw_fdb_set_vport_rule(esw, mac, MLX5_VPORT_UPLINK);
618
619         /* Add this multicast mac to all the mc promiscuous vports */
620         update_allmulti_vports(esw, vaddr, esw_mc);
621
622 add:
623         /* If the multicast mac is added as a result of mc promiscuous vport,
624          * don't increment the multicast ref count
625          */
626         if (!vaddr->mc_promisc)
627                 esw_mc->refcnt++;
628
629         /* Forward MC MAC to vport */
630         vaddr->flow_rule = esw_fdb_set_vport_rule(esw, mac, vport);
631         esw_debug(esw->dev,
632                   "\tADDED MC MAC: vport[%d] %pM fr(%p) refcnt(%d) uplinkfr(%p)\n",
633                   vport, mac, vaddr->flow_rule,
634                   esw_mc->refcnt, esw_mc->uplink_rule);
635         return 0;
636 }
637
638 static int esw_del_mc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
639 {
640         struct hlist_head *hash = esw->mc_table;
641         struct esw_mc_addr *esw_mc;
642         u8 *mac = vaddr->node.addr;
643         u16 vport = vaddr->vport;
644
645         if (!esw->fdb_table.legacy.fdb)
646                 return 0;
647
648         esw_mc = l2addr_hash_find(hash, mac, struct esw_mc_addr);
649         if (!esw_mc) {
650                 esw_warn(esw->dev,
651                          "Failed to find eswitch MC addr for MAC(%pM) vport(%d)",
652                          mac, vport);
653                 return -EINVAL;
654         }
655         esw_debug(esw->dev,
656                   "\tDELETE MC MAC: vport[%d] %pM fr(%p) refcnt(%d) uplinkfr(%p)\n",
657                   vport, mac, vaddr->flow_rule, esw_mc->refcnt,
658                   esw_mc->uplink_rule);
659
660         if (vaddr->flow_rule)
661                 mlx5_del_flow_rules(vaddr->flow_rule);
662         vaddr->flow_rule = NULL;
663
664         /* If the multicast mac is added as a result of mc promiscuous vport,
665          * don't decrement the multicast ref count.
666          */
667         if (vaddr->mc_promisc || (--esw_mc->refcnt > 0))
668                 return 0;
669
670         /* Remove this multicast mac from all the mc promiscuous vports */
671         update_allmulti_vports(esw, vaddr, esw_mc);
672
673         if (esw_mc->uplink_rule)
674                 mlx5_del_flow_rules(esw_mc->uplink_rule);
675
676         l2addr_hash_del(esw_mc);
677         return 0;
678 }
679
680 /* Apply vport UC/MC list to HW l2 table and FDB table */
681 static void esw_apply_vport_addr_list(struct mlx5_eswitch *esw,
682                                       struct mlx5_vport *vport, int list_type)
683 {
684         bool is_uc = list_type == MLX5_NVPRT_LIST_TYPE_UC;
685         vport_addr_action vport_addr_add;
686         vport_addr_action vport_addr_del;
687         struct vport_addr *addr;
688         struct l2addr_node *node;
689         struct hlist_head *hash;
690         struct hlist_node *tmp;
691         int hi;
692
693         vport_addr_add = is_uc ? esw_add_uc_addr :
694                                  esw_add_mc_addr;
695         vport_addr_del = is_uc ? esw_del_uc_addr :
696                                  esw_del_mc_addr;
697
698         hash = is_uc ? vport->uc_list : vport->mc_list;
699         for_each_l2hash_node(node, tmp, hash, hi) {
700                 addr = container_of(node, struct vport_addr, node);
701                 switch (addr->action) {
702                 case MLX5_ACTION_ADD:
703                         vport_addr_add(esw, addr);
704                         addr->action = MLX5_ACTION_NONE;
705                         break;
706                 case MLX5_ACTION_DEL:
707                         vport_addr_del(esw, addr);
708                         l2addr_hash_del(addr);
709                         break;
710                 }
711         }
712 }
713
714 /* Sync vport UC/MC list from vport context */
715 static void esw_update_vport_addr_list(struct mlx5_eswitch *esw,
716                                        struct mlx5_vport *vport, int list_type)
717 {
718         bool is_uc = list_type == MLX5_NVPRT_LIST_TYPE_UC;
719         u8 (*mac_list)[ETH_ALEN];
720         struct l2addr_node *node;
721         struct vport_addr *addr;
722         struct hlist_head *hash;
723         struct hlist_node *tmp;
724         int size;
725         int err;
726         int hi;
727         int i;
728
729         size = is_uc ? MLX5_MAX_UC_PER_VPORT(esw->dev) :
730                        MLX5_MAX_MC_PER_VPORT(esw->dev);
731
732         mac_list = kcalloc(size, ETH_ALEN, GFP_KERNEL);
733         if (!mac_list)
734                 return;
735
736         hash = is_uc ? vport->uc_list : vport->mc_list;
737
738         for_each_l2hash_node(node, tmp, hash, hi) {
739                 addr = container_of(node, struct vport_addr, node);
740                 addr->action = MLX5_ACTION_DEL;
741         }
742
743         if (!vport->enabled)
744                 goto out;
745
746         err = mlx5_query_nic_vport_mac_list(esw->dev, vport->vport, list_type,
747                                             mac_list, &size);
748         if (err)
749                 goto out;
750         esw_debug(esw->dev, "vport[%d] context update %s list size (%d)\n",
751                   vport->vport, is_uc ? "UC" : "MC", size);
752
753         for (i = 0; i < size; i++) {
754                 if (is_uc && !is_valid_ether_addr(mac_list[i]))
755                         continue;
756
757                 if (!is_uc && !is_multicast_ether_addr(mac_list[i]))
758                         continue;
759
760                 addr = l2addr_hash_find(hash, mac_list[i], struct vport_addr);
761                 if (addr) {
762                         addr->action = MLX5_ACTION_NONE;
763                         /* If this mac was previously added because of allmulti
764                          * promiscuous rx mode, its now converted to be original
765                          * vport mac.
766                          */
767                         if (addr->mc_promisc) {
768                                 struct esw_mc_addr *esw_mc =
769                                         l2addr_hash_find(esw->mc_table,
770                                                          mac_list[i],
771                                                          struct esw_mc_addr);
772                                 if (!esw_mc) {
773                                         esw_warn(esw->dev,
774                                                  "Failed to MAC(%pM) in mcast DB\n",
775                                                  mac_list[i]);
776                                         continue;
777                                 }
778                                 esw_mc->refcnt++;
779                                 addr->mc_promisc = false;
780                         }
781                         continue;
782                 }
783
784                 addr = l2addr_hash_add(hash, mac_list[i], struct vport_addr,
785                                        GFP_KERNEL);
786                 if (!addr) {
787                         esw_warn(esw->dev,
788                                  "Failed to add MAC(%pM) to vport[%d] DB\n",
789                                  mac_list[i], vport->vport);
790                         continue;
791                 }
792                 addr->vport = vport->vport;
793                 addr->action = MLX5_ACTION_ADD;
794         }
795 out:
796         kfree(mac_list);
797 }
798
799 /* Sync vport UC/MC list from vport context
800  * Must be called after esw_update_vport_addr_list
801  */
802 static void esw_update_vport_mc_promisc(struct mlx5_eswitch *esw,
803                                         struct mlx5_vport *vport)
804 {
805         struct l2addr_node *node;
806         struct vport_addr *addr;
807         struct hlist_head *hash;
808         struct hlist_node *tmp;
809         int hi;
810
811         hash = vport->mc_list;
812
813         for_each_l2hash_node(node, tmp, esw->mc_table, hi) {
814                 u8 *mac = node->addr;
815
816                 addr = l2addr_hash_find(hash, mac, struct vport_addr);
817                 if (addr) {
818                         if (addr->action == MLX5_ACTION_DEL)
819                                 addr->action = MLX5_ACTION_NONE;
820                         continue;
821                 }
822                 addr = l2addr_hash_add(hash, mac, struct vport_addr,
823                                        GFP_KERNEL);
824                 if (!addr) {
825                         esw_warn(esw->dev,
826                                  "Failed to add allmulti MAC(%pM) to vport[%d] DB\n",
827                                  mac, vport->vport);
828                         continue;
829                 }
830                 addr->vport = vport->vport;
831                 addr->action = MLX5_ACTION_ADD;
832                 addr->mc_promisc = true;
833         }
834 }
835
836 /* Apply vport rx mode to HW FDB table */
837 static void esw_apply_vport_rx_mode(struct mlx5_eswitch *esw,
838                                     struct mlx5_vport *vport,
839                                     bool promisc, bool mc_promisc)
840 {
841         struct esw_mc_addr *allmulti_addr = &esw->mc_promisc;
842
843         if (IS_ERR_OR_NULL(vport->allmulti_rule) != mc_promisc)
844                 goto promisc;
845
846         if (mc_promisc) {
847                 vport->allmulti_rule =
848                         esw_fdb_set_vport_allmulti_rule(esw, vport->vport);
849                 if (!allmulti_addr->uplink_rule)
850                         allmulti_addr->uplink_rule =
851                                 esw_fdb_set_vport_allmulti_rule(esw,
852                                                                 MLX5_VPORT_UPLINK);
853                 allmulti_addr->refcnt++;
854         } else if (vport->allmulti_rule) {
855                 mlx5_del_flow_rules(vport->allmulti_rule);
856                 vport->allmulti_rule = NULL;
857
858                 if (--allmulti_addr->refcnt > 0)
859                         goto promisc;
860
861                 if (allmulti_addr->uplink_rule)
862                         mlx5_del_flow_rules(allmulti_addr->uplink_rule);
863                 allmulti_addr->uplink_rule = NULL;
864         }
865
866 promisc:
867         if (IS_ERR_OR_NULL(vport->promisc_rule) != promisc)
868                 return;
869
870         if (promisc) {
871                 vport->promisc_rule =
872                         esw_fdb_set_vport_promisc_rule(esw, vport->vport);
873         } else if (vport->promisc_rule) {
874                 mlx5_del_flow_rules(vport->promisc_rule);
875                 vport->promisc_rule = NULL;
876         }
877 }
878
879 /* Sync vport rx mode from vport context */
880 static void esw_update_vport_rx_mode(struct mlx5_eswitch *esw,
881                                      struct mlx5_vport *vport)
882 {
883         int promisc_all = 0;
884         int promisc_uc = 0;
885         int promisc_mc = 0;
886         int err;
887
888         err = mlx5_query_nic_vport_promisc(esw->dev,
889                                            vport->vport,
890                                            &promisc_uc,
891                                            &promisc_mc,
892                                            &promisc_all);
893         if (err)
894                 return;
895         esw_debug(esw->dev, "vport[%d] context update rx mode promisc_all=%d, all_multi=%d\n",
896                   vport->vport, promisc_all, promisc_mc);
897
898         if (!vport->info.trusted || !vport->enabled) {
899                 promisc_uc = 0;
900                 promisc_mc = 0;
901                 promisc_all = 0;
902         }
903
904         esw_apply_vport_rx_mode(esw, vport, promisc_all,
905                                 (promisc_all || promisc_mc));
906 }
907
908 static void esw_vport_change_handle_locked(struct mlx5_vport *vport)
909 {
910         struct mlx5_core_dev *dev = vport->dev;
911         struct mlx5_eswitch *esw = dev->priv.eswitch;
912         u8 mac[ETH_ALEN];
913
914         mlx5_query_nic_vport_mac_address(dev, vport->vport, true, mac);
915         esw_debug(dev, "vport[%d] Context Changed: perm mac: %pM\n",
916                   vport->vport, mac);
917
918         if (vport->enabled_events & MLX5_VPORT_UC_ADDR_CHANGE) {
919                 esw_update_vport_addr_list(esw, vport, MLX5_NVPRT_LIST_TYPE_UC);
920                 esw_apply_vport_addr_list(esw, vport, MLX5_NVPRT_LIST_TYPE_UC);
921         }
922
923         if (vport->enabled_events & MLX5_VPORT_MC_ADDR_CHANGE)
924                 esw_update_vport_addr_list(esw, vport, MLX5_NVPRT_LIST_TYPE_MC);
925
926         if (vport->enabled_events & MLX5_VPORT_PROMISC_CHANGE) {
927                 esw_update_vport_rx_mode(esw, vport);
928                 if (!IS_ERR_OR_NULL(vport->allmulti_rule))
929                         esw_update_vport_mc_promisc(esw, vport);
930         }
931
932         if (vport->enabled_events & (MLX5_VPORT_PROMISC_CHANGE | MLX5_VPORT_MC_ADDR_CHANGE))
933                 esw_apply_vport_addr_list(esw, vport, MLX5_NVPRT_LIST_TYPE_MC);
934
935         esw_debug(esw->dev, "vport[%d] Context Changed: Done\n", vport->vport);
936         if (vport->enabled)
937                 arm_vport_context_events_cmd(dev, vport->vport,
938                                              vport->enabled_events);
939 }
940
941 static void esw_vport_change_handler(struct work_struct *work)
942 {
943         struct mlx5_vport *vport =
944                 container_of(work, struct mlx5_vport, vport_change_handler);
945         struct mlx5_eswitch *esw = vport->dev->priv.eswitch;
946
947         mutex_lock(&esw->state_lock);
948         esw_vport_change_handle_locked(vport);
949         mutex_unlock(&esw->state_lock);
950 }
951
952 int esw_vport_enable_egress_acl(struct mlx5_eswitch *esw,
953                                 struct mlx5_vport *vport)
954 {
955         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
956         struct mlx5_flow_group *vlan_grp = NULL;
957         struct mlx5_flow_group *drop_grp = NULL;
958         struct mlx5_core_dev *dev = esw->dev;
959         struct mlx5_flow_namespace *root_ns;
960         struct mlx5_flow_table *acl;
961         void *match_criteria;
962         u32 *flow_group_in;
963         /* The egress acl table contains 2 rules:
964          * 1)Allow traffic with vlan_tag=vst_vlan_id
965          * 2)Drop all other traffic.
966          */
967         int table_size = 2;
968         int err = 0;
969
970         if (!MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support))
971                 return -EOPNOTSUPP;
972
973         if (!IS_ERR_OR_NULL(vport->egress.acl))
974                 return 0;
975
976         esw_debug(dev, "Create vport[%d] egress ACL log_max_size(%d)\n",
977                   vport->vport, MLX5_CAP_ESW_EGRESS_ACL(dev, log_max_ft_size));
978
979         root_ns = mlx5_get_flow_vport_acl_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_EGRESS,
980                         mlx5_eswitch_vport_num_to_index(esw, vport->vport));
981         if (!root_ns) {
982                 esw_warn(dev, "Failed to get E-Switch egress flow namespace for vport (%d)\n", vport->vport);
983                 return -EOPNOTSUPP;
984         }
985
986         flow_group_in = kvzalloc(inlen, GFP_KERNEL);
987         if (!flow_group_in)
988                 return -ENOMEM;
989
990         acl = mlx5_create_vport_flow_table(root_ns, 0, table_size, 0, vport->vport);
991         if (IS_ERR(acl)) {
992                 err = PTR_ERR(acl);
993                 esw_warn(dev, "Failed to create E-Switch vport[%d] egress flow Table, err(%d)\n",
994                          vport->vport, err);
995                 goto out;
996         }
997
998         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
999         match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
1000         MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.cvlan_tag);
1001         MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.first_vid);
1002         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
1003         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 0);
1004
1005         vlan_grp = mlx5_create_flow_group(acl, flow_group_in);
1006         if (IS_ERR(vlan_grp)) {
1007                 err = PTR_ERR(vlan_grp);
1008                 esw_warn(dev, "Failed to create E-Switch vport[%d] egress allowed vlans flow group, err(%d)\n",
1009                          vport->vport, err);
1010                 goto out;
1011         }
1012
1013         memset(flow_group_in, 0, inlen);
1014         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 1);
1015         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 1);
1016         drop_grp = mlx5_create_flow_group(acl, flow_group_in);
1017         if (IS_ERR(drop_grp)) {
1018                 err = PTR_ERR(drop_grp);
1019                 esw_warn(dev, "Failed to create E-Switch vport[%d] egress drop flow group, err(%d)\n",
1020                          vport->vport, err);
1021                 goto out;
1022         }
1023
1024         vport->egress.acl = acl;
1025         vport->egress.drop_grp = drop_grp;
1026         vport->egress.allowed_vlans_grp = vlan_grp;
1027 out:
1028         kvfree(flow_group_in);
1029         if (err && !IS_ERR_OR_NULL(vlan_grp))
1030                 mlx5_destroy_flow_group(vlan_grp);
1031         if (err && !IS_ERR_OR_NULL(acl))
1032                 mlx5_destroy_flow_table(acl);
1033         return err;
1034 }
1035
1036 void esw_vport_cleanup_egress_rules(struct mlx5_eswitch *esw,
1037                                     struct mlx5_vport *vport)
1038 {
1039         if (!IS_ERR_OR_NULL(vport->egress.allowed_vlan)) {
1040                 mlx5_del_flow_rules(vport->egress.allowed_vlan);
1041                 vport->egress.allowed_vlan = NULL;
1042         }
1043
1044         if (!IS_ERR_OR_NULL(vport->egress.legacy.drop_rule)) {
1045                 mlx5_del_flow_rules(vport->egress.legacy.drop_rule);
1046                 vport->egress.legacy.drop_rule = NULL;
1047         }
1048 }
1049
1050 void esw_vport_disable_egress_acl(struct mlx5_eswitch *esw,
1051                                   struct mlx5_vport *vport)
1052 {
1053         if (IS_ERR_OR_NULL(vport->egress.acl))
1054                 return;
1055
1056         esw_debug(esw->dev, "Destroy vport[%d] E-Switch egress ACL\n", vport->vport);
1057
1058         esw_vport_cleanup_egress_rules(esw, vport);
1059         mlx5_destroy_flow_group(vport->egress.allowed_vlans_grp);
1060         mlx5_destroy_flow_group(vport->egress.drop_grp);
1061         mlx5_destroy_flow_table(vport->egress.acl);
1062         vport->egress.allowed_vlans_grp = NULL;
1063         vport->egress.drop_grp = NULL;
1064         vport->egress.acl = NULL;
1065 }
1066
1067 static int
1068 esw_vport_create_legacy_ingress_acl_groups(struct mlx5_eswitch *esw,
1069                                            struct mlx5_vport *vport)
1070 {
1071         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
1072         struct mlx5_core_dev *dev = esw->dev;
1073         struct mlx5_flow_group *g;
1074         void *match_criteria;
1075         u32 *flow_group_in;
1076         int err;
1077
1078         flow_group_in = kvzalloc(inlen, GFP_KERNEL);
1079         if (!flow_group_in)
1080                 return -ENOMEM;
1081
1082         match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
1083
1084         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
1085         MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.cvlan_tag);
1086         MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.smac_47_16);
1087         MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.smac_15_0);
1088         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
1089         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 0);
1090
1091         g = mlx5_create_flow_group(vport->ingress.acl, flow_group_in);
1092         if (IS_ERR(g)) {
1093                 err = PTR_ERR(g);
1094                 esw_warn(dev, "vport[%d] ingress create untagged spoofchk flow group, err(%d)\n",
1095                          vport->vport, err);
1096                 goto spoof_err;
1097         }
1098         vport->ingress.legacy.allow_untagged_spoofchk_grp = g;
1099
1100         memset(flow_group_in, 0, inlen);
1101         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
1102         MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.cvlan_tag);
1103         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 1);
1104         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 1);
1105
1106         g = mlx5_create_flow_group(vport->ingress.acl, flow_group_in);
1107         if (IS_ERR(g)) {
1108                 err = PTR_ERR(g);
1109                 esw_warn(dev, "vport[%d] ingress create untagged flow group, err(%d)\n",
1110                          vport->vport, err);
1111                 goto untagged_err;
1112         }
1113         vport->ingress.legacy.allow_untagged_only_grp = g;
1114
1115         memset(flow_group_in, 0, inlen);
1116         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
1117         MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.smac_47_16);
1118         MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.smac_15_0);
1119         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 2);
1120         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 2);
1121
1122         g = mlx5_create_flow_group(vport->ingress.acl, flow_group_in);
1123         if (IS_ERR(g)) {
1124                 err = PTR_ERR(g);
1125                 esw_warn(dev, "vport[%d] ingress create spoofchk flow group, err(%d)\n",
1126                          vport->vport, err);
1127                 goto allow_spoof_err;
1128         }
1129         vport->ingress.legacy.allow_spoofchk_only_grp = g;
1130
1131         memset(flow_group_in, 0, inlen);
1132         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 3);
1133         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 3);
1134
1135         g = mlx5_create_flow_group(vport->ingress.acl, flow_group_in);
1136         if (IS_ERR(g)) {
1137                 err = PTR_ERR(g);
1138                 esw_warn(dev, "vport[%d] ingress create drop flow group, err(%d)\n",
1139                          vport->vport, err);
1140                 goto drop_err;
1141         }
1142         vport->ingress.legacy.drop_grp = g;
1143         kvfree(flow_group_in);
1144         return 0;
1145
1146 drop_err:
1147         if (!IS_ERR_OR_NULL(vport->ingress.legacy.allow_spoofchk_only_grp)) {
1148                 mlx5_destroy_flow_group(vport->ingress.legacy.allow_spoofchk_only_grp);
1149                 vport->ingress.legacy.allow_spoofchk_only_grp = NULL;
1150         }
1151 allow_spoof_err:
1152         if (!IS_ERR_OR_NULL(vport->ingress.legacy.allow_untagged_only_grp)) {
1153                 mlx5_destroy_flow_group(vport->ingress.legacy.allow_untagged_only_grp);
1154                 vport->ingress.legacy.allow_untagged_only_grp = NULL;
1155         }
1156 untagged_err:
1157         if (!IS_ERR_OR_NULL(vport->ingress.legacy.allow_untagged_spoofchk_grp)) {
1158                 mlx5_destroy_flow_group(vport->ingress.legacy.allow_untagged_spoofchk_grp);
1159                 vport->ingress.legacy.allow_untagged_spoofchk_grp = NULL;
1160         }
1161 spoof_err:
1162         kvfree(flow_group_in);
1163         return err;
1164 }
1165
1166 int esw_vport_create_ingress_acl_table(struct mlx5_eswitch *esw,
1167                                        struct mlx5_vport *vport, int table_size)
1168 {
1169         struct mlx5_core_dev *dev = esw->dev;
1170         struct mlx5_flow_namespace *root_ns;
1171         struct mlx5_flow_table *acl;
1172         int vport_index;
1173         int err;
1174
1175         if (!MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support))
1176                 return -EOPNOTSUPP;
1177
1178         esw_debug(dev, "Create vport[%d] ingress ACL log_max_size(%d)\n",
1179                   vport->vport, MLX5_CAP_ESW_INGRESS_ACL(dev, log_max_ft_size));
1180
1181         vport_index = mlx5_eswitch_vport_num_to_index(esw, vport->vport);
1182         root_ns = mlx5_get_flow_vport_acl_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_INGRESS,
1183                                                     vport_index);
1184         if (!root_ns) {
1185                 esw_warn(dev, "Failed to get E-Switch ingress flow namespace for vport (%d)\n",
1186                          vport->vport);
1187                 return -EOPNOTSUPP;
1188         }
1189
1190         acl = mlx5_create_vport_flow_table(root_ns, 0, table_size, 0, vport->vport);
1191         if (IS_ERR(acl)) {
1192                 err = PTR_ERR(acl);
1193                 esw_warn(dev, "vport[%d] ingress create flow Table, err(%d)\n",
1194                          vport->vport, err);
1195                 return err;
1196         }
1197         vport->ingress.acl = acl;
1198         return 0;
1199 }
1200
1201 void esw_vport_destroy_ingress_acl_table(struct mlx5_vport *vport)
1202 {
1203         if (!vport->ingress.acl)
1204                 return;
1205
1206         mlx5_destroy_flow_table(vport->ingress.acl);
1207         vport->ingress.acl = NULL;
1208 }
1209
1210 void esw_vport_cleanup_ingress_rules(struct mlx5_eswitch *esw,
1211                                      struct mlx5_vport *vport)
1212 {
1213         if (vport->ingress.legacy.drop_rule) {
1214                 mlx5_del_flow_rules(vport->ingress.legacy.drop_rule);
1215                 vport->ingress.legacy.drop_rule = NULL;
1216         }
1217
1218         if (vport->ingress.allow_rule) {
1219                 mlx5_del_flow_rules(vport->ingress.allow_rule);
1220                 vport->ingress.allow_rule = NULL;
1221         }
1222 }
1223
1224 static void esw_vport_disable_legacy_ingress_acl(struct mlx5_eswitch *esw,
1225                                                  struct mlx5_vport *vport)
1226 {
1227         if (!vport->ingress.acl)
1228                 return;
1229
1230         esw_debug(esw->dev, "Destroy vport[%d] E-Switch ingress ACL\n", vport->vport);
1231
1232         esw_vport_cleanup_ingress_rules(esw, vport);
1233         if (vport->ingress.legacy.allow_spoofchk_only_grp) {
1234                 mlx5_destroy_flow_group(vport->ingress.legacy.allow_spoofchk_only_grp);
1235                 vport->ingress.legacy.allow_spoofchk_only_grp = NULL;
1236         }
1237         if (vport->ingress.legacy.allow_untagged_only_grp) {
1238                 mlx5_destroy_flow_group(vport->ingress.legacy.allow_untagged_only_grp);
1239                 vport->ingress.legacy.allow_untagged_only_grp = NULL;
1240         }
1241         if (vport->ingress.legacy.allow_untagged_spoofchk_grp) {
1242                 mlx5_destroy_flow_group(vport->ingress.legacy.allow_untagged_spoofchk_grp);
1243                 vport->ingress.legacy.allow_untagged_spoofchk_grp = NULL;
1244         }
1245         if (vport->ingress.legacy.drop_grp) {
1246                 mlx5_destroy_flow_group(vport->ingress.legacy.drop_grp);
1247                 vport->ingress.legacy.drop_grp = NULL;
1248         }
1249         esw_vport_destroy_ingress_acl_table(vport);
1250 }
1251
1252 static int esw_vport_ingress_config(struct mlx5_eswitch *esw,
1253                                     struct mlx5_vport *vport)
1254 {
1255         struct mlx5_fc *counter = vport->ingress.legacy.drop_counter;
1256         struct mlx5_flow_destination drop_ctr_dst = {0};
1257         struct mlx5_flow_destination *dst = NULL;
1258         struct mlx5_flow_act flow_act = {0};
1259         struct mlx5_flow_spec *spec = NULL;
1260         int dest_num = 0;
1261         int err = 0;
1262         u8 *smac_v;
1263
1264         /* The ingress acl table contains 4 groups
1265          * (2 active rules at the same time -
1266          *      1 allow rule from one of the first 3 groups.
1267          *      1 drop rule from the last group):
1268          * 1)Allow untagged traffic with smac=original mac.
1269          * 2)Allow untagged traffic.
1270          * 3)Allow traffic with smac=original mac.
1271          * 4)Drop all other traffic.
1272          */
1273         int table_size = 4;
1274
1275         esw_vport_cleanup_ingress_rules(esw, vport);
1276
1277         if (!vport->info.vlan && !vport->info.qos && !vport->info.spoofchk) {
1278                 esw_vport_disable_legacy_ingress_acl(esw, vport);
1279                 return 0;
1280         }
1281
1282         if (!vport->ingress.acl) {
1283                 err = esw_vport_create_ingress_acl_table(esw, vport, table_size);
1284                 if (err) {
1285                         esw_warn(esw->dev,
1286                                  "vport[%d] enable ingress acl err (%d)\n",
1287                                  err, vport->vport);
1288                         return err;
1289                 }
1290
1291                 err = esw_vport_create_legacy_ingress_acl_groups(esw, vport);
1292                 if (err)
1293                         goto out;
1294         }
1295
1296         esw_debug(esw->dev,
1297                   "vport[%d] configure ingress rules, vlan(%d) qos(%d)\n",
1298                   vport->vport, vport->info.vlan, vport->info.qos);
1299
1300         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1301         if (!spec) {
1302                 err = -ENOMEM;
1303                 goto out;
1304         }
1305
1306         if (vport->info.vlan || vport->info.qos)
1307                 MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.cvlan_tag);
1308
1309         if (vport->info.spoofchk) {
1310                 MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.smac_47_16);
1311                 MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.smac_15_0);
1312                 smac_v = MLX5_ADDR_OF(fte_match_param,
1313                                       spec->match_value,
1314                                       outer_headers.smac_47_16);
1315                 ether_addr_copy(smac_v, vport->info.mac);
1316         }
1317
1318         spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
1319         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_ALLOW;
1320         vport->ingress.allow_rule =
1321                 mlx5_add_flow_rules(vport->ingress.acl, spec,
1322                                     &flow_act, NULL, 0);
1323         if (IS_ERR(vport->ingress.allow_rule)) {
1324                 err = PTR_ERR(vport->ingress.allow_rule);
1325                 esw_warn(esw->dev,
1326                          "vport[%d] configure ingress allow rule, err(%d)\n",
1327                          vport->vport, err);
1328                 vport->ingress.allow_rule = NULL;
1329                 goto out;
1330         }
1331
1332         memset(spec, 0, sizeof(*spec));
1333         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP;
1334
1335         /* Attach drop flow counter */
1336         if (counter) {
1337                 flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
1338                 drop_ctr_dst.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
1339                 drop_ctr_dst.counter_id = mlx5_fc_id(counter);
1340                 dst = &drop_ctr_dst;
1341                 dest_num++;
1342         }
1343         vport->ingress.legacy.drop_rule =
1344                 mlx5_add_flow_rules(vport->ingress.acl, spec,
1345                                     &flow_act, dst, dest_num);
1346         if (IS_ERR(vport->ingress.legacy.drop_rule)) {
1347                 err = PTR_ERR(vport->ingress.legacy.drop_rule);
1348                 esw_warn(esw->dev,
1349                          "vport[%d] configure ingress drop rule, err(%d)\n",
1350                          vport->vport, err);
1351                 vport->ingress.legacy.drop_rule = NULL;
1352                 goto out;
1353         }
1354         kvfree(spec);
1355         return 0;
1356
1357 out:
1358         esw_vport_disable_legacy_ingress_acl(esw, vport);
1359         kvfree(spec);
1360         return err;
1361 }
1362
1363 int mlx5_esw_create_vport_egress_acl_vlan(struct mlx5_eswitch *esw,
1364                                           struct mlx5_vport *vport,
1365                                           u16 vlan_id, u32 flow_action)
1366 {
1367         struct mlx5_flow_act flow_act = {};
1368         struct mlx5_flow_spec *spec;
1369         int err = 0;
1370
1371         if (vport->egress.allowed_vlan)
1372                 return -EEXIST;
1373
1374         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1375         if (!spec)
1376                 return -ENOMEM;
1377
1378         MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.cvlan_tag);
1379         MLX5_SET_TO_ONES(fte_match_param, spec->match_value, outer_headers.cvlan_tag);
1380         MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.first_vid);
1381         MLX5_SET(fte_match_param, spec->match_value, outer_headers.first_vid, vlan_id);
1382
1383         spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
1384         flow_act.action = flow_action;
1385         vport->egress.allowed_vlan =
1386                 mlx5_add_flow_rules(vport->egress.acl, spec,
1387                                     &flow_act, NULL, 0);
1388         if (IS_ERR(vport->egress.allowed_vlan)) {
1389                 err = PTR_ERR(vport->egress.allowed_vlan);
1390                 esw_warn(esw->dev,
1391                          "vport[%d] configure egress vlan rule failed, err(%d)\n",
1392                          vport->vport, err);
1393                 vport->egress.allowed_vlan = NULL;
1394         }
1395
1396         kvfree(spec);
1397         return err;
1398 }
1399
1400 static int esw_vport_egress_config(struct mlx5_eswitch *esw,
1401                                    struct mlx5_vport *vport)
1402 {
1403         struct mlx5_fc *counter = vport->egress.legacy.drop_counter;
1404         struct mlx5_flow_destination drop_ctr_dst = {0};
1405         struct mlx5_flow_destination *dst = NULL;
1406         struct mlx5_flow_act flow_act = {0};
1407         struct mlx5_flow_spec *spec;
1408         int dest_num = 0;
1409         int err = 0;
1410
1411         esw_vport_cleanup_egress_rules(esw, vport);
1412
1413         if (!vport->info.vlan && !vport->info.qos) {
1414                 esw_vport_disable_egress_acl(esw, vport);
1415                 return 0;
1416         }
1417
1418         err = esw_vport_enable_egress_acl(esw, vport);
1419         if (err) {
1420                 mlx5_core_warn(esw->dev,
1421                                "failed to enable egress acl (%d) on vport[%d]\n",
1422                                err, vport->vport);
1423                 return err;
1424         }
1425
1426         esw_debug(esw->dev,
1427                   "vport[%d] configure egress rules, vlan(%d) qos(%d)\n",
1428                   vport->vport, vport->info.vlan, vport->info.qos);
1429
1430         /* Allowed vlan rule */
1431         err = mlx5_esw_create_vport_egress_acl_vlan(esw, vport, vport->info.vlan,
1432                                                     MLX5_FLOW_CONTEXT_ACTION_ALLOW);
1433         if (err)
1434                 return err;
1435
1436         /* Drop others rule (star rule) */
1437         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1438         if (!spec)
1439                 goto out;
1440
1441         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP;
1442
1443         /* Attach egress drop flow counter */
1444         if (counter) {
1445                 flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
1446                 drop_ctr_dst.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
1447                 drop_ctr_dst.counter_id = mlx5_fc_id(counter);
1448                 dst = &drop_ctr_dst;
1449                 dest_num++;
1450         }
1451         vport->egress.legacy.drop_rule =
1452                 mlx5_add_flow_rules(vport->egress.acl, spec,
1453                                     &flow_act, dst, dest_num);
1454         if (IS_ERR(vport->egress.legacy.drop_rule)) {
1455                 err = PTR_ERR(vport->egress.legacy.drop_rule);
1456                 esw_warn(esw->dev,
1457                          "vport[%d] configure egress drop rule failed, err(%d)\n",
1458                          vport->vport, err);
1459                 vport->egress.legacy.drop_rule = NULL;
1460         }
1461 out:
1462         kvfree(spec);
1463         return err;
1464 }
1465
1466 static bool element_type_supported(struct mlx5_eswitch *esw, int type)
1467 {
1468         const struct mlx5_core_dev *dev = esw->dev;
1469
1470         switch (type) {
1471         case SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR:
1472                 return MLX5_CAP_QOS(dev, esw_element_type) &
1473                        ELEMENT_TYPE_CAP_MASK_TASR;
1474         case SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT:
1475                 return MLX5_CAP_QOS(dev, esw_element_type) &
1476                        ELEMENT_TYPE_CAP_MASK_VPORT;
1477         case SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT_TC:
1478                 return MLX5_CAP_QOS(dev, esw_element_type) &
1479                        ELEMENT_TYPE_CAP_MASK_VPORT_TC;
1480         case SCHEDULING_CONTEXT_ELEMENT_TYPE_PARA_VPORT_TC:
1481                 return MLX5_CAP_QOS(dev, esw_element_type) &
1482                        ELEMENT_TYPE_CAP_MASK_PARA_VPORT_TC;
1483         }
1484         return false;
1485 }
1486
1487 /* Vport QoS management */
1488 static void esw_create_tsar(struct mlx5_eswitch *esw)
1489 {
1490         u32 tsar_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {0};
1491         struct mlx5_core_dev *dev = esw->dev;
1492         __be32 *attr;
1493         int err;
1494
1495         if (!MLX5_CAP_GEN(dev, qos) || !MLX5_CAP_QOS(dev, esw_scheduling))
1496                 return;
1497
1498         if (!element_type_supported(esw, SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR))
1499                 return;
1500
1501         if (esw->qos.enabled)
1502                 return;
1503
1504         MLX5_SET(scheduling_context, tsar_ctx, element_type,
1505                  SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR);
1506
1507         attr = MLX5_ADDR_OF(scheduling_context, tsar_ctx, element_attributes);
1508         *attr = cpu_to_be32(TSAR_ELEMENT_TSAR_TYPE_DWRR << 16);
1509
1510         err = mlx5_create_scheduling_element_cmd(dev,
1511                                                  SCHEDULING_HIERARCHY_E_SWITCH,
1512                                                  tsar_ctx,
1513                                                  &esw->qos.root_tsar_id);
1514         if (err) {
1515                 esw_warn(esw->dev, "E-Switch create TSAR failed (%d)\n", err);
1516                 return;
1517         }
1518
1519         esw->qos.enabled = true;
1520 }
1521
1522 static void esw_destroy_tsar(struct mlx5_eswitch *esw)
1523 {
1524         int err;
1525
1526         if (!esw->qos.enabled)
1527                 return;
1528
1529         err = mlx5_destroy_scheduling_element_cmd(esw->dev,
1530                                                   SCHEDULING_HIERARCHY_E_SWITCH,
1531                                                   esw->qos.root_tsar_id);
1532         if (err)
1533                 esw_warn(esw->dev, "E-Switch destroy TSAR failed (%d)\n", err);
1534
1535         esw->qos.enabled = false;
1536 }
1537
1538 static int esw_vport_enable_qos(struct mlx5_eswitch *esw,
1539                                 struct mlx5_vport *vport,
1540                                 u32 initial_max_rate, u32 initial_bw_share)
1541 {
1542         u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {0};
1543         struct mlx5_core_dev *dev = esw->dev;
1544         void *vport_elem;
1545         int err = 0;
1546
1547         if (!esw->qos.enabled || !MLX5_CAP_GEN(dev, qos) ||
1548             !MLX5_CAP_QOS(dev, esw_scheduling))
1549                 return 0;
1550
1551         if (vport->qos.enabled)
1552                 return -EEXIST;
1553
1554         MLX5_SET(scheduling_context, sched_ctx, element_type,
1555                  SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT);
1556         vport_elem = MLX5_ADDR_OF(scheduling_context, sched_ctx,
1557                                   element_attributes);
1558         MLX5_SET(vport_element, vport_elem, vport_number, vport->vport);
1559         MLX5_SET(scheduling_context, sched_ctx, parent_element_id,
1560                  esw->qos.root_tsar_id);
1561         MLX5_SET(scheduling_context, sched_ctx, max_average_bw,
1562                  initial_max_rate);
1563         MLX5_SET(scheduling_context, sched_ctx, bw_share, initial_bw_share);
1564
1565         err = mlx5_create_scheduling_element_cmd(dev,
1566                                                  SCHEDULING_HIERARCHY_E_SWITCH,
1567                                                  sched_ctx,
1568                                                  &vport->qos.esw_tsar_ix);
1569         if (err) {
1570                 esw_warn(esw->dev, "E-Switch create TSAR vport element failed (vport=%d,err=%d)\n",
1571                          vport->vport, err);
1572                 return err;
1573         }
1574
1575         vport->qos.enabled = true;
1576         return 0;
1577 }
1578
1579 static void esw_vport_disable_qos(struct mlx5_eswitch *esw,
1580                                   struct mlx5_vport *vport)
1581 {
1582         int err;
1583
1584         if (!vport->qos.enabled)
1585                 return;
1586
1587         err = mlx5_destroy_scheduling_element_cmd(esw->dev,
1588                                                   SCHEDULING_HIERARCHY_E_SWITCH,
1589                                                   vport->qos.esw_tsar_ix);
1590         if (err)
1591                 esw_warn(esw->dev, "E-Switch destroy TSAR vport element failed (vport=%d,err=%d)\n",
1592                          vport->vport, err);
1593
1594         vport->qos.enabled = false;
1595 }
1596
1597 static int esw_vport_qos_config(struct mlx5_eswitch *esw,
1598                                 struct mlx5_vport *vport,
1599                                 u32 max_rate, u32 bw_share)
1600 {
1601         u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {0};
1602         struct mlx5_core_dev *dev = esw->dev;
1603         void *vport_elem;
1604         u32 bitmask = 0;
1605         int err = 0;
1606
1607         if (!MLX5_CAP_GEN(dev, qos) || !MLX5_CAP_QOS(dev, esw_scheduling))
1608                 return -EOPNOTSUPP;
1609
1610         if (!vport->qos.enabled)
1611                 return -EIO;
1612
1613         MLX5_SET(scheduling_context, sched_ctx, element_type,
1614                  SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT);
1615         vport_elem = MLX5_ADDR_OF(scheduling_context, sched_ctx,
1616                                   element_attributes);
1617         MLX5_SET(vport_element, vport_elem, vport_number, vport->vport);
1618         MLX5_SET(scheduling_context, sched_ctx, parent_element_id,
1619                  esw->qos.root_tsar_id);
1620         MLX5_SET(scheduling_context, sched_ctx, max_average_bw,
1621                  max_rate);
1622         MLX5_SET(scheduling_context, sched_ctx, bw_share, bw_share);
1623         bitmask |= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_MAX_AVERAGE_BW;
1624         bitmask |= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_BW_SHARE;
1625
1626         err = mlx5_modify_scheduling_element_cmd(dev,
1627                                                  SCHEDULING_HIERARCHY_E_SWITCH,
1628                                                  sched_ctx,
1629                                                  vport->qos.esw_tsar_ix,
1630                                                  bitmask);
1631         if (err) {
1632                 esw_warn(esw->dev, "E-Switch modify TSAR vport element failed (vport=%d,err=%d)\n",
1633                          vport->vport, err);
1634                 return err;
1635         }
1636
1637         return 0;
1638 }
1639
1640 int mlx5_esw_modify_vport_rate(struct mlx5_eswitch *esw, u16 vport_num,
1641                                u32 rate_mbps)
1642 {
1643         u32 ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
1644         struct mlx5_vport *vport;
1645
1646         vport = mlx5_eswitch_get_vport(esw, vport_num);
1647         MLX5_SET(scheduling_context, ctx, max_average_bw, rate_mbps);
1648
1649         return mlx5_modify_scheduling_element_cmd(esw->dev,
1650                                                   SCHEDULING_HIERARCHY_E_SWITCH,
1651                                                   ctx,
1652                                                   vport->qos.esw_tsar_ix,
1653                                                   MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_MAX_AVERAGE_BW);
1654 }
1655
1656 static void node_guid_gen_from_mac(u64 *node_guid, u8 mac[ETH_ALEN])
1657 {
1658         ((u8 *)node_guid)[7] = mac[0];
1659         ((u8 *)node_guid)[6] = mac[1];
1660         ((u8 *)node_guid)[5] = mac[2];
1661         ((u8 *)node_guid)[4] = 0xff;
1662         ((u8 *)node_guid)[3] = 0xfe;
1663         ((u8 *)node_guid)[2] = mac[3];
1664         ((u8 *)node_guid)[1] = mac[4];
1665         ((u8 *)node_guid)[0] = mac[5];
1666 }
1667
1668 static void esw_apply_vport_conf(struct mlx5_eswitch *esw,
1669                                  struct mlx5_vport *vport)
1670 {
1671         u16 vport_num = vport->vport;
1672         int flags;
1673
1674         if (mlx5_esw_is_manager_vport(esw, vport_num))
1675                 return;
1676
1677         mlx5_modify_vport_admin_state(esw->dev,
1678                                       MLX5_VPORT_STATE_OP_MOD_ESW_VPORT,
1679                                       vport_num, 1,
1680                                       vport->info.link_state);
1681
1682         /* Host PF has its own mac/guid. */
1683         if (vport_num) {
1684                 mlx5_modify_nic_vport_mac_address(esw->dev, vport_num,
1685                                                   vport->info.mac);
1686                 mlx5_modify_nic_vport_node_guid(esw->dev, vport_num,
1687                                                 vport->info.node_guid);
1688         }
1689
1690         flags = (vport->info.vlan || vport->info.qos) ?
1691                 SET_VLAN_STRIP | SET_VLAN_INSERT : 0;
1692         modify_esw_vport_cvlan(esw->dev, vport_num, vport->info.vlan, vport->info.qos,
1693                                flags);
1694 }
1695
1696 static int esw_vport_create_legacy_acl_tables(struct mlx5_eswitch *esw,
1697                                               struct mlx5_vport *vport)
1698 {
1699         int ret;
1700
1701         /* Only non manager vports need ACL in legacy mode */
1702         if (mlx5_esw_is_manager_vport(esw, vport->vport))
1703                 return 0;
1704
1705         if (!mlx5_esw_is_manager_vport(esw, vport->vport) &&
1706             MLX5_CAP_ESW_INGRESS_ACL(esw->dev, flow_counter)) {
1707                 vport->ingress.legacy.drop_counter = mlx5_fc_create(esw->dev, false);
1708                 if (IS_ERR(vport->ingress.legacy.drop_counter)) {
1709                         esw_warn(esw->dev,
1710                                  "vport[%d] configure ingress drop rule counter failed\n",
1711                                  vport->vport);
1712                         vport->ingress.legacy.drop_counter = NULL;
1713                 }
1714         }
1715
1716         ret = esw_vport_ingress_config(esw, vport);
1717         if (ret)
1718                 goto ingress_err;
1719
1720         if (!mlx5_esw_is_manager_vport(esw, vport->vport) &&
1721             MLX5_CAP_ESW_EGRESS_ACL(esw->dev, flow_counter)) {
1722                 vport->egress.legacy.drop_counter = mlx5_fc_create(esw->dev, false);
1723                 if (IS_ERR(vport->egress.legacy.drop_counter)) {
1724                         esw_warn(esw->dev,
1725                                  "vport[%d] configure egress drop rule counter failed\n",
1726                                  vport->vport);
1727                         vport->egress.legacy.drop_counter = NULL;
1728                 }
1729         }
1730
1731         ret = esw_vport_egress_config(esw, vport);
1732         if (ret)
1733                 goto egress_err;
1734
1735         return 0;
1736
1737 egress_err:
1738         esw_vport_disable_legacy_ingress_acl(esw, vport);
1739         mlx5_fc_destroy(esw->dev, vport->egress.legacy.drop_counter);
1740         vport->egress.legacy.drop_counter = NULL;
1741
1742 ingress_err:
1743         mlx5_fc_destroy(esw->dev, vport->ingress.legacy.drop_counter);
1744         vport->ingress.legacy.drop_counter = NULL;
1745         return ret;
1746 }
1747
1748 static int esw_vport_setup_acl(struct mlx5_eswitch *esw,
1749                                struct mlx5_vport *vport)
1750 {
1751         if (esw->mode == MLX5_ESWITCH_LEGACY)
1752                 return esw_vport_create_legacy_acl_tables(esw, vport);
1753         else
1754                 return esw_vport_create_offloads_acl_tables(esw, vport);
1755 }
1756
1757 static void esw_vport_destroy_legacy_acl_tables(struct mlx5_eswitch *esw,
1758                                                 struct mlx5_vport *vport)
1759
1760 {
1761         if (mlx5_esw_is_manager_vport(esw, vport->vport))
1762                 return;
1763
1764         esw_vport_disable_egress_acl(esw, vport);
1765         mlx5_fc_destroy(esw->dev, vport->egress.legacy.drop_counter);
1766         vport->egress.legacy.drop_counter = NULL;
1767
1768         esw_vport_disable_legacy_ingress_acl(esw, vport);
1769         mlx5_fc_destroy(esw->dev, vport->ingress.legacy.drop_counter);
1770         vport->ingress.legacy.drop_counter = NULL;
1771 }
1772
1773 static void esw_vport_cleanup_acl(struct mlx5_eswitch *esw,
1774                                   struct mlx5_vport *vport)
1775 {
1776         if (esw->mode == MLX5_ESWITCH_LEGACY)
1777                 esw_vport_destroy_legacy_acl_tables(esw, vport);
1778         else
1779                 esw_vport_destroy_offloads_acl_tables(esw, vport);
1780 }
1781
1782 static int esw_enable_vport(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
1783                             enum mlx5_eswitch_vport_event enabled_events)
1784 {
1785         u16 vport_num = vport->vport;
1786         int ret;
1787
1788         mutex_lock(&esw->state_lock);
1789         WARN_ON(vport->enabled);
1790
1791         esw_debug(esw->dev, "Enabling VPORT(%d)\n", vport_num);
1792
1793         /* Restore old vport configuration */
1794         esw_apply_vport_conf(esw, vport);
1795
1796         ret = esw_vport_setup_acl(esw, vport);
1797         if (ret)
1798                 goto done;
1799
1800         /* Attach vport to the eswitch rate limiter */
1801         if (esw_vport_enable_qos(esw, vport, vport->info.max_rate,
1802                                  vport->qos.bw_share))
1803                 esw_warn(esw->dev, "Failed to attach vport %d to eswitch rate limiter", vport_num);
1804
1805         /* Sync with current vport context */
1806         vport->enabled_events = enabled_events;
1807         vport->enabled = true;
1808
1809         /* Esw manager is trusted by default. Host PF (vport 0) is trusted as well
1810          * in smartNIC as it's a vport group manager.
1811          */
1812         if (mlx5_esw_is_manager_vport(esw, vport_num) ||
1813             (!vport_num && mlx5_core_is_ecpf(esw->dev)))
1814                 vport->info.trusted = true;
1815
1816         esw_vport_change_handle_locked(vport);
1817
1818         esw->enabled_vports++;
1819         esw_debug(esw->dev, "Enabled VPORT(%d)\n", vport_num);
1820 done:
1821         mutex_unlock(&esw->state_lock);
1822         return ret;
1823 }
1824
1825 static void esw_disable_vport(struct mlx5_eswitch *esw,
1826                               struct mlx5_vport *vport)
1827 {
1828         u16 vport_num = vport->vport;
1829
1830         mutex_lock(&esw->state_lock);
1831         if (!vport->enabled)
1832                 goto done;
1833
1834         esw_debug(esw->dev, "Disabling vport(%d)\n", vport_num);
1835         /* Mark this vport as disabled to discard new events */
1836         vport->enabled = false;
1837
1838         /* Disable events from this vport */
1839         arm_vport_context_events_cmd(esw->dev, vport->vport, 0);
1840         /* We don't assume VFs will cleanup after themselves.
1841          * Calling vport change handler while vport is disabled will cleanup
1842          * the vport resources.
1843          */
1844         esw_vport_change_handle_locked(vport);
1845         vport->enabled_events = 0;
1846         esw_vport_disable_qos(esw, vport);
1847
1848         if (!mlx5_esw_is_manager_vport(esw, vport->vport) &&
1849             esw->mode == MLX5_ESWITCH_LEGACY)
1850                 mlx5_modify_vport_admin_state(esw->dev,
1851                                               MLX5_VPORT_STATE_OP_MOD_ESW_VPORT,
1852                                               vport_num, 1,
1853                                               MLX5_VPORT_ADMIN_STATE_DOWN);
1854
1855         esw_vport_cleanup_acl(esw, vport);
1856         esw->enabled_vports--;
1857
1858 done:
1859         mutex_unlock(&esw->state_lock);
1860 }
1861
1862 static int eswitch_vport_event(struct notifier_block *nb,
1863                                unsigned long type, void *data)
1864 {
1865         struct mlx5_eswitch *esw = mlx5_nb_cof(nb, struct mlx5_eswitch, nb);
1866         struct mlx5_eqe *eqe = data;
1867         struct mlx5_vport *vport;
1868         u16 vport_num;
1869
1870         vport_num = be16_to_cpu(eqe->data.vport_change.vport_num);
1871         vport = mlx5_eswitch_get_vport(esw, vport_num);
1872         if (!IS_ERR(vport))
1873                 queue_work(esw->work_queue, &vport->vport_change_handler);
1874         return NOTIFY_OK;
1875 }
1876
1877 /**
1878  * mlx5_esw_query_functions - Returns raw output about functions state
1879  * @dev:        Pointer to device to query
1880  *
1881  * mlx5_esw_query_functions() allocates and returns functions changed
1882  * raw output memory pointer from device on success. Otherwise returns ERR_PTR.
1883  * Caller must free the memory using kvfree() when valid pointer is returned.
1884  */
1885 const u32 *mlx5_esw_query_functions(struct mlx5_core_dev *dev)
1886 {
1887         int outlen = MLX5_ST_SZ_BYTES(query_esw_functions_out);
1888         u32 in[MLX5_ST_SZ_DW(query_esw_functions_in)] = {};
1889         u32 *out;
1890         int err;
1891
1892         out = kvzalloc(outlen, GFP_KERNEL);
1893         if (!out)
1894                 return ERR_PTR(-ENOMEM);
1895
1896         MLX5_SET(query_esw_functions_in, in, opcode,
1897                  MLX5_CMD_OP_QUERY_ESW_FUNCTIONS);
1898
1899         err = mlx5_cmd_exec(dev, in, sizeof(in), out, outlen);
1900         if (!err)
1901                 return out;
1902
1903         kvfree(out);
1904         return ERR_PTR(err);
1905 }
1906
1907 static void mlx5_eswitch_event_handlers_register(struct mlx5_eswitch *esw)
1908 {
1909         MLX5_NB_INIT(&esw->nb, eswitch_vport_event, NIC_VPORT_CHANGE);
1910         mlx5_eq_notifier_register(esw->dev, &esw->nb);
1911
1912         if (esw->mode == MLX5_ESWITCH_OFFLOADS && mlx5_eswitch_is_funcs_handler(esw->dev)) {
1913                 MLX5_NB_INIT(&esw->esw_funcs.nb, mlx5_esw_funcs_changed_handler,
1914                              ESW_FUNCTIONS_CHANGED);
1915                 mlx5_eq_notifier_register(esw->dev, &esw->esw_funcs.nb);
1916         }
1917 }
1918
1919 static void mlx5_eswitch_event_handlers_unregister(struct mlx5_eswitch *esw)
1920 {
1921         if (esw->mode == MLX5_ESWITCH_OFFLOADS && mlx5_eswitch_is_funcs_handler(esw->dev))
1922                 mlx5_eq_notifier_unregister(esw->dev, &esw->esw_funcs.nb);
1923
1924         mlx5_eq_notifier_unregister(esw->dev, &esw->nb);
1925
1926         flush_workqueue(esw->work_queue);
1927 }
1928
1929 static void mlx5_eswitch_clear_vf_vports_info(struct mlx5_eswitch *esw)
1930 {
1931         struct mlx5_vport *vport;
1932         int i;
1933
1934         mlx5_esw_for_each_vf_vport(esw, i, vport, esw->esw_funcs.num_vfs)
1935                 memset(&vport->info, 0, sizeof(vport->info));
1936 }
1937
1938 /* Public E-Switch API */
1939 #define ESW_ALLOWED(esw) ((esw) && MLX5_ESWITCH_MANAGER((esw)->dev))
1940
1941 /* mlx5_eswitch_enable_pf_vf_vports() enables vports of PF, ECPF and VFs
1942  * whichever are present on the eswitch.
1943  */
1944 int
1945 mlx5_eswitch_enable_pf_vf_vports(struct mlx5_eswitch *esw,
1946                                  enum mlx5_eswitch_vport_event enabled_events)
1947 {
1948         struct mlx5_vport *vport;
1949         int num_vfs;
1950         int ret;
1951         int i;
1952
1953         /* Enable PF vport */
1954         vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_PF);
1955         ret = esw_enable_vport(esw, vport, enabled_events);
1956         if (ret)
1957                 return ret;
1958
1959         /* Enable ECPF vport */
1960         if (mlx5_ecpf_vport_exists(esw->dev)) {
1961                 vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_ECPF);
1962                 ret = esw_enable_vport(esw, vport, enabled_events);
1963                 if (ret)
1964                         goto ecpf_err;
1965         }
1966
1967         /* Enable VF vports */
1968         mlx5_esw_for_each_vf_vport(esw, i, vport, esw->esw_funcs.num_vfs) {
1969                 ret = esw_enable_vport(esw, vport, enabled_events);
1970                 if (ret)
1971                         goto vf_err;
1972         }
1973         return 0;
1974
1975 vf_err:
1976         num_vfs = i - 1;
1977         mlx5_esw_for_each_vf_vport_reverse(esw, i, vport, num_vfs)
1978                 esw_disable_vport(esw, vport);
1979
1980         if (mlx5_ecpf_vport_exists(esw->dev)) {
1981                 vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_ECPF);
1982                 esw_disable_vport(esw, vport);
1983         }
1984
1985 ecpf_err:
1986         vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_PF);
1987         esw_disable_vport(esw, vport);
1988         return ret;
1989 }
1990
1991 /* mlx5_eswitch_disable_pf_vf_vports() disables vports of PF, ECPF and VFs
1992  * whichever are previously enabled on the eswitch.
1993  */
1994 void mlx5_eswitch_disable_pf_vf_vports(struct mlx5_eswitch *esw)
1995 {
1996         struct mlx5_vport *vport;
1997         int i;
1998
1999         mlx5_esw_for_all_vports_reverse(esw, i, vport)
2000                 esw_disable_vport(esw, vport);
2001 }
2002
2003 int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int mode)
2004 {
2005         int err;
2006
2007         if (!ESW_ALLOWED(esw) ||
2008             !MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, ft_support)) {
2009                 esw_warn(esw->dev, "FDB is not supported, aborting ...\n");
2010                 return -EOPNOTSUPP;
2011         }
2012
2013         if (!MLX5_CAP_ESW_INGRESS_ACL(esw->dev, ft_support))
2014                 esw_warn(esw->dev, "ingress ACL is not supported by FW\n");
2015
2016         if (!MLX5_CAP_ESW_EGRESS_ACL(esw->dev, ft_support))
2017                 esw_warn(esw->dev, "engress ACL is not supported by FW\n");
2018
2019         esw_create_tsar(esw);
2020
2021         esw->mode = mode;
2022
2023         mlx5_lag_update(esw->dev);
2024
2025         if (mode == MLX5_ESWITCH_LEGACY) {
2026                 err = esw_legacy_enable(esw);
2027         } else {
2028                 mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_ETH);
2029                 mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
2030                 err = esw_offloads_enable(esw);
2031         }
2032
2033         if (err)
2034                 goto abort;
2035
2036         mlx5_eswitch_event_handlers_register(esw);
2037
2038         esw_info(esw->dev, "Enable: mode(%s), nvfs(%d), active vports(%d)\n",
2039                  mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",
2040                  esw->esw_funcs.num_vfs, esw->enabled_vports);
2041
2042         return 0;
2043
2044 abort:
2045         esw->mode = MLX5_ESWITCH_NONE;
2046
2047         if (mode == MLX5_ESWITCH_OFFLOADS) {
2048                 mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
2049                 mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_ETH);
2050         }
2051
2052         return err;
2053 }
2054
2055 void mlx5_eswitch_disable(struct mlx5_eswitch *esw, bool clear_vf)
2056 {
2057         int old_mode;
2058
2059         if (!ESW_ALLOWED(esw) || esw->mode == MLX5_ESWITCH_NONE)
2060                 return;
2061
2062         esw_info(esw->dev, "Disable: mode(%s), nvfs(%d), active vports(%d)\n",
2063                  esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",
2064                  esw->esw_funcs.num_vfs, esw->enabled_vports);
2065
2066         mlx5_eswitch_event_handlers_unregister(esw);
2067
2068         if (esw->mode == MLX5_ESWITCH_LEGACY)
2069                 esw_legacy_disable(esw);
2070         else if (esw->mode == MLX5_ESWITCH_OFFLOADS)
2071                 esw_offloads_disable(esw);
2072
2073         esw_destroy_tsar(esw);
2074
2075         old_mode = esw->mode;
2076         esw->mode = MLX5_ESWITCH_NONE;
2077
2078         mlx5_lag_update(esw->dev);
2079
2080         if (old_mode == MLX5_ESWITCH_OFFLOADS) {
2081                 mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
2082                 mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_ETH);
2083         }
2084         if (clear_vf)
2085                 mlx5_eswitch_clear_vf_vports_info(esw);
2086 }
2087
2088 int mlx5_eswitch_init(struct mlx5_core_dev *dev)
2089 {
2090         struct mlx5_eswitch *esw;
2091         struct mlx5_vport *vport;
2092         int total_vports;
2093         int err, i;
2094
2095         if (!MLX5_VPORT_MANAGER(dev))
2096                 return 0;
2097
2098         total_vports = mlx5_eswitch_get_total_vports(dev);
2099
2100         esw_info(dev,
2101                  "Total vports %d, per vport: max uc(%d) max mc(%d)\n",
2102                  total_vports,
2103                  MLX5_MAX_UC_PER_VPORT(dev),
2104                  MLX5_MAX_MC_PER_VPORT(dev));
2105
2106         esw = kzalloc(sizeof(*esw), GFP_KERNEL);
2107         if (!esw)
2108                 return -ENOMEM;
2109
2110         esw->dev = dev;
2111         esw->manager_vport = mlx5_eswitch_manager_vport(dev);
2112         esw->first_host_vport = mlx5_eswitch_first_host_vport_num(dev);
2113
2114         esw->work_queue = create_singlethread_workqueue("mlx5_esw_wq");
2115         if (!esw->work_queue) {
2116                 err = -ENOMEM;
2117                 goto abort;
2118         }
2119
2120         esw->vports = kcalloc(total_vports, sizeof(struct mlx5_vport),
2121                               GFP_KERNEL);
2122         if (!esw->vports) {
2123                 err = -ENOMEM;
2124                 goto abort;
2125         }
2126
2127         esw->total_vports = total_vports;
2128
2129         err = esw_offloads_init_reps(esw);
2130         if (err)
2131                 goto abort;
2132
2133         mutex_init(&esw->offloads.encap_tbl_lock);
2134         hash_init(esw->offloads.encap_tbl);
2135         mutex_init(&esw->offloads.mod_hdr.lock);
2136         hash_init(esw->offloads.mod_hdr.hlist);
2137         atomic64_set(&esw->offloads.num_flows, 0);
2138         mutex_init(&esw->state_lock);
2139
2140         mlx5_esw_for_all_vports(esw, i, vport) {
2141                 vport->vport = mlx5_eswitch_index_to_vport_num(esw, i);
2142                 vport->info.link_state = MLX5_VPORT_ADMIN_STATE_AUTO;
2143                 vport->dev = dev;
2144                 INIT_WORK(&vport->vport_change_handler,
2145                           esw_vport_change_handler);
2146         }
2147
2148         esw->enabled_vports = 0;
2149         esw->mode = MLX5_ESWITCH_NONE;
2150         esw->offloads.inline_mode = MLX5_INLINE_MODE_NONE;
2151
2152         dev->priv.eswitch = esw;
2153         return 0;
2154 abort:
2155         if (esw->work_queue)
2156                 destroy_workqueue(esw->work_queue);
2157         esw_offloads_cleanup_reps(esw);
2158         kfree(esw->vports);
2159         kfree(esw);
2160         return err;
2161 }
2162
2163 void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw)
2164 {
2165         if (!esw || !MLX5_VPORT_MANAGER(esw->dev))
2166                 return;
2167
2168         esw_info(esw->dev, "cleanup\n");
2169
2170         esw->dev->priv.eswitch = NULL;
2171         destroy_workqueue(esw->work_queue);
2172         esw_offloads_cleanup_reps(esw);
2173         mutex_destroy(&esw->offloads.mod_hdr.lock);
2174         mutex_destroy(&esw->offloads.encap_tbl_lock);
2175         kfree(esw->vports);
2176         kfree(esw);
2177 }
2178
2179 /* Vport Administration */
2180 int mlx5_eswitch_set_vport_mac(struct mlx5_eswitch *esw,
2181                                u16 vport, u8 mac[ETH_ALEN])
2182 {
2183         struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport);
2184         u64 node_guid;
2185         int err = 0;
2186
2187         if (IS_ERR(evport))
2188                 return PTR_ERR(evport);
2189         if (is_multicast_ether_addr(mac))
2190                 return -EINVAL;
2191
2192         mutex_lock(&esw->state_lock);
2193
2194         if (evport->info.spoofchk && !is_valid_ether_addr(mac))
2195                 mlx5_core_warn(esw->dev,
2196                                "Set invalid MAC while spoofchk is on, vport(%d)\n",
2197                                vport);
2198
2199         err = mlx5_modify_nic_vport_mac_address(esw->dev, vport, mac);
2200         if (err) {
2201                 mlx5_core_warn(esw->dev,
2202                                "Failed to mlx5_modify_nic_vport_mac vport(%d) err=(%d)\n",
2203                                vport, err);
2204                 goto unlock;
2205         }
2206
2207         node_guid_gen_from_mac(&node_guid, mac);
2208         err = mlx5_modify_nic_vport_node_guid(esw->dev, vport, node_guid);
2209         if (err)
2210                 mlx5_core_warn(esw->dev,
2211                                "Failed to set vport %d node guid, err = %d. RDMA_CM will not function properly for this VF.\n",
2212                                vport, err);
2213
2214         ether_addr_copy(evport->info.mac, mac);
2215         evport->info.node_guid = node_guid;
2216         if (evport->enabled && esw->mode == MLX5_ESWITCH_LEGACY)
2217                 err = esw_vport_ingress_config(esw, evport);
2218
2219 unlock:
2220         mutex_unlock(&esw->state_lock);
2221         return err;
2222 }
2223
2224 int mlx5_eswitch_set_vport_state(struct mlx5_eswitch *esw,
2225                                  u16 vport, int link_state)
2226 {
2227         struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport);
2228         int err = 0;
2229
2230         if (!ESW_ALLOWED(esw))
2231                 return -EPERM;
2232         if (IS_ERR(evport))
2233                 return PTR_ERR(evport);
2234
2235         mutex_lock(&esw->state_lock);
2236
2237         err = mlx5_modify_vport_admin_state(esw->dev,
2238                                             MLX5_VPORT_STATE_OP_MOD_ESW_VPORT,
2239                                             vport, 1, link_state);
2240         if (err) {
2241                 mlx5_core_warn(esw->dev,
2242                                "Failed to set vport %d link state, err = %d",
2243                                vport, err);
2244                 goto unlock;
2245         }
2246
2247         evport->info.link_state = link_state;
2248
2249 unlock:
2250         mutex_unlock(&esw->state_lock);
2251         return err;
2252 }
2253
2254 int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,
2255                                   u16 vport, struct ifla_vf_info *ivi)
2256 {
2257         struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport);
2258
2259         if (IS_ERR(evport))
2260                 return PTR_ERR(evport);
2261
2262         memset(ivi, 0, sizeof(*ivi));
2263         ivi->vf = vport - 1;
2264
2265         mutex_lock(&esw->state_lock);
2266         ether_addr_copy(ivi->mac, evport->info.mac);
2267         ivi->linkstate = evport->info.link_state;
2268         ivi->vlan = evport->info.vlan;
2269         ivi->qos = evport->info.qos;
2270         ivi->spoofchk = evport->info.spoofchk;
2271         ivi->trusted = evport->info.trusted;
2272         ivi->min_tx_rate = evport->info.min_rate;
2273         ivi->max_tx_rate = evport->info.max_rate;
2274         mutex_unlock(&esw->state_lock);
2275
2276         return 0;
2277 }
2278
2279 int __mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw,
2280                                   u16 vport, u16 vlan, u8 qos, u8 set_flags)
2281 {
2282         struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport);
2283         int err = 0;
2284
2285         if (!ESW_ALLOWED(esw))
2286                 return -EPERM;
2287         if (IS_ERR(evport))
2288                 return PTR_ERR(evport);
2289         if (vlan > 4095 || qos > 7)
2290                 return -EINVAL;
2291
2292         err = modify_esw_vport_cvlan(esw->dev, vport, vlan, qos, set_flags);
2293         if (err)
2294                 return err;
2295
2296         evport->info.vlan = vlan;
2297         evport->info.qos = qos;
2298         if (evport->enabled && esw->mode == MLX5_ESWITCH_LEGACY) {
2299                 err = esw_vport_ingress_config(esw, evport);
2300                 if (err)
2301                         return err;
2302                 err = esw_vport_egress_config(esw, evport);
2303         }
2304
2305         return err;
2306 }
2307
2308 int mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw,
2309                                 u16 vport, u16 vlan, u8 qos)
2310 {
2311         u8 set_flags = 0;
2312         int err;
2313
2314         if (vlan || qos)
2315                 set_flags = SET_VLAN_STRIP | SET_VLAN_INSERT;
2316
2317         mutex_lock(&esw->state_lock);
2318         err = __mlx5_eswitch_set_vport_vlan(esw, vport, vlan, qos, set_flags);
2319         mutex_unlock(&esw->state_lock);
2320
2321         return err;
2322 }
2323
2324 int mlx5_eswitch_set_vport_spoofchk(struct mlx5_eswitch *esw,
2325                                     u16 vport, bool spoofchk)
2326 {
2327         struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport);
2328         bool pschk;
2329         int err = 0;
2330
2331         if (!ESW_ALLOWED(esw))
2332                 return -EPERM;
2333         if (IS_ERR(evport))
2334                 return PTR_ERR(evport);
2335
2336         mutex_lock(&esw->state_lock);
2337         pschk = evport->info.spoofchk;
2338         evport->info.spoofchk = spoofchk;
2339         if (pschk && !is_valid_ether_addr(evport->info.mac))
2340                 mlx5_core_warn(esw->dev,
2341                                "Spoofchk in set while MAC is invalid, vport(%d)\n",
2342                                evport->vport);
2343         if (evport->enabled && esw->mode == MLX5_ESWITCH_LEGACY)
2344                 err = esw_vport_ingress_config(esw, evport);
2345         if (err)
2346                 evport->info.spoofchk = pschk;
2347         mutex_unlock(&esw->state_lock);
2348
2349         return err;
2350 }
2351
2352 static void esw_cleanup_vepa_rules(struct mlx5_eswitch *esw)
2353 {
2354         if (esw->fdb_table.legacy.vepa_uplink_rule)
2355                 mlx5_del_flow_rules(esw->fdb_table.legacy.vepa_uplink_rule);
2356
2357         if (esw->fdb_table.legacy.vepa_star_rule)
2358                 mlx5_del_flow_rules(esw->fdb_table.legacy.vepa_star_rule);
2359
2360         esw->fdb_table.legacy.vepa_uplink_rule = NULL;
2361         esw->fdb_table.legacy.vepa_star_rule = NULL;
2362 }
2363
2364 static int _mlx5_eswitch_set_vepa_locked(struct mlx5_eswitch *esw,
2365                                          u8 setting)
2366 {
2367         struct mlx5_flow_destination dest = {};
2368         struct mlx5_flow_act flow_act = {};
2369         struct mlx5_flow_handle *flow_rule;
2370         struct mlx5_flow_spec *spec;
2371         int err = 0;
2372         void *misc;
2373
2374         if (!setting) {
2375                 esw_cleanup_vepa_rules(esw);
2376                 return 0;
2377         }
2378
2379         if (esw->fdb_table.legacy.vepa_uplink_rule)
2380                 return 0;
2381
2382         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
2383         if (!spec)
2384                 return -ENOMEM;
2385
2386         /* Uplink rule forward uplink traffic to FDB */
2387         misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
2388         MLX5_SET(fte_match_set_misc, misc, source_port, MLX5_VPORT_UPLINK);
2389
2390         misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
2391         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
2392
2393         spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
2394         dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
2395         dest.ft = esw->fdb_table.legacy.fdb;
2396         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
2397         flow_rule = mlx5_add_flow_rules(esw->fdb_table.legacy.vepa_fdb, spec,
2398                                         &flow_act, &dest, 1);
2399         if (IS_ERR(flow_rule)) {
2400                 err = PTR_ERR(flow_rule);
2401                 goto out;
2402         } else {
2403                 esw->fdb_table.legacy.vepa_uplink_rule = flow_rule;
2404         }
2405
2406         /* Star rule to forward all traffic to uplink vport */
2407         memset(spec, 0, sizeof(*spec));
2408         memset(&dest, 0, sizeof(dest));
2409         dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
2410         dest.vport.num = MLX5_VPORT_UPLINK;
2411         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
2412         flow_rule = mlx5_add_flow_rules(esw->fdb_table.legacy.vepa_fdb, spec,
2413                                         &flow_act, &dest, 1);
2414         if (IS_ERR(flow_rule)) {
2415                 err = PTR_ERR(flow_rule);
2416                 goto out;
2417         } else {
2418                 esw->fdb_table.legacy.vepa_star_rule = flow_rule;
2419         }
2420
2421 out:
2422         kvfree(spec);
2423         if (err)
2424                 esw_cleanup_vepa_rules(esw);
2425         return err;
2426 }
2427
2428 int mlx5_eswitch_set_vepa(struct mlx5_eswitch *esw, u8 setting)
2429 {
2430         int err = 0;
2431
2432         if (!esw)
2433                 return -EOPNOTSUPP;
2434
2435         if (!ESW_ALLOWED(esw))
2436                 return -EPERM;
2437
2438         mutex_lock(&esw->state_lock);
2439         if (esw->mode != MLX5_ESWITCH_LEGACY) {
2440                 err = -EOPNOTSUPP;
2441                 goto out;
2442         }
2443
2444         err = _mlx5_eswitch_set_vepa_locked(esw, setting);
2445
2446 out:
2447         mutex_unlock(&esw->state_lock);
2448         return err;
2449 }
2450
2451 int mlx5_eswitch_get_vepa(struct mlx5_eswitch *esw, u8 *setting)
2452 {
2453         int err = 0;
2454
2455         if (!esw)
2456                 return -EOPNOTSUPP;
2457
2458         if (!ESW_ALLOWED(esw))
2459                 return -EPERM;
2460
2461         mutex_lock(&esw->state_lock);
2462         if (esw->mode != MLX5_ESWITCH_LEGACY) {
2463                 err = -EOPNOTSUPP;
2464                 goto out;
2465         }
2466
2467         *setting = esw->fdb_table.legacy.vepa_uplink_rule ? 1 : 0;
2468
2469 out:
2470         mutex_unlock(&esw->state_lock);
2471         return err;
2472 }
2473
2474 int mlx5_eswitch_set_vport_trust(struct mlx5_eswitch *esw,
2475                                  u16 vport, bool setting)
2476 {
2477         struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport);
2478
2479         if (!ESW_ALLOWED(esw))
2480                 return -EPERM;
2481         if (IS_ERR(evport))
2482                 return PTR_ERR(evport);
2483
2484         mutex_lock(&esw->state_lock);
2485         evport->info.trusted = setting;
2486         if (evport->enabled)
2487                 esw_vport_change_handle_locked(evport);
2488         mutex_unlock(&esw->state_lock);
2489
2490         return 0;
2491 }
2492
2493 static u32 calculate_vports_min_rate_divider(struct mlx5_eswitch *esw)
2494 {
2495         u32 fw_max_bw_share = MLX5_CAP_QOS(esw->dev, max_tsar_bw_share);
2496         struct mlx5_vport *evport;
2497         u32 max_guarantee = 0;
2498         int i;
2499
2500         mlx5_esw_for_all_vports(esw, i, evport) {
2501                 if (!evport->enabled || evport->info.min_rate < max_guarantee)
2502                         continue;
2503                 max_guarantee = evport->info.min_rate;
2504         }
2505
2506         return max_t(u32, max_guarantee / fw_max_bw_share, 1);
2507 }
2508
2509 static int normalize_vports_min_rate(struct mlx5_eswitch *esw, u32 divider)
2510 {
2511         u32 fw_max_bw_share = MLX5_CAP_QOS(esw->dev, max_tsar_bw_share);
2512         struct mlx5_vport *evport;
2513         u32 vport_max_rate;
2514         u32 vport_min_rate;
2515         u32 bw_share;
2516         int err;
2517         int i;
2518
2519         mlx5_esw_for_all_vports(esw, i, evport) {
2520                 if (!evport->enabled)
2521                         continue;
2522                 vport_min_rate = evport->info.min_rate;
2523                 vport_max_rate = evport->info.max_rate;
2524                 bw_share = MLX5_MIN_BW_SHARE;
2525
2526                 if (vport_min_rate)
2527                         bw_share = MLX5_RATE_TO_BW_SHARE(vport_min_rate,
2528                                                          divider,
2529                                                          fw_max_bw_share);
2530
2531                 if (bw_share == evport->qos.bw_share)
2532                         continue;
2533
2534                 err = esw_vport_qos_config(esw, evport, vport_max_rate,
2535                                            bw_share);
2536                 if (!err)
2537                         evport->qos.bw_share = bw_share;
2538                 else
2539                         return err;
2540         }
2541
2542         return 0;
2543 }
2544
2545 int mlx5_eswitch_set_vport_rate(struct mlx5_eswitch *esw, u16 vport,
2546                                 u32 max_rate, u32 min_rate)
2547 {
2548         struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport);
2549         u32 fw_max_bw_share;
2550         u32 previous_min_rate;
2551         u32 divider;
2552         bool min_rate_supported;
2553         bool max_rate_supported;
2554         int err = 0;
2555
2556         if (!ESW_ALLOWED(esw))
2557                 return -EPERM;
2558         if (IS_ERR(evport))
2559                 return PTR_ERR(evport);
2560
2561         fw_max_bw_share = MLX5_CAP_QOS(esw->dev, max_tsar_bw_share);
2562         min_rate_supported = MLX5_CAP_QOS(esw->dev, esw_bw_share) &&
2563                                 fw_max_bw_share >= MLX5_MIN_BW_SHARE;
2564         max_rate_supported = MLX5_CAP_QOS(esw->dev, esw_rate_limit);
2565
2566         if ((min_rate && !min_rate_supported) || (max_rate && !max_rate_supported))
2567                 return -EOPNOTSUPP;
2568
2569         mutex_lock(&esw->state_lock);
2570
2571         if (min_rate == evport->info.min_rate)
2572                 goto set_max_rate;
2573
2574         previous_min_rate = evport->info.min_rate;
2575         evport->info.min_rate = min_rate;
2576         divider = calculate_vports_min_rate_divider(esw);
2577         err = normalize_vports_min_rate(esw, divider);
2578         if (err) {
2579                 evport->info.min_rate = previous_min_rate;
2580                 goto unlock;
2581         }
2582
2583 set_max_rate:
2584         if (max_rate == evport->info.max_rate)
2585                 goto unlock;
2586
2587         err = esw_vport_qos_config(esw, evport, max_rate, evport->qos.bw_share);
2588         if (!err)
2589                 evport->info.max_rate = max_rate;
2590
2591 unlock:
2592         mutex_unlock(&esw->state_lock);
2593         return err;
2594 }
2595
2596 static int mlx5_eswitch_query_vport_drop_stats(struct mlx5_core_dev *dev,
2597                                                struct mlx5_vport *vport,
2598                                                struct mlx5_vport_drop_stats *stats)
2599 {
2600         struct mlx5_eswitch *esw = dev->priv.eswitch;
2601         u64 rx_discard_vport_down, tx_discard_vport_down;
2602         u64 bytes = 0;
2603         int err = 0;
2604
2605         if (!vport->enabled || esw->mode != MLX5_ESWITCH_LEGACY)
2606                 return 0;
2607
2608         if (vport->egress.legacy.drop_counter)
2609                 mlx5_fc_query(dev, vport->egress.legacy.drop_counter,
2610                               &stats->rx_dropped, &bytes);
2611
2612         if (vport->ingress.legacy.drop_counter)
2613                 mlx5_fc_query(dev, vport->ingress.legacy.drop_counter,
2614                               &stats->tx_dropped, &bytes);
2615
2616         if (!MLX5_CAP_GEN(dev, receive_discard_vport_down) &&
2617             !MLX5_CAP_GEN(dev, transmit_discard_vport_down))
2618                 return 0;
2619
2620         err = mlx5_query_vport_down_stats(dev, vport->vport, 1,
2621                                           &rx_discard_vport_down,
2622                                           &tx_discard_vport_down);
2623         if (err)
2624                 return err;
2625
2626         if (MLX5_CAP_GEN(dev, receive_discard_vport_down))
2627                 stats->rx_dropped += rx_discard_vport_down;
2628         if (MLX5_CAP_GEN(dev, transmit_discard_vport_down))
2629                 stats->tx_dropped += tx_discard_vport_down;
2630
2631         return 0;
2632 }
2633
2634 int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw,
2635                                  u16 vport_num,
2636                                  struct ifla_vf_stats *vf_stats)
2637 {
2638         struct mlx5_vport *vport = mlx5_eswitch_get_vport(esw, vport_num);
2639         int outlen = MLX5_ST_SZ_BYTES(query_vport_counter_out);
2640         u32 in[MLX5_ST_SZ_DW(query_vport_counter_in)] = {0};
2641         struct mlx5_vport_drop_stats stats = {0};
2642         int err = 0;
2643         u32 *out;
2644
2645         if (IS_ERR(vport))
2646                 return PTR_ERR(vport);
2647
2648         out = kvzalloc(outlen, GFP_KERNEL);
2649         if (!out)
2650                 return -ENOMEM;
2651
2652         MLX5_SET(query_vport_counter_in, in, opcode,
2653                  MLX5_CMD_OP_QUERY_VPORT_COUNTER);
2654         MLX5_SET(query_vport_counter_in, in, op_mod, 0);
2655         MLX5_SET(query_vport_counter_in, in, vport_number, vport->vport);
2656         MLX5_SET(query_vport_counter_in, in, other_vport, 1);
2657
2658         err = mlx5_cmd_exec(esw->dev, in, sizeof(in), out, outlen);
2659         if (err)
2660                 goto free_out;
2661
2662         #define MLX5_GET_CTR(p, x) \
2663                 MLX5_GET64(query_vport_counter_out, p, x)
2664
2665         memset(vf_stats, 0, sizeof(*vf_stats));
2666         vf_stats->rx_packets =
2667                 MLX5_GET_CTR(out, received_eth_unicast.packets) +
2668                 MLX5_GET_CTR(out, received_ib_unicast.packets) +
2669                 MLX5_GET_CTR(out, received_eth_multicast.packets) +
2670                 MLX5_GET_CTR(out, received_ib_multicast.packets) +
2671                 MLX5_GET_CTR(out, received_eth_broadcast.packets);
2672
2673         vf_stats->rx_bytes =
2674                 MLX5_GET_CTR(out, received_eth_unicast.octets) +
2675                 MLX5_GET_CTR(out, received_ib_unicast.octets) +
2676                 MLX5_GET_CTR(out, received_eth_multicast.octets) +
2677                 MLX5_GET_CTR(out, received_ib_multicast.octets) +
2678                 MLX5_GET_CTR(out, received_eth_broadcast.octets);
2679
2680         vf_stats->tx_packets =
2681                 MLX5_GET_CTR(out, transmitted_eth_unicast.packets) +
2682                 MLX5_GET_CTR(out, transmitted_ib_unicast.packets) +
2683                 MLX5_GET_CTR(out, transmitted_eth_multicast.packets) +
2684                 MLX5_GET_CTR(out, transmitted_ib_multicast.packets) +
2685                 MLX5_GET_CTR(out, transmitted_eth_broadcast.packets);
2686
2687         vf_stats->tx_bytes =
2688                 MLX5_GET_CTR(out, transmitted_eth_unicast.octets) +
2689                 MLX5_GET_CTR(out, transmitted_ib_unicast.octets) +
2690                 MLX5_GET_CTR(out, transmitted_eth_multicast.octets) +
2691                 MLX5_GET_CTR(out, transmitted_ib_multicast.octets) +
2692                 MLX5_GET_CTR(out, transmitted_eth_broadcast.octets);
2693
2694         vf_stats->multicast =
2695                 MLX5_GET_CTR(out, received_eth_multicast.packets) +
2696                 MLX5_GET_CTR(out, received_ib_multicast.packets);
2697
2698         vf_stats->broadcast =
2699                 MLX5_GET_CTR(out, received_eth_broadcast.packets);
2700
2701         err = mlx5_eswitch_query_vport_drop_stats(esw->dev, vport, &stats);
2702         if (err)
2703                 goto free_out;
2704         vf_stats->rx_dropped = stats.rx_dropped;
2705         vf_stats->tx_dropped = stats.tx_dropped;
2706
2707 free_out:
2708         kvfree(out);
2709         return err;
2710 }
2711
2712 u8 mlx5_eswitch_mode(struct mlx5_eswitch *esw)
2713 {
2714         return ESW_ALLOWED(esw) ? esw->mode : MLX5_ESWITCH_NONE;
2715 }
2716 EXPORT_SYMBOL_GPL(mlx5_eswitch_mode);
2717
2718 enum devlink_eswitch_encap_mode
2719 mlx5_eswitch_get_encap_mode(const struct mlx5_core_dev *dev)
2720 {
2721         struct mlx5_eswitch *esw;
2722
2723         esw = dev->priv.eswitch;
2724         return ESW_ALLOWED(esw) ? esw->offloads.encap :
2725                 DEVLINK_ESWITCH_ENCAP_MODE_NONE;
2726 }
2727 EXPORT_SYMBOL(mlx5_eswitch_get_encap_mode);
2728
2729 bool mlx5_esw_lag_prereq(struct mlx5_core_dev *dev0, struct mlx5_core_dev *dev1)
2730 {
2731         if ((dev0->priv.eswitch->mode == MLX5_ESWITCH_NONE &&
2732              dev1->priv.eswitch->mode == MLX5_ESWITCH_NONE) ||
2733             (dev0->priv.eswitch->mode == MLX5_ESWITCH_OFFLOADS &&
2734              dev1->priv.eswitch->mode == MLX5_ESWITCH_OFFLOADS))
2735                 return true;
2736
2737         return false;
2738 }
2739
2740 bool mlx5_esw_multipath_prereq(struct mlx5_core_dev *dev0,
2741                                struct mlx5_core_dev *dev1)
2742 {
2743         return (dev0->priv.eswitch->mode == MLX5_ESWITCH_OFFLOADS &&
2744                 dev1->priv.eswitch->mode == MLX5_ESWITCH_OFFLOADS);
2745 }
2746
2747 void mlx5_eswitch_update_num_of_vfs(struct mlx5_eswitch *esw, const int num_vfs)
2748 {
2749         const u32 *out;
2750
2751         WARN_ON_ONCE(esw->mode != MLX5_ESWITCH_NONE);
2752
2753         if (!mlx5_core_is_ecpf_esw_manager(esw->dev)) {
2754                 esw->esw_funcs.num_vfs = num_vfs;
2755                 return;
2756         }
2757
2758         out = mlx5_esw_query_functions(esw->dev);
2759         if (IS_ERR(out))
2760                 return;
2761
2762         esw->esw_funcs.num_vfs = MLX5_GET(query_esw_functions_out, out,
2763                                           host_params_context.host_num_of_vfs);
2764         kvfree(out);
2765 }