| /* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */ |
| /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */ |
| |
| #ifndef _MLXSW_SPECTRUM_ACL_TCAM_H |
| #define _MLXSW_SPECTRUM_ACL_TCAM_H |
| |
| #include <linux/list.h> |
| #include <linux/parman.h> |
| #include <linux/idr.h> |
| |
| #include "reg.h" |
| #include "spectrum.h" |
| #include "core_acl_flex_keys.h" |
| |
| struct mlxsw_sp_acl_tcam { |
| struct ida used_regions; |
| unsigned int max_regions; |
| struct ida used_groups; |
| unsigned int max_groups; |
| unsigned int max_group_size; |
| struct mutex lock; /* guards vregion list */ |
| struct list_head vregion_list; |
| u32 vregion_rehash_intrvl; /* ms */ |
| unsigned long priv[]; |
| /* priv has to be always the last item */ |
| }; |
| |
| size_t mlxsw_sp_acl_tcam_priv_size(struct mlxsw_sp *mlxsw_sp); |
| int mlxsw_sp_acl_tcam_init(struct mlxsw_sp *mlxsw_sp, |
| struct mlxsw_sp_acl_tcam *tcam); |
| void mlxsw_sp_acl_tcam_fini(struct mlxsw_sp *mlxsw_sp, |
| struct mlxsw_sp_acl_tcam *tcam); |
| int mlxsw_sp_acl_tcam_priority_get(struct mlxsw_sp *mlxsw_sp, |
| struct mlxsw_sp_acl_rule_info *rulei, |
| u32 *priority, bool fillup_priority); |
| |
| struct mlxsw_sp_acl_profile_ops { |
| size_t ruleset_priv_size; |
| int (*ruleset_add)(struct mlxsw_sp *mlxsw_sp, |
| struct mlxsw_sp_acl_tcam *tcam, void *ruleset_priv, |
| struct mlxsw_afk_element_usage *tmplt_elusage, |
| unsigned int *p_min_prio, unsigned int *p_max_prio); |
| void (*ruleset_del)(struct mlxsw_sp *mlxsw_sp, void *ruleset_priv); |
| int (*ruleset_bind)(struct mlxsw_sp *mlxsw_sp, void *ruleset_priv, |
| struct mlxsw_sp_port *mlxsw_sp_port, |
| bool ingress); |
| void (*ruleset_unbind)(struct mlxsw_sp *mlxsw_sp, void *ruleset_priv, |
| struct mlxsw_sp_port *mlxsw_sp_port, |
| bool ingress); |
| u16 (*ruleset_group_id)(void *ruleset_priv); |
| size_t rule_priv_size; |
| int (*rule_add)(struct mlxsw_sp *mlxsw_sp, |
| void *ruleset_priv, void *rule_priv, |
| struct mlxsw_sp_acl_rule_info *rulei); |
| void (*rule_del)(struct mlxsw_sp *mlxsw_sp, void *rule_priv); |
| int (*rule_action_replace)(struct mlxsw_sp *mlxsw_sp, void *rule_priv, |
| struct mlxsw_sp_acl_rule_info *rulei); |
| int (*rule_activity_get)(struct mlxsw_sp *mlxsw_sp, void *rule_priv, |
| bool *activity); |
| }; |
| |
| const struct mlxsw_sp_acl_profile_ops * |
| mlxsw_sp_acl_tcam_profile_ops(struct mlxsw_sp *mlxsw_sp, |
| enum mlxsw_sp_acl_profile profile); |
| |
| #define MLXSW_SP_ACL_TCAM_REGION_BASE_COUNT 16 |
| #define MLXSW_SP_ACL_TCAM_REGION_RESIZE_STEP 16 |
| |
| #define MLXSW_SP_ACL_TCAM_CATCHALL_PRIO (~0U) |
| |
| #define MLXSW_SP_ACL_TCAM_MASK_LEN \ |
| (MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN * BITS_PER_BYTE) |
| |
| struct mlxsw_sp_acl_tcam_group; |
| struct mlxsw_sp_acl_tcam_vregion; |
| |
| struct mlxsw_sp_acl_tcam_region { |
| struct mlxsw_sp_acl_tcam_vregion *vregion; |
| struct mlxsw_sp_acl_tcam_group *group; |
| struct list_head list; /* Member of a TCAM group */ |
| enum mlxsw_reg_ptar_key_type key_type; |
| u16 id; /* ACL ID and region ID - they are same */ |
| char tcam_region_info[MLXSW_REG_PXXX_TCAM_REGION_INFO_LEN]; |
| struct mlxsw_afk_key_info *key_info; |
| struct mlxsw_sp *mlxsw_sp; |
| unsigned long priv[]; |
| /* priv has to be always the last item */ |
| }; |
| |
| struct mlxsw_sp_acl_ctcam_region { |
| struct parman *parman; |
| const struct mlxsw_sp_acl_ctcam_region_ops *ops; |
| struct mlxsw_sp_acl_tcam_region *region; |
| }; |
| |
| struct mlxsw_sp_acl_ctcam_chunk { |
| struct parman_prio parman_prio; |
| }; |
| |
| struct mlxsw_sp_acl_ctcam_entry { |
| struct parman_item parman_item; |
| }; |
| |
| struct mlxsw_sp_acl_ctcam_region_ops { |
| int (*entry_insert)(struct mlxsw_sp_acl_ctcam_region *cregion, |
| struct mlxsw_sp_acl_ctcam_entry *centry, |
| const char *mask); |
| void (*entry_remove)(struct mlxsw_sp_acl_ctcam_region *cregion, |
| struct mlxsw_sp_acl_ctcam_entry *centry); |
| }; |
| |
| int |
| mlxsw_sp_acl_ctcam_region_init(struct mlxsw_sp *mlxsw_sp, |
| struct mlxsw_sp_acl_ctcam_region *cregion, |
| struct mlxsw_sp_acl_tcam_region *region, |
| const struct mlxsw_sp_acl_ctcam_region_ops *ops); |
| void mlxsw_sp_acl_ctcam_region_fini(struct mlxsw_sp_acl_ctcam_region *cregion); |
| void mlxsw_sp_acl_ctcam_chunk_init(struct mlxsw_sp_acl_ctcam_region *cregion, |
| struct mlxsw_sp_acl_ctcam_chunk *cchunk, |
| unsigned int priority); |
| void mlxsw_sp_acl_ctcam_chunk_fini(struct mlxsw_sp_acl_ctcam_chunk *cchunk); |
| int mlxsw_sp_acl_ctcam_entry_add(struct mlxsw_sp *mlxsw_sp, |
| struct mlxsw_sp_acl_ctcam_region *cregion, |
| struct mlxsw_sp_acl_ctcam_chunk *cchunk, |
| struct mlxsw_sp_acl_ctcam_entry *centry, |
| struct mlxsw_sp_acl_rule_info *rulei, |
| bool fillup_priority); |
| void mlxsw_sp_acl_ctcam_entry_del(struct mlxsw_sp *mlxsw_sp, |
| struct mlxsw_sp_acl_ctcam_region *cregion, |
| struct mlxsw_sp_acl_ctcam_chunk *cchunk, |
| struct mlxsw_sp_acl_ctcam_entry *centry); |
| int mlxsw_sp_acl_ctcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp, |
| struct mlxsw_sp_acl_ctcam_region *cregion, |
| struct mlxsw_sp_acl_ctcam_entry *centry, |
| struct mlxsw_sp_acl_rule_info *rulei); |
| static inline unsigned int |
| mlxsw_sp_acl_ctcam_entry_offset(struct mlxsw_sp_acl_ctcam_entry *centry) |
| { |
| return centry->parman_item.index; |
| } |
| |
| enum mlxsw_sp_acl_atcam_region_type { |
| MLXSW_SP_ACL_ATCAM_REGION_TYPE_2KB, |
| MLXSW_SP_ACL_ATCAM_REGION_TYPE_4KB, |
| MLXSW_SP_ACL_ATCAM_REGION_TYPE_8KB, |
| MLXSW_SP_ACL_ATCAM_REGION_TYPE_12KB, |
| __MLXSW_SP_ACL_ATCAM_REGION_TYPE_MAX, |
| }; |
| |
| #define MLXSW_SP_ACL_ATCAM_REGION_TYPE_MAX \ |
| (__MLXSW_SP_ACL_ATCAM_REGION_TYPE_MAX - 1) |
| |
| struct mlxsw_sp_acl_atcam { |
| struct mlxsw_sp_acl_erp_core *erp_core; |
| }; |
| |
| struct mlxsw_sp_acl_atcam_region { |
| struct rhashtable entries_ht; /* A-TCAM only */ |
| struct list_head entries_list; /* A-TCAM only */ |
| struct mlxsw_sp_acl_ctcam_region cregion; |
| const struct mlxsw_sp_acl_atcam_region_ops *ops; |
| struct mlxsw_sp_acl_tcam_region *region; |
| struct mlxsw_sp_acl_atcam *atcam; |
| enum mlxsw_sp_acl_atcam_region_type type; |
| struct mlxsw_sp_acl_erp_table *erp_table; |
| void *priv; |
| }; |
| |
| struct mlxsw_sp_acl_atcam_entry_ht_key { |
| char enc_key[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN]; /* Encoded key, minus |
| * delta bits. |
| */ |
| u8 erp_id; |
| }; |
| |
| struct mlxsw_sp_acl_atcam_chunk { |
| struct mlxsw_sp_acl_ctcam_chunk cchunk; |
| }; |
| |
| struct mlxsw_sp_acl_atcam_entry { |
| struct rhash_head ht_node; |
| struct list_head list; /* Member in entries_list */ |
| struct mlxsw_sp_acl_atcam_entry_ht_key ht_key; |
| struct { |
| u16 start; |
| u8 mask; |
| u8 value; |
| } delta_info; |
| struct mlxsw_sp_acl_ctcam_entry centry; |
| struct mlxsw_sp_acl_atcam_lkey_id *lkey_id; |
| struct mlxsw_sp_acl_erp_mask *erp_mask; |
| }; |
| |
| static inline struct mlxsw_sp_acl_atcam_region * |
| mlxsw_sp_acl_tcam_cregion_aregion(struct mlxsw_sp_acl_ctcam_region *cregion) |
| { |
| return container_of(cregion, struct mlxsw_sp_acl_atcam_region, cregion); |
| } |
| |
| static inline struct mlxsw_sp_acl_atcam_entry * |
| mlxsw_sp_acl_tcam_centry_aentry(struct mlxsw_sp_acl_ctcam_entry *centry) |
| { |
| return container_of(centry, struct mlxsw_sp_acl_atcam_entry, centry); |
| } |
| |
| int mlxsw_sp_acl_atcam_region_associate(struct mlxsw_sp *mlxsw_sp, |
| u16 region_id); |
| int |
| mlxsw_sp_acl_atcam_region_init(struct mlxsw_sp *mlxsw_sp, |
| struct mlxsw_sp_acl_atcam *atcam, |
| struct mlxsw_sp_acl_atcam_region *aregion, |
| struct mlxsw_sp_acl_tcam_region *region, |
| void *hints_priv, |
| const struct mlxsw_sp_acl_ctcam_region_ops *ops); |
| void mlxsw_sp_acl_atcam_region_fini(struct mlxsw_sp_acl_atcam_region *aregion); |
| void mlxsw_sp_acl_atcam_chunk_init(struct mlxsw_sp_acl_atcam_region *aregion, |
| struct mlxsw_sp_acl_atcam_chunk *achunk, |
| unsigned int priority); |
| void mlxsw_sp_acl_atcam_chunk_fini(struct mlxsw_sp_acl_atcam_chunk *achunk); |
| int mlxsw_sp_acl_atcam_entry_add(struct mlxsw_sp *mlxsw_sp, |
| struct mlxsw_sp_acl_atcam_region *aregion, |
| struct mlxsw_sp_acl_atcam_chunk *achunk, |
| struct mlxsw_sp_acl_atcam_entry *aentry, |
| struct mlxsw_sp_acl_rule_info *rulei); |
| void mlxsw_sp_acl_atcam_entry_del(struct mlxsw_sp *mlxsw_sp, |
| struct mlxsw_sp_acl_atcam_region *aregion, |
| struct mlxsw_sp_acl_atcam_chunk *achunk, |
| struct mlxsw_sp_acl_atcam_entry *aentry); |
| int mlxsw_sp_acl_atcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp, |
| struct mlxsw_sp_acl_atcam_region *aregion, |
| struct mlxsw_sp_acl_atcam_entry *aentry, |
| struct mlxsw_sp_acl_rule_info *rulei); |
| int mlxsw_sp_acl_atcam_init(struct mlxsw_sp *mlxsw_sp, |
| struct mlxsw_sp_acl_atcam *atcam); |
| void mlxsw_sp_acl_atcam_fini(struct mlxsw_sp *mlxsw_sp, |
| struct mlxsw_sp_acl_atcam *atcam); |
| void * |
| mlxsw_sp_acl_atcam_rehash_hints_get(struct mlxsw_sp_acl_atcam_region *aregion); |
| void mlxsw_sp_acl_atcam_rehash_hints_put(void *hints_priv); |
| |
| struct mlxsw_sp_acl_erp_delta; |
| |
| u16 mlxsw_sp_acl_erp_delta_start(const struct mlxsw_sp_acl_erp_delta *delta); |
| u8 mlxsw_sp_acl_erp_delta_mask(const struct mlxsw_sp_acl_erp_delta *delta); |
| u8 mlxsw_sp_acl_erp_delta_value(const struct mlxsw_sp_acl_erp_delta *delta, |
| const char *enc_key); |
| void mlxsw_sp_acl_erp_delta_clear(const struct mlxsw_sp_acl_erp_delta *delta, |
| const char *enc_key); |
| |
| struct mlxsw_sp_acl_erp_mask; |
| |
| bool |
| mlxsw_sp_acl_erp_mask_is_ctcam(const struct mlxsw_sp_acl_erp_mask *erp_mask); |
| u8 mlxsw_sp_acl_erp_mask_erp_id(const struct mlxsw_sp_acl_erp_mask *erp_mask); |
| const struct mlxsw_sp_acl_erp_delta * |
| mlxsw_sp_acl_erp_delta(const struct mlxsw_sp_acl_erp_mask *erp_mask); |
| struct mlxsw_sp_acl_erp_mask * |
| mlxsw_sp_acl_erp_mask_get(struct mlxsw_sp_acl_atcam_region *aregion, |
| const char *mask, bool ctcam); |
| void mlxsw_sp_acl_erp_mask_put(struct mlxsw_sp_acl_atcam_region *aregion, |
| struct mlxsw_sp_acl_erp_mask *erp_mask); |
| int mlxsw_sp_acl_erp_bf_insert(struct mlxsw_sp *mlxsw_sp, |
| struct mlxsw_sp_acl_atcam_region *aregion, |
| struct mlxsw_sp_acl_erp_mask *erp_mask, |
| struct mlxsw_sp_acl_atcam_entry *aentry); |
| void mlxsw_sp_acl_erp_bf_remove(struct mlxsw_sp *mlxsw_sp, |
| struct mlxsw_sp_acl_atcam_region *aregion, |
| struct mlxsw_sp_acl_erp_mask *erp_mask, |
| struct mlxsw_sp_acl_atcam_entry *aentry); |
| void * |
| mlxsw_sp_acl_erp_rehash_hints_get(struct mlxsw_sp_acl_atcam_region *aregion); |
| void mlxsw_sp_acl_erp_rehash_hints_put(void *hints_priv); |
| int mlxsw_sp_acl_erp_region_init(struct mlxsw_sp_acl_atcam_region *aregion, |
| void *hints_priv); |
| void mlxsw_sp_acl_erp_region_fini(struct mlxsw_sp_acl_atcam_region *aregion); |
| int mlxsw_sp_acl_erps_init(struct mlxsw_sp *mlxsw_sp, |
| struct mlxsw_sp_acl_atcam *atcam); |
| void mlxsw_sp_acl_erps_fini(struct mlxsw_sp *mlxsw_sp, |
| struct mlxsw_sp_acl_atcam *atcam); |
| |
| struct mlxsw_sp_acl_bf; |
| |
| struct mlxsw_sp_acl_bf_ops { |
| unsigned int (*index_get)(struct mlxsw_sp_acl_bf *bf, |
| struct mlxsw_sp_acl_atcam_region *aregion, |
| struct mlxsw_sp_acl_atcam_entry *aentry); |
| }; |
| |
| int |
| mlxsw_sp_acl_bf_entry_add(struct mlxsw_sp *mlxsw_sp, |
| struct mlxsw_sp_acl_bf *bf, |
| struct mlxsw_sp_acl_atcam_region *aregion, |
| unsigned int erp_bank, |
| struct mlxsw_sp_acl_atcam_entry *aentry); |
| void |
| mlxsw_sp_acl_bf_entry_del(struct mlxsw_sp *mlxsw_sp, |
| struct mlxsw_sp_acl_bf *bf, |
| struct mlxsw_sp_acl_atcam_region *aregion, |
| unsigned int erp_bank, |
| struct mlxsw_sp_acl_atcam_entry *aentry); |
| struct mlxsw_sp_acl_bf * |
| mlxsw_sp_acl_bf_init(struct mlxsw_sp *mlxsw_sp, unsigned int num_erp_banks); |
| void mlxsw_sp_acl_bf_fini(struct mlxsw_sp_acl_bf *bf); |
| |
| #endif |