root/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc_complex.h
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */

#ifndef HWS_BWC_COMPLEX_H_
#define HWS_BWC_COMPLEX_H_

#define MLX5HWS_BWC_COMPLEX_MAX_SUBMATCHERS 4

/* A matcher can't contain two rules with the same match tag, but it is possible
 * that two different complex rules' subrules have the same match tag. In that
 * case, those subrules correspond to a single rule, and we need to refcount.
 */
struct mlx5hws_bwc_complex_subrule_data {
        struct mlx5hws_rule_match_tag match_tag;
        refcount_t refcount;
        /* The chain_id is what glues individual subrules into larger complex
         * rules. It is the value that this subrule writes to register C6, and
         * that the next subrule matches against.
         */
        u32 chain_id;
        u32 rtc_0;
        u32 rtc_1;
        /* During rehash we iterate through all the subrules to move them. But
         * two or more subrules can share the same physical rule in the
         * submatcher, so we use `was_moved` to keep track if a given rule was
         * already moved.
         */
        bool was_moved;
        struct rhash_head hash_node;
};

struct mlx5hws_bwc_complex_submatcher {
        /* Isolated table that the matcher lives in. Not set for the first
         * matcher, which lives in the original table.
         */
        struct mlx5hws_table *tbl;
        /* Match a rule with this action to go to `tbl`. This is set in all
         * submatchers but the first.
         */
        struct mlx5hws_action *action_tbl;
        /* This submatcher's simple matcher. The first submatcher points to the
         * outer (complex) matcher.
         */
        struct mlx5hws_bwc_matcher *bwc_matcher;
        struct rhashtable rules_hash;
        struct ida chain_ida;
        struct mutex hash_lock; /* Protect the hash and ida. */
};

struct mlx5hws_bwc_matcher_complex_data {
        struct mlx5hws_bwc_complex_submatcher
                submatchers[MLX5HWS_BWC_COMPLEX_MAX_SUBMATCHERS];
        int num_submatchers;
        /* Actions used by all but the last submatcher to point to the next
         * submatcher in the chain. The last submatcher uses the action template
         * from the complex matcher, to perform the actions that the user
         * originally requested.
         */
        struct mlx5hws_action *action_metadata;
        struct mlx5hws_action *action_last;
};

bool mlx5hws_bwc_match_params_is_complex(struct mlx5hws_context *ctx,
                                         u8 match_criteria_enable,
                                         struct mlx5hws_match_parameters *mask);

int mlx5hws_bwc_matcher_create_complex(struct mlx5hws_bwc_matcher *bwc_matcher,
                                       struct mlx5hws_table *table,
                                       u32 priority,
                                       u8 match_criteria_enable,
                                       struct mlx5hws_match_parameters *mask);

void mlx5hws_bwc_matcher_destroy_complex(struct mlx5hws_bwc_matcher *bwc_matcher);

int mlx5hws_bwc_matcher_complex_move(struct mlx5hws_bwc_matcher *bwc_matcher);

int
mlx5hws_bwc_matcher_complex_move_first(struct mlx5hws_bwc_matcher *bwc_matcher);

int mlx5hws_bwc_rule_create_complex(struct mlx5hws_bwc_rule *bwc_rule,
                                    struct mlx5hws_match_parameters *params,
                                    u32 flow_source,
                                    struct mlx5hws_rule_action rule_actions[],
                                    u16 bwc_queue_idx);

int mlx5hws_bwc_rule_destroy_complex(struct mlx5hws_bwc_rule *bwc_rule);

#endif /* HWS_BWC_COMPLEX_H_ */