linux/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2015, Mellanox Technologies. All rights reserved.
   3 *
   4 * This software is available to you under a choice of one of two
   5 * licenses.  You may choose to be licensed under the terms of the GNU
   6 * General Public License (GPL) Version 2, available from the file
   7 * COPYING in the main directory of this source tree, or the
   8 * OpenIB.org BSD license below:
   9 *
  10 *     Redistribution and use in source and binary forms, with or
  11 *     without modification, are permitted provided that the following
  12 *     conditions are met:
  13 *
  14 *      - Redistributions of source code must retain the above
  15 *        copyright notice, this list of conditions and the following
  16 *        disclaimer.
  17 *
  18 *      - Redistributions in binary form must reproduce the above
  19 *        copyright notice, this list of conditions and the following
  20 *        disclaimer in the documentation and/or other materials
  21 *        provided with the distribution.
  22 *
  23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  30 * SOFTWARE.
  31 */
  32
  33#include <linux/mutex.h>
  34#include <linux/mlx5/driver.h>
  35
  36#include "mlx5_core.h"
  37#include "fs_core.h"
  38#include "fs_cmd.h"
  39
  40#define INIT_TREE_NODE_ARRAY_SIZE(...)  (sizeof((struct init_tree_node[]){__VA_ARGS__}) /\
  41                                         sizeof(struct init_tree_node))
  42
  43#define ADD_PRIO(num_prios_val, min_level_val, num_levels_val, caps_val,\
  44                 ...) {.type = FS_TYPE_PRIO,\
  45        .min_ft_level = min_level_val,\
  46        .num_levels = num_levels_val,\
  47        .num_leaf_prios = num_prios_val,\
  48        .caps = caps_val,\
  49        .children = (struct init_tree_node[]) {__VA_ARGS__},\
  50        .ar_size = INIT_TREE_NODE_ARRAY_SIZE(__VA_ARGS__) \
  51}
  52
  53#define ADD_MULTIPLE_PRIO(num_prios_val, num_levels_val, ...)\
  54        ADD_PRIO(num_prios_val, 0, num_levels_val, {},\
  55                 __VA_ARGS__)\
  56
  57#define ADD_NS(...) {.type = FS_TYPE_NAMESPACE,\
  58        .children = (struct init_tree_node[]) {__VA_ARGS__},\
  59        .ar_size = INIT_TREE_NODE_ARRAY_SIZE(__VA_ARGS__) \
  60}
  61
  62#define INIT_CAPS_ARRAY_SIZE(...) (sizeof((long[]){__VA_ARGS__}) /\
  63                                   sizeof(long))
  64
  65#define FS_CAP(cap) (__mlx5_bit_off(flow_table_nic_cap, cap))
  66
  67#define FS_REQUIRED_CAPS(...) {.arr_sz = INIT_CAPS_ARRAY_SIZE(__VA_ARGS__), \
  68                               .caps = (long[]) {__VA_ARGS__} }
  69
  70#define LEFTOVERS_NUM_LEVELS 1
  71#define LEFTOVERS_NUM_PRIOS 1
  72
  73#define BY_PASS_PRIO_NUM_LEVELS 1
  74#define BY_PASS_MIN_LEVEL (KERNEL_MIN_LEVEL + MLX5_BY_PASS_NUM_PRIOS +\
  75                           LEFTOVERS_NUM_PRIOS)
  76
  77/* Vlan, mac, ttc, aRFS */
  78#define KERNEL_NIC_PRIO_NUM_LEVELS 4
  79#define KERNEL_NIC_NUM_PRIOS 1
  80/* One more level for tc */
  81#define KERNEL_MIN_LEVEL (KERNEL_NIC_PRIO_NUM_LEVELS + 1)
  82
  83#define ANCHOR_NUM_LEVELS 1
  84#define ANCHOR_NUM_PRIOS 1
  85#define ANCHOR_MIN_LEVEL (BY_PASS_MIN_LEVEL + 1)
  86struct node_caps {
  87        size_t  arr_sz;
  88        long    *caps;
  89};
  90static struct init_tree_node {
  91        enum fs_node_type       type;
  92        struct init_tree_node *children;
  93        int ar_size;
  94        struct node_caps caps;
  95        int min_ft_level;
  96        int num_leaf_prios;
  97        int prio;
  98        int num_levels;
  99} root_fs = {
 100        .type = FS_TYPE_NAMESPACE,
 101        .ar_size = 4,
 102        .children = (struct init_tree_node[]) {
 103                ADD_PRIO(0, BY_PASS_MIN_LEVEL, 0,
 104                         FS_REQUIRED_CAPS(FS_CAP(flow_table_properties_nic_receive.flow_modify_en),
 105                                          FS_CAP(flow_table_properties_nic_receive.modify_root),
 106                                          FS_CAP(flow_table_properties_nic_receive.identified_miss_table_mode),
 107                                          FS_CAP(flow_table_properties_nic_receive.flow_table_modify)),
 108                         ADD_NS(ADD_MULTIPLE_PRIO(MLX5_BY_PASS_NUM_PRIOS,
 109                                                  BY_PASS_PRIO_NUM_LEVELS))),
 110                ADD_PRIO(0, KERNEL_MIN_LEVEL, 0, {},
 111                         ADD_NS(ADD_MULTIPLE_PRIO(1, 1),
 112                                ADD_MULTIPLE_PRIO(KERNEL_NIC_NUM_PRIOS,
 113                                                  KERNEL_NIC_PRIO_NUM_LEVELS))),
 114                ADD_PRIO(0, BY_PASS_MIN_LEVEL, 0,
 115                         FS_REQUIRED_CAPS(FS_CAP(flow_table_properties_nic_receive.flow_modify_en),
 116                                          FS_CAP(flow_table_properties_nic_receive.modify_root),
 117                                          FS_CAP(flow_table_properties_nic_receive.identified_miss_table_mode),
 118                                          FS_CAP(flow_table_properties_nic_receive.flow_table_modify)),
 119                         ADD_NS(ADD_MULTIPLE_PRIO(LEFTOVERS_NUM_PRIOS, LEFTOVERS_NUM_LEVELS))),
 120                ADD_PRIO(0, ANCHOR_MIN_LEVEL, 0, {},
 121                         ADD_NS(ADD_MULTIPLE_PRIO(ANCHOR_NUM_PRIOS, ANCHOR_NUM_LEVELS))),
 122        }
 123};
 124
 125enum fs_i_mutex_lock_class {
 126        FS_MUTEX_GRANDPARENT,
 127        FS_MUTEX_PARENT,
 128        FS_MUTEX_CHILD
 129};
 130
 131static void del_rule(struct fs_node *node);
 132static void del_flow_table(struct fs_node *node);
 133static void del_flow_group(struct fs_node *node);
 134static void del_fte(struct fs_node *node);
 135
 136static void tree_init_node(struct fs_node *node,
 137                           unsigned int refcount,
 138                           void (*remove_func)(struct fs_node *))
 139{
 140        atomic_set(&node->refcount, refcount);
 141        INIT_LIST_HEAD(&node->list);
 142        INIT_LIST_HEAD(&node->children);
 143        mutex_init(&node->lock);
 144        node->remove_func = remove_func;
 145}
 146
 147static void tree_add_node(struct fs_node *node, struct fs_node *parent)
 148{
 149        if (parent)
 150                atomic_inc(&parent->refcount);
 151        node->parent = parent;
 152
 153        /* Parent is the root */
 154        if (!parent)
 155                node->root = node;
 156        else
 157                node->root = parent->root;
 158}
 159
 160static void tree_get_node(struct fs_node *node)
 161{
 162        atomic_inc(&node->refcount);
 163}
 164
 165static void nested_lock_ref_node(struct fs_node *node,
 166                                 enum fs_i_mutex_lock_class class)
 167{
 168        if (node) {
 169                mutex_lock_nested(&node->lock, class);
 170                atomic_inc(&node->refcount);
 171        }
 172}
 173
 174static void lock_ref_node(struct fs_node *node)
 175{
 176        if (node) {
 177                mutex_lock(&node->lock);
 178                atomic_inc(&node->refcount);
 179        }
 180}
 181
 182static void unlock_ref_node(struct fs_node *node)
 183{
 184        if (node) {
 185                atomic_dec(&node->refcount);
 186                mutex_unlock(&node->lock);
 187        }
 188}
 189
 190static void tree_put_node(struct fs_node *node)
 191{
 192        struct fs_node *parent_node = node->parent;
 193
 194        lock_ref_node(parent_node);
 195        if (atomic_dec_and_test(&node->refcount)) {
 196                if (parent_node)
 197                        list_del_init(&node->list);
 198                if (node->remove_func)
 199                        node->remove_func(node);
 200                kfree(node);
 201                node = NULL;
 202        }
 203        unlock_ref_node(parent_node);
 204        if (!node && parent_node)
 205                tree_put_node(parent_node);
 206}
 207
 208static int tree_remove_node(struct fs_node *node)
 209{
 210        if (atomic_read(&node->refcount) > 1) {
 211                atomic_dec(&node->refcount);
 212                return -EEXIST;
 213        }
 214        tree_put_node(node);
 215        return 0;
 216}
 217
 218static struct fs_prio *find_prio(struct mlx5_flow_namespace *ns,
 219                                 unsigned int prio)
 220{
 221        struct fs_prio *iter_prio;
 222
 223        fs_for_each_prio(iter_prio, ns) {
 224                if (iter_prio->prio == prio)
 225                        return iter_prio;
 226        }
 227
 228        return NULL;
 229}
 230
 231static bool masked_memcmp(void *mask, void *val1, void *val2, size_t size)
 232{
 233        unsigned int i;
 234
 235        for (i = 0; i < size; i++, mask++, val1++, val2++)
 236                if ((*((u8 *)val1) & (*(u8 *)mask)) !=
 237                    ((*(u8 *)val2) & (*(u8 *)mask)))
 238                        return false;
 239
 240        return true;
 241}
 242
 243static bool compare_match_value(struct mlx5_flow_group_mask *mask,
 244                                void *fte_param1, void *fte_param2)
 245{
 246        if (mask->match_criteria_enable &
 247            1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_OUTER_HEADERS) {
 248                void *fte_match1 = MLX5_ADDR_OF(fte_match_param,
 249                                                fte_param1, outer_headers);
 250                void *fte_match2 = MLX5_ADDR_OF(fte_match_param,
 251                                                fte_param2, outer_headers);
 252                void *fte_mask = MLX5_ADDR_OF(fte_match_param,
 253                                              mask->match_criteria, outer_headers);
 254
 255                if (!masked_memcmp(fte_mask, fte_match1, fte_match2,
 256                                   MLX5_ST_SZ_BYTES(fte_match_set_lyr_2_4)))
 257                        return false;
 258        }
 259
 260        if (mask->match_criteria_enable &
 261            1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_MISC_PARAMETERS) {
 262                void *fte_match1 = MLX5_ADDR_OF(fte_match_param,
 263                                                fte_param1, misc_parameters);
 264                void *fte_match2 = MLX5_ADDR_OF(fte_match_param,
 265                                                fte_param2, misc_parameters);
 266                void *fte_mask = MLX5_ADDR_OF(fte_match_param,
 267                                          mask->match_criteria, misc_parameters);
 268
 269                if (!masked_memcmp(fte_mask, fte_match1, fte_match2,
 270                                   MLX5_ST_SZ_BYTES(fte_match_set_misc)))
 271                        return false;
 272        }
 273
 274        if (mask->match_criteria_enable &
 275            1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_INNER_HEADERS) {
 276                void *fte_match1 = MLX5_ADDR_OF(fte_match_param,
 277                                                fte_param1, inner_headers);
 278                void *fte_match2 = MLX5_ADDR_OF(fte_match_param,
 279                                                fte_param2, inner_headers);
 280                void *fte_mask = MLX5_ADDR_OF(fte_match_param,
 281                                          mask->match_criteria, inner_headers);
 282
 283                if (!masked_memcmp(fte_mask, fte_match1, fte_match2,
 284                                   MLX5_ST_SZ_BYTES(fte_match_set_lyr_2_4)))
 285                        return false;
 286        }
 287        return true;
 288}
 289
 290static bool compare_match_criteria(u8 match_criteria_enable1,
 291                                   u8 match_criteria_enable2,
 292                                   void *mask1, void *mask2)
 293{
 294        return match_criteria_enable1 == match_criteria_enable2 &&
 295                !memcmp(mask1, mask2, MLX5_ST_SZ_BYTES(fte_match_param));
 296}
 297
 298static struct mlx5_flow_root_namespace *find_root(struct fs_node *node)
 299{
 300        struct fs_node *root;
 301        struct mlx5_flow_namespace *ns;
 302
 303        root = node->root;
 304
 305        if (WARN_ON(root->type != FS_TYPE_NAMESPACE)) {
 306                pr_warn("mlx5: flow steering node is not in tree or garbaged\n");
 307                return NULL;
 308        }
 309
 310        ns = container_of(root, struct mlx5_flow_namespace, node);
 311        return container_of(ns, struct mlx5_flow_root_namespace, ns);
 312}
 313
 314static inline struct mlx5_core_dev *get_dev(struct fs_node *node)
 315{
 316        struct mlx5_flow_root_namespace *root = find_root(node);
 317
 318        if (root)
 319                return root->dev;
 320        return NULL;
 321}
 322
 323static void del_flow_table(struct fs_node *node)
 324{
 325        struct mlx5_flow_table *ft;
 326        struct mlx5_core_dev *dev;
 327        struct fs_prio *prio;
 328        int err;
 329
 330        fs_get_obj(ft, node);
 331        dev = get_dev(&ft->node);
 332
 333        err = mlx5_cmd_destroy_flow_table(dev, ft);
 334        if (err)
 335                pr_warn("flow steering can't destroy ft\n");
 336        fs_get_obj(prio, ft->node.parent);
 337        prio->num_ft--;
 338}
 339
 340static void del_rule(struct fs_node *node)
 341{
 342        struct mlx5_flow_rule *rule;
 343        struct mlx5_flow_table *ft;
 344        struct mlx5_flow_group *fg;
 345        struct fs_fte *fte;
 346        u32     *match_value;
 347        int modify_mask;
 348        struct mlx5_core_dev *dev = get_dev(node);
 349        int match_len = MLX5_ST_SZ_BYTES(fte_match_param);
 350        int err;
 351
 352        match_value = mlx5_vzalloc(match_len);
 353        if (!match_value) {
 354                pr_warn("failed to allocate inbox\n");
 355                return;
 356        }
 357
 358        fs_get_obj(rule, node);
 359        fs_get_obj(fte, rule->node.parent);
 360        fs_get_obj(fg, fte->node.parent);
 361        memcpy(match_value, fte->val, sizeof(fte->val));
 362        fs_get_obj(ft, fg->node.parent);
 363        list_del(&rule->node.list);
 364        if (rule->sw_action == MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO) {
 365                mutex_lock(&rule->dest_attr.ft->lock);
 366                list_del(&rule->next_ft);
 367                mutex_unlock(&rule->dest_attr.ft->lock);
 368        }
 369        if ((fte->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) &&
 370            --fte->dests_size) {
 371                modify_mask = BIT(MLX5_SET_FTE_MODIFY_ENABLE_MASK_DESTINATION_LIST),
 372                err = mlx5_cmd_update_fte(dev, ft,
 373                                          fg->id,
 374                                          modify_mask,
 375                                          fte);
 376                if (err)
 377                        pr_warn("%s can't del rule fg id=%d fte_index=%d\n",
 378                                __func__, fg->id, fte->index);
 379        }
 380        kvfree(match_value);
 381}
 382
 383static void del_fte(struct fs_node *node)
 384{
 385        struct mlx5_flow_table *ft;
 386        struct mlx5_flow_group *fg;
 387        struct mlx5_core_dev *dev;
 388        struct fs_fte *fte;
 389        int err;
 390
 391        fs_get_obj(fte, node);
 392        fs_get_obj(fg, fte->node.parent);
 393        fs_get_obj(ft, fg->node.parent);
 394
 395        dev = get_dev(&ft->node);
 396        err = mlx5_cmd_delete_fte(dev, ft,
 397                                  fte->index);
 398        if (err)
 399                pr_warn("flow steering can't delete fte in index %d of flow group id %d\n",
 400                        fte->index, fg->id);
 401
 402        fte->status = 0;
 403        fg->num_ftes--;
 404}
 405
 406static void del_flow_group(struct fs_node *node)
 407{
 408        struct mlx5_flow_group *fg;
 409        struct mlx5_flow_table *ft;
 410        struct mlx5_core_dev *dev;
 411
 412        fs_get_obj(fg, node);
 413        fs_get_obj(ft, fg->node.parent);
 414        dev = get_dev(&ft->node);
 415
 416        if (mlx5_cmd_destroy_flow_group(dev, ft, fg->id))
 417                pr_warn("flow steering can't destroy fg %d of ft %d\n",
 418                        fg->id, ft->id);
 419}
 420
 421static struct fs_fte *alloc_fte(u8 action,
 422                                u32 flow_tag,
 423                                u32 *match_value,
 424                                unsigned int index)
 425{
 426        struct fs_fte *fte;
 427
 428        fte = kzalloc(sizeof(*fte), GFP_KERNEL);
 429        if (!fte)
 430                return ERR_PTR(-ENOMEM);
 431
 432        memcpy(fte->val, match_value, sizeof(fte->val));
 433        fte->node.type =  FS_TYPE_FLOW_ENTRY;
 434        fte->flow_tag = flow_tag;
 435        fte->index = index;
 436        fte->action = action;
 437
 438        return fte;
 439}
 440
 441static struct mlx5_flow_group *alloc_flow_group(u32 *create_fg_in)
 442{
 443        struct mlx5_flow_group *fg;
 444        void *match_criteria = MLX5_ADDR_OF(create_flow_group_in,
 445                                            create_fg_in, match_criteria);
 446        u8 match_criteria_enable = MLX5_GET(create_flow_group_in,
 447                                            create_fg_in,
 448                                            match_criteria_enable);
 449        fg = kzalloc(sizeof(*fg), GFP_KERNEL);
 450        if (!fg)
 451                return ERR_PTR(-ENOMEM);
 452
 453        fg->mask.match_criteria_enable = match_criteria_enable;
 454        memcpy(&fg->mask.match_criteria, match_criteria,
 455               sizeof(fg->mask.match_criteria));
 456        fg->node.type =  FS_TYPE_FLOW_GROUP;
 457        fg->start_index = MLX5_GET(create_flow_group_in, create_fg_in,
 458                                   start_flow_index);
 459        fg->max_ftes = MLX5_GET(create_flow_group_in, create_fg_in,
 460                                end_flow_index) - fg->start_index + 1;
 461        return fg;
 462}
 463
 464static struct mlx5_flow_table *alloc_flow_table(int level, u16 vport, int max_fte,
 465                                                enum fs_flow_table_type table_type)
 466{
 467        struct mlx5_flow_table *ft;
 468
 469        ft  = kzalloc(sizeof(*ft), GFP_KERNEL);
 470        if (!ft)
 471                return NULL;
 472
 473        ft->level = level;
 474        ft->node.type = FS_TYPE_FLOW_TABLE;
 475        ft->type = table_type;
 476        ft->vport = vport;
 477        ft->max_fte = max_fte;
 478        INIT_LIST_HEAD(&ft->fwd_rules);
 479        mutex_init(&ft->lock);
 480
 481        return ft;
 482}
 483
 484/* If reverse is false, then we search for the first flow table in the
 485 * root sub-tree from start(closest from right), else we search for the
 486 * last flow table in the root sub-tree till start(closest from left).
 487 */
 488static struct mlx5_flow_table *find_closest_ft_recursive(struct fs_node  *root,
 489                                                         struct list_head *start,
 490                                                         bool reverse)
 491{
 492#define list_advance_entry(pos, reverse)                \
 493        ((reverse) ? list_prev_entry(pos, list) : list_next_entry(pos, list))
 494
 495#define list_for_each_advance_continue(pos, head, reverse)      \
 496        for (pos = list_advance_entry(pos, reverse);            \
 497             &pos->list != (head);                              \
 498             pos = list_advance_entry(pos, reverse))
 499
 500        struct fs_node *iter = list_entry(start, struct fs_node, list);
 501        struct mlx5_flow_table *ft = NULL;
 502
 503        if (!root)
 504                return NULL;
 505
 506        list_for_each_advance_continue(iter, &root->children, reverse) {
 507                if (iter->type == FS_TYPE_FLOW_TABLE) {
 508                        fs_get_obj(ft, iter);
 509                        return ft;
 510                }
 511                ft = find_closest_ft_recursive(iter, &iter->children, reverse);
 512                if (ft)
 513                        return ft;
 514        }
 515
 516        return ft;
 517}
 518
 519/* If reverse if false then return the first flow table in next priority of
 520 * prio in the tree, else return the last flow table in the previous priority
 521 * of prio in the tree.
 522 */
 523static struct mlx5_flow_table *find_closest_ft(struct fs_prio *prio, bool reverse)
 524{
 525        struct mlx5_flow_table *ft = NULL;
 526        struct fs_node *curr_node;
 527        struct fs_node *parent;
 528
 529        parent = prio->node.parent;
 530        curr_node = &prio->node;
 531        while (!ft && parent) {
 532                ft = find_closest_ft_recursive(parent, &curr_node->list, reverse);
 533                curr_node = parent;
 534                parent = curr_node->parent;
 535        }
 536        return ft;
 537}
 538
 539/* Assuming all the tree is locked by mutex chain lock */
 540static struct mlx5_flow_table *find_next_chained_ft(struct fs_prio *prio)
 541{
 542        return find_closest_ft(prio, false);
 543}
 544
 545/* Assuming all the tree is locked by mutex chain lock */
 546static struct mlx5_flow_table *find_prev_chained_ft(struct fs_prio *prio)
 547{
 548        return find_closest_ft(prio, true);
 549}
 550
 551static int connect_fts_in_prio(struct mlx5_core_dev *dev,
 552                               struct fs_prio *prio,
 553                               struct mlx5_flow_table *ft)
 554{
 555        struct mlx5_flow_table *iter;
 556        int i = 0;
 557        int err;
 558
 559        fs_for_each_ft(iter, prio) {
 560                i++;
 561                err = mlx5_cmd_modify_flow_table(dev,
 562                                                 iter,
 563                                                 ft);
 564                if (err) {
 565                        mlx5_core_warn(dev, "Failed to modify flow table %d\n",
 566                                       iter->id);
 567                        /* The driver is out of sync with the FW */
 568                        if (i > 1)
 569                                WARN_ON(true);
 570                        return err;
 571                }
 572        }
 573        return 0;
 574}
 575
 576/* Connect flow tables from previous priority of prio to ft */
 577static int connect_prev_fts(struct mlx5_core_dev *dev,
 578                            struct mlx5_flow_table *ft,
 579                            struct fs_prio *prio)
 580{
 581        struct mlx5_flow_table *prev_ft;
 582
 583        prev_ft = find_prev_chained_ft(prio);
 584        if (prev_ft) {
 585                struct fs_prio *prev_prio;
 586
 587                fs_get_obj(prev_prio, prev_ft->node.parent);
 588                return connect_fts_in_prio(dev, prev_prio, ft);
 589        }
 590        return 0;
 591}
 592
 593static int update_root_ft_create(struct mlx5_flow_table *ft, struct fs_prio
 594                                 *prio)
 595{
 596        struct mlx5_flow_root_namespace *root = find_root(&prio->node);
 597        int min_level = INT_MAX;
 598        int err;
 599
 600        if (root->root_ft)
 601                min_level = root->root_ft->level;
 602
 603        if (ft->level >= min_level)
 604                return 0;
 605
 606        err = mlx5_cmd_update_root_ft(root->dev, ft);
 607        if (err)
 608                mlx5_core_warn(root->dev, "Update root flow table of id=%u failed\n",
 609                               ft->id);
 610        else
 611                root->root_ft = ft;
 612
 613        return err;
 614}
 615
 616int mlx5_modify_rule_destination(struct mlx5_flow_rule *rule,
 617                                 struct mlx5_flow_destination *dest)
 618{
 619        struct mlx5_flow_table *ft;
 620        struct mlx5_flow_group *fg;
 621        struct fs_fte *fte;
 622        int modify_mask = BIT(MLX5_SET_FTE_MODIFY_ENABLE_MASK_DESTINATION_LIST);
 623        int err = 0;
 624
 625        fs_get_obj(fte, rule->node.parent);
 626        if (!(fte->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST))
 627                return -EINVAL;
 628        lock_ref_node(&fte->node);
 629        fs_get_obj(fg, fte->node.parent);
 630        fs_get_obj(ft, fg->node.parent);
 631
 632        memcpy(&rule->dest_attr, dest, sizeof(*dest));
 633        err = mlx5_cmd_update_fte(get_dev(&ft->node),
 634                                  ft, fg->id,
 635                                  modify_mask,
 636                                  fte);
 637        unlock_ref_node(&fte->node);
 638
 639        return err;
 640}
 641
 642/* Modify/set FWD rules that point on old_next_ft to point on new_next_ft  */
 643static int connect_fwd_rules(struct mlx5_core_dev *dev,
 644                             struct mlx5_flow_table *new_next_ft,
 645                             struct mlx5_flow_table *old_next_ft)
 646{
 647        struct mlx5_flow_destination dest;
 648        struct mlx5_flow_rule *iter;
 649        int err = 0;
 650
 651        /* new_next_ft and old_next_ft could be NULL only
 652         * when we create/destroy the anchor flow table.
 653         */
 654        if (!new_next_ft || !old_next_ft)
 655                return 0;
 656
 657        dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
 658        dest.ft = new_next_ft;
 659
 660        mutex_lock(&old_next_ft->lock);
 661        list_splice_init(&old_next_ft->fwd_rules, &new_next_ft->fwd_rules);
 662        mutex_unlock(&old_next_ft->lock);
 663        list_for_each_entry(iter, &new_next_ft->fwd_rules, next_ft) {
 664                err = mlx5_modify_rule_destination(iter, &dest);
 665                if (err)
 666                        pr_err("mlx5_core: failed to modify rule to point on flow table %d\n",
 667                               new_next_ft->id);
 668        }
 669        return 0;
 670}
 671
 672static int connect_flow_table(struct mlx5_core_dev *dev, struct mlx5_flow_table *ft,
 673                              struct fs_prio *prio)
 674{
 675        struct mlx5_flow_table *next_ft;
 676        int err = 0;
 677
 678        /* Connect_prev_fts and update_root_ft_create are mutually exclusive */
 679
 680        if (list_empty(&prio->node.children)) {
 681                err = connect_prev_fts(dev, ft, prio);
 682                if (err)
 683                        return err;
 684
 685                next_ft = find_next_chained_ft(prio);
 686                err = connect_fwd_rules(dev, ft, next_ft);
 687                if (err)
 688                        return err;
 689        }
 690
 691        if (MLX5_CAP_FLOWTABLE(dev,
 692                               flow_table_properties_nic_receive.modify_root))
 693                err = update_root_ft_create(ft, prio);
 694        return err;
 695}
 696
 697static void list_add_flow_table(struct mlx5_flow_table *ft,
 698                                struct fs_prio *prio)
 699{
 700        struct list_head *prev = &prio->node.children;
 701        struct mlx5_flow_table *iter;
 702
 703        fs_for_each_ft(iter, prio) {
 704                if (iter->level > ft->level)
 705                        break;
 706                prev = &iter->node.list;
 707        }
 708        list_add(&ft->node.list, prev);
 709}
 710
 711static struct mlx5_flow_table *__mlx5_create_flow_table(struct mlx5_flow_namespace *ns,
 712                                                        u16 vport, int prio,
 713                                                        int max_fte, u32 level)
 714{
 715        struct mlx5_flow_table *next_ft = NULL;
 716        struct mlx5_flow_table *ft;
 717        int err;
 718        int log_table_sz;
 719        struct mlx5_flow_root_namespace *root =
 720                find_root(&ns->node);
 721        struct fs_prio *fs_prio = NULL;
 722
 723        if (!root) {
 724                pr_err("mlx5: flow steering failed to find root of namespace\n");
 725                return ERR_PTR(-ENODEV);
 726        }
 727
 728        mutex_lock(&root->chain_lock);
 729        fs_prio = find_prio(ns, prio);
 730        if (!fs_prio) {
 731                err = -EINVAL;
 732                goto unlock_root;
 733        }
 734        if (level >= fs_prio->num_levels) {
 735                err = -ENOSPC;
 736                goto unlock_root;
 737        }
 738        /* The level is related to the
 739         * priority level range.
 740         */
 741        level += fs_prio->start_level;
 742        ft = alloc_flow_table(level,
 743                              vport,
 744                              roundup_pow_of_two(max_fte),
 745                              root->table_type);
 746        if (!ft) {
 747                err = -ENOMEM;
 748                goto unlock_root;
 749        }
 750
 751        tree_init_node(&ft->node, 1, del_flow_table);
 752        log_table_sz = ilog2(ft->max_fte);
 753        next_ft = find_next_chained_ft(fs_prio);
 754        err = mlx5_cmd_create_flow_table(root->dev, ft->vport, ft->type, ft->level,
 755                                         log_table_sz, next_ft, &ft->id);
 756        if (err)
 757                goto free_ft;
 758
 759        err = connect_flow_table(root->dev, ft, fs_prio);
 760        if (err)
 761                goto destroy_ft;
 762        lock_ref_node(&fs_prio->node);
 763        tree_add_node(&ft->node, &fs_prio->node);
 764        list_add_flow_table(ft, fs_prio);
 765        fs_prio->num_ft++;
 766        unlock_ref_node(&fs_prio->node);
 767        mutex_unlock(&root->chain_lock);
 768        return ft;
 769destroy_ft:
 770        mlx5_cmd_destroy_flow_table(root->dev, ft);
 771free_ft:
 772        kfree(ft);
 773unlock_root:
 774        mutex_unlock(&root->chain_lock);
 775        return ERR_PTR(err);
 776}
 777
 778struct mlx5_flow_table *mlx5_create_flow_table(struct mlx5_flow_namespace *ns,
 779                                               int prio, int max_fte,
 780                                               u32 level)
 781{
 782        return __mlx5_create_flow_table(ns, 0, prio, max_fte, level);
 783}
 784
 785struct mlx5_flow_table *mlx5_create_vport_flow_table(struct mlx5_flow_namespace *ns,
 786                                                     int prio, int max_fte,
 787                                                     u32 level, u16 vport)
 788{
 789        return __mlx5_create_flow_table(ns, vport, prio, max_fte, level);
 790}
 791
 792struct mlx5_flow_table *mlx5_create_auto_grouped_flow_table(struct mlx5_flow_namespace *ns,
 793                                                            int prio,
 794                                                            int num_flow_table_entries,
 795                                                            int max_num_groups,
 796                                                            u32 level)
 797{
 798        struct mlx5_flow_table *ft;
 799
 800        if (max_num_groups > num_flow_table_entries)
 801                return ERR_PTR(-EINVAL);
 802
 803        ft = mlx5_create_flow_table(ns, prio, num_flow_table_entries, level);
 804        if (IS_ERR(ft))
 805                return ft;
 806
 807        ft->autogroup.active = true;
 808        ft->autogroup.required_groups = max_num_groups;
 809
 810        return ft;
 811}
 812EXPORT_SYMBOL(mlx5_create_auto_grouped_flow_table);
 813
 814/* Flow table should be locked */
 815static struct mlx5_flow_group *create_flow_group_common(struct mlx5_flow_table *ft,
 816                                                        u32 *fg_in,
 817                                                        struct list_head
 818                                                        *prev_fg,
 819                                                        bool is_auto_fg)
 820{
 821        struct mlx5_flow_group *fg;
 822        struct mlx5_core_dev *dev = get_dev(&ft->node);
 823        int err;
 824
 825        if (!dev)
 826                return ERR_PTR(-ENODEV);
 827
 828        fg = alloc_flow_group(fg_in);
 829        if (IS_ERR(fg))
 830                return fg;
 831
 832        err = mlx5_cmd_create_flow_group(dev, ft, fg_in, &fg->id);
 833        if (err) {
 834                kfree(fg);
 835                return ERR_PTR(err);
 836        }
 837
 838        if (ft->autogroup.active)
 839                ft->autogroup.num_groups++;
 840        /* Add node to tree */
 841        tree_init_node(&fg->node, !is_auto_fg, del_flow_group);
 842        tree_add_node(&fg->node, &ft->node);
 843        /* Add node to group list */
 844        list_add(&fg->node.list, ft->node.children.prev);
 845
 846        return fg;
 847}
 848
 849struct mlx5_flow_group *mlx5_create_flow_group(struct mlx5_flow_table *ft,
 850                                               u32 *fg_in)
 851{
 852        struct mlx5_flow_group *fg;
 853
 854        if (ft->autogroup.active)
 855                return ERR_PTR(-EPERM);
 856
 857        lock_ref_node(&ft->node);
 858        fg = create_flow_group_common(ft, fg_in, &ft->node.children, false);
 859        unlock_ref_node(&ft->node);
 860
 861        return fg;
 862}
 863
 864static struct mlx5_flow_rule *alloc_rule(struct mlx5_flow_destination *dest)
 865{
 866        struct mlx5_flow_rule *rule;
 867
 868        rule = kzalloc(sizeof(*rule), GFP_KERNEL);
 869        if (!rule)
 870                return NULL;
 871
 872        INIT_LIST_HEAD(&rule->next_ft);
 873        rule->node.type = FS_TYPE_FLOW_DEST;
 874        if (dest)
 875                memcpy(&rule->dest_attr, dest, sizeof(*dest));
 876
 877        return rule;
 878}
 879
 880/* fte should not be deleted while calling this function */
 881static struct mlx5_flow_rule *add_rule_fte(struct fs_fte *fte,
 882                                           struct mlx5_flow_group *fg,
 883                                           struct mlx5_flow_destination *dest)
 884{
 885        struct mlx5_flow_table *ft;
 886        struct mlx5_flow_rule *rule;
 887        int modify_mask = 0;
 888        int err;
 889
 890        rule = alloc_rule(dest);
 891        if (!rule)
 892                return ERR_PTR(-ENOMEM);
 893
 894        fs_get_obj(ft, fg->node.parent);
 895        /* Add dest to dests list- we need flow tables to be in the
 896         * end of the list for forward to next prio rules.
 897         */
 898        tree_init_node(&rule->node, 1, del_rule);
 899        if (dest && dest->type != MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE)
 900                list_add(&rule->node.list, &fte->node.children);
 901        else
 902                list_add_tail(&rule->node.list, &fte->node.children);
 903        if (dest) {
 904                fte->dests_size++;
 905
 906                modify_mask |= dest->type == MLX5_FLOW_DESTINATION_TYPE_COUNTER ?
 907                        BIT(MLX5_SET_FTE_MODIFY_ENABLE_MASK_FLOW_COUNTERS) :
 908                        BIT(MLX5_SET_FTE_MODIFY_ENABLE_MASK_DESTINATION_LIST);
 909        }
 910
 911        if (fte->dests_size == 1 || !dest)
 912                err = mlx5_cmd_create_fte(get_dev(&ft->node),
 913                                          ft, fg->id, fte);
 914        else
 915                err = mlx5_cmd_update_fte(get_dev(&ft->node),
 916                                          ft, fg->id, modify_mask, fte);
 917        if (err)
 918                goto free_rule;
 919
 920        fte->status |= FS_FTE_STATUS_EXISTING;
 921
 922        return rule;
 923
 924free_rule:
 925        list_del(&rule->node.list);
 926        kfree(rule);
 927        if (dest)
 928                fte->dests_size--;
 929        return ERR_PTR(err);
 930}
 931
 932/* Assumed fg is locked */
 933static unsigned int get_free_fte_index(struct mlx5_flow_group *fg,
 934                                       struct list_head **prev)
 935{
 936        struct fs_fte *fte;
 937        unsigned int start = fg->start_index;
 938
 939        if (prev)
 940                *prev = &fg->node.children;
 941
 942        /* assumed list is sorted by index */
 943        fs_for_each_fte(fte, fg) {
 944                if (fte->index != start)
 945                        return start;
 946                start++;
 947                if (prev)
 948                        *prev = &fte->node.list;
 949        }
 950
 951        return start;
 952}
 953
 954/* prev is output, prev->next = new_fte */
 955static struct fs_fte *create_fte(struct mlx5_flow_group *fg,
 956                                 u32 *match_value,
 957                                 u8 action,
 958                                 u32 flow_tag,
 959                                 struct list_head **prev)
 960{
 961        struct fs_fte *fte;
 962        int index;
 963
 964        index = get_free_fte_index(fg, prev);
 965        fte = alloc_fte(action, flow_tag, match_value, index);
 966        if (IS_ERR(fte))
 967                return fte;
 968
 969        return fte;
 970}
 971
 972static struct mlx5_flow_group *create_autogroup(struct mlx5_flow_table *ft,
 973                                                u8 match_criteria_enable,
 974                                                u32 *match_criteria)
 975{
 976        int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
 977        struct list_head *prev = &ft->node.children;
 978        unsigned int candidate_index = 0;
 979        struct mlx5_flow_group *fg;
 980        void *match_criteria_addr;
 981        unsigned int group_size = 0;
 982        u32 *in;
 983
 984        if (!ft->autogroup.active)
 985                return ERR_PTR(-ENOENT);
 986
 987        in = mlx5_vzalloc(inlen);
 988        if (!in)
 989                return ERR_PTR(-ENOMEM);
 990
 991        if (ft->autogroup.num_groups < ft->autogroup.required_groups)
 992                /* We save place for flow groups in addition to max types */
 993                group_size = ft->max_fte / (ft->autogroup.required_groups + 1);
 994
 995        /*  ft->max_fte == ft->autogroup.max_types */
 996        if (group_size == 0)
 997                group_size = 1;
 998
 999        /* sorted by start_index */
1000        fs_for_each_fg(fg, ft) {
1001                if (candidate_index + group_size > fg->start_index)
1002                        candidate_index = fg->start_index + fg->max_ftes;
1003                else
1004                        break;
1005                prev = &fg->node.list;
1006        }
1007
1008        if (candidate_index + group_size > ft->max_fte) {
1009                fg = ERR_PTR(-ENOSPC);
1010                goto out;
1011        }
1012
1013        MLX5_SET(create_flow_group_in, in, match_criteria_enable,
1014                 match_criteria_enable);
1015        MLX5_SET(create_flow_group_in, in, start_flow_index, candidate_index);
1016        MLX5_SET(create_flow_group_in, in, end_flow_index,   candidate_index +
1017                 group_size - 1);
1018        match_criteria_addr = MLX5_ADDR_OF(create_flow_group_in,
1019                                           in, match_criteria);
1020        memcpy(match_criteria_addr, match_criteria,
1021               MLX5_ST_SZ_BYTES(fte_match_param));
1022
1023        fg = create_flow_group_common(ft, in, prev, true);
1024out:
1025        kvfree(in);
1026        return fg;
1027}
1028
1029static struct mlx5_flow_rule *find_flow_rule(struct fs_fte *fte,
1030                                             struct mlx5_flow_destination *dest)
1031{
1032        struct mlx5_flow_rule *rule;
1033
1034        list_for_each_entry(rule, &fte->node.children, node.list) {
1035                if (rule->dest_attr.type == dest->type) {
1036                        if ((dest->type == MLX5_FLOW_DESTINATION_TYPE_VPORT &&
1037                             dest->vport_num == rule->dest_attr.vport_num) ||
1038                            (dest->type == MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE &&
1039                             dest->ft == rule->dest_attr.ft) ||
1040                            (dest->type == MLX5_FLOW_DESTINATION_TYPE_TIR &&
1041                             dest->tir_num == rule->dest_attr.tir_num))
1042                                return rule;
1043                }
1044        }
1045        return NULL;
1046}
1047
1048static struct mlx5_flow_rule *add_rule_fg(struct mlx5_flow_group *fg,
1049                                          u32 *match_value,
1050                                          u8 action,
1051                                          u32 flow_tag,
1052                                          struct mlx5_flow_destination *dest)
1053{
1054        struct fs_fte *fte;
1055        struct mlx5_flow_rule *rule;
1056        struct mlx5_flow_table *ft;
1057        struct list_head *prev;
1058
1059        nested_lock_ref_node(&fg->node, FS_MUTEX_PARENT);
1060        fs_for_each_fte(fte, fg) {
1061                nested_lock_ref_node(&fte->node, FS_MUTEX_CHILD);
1062                if (compare_match_value(&fg->mask, match_value, &fte->val) &&
1063                    action == fte->action && flow_tag == fte->flow_tag) {
1064                        rule = find_flow_rule(fte, dest);
1065                        if (rule) {
1066                                atomic_inc(&rule->node.refcount);
1067                                unlock_ref_node(&fte->node);
1068                                unlock_ref_node(&fg->node);
1069                                return rule;
1070                        }
1071                        rule = add_rule_fte(fte, fg, dest);
1072                        unlock_ref_node(&fte->node);
1073                        if (IS_ERR(rule))
1074                                goto unlock_fg;
1075                        else
1076                                goto add_rule;
1077                }
1078                unlock_ref_node(&fte->node);
1079        }
1080        fs_get_obj(ft, fg->node.parent);
1081        if (fg->num_ftes >= fg->max_ftes) {
1082                rule = ERR_PTR(-ENOSPC);
1083                goto unlock_fg;
1084        }
1085
1086        fte = create_fte(fg, match_value, action, flow_tag, &prev);
1087        if (IS_ERR(fte)) {
1088                rule = (void *)fte;
1089                goto unlock_fg;
1090        }
1091        tree_init_node(&fte->node, 0, del_fte);
1092        rule = add_rule_fte(fte, fg, dest);
1093        if (IS_ERR(rule)) {
1094                kfree(fte);
1095                goto unlock_fg;
1096        }
1097
1098        fg->num_ftes++;
1099
1100        tree_add_node(&fte->node, &fg->node);
1101        list_add(&fte->node.list, prev);
1102add_rule:
1103        tree_add_node(&rule->node, &fte->node);
1104unlock_fg:
1105        unlock_ref_node(&fg->node);
1106        return rule;
1107}
1108
1109struct mlx5_fc *mlx5_flow_rule_counter(struct mlx5_flow_rule *rule)
1110{
1111        struct mlx5_flow_rule *dst;
1112        struct fs_fte *fte;
1113
1114        fs_get_obj(fte, rule->node.parent);
1115
1116        fs_for_each_dst(dst, fte) {
1117                if (dst->dest_attr.type == MLX5_FLOW_DESTINATION_TYPE_COUNTER)
1118                        return dst->dest_attr.counter;
1119        }
1120
1121        return NULL;
1122}
1123
1124static bool counter_is_valid(struct mlx5_fc *counter, u32 action)
1125{
1126        if (!(action & MLX5_FLOW_CONTEXT_ACTION_COUNT))
1127                return !counter;
1128
1129        if (!counter)
1130                return false;
1131
1132        /* Hardware support counter for a drop action only */
1133        return action == (MLX5_FLOW_CONTEXT_ACTION_DROP | MLX5_FLOW_CONTEXT_ACTION_COUNT);
1134}
1135
1136static bool dest_is_valid(struct mlx5_flow_destination *dest,
1137                          u32 action,
1138                          struct mlx5_flow_table *ft)
1139{
1140        if (dest && (dest->type == MLX5_FLOW_DESTINATION_TYPE_COUNTER))
1141                return counter_is_valid(dest->counter, action);
1142
1143        if (!(action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST))
1144                return true;
1145
1146        if (!dest || ((dest->type ==
1147            MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE) &&
1148            (dest->ft->level <= ft->level)))
1149                return false;
1150        return true;
1151}
1152
1153static struct mlx5_flow_rule *
1154_mlx5_add_flow_rule(struct mlx5_flow_table *ft,
1155                    u8 match_criteria_enable,
1156                    u32 *match_criteria,
1157                    u32 *match_value,
1158                    u32 action,
1159                    u32 flow_tag,
1160                    struct mlx5_flow_destination *dest)
1161{
1162        struct mlx5_flow_group *g;
1163        struct mlx5_flow_rule *rule;
1164
1165        if (!dest_is_valid(dest, action, ft))
1166                return ERR_PTR(-EINVAL);
1167
1168        nested_lock_ref_node(&ft->node, FS_MUTEX_GRANDPARENT);
1169        fs_for_each_fg(g, ft)
1170                if (compare_match_criteria(g->mask.match_criteria_enable,
1171                                           match_criteria_enable,
1172                                           g->mask.match_criteria,
1173                                           match_criteria)) {
1174                        rule = add_rule_fg(g, match_value,
1175                                           action, flow_tag, dest);
1176                        if (!IS_ERR(rule) || PTR_ERR(rule) != -ENOSPC)
1177                                goto unlock;
1178                }
1179
1180        g = create_autogroup(ft, match_criteria_enable, match_criteria);
1181        if (IS_ERR(g)) {
1182                rule = (void *)g;
1183                goto unlock;
1184        }
1185
1186        rule = add_rule_fg(g, match_value,
1187                           action, flow_tag, dest);
1188        if (IS_ERR(rule)) {
1189                /* Remove assumes refcount > 0 and autogroup creates a group
1190                 * with a refcount = 0.
1191                 */
1192                unlock_ref_node(&ft->node);
1193                tree_get_node(&g->node);
1194                tree_remove_node(&g->node);
1195                return rule;
1196        }
1197unlock:
1198        unlock_ref_node(&ft->node);
1199        return rule;
1200}
1201
1202static bool fwd_next_prio_supported(struct mlx5_flow_table *ft)
1203{
1204        return ((ft->type == FS_FT_NIC_RX) &&
1205                (MLX5_CAP_FLOWTABLE(get_dev(&ft->node), nic_rx_multi_path_tirs)));
1206}
1207
1208struct mlx5_flow_rule *
1209mlx5_add_flow_rule(struct mlx5_flow_table *ft,
1210                   u8 match_criteria_enable,
1211                   u32 *match_criteria,
1212                   u32 *match_value,
1213                   u32 action,
1214                   u32 flow_tag,
1215                   struct mlx5_flow_destination *dest)
1216{
1217        struct mlx5_flow_root_namespace *root = find_root(&ft->node);
1218        struct mlx5_flow_destination gen_dest;
1219        struct mlx5_flow_table *next_ft = NULL;
1220        struct mlx5_flow_rule *rule = NULL;
1221        u32 sw_action = action;
1222        struct fs_prio *prio;
1223
1224        fs_get_obj(prio, ft->node.parent);
1225        if (action == MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO) {
1226                if (!fwd_next_prio_supported(ft))
1227                        return ERR_PTR(-EOPNOTSUPP);
1228                if (dest)
1229                        return ERR_PTR(-EINVAL);
1230                mutex_lock(&root->chain_lock);
1231                next_ft = find_next_chained_ft(prio);
1232                if (next_ft) {
1233                        gen_dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
1234                        gen_dest.ft = next_ft;
1235                        dest = &gen_dest;
1236                        action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
1237                } else {
1238                        mutex_unlock(&root->chain_lock);
1239                        return ERR_PTR(-EOPNOTSUPP);
1240                }
1241        }
1242
1243        rule =  _mlx5_add_flow_rule(ft, match_criteria_enable, match_criteria,
1244                                    match_value, action, flow_tag, dest);
1245
1246        if (sw_action == MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO) {
1247                if (!IS_ERR_OR_NULL(rule) &&
1248                    (list_empty(&rule->next_ft))) {
1249                        mutex_lock(&next_ft->lock);
1250                        list_add(&rule->next_ft, &next_ft->fwd_rules);
1251                        mutex_unlock(&next_ft->lock);
1252                        rule->sw_action = MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO;
1253                }
1254                mutex_unlock(&root->chain_lock);
1255        }
1256        return rule;
1257}
1258EXPORT_SYMBOL(mlx5_add_flow_rule);
1259
1260void mlx5_del_flow_rule(struct mlx5_flow_rule *rule)
1261{
1262        tree_remove_node(&rule->node);
1263}
1264EXPORT_SYMBOL(mlx5_del_flow_rule);
1265
1266/* Assuming prio->node.children(flow tables) is sorted by level */
1267static struct mlx5_flow_table *find_next_ft(struct mlx5_flow_table *ft)
1268{
1269        struct fs_prio *prio;
1270
1271        fs_get_obj(prio, ft->node.parent);
1272
1273        if (!list_is_last(&ft->node.list, &prio->node.children))
1274                return list_next_entry(ft, node.list);
1275        return find_next_chained_ft(prio);
1276}
1277
1278static int update_root_ft_destroy(struct mlx5_flow_table *ft)
1279{
1280        struct mlx5_flow_root_namespace *root = find_root(&ft->node);
1281        struct mlx5_flow_table *new_root_ft = NULL;
1282
1283        if (root->root_ft != ft)
1284                return 0;
1285
1286        new_root_ft = find_next_ft(ft);
1287        if (new_root_ft) {
1288                int err = mlx5_cmd_update_root_ft(root->dev, new_root_ft);
1289
1290                if (err) {
1291                        mlx5_core_warn(root->dev, "Update root flow table of id=%u failed\n",
1292                                       ft->id);
1293                        return err;
1294                }
1295        }
1296        root->root_ft = new_root_ft;
1297        return 0;
1298}
1299
1300/* Connect flow table from previous priority to
1301 * the next flow table.
1302 */
1303static int disconnect_flow_table(struct mlx5_flow_table *ft)
1304{
1305        struct mlx5_core_dev *dev = get_dev(&ft->node);
1306        struct mlx5_flow_table *next_ft;
1307        struct fs_prio *prio;
1308        int err = 0;
1309
1310        err = update_root_ft_destroy(ft);
1311        if (err)
1312                return err;
1313
1314        fs_get_obj(prio, ft->node.parent);
1315        if  (!(list_first_entry(&prio->node.children,
1316                                struct mlx5_flow_table,
1317                                node.list) == ft))
1318                return 0;
1319
1320        next_ft = find_next_chained_ft(prio);
1321        err = connect_fwd_rules(dev, next_ft, ft);
1322        if (err)
1323                return err;
1324
1325        err = connect_prev_fts(dev, next_ft, prio);
1326        if (err)
1327                mlx5_core_warn(dev, "Failed to disconnect flow table %d\n",
1328                               ft->id);
1329        return err;
1330}
1331
1332int mlx5_destroy_flow_table(struct mlx5_flow_table *ft)
1333{
1334        struct mlx5_flow_root_namespace *root = find_root(&ft->node);
1335        int err = 0;
1336
1337        mutex_lock(&root->chain_lock);
1338        err = disconnect_flow_table(ft);
1339        if (err) {
1340                mutex_unlock(&root->chain_lock);
1341                return err;
1342        }
1343        if (tree_remove_node(&ft->node))
1344                mlx5_core_warn(get_dev(&ft->node), "Flow table %d wasn't destroyed, refcount > 1\n",
1345                               ft->id);
1346        mutex_unlock(&root->chain_lock);
1347
1348        return err;
1349}
1350EXPORT_SYMBOL(mlx5_destroy_flow_table);
1351
1352void mlx5_destroy_flow_group(struct mlx5_flow_group *fg)
1353{
1354        if (tree_remove_node(&fg->node))
1355                mlx5_core_warn(get_dev(&fg->node), "Flow group %d wasn't destroyed, refcount > 1\n",
1356                               fg->id);
1357}
1358
1359struct mlx5_flow_namespace *mlx5_get_flow_namespace(struct mlx5_core_dev *dev,
1360                                                    enum mlx5_flow_namespace_type type)
1361{
1362        struct mlx5_flow_root_namespace *root_ns = dev->priv.root_ns;
1363        int prio;
1364        struct fs_prio *fs_prio;
1365        struct mlx5_flow_namespace *ns;
1366
1367        if (!root_ns)
1368                return NULL;
1369
1370        switch (type) {
1371        case MLX5_FLOW_NAMESPACE_BYPASS:
1372        case MLX5_FLOW_NAMESPACE_KERNEL:
1373        case MLX5_FLOW_NAMESPACE_LEFTOVERS:
1374        case MLX5_FLOW_NAMESPACE_ANCHOR:
1375                prio = type;
1376                break;
1377        case MLX5_FLOW_NAMESPACE_FDB:
1378                if (dev->priv.fdb_root_ns)
1379                        return &dev->priv.fdb_root_ns->ns;
1380                else
1381                        return NULL;
1382        case MLX5_FLOW_NAMESPACE_ESW_EGRESS:
1383                if (dev->priv.esw_egress_root_ns)
1384                        return &dev->priv.esw_egress_root_ns->ns;
1385                else
1386                        return NULL;
1387        case MLX5_FLOW_NAMESPACE_ESW_INGRESS:
1388                if (dev->priv.esw_ingress_root_ns)
1389                        return &dev->priv.esw_ingress_root_ns->ns;
1390                else
1391                        return NULL;
1392        default:
1393                return NULL;
1394        }
1395
1396        fs_prio = find_prio(&root_ns->ns, prio);
1397        if (!fs_prio)
1398                return NULL;
1399
1400        ns = list_first_entry(&fs_prio->node.children,
1401                              typeof(*ns),
1402                              node.list);
1403
1404        return ns;
1405}
1406EXPORT_SYMBOL(mlx5_get_flow_namespace);
1407
1408static struct fs_prio *fs_create_prio(struct mlx5_flow_namespace *ns,
1409                                      unsigned int prio, int num_levels)
1410{
1411        struct fs_prio *fs_prio;
1412
1413        fs_prio = kzalloc(sizeof(*fs_prio), GFP_KERNEL);
1414        if (!fs_prio)
1415                return ERR_PTR(-ENOMEM);
1416
1417        fs_prio->node.type = FS_TYPE_PRIO;
1418        tree_init_node(&fs_prio->node, 1, NULL);
1419        tree_add_node(&fs_prio->node, &ns->node);
1420        fs_prio->num_levels = num_levels;
1421        fs_prio->prio = prio;
1422        list_add_tail(&fs_prio->node.list, &ns->node.children);
1423
1424        return fs_prio;
1425}
1426
1427static struct mlx5_flow_namespace *fs_init_namespace(struct mlx5_flow_namespace
1428                                                     *ns)
1429{
1430        ns->node.type = FS_TYPE_NAMESPACE;
1431
1432        return ns;
1433}
1434
1435static struct mlx5_flow_namespace *fs_create_namespace(struct fs_prio *prio)
1436{
1437        struct mlx5_flow_namespace      *ns;
1438
1439        ns = kzalloc(sizeof(*ns), GFP_KERNEL);
1440        if (!ns)
1441                return ERR_PTR(-ENOMEM);
1442
1443        fs_init_namespace(ns);
1444        tree_init_node(&ns->node, 1, NULL);
1445        tree_add_node(&ns->node, &prio->node);
1446        list_add_tail(&ns->node.list, &prio->node.children);
1447
1448        return ns;
1449}
1450
1451static int create_leaf_prios(struct mlx5_flow_namespace *ns, int prio,
1452                             struct init_tree_node *prio_metadata)
1453{
1454        struct fs_prio *fs_prio;
1455        int i;
1456
1457        for (i = 0; i < prio_metadata->num_leaf_prios; i++) {
1458                fs_prio = fs_create_prio(ns, prio++, prio_metadata->num_levels);
1459                if (IS_ERR(fs_prio))
1460                        return PTR_ERR(fs_prio);
1461        }
1462        return 0;
1463}
1464
1465#define FLOW_TABLE_BIT_SZ 1
1466#define GET_FLOW_TABLE_CAP(dev, offset) \
1467        ((be32_to_cpu(*((__be32 *)(dev->hca_caps_cur[MLX5_CAP_FLOW_TABLE]) +    \
1468                        offset / 32)) >>                                        \
1469          (32 - FLOW_TABLE_BIT_SZ - (offset & 0x1f))) & FLOW_TABLE_BIT_SZ)
1470static bool has_required_caps(struct mlx5_core_dev *dev, struct node_caps *caps)
1471{
1472        int i;
1473
1474        for (i = 0; i < caps->arr_sz; i++) {
1475                if (!GET_FLOW_TABLE_CAP(dev, caps->caps[i]))
1476                        return false;
1477        }
1478        return true;
1479}
1480
1481static int init_root_tree_recursive(struct mlx5_core_dev *dev,
1482                                    struct init_tree_node *init_node,
1483                                    struct fs_node *fs_parent_node,
1484                                    struct init_tree_node *init_parent_node,
1485                                    int prio)
1486{
1487        int max_ft_level = MLX5_CAP_FLOWTABLE(dev,
1488                                              flow_table_properties_nic_receive.
1489                                              max_ft_level);
1490        struct mlx5_flow_namespace *fs_ns;
1491        struct fs_prio *fs_prio;
1492        struct fs_node *base;
1493        int i;
1494        int err;
1495
1496        if (init_node->type == FS_TYPE_PRIO) {
1497                if ((init_node->min_ft_level > max_ft_level) ||
1498                    !has_required_caps(dev, &init_node->caps))
1499                        return 0;
1500
1501                fs_get_obj(fs_ns, fs_parent_node);
1502                if (init_node->num_leaf_prios)
1503                        return create_leaf_prios(fs_ns, prio, init_node);
1504                fs_prio = fs_create_prio(fs_ns, prio, init_node->num_levels);
1505                if (IS_ERR(fs_prio))
1506                        return PTR_ERR(fs_prio);
1507                base = &fs_prio->node;
1508        } else if (init_node->type == FS_TYPE_NAMESPACE) {
1509                fs_get_obj(fs_prio, fs_parent_node);
1510                fs_ns = fs_create_namespace(fs_prio);
1511                if (IS_ERR(fs_ns))
1512                        return PTR_ERR(fs_ns);
1513                base = &fs_ns->node;
1514        } else {
1515                return -EINVAL;
1516        }
1517        prio = 0;
1518        for (i = 0; i < init_node->ar_size; i++) {
1519                err = init_root_tree_recursive(dev, &init_node->children[i],
1520                                               base, init_node, prio);
1521                if (err)
1522                        return err;
1523                if (init_node->children[i].type == FS_TYPE_PRIO &&
1524                    init_node->children[i].num_leaf_prios) {
1525                        prio += init_node->children[i].num_leaf_prios;
1526                }
1527        }
1528
1529        return 0;
1530}
1531
1532static int init_root_tree(struct mlx5_core_dev *dev,
1533                          struct init_tree_node *init_node,
1534                          struct fs_node *fs_parent_node)
1535{
1536        int i;
1537        struct mlx5_flow_namespace *fs_ns;
1538        int err;
1539
1540        fs_get_obj(fs_ns, fs_parent_node);
1541        for (i = 0; i < init_node->ar_size; i++) {
1542                err = init_root_tree_recursive(dev, &init_node->children[i],
1543                                               &fs_ns->node,
1544                                               init_node, i);
1545                if (err)
1546                        return err;
1547        }
1548        return 0;
1549}
1550
1551static struct mlx5_flow_root_namespace *create_root_ns(struct mlx5_core_dev *dev,
1552                                                       enum fs_flow_table_type
1553                                                       table_type)
1554{
1555        struct mlx5_flow_root_namespace *root_ns;
1556        struct mlx5_flow_namespace *ns;
1557
1558        /* Create the root namespace */
1559        root_ns = mlx5_vzalloc(sizeof(*root_ns));
1560        if (!root_ns)
1561                return NULL;
1562
1563        root_ns->dev = dev;
1564        root_ns->table_type = table_type;
1565
1566        ns = &root_ns->ns;
1567        fs_init_namespace(ns);
1568        mutex_init(&root_ns->chain_lock);
1569        tree_init_node(&ns->node, 1, NULL);
1570        tree_add_node(&ns->node, NULL);
1571
1572        return root_ns;
1573}
1574
1575static void set_prio_attrs_in_prio(struct fs_prio *prio, int acc_level);
1576
1577static int set_prio_attrs_in_ns(struct mlx5_flow_namespace *ns, int acc_level)
1578{
1579        struct fs_prio *prio;
1580
1581        fs_for_each_prio(prio, ns) {
1582                 /* This updates prio start_level and num_levels */
1583                set_prio_attrs_in_prio(prio, acc_level);
1584                acc_level += prio->num_levels;
1585        }
1586        return acc_level;
1587}
1588
1589static void set_prio_attrs_in_prio(struct fs_prio *prio, int acc_level)
1590{
1591        struct mlx5_flow_namespace *ns;
1592        int acc_level_ns = acc_level;
1593
1594        prio->start_level = acc_level;
1595        fs_for_each_ns(ns, prio)
1596                /* This updates start_level and num_levels of ns's priority descendants */
1597                acc_level_ns = set_prio_attrs_in_ns(ns, acc_level);
1598        if (!prio->num_levels)
1599                prio->num_levels = acc_level_ns - prio->start_level;
1600        WARN_ON(prio->num_levels < acc_level_ns - prio->start_level);
1601}
1602
1603static void set_prio_attrs(struct mlx5_flow_root_namespace *root_ns)
1604{
1605        struct mlx5_flow_namespace *ns = &root_ns->ns;
1606        struct fs_prio *prio;
1607        int start_level = 0;
1608
1609        fs_for_each_prio(prio, ns) {
1610                set_prio_attrs_in_prio(prio, start_level);
1611                start_level += prio->num_levels;
1612        }
1613}
1614
1615#define ANCHOR_PRIO 0
1616#define ANCHOR_SIZE 1
1617#define ANCHOR_LEVEL 0
1618static int create_anchor_flow_table(struct mlx5_core_dev
1619                                                        *dev)
1620{
1621        struct mlx5_flow_namespace *ns = NULL;
1622        struct mlx5_flow_table *ft;
1623
1624        ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_ANCHOR);
1625        if (!ns)
1626                return -EINVAL;
1627        ft = mlx5_create_flow_table(ns, ANCHOR_PRIO, ANCHOR_SIZE, ANCHOR_LEVEL);
1628        if (IS_ERR(ft)) {
1629                mlx5_core_err(dev, "Failed to create last anchor flow table");
1630                return PTR_ERR(ft);
1631        }
1632        return 0;
1633}
1634
1635static int init_root_ns(struct mlx5_core_dev *dev)
1636{
1637
1638        dev->priv.root_ns = create_root_ns(dev, FS_FT_NIC_RX);
1639        if (IS_ERR_OR_NULL(dev->priv.root_ns))
1640                goto cleanup;
1641
1642        if (init_root_tree(dev, &root_fs, &dev->priv.root_ns->ns.node))
1643                goto cleanup;
1644
1645        set_prio_attrs(dev->priv.root_ns);
1646
1647        if (create_anchor_flow_table(dev))
1648                goto cleanup;
1649
1650        return 0;
1651
1652cleanup:
1653        mlx5_cleanup_fs(dev);
1654        return -ENOMEM;
1655}
1656
1657static void cleanup_single_prio_root_ns(struct mlx5_core_dev *dev,
1658                                        struct mlx5_flow_root_namespace *root_ns)
1659{
1660        struct fs_node *prio;
1661
1662        if (!root_ns)
1663                return;
1664
1665        if (!list_empty(&root_ns->ns.node.children)) {
1666                prio = list_first_entry(&root_ns->ns.node.children,
1667                                        struct fs_node,
1668                                 list);
1669                if (tree_remove_node(prio))
1670                        mlx5_core_warn(dev,
1671                                       "Flow steering priority wasn't destroyed, refcount > 1\n");
1672        }
1673        if (tree_remove_node(&root_ns->ns.node))
1674                mlx5_core_warn(dev,
1675                               "Flow steering namespace wasn't destroyed, refcount > 1\n");
1676        root_ns = NULL;
1677}
1678
1679static void destroy_flow_tables(struct fs_prio *prio)
1680{
1681        struct mlx5_flow_table *iter;
1682        struct mlx5_flow_table *tmp;
1683
1684        fs_for_each_ft_safe(iter, tmp, prio)
1685                mlx5_destroy_flow_table(iter);
1686}
1687
1688static void cleanup_root_ns(struct mlx5_core_dev *dev)
1689{
1690        struct mlx5_flow_root_namespace *root_ns = dev->priv.root_ns;
1691        struct fs_prio *iter_prio;
1692
1693        if (!MLX5_CAP_GEN(dev, nic_flow_table))
1694                return;
1695
1696        if (!root_ns)
1697                return;
1698
1699        /* stage 1 */
1700        fs_for_each_prio(iter_prio, &root_ns->ns) {
1701                struct fs_node *node;
1702                struct mlx5_flow_namespace *iter_ns;
1703
1704                fs_for_each_ns_or_ft(node, iter_prio) {
1705                        if (node->type == FS_TYPE_FLOW_TABLE)
1706                                continue;
1707                        fs_get_obj(iter_ns, node);
1708                        while (!list_empty(&iter_ns->node.children)) {
1709                                struct fs_prio *obj_iter_prio2;
1710                                struct fs_node *iter_prio2 =
1711                                        list_first_entry(&iter_ns->node.children,
1712                                                         struct fs_node,
1713                                                         list);
1714
1715                                fs_get_obj(obj_iter_prio2, iter_prio2);
1716                                destroy_flow_tables(obj_iter_prio2);
1717                                if (tree_remove_node(iter_prio2)) {
1718                                        mlx5_core_warn(dev,
1719                                                       "Priority %d wasn't destroyed, refcount > 1\n",
1720                                                       obj_iter_prio2->prio);
1721                                        return;
1722                                }
1723                        }
1724                }
1725        }
1726
1727        /* stage 2 */
1728        fs_for_each_prio(iter_prio, &root_ns->ns) {
1729                while (!list_empty(&iter_prio->node.children)) {
1730                        struct fs_node *iter_ns =
1731                                list_first_entry(&iter_prio->node.children,
1732                                                 struct fs_node,
1733                                                 list);
1734                        if (tree_remove_node(iter_ns)) {
1735                                mlx5_core_warn(dev,
1736                                               "Namespace wasn't destroyed, refcount > 1\n");
1737                                return;
1738                        }
1739                }
1740        }
1741
1742        /* stage 3 */
1743        while (!list_empty(&root_ns->ns.node.children)) {
1744                struct fs_prio *obj_prio_node;
1745                struct fs_node *prio_node =
1746                        list_first_entry(&root_ns->ns.node.children,
1747                                         struct fs_node,
1748                                         list);
1749
1750                fs_get_obj(obj_prio_node, prio_node);
1751                if (tree_remove_node(prio_node)) {
1752                        mlx5_core_warn(dev,
1753                                       "Priority %d wasn't destroyed, refcount > 1\n",
1754                                       obj_prio_node->prio);
1755                        return;
1756                }
1757        }
1758
1759        if (tree_remove_node(&root_ns->ns.node)) {
1760                mlx5_core_warn(dev,
1761                               "root namespace wasn't destroyed, refcount > 1\n");
1762                return;
1763        }
1764
1765        dev->priv.root_ns = NULL;
1766}
1767
1768void mlx5_cleanup_fs(struct mlx5_core_dev *dev)
1769{
1770        if (MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
1771                return;
1772
1773        cleanup_root_ns(dev);
1774        cleanup_single_prio_root_ns(dev, dev->priv.fdb_root_ns);
1775        cleanup_single_prio_root_ns(dev, dev->priv.esw_egress_root_ns);
1776        cleanup_single_prio_root_ns(dev, dev->priv.esw_ingress_root_ns);
1777        mlx5_cleanup_fc_stats(dev);
1778}
1779
1780static int init_fdb_root_ns(struct mlx5_core_dev *dev)
1781{
1782        struct fs_prio *prio;
1783
1784        dev->priv.fdb_root_ns = create_root_ns(dev, FS_FT_FDB);
1785        if (!dev->priv.fdb_root_ns)
1786                return -ENOMEM;
1787
1788        /* Create single prio */
1789        prio = fs_create_prio(&dev->priv.fdb_root_ns->ns, 0, 1);
1790        if (IS_ERR(prio)) {
1791                cleanup_single_prio_root_ns(dev, dev->priv.fdb_root_ns);
1792                return PTR_ERR(prio);
1793        } else {
1794                return 0;
1795        }
1796}
1797
1798static int init_egress_acl_root_ns(struct mlx5_core_dev *dev)
1799{
1800        struct fs_prio *prio;
1801
1802        dev->priv.esw_egress_root_ns = create_root_ns(dev, FS_FT_ESW_EGRESS_ACL);
1803        if (!dev->priv.esw_egress_root_ns)
1804                return -ENOMEM;
1805
1806        /* create 1 prio*/
1807        prio = fs_create_prio(&dev->priv.esw_egress_root_ns->ns, 0, MLX5_TOTAL_VPORTS(dev));
1808        if (IS_ERR(prio))
1809                return PTR_ERR(prio);
1810        else
1811                return 0;
1812}
1813
1814static int init_ingress_acl_root_ns(struct mlx5_core_dev *dev)
1815{
1816        struct fs_prio *prio;
1817
1818        dev->priv.esw_ingress_root_ns = create_root_ns(dev, FS_FT_ESW_INGRESS_ACL);
1819        if (!dev->priv.esw_ingress_root_ns)
1820                return -ENOMEM;
1821
1822        /* create 1 prio*/
1823        prio = fs_create_prio(&dev->priv.esw_ingress_root_ns->ns, 0, MLX5_TOTAL_VPORTS(dev));
1824        if (IS_ERR(prio))
1825                return PTR_ERR(prio);
1826        else
1827                return 0;
1828}
1829
1830int mlx5_init_fs(struct mlx5_core_dev *dev)
1831{
1832        int err = 0;
1833
1834        if (MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
1835                return 0;
1836
1837        err = mlx5_init_fc_stats(dev);
1838        if (err)
1839                return err;
1840
1841        if (MLX5_CAP_GEN(dev, nic_flow_table) &&
1842            MLX5_CAP_FLOWTABLE_NIC_RX(dev, ft_support)) {
1843                err = init_root_ns(dev);
1844                if (err)
1845                        goto err;
1846        }
1847
1848        if (MLX5_CAP_GEN(dev, eswitch_flow_table)) {
1849                if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, ft_support)) {
1850                        err = init_fdb_root_ns(dev);
1851                        if (err)
1852                                goto err;
1853                }
1854                if (MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support)) {
1855                        err = init_egress_acl_root_ns(dev);
1856                        if (err)
1857                                goto err;
1858                }
1859                if (MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support)) {
1860                        err = init_ingress_acl_root_ns(dev);
1861                        if (err)
1862                                goto err;
1863                }
1864        }
1865
1866        return 0;
1867err:
1868        mlx5_cleanup_fs(dev);
1869        return err;
1870}
1871