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