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 	int err;
2403f1a84e6SJiri Pirko 
24178844068SGustavo A. R. Silva 	key_info = kzalloc(struct_size(key_info, blocks, mlxsw_afk->max_blocks),
24278844068SGustavo A. R. Silva 			   GFP_KERNEL);
2433f1a84e6SJiri Pirko 	if (!key_info)
2443f1a84e6SJiri Pirko 		return ERR_PTR(-ENOMEM);
2453f1a84e6SJiri Pirko 	err = mlxsw_afk_picker(mlxsw_afk, key_info, elusage);
2463f1a84e6SJiri Pirko 	if (err)
2473f1a84e6SJiri Pirko 		goto err_picker;
2483f1a84e6SJiri Pirko 	list_add(&key_info->list, &mlxsw_afk->key_info_list);
2493f1a84e6SJiri Pirko 	key_info->ref_count = 1;
2503f1a84e6SJiri Pirko 	return key_info;
2513f1a84e6SJiri Pirko 
2523f1a84e6SJiri Pirko err_picker:
2533f1a84e6SJiri Pirko 	kfree(key_info);
2543f1a84e6SJiri Pirko 	return ERR_PTR(err);
2553f1a84e6SJiri Pirko }
2563f1a84e6SJiri Pirko 
2573f1a84e6SJiri Pirko static void mlxsw_afk_key_info_destroy(struct mlxsw_afk_key_info *key_info)
2583f1a84e6SJiri Pirko {
2593f1a84e6SJiri Pirko 	list_del(&key_info->list);
2603f1a84e6SJiri Pirko 	kfree(key_info);
2613f1a84e6SJiri Pirko }
2623f1a84e6SJiri Pirko 
2633f1a84e6SJiri Pirko struct mlxsw_afk_key_info *
2643f1a84e6SJiri Pirko mlxsw_afk_key_info_get(struct mlxsw_afk *mlxsw_afk,
2653f1a84e6SJiri Pirko 		       struct mlxsw_afk_element_usage *elusage)
2663f1a84e6SJiri Pirko {
2673f1a84e6SJiri Pirko 	struct mlxsw_afk_key_info *key_info;
2683f1a84e6SJiri Pirko 
2693f1a84e6SJiri Pirko 	key_info = mlxsw_afk_key_info_find(mlxsw_afk, elusage);
2703f1a84e6SJiri Pirko 	if (key_info) {
2713f1a84e6SJiri Pirko 		key_info->ref_count++;
2723f1a84e6SJiri Pirko 		return key_info;
2733f1a84e6SJiri Pirko 	}
2743f1a84e6SJiri Pirko 	return mlxsw_afk_key_info_create(mlxsw_afk, elusage);
2753f1a84e6SJiri Pirko }
2763f1a84e6SJiri Pirko EXPORT_SYMBOL(mlxsw_afk_key_info_get);
2773f1a84e6SJiri Pirko 
2783f1a84e6SJiri Pirko void mlxsw_afk_key_info_put(struct mlxsw_afk_key_info *key_info)
2793f1a84e6SJiri Pirko {
2803f1a84e6SJiri Pirko 	if (--key_info->ref_count)
2813f1a84e6SJiri Pirko 		return;
2823f1a84e6SJiri Pirko 	mlxsw_afk_key_info_destroy(key_info);
2833f1a84e6SJiri Pirko }
2843f1a84e6SJiri Pirko EXPORT_SYMBOL(mlxsw_afk_key_info_put);
2853f1a84e6SJiri Pirko 
2863f1a84e6SJiri Pirko bool mlxsw_afk_key_info_subset(struct mlxsw_afk_key_info *key_info,
2873f1a84e6SJiri Pirko 			       struct mlxsw_afk_element_usage *elusage)
2883f1a84e6SJiri Pirko {
2893f1a84e6SJiri Pirko 	return mlxsw_afk_element_usage_subset(elusage, &key_info->elusage);
2903f1a84e6SJiri Pirko }
2913f1a84e6SJiri Pirko EXPORT_SYMBOL(mlxsw_afk_key_info_subset);
2923f1a84e6SJiri Pirko 
2933f1a84e6SJiri Pirko static const struct mlxsw_afk_element_inst *
2943f1a84e6SJiri Pirko mlxsw_afk_block_elinst_get(const struct mlxsw_afk_block *block,
2953f1a84e6SJiri Pirko 			   enum mlxsw_afk_element element)
2963f1a84e6SJiri Pirko {
2973f1a84e6SJiri Pirko 	int i;
2983f1a84e6SJiri Pirko 
2993f1a84e6SJiri Pirko 	for (i = 0; i < block->instances_count; i++) {
3003f1a84e6SJiri Pirko 		struct mlxsw_afk_element_inst *elinst;
3013f1a84e6SJiri Pirko 
3023f1a84e6SJiri Pirko 		elinst = &block->instances[i];
3033f1a84e6SJiri Pirko 		if (elinst->info->element == element)
3043f1a84e6SJiri Pirko 			return elinst;
3053f1a84e6SJiri Pirko 	}
3063f1a84e6SJiri Pirko 	return NULL;
3073f1a84e6SJiri Pirko }
3083f1a84e6SJiri Pirko 
3093f1a84e6SJiri Pirko static const struct mlxsw_afk_element_inst *
3103f1a84e6SJiri Pirko mlxsw_afk_key_info_elinst_get(struct mlxsw_afk_key_info *key_info,
3113f1a84e6SJiri Pirko 			      enum mlxsw_afk_element element,
3123f1a84e6SJiri Pirko 			      int *p_block_index)
3133f1a84e6SJiri Pirko {
3143f1a84e6SJiri Pirko 	const struct mlxsw_afk_element_inst *elinst;
3153f1a84e6SJiri Pirko 	const struct mlxsw_afk_block *block;
3163f1a84e6SJiri Pirko 	int block_index;
3173f1a84e6SJiri Pirko 
3183f1a84e6SJiri Pirko 	if (WARN_ON(!test_bit(element, key_info->elusage.usage)))
3193f1a84e6SJiri Pirko 		return NULL;
3203f1a84e6SJiri Pirko 	block_index = key_info->element_to_block[element];
3213f1a84e6SJiri Pirko 	block = key_info->blocks[block_index];
3223f1a84e6SJiri Pirko 
3233f1a84e6SJiri Pirko 	elinst = mlxsw_afk_block_elinst_get(block, element);
3243f1a84e6SJiri Pirko 	if (WARN_ON(!elinst))
3253f1a84e6SJiri Pirko 		return NULL;
3263f1a84e6SJiri Pirko 
3273f1a84e6SJiri Pirko 	*p_block_index = block_index;
3283f1a84e6SJiri Pirko 	return elinst;
3293f1a84e6SJiri Pirko }
3303f1a84e6SJiri Pirko 
3313f1a84e6SJiri Pirko u16
3323f1a84e6SJiri Pirko mlxsw_afk_key_info_block_encoding_get(const struct mlxsw_afk_key_info *key_info,
3333f1a84e6SJiri Pirko 				      int block_index)
3343f1a84e6SJiri Pirko {
3353f1a84e6SJiri Pirko 	return key_info->blocks[block_index]->encoding;
3363f1a84e6SJiri Pirko }
3373f1a84e6SJiri Pirko EXPORT_SYMBOL(mlxsw_afk_key_info_block_encoding_get);
3383f1a84e6SJiri Pirko 
3393f1a84e6SJiri Pirko unsigned int
3403f1a84e6SJiri Pirko mlxsw_afk_key_info_blocks_count_get(const struct mlxsw_afk_key_info *key_info)
3413f1a84e6SJiri Pirko {
3423f1a84e6SJiri Pirko 	return key_info->blocks_count;
3433f1a84e6SJiri Pirko }
3443f1a84e6SJiri Pirko EXPORT_SYMBOL(mlxsw_afk_key_info_blocks_count_get);
3453f1a84e6SJiri Pirko 
3463f1a84e6SJiri Pirko void mlxsw_afk_values_add_u32(struct mlxsw_afk_element_values *values,
3473f1a84e6SJiri Pirko 			      enum mlxsw_afk_element element,
3483f1a84e6SJiri Pirko 			      u32 key_value, u32 mask_value)
3493f1a84e6SJiri Pirko {
3503f1a84e6SJiri Pirko 	const struct mlxsw_afk_element_info *elinfo =
3513f1a84e6SJiri Pirko 				&mlxsw_afk_element_infos[element];
3523f1a84e6SJiri Pirko 	const struct mlxsw_item *storage_item = &elinfo->item;
3533f1a84e6SJiri Pirko 
3543f1a84e6SJiri Pirko 	if (!mask_value)
3553f1a84e6SJiri Pirko 		return;
3563f1a84e6SJiri Pirko 	if (WARN_ON(elinfo->type != MLXSW_AFK_ELEMENT_TYPE_U32))
3573f1a84e6SJiri Pirko 		return;
3583f1a84e6SJiri Pirko 	__mlxsw_item_set32(values->storage.key, storage_item, 0, key_value);
3593f1a84e6SJiri Pirko 	__mlxsw_item_set32(values->storage.mask, storage_item, 0, mask_value);
3603f1a84e6SJiri Pirko 	mlxsw_afk_element_usage_add(&values->elusage, element);
3613f1a84e6SJiri Pirko }
3623f1a84e6SJiri Pirko EXPORT_SYMBOL(mlxsw_afk_values_add_u32);
3633f1a84e6SJiri Pirko 
3643f1a84e6SJiri Pirko void mlxsw_afk_values_add_buf(struct mlxsw_afk_element_values *values,
3653f1a84e6SJiri Pirko 			      enum mlxsw_afk_element element,
3663f1a84e6SJiri Pirko 			      const char *key_value, const char *mask_value,
3673f1a84e6SJiri Pirko 			      unsigned int len)
3683f1a84e6SJiri Pirko {
3693f1a84e6SJiri Pirko 	const struct mlxsw_afk_element_info *elinfo =
3703f1a84e6SJiri Pirko 				&mlxsw_afk_element_infos[element];
3713f1a84e6SJiri Pirko 	const struct mlxsw_item *storage_item = &elinfo->item;
3723f1a84e6SJiri Pirko 
3733f1a84e6SJiri Pirko 	if (!memchr_inv(mask_value, 0, len)) /* If mask is zero */
3743f1a84e6SJiri Pirko 		return;
3753f1a84e6SJiri Pirko 	if (WARN_ON(elinfo->type != MLXSW_AFK_ELEMENT_TYPE_BUF) ||
3763f1a84e6SJiri Pirko 	    WARN_ON(elinfo->item.size.bytes != len))
3773f1a84e6SJiri Pirko 		return;
3783f1a84e6SJiri Pirko 	__mlxsw_item_memcpy_to(values->storage.key, key_value,
3793f1a84e6SJiri Pirko 			       storage_item, 0);
3803f1a84e6SJiri Pirko 	__mlxsw_item_memcpy_to(values->storage.mask, mask_value,
3813f1a84e6SJiri Pirko 			       storage_item, 0);
3823f1a84e6SJiri Pirko 	mlxsw_afk_element_usage_add(&values->elusage, element);
3833f1a84e6SJiri Pirko }
3843f1a84e6SJiri Pirko EXPORT_SYMBOL(mlxsw_afk_values_add_buf);
3853f1a84e6SJiri Pirko 
386a6d70a87SIdo Schimmel static void mlxsw_sp_afk_encode_u32(const struct mlxsw_item *storage_item,
387a6d70a87SIdo Schimmel 				    const struct mlxsw_item *output_item,
388a6d70a87SIdo Schimmel 				    char *storage, char *output)
389a6d70a87SIdo Schimmel {
390a6d70a87SIdo Schimmel 	u32 value;
391a6d70a87SIdo Schimmel 
392a6d70a87SIdo Schimmel 	value = __mlxsw_item_get32(storage, storage_item, 0);
393a6d70a87SIdo Schimmel 	__mlxsw_item_set32(output, output_item, 0, value);
394a6d70a87SIdo Schimmel }
395a6d70a87SIdo Schimmel 
396a6d70a87SIdo Schimmel static void mlxsw_sp_afk_encode_buf(const struct mlxsw_item *storage_item,
397a6d70a87SIdo Schimmel 				    const struct mlxsw_item *output_item,
398a6d70a87SIdo Schimmel 				    char *storage, char *output)
399a6d70a87SIdo Schimmel {
400a6d70a87SIdo Schimmel 	char *storage_data = __mlxsw_item_data(storage, storage_item, 0);
401a6d70a87SIdo Schimmel 	char *output_data = __mlxsw_item_data(output, output_item, 0);
402a6d70a87SIdo Schimmel 	size_t len = output_item->size.bytes;
403a6d70a87SIdo Schimmel 
404a6d70a87SIdo Schimmel 	memcpy(output_data, storage_data, len);
405a6d70a87SIdo Schimmel }
406a6d70a87SIdo Schimmel 
407a6d70a87SIdo Schimmel static void
408a6d70a87SIdo Schimmel mlxsw_sp_afk_encode_one(const struct mlxsw_afk_element_inst *elinst,
409a6d70a87SIdo Schimmel 			char *output, char *storage)
410a6d70a87SIdo Schimmel {
411a6d70a87SIdo Schimmel 	const struct mlxsw_item *storage_item = &elinst->info->item;
412a6d70a87SIdo Schimmel 	const struct mlxsw_item *output_item = &elinst->item;
413a6d70a87SIdo Schimmel 
414a6d70a87SIdo Schimmel 	if (elinst->type == MLXSW_AFK_ELEMENT_TYPE_U32)
415a6d70a87SIdo Schimmel 		mlxsw_sp_afk_encode_u32(storage_item, output_item,
416a6d70a87SIdo Schimmel 					storage, output);
417a6d70a87SIdo Schimmel 	else if (elinst->type == MLXSW_AFK_ELEMENT_TYPE_BUF)
418a6d70a87SIdo Schimmel 		mlxsw_sp_afk_encode_buf(storage_item, output_item,
419a6d70a87SIdo Schimmel 					storage, output);
420a6d70a87SIdo Schimmel }
421a6d70a87SIdo Schimmel 
422a6d70a87SIdo Schimmel #define MLXSW_SP_AFK_KEY_BLOCK_MAX_SIZE 16
423a6d70a87SIdo Schimmel 
424a5995cc8SJiri Pirko void mlxsw_afk_encode(struct mlxsw_afk *mlxsw_afk,
425a5995cc8SJiri Pirko 		      struct mlxsw_afk_key_info *key_info,
4263f1a84e6SJiri Pirko 		      struct mlxsw_afk_element_values *values,
42759600844SJiri Pirko 		      char *key, char *mask)
4283f1a84e6SJiri Pirko {
42959600844SJiri Pirko 	unsigned int blocks_count =
43059600844SJiri Pirko 			mlxsw_afk_key_info_blocks_count_get(key_info);
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 
43759600844SJiri Pirko 	for (i = 0; i < blocks_count; 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 
4543bc6f385SJiri Pirko 		mlxsw_afk->ops->encode_block(key, i, block_key);
4553bc6f385SJiri Pirko 		mlxsw_afk->ops->encode_block(mask, i, block_mask);
4563f1a84e6SJiri Pirko 	}
4573f1a84e6SJiri Pirko }
4583f1a84e6SJiri Pirko EXPORT_SYMBOL(mlxsw_afk_encode);
459b1ce60e6SJiri Pirko 
460b1ce60e6SJiri Pirko void mlxsw_afk_clear(struct mlxsw_afk *mlxsw_afk, char *key,
461b1ce60e6SJiri Pirko 		     int block_start, int block_end)
462b1ce60e6SJiri Pirko {
463b1ce60e6SJiri Pirko 	int i;
464b1ce60e6SJiri Pirko 
465b1ce60e6SJiri Pirko 	for (i = block_start; i <= block_end; i++)
466b1ce60e6SJiri Pirko 		mlxsw_afk->ops->clear_block(key, i);
467b1ce60e6SJiri Pirko }
468b1ce60e6SJiri Pirko EXPORT_SYMBOL(mlxsw_afk_clear);
469