// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
/* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/rhashtable.h>
#include <linux/list.h>
#include "item.h"
#include "trap.h"
#include "core_acl_flex_actions.h"
enum mlxsw_afa_set_type {
MLXSW_AFA_SET_TYPE_NEXT,
MLXSW_AFA_SET_TYPE_GOTO,
};
/* afa_set_type
* Type of the record at the end of the action set.
*/
MLXSW_ITEM32(afa, set, type, 0xA0, 28, 4);
/* afa_set_next_action_set_ptr
* A pointer to the next action set in the KVD Centralized database.
*/
MLXSW_ITEM32(afa, set, next_action_set_ptr, 0xA4, 0, 24);
/* afa_set_goto_g
* group - When set, the binding is of an ACL group. When cleared,
* the binding is of an ACL.
* Must be set to 1 for Spectrum.
*/
MLXSW_ITEM32(afa, set, goto_g, 0xA4, 29, 1);
enum mlxsw_afa_set_goto_binding_cmd {
/* continue go the next binding point */
MLXSW_AFA_SET_GOTO_BINDING_CMD_NONE,
/* jump to the next binding point no return */
MLXSW_AFA_SET_GOTO_BINDING_CMD_JUMP,
/* terminate the acl binding */
MLXSW_AFA_SET_GOTO_BINDING_CMD_TERM = 4,
};
/* afa_set_goto_binding_cmd */
MLXSW_ITEM32(afa, set, goto_binding_cmd, 0xA4, 24, 3);
/* afa_set_goto_next_binding
* ACL/ACL group identifier. If the g bit is set, this field should hold
* the acl_group_id, else it should hold the acl_id.
*/
MLXSW_ITEM32(afa, set, goto_next_binding, 0xA4, 0, 16);
/* afa_all_action_type
* Action Type.
*/
MLXSW_ITEM32(afa, all, action_type, 0x00, 24, 6);
struct mlxsw_afa {
unsigned int max_acts_per_set;
const struct mlxsw_afa_ops *ops;
void *ops_priv;
struct rhashtable set_ht;
struct rhashtable fwd_entry_ht;
};
#define MLXSW_AFA_SET_LEN 0xA8
struct mlxsw_afa_set_ht_key {
char enc_actions[MLXSW_AFA_SET_LEN]; /* Encoded set */
bool is_first;
};
/* Set structure holds one action set record. It contains up to three
* actions (depends on size of particular actions). The set is either
* put directly to a rule, or it is stored in KVD linear area.
* To prevent duplicate entries in KVD linear area, a hashtable is
* used to track sets that were previously inserted and may be shared.
*/
struct mlxsw_afa_set {
struct rhash_head ht_node;
struct mlxsw_afa_set_ht_key ht_key;
u32 kvdl_index;
bool shared; /* Inserted in hashtable (doesn't mean that
* kvdl_index is valid).
*/
unsigned int ref_count;
struct mlxsw_afa_set *next; /* Pointer to the next set. */
struct mlxsw_afa_set *prev; /* Pointer to the previous set,
* note that set may have multiple
* sets from multiple blocks
* pointing at it. This is only
* usable until commit.
*/
};
static const struct rhashtable_params mlxsw_afa_set_ht_params = {
.key_len = sizeof(struct mlxsw_afa_set_ht_key),
.key_offset = offsetof(struct mlxsw_afa_set, ht_key),
.head_offset = offsetof(struct mlxsw_afa_set, ht_node),
.automatic_shrinking = true,
};
struct mlxsw_afa_fwd_entry_ht_key {
u8 local_port;
};
struct mlxsw_afa_fwd_entry {
struct rhash_head ht_node;
struct mlxsw_afa_fwd_entry_ht_key ht_key;
u32 kvdl_index;
unsigned int ref_count;
};
static const struct