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