19948a064SJiri Pirko // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 29948a064SJiri Pirko /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */ 33f1a84e6SJiri Pirko 43f1a84e6SJiri Pirko #include <linux/kernel.h> 53f1a84e6SJiri Pirko #include <linux/slab.h> 63f1a84e6SJiri Pirko #include <linux/list.h> 73f1a84e6SJiri Pirko #include <linux/errno.h> 83f1a84e6SJiri Pirko 93f1a84e6SJiri Pirko #include "item.h" 103f1a84e6SJiri Pirko #include "core_acl_flex_keys.h" 113f1a84e6SJiri Pirko 123f1a84e6SJiri Pirko struct mlxsw_afk { 133f1a84e6SJiri Pirko struct list_head key_info_list; 143f1a84e6SJiri Pirko unsigned int max_blocks; 15c17d2083SJiri Pirko const struct mlxsw_afk_ops *ops; 163f1a84e6SJiri Pirko const struct mlxsw_afk_block *blocks; 173f1a84e6SJiri Pirko unsigned int blocks_count; 183f1a84e6SJiri Pirko }; 193f1a84e6SJiri Pirko 203f1a84e6SJiri Pirko static bool mlxsw_afk_blocks_check(struct mlxsw_afk *mlxsw_afk) 213f1a84e6SJiri Pirko { 223f1a84e6SJiri Pirko int i; 233f1a84e6SJiri Pirko int j; 243f1a84e6SJiri Pirko 253f1a84e6SJiri Pirko for (i = 0; i < mlxsw_afk->blocks_count; i++) { 263f1a84e6SJiri Pirko const struct mlxsw_afk_block *block = &mlxsw_afk->blocks[i]; 273f1a84e6SJiri Pirko 283f1a84e6SJiri Pirko for (j = 0; j < block->instances_count; j++) { 293f1a84e6SJiri Pirko struct mlxsw_afk_element_inst *elinst; 303f1a84e6SJiri Pirko 313f1a84e6SJiri Pirko elinst = &block->instances[j]; 323f1a84e6SJiri Pirko if (elinst->type != elinst->info->type || 333f1a84e6SJiri Pirko elinst->item.size.bits != 343f1a84e6SJiri Pirko elinst->info->item.size.bits) 353f1a84e6SJiri Pirko return false; 363f1a84e6SJiri Pirko } 373f1a84e6SJiri Pirko } 383f1a84e6SJiri Pirko return true; 393f1a84e6SJiri Pirko } 403f1a84e6SJiri Pirko 413f1a84e6SJiri Pirko struct mlxsw_afk *mlxsw_afk_create(unsigned int max_blocks, 42c17d2083SJiri Pirko const struct mlxsw_afk_ops *ops) 433f1a84e6SJiri Pirko { 443f1a84e6SJiri Pirko struct mlxsw_afk *mlxsw_afk; 453f1a84e6SJiri Pirko 463f1a84e6SJiri Pirko mlxsw_afk = kzalloc(sizeof(*mlxsw_afk), GFP_KERNEL); 473f1a84e6SJiri Pirko if (!mlxsw_afk) 483f1a84e6SJiri Pirko return NULL; 493f1a84e6SJiri Pirko INIT_LIST_HEAD(&mlxsw_afk->key_info_list); 503f1a84e6SJiri Pirko mlxsw_afk->max_blocks = max_blocks; 51c17d2083SJiri Pirko mlxsw_afk->ops = ops; 52c17d2083SJiri Pirko mlxsw_afk->blocks = ops->blocks; 53c17d2083SJiri Pirko mlxsw_afk->blocks_count = ops->blocks_count; 543f1a84e6SJiri Pirko WARN_ON(!mlxsw_afk_blocks_check(mlxsw_afk)); 553f1a84e6SJiri Pirko return mlxsw_afk; 563f1a84e6SJiri Pirko } 573f1a84e6SJiri Pirko EXPORT_SYMBOL(mlxsw_afk_create); 583f1a84e6SJiri Pirko 593f1a84e6SJiri Pirko void mlxsw_afk_destroy(struct mlxsw_afk *mlxsw_afk) 603f1a84e6SJiri Pirko { 613f1a84e6SJiri Pirko WARN_ON(!list_empty(&mlxsw_afk->key_info_list)); 623f1a84e6SJiri Pirko kfree(mlxsw_afk); 633f1a84e6SJiri Pirko } 643f1a84e6SJiri Pirko EXPORT_SYMBOL(mlxsw_afk_destroy); 653f1a84e6SJiri Pirko 663f1a84e6SJiri Pirko struct mlxsw_afk_key_info { 673f1a84e6SJiri Pirko struct list_head list; 683f1a84e6SJiri Pirko unsigned int ref_count; 693f1a84e6SJiri Pirko unsigned int blocks_count; 703f1a84e6SJiri Pirko int element_to_block[MLXSW_AFK_ELEMENT_MAX]; /* index is element, value 713f1a84e6SJiri Pirko * is index inside "blocks" 723f1a84e6SJiri Pirko */ 733f1a84e6SJiri Pirko struct mlxsw_afk_element_usage elusage; 743f1a84e6SJiri Pirko const struct mlxsw_afk_block *blocks[0]; 753f1a84e6SJiri Pirko }; 763f1a84e6SJiri Pirko 773f1a84e6SJiri Pirko static bool 783f1a84e6SJiri Pirko mlxsw_afk_key_info_elements_eq(struct mlxsw_afk_key_info *key_info, 793f1a84e6SJiri Pirko struct mlxsw_afk_element_usage *elusage) 803f1a84e6SJiri Pirko { 813f1a84e6SJiri Pirko return memcmp(&key_info->elusage, elusage, sizeof(*elusage)) == 0; 823f1a84e6SJiri Pirko } 833f1a84e6SJiri Pirko 843f1a84e6SJiri Pirko static struct mlxsw_afk_key_info * 853f1a84e6SJiri Pirko mlxsw_afk_key_info_find(struct mlxsw_afk *mlxsw_afk, 863f1a84e6SJiri Pirko struct mlxsw_afk_element_usage *elusage) 873f1a84e6SJiri Pirko { 883f1a84e6SJiri Pirko struct mlxsw_afk_key_info *key_info; 893f1a84e6SJiri Pirko 903f1a84e6SJiri Pirko list_for_each_entry(key_info, &mlxsw_afk->key_info_list, list) { 913f1a84e6SJiri Pirko if (mlxsw_afk_key_info_elements_eq(key_info, elusage)) 923f1a84e6SJiri Pirko return key_info; 933f1a84e6SJiri Pirko } 943f1a84e6SJiri Pirko return NULL; 953f1a84e6SJiri Pirko } 963f1a84e6SJiri Pirko 973f1a84e6SJiri Pirko struct mlxsw_afk_picker { 983f1a84e6SJiri Pirko struct { 993f1a84e6SJiri Pirko DECLARE_BITMAP(element, MLXSW_AFK_ELEMENT_MAX); 1003f1a84e6SJiri Pirko unsigned int total; 1013f1a84e6SJiri Pirko } hits[0]; 1023f1a84e6SJiri Pirko }; 1033f1a84e6SJiri Pirko 1043f1a84e6SJiri Pirko static void mlxsw_afk_picker_count_hits(struct mlxsw_afk *mlxsw_afk, 1053f1a84e6SJiri Pirko struct mlxsw_afk_picker *picker, 1063f1a84e6SJiri Pirko enum mlxsw_afk_element element) 1073f1a84e6SJiri Pirko { 1083f1a84e6SJiri Pirko int i; 1093f1a84e6SJiri Pirko int j; 1103f1a84e6SJiri Pirko 1113f1a84e6SJiri Pirko for (i = 0; i < mlxsw_afk->blocks_count; i++) { 1123f1a84e6SJiri Pirko const struct mlxsw_afk_block *block = &mlxsw_afk->blocks[i]; 1133f1a84e6SJiri Pirko 1143f1a84e6SJiri Pirko for (j = 0; j < block->instances_count; j++) { 1153f1a84e6SJiri Pirko struct mlxsw_afk_element_inst *elinst; 1163f1a84e6SJiri Pirko 1173f1a84e6SJiri Pirko elinst = &block->instances[j]; 1183f1a84e6SJiri Pirko if (elinst->info->element == element) { 1193f1a84e6SJiri Pirko __set_bit(element, picker->hits[i].element); 1203f1a84e6SJiri Pirko picker->hits[i].total++; 1213f1a84e6SJiri Pirko } 1223f1a84e6SJiri Pirko } 1233f1a84e6SJiri Pirko } 1243f1a84e6SJiri Pirko } 1253f1a84e6SJiri Pirko 1263f1a84e6SJiri Pirko static void mlxsw_afk_picker_subtract_hits(struct mlxsw_afk *mlxsw_afk, 1273f1a84e6SJiri Pirko struct mlxsw_afk_picker *picker, 1283f1a84e6SJiri Pirko int block_index) 1293f1a84e6SJiri Pirko { 1303f1a84e6SJiri Pirko DECLARE_BITMAP(hits_element, MLXSW_AFK_ELEMENT_MAX); 1313f1a84e6SJiri Pirko int i; 1323f1a84e6SJiri Pirko int j; 1333f1a84e6SJiri Pirko 1343f1a84e6SJiri Pirko memcpy(&hits_element, &picker->hits[block_index].element, 1353f1a84e6SJiri Pirko sizeof(hits_element)); 1363f1a84e6SJiri Pirko 1373f1a84e6SJiri Pirko for (i = 0; i < mlxsw_afk->blocks_count; i++) { 1383f1a84e6SJiri Pirko for_each_set_bit(j, hits_element, MLXSW_AFK_ELEMENT_MAX) { 1393f1a84e6SJiri Pirko if (__test_and_clear_bit(j, picker->hits[i].element)) 1403f1a84e6SJiri Pirko picker->hits[i].total--; 1413f1a84e6SJiri Pirko } 1423f1a84e6SJiri Pirko } 1433f1a84e6SJiri Pirko } 1443f1a84e6SJiri Pirko 1453f1a84e6SJiri Pirko static int mlxsw_afk_picker_most_hits_get(struct mlxsw_afk *mlxsw_afk, 1463f1a84e6SJiri Pirko struct mlxsw_afk_picker *picker) 1473f1a84e6SJiri Pirko { 1483f1a84e6SJiri Pirko int most_index = -EINVAL; /* Should never happen to return this */ 1493f1a84e6SJiri Pirko int most_hits = 0; 1503f1a84e6SJiri Pirko int i; 1513f1a84e6SJiri Pirko 1523f1a84e6SJiri Pirko for (i = 0; i < mlxsw_afk->blocks_count; i++) { 1533f1a84e6SJiri Pirko if (picker->hits[i].total > most_hits) { 1543f1a84e6SJiri Pirko most_hits = picker->hits[i].total; 1553f1a84e6SJiri Pirko most_index = i; 1563f1a84e6SJiri Pirko } 1573f1a84e6SJiri Pirko } 1583f1a84e6SJiri Pirko return most_index; 1593f1a84e6SJiri Pirko } 1603f1a84e6SJiri Pirko 1613f1a84e6SJiri Pirko static int mlxsw_afk_picker_key_info_add(struct mlxsw_afk *mlxsw_afk, 1623f1a84e6SJiri Pirko struct mlxsw_afk_picker *picker, 1633f1a84e6SJiri Pirko int block_index, 1643f1a84e6SJiri Pirko struct mlxsw_afk_key_info *key_info) 1653f1a84e6SJiri Pirko { 1663f1a84e6SJiri Pirko enum mlxsw_afk_element element; 1673f1a84e6SJiri Pirko 1683f1a84e6SJiri Pirko if (key_info->blocks_count == mlxsw_afk->max_blocks) 1693f1a84e6SJiri Pirko return -EINVAL; 1703f1a84e6SJiri Pirko 1713f1a84e6SJiri Pirko for_each_set_bit(element, picker->hits[block_index].element, 1723f1a84e6SJiri Pirko MLXSW_AFK_ELEMENT_MAX) { 1733f1a84e6SJiri Pirko key_info->element_to_block[element] = key_info->blocks_count; 1743f1a84e6SJiri Pirko mlxsw_afk_element_usage_add(&key_info->elusage, element); 1753f1a84e6SJiri Pirko } 1763f1a84e6SJiri Pirko 1773f1a84e6SJiri Pirko key_info->blocks[key_info->blocks_count] = 1783f1a84e6SJiri Pirko &mlxsw_afk->blocks[block_index]; 1793f1a84e6SJiri Pirko key_info->blocks_count++; 1803f1a84e6SJiri Pirko return 0; 1813f1a84e6SJiri Pirko } 1823f1a84e6SJiri Pirko 1833f1a84e6SJiri Pirko static int mlxsw_afk_picker(struct mlxsw_afk *mlxsw_afk, 1843f1a84e6SJiri Pirko struct mlxsw_afk_key_info *key_info, 1853f1a84e6SJiri Pirko struct mlxsw_afk_element_usage *elusage) 1863f1a84e6SJiri Pirko { 1873f1a84e6SJiri Pirko struct mlxsw_afk_picker *picker; 1883f1a84e6SJiri Pirko enum mlxsw_afk_element element; 1893f1a84e6SJiri Pirko size_t alloc_size; 1903f1a84e6SJiri Pirko int err; 1913f1a84e6SJiri Pirko 1923f1a84e6SJiri Pirko alloc_size = sizeof(picker->hits[0]) * mlxsw_afk->blocks_count; 1933f1a84e6SJiri Pirko picker = kzalloc(alloc_size, GFP_KERNEL); 1943f1a84e6SJiri Pirko if (!picker) 1953f1a84e6SJiri Pirko return -ENOMEM; 1963f1a84e6SJiri Pirko 1973f1a84e6SJiri Pirko /* Since the same elements could be present in multiple blocks, 1983f1a84e6SJiri Pirko * we must find out optimal block list in order to make the 1993f1a84e6SJiri Pirko * block count as low as possible. 2003f1a84e6SJiri Pirko * 2013f1a84e6SJiri Pirko * First, we count hits. We go over all available blocks and count 2023f1a84e6SJiri Pirko * how many of requested elements are covered by each. 2033f1a84e6SJiri Pirko * 2043f1a84e6SJiri Pirko * Then in loop, we find block with most hits and add it to 2053f1a84e6SJiri Pirko * output key_info. Then we have to subtract this block hits so 2063f1a84e6SJiri Pirko * the next iteration will find most suitable block for 2073f1a84e6SJiri Pirko * the rest of requested elements. 2083f1a84e6SJiri Pirko */ 2093f1a84e6SJiri Pirko 2103f1a84e6SJiri Pirko mlxsw_afk_element_usage_for_each(element, elusage) 2113f1a84e6SJiri Pirko mlxsw_afk_picker_count_hits(mlxsw_afk, picker, element); 2123f1a84e6SJiri Pirko 2133f1a84e6SJiri Pirko do { 2143f1a84e6SJiri Pirko int block_index; 2153f1a84e6SJiri Pirko 2163f1a84e6SJiri Pirko block_index = mlxsw_afk_picker_most_hits_get(mlxsw_afk, picker); 2173f1a84e6SJiri Pirko if (block_index < 0) { 2183f1a84e6SJiri Pirko err = block_index; 2193f1a84e6SJiri Pirko goto out; 2203f1a84e6SJiri Pirko } 2213f1a84e6SJiri Pirko err = mlxsw_afk_picker_key_info_add(mlxsw_afk, picker, 2223f1a84e6SJiri Pirko block_index, key_info); 2233f1a84e6SJiri Pirko if (err) 2243f1a84e6SJiri Pirko goto out; 2253f1a84e6SJiri Pirko mlxsw_afk_picker_subtract_hits(mlxsw_afk, picker, block_index); 2263f1a84e6SJiri Pirko } while (!mlxsw_afk_key_info_elements_eq(key_info, elusage)); 2273f1a84e6SJiri Pirko 2283f1a84e6SJiri Pirko err = 0; 2293f1a84e6SJiri Pirko out: 2303f1a84e6SJiri Pirko kfree(picker); 2313f1a84e6SJiri Pirko return err; 2323f1a84e6SJiri Pirko } 2333f1a84e6SJiri Pirko 2343f1a84e6SJiri Pirko static struct mlxsw_afk_key_info * 2353f1a84e6SJiri Pirko mlxsw_afk_key_info_create(struct mlxsw_afk *mlxsw_afk, 2363f1a84e6SJiri Pirko struct mlxsw_afk_element_usage *elusage) 2373f1a84e6SJiri Pirko { 2383f1a84e6SJiri Pirko struct mlxsw_afk_key_info *key_info; 2393f1a84e6SJiri Pirko size_t alloc_size; 2403f1a84e6SJiri Pirko int err; 2413f1a84e6SJiri Pirko 2423f1a84e6SJiri Pirko alloc_size = sizeof(*key_info) + 2433f1a84e6SJiri Pirko sizeof(key_info->blocks[0]) * mlxsw_afk->max_blocks; 2443f1a84e6SJiri Pirko key_info = kzalloc(alloc_size, GFP_KERNEL); 2453f1a84e6SJiri Pirko if (!key_info) 2463f1a84e6SJiri Pirko return ERR_PTR(-ENOMEM); 2473f1a84e6SJiri Pirko err = mlxsw_afk_picker(mlxsw_afk, key_info, elusage); 2483f1a84e6SJiri Pirko if (err) 2493f1a84e6SJiri Pirko goto err_picker; 2503f1a84e6SJiri Pirko list_add(&key_info->list, &mlxsw_afk->key_info_list); 2513f1a84e6SJiri Pirko key_info->ref_count = 1; 2523f1a84e6SJiri Pirko return key_info; 2533f1a84e6SJiri Pirko 2543f1a84e6SJiri Pirko err_picker: 2553f1a84e6SJiri Pirko kfree(key_info); 2563f1a84e6SJiri Pirko return ERR_PTR(err); 2573f1a84e6SJiri Pirko } 2583f1a84e6SJiri Pirko 2593f1a84e6SJiri Pirko static void mlxsw_afk_key_info_destroy(struct mlxsw_afk_key_info *key_info) 2603f1a84e6SJiri Pirko { 2613f1a84e6SJiri Pirko list_del(&key_info->list); 2623f1a84e6SJiri Pirko kfree(key_info); 2633f1a84e6SJiri Pirko } 2643f1a84e6SJiri Pirko 2653f1a84e6SJiri Pirko struct mlxsw_afk_key_info * 2663f1a84e6SJiri Pirko mlxsw_afk_key_info_get(struct mlxsw_afk *mlxsw_afk, 2673f1a84e6SJiri Pirko struct mlxsw_afk_element_usage *elusage) 2683f1a84e6SJiri Pirko { 2693f1a84e6SJiri Pirko struct mlxsw_afk_key_info *key_info; 2703f1a84e6SJiri Pirko 2713f1a84e6SJiri Pirko key_info = mlxsw_afk_key_info_find(mlxsw_afk, elusage); 2723f1a84e6SJiri Pirko if (key_info) { 2733f1a84e6SJiri Pirko key_info->ref_count++; 2743f1a84e6SJiri Pirko return key_info; 2753f1a84e6SJiri Pirko } 2763f1a84e6SJiri Pirko return mlxsw_afk_key_info_create(mlxsw_afk, elusage); 2773f1a84e6SJiri Pirko } 2783f1a84e6SJiri Pirko EXPORT_SYMBOL(mlxsw_afk_key_info_get); 2793f1a84e6SJiri Pirko 2803f1a84e6SJiri Pirko void mlxsw_afk_key_info_put(struct mlxsw_afk_key_info *key_info) 2813f1a84e6SJiri Pirko { 2823f1a84e6SJiri Pirko if (--key_info->ref_count) 2833f1a84e6SJiri Pirko return; 2843f1a84e6SJiri Pirko mlxsw_afk_key_info_destroy(key_info); 2853f1a84e6SJiri Pirko } 2863f1a84e6SJiri Pirko EXPORT_SYMBOL(mlxsw_afk_key_info_put); 2873f1a84e6SJiri Pirko 2883f1a84e6SJiri Pirko bool mlxsw_afk_key_info_subset(struct mlxsw_afk_key_info *key_info, 2893f1a84e6SJiri Pirko struct mlxsw_afk_element_usage *elusage) 2903f1a84e6SJiri Pirko { 2913f1a84e6SJiri Pirko return mlxsw_afk_element_usage_subset(elusage, &key_info->elusage); 2923f1a84e6SJiri Pirko } 2933f1a84e6SJiri Pirko EXPORT_SYMBOL(mlxsw_afk_key_info_subset); 2943f1a84e6SJiri Pirko 2953f1a84e6SJiri Pirko static const struct mlxsw_afk_element_inst * 2963f1a84e6SJiri Pirko mlxsw_afk_block_elinst_get(const struct mlxsw_afk_block *block, 2973f1a84e6SJiri Pirko enum mlxsw_afk_element element) 2983f1a84e6SJiri Pirko { 2993f1a84e6SJiri Pirko int i; 3003f1a84e6SJiri Pirko 3013f1a84e6SJiri Pirko for (i = 0; i < block->instances_count; i++) { 3023f1a84e6SJiri Pirko struct mlxsw_afk_element_inst *elinst; 3033f1a84e6SJiri Pirko 3043f1a84e6SJiri Pirko elinst = &block->instances[i]; 3053f1a84e6SJiri Pirko if (elinst->info->element == element) 3063f1a84e6SJiri Pirko return elinst; 3073f1a84e6SJiri Pirko } 3083f1a84e6SJiri Pirko return NULL; 3093f1a84e6SJiri Pirko } 3103f1a84e6SJiri Pirko 3113f1a84e6SJiri Pirko static const struct mlxsw_afk_element_inst * 3123f1a84e6SJiri Pirko mlxsw_afk_key_info_elinst_get(struct mlxsw_afk_key_info *key_info, 3133f1a84e6SJiri Pirko enum mlxsw_afk_element element, 3143f1a84e6SJiri Pirko int *p_block_index) 3153f1a84e6SJiri Pirko { 3163f1a84e6SJiri Pirko const struct mlxsw_afk_element_inst *elinst; 3173f1a84e6SJiri Pirko const struct mlxsw_afk_block *block; 3183f1a84e6SJiri Pirko int block_index; 3193f1a84e6SJiri Pirko 3203f1a84e6SJiri Pirko if (WARN_ON(!test_bit(element, key_info->elusage.usage))) 3213f1a84e6SJiri Pirko return NULL; 3223f1a84e6SJiri Pirko block_index = key_info->element_to_block[element]; 3233f1a84e6SJiri Pirko block = key_info->blocks[block_index]; 3243f1a84e6SJiri Pirko 3253f1a84e6SJiri Pirko elinst = mlxsw_afk_block_elinst_get(block, element); 3263f1a84e6SJiri Pirko if (WARN_ON(!elinst)) 3273f1a84e6SJiri Pirko return NULL; 3283f1a84e6SJiri Pirko 3293f1a84e6SJiri Pirko *p_block_index = block_index; 3303f1a84e6SJiri Pirko return elinst; 3313f1a84e6SJiri Pirko } 3323f1a84e6SJiri Pirko 3333f1a84e6SJiri Pirko u16 3343f1a84e6SJiri Pirko mlxsw_afk_key_info_block_encoding_get(const struct mlxsw_afk_key_info *key_info, 3353f1a84e6SJiri Pirko int block_index) 3363f1a84e6SJiri Pirko { 3373f1a84e6SJiri Pirko return key_info->blocks[block_index]->encoding; 3383f1a84e6SJiri Pirko } 3393f1a84e6SJiri Pirko EXPORT_SYMBOL(mlxsw_afk_key_info_block_encoding_get); 3403f1a84e6SJiri Pirko 3413f1a84e6SJiri Pirko unsigned int 3423f1a84e6SJiri Pirko mlxsw_afk_key_info_blocks_count_get(const struct mlxsw_afk_key_info *key_info) 3433f1a84e6SJiri Pirko { 3443f1a84e6SJiri Pirko return key_info->blocks_count; 3453f1a84e6SJiri Pirko } 3463f1a84e6SJiri Pirko EXPORT_SYMBOL(mlxsw_afk_key_info_blocks_count_get); 3473f1a84e6SJiri Pirko 3483f1a84e6SJiri Pirko void mlxsw_afk_values_add_u32(struct mlxsw_afk_element_values *values, 3493f1a84e6SJiri Pirko enum mlxsw_afk_element element, 3503f1a84e6SJiri Pirko u32 key_value, u32 mask_value) 3513f1a84e6SJiri Pirko { 3523f1a84e6SJiri Pirko const struct mlxsw_afk_element_info *elinfo = 3533f1a84e6SJiri Pirko &mlxsw_afk_element_infos[element]; 3543f1a84e6SJiri Pirko const struct mlxsw_item *storage_item = &elinfo->item; 3553f1a84e6SJiri Pirko 3563f1a84e6SJiri Pirko if (!mask_value) 3573f1a84e6SJiri Pirko return; 3583f1a84e6SJiri Pirko if (WARN_ON(elinfo->type != MLXSW_AFK_ELEMENT_TYPE_U32)) 3593f1a84e6SJiri Pirko return; 3603f1a84e6SJiri Pirko __mlxsw_item_set32(values->storage.key, storage_item, 0, key_value); 3613f1a84e6SJiri Pirko __mlxsw_item_set32(values->storage.mask, storage_item, 0, mask_value); 3623f1a84e6SJiri Pirko mlxsw_afk_element_usage_add(&values->elusage, element); 3633f1a84e6SJiri Pirko } 3643f1a84e6SJiri Pirko EXPORT_SYMBOL(mlxsw_afk_values_add_u32); 3653f1a84e6SJiri Pirko 3663f1a84e6SJiri Pirko void mlxsw_afk_values_add_buf(struct mlxsw_afk_element_values *values, 3673f1a84e6SJiri Pirko enum mlxsw_afk_element element, 3683f1a84e6SJiri Pirko const char *key_value, const char *mask_value, 3693f1a84e6SJiri Pirko unsigned int len) 3703f1a84e6SJiri Pirko { 3713f1a84e6SJiri Pirko const struct mlxsw_afk_element_info *elinfo = 3723f1a84e6SJiri Pirko &mlxsw_afk_element_infos[element]; 3733f1a84e6SJiri Pirko const struct mlxsw_item *storage_item = &elinfo->item; 3743f1a84e6SJiri Pirko 3753f1a84e6SJiri Pirko if (!memchr_inv(mask_value, 0, len)) /* If mask is zero */ 3763f1a84e6SJiri Pirko return; 3773f1a84e6SJiri Pirko if (WARN_ON(elinfo->type != MLXSW_AFK_ELEMENT_TYPE_BUF) || 3783f1a84e6SJiri Pirko WARN_ON(elinfo->item.size.bytes != len)) 3793f1a84e6SJiri Pirko return; 3803f1a84e6SJiri Pirko __mlxsw_item_memcpy_to(values->storage.key, key_value, 3813f1a84e6SJiri Pirko storage_item, 0); 3823f1a84e6SJiri Pirko __mlxsw_item_memcpy_to(values->storage.mask, mask_value, 3833f1a84e6SJiri Pirko storage_item, 0); 3843f1a84e6SJiri Pirko mlxsw_afk_element_usage_add(&values->elusage, element); 3853f1a84e6SJiri Pirko } 3863f1a84e6SJiri Pirko EXPORT_SYMBOL(mlxsw_afk_values_add_buf); 3873f1a84e6SJiri Pirko 388a6d70a87SIdo Schimmel static void mlxsw_sp_afk_encode_u32(const struct mlxsw_item *storage_item, 389a6d70a87SIdo Schimmel const struct mlxsw_item *output_item, 390a6d70a87SIdo Schimmel char *storage, char *output) 391a6d70a87SIdo Schimmel { 392a6d70a87SIdo Schimmel u32 value; 393a6d70a87SIdo Schimmel 394a6d70a87SIdo Schimmel value = __mlxsw_item_get32(storage, storage_item, 0); 395a6d70a87SIdo Schimmel __mlxsw_item_set32(output, output_item, 0, value); 396a6d70a87SIdo Schimmel } 397a6d70a87SIdo Schimmel 398a6d70a87SIdo Schimmel static void mlxsw_sp_afk_encode_buf(const struct mlxsw_item *storage_item, 399a6d70a87SIdo Schimmel const struct mlxsw_item *output_item, 400a6d70a87SIdo Schimmel char *storage, char *output) 401a6d70a87SIdo Schimmel { 402a6d70a87SIdo Schimmel char *storage_data = __mlxsw_item_data(storage, storage_item, 0); 403a6d70a87SIdo Schimmel char *output_data = __mlxsw_item_data(output, output_item, 0); 404a6d70a87SIdo Schimmel size_t len = output_item->size.bytes; 405a6d70a87SIdo Schimmel 406a6d70a87SIdo Schimmel memcpy(output_data, storage_data, len); 407a6d70a87SIdo Schimmel } 408a6d70a87SIdo Schimmel 409a6d70a87SIdo Schimmel static void 410a6d70a87SIdo Schimmel mlxsw_sp_afk_encode_one(const struct mlxsw_afk_element_inst *elinst, 411a6d70a87SIdo Schimmel char *output, char *storage) 412a6d70a87SIdo Schimmel { 413a6d70a87SIdo Schimmel const struct mlxsw_item *storage_item = &elinst->info->item; 414a6d70a87SIdo Schimmel const struct mlxsw_item *output_item = &elinst->item; 415a6d70a87SIdo Schimmel 416a6d70a87SIdo Schimmel if (elinst->type == MLXSW_AFK_ELEMENT_TYPE_U32) 417a6d70a87SIdo Schimmel mlxsw_sp_afk_encode_u32(storage_item, output_item, 418a6d70a87SIdo Schimmel storage, output); 419a6d70a87SIdo Schimmel else if (elinst->type == MLXSW_AFK_ELEMENT_TYPE_BUF) 420a6d70a87SIdo Schimmel mlxsw_sp_afk_encode_buf(storage_item, output_item, 421a6d70a87SIdo Schimmel storage, output); 422a6d70a87SIdo Schimmel } 423a6d70a87SIdo Schimmel 424a6d70a87SIdo Schimmel #define MLXSW_SP_AFK_KEY_BLOCK_MAX_SIZE 16 425a6d70a87SIdo Schimmel 426a5995cc8SJiri Pirko void mlxsw_afk_encode(struct mlxsw_afk *mlxsw_afk, 427a5995cc8SJiri Pirko struct mlxsw_afk_key_info *key_info, 4283f1a84e6SJiri Pirko struct mlxsw_afk_element_values *values, 429ca49544eSIdo Schimmel char *key, char *mask, int block_start, int block_end) 4303f1a84e6SJiri Pirko { 431a6d70a87SIdo Schimmel char block_mask[MLXSW_SP_AFK_KEY_BLOCK_MAX_SIZE]; 432a6d70a87SIdo Schimmel char block_key[MLXSW_SP_AFK_KEY_BLOCK_MAX_SIZE]; 4333f1a84e6SJiri Pirko const struct mlxsw_afk_element_inst *elinst; 4343f1a84e6SJiri Pirko enum mlxsw_afk_element element; 435a6d70a87SIdo Schimmel int block_index, i; 436a6d70a87SIdo Schimmel 437ca49544eSIdo Schimmel for (i = block_start; i <= block_end; i++) { 438a6d70a87SIdo Schimmel memset(block_key, 0, MLXSW_SP_AFK_KEY_BLOCK_MAX_SIZE); 439a6d70a87SIdo Schimmel memset(block_mask, 0, MLXSW_SP_AFK_KEY_BLOCK_MAX_SIZE); 4403f1a84e6SJiri Pirko 4413f1a84e6SJiri Pirko mlxsw_afk_element_usage_for_each(element, &values->elusage) { 442a6d70a87SIdo Schimmel elinst = mlxsw_afk_key_info_elinst_get(key_info, 443a6d70a87SIdo Schimmel element, 4443f1a84e6SJiri Pirko &block_index); 445a6d70a87SIdo Schimmel if (!elinst || block_index != i) 4463f1a84e6SJiri Pirko continue; 447a6d70a87SIdo Schimmel 448a6d70a87SIdo Schimmel mlxsw_sp_afk_encode_one(elinst, block_key, 449a6d70a87SIdo Schimmel values->storage.key); 450a6d70a87SIdo Schimmel mlxsw_sp_afk_encode_one(elinst, block_mask, 451a6d70a87SIdo Schimmel values->storage.mask); 452a6d70a87SIdo Schimmel } 453a6d70a87SIdo Schimmel 454ca49544eSIdo Schimmel if (key) 4553bc6f385SJiri Pirko mlxsw_afk->ops->encode_block(key, i, block_key); 456ca49544eSIdo Schimmel if (mask) 4573bc6f385SJiri Pirko mlxsw_afk->ops->encode_block(mask, i, block_mask); 4583f1a84e6SJiri Pirko } 4593f1a84e6SJiri Pirko } 4603f1a84e6SJiri Pirko EXPORT_SYMBOL(mlxsw_afk_encode); 461b1ce60e6SJiri Pirko 462b1ce60e6SJiri Pirko void mlxsw_afk_clear(struct mlxsw_afk *mlxsw_afk, char *key, 463b1ce60e6SJiri Pirko int block_start, int block_end) 464b1ce60e6SJiri Pirko { 465b1ce60e6SJiri Pirko int i; 466b1ce60e6SJiri Pirko 467b1ce60e6SJiri Pirko for (i = block_start; i <= block_end; i++) 468b1ce60e6SJiri Pirko mlxsw_afk->ops->clear_block(key, i); 469b1ce60e6SJiri Pirko } 470b1ce60e6SJiri Pirko EXPORT_SYMBOL(mlxsw_afk_clear); 471