linux/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2016, Mellanox Technologies. All rights reserved.
   3 *
   4 * This software is available to you under a choice of one of two
   5 * licenses.  You may choose to be licensed under the terms of the GNU
   6 * General Public License (GPL) Version 2, available from the file
   7 * COPYING in the main directory of this source tree, or the
   8 * OpenIB.org BSD license below:
   9 *
  10 *     Redistribution and use in source and binary forms, with or
  11 *     without modification, are permitted provided that the following
  12 *     conditions are met:
  13 *
  14 *      - Redistributions of source code must retain the above
  15 *        copyright notice, this list of conditions and the following
  16 *        disclaimer.
  17 *
  18 *      - Redistributions in binary form must reproduce the above
  19 *        copyright notice, this list of conditions and the following
  20 *        disclaimer in the documentation and/or other materials
  21 *        provided with the distribution.
  22 *
  23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  30 * SOFTWARE.
  31 */
  32
  33#include <linux/etherdevice.h>
  34#include <linux/idr.h>
  35#include <linux/mlx5/driver.h>
  36#include <linux/mlx5/mlx5_ifc.h>
  37#include <linux/mlx5/vport.h>
  38#include <linux/mlx5/fs.h>
  39#include "mlx5_core.h"
  40#include "eswitch.h"
  41#include "esw/indir_table.h"
  42#include "esw/acl/ofld.h"
  43#include "rdma.h"
  44#include "en.h"
  45#include "fs_core.h"
  46#include "lib/devcom.h"
  47#include "lib/eq.h"
  48#include "lib/fs_chains.h"
  49#include "en_tc.h"
  50#include "en/mapping.h"
  51#include "devlink.h"
  52
  53#define mlx5_esw_for_each_rep(esw, i, rep) \
  54        xa_for_each(&((esw)->offloads.vport_reps), i, rep)
  55
  56#define mlx5_esw_for_each_sf_rep(esw, i, rep) \
  57        xa_for_each_marked(&((esw)->offloads.vport_reps), i, rep, MLX5_ESW_VPT_SF)
  58
  59#define mlx5_esw_for_each_vf_rep(esw, index, rep)       \
  60        mlx5_esw_for_each_entry_marked(&((esw)->offloads.vport_reps), index, \
  61                                       rep, (esw)->esw_funcs.num_vfs, MLX5_ESW_VPT_VF)
  62
  63/* There are two match-all miss flows, one for unicast dst mac and
  64 * one for multicast.
  65 */
  66#define MLX5_ESW_MISS_FLOWS (2)
  67#define UPLINK_REP_INDEX 0
  68
  69#define MLX5_ESW_VPORT_TBL_SIZE 128
  70#define MLX5_ESW_VPORT_TBL_NUM_GROUPS  4
  71
  72static const struct esw_vport_tbl_namespace mlx5_esw_vport_tbl_mirror_ns = {
  73        .max_fte = MLX5_ESW_VPORT_TBL_SIZE,
  74        .max_num_groups = MLX5_ESW_VPORT_TBL_NUM_GROUPS,
  75        .flags = 0,
  76};
  77
  78static struct mlx5_eswitch_rep *mlx5_eswitch_get_rep(struct mlx5_eswitch *esw,
  79                                                     u16 vport_num)
  80{
  81        return xa_load(&esw->offloads.vport_reps, vport_num);
  82}
  83
  84static void
  85mlx5_eswitch_set_rule_flow_source(struct mlx5_eswitch *esw,
  86                                  struct mlx5_flow_spec *spec,
  87                                  struct mlx5_esw_flow_attr *attr)
  88{
  89        if (MLX5_CAP_ESW_FLOWTABLE(esw->dev, flow_source) &&
  90            attr && attr->in_rep)
  91                spec->flow_context.flow_source =
  92                        attr->in_rep->vport == MLX5_VPORT_UPLINK ?
  93                                MLX5_FLOW_CONTEXT_FLOW_SOURCE_UPLINK :
  94                                MLX5_FLOW_CONTEXT_FLOW_SOURCE_LOCAL_VPORT;
  95}
  96
  97/* Actually only the upper 16 bits of reg c0 need to be cleared, but the lower 16 bits
  98 * are not needed as well in the following process. So clear them all for simplicity.
  99 */
 100void
 101mlx5_eswitch_clear_rule_source_port(struct mlx5_eswitch *esw, struct mlx5_flow_spec *spec)
 102{
 103        if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
 104                void *misc2;
 105
 106                misc2 = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters_2);
 107                MLX5_SET(fte_match_set_misc2, misc2, metadata_reg_c_0, 0);
 108
 109                misc2 = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters_2);
 110                MLX5_SET(fte_match_set_misc2, misc2, metadata_reg_c_0, 0);
 111
 112                if (!memchr_inv(misc2, 0, MLX5_ST_SZ_BYTES(fte_match_set_misc2)))
 113                        spec->match_criteria_enable &= ~MLX5_MATCH_MISC_PARAMETERS_2;
 114        }
 115}
 116
 117static void
 118mlx5_eswitch_set_rule_source_port(struct mlx5_eswitch *esw,
 119                                  struct mlx5_flow_spec *spec,
 120                                  struct mlx5_flow_attr *attr,
 121                                  struct mlx5_eswitch *src_esw,
 122                                  u16 vport)
 123{
 124        void *misc2;
 125        void *misc;
 126
 127        /* Use metadata matching because vport is not represented by single
 128         * VHCA in dual-port RoCE mode, and matching on source vport may fail.
 129         */
 130        if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
 131                if (mlx5_esw_indir_table_decap_vport(attr))
 132                        vport = mlx5_esw_indir_table_decap_vport(attr);
 133                misc2 = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters_2);
 134                MLX5_SET(fte_match_set_misc2, misc2, metadata_reg_c_0,
 135                         mlx5_eswitch_get_vport_metadata_for_match(src_esw,
 136                                                                   vport));
 137
 138                misc2 = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters_2);
 139                MLX5_SET(fte_match_set_misc2, misc2, metadata_reg_c_0,
 140                         mlx5_eswitch_get_vport_metadata_mask());
 141
 142                spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;
 143        } else {
 144                misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
 145                MLX5_SET(fte_match_set_misc, misc, source_port, vport);
 146
 147                if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
 148                        MLX5_SET(fte_match_set_misc, misc,
 149                                 source_eswitch_owner_vhca_id,
 150                                 MLX5_CAP_GEN(src_esw->dev, vhca_id));
 151
 152                misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
 153                MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
 154                if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
 155                        MLX5_SET_TO_ONES(fte_match_set_misc, misc,
 156                                         source_eswitch_owner_vhca_id);
 157
 158                spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS;
 159        }
 160}
 161
 162static int
 163esw_setup_decap_indir(struct mlx5_eswitch *esw,
 164                      struct mlx5_flow_attr *attr,
 165                      struct mlx5_flow_spec *spec)
 166{
 167        struct mlx5_flow_table *ft;
 168
 169        if (!(attr->flags & MLX5_ESW_ATTR_FLAG_SRC_REWRITE))
 170                return -EOPNOTSUPP;
 171
 172        ft = mlx5_esw_indir_table_get(esw, attr, spec,
 173                                      mlx5_esw_indir_table_decap_vport(attr), true);
 174        return PTR_ERR_OR_ZERO(ft);
 175}
 176
 177static void
 178esw_cleanup_decap_indir(struct mlx5_eswitch *esw,
 179                        struct mlx5_flow_attr *attr)
 180{
 181        if (mlx5_esw_indir_table_decap_vport(attr))
 182                mlx5_esw_indir_table_put(esw, attr,
 183                                         mlx5_esw_indir_table_decap_vport(attr),
 184                                         true);
 185}
 186
 187static int
 188esw_setup_sampler_dest(struct mlx5_flow_destination *dest,
 189                       struct mlx5_flow_act *flow_act,
 190                       struct mlx5_esw_flow_attr *esw_attr,
 191                       int i)
 192{
 193        flow_act->flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
 194        dest[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_SAMPLER;
 195        dest[i].sampler_id = esw_attr->sample->sampler_id;
 196
 197        return 0;
 198}
 199
 200static int
 201esw_setup_ft_dest(struct mlx5_flow_destination *dest,
 202                  struct mlx5_flow_act *flow_act,
 203                  struct mlx5_eswitch *esw,
 204                  struct mlx5_flow_attr *attr,
 205                  struct mlx5_flow_spec *spec,
 206                  int i)
 207{
 208        flow_act->flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
 209        dest[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
 210        dest[i].ft = attr->dest_ft;
 211
 212        if (mlx5_esw_indir_table_decap_vport(attr))
 213                return esw_setup_decap_indir(esw, attr, spec);
 214        return 0;
 215}
 216
 217static void
 218esw_setup_slow_path_dest(struct mlx5_flow_destination *dest,
 219                         struct mlx5_flow_act *flow_act,
 220                         struct mlx5_fs_chains *chains,
 221                         int i)
 222{
 223        if (mlx5_chains_ignore_flow_level_supported(chains))
 224                flow_act->flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
 225        dest[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
 226        dest[i].ft = mlx5_chains_get_tc_end_ft(chains);
 227}
 228
 229static int
 230esw_setup_chain_dest(struct mlx5_flow_destination *dest,
 231                     struct mlx5_flow_act *flow_act,
 232                     struct mlx5_fs_chains *chains,
 233                     u32 chain, u32 prio, u32 level,
 234                     int i)
 235{
 236        struct mlx5_flow_table *ft;
 237
 238        flow_act->flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
 239        ft = mlx5_chains_get_table(chains, chain, prio, level);
 240        if (IS_ERR(ft))
 241                return PTR_ERR(ft);
 242
 243        dest[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
 244        dest[i].ft = ft;
 245        return  0;
 246}
 247
 248static void esw_put_dest_tables_loop(struct mlx5_eswitch *esw, struct mlx5_flow_attr *attr,
 249                                     int from, int to)
 250{
 251        struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
 252        struct mlx5_fs_chains *chains = esw_chains(esw);
 253        int i;
 254
 255        for (i = from; i < to; i++)
 256                if (esw_attr->dests[i].flags & MLX5_ESW_DEST_CHAIN_WITH_SRC_PORT_CHANGE)
 257                        mlx5_chains_put_table(chains, 0, 1, 0);
 258                else if (mlx5_esw_indir_table_needed(esw, attr, esw_attr->dests[i].rep->vport,
 259                                                     esw_attr->dests[i].mdev))
 260                        mlx5_esw_indir_table_put(esw, attr, esw_attr->dests[i].rep->vport,
 261                                                 false);
 262}
 263
 264static bool
 265esw_is_chain_src_port_rewrite(struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *esw_attr)
 266{
 267        int i;
 268
 269        for (i = esw_attr->split_count; i < esw_attr->out_count; i++)
 270                if (esw_attr->dests[i].flags & MLX5_ESW_DEST_CHAIN_WITH_SRC_PORT_CHANGE)
 271                        return true;
 272        return false;
 273}
 274
 275static int
 276esw_setup_chain_src_port_rewrite(struct mlx5_flow_destination *dest,
 277                                 struct mlx5_flow_act *flow_act,
 278                                 struct mlx5_eswitch *esw,
 279                                 struct mlx5_fs_chains *chains,
 280                                 struct mlx5_flow_attr *attr,
 281                                 int *i)
 282{
 283        struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
 284        int j, err;
 285
 286        if (!(attr->flags & MLX5_ESW_ATTR_FLAG_SRC_REWRITE))
 287                return -EOPNOTSUPP;
 288
 289        for (j = esw_attr->split_count; j < esw_attr->out_count; j++, (*i)++) {
 290                err = esw_setup_chain_dest(dest, flow_act, chains, attr->dest_chain, 1, 0, *i);
 291                if (err)
 292                        goto err_setup_chain;
 293                flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
 294                flow_act->pkt_reformat = esw_attr->dests[j].pkt_reformat;
 295        }
 296        return 0;
 297
 298err_setup_chain:
 299        esw_put_dest_tables_loop(esw, attr, esw_attr->split_count, j);
 300        return err;
 301}
 302
 303static void esw_cleanup_chain_src_port_rewrite(struct mlx5_eswitch *esw,
 304                                               struct mlx5_flow_attr *attr)
 305{
 306        struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
 307
 308        esw_put_dest_tables_loop(esw, attr, esw_attr->split_count, esw_attr->out_count);
 309}
 310
 311static bool
 312esw_is_indir_table(struct mlx5_eswitch *esw, struct mlx5_flow_attr *attr)
 313{
 314        struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
 315        int i;
 316
 317        for (i = esw_attr->split_count; i < esw_attr->out_count; i++)
 318                if (mlx5_esw_indir_table_needed(esw, attr, esw_attr->dests[i].rep->vport,
 319                                                esw_attr->dests[i].mdev))
 320                        return true;
 321        return false;
 322}
 323
 324static int
 325esw_setup_indir_table(struct mlx5_flow_destination *dest,
 326                      struct mlx5_flow_act *flow_act,
 327                      struct mlx5_eswitch *esw,
 328                      struct mlx5_flow_attr *attr,
 329                      struct mlx5_flow_spec *spec,
 330                      bool ignore_flow_lvl,
 331                      int *i)
 332{
 333        struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
 334        int j, err;
 335
 336        if (!(attr->flags & MLX5_ESW_ATTR_FLAG_SRC_REWRITE))
 337                return -EOPNOTSUPP;
 338
 339        for (j = esw_attr->split_count; j < esw_attr->out_count; j++, (*i)++) {
 340                if (ignore_flow_lvl)
 341                        flow_act->flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
 342                dest[*i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
 343
 344                dest[*i].ft = mlx5_esw_indir_table_get(esw, attr, spec,
 345                                                       esw_attr->dests[j].rep->vport, false);
 346                if (IS_ERR(dest[*i].ft)) {
 347                        err = PTR_ERR(dest[*i].ft);
 348                        goto err_indir_tbl_get;
 349                }
 350        }
 351
 352        if (mlx5_esw_indir_table_decap_vport(attr)) {
 353                err = esw_setup_decap_indir(esw, attr, spec);
 354                if (err)
 355                        goto err_indir_tbl_get;
 356        }
 357
 358        return 0;
 359
 360err_indir_tbl_get:
 361        esw_put_dest_tables_loop(esw, attr, esw_attr->split_count, j);
 362        return err;
 363}
 364
 365static void esw_cleanup_indir_table(struct mlx5_eswitch *esw, struct mlx5_flow_attr *attr)
 366{
 367        struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
 368
 369        esw_put_dest_tables_loop(esw, attr, esw_attr->split_count, esw_attr->out_count);
 370        esw_cleanup_decap_indir(esw, attr);
 371}
 372
 373static void
 374esw_cleanup_chain_dest(struct mlx5_fs_chains *chains, u32 chain, u32 prio, u32 level)
 375{
 376        mlx5_chains_put_table(chains, chain, prio, level);
 377}
 378
 379static void
 380esw_setup_vport_dest(struct mlx5_flow_destination *dest, struct mlx5_flow_act *flow_act,
 381                     struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *esw_attr,
 382                     int attr_idx, int dest_idx, bool pkt_reformat)
 383{
 384        dest[dest_idx].type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
 385        dest[dest_idx].vport.num = esw_attr->dests[attr_idx].rep->vport;
 386        if (MLX5_CAP_ESW(esw->dev, merged_eswitch)) {
 387                dest[dest_idx].vport.vhca_id =
 388                        MLX5_CAP_GEN(esw_attr->dests[attr_idx].mdev, vhca_id);
 389                dest[dest_idx].vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
 390        }
 391        if (esw_attr->dests[attr_idx].flags & MLX5_ESW_DEST_ENCAP) {
 392                if (pkt_reformat) {
 393                        flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
 394                        flow_act->pkt_reformat = esw_attr->dests[attr_idx].pkt_reformat;
 395                }
 396                dest[dest_idx].vport.flags |= MLX5_FLOW_DEST_VPORT_REFORMAT_ID;
 397                dest[dest_idx].vport.pkt_reformat = esw_attr->dests[attr_idx].pkt_reformat;
 398        }
 399}
 400
 401static int
 402esw_setup_vport_dests(struct mlx5_flow_destination *dest, struct mlx5_flow_act *flow_act,
 403                      struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *esw_attr,
 404                      int i)
 405{
 406        int j;
 407
 408        for (j = esw_attr->split_count; j < esw_attr->out_count; j++, i++)
 409                esw_setup_vport_dest(dest, flow_act, esw, esw_attr, j, i, true);
 410        return i;
 411}
 412
 413static bool
 414esw_src_port_rewrite_supported(struct mlx5_eswitch *esw)
 415{
 416        return MLX5_CAP_GEN(esw->dev, reg_c_preserve) &&
 417               mlx5_eswitch_vport_match_metadata_enabled(esw) &&
 418               MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, ignore_flow_level);
 419}
 420
 421static int
 422esw_setup_dests(struct mlx5_flow_destination *dest,
 423                struct mlx5_flow_act *flow_act,
 424                struct mlx5_eswitch *esw,
 425                struct mlx5_flow_attr *attr,
 426                struct mlx5_flow_spec *spec,
 427                int *i)
 428{
 429        struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
 430        struct mlx5_fs_chains *chains = esw_chains(esw);
 431        int err = 0;
 432
 433        if (!mlx5_eswitch_termtbl_required(esw, attr, flow_act, spec) &&
 434            esw_src_port_rewrite_supported(esw))
 435                attr->flags |= MLX5_ESW_ATTR_FLAG_SRC_REWRITE;
 436
 437        if (attr->flags & MLX5_ESW_ATTR_FLAG_SAMPLE) {
 438                esw_setup_sampler_dest(dest, flow_act, esw_attr, *i);
 439                (*i)++;
 440        } else if (attr->dest_ft) {
 441                esw_setup_ft_dest(dest, flow_act, esw, attr, spec, *i);
 442                (*i)++;
 443        } else if (attr->flags & MLX5_ESW_ATTR_FLAG_SLOW_PATH) {
 444                esw_setup_slow_path_dest(dest, flow_act, chains, *i);
 445                (*i)++;
 446        } else if (attr->dest_chain) {
 447                err = esw_setup_chain_dest(dest, flow_act, chains, attr->dest_chain,
 448                                           1, 0, *i);
 449                (*i)++;
 450        } else if (esw_is_indir_table(esw, attr)) {
 451                err = esw_setup_indir_table(dest, flow_act, esw, attr, spec, true, i);
 452        } else if (esw_is_chain_src_port_rewrite(esw, esw_attr)) {
 453                err = esw_setup_chain_src_port_rewrite(dest, flow_act, esw, chains, attr, i);
 454        } else {
 455                *i = esw_setup_vport_dests(dest, flow_act, esw, esw_attr, *i);
 456        }
 457
 458        return err;
 459}
 460
 461static void
 462esw_cleanup_dests(struct mlx5_eswitch *esw,
 463                  struct mlx5_flow_attr *attr)
 464{
 465        struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
 466        struct mlx5_fs_chains *chains = esw_chains(esw);
 467
 468        if (attr->dest_ft) {
 469                esw_cleanup_decap_indir(esw, attr);
 470        } else if (!(attr->flags & MLX5_ESW_ATTR_FLAG_SLOW_PATH)) {
 471                if (attr->dest_chain)
 472                        esw_cleanup_chain_dest(chains, attr->dest_chain, 1, 0);
 473                else if (esw_is_indir_table(esw, attr))
 474                        esw_cleanup_indir_table(esw, attr);
 475                else if (esw_is_chain_src_port_rewrite(esw, esw_attr))
 476                        esw_cleanup_chain_src_port_rewrite(esw, attr);
 477        }
 478}
 479
 480struct mlx5_flow_handle *
 481mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
 482                                struct mlx5_flow_spec *spec,
 483                                struct mlx5_flow_attr *attr)
 484{
 485        struct mlx5_flow_destination dest[MLX5_MAX_FLOW_FWD_VPORTS + 1] = {};
 486        struct mlx5_flow_act flow_act = { .flags = FLOW_ACT_NO_APPEND, };
 487        struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
 488        struct mlx5_fs_chains *chains = esw_chains(esw);
 489        bool split = !!(esw_attr->split_count);
 490        struct mlx5_vport_tbl_attr fwd_attr;
 491        struct mlx5_flow_handle *rule;
 492        struct mlx5_flow_table *fdb;
 493        int i = 0;
 494
 495        if (esw->mode != MLX5_ESWITCH_OFFLOADS)
 496                return ERR_PTR(-EOPNOTSUPP);
 497
 498        flow_act.action = attr->action;
 499        /* if per flow vlan pop/push is emulated, don't set that into the firmware */
 500        if (!mlx5_eswitch_vlan_actions_supported(esw->dev, 1))
 501                flow_act.action &= ~(MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH |
 502                                     MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
 503        else if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH) {
 504                flow_act.vlan[0].ethtype = ntohs(esw_attr->vlan_proto[0]);
 505                flow_act.vlan[0].vid = esw_attr->vlan_vid[0];
 506                flow_act.vlan[0].prio = esw_attr->vlan_prio[0];
 507                if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2) {
 508                        flow_act.vlan[1].ethtype = ntohs(esw_attr->vlan_proto[1]);
 509                        flow_act.vlan[1].vid = esw_attr->vlan_vid[1];
 510                        flow_act.vlan[1].prio = esw_attr->vlan_prio[1];
 511                }
 512        }
 513
 514        mlx5_eswitch_set_rule_flow_source(esw, spec, esw_attr);
 515
 516        if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
 517                int err;
 518
 519                err = esw_setup_dests(dest, &flow_act, esw, attr, spec, &i);
 520                if (err) {
 521                        rule = ERR_PTR(err);
 522                        goto err_create_goto_table;
 523                }
 524        }
 525
 526        if (esw_attr->decap_pkt_reformat)
 527                flow_act.pkt_reformat = esw_attr->decap_pkt_reformat;
 528
 529        if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
 530                dest[i].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
 531                dest[i].counter_id = mlx5_fc_id(attr->counter);
 532                i++;
 533        }
 534
 535        if (attr->outer_match_level != MLX5_MATCH_NONE)
 536                spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
 537        if (attr->inner_match_level != MLX5_MATCH_NONE)
 538                spec->match_criteria_enable |= MLX5_MATCH_INNER_HEADERS;
 539
 540        if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
 541                flow_act.modify_hdr = attr->modify_hdr;
 542
 543        /* esw_attr->sample is allocated only when there is a sample action */
 544        if (esw_attr->sample && esw_attr->sample->sample_default_tbl) {
 545                fdb = esw_attr->sample->sample_default_tbl;
 546        } else if (split) {
 547                fwd_attr.chain = attr->chain;
 548                fwd_attr.prio = attr->prio;
 549                fwd_attr.vport = esw_attr->in_rep->vport;
 550                fwd_attr.vport_ns = &mlx5_esw_vport_tbl_mirror_ns;
 551
 552                fdb = mlx5_esw_vporttbl_get(esw, &fwd_attr);
 553        } else {
 554                if (attr->chain || attr->prio)
 555                        fdb = mlx5_chains_get_table(chains, attr->chain,
 556                                                    attr->prio, 0);
 557                else
 558                        fdb = attr->ft;
 559
 560                if (!(attr->flags & MLX5_ESW_ATTR_FLAG_NO_IN_PORT))
 561                        mlx5_eswitch_set_rule_source_port(esw, spec, attr,
 562                                                          esw_attr->in_mdev->priv.eswitch,
 563                                                          esw_attr->in_rep->vport);
 564        }
 565        if (IS_ERR(fdb)) {
 566                rule = ERR_CAST(fdb);
 567                goto err_esw_get;
 568        }
 569
 570        if (mlx5_eswitch_termtbl_required(esw, attr, &flow_act, spec))
 571                rule = mlx5_eswitch_add_termtbl_rule(esw, fdb, spec, esw_attr,
 572                                                     &flow_act, dest, i);
 573        else
 574                rule = mlx5_add_flow_rules(fdb, spec, &flow_act, dest, i);
 575        if (IS_ERR(rule))
 576                goto err_add_rule;
 577        else
 578                atomic64_inc(&esw->offloads.num_flows);
 579
 580        return rule;
 581
 582err_add_rule:
 583        if (split)
 584                mlx5_esw_vporttbl_put(esw, &fwd_attr);
 585        else if (attr->chain || attr->prio)
 586                mlx5_chains_put_table(chains, attr->chain, attr->prio, 0);
 587err_esw_get:
 588        esw_cleanup_dests(esw, attr);
 589err_create_goto_table:
 590        return rule;
 591}
 592
 593struct mlx5_flow_handle *
 594mlx5_eswitch_add_fwd_rule(struct mlx5_eswitch *esw,
 595                          struct mlx5_flow_spec *spec,
 596                          struct mlx5_flow_attr *attr)
 597{
 598        struct mlx5_flow_destination dest[MLX5_MAX_FLOW_FWD_VPORTS + 1] = {};
 599        struct mlx5_flow_act flow_act = { .flags = FLOW_ACT_NO_APPEND, };
 600        struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
 601        struct mlx5_fs_chains *chains = esw_chains(esw);
 602        struct mlx5_vport_tbl_attr fwd_attr;
 603        struct mlx5_flow_table *fast_fdb;
 604        struct mlx5_flow_table *fwd_fdb;
 605        struct mlx5_flow_handle *rule;
 606        int i, err = 0;
 607
 608        fast_fdb = mlx5_chains_get_table(chains, attr->chain, attr->prio, 0);
 609        if (IS_ERR(fast_fdb)) {
 610                rule = ERR_CAST(fast_fdb);
 611                goto err_get_fast;
 612        }
 613
 614        fwd_attr.chain = attr->chain;
 615        fwd_attr.prio = attr->prio;
 616        fwd_attr.vport = esw_attr->in_rep->vport;
 617        fwd_attr.vport_ns = &mlx5_esw_vport_tbl_mirror_ns;
 618        fwd_fdb = mlx5_esw_vporttbl_get(esw, &fwd_attr);
 619        if (IS_ERR(fwd_fdb)) {
 620                rule = ERR_CAST(fwd_fdb);
 621                goto err_get_fwd;
 622        }
 623
 624        flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
 625        for (i = 0; i < esw_attr->split_count; i++) {
 626                if (esw_is_indir_table(esw, attr))
 627                        err = esw_setup_indir_table(dest, &flow_act, esw, attr, spec, false, &i);
 628                else if (esw_is_chain_src_port_rewrite(esw, esw_attr))
 629                        err = esw_setup_chain_src_port_rewrite(dest, &flow_act, esw, chains, attr,
 630                                                               &i);
 631                else
 632                        esw_setup_vport_dest(dest, &flow_act, esw, esw_attr, i, i, false);
 633
 634                if (err) {
 635                        rule = ERR_PTR(err);
 636                        goto err_chain_src_rewrite;
 637                }
 638        }
 639        dest[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
 640        dest[i].ft = fwd_fdb;
 641        i++;
 642
 643        mlx5_eswitch_set_rule_source_port(esw, spec, attr,
 644                                          esw_attr->in_mdev->priv.eswitch,
 645                                          esw_attr->in_rep->vport);
 646
 647        if (attr->outer_match_level != MLX5_MATCH_NONE)
 648                spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
 649
 650        flow_act.flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
 651        rule = mlx5_add_flow_rules(fast_fdb, spec, &flow_act, dest, i);
 652
 653        if (IS_ERR(rule)) {
 654                i = esw_attr->split_count;
 655                goto err_chain_src_rewrite;
 656        }
 657
 658        atomic64_inc(&esw->offloads.num_flows);
 659
 660        return rule;
 661err_chain_src_rewrite:
 662        esw_put_dest_tables_loop(esw, attr, 0, i);
 663        mlx5_esw_vporttbl_put(esw, &fwd_attr);
 664err_get_fwd:
 665        mlx5_chains_put_table(chains, attr->chain, attr->prio, 0);
 666err_get_fast:
 667        return rule;
 668}
 669
 670static void
 671__mlx5_eswitch_del_rule(struct mlx5_eswitch *esw,
 672                        struct mlx5_flow_handle *rule,
 673                        struct mlx5_flow_attr *attr,
 674                        bool fwd_rule)
 675{
 676        struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
 677        struct mlx5_fs_chains *chains = esw_chains(esw);
 678        bool split = (esw_attr->split_count > 0);
 679        struct mlx5_vport_tbl_attr fwd_attr;
 680        int i;
 681
 682        mlx5_del_flow_rules(rule);
 683
 684        if (!(attr->flags & MLX5_ESW_ATTR_FLAG_SLOW_PATH)) {
 685                /* unref the term table */
 686                for (i = 0; i < MLX5_MAX_FLOW_FWD_VPORTS; i++) {
 687                        if (esw_attr->dests[i].termtbl)
 688                                mlx5_eswitch_termtbl_put(esw, esw_attr->dests[i].termtbl);
 689                }
 690        }
 691
 692        atomic64_dec(&esw->offloads.num_flows);
 693
 694        if (fwd_rule || split) {
 695                fwd_attr.chain = attr->chain;
 696                fwd_attr.prio = attr->prio;
 697                fwd_attr.vport = esw_attr->in_rep->vport;
 698                fwd_attr.vport_ns = &mlx5_esw_vport_tbl_mirror_ns;
 699        }
 700
 701        if (fwd_rule)  {
 702                mlx5_esw_vporttbl_put(esw, &fwd_attr);
 703                mlx5_chains_put_table(chains, attr->chain, attr->prio, 0);
 704                esw_put_dest_tables_loop(esw, attr, 0, esw_attr->split_count);
 705        } else {
 706                if (split)
 707                        mlx5_esw_vporttbl_put(esw, &fwd_attr);
 708                else if (attr->chain || attr->prio)
 709                        mlx5_chains_put_table(chains, attr->chain, attr->prio, 0);
 710                esw_cleanup_dests(esw, attr);
 711        }
 712}
 713
 714void
 715mlx5_eswitch_del_offloaded_rule(struct mlx5_eswitch *esw,
 716                                struct mlx5_flow_handle *rule,
 717                                struct mlx5_flow_attr *attr)
 718{
 719        __mlx5_eswitch_del_rule(esw, rule, attr, false);
 720}
 721
 722void
 723mlx5_eswitch_del_fwd_rule(struct mlx5_eswitch *esw,
 724                          struct mlx5_flow_handle *rule,
 725                          struct mlx5_flow_attr *attr)
 726{
 727        __mlx5_eswitch_del_rule(esw, rule, attr, true);
 728}
 729
 730static int esw_set_global_vlan_pop(struct mlx5_eswitch *esw, u8 val)
 731{
 732        struct mlx5_eswitch_rep *rep;
 733        unsigned long i;
 734        int err = 0;
 735
 736        esw_debug(esw->dev, "%s applying global %s policy\n", __func__, val ? "pop" : "none");
 737        mlx5_esw_for_each_host_func_vport(esw, i, rep, esw->esw_funcs.num_vfs) {
 738                if (atomic_read(&rep->rep_data[REP_ETH].state) != REP_LOADED)
 739                        continue;
 740
 741                err = __mlx5_eswitch_set_vport_vlan(esw, rep->vport, 0, 0, val);
 742                if (err)
 743                        goto out;
 744        }
 745
 746out:
 747        return err;
 748}
 749
 750static struct mlx5_eswitch_rep *
 751esw_vlan_action_get_vport(struct mlx5_esw_flow_attr *attr, bool push, bool pop)
 752{
 753        struct mlx5_eswitch_rep *in_rep, *out_rep, *vport = NULL;
 754
 755        in_rep  = attr->in_rep;
 756        out_rep = attr->dests[0].rep;
 757
 758        if (push)
 759                vport = in_rep;
 760        else if (pop)
 761                vport = out_rep;
 762        else
 763                vport = in_rep;
 764
 765        return vport;
 766}
 767
 768static int esw_add_vlan_action_check(struct mlx5_esw_flow_attr *attr,
 769                                     bool push, bool pop, bool fwd)
 770{
 771        struct mlx5_eswitch_rep *in_rep, *out_rep;
 772
 773        if ((push || pop) && !fwd)
 774                goto out_notsupp;
 775
 776        in_rep  = attr->in_rep;
 777        out_rep = attr->dests[0].rep;
 778
 779        if (push && in_rep->vport == MLX5_VPORT_UPLINK)
 780                goto out_notsupp;
 781
 782        if (pop && out_rep->vport == MLX5_VPORT_UPLINK)
 783                goto out_notsupp;
 784
 785        /* vport has vlan push configured, can't offload VF --> wire rules w.o it */
 786        if (!push && !pop && fwd)
 787                if (in_rep->vlan && out_rep->vport == MLX5_VPORT_UPLINK)
 788                        goto out_notsupp;
 789
 790        /* protects against (1) setting rules with different vlans to push and
 791         * (2) setting rules w.o vlans (attr->vlan = 0) && w. vlans to push (!= 0)
 792         */
 793        if (push && in_rep->vlan_refcount && (in_rep->vlan != attr->vlan_vid[0]))
 794                goto out_notsupp;
 795
 796        return 0;
 797
 798out_notsupp:
 799        return -EOPNOTSUPP;
 800}
 801
 802int mlx5_eswitch_add_vlan_action(struct mlx5_eswitch *esw,
 803                                 struct mlx5_flow_attr *attr)
 804{
 805        struct offloads_fdb *offloads = &esw->fdb_table.offloads;
 806        struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
 807        struct mlx5_eswitch_rep *vport = NULL;
 808        bool push, pop, fwd;
 809        int err = 0;
 810
 811        /* nop if we're on the vlan push/pop non emulation mode */
 812        if (mlx5_eswitch_vlan_actions_supported(esw->dev, 1))
 813                return 0;
 814
 815        push = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH);
 816        pop  = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
 817        fwd  = !!((attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) &&
 818                   !attr->dest_chain);
 819
 820        mutex_lock(&esw->state_lock);
 821
 822        err = esw_add_vlan_action_check(esw_attr, push, pop, fwd);
 823        if (err)
 824                goto unlock;
 825
 826        attr->flags &= ~MLX5_ESW_ATTR_FLAG_VLAN_HANDLED;
 827
 828        vport = esw_vlan_action_get_vport(esw_attr, push, pop);
 829
 830        if (!push && !pop && fwd) {
 831                /* tracks VF --> wire rules without vlan push action */
 832                if (esw_attr->dests[0].rep->vport == MLX5_VPORT_UPLINK) {
 833                        vport->vlan_refcount++;
 834                        attr->flags |= MLX5_ESW_ATTR_FLAG_VLAN_HANDLED;
 835                }
 836
 837                goto unlock;
 838        }
 839
 840        if (!push && !pop)
 841                goto unlock;
 842
 843        if (!(offloads->vlan_push_pop_refcount)) {
 844                /* it's the 1st vlan rule, apply global vlan pop policy */
 845                err = esw_set_global_vlan_pop(esw, SET_VLAN_STRIP);
 846                if (err)
 847                        goto out;
 848        }
 849        offloads->vlan_push_pop_refcount++;
 850
 851        if (push) {
 852                if (vport->vlan_refcount)
 853                        goto skip_set_push;
 854
 855                err = __mlx5_eswitch_set_vport_vlan(esw, vport->vport, esw_attr->vlan_vid[0],
 856                                                    0, SET_VLAN_INSERT | SET_VLAN_STRIP);
 857                if (err)
 858                        goto out;
 859                vport->vlan = esw_attr->vlan_vid[0];
 860skip_set_push:
 861                vport->vlan_refcount++;
 862        }
 863out:
 864        if (!err)
 865                attr->flags |= MLX5_ESW_ATTR_FLAG_VLAN_HANDLED;
 866unlock:
 867        mutex_unlock(&esw->state_lock);
 868        return err;
 869}
 870
 871int mlx5_eswitch_del_vlan_action(struct mlx5_eswitch *esw,
 872                                 struct mlx5_flow_attr *attr)
 873{
 874        struct offloads_fdb *offloads = &esw->fdb_table.offloads;
 875        struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
 876        struct mlx5_eswitch_rep *vport = NULL;
 877        bool push, pop, fwd;
 878        int err = 0;
 879
 880        /* nop if we're on the vlan push/pop non emulation mode */
 881        if (mlx5_eswitch_vlan_actions_supported(esw->dev, 1))
 882                return 0;
 883
 884        if (!(attr->flags & MLX5_ESW_ATTR_FLAG_VLAN_HANDLED))
 885                return 0;
 886
 887        push = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH);
 888        pop  = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
 889        fwd  = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST);
 890
 891        mutex_lock(&esw->state_lock);
 892
 893        vport = esw_vlan_action_get_vport(esw_attr, push, pop);
 894
 895        if (!push && !pop && fwd) {
 896                /* tracks VF --> wire rules without vlan push action */
 897                if (esw_attr->dests[0].rep->vport == MLX5_VPORT_UPLINK)
 898                        vport->vlan_refcount--;
 899
 900                goto out;
 901        }
 902
 903        if (push) {
 904                vport->vlan_refcount--;
 905                if (vport->vlan_refcount)
 906                        goto skip_unset_push;
 907
 908                vport->vlan = 0;
 909                err = __mlx5_eswitch_set_vport_vlan(esw, vport->vport,
 910                                                    0, 0, SET_VLAN_STRIP);
 911                if (err)
 912                        goto out;
 913        }
 914
 915skip_unset_push:
 916        offloads->vlan_push_pop_refcount--;
 917        if (offloads->vlan_push_pop_refcount)
 918                goto out;
 919
 920        /* no more vlan rules, stop global vlan pop policy */
 921        err = esw_set_global_vlan_pop(esw, 0);
 922
 923out:
 924        mutex_unlock(&esw->state_lock);
 925        return err;
 926}
 927
 928struct mlx5_flow_handle *
 929mlx5_eswitch_add_send_to_vport_rule(struct mlx5_eswitch *on_esw,
 930                                    struct mlx5_eswitch_rep *rep,
 931                                    u32 sqn)
 932{
 933        struct mlx5_flow_act flow_act = {0};
 934        struct mlx5_flow_destination dest = {};
 935        struct mlx5_flow_handle *flow_rule;
 936        struct mlx5_flow_spec *spec;
 937        void *misc;
 938
 939        spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
 940        if (!spec) {
 941                flow_rule = ERR_PTR(-ENOMEM);
 942                goto out;
 943        }
 944
 945        misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
 946        MLX5_SET(fte_match_set_misc, misc, source_sqn, sqn);
 947        /* source vport is the esw manager */
 948        MLX5_SET(fte_match_set_misc, misc, source_port, rep->esw->manager_vport);
 949        if (MLX5_CAP_ESW(on_esw->dev, merged_eswitch))
 950                MLX5_SET(fte_match_set_misc, misc, source_eswitch_owner_vhca_id,
 951                         MLX5_CAP_GEN(rep->esw->dev, vhca_id));
 952
 953        misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
 954        MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_sqn);
 955        MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
 956        if (MLX5_CAP_ESW(on_esw->dev, merged_eswitch))
 957                MLX5_SET_TO_ONES(fte_match_set_misc, misc,
 958                                 source_eswitch_owner_vhca_id);
 959
 960        spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
 961        dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
 962        dest.vport.num = rep->vport;
 963        dest.vport.vhca_id = MLX5_CAP_GEN(rep->esw->dev, vhca_id);
 964        dest.vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
 965        flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
 966
 967        flow_rule = mlx5_add_flow_rules(on_esw->fdb_table.offloads.slow_fdb,
 968                                        spec, &flow_act, &dest, 1);
 969        if (IS_ERR(flow_rule))
 970                esw_warn(on_esw->dev, "FDB: Failed to add send to vport rule err %ld\n",
 971                         PTR_ERR(flow_rule));
 972out:
 973        kvfree(spec);
 974        return flow_rule;
 975}
 976EXPORT_SYMBOL(mlx5_eswitch_add_send_to_vport_rule);
 977
 978void mlx5_eswitch_del_send_to_vport_rule(struct mlx5_flow_handle *rule)
 979{
 980        mlx5_del_flow_rules(rule);
 981}
 982
 983static void mlx5_eswitch_del_send_to_vport_meta_rules(struct mlx5_eswitch *esw)
 984{
 985        struct mlx5_flow_handle **flows = esw->fdb_table.offloads.send_to_vport_meta_rules;
 986        int i = 0, num_vfs = esw->esw_funcs.num_vfs;
 987
 988        if (!num_vfs || !flows)
 989                return;
 990
 991        for (i = 0; i < num_vfs; i++)
 992                mlx5_del_flow_rules(flows[i]);
 993
 994        kvfree(flows);
 995}
 996
 997static int
 998mlx5_eswitch_add_send_to_vport_meta_rules(struct mlx5_eswitch *esw)
 999{
1000        struct mlx5_flow_destination dest = {};
1001        struct mlx5_flow_act flow_act = {0};
1002        int num_vfs, rule_idx = 0, err = 0;
1003        struct mlx5_flow_handle *flow_rule;
1004        struct mlx5_flow_handle **flows;
1005        struct mlx5_flow_spec *spec;
1006        struct mlx5_vport *vport;
1007        unsigned long i;
1008        u16 vport_num;
1009
1010        num_vfs = esw->esw_funcs.num_vfs;
1011        flows = kvzalloc(num_vfs * sizeof(*flows), GFP_KERNEL);
1012        if (!flows)
1013                return -ENOMEM;
1014
1015        spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1016        if (!spec) {
1017                err = -ENOMEM;
1018                goto alloc_err;
1019        }
1020
1021        MLX5_SET(fte_match_param, spec->match_criteria,
1022                 misc_parameters_2.metadata_reg_c_0, mlx5_eswitch_get_vport_metadata_mask());
1023        MLX5_SET(fte_match_param, spec->match_criteria,
1024                 misc_parameters_2.metadata_reg_c_1, ESW_TUN_MASK);
1025        MLX5_SET(fte_match_param, spec->match_value, misc_parameters_2.metadata_reg_c_1,
1026                 ESW_TUN_SLOW_TABLE_GOTO_VPORT_MARK);
1027
1028        spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS_2;
1029        dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
1030        flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
1031
1032        mlx5_esw_for_each_vf_vport(esw, i, vport, num_vfs) {
1033                vport_num = vport->vport;
1034                MLX5_SET(fte_match_param, spec->match_value, misc_parameters_2.metadata_reg_c_0,
1035                         mlx5_eswitch_get_vport_metadata_for_match(esw, vport_num));
1036                dest.vport.num = vport_num;
1037
1038                flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb,
1039                                                spec, &flow_act, &dest, 1);
1040                if (IS_ERR(flow_rule)) {
1041                        err = PTR_ERR(flow_rule);
1042                        esw_warn(esw->dev, "FDB: Failed to add send to vport meta rule idx %d, err %ld\n",
1043                                 rule_idx, PTR_ERR(flow_rule));
1044                        goto rule_err;
1045                }
1046                flows[rule_idx++] = flow_rule;
1047        }
1048
1049        esw->fdb_table.offloads.send_to_vport_meta_rules = flows;
1050        kvfree(spec);
1051        return 0;
1052
1053rule_err:
1054        while (--rule_idx >= 0)
1055                mlx5_del_flow_rules(flows[rule_idx]);
1056        kvfree(spec);
1057alloc_err:
1058        kvfree(flows);
1059        return err;
1060}
1061
1062static bool mlx5_eswitch_reg_c1_loopback_supported(struct mlx5_eswitch *esw)
1063{
1064        return MLX5_CAP_ESW_FLOWTABLE(esw->dev, fdb_to_vport_reg_c_id) &
1065               MLX5_FDB_TO_VPORT_REG_C_1;
1066}
1067
1068static int esw_set_passing_vport_metadata(struct mlx5_eswitch *esw, bool enable)
1069{
1070        u32 out[MLX5_ST_SZ_DW(query_esw_vport_context_out)] = {};
1071        u32 min[MLX5_ST_SZ_DW(modify_esw_vport_context_in)] = {};
1072        u32 in[MLX5_ST_SZ_DW(query_esw_vport_context_in)] = {};
1073        u8 curr, wanted;
1074        int err;
1075
1076        if (!mlx5_eswitch_reg_c1_loopback_supported(esw) &&
1077            !mlx5_eswitch_vport_match_metadata_enabled(esw))
1078                return 0;
1079
1080        MLX5_SET(query_esw_vport_context_in, in, opcode,
1081                 MLX5_CMD_OP_QUERY_ESW_VPORT_CONTEXT);
1082        err = mlx5_cmd_exec_inout(esw->dev, query_esw_vport_context, in, out);
1083        if (err)
1084                return err;
1085
1086        curr = MLX5_GET(query_esw_vport_context_out, out,
1087                        esw_vport_context.fdb_to_vport_reg_c_id);
1088        wanted = MLX5_FDB_TO_VPORT_REG_C_0;
1089        if (mlx5_eswitch_reg_c1_loopback_supported(esw))
1090                wanted |= MLX5_FDB_TO_VPORT_REG_C_1;
1091
1092        if (enable)
1093                curr |= wanted;
1094        else
1095                curr &= ~wanted;
1096
1097        MLX5_SET(modify_esw_vport_context_in, min,
1098                 esw_vport_context.fdb_to_vport_reg_c_id, curr);
1099        MLX5_SET(modify_esw_vport_context_in, min,
1100                 field_select.fdb_to_vport_reg_c_id, 1);
1101
1102        err = mlx5_eswitch_modify_esw_vport_context(esw->dev, 0, false, min);
1103        if (!err) {
1104                if (enable && (curr & MLX5_FDB_TO_VPORT_REG_C_1))
1105                        esw->flags |= MLX5_ESWITCH_REG_C1_LOOPBACK_ENABLED;
1106                else
1107                        esw->flags &= ~MLX5_ESWITCH_REG_C1_LOOPBACK_ENABLED;
1108        }
1109
1110        return err;
1111}
1112
1113static void peer_miss_rules_setup(struct mlx5_eswitch *esw,
1114                                  struct mlx5_core_dev *peer_dev,
1115                                  struct mlx5_flow_spec *spec,
1116                                  struct mlx5_flow_destination *dest)
1117{
1118        void *misc;
1119
1120        if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
1121                misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
1122                                    misc_parameters_2);
1123                MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0,
1124                         mlx5_eswitch_get_vport_metadata_mask());
1125
1126                spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS_2;
1127        } else {
1128                misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
1129                                    misc_parameters);
1130
1131                MLX5_SET(fte_match_set_misc, misc, source_eswitch_owner_vhca_id,
1132                         MLX5_CAP_GEN(peer_dev, vhca_id));
1133
1134                spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
1135
1136                misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
1137                                    misc_parameters);
1138                MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
1139                MLX5_SET_TO_ONES(fte_match_set_misc, misc,
1140                                 source_eswitch_owner_vhca_id);
1141        }
1142
1143        dest->type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
1144        dest->vport.num = peer_dev->priv.eswitch->manager_vport;
1145        dest->vport.vhca_id = MLX5_CAP_GEN(peer_dev, vhca_id);
1146        dest->vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
1147}
1148
1149static void esw_set_peer_miss_rule_source_port(struct mlx5_eswitch *esw,
1150                                               struct mlx5_eswitch *peer_esw,
1151                                               struct mlx5_flow_spec *spec,
1152                                               u16 vport)
1153{
1154        void *misc;
1155
1156        if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
1157                misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
1158                                    misc_parameters_2);
1159                MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0,
1160                         mlx5_eswitch_get_vport_metadata_for_match(peer_esw,
1161                                                                   vport));
1162        } else {
1163                misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
1164                                    misc_parameters);
1165                MLX5_SET(fte_match_set_misc, misc, source_port, vport);
1166        }
1167}
1168
1169static int esw_add_fdb_peer_miss_rules(struct mlx5_eswitch *esw,
1170                                       struct mlx5_core_dev *peer_dev)
1171{
1172        struct mlx5_flow_destination dest = {};
1173        struct mlx5_flow_act flow_act = {0};
1174        struct mlx5_flow_handle **flows;
1175        /* total vports is the same for both e-switches */
1176        int nvports = esw->total_vports;
1177        struct mlx5_flow_handle *flow;
1178        struct mlx5_flow_spec *spec;
1179        struct mlx5_vport *vport;
1180        unsigned long i;
1181        void *misc;
1182        int err;
1183
1184        spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1185        if (!spec)
1186                return -ENOMEM;
1187
1188        peer_miss_rules_setup(esw, peer_dev, spec, &dest);
1189
1190        flows = kvzalloc(nvports * sizeof(*flows), GFP_KERNEL);
1191        if (!flows) {
1192                err = -ENOMEM;
1193                goto alloc_flows_err;
1194        }
1195
1196        flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
1197        misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
1198                            misc_parameters);
1199
1200        if (mlx5_core_is_ecpf_esw_manager(esw->dev)) {
1201                vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_PF);
1202                esw_set_peer_miss_rule_source_port(esw, peer_dev->priv.eswitch,
1203                                                   spec, MLX5_VPORT_PF);
1204
1205                flow = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb,
1206                                           spec, &flow_act, &dest, 1);
1207                if (IS_ERR(flow)) {
1208                        err = PTR_ERR(flow);
1209                        goto add_pf_flow_err;
1210                }
1211                flows[vport->index] = flow;
1212        }
1213
1214        if (mlx5_ecpf_vport_exists(esw->dev)) {
1215                vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_ECPF);
1216                MLX5_SET(fte_match_set_misc, misc, source_port, MLX5_VPORT_ECPF);
1217                flow = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb,
1218                                           spec, &flow_act, &dest, 1);
1219                if (IS_ERR(flow)) {
1220                        err = PTR_ERR(flow);
1221                        goto add_ecpf_flow_err;
1222                }
1223                flows[vport->index] = flow;
1224        }
1225
1226        mlx5_esw_for_each_vf_vport(esw, i, vport, mlx5_core_max_vfs(esw->dev)) {
1227                esw_set_peer_miss_rule_source_port(esw,
1228                                                   peer_dev->priv.eswitch,
1229                                                   spec, vport->vport);
1230
1231                flow = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb,
1232                                           spec, &flow_act, &dest, 1);
1233                if (IS_ERR(flow)) {
1234                        err = PTR_ERR(flow);
1235                        goto add_vf_flow_err;
1236                }
1237                flows[vport->index] = flow;
1238        }
1239
1240        esw->fdb_table.offloads.peer_miss_rules = flows;
1241
1242        kvfree(spec);
1243        return 0;
1244
1245add_vf_flow_err:
1246        mlx5_esw_for_each_vf_vport(esw, i, vport, mlx5_core_max_vfs(esw->dev)) {
1247                if (!flows[vport->index])
1248                        continue;
1249                mlx5_del_flow_rules(flows[vport->index]);
1250        }
1251        if (mlx5_ecpf_vport_exists(esw->dev)) {
1252                vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_ECPF);
1253                mlx5_del_flow_rules(flows[vport->index]);
1254        }
1255add_ecpf_flow_err:
1256        if (mlx5_core_is_ecpf_esw_manager(esw->dev)) {
1257                vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_PF);
1258                mlx5_del_flow_rules(flows[vport->index]);
1259        }
1260add_pf_flow_err:
1261        esw_warn(esw->dev, "FDB: Failed to add peer miss flow rule err %d\n", err);
1262        kvfree(flows);
1263alloc_flows_err:
1264        kvfree(spec);
1265        return err;
1266}
1267
1268static void esw_del_fdb_peer_miss_rules(struct mlx5_eswitch *esw)
1269{
1270        struct mlx5_flow_handle **flows;
1271        struct mlx5_vport *vport;
1272        unsigned long i;
1273
1274        flows = esw->fdb_table.offloads.peer_miss_rules;
1275
1276        mlx5_esw_for_each_vf_vport(esw, i, vport, mlx5_core_max_vfs(esw->dev))
1277                mlx5_del_flow_rules(flows[vport->index]);
1278
1279        if (mlx5_ecpf_vport_exists(esw->dev)) {
1280                vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_ECPF);
1281                mlx5_del_flow_rules(flows[vport->index]);
1282        }
1283
1284        if (mlx5_core_is_ecpf_esw_manager(esw->dev)) {
1285                vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_PF);
1286                mlx5_del_flow_rules(flows[vport->index]);
1287        }
1288        kvfree(flows);
1289}
1290
1291static int esw_add_fdb_miss_rule(struct mlx5_eswitch *esw)
1292{
1293        struct mlx5_flow_act flow_act = {0};
1294        struct mlx5_flow_destination dest = {};
1295        struct mlx5_flow_handle *flow_rule = NULL;
1296        struct mlx5_flow_spec *spec;
1297        void *headers_c;
1298        void *headers_v;
1299        int err = 0;
1300        u8 *dmac_c;
1301        u8 *dmac_v;
1302
1303        spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1304        if (!spec) {
1305                err = -ENOMEM;
1306                goto out;
1307        }
1308
1309        spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
1310        headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
1311                                 outer_headers);
1312        dmac_c = MLX5_ADDR_OF(fte_match_param, headers_c,
1313                              outer_headers.dmac_47_16);
1314        dmac_c[0] = 0x01;
1315
1316        dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
1317        dest.vport.num = esw->manager_vport;
1318        flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
1319
1320        flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb,
1321                                        spec, &flow_act, &dest, 1);
1322        if (IS_ERR(flow_rule)) {
1323                err = PTR_ERR(flow_rule);
1324                esw_warn(esw->dev,  "FDB: Failed to add unicast miss flow rule err %d\n", err);
1325                goto out;
1326        }
1327
1328        esw->fdb_table.offloads.miss_rule_uni = flow_rule;
1329
1330        headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
1331                                 outer_headers);
1332        dmac_v = MLX5_ADDR_OF(fte_match_param, headers_v,
1333                              outer_headers.dmac_47_16);
1334        dmac_v[0] = 0x01;
1335        flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb,
1336                                        spec, &flow_act, &dest, 1);
1337        if (IS_ERR(flow_rule)) {
1338                err = PTR_ERR(flow_rule);
1339                esw_warn(esw->dev, "FDB: Failed to add multicast miss flow rule err %d\n", err);
1340                mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_uni);
1341                goto out;
1342        }
1343
1344        esw->fdb_table.offloads.miss_rule_multi = flow_rule;
1345
1346out:
1347        kvfree(spec);
1348        return err;
1349}
1350
1351struct mlx5_flow_handle *
1352esw_add_restore_rule(struct mlx5_eswitch *esw, u32 tag)
1353{
1354        struct mlx5_flow_act flow_act = { .flags = FLOW_ACT_NO_APPEND, };
1355        struct mlx5_flow_table *ft = esw->offloads.ft_offloads_restore;
1356        struct mlx5_flow_context *flow_context;
1357        struct mlx5_flow_handle *flow_rule;
1358        struct mlx5_flow_destination dest;
1359        struct mlx5_flow_spec *spec;
1360        void *misc;
1361
1362        if (!mlx5_eswitch_reg_c1_loopback_supported(esw))
1363                return ERR_PTR(-EOPNOTSUPP);
1364
1365        spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1366        if (!spec)
1367                return ERR_PTR(-ENOMEM);
1368
1369        misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
1370                            misc_parameters_2);
1371        MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0,
1372                 ESW_REG_C0_USER_DATA_METADATA_MASK);
1373        misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
1374                            misc_parameters_2);
1375        MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0, tag);
1376        spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS_2;
1377        flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
1378                          MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
1379        flow_act.modify_hdr = esw->offloads.restore_copy_hdr_id;
1380
1381        flow_context = &spec->flow_context;
1382        flow_context->flags |= FLOW_CONTEXT_HAS_TAG;
1383        flow_context->flow_tag = tag;
1384        dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
1385        dest.ft = esw->offloads.ft_offloads;
1386
1387        flow_rule = mlx5_add_flow_rules(ft, spec, &flow_act, &dest, 1);
1388        kvfree(spec);
1389
1390        if (IS_ERR(flow_rule))
1391                esw_warn(esw->dev,
1392                         "Failed to create restore rule for tag: %d, err(%d)\n",
1393                         tag, (int)PTR_ERR(flow_rule));
1394
1395        return flow_rule;
1396}
1397
1398#define MAX_PF_SQ 256
1399#define MAX_SQ_NVPORTS 32
1400
1401static void esw_set_flow_group_source_port(struct mlx5_eswitch *esw,
1402                                           u32 *flow_group_in)
1403{
1404        void *match_criteria = MLX5_ADDR_OF(create_flow_group_in,
1405                                            flow_group_in,
1406                                            match_criteria);
1407
1408        if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
1409                MLX5_SET(create_flow_group_in, flow_group_in,
1410                         match_criteria_enable,
1411                         MLX5_MATCH_MISC_PARAMETERS_2);
1412
1413                MLX5_SET(fte_match_param, match_criteria,
1414                         misc_parameters_2.metadata_reg_c_0,
1415                         mlx5_eswitch_get_vport_metadata_mask());
1416        } else {
1417                MLX5_SET(create_flow_group_in, flow_group_in,
1418                         match_criteria_enable,
1419                         MLX5_MATCH_MISC_PARAMETERS);
1420
1421                MLX5_SET_TO_ONES(fte_match_param, match_criteria,
1422                                 misc_parameters.source_port);
1423        }
1424}
1425
1426#if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
1427static void esw_vport_tbl_put(struct mlx5_eswitch *esw)
1428{
1429        struct mlx5_vport_tbl_attr attr;
1430        struct mlx5_vport *vport;
1431        unsigned long i;
1432
1433        attr.chain = 0;
1434        attr.prio = 1;
1435        mlx5_esw_for_each_vport(esw, i, vport) {
1436                attr.vport = vport->vport;
1437                attr.vport_ns = &mlx5_esw_vport_tbl_mirror_ns;
1438                mlx5_esw_vporttbl_put(esw, &attr);
1439        }
1440}
1441
1442static int esw_vport_tbl_get(struct mlx5_eswitch *esw)
1443{
1444        struct mlx5_vport_tbl_attr attr;
1445        struct mlx5_flow_table *fdb;
1446        struct mlx5_vport *vport;
1447        unsigned long i;
1448
1449        attr.chain = 0;
1450        attr.prio = 1;
1451        mlx5_esw_for_each_vport(esw, i, vport) {
1452                attr.vport = vport->vport;
1453                attr.vport_ns = &mlx5_esw_vport_tbl_mirror_ns;
1454                fdb = mlx5_esw_vporttbl_get(esw, &attr);
1455                if (IS_ERR(fdb))
1456                        goto out;
1457        }
1458        return 0;
1459
1460out:
1461        esw_vport_tbl_put(esw);
1462        return PTR_ERR(fdb);
1463}
1464
1465#define fdb_modify_header_fwd_to_table_supported(esw) \
1466        (MLX5_CAP_ESW_FLOWTABLE((esw)->dev, fdb_modify_header_fwd_to_table))
1467static void esw_init_chains_offload_flags(struct mlx5_eswitch *esw, u32 *flags)
1468{
1469        struct mlx5_core_dev *dev = esw->dev;
1470
1471        if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, ignore_flow_level))
1472                *flags |= MLX5_CHAINS_IGNORE_FLOW_LEVEL_SUPPORTED;
1473
1474        if (!MLX5_CAP_ESW_FLOWTABLE(dev, multi_fdb_encap) &&
1475            esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE) {
1476                *flags &= ~MLX5_CHAINS_AND_PRIOS_SUPPORTED;
1477                esw_warn(dev, "Tc chains and priorities offload aren't supported, update firmware if needed\n");
1478        } else if (!mlx5_eswitch_reg_c1_loopback_enabled(esw)) {
1479                *flags &= ~MLX5_CHAINS_AND_PRIOS_SUPPORTED;
1480                esw_warn(dev, "Tc chains and priorities offload aren't supported\n");
1481        } else if (!fdb_modify_header_fwd_to_table_supported(esw)) {
1482                /* Disabled when ttl workaround is needed, e.g
1483                 * when ESWITCH_IPV4_TTL_MODIFY_ENABLE = true in mlxconfig
1484                 */
1485                esw_warn(dev,
1486                         "Tc chains and priorities offload aren't supported, check firmware version, or mlxconfig settings\n");
1487                *flags &= ~MLX5_CHAINS_AND_PRIOS_SUPPORTED;
1488        } else {
1489                *flags |= MLX5_CHAINS_AND_PRIOS_SUPPORTED;
1490                esw_info(dev, "Supported tc chains and prios offload\n");
1491        }
1492
1493        if (esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE)
1494                *flags |= MLX5_CHAINS_FT_TUNNEL_SUPPORTED;
1495}
1496
1497static int
1498esw_chains_create(struct mlx5_eswitch *esw, struct mlx5_flow_table *miss_fdb)
1499{
1500        struct mlx5_core_dev *dev = esw->dev;
1501        struct mlx5_flow_table *nf_ft, *ft;
1502        struct mlx5_chains_attr attr = {};
1503        struct mlx5_fs_chains *chains;
1504        u32 fdb_max;
1505        int err;
1506
1507        fdb_max = 1 << MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size);
1508
1509        esw_init_chains_offload_flags(esw, &attr.flags);
1510        attr.ns = MLX5_FLOW_NAMESPACE_FDB;
1511        attr.max_ft_sz = fdb_max;
1512        attr.max_grp_num = esw->params.large_group_num;
1513        attr.default_ft = miss_fdb;
1514        attr.mapping = esw->offloads.reg_c0_obj_pool;
1515
1516        chains = mlx5_chains_create(dev, &attr);
1517        if (IS_ERR(chains)) {
1518                err = PTR_ERR(chains);
1519                esw_warn(dev, "Failed to create fdb chains err(%d)\n", err);
1520                return err;
1521        }
1522
1523        esw->fdb_table.offloads.esw_chains_priv = chains;
1524
1525        /* Create tc_end_ft which is the always created ft chain */
1526        nf_ft = mlx5_chains_get_table(chains, mlx5_chains_get_nf_ft_chain(chains),
1527                                      1, 0);
1528        if (IS_ERR(nf_ft)) {
1529                err = PTR_ERR(nf_ft);
1530                goto nf_ft_err;
1531        }
1532
1533        /* Always open the root for fast path */
1534        ft = mlx5_chains_get_table(chains, 0, 1, 0);
1535        if (IS_ERR(ft)) {
1536                err = PTR_ERR(ft);
1537                goto level_0_err;
1538        }
1539
1540        /* Open level 1 for split fdb rules now if prios isn't supported  */
1541        if (!mlx5_chains_prios_supported(chains)) {
1542                err = esw_vport_tbl_get(esw);
1543                if (err)
1544                        goto level_1_err;
1545        }
1546
1547        mlx5_chains_set_end_ft(chains, nf_ft);
1548
1549        return 0;
1550
1551level_1_err:
1552        mlx5_chains_put_table(chains, 0, 1, 0);
1553level_0_err:
1554        mlx5_chains_put_table(chains, mlx5_chains_get_nf_ft_chain(chains), 1, 0);
1555nf_ft_err:
1556        mlx5_chains_destroy(chains);
1557        esw->fdb_table.offloads.esw_chains_priv = NULL;
1558
1559        return err;
1560}
1561
1562static void
1563esw_chains_destroy(struct mlx5_eswitch *esw, struct mlx5_fs_chains *chains)
1564{
1565        if (!mlx5_chains_prios_supported(chains))
1566                esw_vport_tbl_put(esw);
1567        mlx5_chains_put_table(chains, 0, 1, 0);
1568        mlx5_chains_put_table(chains, mlx5_chains_get_nf_ft_chain(chains), 1, 0);
1569        mlx5_chains_destroy(chains);
1570}
1571
1572#else /* CONFIG_MLX5_CLS_ACT */
1573
1574static int
1575esw_chains_create(struct mlx5_eswitch *esw, struct mlx5_flow_table *miss_fdb)
1576{ return 0; }
1577
1578static void
1579esw_chains_destroy(struct mlx5_eswitch *esw, struct mlx5_fs_chains *chains)
1580{}
1581
1582#endif
1583
1584static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw)
1585{
1586        int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
1587        struct mlx5_flow_table_attr ft_attr = {};
1588        int num_vfs, table_size, ix, err = 0;
1589        struct mlx5_core_dev *dev = esw->dev;
1590        struct mlx5_flow_namespace *root_ns;
1591        struct mlx5_flow_table *fdb = NULL;
1592        u32 flags = 0, *flow_group_in;
1593        struct mlx5_flow_group *g;
1594        void *match_criteria;
1595        u8 *dmac;
1596
1597        esw_debug(esw->dev, "Create offloads FDB Tables\n");
1598
1599        flow_group_in = kvzalloc(inlen, GFP_KERNEL);
1600        if (!flow_group_in)
1601                return -ENOMEM;
1602
1603        root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
1604        if (!root_ns) {
1605                esw_warn(dev, "Failed to get FDB flow namespace\n");
1606                err = -EOPNOTSUPP;
1607                goto ns_err;
1608        }
1609        esw->fdb_table.offloads.ns = root_ns;
1610        err = mlx5_flow_namespace_set_mode(root_ns,
1611                                           esw->dev->priv.steering->mode);
1612        if (err) {
1613                esw_warn(dev, "Failed to set FDB namespace steering mode\n");
1614                goto ns_err;
1615        }
1616
1617        table_size = esw->total_vports * MAX_SQ_NVPORTS + MAX_PF_SQ +
1618                MLX5_ESW_MISS_FLOWS + esw->total_vports + esw->esw_funcs.num_vfs;
1619
1620        /* create the slow path fdb with encap set, so further table instances
1621         * can be created at run time while VFs are probed if the FW allows that.
1622         */
1623        if (esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE)
1624                flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT |
1625                          MLX5_FLOW_TABLE_TUNNEL_EN_DECAP);
1626
1627        ft_attr.flags = flags;
1628        ft_attr.max_fte = table_size;
1629        ft_attr.prio = FDB_SLOW_PATH;
1630
1631        fdb = mlx5_create_flow_table(root_ns, &ft_attr);
1632        if (IS_ERR(fdb)) {
1633                err = PTR_ERR(fdb);
1634                esw_warn(dev, "Failed to create slow path FDB Table err %d\n", err);
1635                goto slow_fdb_err;
1636        }
1637        esw->fdb_table.offloads.slow_fdb = fdb;
1638
1639        /* Create empty TC-miss managed table. This allows plugging in following
1640         * priorities without directly exposing their level 0 table to
1641         * eswitch_offloads and passing it as miss_fdb to following call to
1642         * esw_chains_create().
1643         */
1644        memset(&ft_attr, 0, sizeof(ft_attr));
1645        ft_attr.prio = FDB_TC_MISS;
1646        esw->fdb_table.offloads.tc_miss_table = mlx5_create_flow_table(root_ns, &ft_attr);
1647        if (IS_ERR(esw->fdb_table.offloads.tc_miss_table)) {
1648                err = PTR_ERR(esw->fdb_table.offloads.tc_miss_table);
1649                esw_warn(dev, "Failed to create TC miss FDB Table err %d\n", err);
1650                goto tc_miss_table_err;
1651        }
1652
1653        err = esw_chains_create(esw, esw->fdb_table.offloads.tc_miss_table);
1654        if (err) {
1655                esw_warn(dev, "Failed to open fdb chains err(%d)\n", err);
1656                goto fdb_chains_err;
1657        }
1658
1659        /* create send-to-vport group */
1660        MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
1661                 MLX5_MATCH_MISC_PARAMETERS);
1662
1663        match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
1664
1665        MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_sqn);
1666        MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_port);
1667        if (MLX5_CAP_ESW(esw->dev, merged_eswitch)) {
1668                MLX5_SET_TO_ONES(fte_match_param, match_criteria,
1669                                 misc_parameters.source_eswitch_owner_vhca_id);
1670                MLX5_SET(create_flow_group_in, flow_group_in,
1671                         source_eswitch_owner_vhca_id_valid, 1);
1672        }
1673
1674        ix = esw->total_vports * MAX_SQ_NVPORTS + MAX_PF_SQ;
1675        MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
1676        MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, ix - 1);
1677
1678        g = mlx5_create_flow_group(fdb, flow_group_in);
1679        if (IS_ERR(g)) {
1680                err = PTR_ERR(g);
1681                esw_warn(dev, "Failed to create send-to-vport flow group err(%d)\n", err);
1682                goto send_vport_err;
1683        }
1684        esw->fdb_table.offloads.send_to_vport_grp = g;
1685
1686        if (esw_src_port_rewrite_supported(esw)) {
1687                /* meta send to vport */
1688                memset(flow_group_in, 0, inlen);
1689                MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
1690                         MLX5_MATCH_MISC_PARAMETERS_2);
1691
1692                match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
1693
1694                MLX5_SET(fte_match_param, match_criteria,
1695                         misc_parameters_2.metadata_reg_c_0,
1696                         mlx5_eswitch_get_vport_metadata_mask());
1697                MLX5_SET(fte_match_param, match_criteria,
1698                         misc_parameters_2.metadata_reg_c_1, ESW_TUN_MASK);
1699
1700                num_vfs = esw->esw_funcs.num_vfs;
1701                if (num_vfs) {
1702                        MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ix);
1703                        MLX5_SET(create_flow_group_in, flow_group_in,
1704                                 end_flow_index, ix + num_vfs - 1);
1705                        ix += num_vfs;
1706
1707                        g = mlx5_create_flow_group(fdb, flow_group_in);
1708                        if (IS_ERR(g)) {
1709                                err = PTR_ERR(g);
1710                                esw_warn(dev, "Failed to create send-to-vport meta flow group err(%d)\n",
1711                                         err);
1712                                goto send_vport_meta_err;
1713                        }
1714                        esw->fdb_table.offloads.send_to_vport_meta_grp = g;
1715
1716                        err = mlx5_eswitch_add_send_to_vport_meta_rules(esw);
1717                        if (err)
1718                                goto meta_rule_err;
1719                }
1720        }
1721
1722        if (MLX5_CAP_ESW(esw->dev, merged_eswitch)) {
1723                /* create peer esw miss group */
1724                memset(flow_group_in, 0, inlen);
1725
1726                esw_set_flow_group_source_port(esw, flow_group_in);
1727
1728                if (!mlx5_eswitch_vport_match_metadata_enabled(esw)) {
1729                        match_criteria = MLX5_ADDR_OF(create_flow_group_in,
1730                                                      flow_group_in,
1731                                                      match_criteria);
1732
1733                        MLX5_SET_TO_ONES(fte_match_param, match_criteria,
1734                                         misc_parameters.source_eswitch_owner_vhca_id);
1735
1736                        MLX5_SET(create_flow_group_in, flow_group_in,
1737                                 source_eswitch_owner_vhca_id_valid, 1);
1738                }
1739
1740                MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ix);
1741                MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index,
1742                         ix + esw->total_vports - 1);
1743                ix += esw->total_vports;
1744
1745                g = mlx5_create_flow_group(fdb, flow_group_in);
1746                if (IS_ERR(g)) {
1747                        err = PTR_ERR(g);
1748                        esw_warn(dev, "Failed to create peer miss flow group err(%d)\n", err);
1749                        goto peer_miss_err;
1750                }
1751                esw->fdb_table.offloads.peer_miss_grp = g;
1752        }
1753
1754        /* create miss group */
1755        memset(flow_group_in, 0, inlen);
1756        MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
1757                 MLX5_MATCH_OUTER_HEADERS);
1758        match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in,
1759                                      match_criteria);
1760        dmac = MLX5_ADDR_OF(fte_match_param, match_criteria,
1761                            outer_headers.dmac_47_16);
1762        dmac[0] = 0x01;
1763
1764        MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ix);
1765        MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index,
1766                 ix + MLX5_ESW_MISS_FLOWS);
1767
1768        g = mlx5_create_flow_group(fdb, flow_group_in);
1769        if (IS_ERR(g)) {
1770                err = PTR_ERR(g);
1771                esw_warn(dev, "Failed to create miss flow group err(%d)\n", err);
1772                goto miss_err;
1773        }
1774        esw->fdb_table.offloads.miss_grp = g;
1775
1776        err = esw_add_fdb_miss_rule(esw);
1777        if (err)
1778                goto miss_rule_err;
1779
1780        kvfree(flow_group_in);
1781        return 0;
1782
1783miss_rule_err:
1784        mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
1785miss_err:
1786        if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
1787                mlx5_destroy_flow_group(esw->fdb_table.offloads.peer_miss_grp);
1788peer_miss_err:
1789        mlx5_eswitch_del_send_to_vport_meta_rules(esw);
1790meta_rule_err:
1791        if (esw->fdb_table.offloads.send_to_vport_meta_grp)
1792                mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_meta_grp);
1793send_vport_meta_err:
1794        mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
1795send_vport_err:
1796        esw_chains_destroy(esw, esw_chains(esw));
1797fdb_chains_err:
1798        mlx5_destroy_flow_table(esw->fdb_table.offloads.tc_miss_table);
1799tc_miss_table_err:
1800        mlx5_destroy_flow_table(esw->fdb_table.offloads.slow_fdb);
1801slow_fdb_err:
1802        /* Holds true only as long as DMFS is the default */
1803        mlx5_flow_namespace_set_mode(root_ns, MLX5_FLOW_STEERING_MODE_DMFS);
1804ns_err:
1805        kvfree(flow_group_in);
1806        return err;
1807}
1808
1809static void esw_destroy_offloads_fdb_tables(struct mlx5_eswitch *esw)
1810{
1811        if (!esw->fdb_table.offloads.slow_fdb)
1812                return;
1813
1814        esw_debug(esw->dev, "Destroy offloads FDB Tables\n");
1815        mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_multi);
1816        mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_uni);
1817        mlx5_eswitch_del_send_to_vport_meta_rules(esw);
1818        mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
1819        if (esw->fdb_table.offloads.send_to_vport_meta_grp)
1820                mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_meta_grp);
1821        if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
1822                mlx5_destroy_flow_group(esw->fdb_table.offloads.peer_miss_grp);
1823        mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
1824
1825        esw_chains_destroy(esw, esw_chains(esw));
1826
1827        mlx5_destroy_flow_table(esw->fdb_table.offloads.tc_miss_table);
1828        mlx5_destroy_flow_table(esw->fdb_table.offloads.slow_fdb);
1829        /* Holds true only as long as DMFS is the default */
1830        mlx5_flow_namespace_set_mode(esw->fdb_table.offloads.ns,
1831                                     MLX5_FLOW_STEERING_MODE_DMFS);
1832        atomic64_set(&esw->user_count, 0);
1833}
1834
1835static int esw_create_offloads_table(struct mlx5_eswitch *esw)
1836{
1837        struct mlx5_flow_table_attr ft_attr = {};
1838        struct mlx5_core_dev *dev = esw->dev;
1839        struct mlx5_flow_table *ft_offloads;
1840        struct mlx5_flow_namespace *ns;
1841        int err = 0;
1842
1843        ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_OFFLOADS);
1844        if (!ns) {
1845                esw_warn(esw->dev, "Failed to get offloads flow namespace\n");
1846                return -EOPNOTSUPP;
1847        }
1848
1849        ft_attr.max_fte = esw->total_vports + MLX5_ESW_MISS_FLOWS;
1850        ft_attr.prio = 1;
1851
1852        ft_offloads = mlx5_create_flow_table(ns, &ft_attr);
1853        if (IS_ERR(ft_offloads)) {
1854                err = PTR_ERR(ft_offloads);
1855                esw_warn(esw->dev, "Failed to create offloads table, err %d\n", err);
1856                return err;
1857        }
1858
1859        esw->offloads.ft_offloads = ft_offloads;
1860        return 0;
1861}
1862
1863static void esw_destroy_offloads_table(struct mlx5_eswitch *esw)
1864{
1865        struct mlx5_esw_offload *offloads = &esw->offloads;
1866
1867        mlx5_destroy_flow_table(offloads->ft_offloads);
1868}
1869
1870static int esw_create_vport_rx_group(struct mlx5_eswitch *esw)
1871{
1872        int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
1873        struct mlx5_flow_group *g;
1874        u32 *flow_group_in;
1875        int nvports;
1876        int err = 0;
1877
1878        nvports = esw->total_vports + MLX5_ESW_MISS_FLOWS;
1879        flow_group_in = kvzalloc(inlen, GFP_KERNEL);
1880        if (!flow_group_in)
1881                return -ENOMEM;
1882
1883        /* create vport rx group */
1884        esw_set_flow_group_source_port(esw, flow_group_in);
1885
1886        MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
1887        MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, nvports - 1);
1888
1889        g = mlx5_create_flow_group(esw->offloads.ft_offloads, flow_group_in);
1890
1891        if (IS_ERR(g)) {
1892                err = PTR_ERR(g);
1893                mlx5_core_warn(esw->dev, "Failed to create vport rx group err %d\n", err);
1894                goto out;
1895        }
1896
1897        esw->offloads.vport_rx_group = g;
1898out:
1899        kvfree(flow_group_in);
1900        return err;
1901}
1902
1903static void esw_destroy_vport_rx_group(struct mlx5_eswitch *esw)
1904{
1905        mlx5_destroy_flow_group(esw->offloads.vport_rx_group);
1906}
1907
1908struct mlx5_flow_handle *
1909mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, u16 vport,
1910                                  struct mlx5_flow_destination *dest)
1911{
1912        struct mlx5_flow_act flow_act = {0};
1913        struct mlx5_flow_handle *flow_rule;
1914        struct mlx5_flow_spec *spec;
1915        void *misc;
1916
1917        spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1918        if (!spec) {
1919                flow_rule = ERR_PTR(-ENOMEM);
1920                goto out;
1921        }
1922
1923        if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
1924                misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters_2);
1925                MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0,
1926                         mlx5_eswitch_get_vport_metadata_for_match(esw, vport));
1927
1928                misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters_2);
1929                MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0,
1930                         mlx5_eswitch_get_vport_metadata_mask());
1931
1932                spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS_2;
1933        } else {
1934                misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
1935                MLX5_SET(fte_match_set_misc, misc, source_port, vport);
1936
1937                misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
1938                MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
1939
1940                spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
1941        }
1942
1943        flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
1944        flow_rule = mlx5_add_flow_rules(esw->offloads.ft_offloads, spec,
1945                                        &flow_act, dest, 1);
1946        if (IS_ERR(flow_rule)) {
1947                esw_warn(esw->dev, "fs offloads: Failed to add vport rx rule err %ld\n", PTR_ERR(flow_rule));
1948                goto out;
1949        }
1950
1951out:
1952        kvfree(spec);
1953        return flow_rule;
1954}
1955
1956static int mlx5_eswitch_inline_mode_get(struct mlx5_eswitch *esw, u8 *mode)
1957{
1958        u8 prev_mlx5_mode, mlx5_mode = MLX5_INLINE_MODE_L2;
1959        struct mlx5_core_dev *dev = esw->dev;
1960        struct mlx5_vport *vport;
1961        unsigned long i;
1962
1963        if (!MLX5_CAP_GEN(dev, vport_group_manager))
1964                return -EOPNOTSUPP;
1965
1966        if (esw->mode == MLX5_ESWITCH_NONE)
1967                return -EOPNOTSUPP;
1968
1969        switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
1970        case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
1971                mlx5_mode = MLX5_INLINE_MODE_NONE;
1972                goto out;
1973        case MLX5_CAP_INLINE_MODE_L2:
1974                mlx5_mode = MLX5_INLINE_MODE_L2;
1975                goto out;
1976        case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
1977                goto query_vports;
1978        }
1979
1980query_vports:
1981        mlx5_query_nic_vport_min_inline(dev, esw->first_host_vport, &prev_mlx5_mode);
1982        mlx5_esw_for_each_host_func_vport(esw, i, vport, esw->esw_funcs.num_vfs) {
1983                mlx5_query_nic_vport_min_inline(dev, vport->vport, &mlx5_mode);
1984                if (prev_mlx5_mode != mlx5_mode)
1985                        return -EINVAL;
1986                prev_mlx5_mode = mlx5_mode;
1987        }
1988
1989out:
1990        *mode = mlx5_mode;
1991        return 0;
1992}
1993
1994static void esw_destroy_restore_table(struct mlx5_eswitch *esw)
1995{
1996        struct mlx5_esw_offload *offloads = &esw->offloads;
1997
1998        if (!mlx5_eswitch_reg_c1_loopback_supported(esw))
1999                return;
2000
2001        mlx5_modify_header_dealloc(esw->dev, offloads->restore_copy_hdr_id);
2002        mlx5_destroy_flow_group(offloads->restore_group);
2003        mlx5_destroy_flow_table(offloads->ft_offloads_restore);
2004}
2005
2006static int esw_create_restore_table(struct mlx5_eswitch *esw)
2007{
2008        u8 modact[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};
2009        int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
2010        struct mlx5_flow_table_attr ft_attr = {};
2011        struct mlx5_core_dev *dev = esw->dev;
2012        struct mlx5_flow_namespace *ns;
2013        struct mlx5_modify_hdr *mod_hdr;
2014        void *match_criteria, *misc;
2015        struct mlx5_flow_table *ft;
2016        struct mlx5_flow_group *g;
2017        u32 *flow_group_in;
2018        int err = 0;
2019
2020        if (!mlx5_eswitch_reg_c1_loopback_supported(esw))
2021                return 0;
2022
2023        ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_OFFLOADS);
2024        if (!ns) {
2025                esw_warn(esw->dev, "Failed to get offloads flow namespace\n");
2026                return -EOPNOTSUPP;
2027        }
2028
2029        flow_group_in = kvzalloc(inlen, GFP_KERNEL);
2030        if (!flow_group_in) {
2031                err = -ENOMEM;
2032                goto out_free;
2033        }
2034
2035        ft_attr.max_fte = 1 << ESW_REG_C0_USER_DATA_METADATA_BITS;
2036        ft = mlx5_create_flow_table(ns, &ft_attr);
2037        if (IS_ERR(ft)) {
2038                err = PTR_ERR(ft);
2039                esw_warn(esw->dev, "Failed to create restore table, err %d\n",
2040                         err);
2041                goto out_free;
2042        }
2043
2044        match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in,
2045                                      match_criteria);
2046        misc = MLX5_ADDR_OF(fte_match_param, match_criteria,
2047                            misc_parameters_2);
2048
2049        MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0,
2050                 ESW_REG_C0_USER_DATA_METADATA_MASK);
2051        MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
2052        MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index,
2053                 ft_attr.max_fte - 1);
2054        MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
2055                 MLX5_MATCH_MISC_PARAMETERS_2);
2056        g = mlx5_create_flow_group(ft, flow_group_in);
2057        if (IS_ERR(g)) {
2058                err = PTR_ERR(g);
2059                esw_warn(dev, "Failed to create restore flow group, err: %d\n",
2060                         err);
2061                goto err_group;
2062        }
2063
2064        MLX5_SET(copy_action_in, modact, action_type, MLX5_ACTION_TYPE_COPY);
2065        MLX5_SET(copy_action_in, modact, src_field,
2066                 MLX5_ACTION_IN_FIELD_METADATA_REG_C_1);
2067        MLX5_SET(copy_action_in, modact, dst_field,
2068                 MLX5_ACTION_IN_FIELD_METADATA_REG_B);
2069        mod_hdr = mlx5_modify_header_alloc(esw->dev,
2070                                           MLX5_FLOW_NAMESPACE_KERNEL, 1,
2071                                           modact);
2072        if (IS_ERR(mod_hdr)) {
2073                err = PTR_ERR(mod_hdr);
2074                esw_warn(dev, "Failed to create restore mod header, err: %d\n",
2075                         err);
2076                goto err_mod_hdr;
2077        }
2078
2079        esw->offloads.ft_offloads_restore = ft;
2080        esw->offloads.restore_group = g;
2081        esw->offloads.restore_copy_hdr_id = mod_hdr;
2082
2083        kvfree(flow_group_in);
2084
2085        return 0;
2086
2087err_mod_hdr:
2088        mlx5_destroy_flow_group(g);
2089err_group:
2090        mlx5_destroy_flow_table(ft);
2091out_free:
2092        kvfree(flow_group_in);
2093
2094        return err;
2095}
2096
2097static int esw_offloads_start(struct mlx5_eswitch *esw,
2098                              struct netlink_ext_ack *extack)
2099{
2100        int err, err1;
2101
2102        mlx5_eswitch_disable_locked(esw, false);
2103        err = mlx5_eswitch_enable_locked(esw, MLX5_ESWITCH_OFFLOADS,
2104                                         esw->dev->priv.sriov.num_vfs);
2105        if (err) {
2106                NL_SET_ERR_MSG_MOD(extack,
2107                                   "Failed setting eswitch to offloads");
2108                err1 = mlx5_eswitch_enable_locked(esw, MLX5_ESWITCH_LEGACY,
2109                                                  MLX5_ESWITCH_IGNORE_NUM_VFS);
2110                if (err1) {
2111                        NL_SET_ERR_MSG_MOD(extack,
2112                                           "Failed setting eswitch back to legacy");
2113                }
2114        }
2115        if (esw->offloads.inline_mode == MLX5_INLINE_MODE_NONE) {
2116                if (mlx5_eswitch_inline_mode_get(esw,
2117                                                 &esw->offloads.inline_mode)) {
2118                        esw->offloads.inline_mode = MLX5_INLINE_MODE_L2;
2119                        NL_SET_ERR_MSG_MOD(extack,
2120                                           "Inline mode is different between vports");
2121                }
2122        }
2123        return err;
2124}
2125
2126static void mlx5_esw_offloads_rep_mark_set(struct mlx5_eswitch *esw,
2127                                           struct mlx5_eswitch_rep *rep,
2128                                           xa_mark_t mark)
2129{
2130        bool mark_set;
2131
2132        /* Copy the mark from vport to its rep */
2133        mark_set = xa_get_mark(&esw->vports, rep->vport, mark);
2134        if (mark_set)
2135                xa_set_mark(&esw->offloads.vport_reps, rep->vport, mark);
2136}
2137
2138static int mlx5_esw_offloads_rep_init(struct mlx5_eswitch *esw, const struct mlx5_vport *vport)
2139{
2140        struct mlx5_eswitch_rep *rep;
2141        int rep_type;
2142        int err;
2143
2144        rep = kzalloc(sizeof(*rep), GFP_KERNEL);
2145        if (!rep)
2146                return -ENOMEM;
2147
2148        rep->vport = vport->vport;
2149        rep->vport_index = vport->index;
2150        for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++)
2151                atomic_set(&rep->rep_data[rep_type].state, REP_UNREGISTERED);
2152
2153        err = xa_insert(&esw->offloads.vport_reps, rep->vport, rep, GFP_KERNEL);
2154        if (err)
2155                goto insert_err;
2156
2157        mlx5_esw_offloads_rep_mark_set(esw, rep, MLX5_ESW_VPT_HOST_FN);
2158        mlx5_esw_offloads_rep_mark_set(esw, rep, MLX5_ESW_VPT_VF);
2159        mlx5_esw_offloads_rep_mark_set(esw, rep, MLX5_ESW_VPT_SF);
2160        return 0;
2161
2162insert_err:
2163        kfree(rep);
2164        return err;
2165}
2166
2167static void mlx5_esw_offloads_rep_cleanup(struct mlx5_eswitch *esw,
2168                                          struct mlx5_eswitch_rep *rep)
2169{
2170        xa_erase(&esw->offloads.vport_reps, rep->vport);
2171        kfree(rep);
2172}
2173
2174void esw_offloads_cleanup_reps(struct mlx5_eswitch *esw)
2175{
2176        struct mlx5_eswitch_rep *rep;
2177        unsigned long i;
2178
2179        mlx5_esw_for_each_rep(esw, i, rep)
2180                mlx5_esw_offloads_rep_cleanup(esw, rep);
2181        xa_destroy(&esw->offloads.vport_reps);
2182}
2183
2184int esw_offloads_init_reps(struct mlx5_eswitch *esw)
2185{
2186        struct mlx5_vport *vport;
2187        unsigned long i;
2188        int err;
2189
2190        xa_init(&esw->offloads.vport_reps);
2191
2192        mlx5_esw_for_each_vport(esw, i, vport) {
2193                err = mlx5_esw_offloads_rep_init(esw, vport);
2194                if (err)
2195                        goto err;
2196        }
2197        return 0;
2198
2199err:
2200        esw_offloads_cleanup_reps(esw);
2201        return err;
2202}
2203
2204static void __esw_offloads_unload_rep(struct mlx5_eswitch *esw,
2205                                      struct mlx5_eswitch_rep *rep, u8 rep_type)
2206{
2207        if (atomic_cmpxchg(&rep->rep_data[rep_type].state,
2208                           REP_LOADED, REP_REGISTERED) == REP_LOADED)
2209                esw->offloads.rep_ops[rep_type]->unload(rep);
2210}
2211
2212static void __unload_reps_sf_vport(struct mlx5_eswitch *esw, u8 rep_type)
2213{
2214        struct mlx5_eswitch_rep *rep;
2215        unsigned long i;
2216
2217        mlx5_esw_for_each_sf_rep(esw, i, rep)
2218                __esw_offloads_unload_rep(esw, rep, rep_type);
2219}
2220
2221static void __unload_reps_all_vport(struct mlx5_eswitch *esw, u8 rep_type)
2222{
2223        struct mlx5_eswitch_rep *rep;
2224        unsigned long i;
2225
2226        __unload_reps_sf_vport(esw, rep_type);
2227
2228        mlx5_esw_for_each_vf_rep(esw, i, rep)
2229                __esw_offloads_unload_rep(esw, rep, rep_type);
2230
2231        if (mlx5_ecpf_vport_exists(esw->dev)) {
2232                rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_ECPF);
2233                __esw_offloads_unload_rep(esw, rep, rep_type);
2234        }
2235
2236        if (mlx5_core_is_ecpf_esw_manager(esw->dev)) {
2237                rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_PF);
2238                __esw_offloads_unload_rep(esw, rep, rep_type);
2239        }
2240
2241        rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_UPLINK);
2242        __esw_offloads_unload_rep(esw, rep, rep_type);
2243}
2244
2245int mlx5_esw_offloads_rep_load(struct mlx5_eswitch *esw, u16 vport_num)
2246{
2247        struct mlx5_eswitch_rep *rep;
2248        int rep_type;
2249        int err;
2250
2251        rep = mlx5_eswitch_get_rep(esw, vport_num);
2252        for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++)
2253                if (atomic_cmpxchg(&rep->rep_data[rep_type].state,
2254                                   REP_REGISTERED, REP_LOADED) == REP_REGISTERED) {
2255                        err = esw->offloads.rep_ops[rep_type]->load(esw->dev, rep);
2256                        if (err)
2257                                goto err_reps;
2258                }
2259
2260        return 0;
2261
2262err_reps:
2263        atomic_set(&rep->rep_data[rep_type].state, REP_REGISTERED);
2264        for (--rep_type; rep_type >= 0; rep_type--)
2265                __esw_offloads_unload_rep(esw, rep, rep_type);
2266        return err;
2267}
2268
2269void mlx5_esw_offloads_rep_unload(struct mlx5_eswitch *esw, u16 vport_num)
2270{
2271        struct mlx5_eswitch_rep *rep;
2272        int rep_type;
2273
2274        rep = mlx5_eswitch_get_rep(esw, vport_num);
2275        for (rep_type = NUM_REP_TYPES - 1; rep_type >= 0; rep_type--)
2276                __esw_offloads_unload_rep(esw, rep, rep_type);
2277}
2278
2279int esw_offloads_load_rep(struct mlx5_eswitch *esw, u16 vport_num)
2280{
2281        int err;
2282
2283        if (esw->mode != MLX5_ESWITCH_OFFLOADS)
2284                return 0;
2285
2286        if (vport_num != MLX5_VPORT_UPLINK) {
2287                err = mlx5_esw_offloads_devlink_port_register(esw, vport_num);
2288                if (err)
2289                        return err;
2290        }
2291
2292        err = mlx5_esw_offloads_rep_load(esw, vport_num);
2293        if (err)
2294                goto load_err;
2295        return err;
2296
2297load_err:
2298        if (vport_num != MLX5_VPORT_UPLINK)
2299                mlx5_esw_offloads_devlink_port_unregister(esw, vport_num);
2300        return err;
2301}
2302
2303void esw_offloads_unload_rep(struct mlx5_eswitch *esw, u16 vport_num)
2304{
2305        if (esw->mode != MLX5_ESWITCH_OFFLOADS)
2306                return;
2307
2308        mlx5_esw_offloads_rep_unload(esw, vport_num);
2309
2310        if (vport_num != MLX5_VPORT_UPLINK)
2311                mlx5_esw_offloads_devlink_port_unregister(esw, vport_num);
2312}
2313
2314#define ESW_OFFLOADS_DEVCOM_PAIR        (0)
2315#define ESW_OFFLOADS_DEVCOM_UNPAIR      (1)
2316
2317static int mlx5_esw_offloads_pair(struct mlx5_eswitch *esw,
2318                                  struct mlx5_eswitch *peer_esw)
2319{
2320
2321        return esw_add_fdb_peer_miss_rules(esw, peer_esw->dev);
2322}
2323
2324static void mlx5_esw_offloads_unpair(struct mlx5_eswitch *esw)
2325{
2326#if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
2327        mlx5e_tc_clean_fdb_peer_flows(esw);
2328#endif
2329        esw_del_fdb_peer_miss_rules(esw);
2330}
2331
2332static int mlx5_esw_offloads_set_ns_peer(struct mlx5_eswitch *esw,
2333                                         struct mlx5_eswitch *peer_esw,
2334                                         bool pair)
2335{
2336        struct mlx5_flow_root_namespace *peer_ns;
2337        struct mlx5_flow_root_namespace *ns;
2338        int err;
2339
2340        peer_ns = peer_esw->dev->priv.steering->fdb_root_ns;
2341        ns = esw->dev->priv.steering->fdb_root_ns;
2342
2343        if (pair) {
2344                err = mlx5_flow_namespace_set_peer(ns, peer_ns);
2345                if (err)
2346                        return err;
2347
2348                err = mlx5_flow_namespace_set_peer(peer_ns, ns);
2349                if (err) {
2350                        mlx5_flow_namespace_set_peer(ns, NULL);
2351                        return err;
2352                }
2353        } else {
2354                mlx5_flow_namespace_set_peer(ns, NULL);
2355                mlx5_flow_namespace_set_peer(peer_ns, NULL);
2356        }
2357
2358        return 0;
2359}
2360
2361static int mlx5_esw_offloads_devcom_event(int event,
2362                                          void *my_data,
2363                                          void *event_data)
2364{
2365        struct mlx5_eswitch *esw = my_data;
2366        struct mlx5_devcom *devcom = esw->dev->priv.devcom;
2367        struct mlx5_eswitch *peer_esw = event_data;
2368        int err;
2369
2370        switch (event) {
2371        case ESW_OFFLOADS_DEVCOM_PAIR:
2372                if (mlx5_get_next_phys_dev(esw->dev) != peer_esw->dev)
2373                        break;
2374
2375                if (mlx5_eswitch_vport_match_metadata_enabled(esw) !=
2376                    mlx5_eswitch_vport_match_metadata_enabled(peer_esw))
2377                        break;
2378
2379                err = mlx5_esw_offloads_set_ns_peer(esw, peer_esw, true);
2380                if (err)
2381                        goto err_out;
2382                err = mlx5_esw_offloads_pair(esw, peer_esw);
2383                if (err)
2384                        goto err_peer;
2385
2386                err = mlx5_esw_offloads_pair(peer_esw, esw);
2387                if (err)
2388                        goto err_pair;
2389
2390                mlx5_devcom_set_paired(devcom, MLX5_DEVCOM_ESW_OFFLOADS, true);
2391                break;
2392
2393        case ESW_OFFLOADS_DEVCOM_UNPAIR:
2394                if (!mlx5_devcom_is_paired(devcom, MLX5_DEVCOM_ESW_OFFLOADS))
2395                        break;
2396
2397                mlx5_devcom_set_paired(devcom, MLX5_DEVCOM_ESW_OFFLOADS, false);
2398                mlx5_esw_offloads_unpair(peer_esw);
2399                mlx5_esw_offloads_unpair(esw);
2400                mlx5_esw_offloads_set_ns_peer(esw, peer_esw, false);
2401                break;
2402        }
2403
2404        return 0;
2405
2406err_pair:
2407        mlx5_esw_offloads_unpair(esw);
2408err_peer:
2409        mlx5_esw_offloads_set_ns_peer(esw, peer_esw, false);
2410err_out:
2411        mlx5_core_err(esw->dev, "esw offloads devcom event failure, event %u err %d",
2412                      event, err);
2413        return err;
2414}
2415
2416static void esw_offloads_devcom_init(struct mlx5_eswitch *esw)
2417{
2418        struct mlx5_devcom *devcom = esw->dev->priv.devcom;
2419
2420        INIT_LIST_HEAD(&esw->offloads.peer_flows);
2421        mutex_init(&esw->offloads.peer_mutex);
2422
2423        if (!MLX5_CAP_ESW(esw->dev, merged_eswitch))
2424                return;
2425
2426        mlx5_devcom_register_component(devcom,
2427                                       MLX5_DEVCOM_ESW_OFFLOADS,
2428                                       mlx5_esw_offloads_devcom_event,
2429                                       esw);
2430
2431        mlx5_devcom_send_event(devcom,
2432                               MLX5_DEVCOM_ESW_OFFLOADS,
2433                               ESW_OFFLOADS_DEVCOM_PAIR, esw);
2434}
2435
2436static void esw_offloads_devcom_cleanup(struct mlx5_eswitch *esw)
2437{
2438        struct mlx5_devcom *devcom = esw->dev->priv.devcom;
2439
2440        if (!MLX5_CAP_ESW(esw->dev, merged_eswitch))
2441                return;
2442
2443        mlx5_devcom_send_event(devcom, MLX5_DEVCOM_ESW_OFFLOADS,
2444                               ESW_OFFLOADS_DEVCOM_UNPAIR, esw);
2445
2446        mlx5_devcom_unregister_component(devcom, MLX5_DEVCOM_ESW_OFFLOADS);
2447}
2448
2449bool mlx5_esw_vport_match_metadata_supported(const struct mlx5_eswitch *esw)
2450{
2451        if (!MLX5_CAP_ESW(esw->dev, esw_uplink_ingress_acl))
2452                return false;
2453
2454        if (!(MLX5_CAP_ESW_FLOWTABLE(esw->dev, fdb_to_vport_reg_c_id) &
2455              MLX5_FDB_TO_VPORT_REG_C_0))
2456                return false;
2457
2458        if (!MLX5_CAP_ESW_FLOWTABLE(esw->dev, flow_source))
2459                return false;
2460
2461        if (mlx5_core_is_ecpf_esw_manager(esw->dev) ||
2462            mlx5_ecpf_vport_exists(esw->dev))
2463                return false;
2464
2465        return true;
2466}
2467
2468u32 mlx5_esw_match_metadata_alloc(struct mlx5_eswitch *esw)
2469{
2470        u32 vport_end_ida = (1 << ESW_VPORT_BITS) - 1;
2471        u32 max_pf_num = (1 << ESW_PFNUM_BITS) - 1;
2472        u32 pf_num;
2473        int id;
2474
2475        /* Only 4 bits of pf_num */
2476        pf_num = PCI_FUNC(esw->dev->pdev->devfn);
2477        if (pf_num > max_pf_num)
2478                return 0;
2479
2480        /* Metadata is 4 bits of PFNUM and 12 bits of unique id */
2481        /* Use only non-zero vport_id (1-4095) for all PF's */
2482        id = ida_alloc_range(&esw->offloads.vport_metadata_ida, 1, vport_end_ida, GFP_KERNEL);
2483        if (id < 0)
2484                return 0;
2485        id = (pf_num << ESW_VPORT_BITS) | id;
2486        return id;
2487}
2488
2489void mlx5_esw_match_metadata_free(struct mlx5_eswitch *esw, u32 metadata)
2490{
2491        u32 vport_bit_mask = (1 << ESW_VPORT_BITS) - 1;
2492
2493        /* Metadata contains only 12 bits of actual ida id */
2494        ida_free(&esw->offloads.vport_metadata_ida, metadata & vport_bit_mask);
2495}
2496
2497static int esw_offloads_vport_metadata_setup(struct mlx5_eswitch *esw,
2498                                             struct mlx5_vport *vport)
2499{
2500        vport->default_metadata = mlx5_esw_match_metadata_alloc(esw);
2501        vport->metadata = vport->default_metadata;
2502        return vport->metadata ? 0 : -ENOSPC;
2503}
2504
2505static void esw_offloads_vport_metadata_cleanup(struct mlx5_eswitch *esw,
2506                                                struct mlx5_vport *vport)
2507{
2508        if (!vport->default_metadata)
2509                return;
2510
2511        WARN_ON(vport->metadata != vport->default_metadata);
2512        mlx5_esw_match_metadata_free(esw, vport->default_metadata);
2513}
2514
2515static void esw_offloads_metadata_uninit(struct mlx5_eswitch *esw)
2516{
2517        struct mlx5_vport *vport;
2518        unsigned long i;
2519
2520        if (!mlx5_eswitch_vport_match_metadata_enabled(esw))
2521                return;
2522
2523        mlx5_esw_for_each_vport(esw, i, vport)
2524                esw_offloads_vport_metadata_cleanup(esw, vport);
2525}
2526
2527static int esw_offloads_metadata_init(struct mlx5_eswitch *esw)
2528{
2529        struct mlx5_vport *vport;
2530        unsigned long i;
2531        int err;
2532
2533        if (!mlx5_eswitch_vport_match_metadata_enabled(esw))
2534                return 0;
2535
2536        mlx5_esw_for_each_vport(esw, i, vport) {
2537                err = esw_offloads_vport_metadata_setup(esw, vport);
2538                if (err)
2539                        goto metadata_err;
2540        }
2541
2542        return 0;
2543
2544metadata_err:
2545        esw_offloads_metadata_uninit(esw);
2546        return err;
2547}
2548
2549int mlx5_esw_offloads_vport_metadata_set(struct mlx5_eswitch *esw, bool enable)
2550{
2551        int err = 0;
2552
2553        down_write(&esw->mode_lock);
2554        if (esw->mode != MLX5_ESWITCH_NONE) {
2555                err = -EBUSY;
2556                goto done;
2557        }
2558        if (!mlx5_esw_vport_match_metadata_supported(esw)) {
2559                err = -EOPNOTSUPP;
2560                goto done;
2561        }
2562        if (enable)
2563                esw->flags |= MLX5_ESWITCH_VPORT_MATCH_METADATA;
2564        else
2565                esw->flags &= ~MLX5_ESWITCH_VPORT_MATCH_METADATA;
2566done:
2567        up_write(&esw->mode_lock);
2568        return err;
2569}
2570
2571int
2572esw_vport_create_offloads_acl_tables(struct mlx5_eswitch *esw,
2573                                     struct mlx5_vport *vport)
2574{
2575        int err;
2576
2577        err = esw_acl_ingress_ofld_setup(esw, vport);
2578        if (err)
2579                return err;
2580
2581        err = esw_acl_egress_ofld_setup(esw, vport);
2582        if (err)
2583                goto egress_err;
2584
2585        return 0;
2586
2587egress_err:
2588        esw_acl_ingress_ofld_cleanup(esw, vport);
2589        return err;
2590}
2591
2592void
2593esw_vport_destroy_offloads_acl_tables(struct mlx5_eswitch *esw,
2594                                      struct mlx5_vport *vport)
2595{
2596        esw_acl_egress_ofld_cleanup(vport);
2597        esw_acl_ingress_ofld_cleanup(esw, vport);
2598}
2599
2600static int esw_create_uplink_offloads_acl_tables(struct mlx5_eswitch *esw)
2601{
2602        struct mlx5_vport *vport;
2603
2604        vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_UPLINK);
2605        if (IS_ERR(vport))
2606                return PTR_ERR(vport);
2607
2608        return esw_vport_create_offloads_acl_tables(esw, vport);
2609}
2610
2611static void esw_destroy_uplink_offloads_acl_tables(struct mlx5_eswitch *esw)
2612{
2613        struct mlx5_vport *vport;
2614
2615        vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_UPLINK);
2616        if (IS_ERR(vport))
2617                return;
2618
2619        esw_vport_destroy_offloads_acl_tables(esw, vport);
2620}
2621
2622static int esw_offloads_steering_init(struct mlx5_eswitch *esw)
2623{
2624        struct mlx5_esw_indir_table *indir;
2625        int err;
2626
2627        memset(&esw->fdb_table.offloads, 0, sizeof(struct offloads_fdb));
2628        mutex_init(&esw->fdb_table.offloads.vports.lock);
2629        hash_init(esw->fdb_table.offloads.vports.table);
2630        atomic64_set(&esw->user_count, 0);
2631
2632        indir = mlx5_esw_indir_table_init();
2633        if (IS_ERR(indir)) {
2634                err = PTR_ERR(indir);
2635                goto create_indir_err;
2636        }
2637        esw->fdb_table.offloads.indir = indir;
2638
2639        err = esw_create_uplink_offloads_acl_tables(esw);
2640        if (err)
2641                goto create_acl_err;
2642
2643        err = esw_create_offloads_table(esw);
2644        if (err)
2645                goto create_offloads_err;
2646
2647        err = esw_create_restore_table(esw);
2648        if (err)
2649                goto create_restore_err;
2650
2651        err = esw_create_offloads_fdb_tables(esw);
2652        if (err)
2653                goto create_fdb_err;
2654
2655        err = esw_create_vport_rx_group(esw);
2656        if (err)
2657                goto create_fg_err;
2658
2659        return 0;
2660
2661create_fg_err:
2662        esw_destroy_offloads_fdb_tables(esw);
2663create_fdb_err:
2664        esw_destroy_restore_table(esw);
2665create_restore_err:
2666        esw_destroy_offloads_table(esw);
2667create_offloads_err:
2668        esw_destroy_uplink_offloads_acl_tables(esw);
2669create_acl_err:
2670        mlx5_esw_indir_table_destroy(esw->fdb_table.offloads.indir);
2671create_indir_err:
2672        mutex_destroy(&esw->fdb_table.offloads.vports.lock);
2673        return err;
2674}
2675
2676static void esw_offloads_steering_cleanup(struct mlx5_eswitch *esw)
2677{
2678        esw_destroy_vport_rx_group(esw);
2679        esw_destroy_offloads_fdb_tables(esw);
2680        esw_destroy_restore_table(esw);
2681        esw_destroy_offloads_table(esw);
2682        esw_destroy_uplink_offloads_acl_tables(esw);
2683        mlx5_esw_indir_table_destroy(esw->fdb_table.offloads.indir);
2684        mutex_destroy(&esw->fdb_table.offloads.vports.lock);
2685}
2686
2687static void
2688esw_vfs_changed_event_handler(struct mlx5_eswitch *esw, const u32 *out)
2689{
2690        bool host_pf_disabled;
2691        u16 new_num_vfs;
2692
2693        new_num_vfs = MLX5_GET(query_esw_functions_out, out,
2694                               host_params_context.host_num_of_vfs);
2695        host_pf_disabled = MLX5_GET(query_esw_functions_out, out,
2696                                    host_params_context.host_pf_disabled);
2697
2698        if (new_num_vfs == esw->esw_funcs.num_vfs || host_pf_disabled)
2699                return;
2700
2701        /* Number of VFs can only change from "0 to x" or "x to 0". */
2702        if (esw->esw_funcs.num_vfs > 0) {
2703                mlx5_eswitch_unload_vf_vports(esw, esw->esw_funcs.num_vfs);
2704        } else {
2705                int err;
2706
2707                err = mlx5_eswitch_load_vf_vports(esw, new_num_vfs,
2708                                                  MLX5_VPORT_UC_ADDR_CHANGE);
2709                if (err)
2710                        return;
2711        }
2712        esw->esw_funcs.num_vfs = new_num_vfs;
2713}
2714
2715static void esw_functions_changed_event_handler(struct work_struct *work)
2716{
2717        struct mlx5_host_work *host_work;
2718        struct mlx5_eswitch *esw;
2719        const u32 *out;
2720
2721        host_work = container_of(work, struct mlx5_host_work, work);
2722        esw = host_work->esw;
2723
2724        out = mlx5_esw_query_functions(esw->dev);
2725        if (IS_ERR(out))
2726                goto out;
2727
2728        esw_vfs_changed_event_handler(esw, out);
2729        kvfree(out);
2730out:
2731        kfree(host_work);
2732}
2733
2734int mlx5_esw_funcs_changed_handler(struct notifier_block *nb, unsigned long type, void *data)
2735{
2736        struct mlx5_esw_functions *esw_funcs;
2737        struct mlx5_host_work *host_work;
2738        struct mlx5_eswitch *esw;
2739
2740        host_work = kzalloc(sizeof(*host_work), GFP_ATOMIC);
2741        if (!host_work)
2742                return NOTIFY_DONE;
2743
2744        esw_funcs = mlx5_nb_cof(nb, struct mlx5_esw_functions, nb);
2745        esw = container_of(esw_funcs, struct mlx5_eswitch, esw_funcs);
2746
2747        host_work->esw = esw;
2748
2749        INIT_WORK(&host_work->work, esw_functions_changed_event_handler);
2750        queue_work(esw->work_queue, &host_work->work);
2751
2752        return NOTIFY_OK;
2753}
2754
2755static int mlx5_esw_host_number_init(struct mlx5_eswitch *esw)
2756{
2757        const u32 *query_host_out;
2758
2759        if (!mlx5_core_is_ecpf_esw_manager(esw->dev))
2760                return 0;
2761
2762        query_host_out = mlx5_esw_query_functions(esw->dev);
2763        if (IS_ERR(query_host_out))
2764                return PTR_ERR(query_host_out);
2765
2766        /* Mark non local controller with non zero controller number. */
2767        esw->offloads.host_number = MLX5_GET(query_esw_functions_out, query_host_out,
2768                                             host_params_context.host_number);
2769        kvfree(query_host_out);
2770        return 0;
2771}
2772
2773bool mlx5_esw_offloads_controller_valid(const struct mlx5_eswitch *esw, u32 controller)
2774{
2775        /* Local controller is always valid */
2776        if (controller == 0)
2777                return true;
2778
2779        if (!mlx5_core_is_ecpf_esw_manager(esw->dev))
2780                return false;
2781
2782        /* External host number starts with zero in device */
2783        return (controller == esw->offloads.host_number + 1);
2784}
2785
2786int esw_offloads_enable(struct mlx5_eswitch *esw)
2787{
2788        struct mapping_ctx *reg_c0_obj_pool;
2789        struct mlx5_vport *vport;
2790        unsigned long i;
2791        int err;
2792
2793        if (MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, reformat) &&
2794            MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, decap))
2795                esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_BASIC;
2796        else
2797                esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_NONE;
2798
2799        mutex_init(&esw->offloads.termtbl_mutex);
2800        mlx5_rdma_enable_roce(esw->dev);
2801
2802        err = mlx5_esw_host_number_init(esw);
2803        if (err)
2804                goto err_metadata;
2805
2806        err = esw_offloads_metadata_init(esw);
2807        if (err)
2808                goto err_metadata;
2809
2810        err = esw_set_passing_vport_metadata(esw, true);
2811        if (err)
2812                goto err_vport_metadata;
2813
2814        reg_c0_obj_pool = mapping_create(sizeof(struct mlx5_mapped_obj),
2815                                         ESW_REG_C0_USER_DATA_METADATA_MASK,
2816                                         true);
2817        if (IS_ERR(reg_c0_obj_pool)) {
2818                err = PTR_ERR(reg_c0_obj_pool);
2819                goto err_pool;
2820        }
2821        esw->offloads.reg_c0_obj_pool = reg_c0_obj_pool;
2822
2823        err = esw_offloads_steering_init(esw);
2824        if (err)
2825                goto err_steering_init;
2826
2827        /* Representor will control the vport link state */
2828        mlx5_esw_for_each_vf_vport(esw, i, vport, esw->esw_funcs.num_vfs)
2829                vport->info.link_state = MLX5_VPORT_ADMIN_STATE_DOWN;
2830
2831        /* Uplink vport rep must load first. */
2832        err = esw_offloads_load_rep(esw, MLX5_VPORT_UPLINK);
2833        if (err)
2834                goto err_uplink;
2835
2836        err = mlx5_eswitch_enable_pf_vf_vports(esw, MLX5_VPORT_UC_ADDR_CHANGE);
2837        if (err)
2838                goto err_vports;
2839
2840        esw_offloads_devcom_init(esw);
2841
2842        return 0;
2843
2844err_vports:
2845        esw_offloads_unload_rep(esw, MLX5_VPORT_UPLINK);
2846err_uplink:
2847        esw_offloads_steering_cleanup(esw);
2848err_steering_init:
2849        mapping_destroy(reg_c0_obj_pool);
2850err_pool:
2851        esw_set_passing_vport_metadata(esw, false);
2852err_vport_metadata:
2853        esw_offloads_metadata_uninit(esw);
2854err_metadata:
2855        mlx5_rdma_disable_roce(esw->dev);
2856        mutex_destroy(&esw->offloads.termtbl_mutex);
2857        return err;
2858}
2859
2860static int esw_offloads_stop(struct mlx5_eswitch *esw,
2861                             struct netlink_ext_ack *extack)
2862{
2863        int err, err1;
2864
2865        mlx5_eswitch_disable_locked(esw, false);
2866        err = mlx5_eswitch_enable_locked(esw, MLX5_ESWITCH_LEGACY,
2867                                         MLX5_ESWITCH_IGNORE_NUM_VFS);
2868        if (err) {
2869                NL_SET_ERR_MSG_MOD(extack, "Failed setting eswitch to legacy");
2870                err1 = mlx5_eswitch_enable_locked(esw, MLX5_ESWITCH_OFFLOADS,
2871                                                  MLX5_ESWITCH_IGNORE_NUM_VFS);
2872                if (err1) {
2873                        NL_SET_ERR_MSG_MOD(extack,
2874                                           "Failed setting eswitch back to offloads");
2875                }
2876        }
2877
2878        return err;
2879}
2880
2881void esw_offloads_disable(struct mlx5_eswitch *esw)
2882{
2883        esw_offloads_devcom_cleanup(esw);
2884        mlx5_eswitch_disable_pf_vf_vports(esw);
2885        esw_offloads_unload_rep(esw, MLX5_VPORT_UPLINK);
2886        esw_set_passing_vport_metadata(esw, false);
2887        esw_offloads_steering_cleanup(esw);
2888        mapping_destroy(esw->offloads.reg_c0_obj_pool);
2889        esw_offloads_metadata_uninit(esw);
2890        mlx5_rdma_disable_roce(esw->dev);
2891        mutex_destroy(&esw->offloads.termtbl_mutex);
2892        esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_NONE;
2893}
2894
2895static int esw_mode_from_devlink(u16 mode, u16 *mlx5_mode)
2896{
2897        switch (mode) {
2898        case DEVLINK_ESWITCH_MODE_LEGACY:
2899                *mlx5_mode = MLX5_ESWITCH_LEGACY;
2900                break;
2901        case DEVLINK_ESWITCH_MODE_SWITCHDEV:
2902                *mlx5_mode = MLX5_ESWITCH_OFFLOADS;
2903                break;
2904        default:
2905                return -EINVAL;
2906        }
2907
2908        return 0;
2909}
2910
2911static int esw_mode_to_devlink(u16 mlx5_mode, u16 *mode)
2912{
2913        switch (mlx5_mode) {
2914        case MLX5_ESWITCH_LEGACY:
2915                *mode = DEVLINK_ESWITCH_MODE_LEGACY;
2916                break;
2917        case MLX5_ESWITCH_OFFLOADS:
2918                *mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
2919                break;
2920        default:
2921                return -EINVAL;
2922        }
2923
2924        return 0;
2925}
2926
2927static int esw_inline_mode_from_devlink(u8 mode, u8 *mlx5_mode)
2928{
2929        switch (mode) {
2930        case DEVLINK_ESWITCH_INLINE_MODE_NONE:
2931                *mlx5_mode = MLX5_INLINE_MODE_NONE;
2932                break;
2933        case DEVLINK_ESWITCH_INLINE_MODE_LINK:
2934                *mlx5_mode = MLX5_INLINE_MODE_L2;
2935                break;
2936        case DEVLINK_ESWITCH_INLINE_MODE_NETWORK:
2937                *mlx5_mode = MLX5_INLINE_MODE_IP;
2938                break;
2939        case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT:
2940                *mlx5_mode = MLX5_INLINE_MODE_TCP_UDP;
2941                break;
2942        default:
2943                return -EINVAL;
2944        }
2945
2946        return 0;
2947}
2948
2949static int esw_inline_mode_to_devlink(u8 mlx5_mode, u8 *mode)
2950{
2951        switch (mlx5_mode) {
2952        case MLX5_INLINE_MODE_NONE:
2953                *mode = DEVLINK_ESWITCH_INLINE_MODE_NONE;
2954                break;
2955        case MLX5_INLINE_MODE_L2:
2956                *mode = DEVLINK_ESWITCH_INLINE_MODE_LINK;
2957                break;
2958        case MLX5_INLINE_MODE_IP:
2959                *mode = DEVLINK_ESWITCH_INLINE_MODE_NETWORK;
2960                break;
2961        case MLX5_INLINE_MODE_TCP_UDP:
2962                *mode = DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT;
2963                break;
2964        default:
2965                return -EINVAL;
2966        }
2967
2968        return 0;
2969}
2970
2971static int eswitch_devlink_esw_mode_check(const struct mlx5_eswitch *esw)
2972{
2973        /* devlink commands in NONE eswitch mode are currently supported only
2974         * on ECPF.
2975         */
2976        return (esw->mode == MLX5_ESWITCH_NONE &&
2977                !mlx5_core_is_ecpf_esw_manager(esw->dev)) ? -EOPNOTSUPP : 0;
2978}
2979
2980int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
2981                                  struct netlink_ext_ack *extack)
2982{
2983        u16 cur_mlx5_mode, mlx5_mode = 0;
2984        struct mlx5_eswitch *esw;
2985        int err = 0;
2986
2987        esw = mlx5_devlink_eswitch_get(devlink);
2988        if (IS_ERR(esw))
2989                return PTR_ERR(esw);
2990
2991        if (esw_mode_from_devlink(mode, &mlx5_mode))
2992                return -EINVAL;
2993
2994        err = mlx5_esw_try_lock(esw);
2995        if (err < 0) {
2996                NL_SET_ERR_MSG_MOD(extack, "Can't change mode, E-Switch is busy");
2997                return err;
2998        }
2999        cur_mlx5_mode = err;
3000        err = 0;
3001
3002        if (cur_mlx5_mode == mlx5_mode)
3003                goto unlock;
3004
3005        if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV) {
3006                if (mlx5_devlink_trap_get_num_active(esw->dev)) {
3007                        NL_SET_ERR_MSG_MOD(extack,
3008                                           "Can't change mode while devlink traps are active");
3009                        err = -EOPNOTSUPP;
3010                        goto unlock;
3011                }
3012                err = esw_offloads_start(esw, extack);
3013        } else if (mode == DEVLINK_ESWITCH_MODE_LEGACY) {
3014                err = esw_offloads_stop(esw, extack);
3015        } else {
3016                err = -EINVAL;
3017        }
3018
3019unlock:
3020        mlx5_esw_unlock(esw);
3021        return err;
3022}
3023
3024int mlx5_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
3025{
3026        struct mlx5_eswitch *esw;
3027        int err;
3028
3029        esw = mlx5_devlink_eswitch_get(devlink);
3030        if (IS_ERR(esw))
3031                return PTR_ERR(esw);
3032
3033        down_write(&esw->mode_lock);
3034        err = eswitch_devlink_esw_mode_check(esw);
3035        if (err)
3036                goto unlock;
3037
3038        err = esw_mode_to_devlink(esw->mode, mode);
3039unlock:
3040        up_write(&esw->mode_lock);
3041        return err;
3042}
3043
3044static int mlx5_esw_vports_inline_set(struct mlx5_eswitch *esw, u8 mlx5_mode,
3045                                      struct netlink_ext_ack *extack)
3046{
3047        struct mlx5_core_dev *dev = esw->dev;
3048        struct mlx5_vport *vport;
3049        u16 err_vport_num = 0;
3050        unsigned long i;
3051        int err = 0;
3052
3053        mlx5_esw_for_each_host_func_vport(esw, i, vport, esw->esw_funcs.num_vfs) {
3054                err = mlx5_modify_nic_vport_min_inline(dev, vport->vport, mlx5_mode);
3055                if (err) {
3056                        err_vport_num = vport->vport;
3057                        NL_SET_ERR_MSG_MOD(extack,
3058                                           "Failed to set min inline on vport");
3059                        goto revert_inline_mode;
3060                }
3061        }
3062        return 0;
3063
3064revert_inline_mode:
3065        mlx5_esw_for_each_host_func_vport(esw, i, vport, esw->esw_funcs.num_vfs) {
3066                if (vport->vport == err_vport_num)
3067                        break;
3068                mlx5_modify_nic_vport_min_inline(dev,
3069                                                 vport->vport,
3070                                                 esw->offloads.inline_mode);
3071        }
3072        return err;
3073}
3074
3075int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode,
3076                                         struct netlink_ext_ack *extack)
3077{
3078        struct mlx5_core_dev *dev = devlink_priv(devlink);
3079        struct mlx5_eswitch *esw;
3080        u8 mlx5_mode;
3081        int err;
3082
3083        esw = mlx5_devlink_eswitch_get(devlink);
3084        if (IS_ERR(esw))
3085                return PTR_ERR(esw);
3086
3087        down_write(&esw->mode_lock);
3088        err = eswitch_devlink_esw_mode_check(esw);
3089        if (err)
3090                goto out;
3091
3092        switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
3093        case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
3094                if (mode == DEVLINK_ESWITCH_INLINE_MODE_NONE)
3095                        goto out;
3096                fallthrough;
3097        case MLX5_CAP_INLINE_MODE_L2:
3098                NL_SET_ERR_MSG_MOD(extack, "Inline mode can't be set");
3099                err = -EOPNOTSUPP;
3100                goto out;
3101        case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
3102                break;
3103        }
3104
3105        if (atomic64_read(&esw->offloads.num_flows) > 0) {
3106                NL_SET_ERR_MSG_MOD(extack,
3107                                   "Can't set inline mode when flows are configured");
3108                err = -EOPNOTSUPP;
3109                goto out;
3110        }
3111
3112        err = esw_inline_mode_from_devlink(mode, &mlx5_mode);
3113        if (err)
3114                goto out;
3115
3116        err = mlx5_esw_vports_inline_set(esw, mlx5_mode, extack);
3117        if (err)
3118                goto out;
3119
3120        esw->offloads.inline_mode = mlx5_mode;
3121        up_write(&esw->mode_lock);
3122        return 0;
3123
3124out:
3125        up_write(&esw->mode_lock);
3126        return err;
3127}
3128
3129int mlx5_devlink_eswitch_inline_mode_get(struct devlink *devlink, u8 *mode)
3130{
3131        struct mlx5_eswitch *esw;
3132        int err;
3133
3134        esw = mlx5_devlink_eswitch_get(devlink);
3135        if (IS_ERR(esw))
3136                return PTR_ERR(esw);
3137
3138        down_write(&esw->mode_lock);
3139        err = eswitch_devlink_esw_mode_check(esw);
3140        if (err)
3141                goto unlock;
3142
3143        err = esw_inline_mode_to_devlink(esw->offloads.inline_mode, mode);
3144unlock:
3145        up_write(&esw->mode_lock);
3146        return err;
3147}
3148
3149int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink,
3150                                        enum devlink_eswitch_encap_mode encap,
3151                                        struct netlink_ext_ack *extack)
3152{
3153        struct mlx5_core_dev *dev = devlink_priv(devlink);
3154        struct mlx5_eswitch *esw;
3155        int err;
3156
3157        esw = mlx5_devlink_eswitch_get(devlink);
3158        if (IS_ERR(esw))
3159                return PTR_ERR(esw);
3160
3161        down_write(&esw->mode_lock);
3162        err = eswitch_devlink_esw_mode_check(esw);
3163        if (err)
3164                goto unlock;
3165
3166        if (encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE &&
3167            (!MLX5_CAP_ESW_FLOWTABLE_FDB(dev, reformat) ||
3168             !MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap))) {
3169                err = -EOPNOTSUPP;
3170                goto unlock;
3171        }
3172
3173        if (encap && encap != DEVLINK_ESWITCH_ENCAP_MODE_BASIC) {
3174                err = -EOPNOTSUPP;
3175                goto unlock;
3176        }
3177
3178        if (esw->mode == MLX5_ESWITCH_LEGACY) {
3179                esw->offloads.encap = encap;
3180                goto unlock;
3181        }
3182
3183        if (esw->offloads.encap == encap)
3184                goto unlock;
3185
3186        if (atomic64_read(&esw->offloads.num_flows) > 0) {
3187                NL_SET_ERR_MSG_MOD(extack,
3188                                   "Can't set encapsulation when flows are configured");
3189                err = -EOPNOTSUPP;
3190                goto unlock;
3191        }
3192
3193        esw_destroy_offloads_fdb_tables(esw);
3194
3195        esw->offloads.encap = encap;
3196
3197        err = esw_create_offloads_fdb_tables(esw);
3198
3199        if (err) {
3200                NL_SET_ERR_MSG_MOD(extack,
3201                                   "Failed re-creating fast FDB table");
3202                esw->offloads.encap = !encap;
3203                (void)esw_create_offloads_fdb_tables(esw);
3204        }
3205
3206unlock:
3207        up_write(&esw->mode_lock);
3208        return err;
3209}
3210
3211int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink,
3212                                        enum devlink_eswitch_encap_mode *encap)
3213{
3214        struct mlx5_eswitch *esw;
3215        int err;
3216
3217        esw = mlx5_devlink_eswitch_get(devlink);
3218        if (IS_ERR(esw))
3219                return PTR_ERR(esw);
3220
3221
3222        down_write(&esw->mode_lock);
3223        err = eswitch_devlink_esw_mode_check(esw);
3224        if (err)
3225                goto unlock;
3226
3227        *encap = esw->offloads.encap;
3228unlock:
3229        up_write(&esw->mode_lock);
3230        return 0;
3231}
3232
3233static bool
3234mlx5_eswitch_vport_has_rep(const struct mlx5_eswitch *esw, u16 vport_num)
3235{
3236        /* Currently, only ECPF based device has representor for host PF. */
3237        if (vport_num == MLX5_VPORT_PF &&
3238            !mlx5_core_is_ecpf_esw_manager(esw->dev))
3239                return false;
3240
3241        if (vport_num == MLX5_VPORT_ECPF &&
3242            !mlx5_ecpf_vport_exists(esw->dev))
3243                return false;
3244
3245        return true;
3246}
3247
3248void mlx5_eswitch_register_vport_reps(struct mlx5_eswitch *esw,
3249                                      const struct mlx5_eswitch_rep_ops *ops,
3250                                      u8 rep_type)
3251{
3252        struct mlx5_eswitch_rep_data *rep_data;
3253        struct mlx5_eswitch_rep *rep;
3254        unsigned long i;
3255
3256        esw->offloads.rep_ops[rep_type] = ops;
3257        mlx5_esw_for_each_rep(esw, i, rep) {
3258                if (likely(mlx5_eswitch_vport_has_rep(esw, rep->vport))) {
3259                        rep->esw = esw;
3260                        rep_data = &rep->rep_data[rep_type];
3261                        atomic_set(&rep_data->state, REP_REGISTERED);
3262                }
3263        }
3264}
3265EXPORT_SYMBOL(mlx5_eswitch_register_vport_reps);
3266
3267void mlx5_eswitch_unregister_vport_reps(struct mlx5_eswitch *esw, u8 rep_type)
3268{
3269        struct mlx5_eswitch_rep *rep;
3270        unsigned long i;
3271
3272        if (esw->mode == MLX5_ESWITCH_OFFLOADS)
3273                __unload_reps_all_vport(esw, rep_type);
3274
3275        mlx5_esw_for_each_rep(esw, i, rep)
3276                atomic_set(&rep->rep_data[rep_type].state, REP_UNREGISTERED);
3277}
3278EXPORT_SYMBOL(mlx5_eswitch_unregister_vport_reps);
3279
3280void *mlx5_eswitch_get_uplink_priv(struct mlx5_eswitch *esw, u8 rep_type)
3281{
3282        struct mlx5_eswitch_rep *rep;
3283
3284        rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_UPLINK);
3285        return rep->rep_data[rep_type].priv;
3286}
3287
3288void *mlx5_eswitch_get_proto_dev(struct mlx5_eswitch *esw,
3289                                 u16 vport,
3290                                 u8 rep_type)
3291{
3292        struct mlx5_eswitch_rep *rep;
3293
3294        rep = mlx5_eswitch_get_rep(esw, vport);
3295
3296        if (atomic_read(&rep->rep_data[rep_type].state) == REP_LOADED &&
3297            esw->offloads.rep_ops[rep_type]->get_proto_dev)
3298                return esw->offloads.rep_ops[rep_type]->get_proto_dev(rep);
3299        return NULL;
3300}
3301EXPORT_SYMBOL(mlx5_eswitch_get_proto_dev);
3302
3303void *mlx5_eswitch_uplink_get_proto_dev(struct mlx5_eswitch *esw, u8 rep_type)
3304{
3305        return mlx5_eswitch_get_proto_dev(esw, MLX5_VPORT_UPLINK, rep_type);
3306}
3307EXPORT_SYMBOL(mlx5_eswitch_uplink_get_proto_dev);
3308
3309struct mlx5_eswitch_rep *mlx5_eswitch_vport_rep(struct mlx5_eswitch *esw,
3310                                                u16 vport)
3311{
3312        return mlx5_eswitch_get_rep(esw, vport);
3313}
3314EXPORT_SYMBOL(mlx5_eswitch_vport_rep);
3315
3316bool mlx5_eswitch_reg_c1_loopback_enabled(const struct mlx5_eswitch *esw)
3317{
3318        return !!(esw->flags & MLX5_ESWITCH_REG_C1_LOOPBACK_ENABLED);
3319}
3320EXPORT_SYMBOL(mlx5_eswitch_reg_c1_loopback_enabled);
3321
3322bool mlx5_eswitch_vport_match_metadata_enabled(const struct mlx5_eswitch *esw)
3323{
3324        return !!(esw->flags & MLX5_ESWITCH_VPORT_MATCH_METADATA);
3325}
3326EXPORT_SYMBOL(mlx5_eswitch_vport_match_metadata_enabled);
3327
3328u32 mlx5_eswitch_get_vport_metadata_for_match(struct mlx5_eswitch *esw,
3329                                              u16 vport_num)
3330{
3331        struct mlx5_vport *vport = mlx5_eswitch_get_vport(esw, vport_num);
3332
3333        if (WARN_ON_ONCE(IS_ERR(vport)))
3334                return 0;
3335
3336        return vport->metadata << (32 - ESW_SOURCE_PORT_METADATA_BITS);
3337}
3338EXPORT_SYMBOL(mlx5_eswitch_get_vport_metadata_for_match);
3339
3340int mlx5_esw_offloads_sf_vport_enable(struct mlx5_eswitch *esw, struct devlink_port *dl_port,
3341                                      u16 vport_num, u32 controller, u32 sfnum)
3342{
3343        int err;
3344
3345        err = mlx5_esw_vport_enable(esw, vport_num, MLX5_VPORT_UC_ADDR_CHANGE);
3346        if (err)
3347                return err;
3348
3349        err = mlx5_esw_devlink_sf_port_register(esw, dl_port, vport_num, controller, sfnum);
3350        if (err)
3351                goto devlink_err;
3352
3353        err = mlx5_esw_offloads_rep_load(esw, vport_num);
3354        if (err)
3355                goto rep_err;
3356        return 0;
3357
3358rep_err:
3359        mlx5_esw_devlink_sf_port_unregister(esw, vport_num);
3360devlink_err:
3361        mlx5_esw_vport_disable(esw, vport_num);
3362        return err;
3363}
3364
3365void mlx5_esw_offloads_sf_vport_disable(struct mlx5_eswitch *esw, u16 vport_num)
3366{
3367        mlx5_esw_offloads_rep_unload(esw, vport_num);
3368        mlx5_esw_devlink_sf_port_unregister(esw, vport_num);
3369        mlx5_esw_vport_disable(esw, vport_num);
3370}
3371
3372static int mlx5_esw_query_vport_vhca_id(struct mlx5_eswitch *esw, u16 vport_num, u16 *vhca_id)
3373{
3374        int query_out_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
3375        void *query_ctx;
3376        void *hca_caps;
3377        int err;
3378
3379        *vhca_id = 0;
3380        if (mlx5_esw_is_manager_vport(esw, vport_num) ||
3381            !MLX5_CAP_GEN(esw->dev, vhca_resource_manager))
3382                return -EPERM;
3383
3384        query_ctx = kzalloc(query_out_sz, GFP_KERNEL);
3385        if (!query_ctx)
3386                return -ENOMEM;
3387
3388        err = mlx5_vport_get_other_func_cap(esw->dev, vport_num, query_ctx);
3389        if (err)
3390                goto out_free;
3391
3392        hca_caps = MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability);
3393        *vhca_id = MLX5_GET(cmd_hca_cap, hca_caps, vhca_id);
3394
3395out_free:
3396        kfree(query_ctx);
3397        return err;
3398}
3399
3400int mlx5_esw_vport_vhca_id_set(struct mlx5_eswitch *esw, u16 vport_num)
3401{
3402        u16 *old_entry, *vhca_map_entry, vhca_id;
3403        int err;
3404
3405        err = mlx5_esw_query_vport_vhca_id(esw, vport_num, &vhca_id);
3406        if (err) {
3407                esw_warn(esw->dev, "Getting vhca_id for vport failed (vport=%u,err=%d)\n",
3408                         vport_num, err);
3409                return err;
3410        }
3411
3412        vhca_map_entry = kmalloc(sizeof(*vhca_map_entry), GFP_KERNEL);
3413        if (!vhca_map_entry)
3414                return -ENOMEM;
3415
3416        *vhca_map_entry = vport_num;
3417        old_entry = xa_store(&esw->offloads.vhca_map, vhca_id, vhca_map_entry, GFP_KERNEL);
3418        if (xa_is_err(old_entry)) {
3419                kfree(vhca_map_entry);
3420                return xa_err(old_entry);
3421        }
3422        kfree(old_entry);
3423        return 0;
3424}
3425
3426void mlx5_esw_vport_vhca_id_clear(struct mlx5_eswitch *esw, u16 vport_num)
3427{
3428        u16 *vhca_map_entry, vhca_id;
3429        int err;
3430
3431        err = mlx5_esw_query_vport_vhca_id(esw, vport_num, &vhca_id);
3432        if (err)
3433                esw_warn(esw->dev, "Getting vhca_id for vport failed (vport=%hu,err=%d)\n",
3434                         vport_num, err);
3435
3436        vhca_map_entry = xa_erase(&esw->offloads.vhca_map, vhca_id);
3437        kfree(vhca_map_entry);
3438}
3439
3440int mlx5_eswitch_vhca_id_to_vport(struct mlx5_eswitch *esw, u16 vhca_id, u16 *vport_num)
3441{
3442        u16 *res = xa_load(&esw->offloads.vhca_map, vhca_id);
3443
3444        if (!res)
3445                return -ENOENT;
3446
3447        *vport_num = *res;
3448        return 0;
3449}
3450
3451u32 mlx5_eswitch_get_vport_metadata_for_set(struct mlx5_eswitch *esw,
3452                                            u16 vport_num)
3453{
3454        struct mlx5_vport *vport = mlx5_eswitch_get_vport(esw, vport_num);
3455
3456        if (WARN_ON_ONCE(IS_ERR(vport)))
3457                return 0;
3458
3459        return vport->metadata;
3460}
3461EXPORT_SYMBOL(mlx5_eswitch_get_vport_metadata_for_set);
3462