summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c')
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c70
1 files changed, 61 insertions, 9 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c
index 70f9b5e85a26..0d5e6f9b466e 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c
@@ -32,8 +32,7 @@ static const struct mlxsw_afk_element_info mlxsw_afk_element_infos[] = {
MLXSW_AFK_ELEMENT_INFO_U32(IP_TTL_, 0x18, 0, 8),
MLXSW_AFK_ELEMENT_INFO_U32(IP_ECN, 0x18, 9, 2),
MLXSW_AFK_ELEMENT_INFO_U32(IP_DSCP, 0x18, 11, 6),
- MLXSW_AFK_ELEMENT_INFO_U32(VIRT_ROUTER_MSB, 0x18, 17, 4),
- MLXSW_AFK_ELEMENT_INFO_U32(VIRT_ROUTER_LSB, 0x18, 21, 8),
+ MLXSW_AFK_ELEMENT_INFO_U32(VIRT_ROUTER, 0x18, 17, 12),
MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP_96_127, 0x20, 4),
MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP_64_95, 0x24, 4),
MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP_32_63, 0x28, 4),
@@ -44,6 +43,9 @@ static const struct mlxsw_afk_element_info mlxsw_afk_element_infos[] = {
MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP_0_31, 0x3C, 4),
MLXSW_AFK_ELEMENT_INFO_U32(FDB_MISS, 0x40, 0, 1),
MLXSW_AFK_ELEMENT_INFO_U32(L4_PORT_RANGE, 0x40, 1, 16),
+ MLXSW_AFK_ELEMENT_INFO_U32(VIRT_ROUTER_0_3, 0x40, 17, 4),
+ MLXSW_AFK_ELEMENT_INFO_U32(VIRT_ROUTER_4_7, 0x40, 21, 4),
+ MLXSW_AFK_ELEMENT_INFO_U32(VIRT_ROUTER_MSB, 0x40, 25, 4),
};
struct mlxsw_afk {
@@ -136,6 +138,7 @@ mlxsw_afk_key_info_find(struct mlxsw_afk *mlxsw_afk,
struct mlxsw_afk_picker {
DECLARE_BITMAP(element, MLXSW_AFK_ELEMENT_MAX);
+ DECLARE_BITMAP(chosen_element, MLXSW_AFK_ELEMENT_MAX);
unsigned int total;
};
@@ -206,7 +209,7 @@ static int mlxsw_afk_picker_key_info_add(struct mlxsw_afk *mlxsw_afk,
if (key_info->blocks_count == mlxsw_afk->max_blocks)
return -EINVAL;
- for_each_set_bit(element, picker[block_index].element,
+ for_each_set_bit(element, picker[block_index].chosen_element,
MLXSW_AFK_ELEMENT_MAX) {
key_info->element_to_block[element] = key_info->blocks_count;
mlxsw_afk_element_usage_add(&key_info->elusage, element);
@@ -218,11 +221,43 @@ static int mlxsw_afk_picker_key_info_add(struct mlxsw_afk *mlxsw_afk,
return 0;
}
+static int mlxsw_afk_keys_fill(struct mlxsw_afk *mlxsw_afk,
+ unsigned long *chosen_blocks_bm,
+ struct mlxsw_afk_picker *picker,
+ struct mlxsw_afk_key_info *key_info)
+{
+ int i, err;
+
+ /* First fill only key blocks with high_entropy. */
+ for_each_set_bit(i, chosen_blocks_bm, mlxsw_afk->blocks_count) {
+ if (!mlxsw_afk->blocks[i].high_entropy)
+ continue;
+
+ err = mlxsw_afk_picker_key_info_add(mlxsw_afk, picker, i,
+ key_info);
+ if (err)
+ return err;
+ __clear_bit(i, chosen_blocks_bm);
+ }
+
+ /* Fill the rest of key blocks. */
+ for_each_set_bit(i, chosen_blocks_bm, mlxsw_afk->blocks_count) {
+ err = mlxsw_afk_picker_key_info_add(mlxsw_afk, picker, i,
+ key_info);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
static int mlxsw_afk_picker(struct mlxsw_afk *mlxsw_afk,
struct mlxsw_afk_key_info *key_info,
struct mlxsw_afk_element_usage *elusage)
{
+ DECLARE_BITMAP(elusage_chosen, MLXSW_AFK_ELEMENT_MAX) = {0};
struct mlxsw_afk_picker *picker;
+ unsigned long *chosen_blocks_bm;
enum mlxsw_afk_element element;
int err;
@@ -230,6 +265,12 @@ static int mlxsw_afk_picker(struct mlxsw_afk *mlxsw_afk,
if (!picker)
return -ENOMEM;
+ chosen_blocks_bm = bitmap_zalloc(mlxsw_afk->blocks_count, GFP_KERNEL);
+ if (!chosen_blocks_bm) {
+ err = -ENOMEM;
+ goto err_bitmap_alloc;
+ }
+
/* Since the same elements could be present in multiple blocks,
* we must find out optimal block list in order to make the
* block count as low as possible.
@@ -254,15 +295,26 @@ static int mlxsw_afk_picker(struct mlxsw_afk *mlxsw_afk,
err = block_index;
goto out;
}
- err = mlxsw_afk_picker_key_info_add(mlxsw_afk, picker,
- block_index, key_info);
- if (err)
- goto out;
+
+ __set_bit(block_index, chosen_blocks_bm);
+
+ bitmap_copy(picker[block_index].chosen_element,
+ picker[block_index].element, MLXSW_AFK_ELEMENT_MAX);
+
+ bitmap_or(elusage_chosen, elusage_chosen,
+ picker[block_index].chosen_element,
+ MLXSW_AFK_ELEMENT_MAX);
+
mlxsw_afk_picker_subtract_hits(mlxsw_afk, picker, block_index);
- } while (!mlxsw_afk_key_info_elements_eq(key_info, elusage));
- err = 0;
+ } while (!bitmap_equal(elusage_chosen, elusage->usage,
+ MLXSW_AFK_ELEMENT_MAX));
+
+ err = mlxsw_afk_keys_fill(mlxsw_afk, chosen_blocks_bm, picker,
+ key_info);
out:
+ bitmap_free(chosen_blocks_bm);
+err_bitmap_alloc:
kfree(picker);
return err;
}