| /* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */ |
| /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */ |
| |
| #ifndef _MLXSW_CORE_ACL_FLEX_KEYS_H |
| #define _MLXSW_CORE_ACL_FLEX_KEYS_H |
| |
| #include <linux/types.h> |
| #include <linux/bitmap.h> |
| |
| #include "item.h" |
| |
| enum mlxsw_afk_element { |
| MLXSW_AFK_ELEMENT_SRC_SYS_PORT, |
| MLXSW_AFK_ELEMENT_DMAC_32_47, |
| MLXSW_AFK_ELEMENT_DMAC_0_31, |
| MLXSW_AFK_ELEMENT_SMAC_32_47, |
| MLXSW_AFK_ELEMENT_SMAC_0_31, |
| MLXSW_AFK_ELEMENT_ETHERTYPE, |
| MLXSW_AFK_ELEMENT_IP_PROTO, |
| MLXSW_AFK_ELEMENT_SRC_IP_96_127, |
| MLXSW_AFK_ELEMENT_SRC_IP_64_95, |
| MLXSW_AFK_ELEMENT_SRC_IP_32_63, |
| MLXSW_AFK_ELEMENT_SRC_IP_0_31, |
| MLXSW_AFK_ELEMENT_DST_IP_96_127, |
| MLXSW_AFK_ELEMENT_DST_IP_64_95, |
| MLXSW_AFK_ELEMENT_DST_IP_32_63, |
| MLXSW_AFK_ELEMENT_DST_IP_0_31, |
| MLXSW_AFK_ELEMENT_DST_L4_PORT, |
| MLXSW_AFK_ELEMENT_SRC_L4_PORT, |
| MLXSW_AFK_ELEMENT_VID, |
| MLXSW_AFK_ELEMENT_PCP, |
| MLXSW_AFK_ELEMENT_TCP_FLAGS, |
| MLXSW_AFK_ELEMENT_IP_TTL_, |
| MLXSW_AFK_ELEMENT_IP_ECN, |
| MLXSW_AFK_ELEMENT_IP_DSCP, |
| MLXSW_AFK_ELEMENT_VIRT_ROUTER_8_10, |
| MLXSW_AFK_ELEMENT_VIRT_ROUTER_0_7, |
| MLXSW_AFK_ELEMENT_MAX, |
| }; |
| |
| enum mlxsw_afk_element_type { |
| MLXSW_AFK_ELEMENT_TYPE_U32, |
| MLXSW_AFK_ELEMENT_TYPE_BUF, |
| }; |
| |
| struct mlxsw_afk_element_info { |
| enum mlxsw_afk_element element; /* element ID */ |
| enum mlxsw_afk_element_type type; |
| struct mlxsw_item item; /* element geometry in internal storage */ |
| }; |
| |
| #define MLXSW_AFK_ELEMENT_INFO(_type, _element, _offset, _shift, _size) \ |
| [MLXSW_AFK_ELEMENT_##_element] = { \ |
| .element = MLXSW_AFK_ELEMENT_##_element, \ |
| .type = _type, \ |
| .item = { \ |
| .offset = _offset, \ |
| .shift = _shift, \ |
| .size = {.bits = _size}, \ |
| .name = #_element, \ |
| }, \ |
| } |
| |
| #define MLXSW_AFK_ELEMENT_INFO_U32(_element, _offset, _shift, _size) \ |
| MLXSW_AFK_ELEMENT_INFO(MLXSW_AFK_ELEMENT_TYPE_U32, \ |
| _element, _offset, _shift, _size) |
| |
| #define MLXSW_AFK_ELEMENT_INFO_BUF(_element, _offset, _size) \ |
| MLXSW_AFK_ELEMENT_INFO(MLXSW_AFK_ELEMENT_TYPE_BUF, \ |
| _element, _offset, 0, _size) |
| |
| #define MLXSW_AFK_ELEMENT_STORAGE_SIZE 0x40 |
| |
| struct mlxsw_afk_element_inst { /* element instance in actual block */ |
| enum mlxsw_afk_element element; |
| enum mlxsw_afk_element_type type; |
| struct mlxsw_item item; /* element geometry in block */ |
| int u32_key_diff; /* in case value needs to be adjusted before write |
| * this diff is here to handle that |
| */ |
| bool avoid_size_check; |
| }; |
| |
| #define MLXSW_AFK_ELEMENT_INST(_type, _element, _offset, \ |
| _shift, _size, _u32_key_diff, _avoid_size_check) \ |
| { \ |
| .element = MLXSW_AFK_ELEMENT_##_element, \ |
| .type = _type, \ |
| .item = { \ |
| .offset = _offset, \ |
| .shift = _shift, \ |
| .size = {.bits = _size}, \ |
| .name = #_element, \ |
| }, \ |
| .u32_key_diff = _u32_key_diff, \ |
| .avoid_size_check = _avoid_size_check, \ |
| } |
| |
| #define MLXSW_AFK_ELEMENT_INST_U32(_element, _offset, _shift, _size) \ |
| MLXSW_AFK_ELEMENT_INST(MLXSW_AFK_ELEMENT_TYPE_U32, \ |
| _element, _offset, _shift, _size, 0, false) |
| |
| #define MLXSW_AFK_ELEMENT_INST_EXT_U32(_element, _offset, \ |
| _shift, _size, _key_diff, \ |
| _avoid_size_check) \ |
| MLXSW_AFK_ELEMENT_INST(MLXSW_AFK_ELEMENT_TYPE_U32, \ |
| _element, _offset, _shift, _size, \ |
| _key_diff, _avoid_size_check) |
| |
| #define MLXSW_AFK_ELEMENT_INST_BUF(_element, _offset, _size) \ |
| MLXSW_AFK_ELEMENT_INST(MLXSW_AFK_ELEMENT_TYPE_BUF, \ |
| _element, _offset, 0, _size, 0, false) |
| |
| struct mlxsw_afk_block { |
| u16 encoding; /* block ID */ |
| struct mlxsw_afk_element_inst *instances; |
| unsigned int instances_count; |
| }; |
| |
| #define MLXSW_AFK_BLOCK(_encoding, _instances) \ |
| { \ |
| .encoding = _encoding, \ |
| .instances = _instances, \ |
| .instances_count = ARRAY_SIZE(_instances), \ |
| } |
| |
| struct mlxsw_afk_element_usage { |
| DECLARE_BITMAP(usage, MLXSW_AFK_ELEMENT_MAX); |
| }; |
| |
| #define mlxsw_afk_element_usage_for_each(element, elusage) \ |
| for_each_set_bit(element, (elusage)->usage, MLXSW_AFK_ELEMENT_MAX) |
| |
| static inline void |
| mlxsw_afk_element_usage_add(struct mlxsw_afk_element_usage *elusage, |
| enum mlxsw_afk_element element) |
| { |
| __set_bit(element, elusage->usage); |
| } |
| |
| static inline void |
| mlxsw_afk_element_usage_zero(struct mlxsw_afk_element_usage *elusage) |
| { |
| bitmap_zero(elusage->usage, MLXSW_AFK_ELEMENT_MAX); |
| } |
| |
| static inline void |
| mlxsw_afk_element_usage_fill(struct mlxsw_afk_element_usage *elusage, |
| const enum mlxsw_afk_element *elements, |
| unsigned int elements_count) |
| { |
| int i; |
| |
| mlxsw_afk_element_usage_zero(elusage); |
| for (i = 0; i < elements_count; i++) |
| mlxsw_afk_element_usage_add(elusage, elements[i]); |
| } |
| |
| static inline bool |
| mlxsw_afk_element_usage_subset(struct mlxsw_afk_element_usage *elusage_small, |
| struct mlxsw_afk_element_usage *elusage_big) |
| { |
| int i; |
| |
| for (i = 0; i < MLXSW_AFK_ELEMENT_MAX; i++) |
| if (test_bit(i, elusage_small->usage) && |
| !test_bit(i, elusage_big->usage)) |
| return false; |
| return true; |
| } |
| |
| struct mlxsw_afk; |
| |
| struct mlxsw_afk_ops { |
| const struct mlxsw_afk_block *blocks; |
| unsigned int blocks_count; |
| void (*encode_block)(char *output, int block_index, char *block); |
| void (*clear_block)(char *output, int block_index); |
| }; |
| |
| struct mlxsw_afk *mlxsw_afk_create(unsigned int max_blocks, |
| const struct mlxsw_afk_ops *ops); |
| void mlxsw_afk_destroy(struct mlxsw_afk *mlxsw_afk); |
| |
| struct mlxsw_afk_key_info; |
| |
| struct mlxsw_afk_key_info * |
| mlxsw_afk_key_info_get(struct mlxsw_afk *mlxsw_afk, |
| struct mlxsw_afk_element_usage *elusage); |
| void mlxsw_afk_key_info_put(struct mlxsw_afk_key_info *key_info); |
| bool mlxsw_afk_key_info_subset(struct mlxsw_afk_key_info *key_info, |
| struct mlxsw_afk_element_usage *elusage); |
| |
| u16 |
| mlxsw_afk_key_info_block_encoding_get(const struct mlxsw_afk_key_info *key_info, |
| int block_index); |
| unsigned int |
| mlxsw_afk_key_info_blocks_count_get(const struct mlxsw_afk_key_info *key_info); |
| |
| struct mlxsw_afk_element_values { |
| struct mlxsw_afk_element_usage elusage; |
| struct { |
| char key[MLXSW_AFK_ELEMENT_STORAGE_SIZE]; |
| char mask[MLXSW_AFK_ELEMENT_STORAGE_SIZE]; |
| } storage; |
| }; |
| |
| void mlxsw_afk_values_add_u32(struct mlxsw_afk_element_values *values, |
| enum mlxsw_afk_element element, |
| u32 key_value, u32 mask_value); |
| void mlxsw_afk_values_add_buf(struct mlxsw_afk_element_values *values, |
| enum mlxsw_afk_element element, |
| const char *key_value, const char *mask_value, |
| unsigned int len); |
| void mlxsw_afk_encode(struct mlxsw_afk *mlxsw_afk, |
| struct mlxsw_afk_key_info *key_info, |
| struct mlxsw_afk_element_values *values, |
| char *key, char *mask); |
| void mlxsw_afk_clear(struct mlxsw_afk *mlxsw_afk, char *key, |
| int block_start, int block_end); |
| |
| #endif |