xref: /dpdk/lib/table/rte_swx_table_selector.c (revision 44bcb29f5c1b5b5af1942dee58ba16fba78c35f0)
1f7598a62SCristian Dumitrescu /* SPDX-License-Identifier: BSD-3-Clause
2f7598a62SCristian Dumitrescu  * Copyright(c) 2021 Intel Corporation
3f7598a62SCristian Dumitrescu  */
4f7598a62SCristian Dumitrescu #include <stdlib.h>
5f7598a62SCristian Dumitrescu #include <string.h>
6f7598a62SCristian Dumitrescu #include <stdio.h>
7f7598a62SCristian Dumitrescu #include <errno.h>
8f7598a62SCristian Dumitrescu 
9f7598a62SCristian Dumitrescu #include <rte_common.h>
10f7598a62SCristian Dumitrescu 
11f7598a62SCristian Dumitrescu #include "rte_swx_table_selector.h"
12f7598a62SCristian Dumitrescu 
13f7598a62SCristian Dumitrescu #ifndef RTE_SWX_TABLE_SELECTOR_HUGE_PAGES_DISABLE
14f7598a62SCristian Dumitrescu 
15f7598a62SCristian Dumitrescu #include <rte_malloc.h>
16f7598a62SCristian Dumitrescu 
17f7598a62SCristian Dumitrescu static void *
env_calloc(size_t size,size_t alignment,int numa_node)18f7598a62SCristian Dumitrescu env_calloc(size_t size, size_t alignment, int numa_node)
19f7598a62SCristian Dumitrescu {
20f7598a62SCristian Dumitrescu 	return rte_zmalloc_socket(NULL, size, alignment, numa_node);
21f7598a62SCristian Dumitrescu }
22f7598a62SCristian Dumitrescu 
23f7598a62SCristian Dumitrescu static void
env_free(void * start,size_t size __rte_unused)24f7598a62SCristian Dumitrescu env_free(void *start, size_t size __rte_unused)
25f7598a62SCristian Dumitrescu {
26f7598a62SCristian Dumitrescu 	rte_free(start);
27f7598a62SCristian Dumitrescu }
28f7598a62SCristian Dumitrescu 
29f7598a62SCristian Dumitrescu #else
30f7598a62SCristian Dumitrescu 
31f7598a62SCristian Dumitrescu #include <numa.h>
32f7598a62SCristian Dumitrescu 
33f7598a62SCristian Dumitrescu static void *
env_calloc(size_t size,size_t alignment __rte_unused,int numa_node)34f7598a62SCristian Dumitrescu env_calloc(size_t size, size_t alignment __rte_unused, int numa_node)
35f7598a62SCristian Dumitrescu {
36f7598a62SCristian Dumitrescu 	void *start;
37f7598a62SCristian Dumitrescu 
38f7598a62SCristian Dumitrescu 	if (numa_available() == -1)
39f7598a62SCristian Dumitrescu 		return NULL;
40f7598a62SCristian Dumitrescu 
41f7598a62SCristian Dumitrescu 	start = numa_alloc_onnode(size, numa_node);
42f7598a62SCristian Dumitrescu 	if (!start)
43f7598a62SCristian Dumitrescu 		return NULL;
44f7598a62SCristian Dumitrescu 
45f7598a62SCristian Dumitrescu 	memset(start, 0, size);
46f7598a62SCristian Dumitrescu 	return start;
47f7598a62SCristian Dumitrescu }
48f7598a62SCristian Dumitrescu 
49f7598a62SCristian Dumitrescu static void
env_free(void * start,size_t size)50f7598a62SCristian Dumitrescu env_free(void *start, size_t size)
51f7598a62SCristian Dumitrescu {
52f7598a62SCristian Dumitrescu 	if ((numa_available() == -1) || !start)
53f7598a62SCristian Dumitrescu 		return;
54f7598a62SCristian Dumitrescu 
55f7598a62SCristian Dumitrescu 	numa_free(start, size);
56f7598a62SCristian Dumitrescu }
57f7598a62SCristian Dumitrescu 
58f7598a62SCristian Dumitrescu #endif
59f7598a62SCristian Dumitrescu 
60f7598a62SCristian Dumitrescu #if defined(RTE_ARCH_X86_64)
61f7598a62SCristian Dumitrescu 
62f7598a62SCristian Dumitrescu #include <x86intrin.h>
63f7598a62SCristian Dumitrescu 
64f7598a62SCristian Dumitrescu #define crc32_u64(crc, v) _mm_crc32_u64(crc, v)
65f7598a62SCristian Dumitrescu 
66f7598a62SCristian Dumitrescu #else
67f7598a62SCristian Dumitrescu 
68f7598a62SCristian Dumitrescu static inline uint64_t
crc32_u64_generic(uint64_t crc,uint64_t value)69f7598a62SCristian Dumitrescu crc32_u64_generic(uint64_t crc, uint64_t value)
70f7598a62SCristian Dumitrescu {
71f7598a62SCristian Dumitrescu 	int i;
72f7598a62SCristian Dumitrescu 
73f7598a62SCristian Dumitrescu 	crc = (crc & 0xFFFFFFFFLLU) ^ value;
74f7598a62SCristian Dumitrescu 	for (i = 63; i >= 0; i--) {
75f7598a62SCristian Dumitrescu 		uint64_t mask;
76f7598a62SCristian Dumitrescu 
77f7598a62SCristian Dumitrescu 		mask = -(crc & 1LLU);
78f7598a62SCristian Dumitrescu 		crc = (crc >> 1LLU) ^ (0x82F63B78LLU & mask);
79f7598a62SCristian Dumitrescu 	}
80f7598a62SCristian Dumitrescu 
81f7598a62SCristian Dumitrescu 	return crc;
82f7598a62SCristian Dumitrescu }
83f7598a62SCristian Dumitrescu 
84f7598a62SCristian Dumitrescu #define crc32_u64(crc, v) crc32_u64_generic(crc, v)
85f7598a62SCristian Dumitrescu 
86f7598a62SCristian Dumitrescu #endif
87f7598a62SCristian Dumitrescu 
88f7598a62SCristian Dumitrescu /* Key size needs to be one of: 8, 16, 32 or 64. */
89f7598a62SCristian Dumitrescu static inline uint32_t
hash(void * key,void * key_mask,uint32_t key_size,uint32_t seed)90f7598a62SCristian Dumitrescu hash(void *key, void *key_mask, uint32_t key_size, uint32_t seed)
91f7598a62SCristian Dumitrescu {
92f7598a62SCristian Dumitrescu 	uint64_t *k = key;
93f7598a62SCristian Dumitrescu 	uint64_t *m = key_mask;
94f7598a62SCristian Dumitrescu 	uint64_t k0, k2, k5, crc0, crc1, crc2, crc3, crc4, crc5;
95f7598a62SCristian Dumitrescu 
96f7598a62SCristian Dumitrescu 	switch (key_size) {
97f7598a62SCristian Dumitrescu 	case 8:
98f7598a62SCristian Dumitrescu 		crc0 = crc32_u64(seed, k[0] & m[0]);
99f7598a62SCristian Dumitrescu 		return crc0;
100f7598a62SCristian Dumitrescu 
101f7598a62SCristian Dumitrescu 	case 16:
102f7598a62SCristian Dumitrescu 		k0 = k[0] & m[0];
103f7598a62SCristian Dumitrescu 
104f7598a62SCristian Dumitrescu 		crc0 = crc32_u64(k0, seed);
105f7598a62SCristian Dumitrescu 		crc1 = crc32_u64(k0 >> 32, k[1] & m[1]);
106f7598a62SCristian Dumitrescu 
107f7598a62SCristian Dumitrescu 		crc0 ^= crc1;
108f7598a62SCristian Dumitrescu 
109f7598a62SCristian Dumitrescu 		return crc0;
110f7598a62SCristian Dumitrescu 
111f7598a62SCristian Dumitrescu 	case 32:
112f7598a62SCristian Dumitrescu 		k0 = k[0] & m[0];
113f7598a62SCristian Dumitrescu 		k2 = k[2] & m[2];
114f7598a62SCristian Dumitrescu 
115f7598a62SCristian Dumitrescu 		crc0 = crc32_u64(k0, seed);
116f7598a62SCristian Dumitrescu 		crc1 = crc32_u64(k0 >> 32, k[1] & m[1]);
117f7598a62SCristian Dumitrescu 
118f7598a62SCristian Dumitrescu 		crc2 = crc32_u64(k2, k[3] & m[3]);
119f7598a62SCristian Dumitrescu 		crc3 = k2 >> 32;
120f7598a62SCristian Dumitrescu 
121f7598a62SCristian Dumitrescu 		crc0 = crc32_u64(crc0, crc1);
122f7598a62SCristian Dumitrescu 		crc1 = crc32_u64(crc2, crc3);
123f7598a62SCristian Dumitrescu 
124f7598a62SCristian Dumitrescu 		crc0 ^= crc1;
125f7598a62SCristian Dumitrescu 
126f7598a62SCristian Dumitrescu 		return crc0;
127f7598a62SCristian Dumitrescu 
128f7598a62SCristian Dumitrescu 	case 64:
129f7598a62SCristian Dumitrescu 		k0 = k[0] & m[0];
130f7598a62SCristian Dumitrescu 		k2 = k[2] & m[2];
131f7598a62SCristian Dumitrescu 		k5 = k[5] & m[5];
132f7598a62SCristian Dumitrescu 
133f7598a62SCristian Dumitrescu 		crc0 = crc32_u64(k0, seed);
134f7598a62SCristian Dumitrescu 		crc1 = crc32_u64(k0 >> 32, k[1] & m[1]);
135f7598a62SCristian Dumitrescu 
136f7598a62SCristian Dumitrescu 		crc2 = crc32_u64(k2, k[3] & m[3]);
137f7598a62SCristian Dumitrescu 		crc3 = crc32_u64(k2 >> 32, k[4] & m[4]);
138f7598a62SCristian Dumitrescu 
139f7598a62SCristian Dumitrescu 		crc4 = crc32_u64(k5, k[6] & m[6]);
140f7598a62SCristian Dumitrescu 		crc5 = crc32_u64(k5 >> 32, k[7] & m[7]);
141f7598a62SCristian Dumitrescu 
142f7598a62SCristian Dumitrescu 		crc0 = crc32_u64(crc0, (crc1 << 32) ^ crc2);
143f7598a62SCristian Dumitrescu 		crc1 = crc32_u64(crc3, (crc4 << 32) ^ crc5);
144f7598a62SCristian Dumitrescu 
145f7598a62SCristian Dumitrescu 		crc0 ^= crc1;
146f7598a62SCristian Dumitrescu 
147f7598a62SCristian Dumitrescu 		return crc0;
148f7598a62SCristian Dumitrescu 
149f7598a62SCristian Dumitrescu 	default:
150f7598a62SCristian Dumitrescu 		crc0 = 0;
151f7598a62SCristian Dumitrescu 		return crc0;
152f7598a62SCristian Dumitrescu 	}
153f7598a62SCristian Dumitrescu }
154f7598a62SCristian Dumitrescu 
155f7598a62SCristian Dumitrescu struct group_member_info {
156f7598a62SCristian Dumitrescu 	uint32_t member_id;
157f7598a62SCristian Dumitrescu 	uint32_t member_weight;
158f7598a62SCristian Dumitrescu 	uint32_t member_weight_normalized;
159f7598a62SCristian Dumitrescu 	uint32_t count;
160f7598a62SCristian Dumitrescu };
161f7598a62SCristian Dumitrescu 
162f7598a62SCristian Dumitrescu struct table {
163f7598a62SCristian Dumitrescu 	/* Input parameters */
164f7598a62SCristian Dumitrescu 	struct rte_swx_table_selector_params params;
165f7598a62SCristian Dumitrescu 
166f7598a62SCristian Dumitrescu 	/* Internal. */
167f7598a62SCristian Dumitrescu 	uint32_t *group_table;
168f7598a62SCristian Dumitrescu 	uint64_t group_table_size;
169f7598a62SCristian Dumitrescu 	struct group_member_info *members;
170f7598a62SCristian Dumitrescu 	uint32_t n_members_per_group_max_log2;
171f7598a62SCristian Dumitrescu };
172f7598a62SCristian Dumitrescu 
173f7598a62SCristian Dumitrescu uint64_t
rte_swx_table_selector_footprint_get(uint32_t n_groups_max,uint32_t n_members_per_group_max)174f7598a62SCristian Dumitrescu rte_swx_table_selector_footprint_get(uint32_t n_groups_max, uint32_t n_members_per_group_max)
175f7598a62SCristian Dumitrescu {
176f7598a62SCristian Dumitrescu 	uint64_t group_table_size, members_size;
177f7598a62SCristian Dumitrescu 
178f7598a62SCristian Dumitrescu 	group_table_size = n_groups_max * n_members_per_group_max * sizeof(uint32_t);
179f7598a62SCristian Dumitrescu 
180f7598a62SCristian Dumitrescu 	members_size = n_members_per_group_max * sizeof(struct group_member_info);
181f7598a62SCristian Dumitrescu 
182f7598a62SCristian Dumitrescu 	return sizeof(struct table) + group_table_size + members_size;
183f7598a62SCristian Dumitrescu }
184f7598a62SCristian Dumitrescu 
185f7598a62SCristian Dumitrescu void
rte_swx_table_selector_free(void * table)186f7598a62SCristian Dumitrescu rte_swx_table_selector_free(void *table)
187f7598a62SCristian Dumitrescu {
188f7598a62SCristian Dumitrescu 	struct table *t = table;
189f7598a62SCristian Dumitrescu 
190f7598a62SCristian Dumitrescu 	if (!t)
191f7598a62SCristian Dumitrescu 		return;
192f7598a62SCristian Dumitrescu 
193f7598a62SCristian Dumitrescu 	free(t->members);
194f7598a62SCristian Dumitrescu 
195f7598a62SCristian Dumitrescu 	env_free(t->group_table, t->group_table_size);
196f7598a62SCristian Dumitrescu 
197f7598a62SCristian Dumitrescu 	free(t->params.selector_mask);
198f7598a62SCristian Dumitrescu 
199f7598a62SCristian Dumitrescu 	free(t);
200f7598a62SCristian Dumitrescu }
201f7598a62SCristian Dumitrescu 
202f7598a62SCristian Dumitrescu static int
table_create_check(struct rte_swx_table_selector_params * params)203f7598a62SCristian Dumitrescu table_create_check(struct rte_swx_table_selector_params *params)
204f7598a62SCristian Dumitrescu {
205f7598a62SCristian Dumitrescu 	if (!params)
206f7598a62SCristian Dumitrescu 		return -1;
207f7598a62SCristian Dumitrescu 
208f7598a62SCristian Dumitrescu 	if (!params->selector_size ||
209f7598a62SCristian Dumitrescu 	    (params->selector_size > 64) ||
210f7598a62SCristian Dumitrescu 	    !params->n_groups_max ||
211f7598a62SCristian Dumitrescu 	    (params->n_groups_max > 1U << 31) ||
212f7598a62SCristian Dumitrescu 	    !params->n_members_per_group_max ||
213f7598a62SCristian Dumitrescu 	    (params->n_members_per_group_max > 1U << 31))
214f7598a62SCristian Dumitrescu 		return -EINVAL;
215f7598a62SCristian Dumitrescu 
216f7598a62SCristian Dumitrescu 	return 0;
217f7598a62SCristian Dumitrescu }
218f7598a62SCristian Dumitrescu 
219f7598a62SCristian Dumitrescu static int
table_params_copy(struct table * t,struct rte_swx_table_selector_params * params)220f7598a62SCristian Dumitrescu table_params_copy(struct table *t, struct rte_swx_table_selector_params *params)
221f7598a62SCristian Dumitrescu {
222f7598a62SCristian Dumitrescu 	uint32_t selector_size, i;
223f7598a62SCristian Dumitrescu 
224f7598a62SCristian Dumitrescu 	selector_size = rte_align32pow2(params->selector_size);
225f7598a62SCristian Dumitrescu 	if (selector_size < 8)
226f7598a62SCristian Dumitrescu 		selector_size = 8;
227f7598a62SCristian Dumitrescu 
228f7598a62SCristian Dumitrescu 	memcpy(&t->params, params, sizeof(struct rte_swx_table_selector_params));
229f7598a62SCristian Dumitrescu 	t->params.selector_size = selector_size;
230f7598a62SCristian Dumitrescu 	t->params.selector_mask = NULL;
231f7598a62SCristian Dumitrescu 	t->params.n_groups_max = rte_align32pow2(params->n_groups_max);
232f7598a62SCristian Dumitrescu 	t->params.n_members_per_group_max = rte_align32pow2(params->n_members_per_group_max);
233f7598a62SCristian Dumitrescu 
234f7598a62SCristian Dumitrescu 	for (i = 0; i < 32; i++)
235*44bcb29fSYogesh Jangra 		if (t->params.n_members_per_group_max == 1U << i)
236f7598a62SCristian Dumitrescu 			t->n_members_per_group_max_log2 = i;
237f7598a62SCristian Dumitrescu 
238f7598a62SCristian Dumitrescu 	/* t->params.selector_mask */
239f7598a62SCristian Dumitrescu 	t->params.selector_mask = calloc(selector_size, sizeof(uint8_t));
240f7598a62SCristian Dumitrescu 	if (!t->params.selector_mask)
241f7598a62SCristian Dumitrescu 		goto error;
242f7598a62SCristian Dumitrescu 
243f7598a62SCristian Dumitrescu 	if (params->selector_mask)
244f7598a62SCristian Dumitrescu 		memcpy(t->params.selector_mask, params->selector_mask, params->selector_size);
245f7598a62SCristian Dumitrescu 	else
246f7598a62SCristian Dumitrescu 		memset(t->params.selector_mask, 0xFF, params->selector_size);
247f7598a62SCristian Dumitrescu 
248f7598a62SCristian Dumitrescu 	return 0;
249f7598a62SCristian Dumitrescu 
250f7598a62SCristian Dumitrescu error:
251f7598a62SCristian Dumitrescu 	free(t->params.selector_mask);
252f7598a62SCristian Dumitrescu 	t->params.selector_mask = NULL;
253f7598a62SCristian Dumitrescu 
254f7598a62SCristian Dumitrescu 	return -ENOMEM;
255f7598a62SCristian Dumitrescu }
256f7598a62SCristian Dumitrescu 
257f7598a62SCristian Dumitrescu static int
258f7598a62SCristian Dumitrescu group_set(struct table *t,
259f7598a62SCristian Dumitrescu 	  uint32_t group_id,
260f7598a62SCristian Dumitrescu 	  struct rte_swx_table_selector_group *group);
261f7598a62SCristian Dumitrescu 
262f7598a62SCristian Dumitrescu void *
rte_swx_table_selector_create(struct rte_swx_table_selector_params * params,struct rte_swx_table_selector_group ** groups,int numa_node)263f7598a62SCristian Dumitrescu rte_swx_table_selector_create(struct rte_swx_table_selector_params *params,
264f7598a62SCristian Dumitrescu 			      struct rte_swx_table_selector_group **groups,
265f7598a62SCristian Dumitrescu 			      int numa_node)
266f7598a62SCristian Dumitrescu {
267f7598a62SCristian Dumitrescu 	struct table *t = NULL;
268f7598a62SCristian Dumitrescu 	uint32_t group_size, i;
269f7598a62SCristian Dumitrescu 	int status;
270f7598a62SCristian Dumitrescu 
271f7598a62SCristian Dumitrescu 	/* Check input arguments. */
272f7598a62SCristian Dumitrescu 	status = table_create_check(params);
273f7598a62SCristian Dumitrescu 	if (status)
274f7598a62SCristian Dumitrescu 		goto error;
275f7598a62SCristian Dumitrescu 
276f7598a62SCristian Dumitrescu 	/* Table object. */
277f7598a62SCristian Dumitrescu 	t = calloc(1, sizeof(struct table));
278f7598a62SCristian Dumitrescu 	if (!t)
279f7598a62SCristian Dumitrescu 		goto error;
280f7598a62SCristian Dumitrescu 
281f7598a62SCristian Dumitrescu 	/* Parameter copy. */
282f7598a62SCristian Dumitrescu 	status = table_params_copy(t, params);
283f7598a62SCristian Dumitrescu 	if (status)
284f7598a62SCristian Dumitrescu 		goto error;
285f7598a62SCristian Dumitrescu 
286f7598a62SCristian Dumitrescu 	/* Group. */
287f7598a62SCristian Dumitrescu 	group_size = params->n_members_per_group_max * sizeof(uint32_t);
288f7598a62SCristian Dumitrescu 	t->group_table_size = params->n_groups_max * group_size;
289f7598a62SCristian Dumitrescu 
290f7598a62SCristian Dumitrescu 	t->group_table = env_calloc(t->group_table_size, RTE_CACHE_LINE_SIZE, numa_node);
291f7598a62SCristian Dumitrescu 	if (!t->group_table)
292f7598a62SCristian Dumitrescu 		goto error;
293f7598a62SCristian Dumitrescu 
294f7598a62SCristian Dumitrescu 	t->members = calloc(params->n_members_per_group_max, sizeof(struct group_member_info));
295f7598a62SCristian Dumitrescu 	if (!t->members)
296f7598a62SCristian Dumitrescu 		goto error;
297f7598a62SCristian Dumitrescu 
298f7598a62SCristian Dumitrescu 	if (groups)
299f7598a62SCristian Dumitrescu 		for (i = 0; i < params->n_groups_max; i++)
300f7598a62SCristian Dumitrescu 			if (groups[i]) {
301f7598a62SCristian Dumitrescu 				status = group_set(t, i, groups[i]);
302f7598a62SCristian Dumitrescu 				if (status)
303f7598a62SCristian Dumitrescu 					goto error;
304f7598a62SCristian Dumitrescu 			}
305f7598a62SCristian Dumitrescu 
306f7598a62SCristian Dumitrescu 	return t;
307f7598a62SCristian Dumitrescu 
308f7598a62SCristian Dumitrescu error:
309f7598a62SCristian Dumitrescu 	rte_swx_table_selector_free(t);
310f7598a62SCristian Dumitrescu 	return NULL;
311f7598a62SCristian Dumitrescu }
312f7598a62SCristian Dumitrescu 
313f7598a62SCristian Dumitrescu 
314f7598a62SCristian Dumitrescu static int
group_check(struct table * t,struct rte_swx_table_selector_group * group)315f7598a62SCristian Dumitrescu group_check(struct table *t, struct rte_swx_table_selector_group *group)
316f7598a62SCristian Dumitrescu {
317f7598a62SCristian Dumitrescu 	struct rte_swx_table_selector_member *elem;
318f7598a62SCristian Dumitrescu 	uint32_t n_members = 0;
319f7598a62SCristian Dumitrescu 
320f7598a62SCristian Dumitrescu 	if (!group)
321f7598a62SCristian Dumitrescu 		return 0;
322f7598a62SCristian Dumitrescu 
323f7598a62SCristian Dumitrescu 	TAILQ_FOREACH(elem, &group->members, node) {
324f7598a62SCristian Dumitrescu 		struct rte_swx_table_selector_member *e;
325f7598a62SCristian Dumitrescu 		uint32_t n = 0;
326f7598a62SCristian Dumitrescu 
327f7598a62SCristian Dumitrescu 		/* Check group size. */
328f7598a62SCristian Dumitrescu 		if (n_members >= t->params.n_members_per_group_max)
329f7598a62SCristian Dumitrescu 			return -ENOSPC;
330f7598a62SCristian Dumitrescu 
331f7598a62SCristian Dumitrescu 		/* Check attributes of the current group member. */
332f7598a62SCristian Dumitrescu 		if (elem->member_id >= t->params.n_members_per_group_max ||
333f7598a62SCristian Dumitrescu 		    !elem->member_weight)
334f7598a62SCristian Dumitrescu 			return -ENOSPC;
335f7598a62SCristian Dumitrescu 
336f7598a62SCristian Dumitrescu 		/* Check against duplicate member IDs. */
337f7598a62SCristian Dumitrescu 		TAILQ_FOREACH(e, &group->members, node)
338f7598a62SCristian Dumitrescu 			if (e->member_id == elem->member_id)
339f7598a62SCristian Dumitrescu 				n++;
340f7598a62SCristian Dumitrescu 
341f7598a62SCristian Dumitrescu 		if (n != 1)
342f7598a62SCristian Dumitrescu 			return -EINVAL;
343f7598a62SCristian Dumitrescu 
344f7598a62SCristian Dumitrescu 		/* Update group size. */
345f7598a62SCristian Dumitrescu 		n_members++;
346f7598a62SCristian Dumitrescu 	}
347f7598a62SCristian Dumitrescu 
348f7598a62SCristian Dumitrescu 	return 0;
349f7598a62SCristian Dumitrescu }
350f7598a62SCristian Dumitrescu 
351f7598a62SCristian Dumitrescu static uint32_t
members_read(struct group_member_info * members,struct rte_swx_table_selector_group * group)352f7598a62SCristian Dumitrescu members_read(struct group_member_info *members,
353f7598a62SCristian Dumitrescu 	     struct rte_swx_table_selector_group *group)
354f7598a62SCristian Dumitrescu {
355f7598a62SCristian Dumitrescu 	struct rte_swx_table_selector_member *elem;
356f7598a62SCristian Dumitrescu 	uint32_t n_members = 0;
357f7598a62SCristian Dumitrescu 
358f7598a62SCristian Dumitrescu 	if (!group)
359f7598a62SCristian Dumitrescu 		return 0;
360f7598a62SCristian Dumitrescu 
361f7598a62SCristian Dumitrescu 	TAILQ_FOREACH(elem, &group->members, node) {
362f7598a62SCristian Dumitrescu 		struct group_member_info *m = &members[n_members];
363f7598a62SCristian Dumitrescu 
364f7598a62SCristian Dumitrescu 		memset(m, 0, sizeof(struct group_member_info));
365f7598a62SCristian Dumitrescu 
366f7598a62SCristian Dumitrescu 		m->member_id = elem->member_id;
367f7598a62SCristian Dumitrescu 		m->member_weight = elem->member_weight;
368f7598a62SCristian Dumitrescu 		m->member_weight_normalized = elem->member_weight;
369f7598a62SCristian Dumitrescu 
370f7598a62SCristian Dumitrescu 		n_members++;
371f7598a62SCristian Dumitrescu 	}
372f7598a62SCristian Dumitrescu 
373f7598a62SCristian Dumitrescu 	return n_members;
374f7598a62SCristian Dumitrescu }
375f7598a62SCristian Dumitrescu 
376f7598a62SCristian Dumitrescu static uint32_t
members_min_weight_find(struct group_member_info * members,uint32_t n_members)377f7598a62SCristian Dumitrescu members_min_weight_find(struct group_member_info *members, uint32_t n_members)
378f7598a62SCristian Dumitrescu {
379f7598a62SCristian Dumitrescu 	uint32_t min = UINT32_MAX, i;
380f7598a62SCristian Dumitrescu 
381f7598a62SCristian Dumitrescu 	for (i = 0; i < n_members; i++) {
382f7598a62SCristian Dumitrescu 		struct group_member_info *m = &members[i];
383f7598a62SCristian Dumitrescu 
384f7598a62SCristian Dumitrescu 		if (m->member_weight < min)
385f7598a62SCristian Dumitrescu 			min = m->member_weight;
386f7598a62SCristian Dumitrescu 	}
387f7598a62SCristian Dumitrescu 
388f7598a62SCristian Dumitrescu 	return min;
389f7598a62SCristian Dumitrescu }
390f7598a62SCristian Dumitrescu 
391f7598a62SCristian Dumitrescu static uint32_t
members_weight_divisor_check(struct group_member_info * members,uint32_t n_members,uint32_t divisor)392f7598a62SCristian Dumitrescu members_weight_divisor_check(struct group_member_info *members,
393f7598a62SCristian Dumitrescu 			     uint32_t n_members,
394f7598a62SCristian Dumitrescu 			     uint32_t divisor)
395f7598a62SCristian Dumitrescu {
396f7598a62SCristian Dumitrescu 	uint32_t i;
397f7598a62SCristian Dumitrescu 
398f7598a62SCristian Dumitrescu 	for (i = 0; i < n_members; i++) {
399f7598a62SCristian Dumitrescu 		struct group_member_info *m = &members[i];
400f7598a62SCristian Dumitrescu 
401f7598a62SCristian Dumitrescu 		if (m->member_weight_normalized % divisor)
402f7598a62SCristian Dumitrescu 			return 0; /* FALSE. */
403f7598a62SCristian Dumitrescu 	}
404f7598a62SCristian Dumitrescu 
405f7598a62SCristian Dumitrescu 	return 1; /* TRUE. */
406f7598a62SCristian Dumitrescu }
407f7598a62SCristian Dumitrescu 
408f7598a62SCristian Dumitrescu static void
members_weight_divisor_apply(struct group_member_info * members,uint32_t n_members,uint32_t divisor)409f7598a62SCristian Dumitrescu members_weight_divisor_apply(struct group_member_info *members,
410f7598a62SCristian Dumitrescu 			     uint32_t n_members,
411f7598a62SCristian Dumitrescu 			     uint32_t divisor)
412f7598a62SCristian Dumitrescu {
413f7598a62SCristian Dumitrescu 	uint32_t i;
414f7598a62SCristian Dumitrescu 
415f7598a62SCristian Dumitrescu 	for (i = 0; i < n_members; i++) {
416f7598a62SCristian Dumitrescu 		struct group_member_info *m = &members[i];
417f7598a62SCristian Dumitrescu 
418f7598a62SCristian Dumitrescu 		m->member_weight_normalized /= divisor;
419f7598a62SCristian Dumitrescu 	}
420f7598a62SCristian Dumitrescu }
421f7598a62SCristian Dumitrescu 
422f7598a62SCristian Dumitrescu static uint32_t
members_weight_sum(struct group_member_info * members,uint32_t n_members)423f7598a62SCristian Dumitrescu members_weight_sum(struct group_member_info *members, uint32_t n_members)
424f7598a62SCristian Dumitrescu {
425f7598a62SCristian Dumitrescu 	uint32_t result = 0, i;
426f7598a62SCristian Dumitrescu 
427f7598a62SCristian Dumitrescu 	for (i = 0; i < n_members; i++) {
428f7598a62SCristian Dumitrescu 		struct group_member_info *m = &members[i];
429f7598a62SCristian Dumitrescu 
430f7598a62SCristian Dumitrescu 		result += m->member_weight_normalized;
431f7598a62SCristian Dumitrescu 	}
432f7598a62SCristian Dumitrescu 
433f7598a62SCristian Dumitrescu 	return result;
434f7598a62SCristian Dumitrescu }
435f7598a62SCristian Dumitrescu 
436f7598a62SCristian Dumitrescu static void
members_weight_scale(struct group_member_info * members,uint32_t n_members,uint32_t n_members_per_group_max,uint32_t weight_sum)437f7598a62SCristian Dumitrescu members_weight_scale(struct group_member_info *members,
438f7598a62SCristian Dumitrescu 		     uint32_t n_members,
439f7598a62SCristian Dumitrescu 		     uint32_t n_members_per_group_max,
440f7598a62SCristian Dumitrescu 		     uint32_t weight_sum)
441f7598a62SCristian Dumitrescu {
442f7598a62SCristian Dumitrescu 	uint32_t multiplier, remainder, i;
443f7598a62SCristian Dumitrescu 
444f7598a62SCristian Dumitrescu 	multiplier = n_members_per_group_max / weight_sum;
445f7598a62SCristian Dumitrescu 	remainder = n_members_per_group_max % weight_sum;
446f7598a62SCristian Dumitrescu 
447f7598a62SCristian Dumitrescu 	for (i = 0; i < n_members; i++) {
448f7598a62SCristian Dumitrescu 		struct group_member_info *m = &members[i];
449f7598a62SCristian Dumitrescu 
450f7598a62SCristian Dumitrescu 		m->count = m->member_weight_normalized * multiplier;
451f7598a62SCristian Dumitrescu 	}
452f7598a62SCristian Dumitrescu 
453f7598a62SCristian Dumitrescu 	for (i = 0; i < n_members; i++) {
454f7598a62SCristian Dumitrescu 		struct group_member_info *m = &members[i];
455f7598a62SCristian Dumitrescu 		uint32_t min;
456f7598a62SCristian Dumitrescu 
457f7598a62SCristian Dumitrescu 		min = m->member_weight_normalized;
458f7598a62SCristian Dumitrescu 		if (remainder < m->member_weight_normalized)
459f7598a62SCristian Dumitrescu 			min = remainder;
460f7598a62SCristian Dumitrescu 
461f7598a62SCristian Dumitrescu 		m->count += min;
462f7598a62SCristian Dumitrescu 		remainder -= min;
463f7598a62SCristian Dumitrescu 		if (!remainder)
464f7598a62SCristian Dumitrescu 			break;
465f7598a62SCristian Dumitrescu 	}
466f7598a62SCristian Dumitrescu }
467f7598a62SCristian Dumitrescu 
468f7598a62SCristian Dumitrescu static void
members_write(struct group_member_info * members,uint32_t n_members,uint32_t * group_table)469f7598a62SCristian Dumitrescu members_write(struct group_member_info *members,
470f7598a62SCristian Dumitrescu 	      uint32_t n_members,
471f7598a62SCristian Dumitrescu 	      uint32_t *group_table)
472f7598a62SCristian Dumitrescu {
473f7598a62SCristian Dumitrescu 	uint32_t pos = 0, i;
474f7598a62SCristian Dumitrescu 
475f7598a62SCristian Dumitrescu 	for (i = 0; i < n_members; i++) {
476f7598a62SCristian Dumitrescu 		struct group_member_info *m = &members[i];
477f7598a62SCristian Dumitrescu 		uint32_t j;
478f7598a62SCristian Dumitrescu 
479f7598a62SCristian Dumitrescu 		for (j = 0; j < m->count; j++)
480f7598a62SCristian Dumitrescu 			group_table[pos++] = m->member_id;
481f7598a62SCristian Dumitrescu 	}
482f7598a62SCristian Dumitrescu }
483f7598a62SCristian Dumitrescu 
484f7598a62SCristian Dumitrescu static int
group_set(struct table * t,uint32_t group_id,struct rte_swx_table_selector_group * group)485f7598a62SCristian Dumitrescu group_set(struct table *t,
486f7598a62SCristian Dumitrescu 	  uint32_t group_id,
487f7598a62SCristian Dumitrescu 	  struct rte_swx_table_selector_group *group)
488f7598a62SCristian Dumitrescu {
489f7598a62SCristian Dumitrescu 	uint32_t *gt = &t->group_table[group_id * t->params.n_members_per_group_max];
490f7598a62SCristian Dumitrescu 	struct group_member_info *members = t->members;
491f7598a62SCristian Dumitrescu 	uint32_t n_members, weight_min, weight_sum, divisor;
492f7598a62SCristian Dumitrescu 	int status = 0;
493f7598a62SCristian Dumitrescu 
494f7598a62SCristian Dumitrescu 	/* Check input arguments. */
495f7598a62SCristian Dumitrescu 	if (group_id >= t->params.n_groups_max)
496f7598a62SCristian Dumitrescu 		return -EINVAL;
497f7598a62SCristian Dumitrescu 
498f7598a62SCristian Dumitrescu 	status = group_check(t, group);
499f7598a62SCristian Dumitrescu 	if (status)
500f7598a62SCristian Dumitrescu 		return status;
501f7598a62SCristian Dumitrescu 
502f7598a62SCristian Dumitrescu 	/* Read group members. */
503f7598a62SCristian Dumitrescu 	n_members = members_read(members, group);
504f7598a62SCristian Dumitrescu 
505f7598a62SCristian Dumitrescu 	if (!n_members) {
506f7598a62SCristian Dumitrescu 		memset(gt, 0, t->params.n_members_per_group_max * sizeof(uint32_t));
507f7598a62SCristian Dumitrescu 
508f7598a62SCristian Dumitrescu 		return 0;
509f7598a62SCristian Dumitrescu 	}
510f7598a62SCristian Dumitrescu 
511f7598a62SCristian Dumitrescu 	/* Normalize weights. */
512f7598a62SCristian Dumitrescu 	weight_min = members_min_weight_find(members, n_members);
513f7598a62SCristian Dumitrescu 
514f7598a62SCristian Dumitrescu 	for (divisor = 2; divisor <= weight_min; divisor++)
515f7598a62SCristian Dumitrescu 		if (members_weight_divisor_check(members, n_members, divisor))
516f7598a62SCristian Dumitrescu 			members_weight_divisor_apply(members, n_members, divisor);
517f7598a62SCristian Dumitrescu 
518f7598a62SCristian Dumitrescu 	/* Scale weights. */
519f7598a62SCristian Dumitrescu 	weight_sum = members_weight_sum(members, n_members);
520f7598a62SCristian Dumitrescu 	if (weight_sum > t->params.n_members_per_group_max)
521f7598a62SCristian Dumitrescu 		return -ENOSPC;
522f7598a62SCristian Dumitrescu 
523f7598a62SCristian Dumitrescu 	members_weight_scale(members, n_members, t->params.n_members_per_group_max, weight_sum);
524f7598a62SCristian Dumitrescu 
525f7598a62SCristian Dumitrescu 	/* Write group members to the group table. */
526f7598a62SCristian Dumitrescu 	members_write(members, n_members, gt);
527f7598a62SCristian Dumitrescu 
528f7598a62SCristian Dumitrescu 	return 0;
529f7598a62SCristian Dumitrescu }
530f7598a62SCristian Dumitrescu 
531f7598a62SCristian Dumitrescu int
rte_swx_table_selector_group_set(void * table,uint32_t group_id,struct rte_swx_table_selector_group * group)532f7598a62SCristian Dumitrescu rte_swx_table_selector_group_set(void *table,
533f7598a62SCristian Dumitrescu 				 uint32_t group_id,
534f7598a62SCristian Dumitrescu 				 struct rte_swx_table_selector_group *group)
535f7598a62SCristian Dumitrescu {
536f7598a62SCristian Dumitrescu 	struct table *t = table;
537f7598a62SCristian Dumitrescu 
538f7598a62SCristian Dumitrescu 	return group_set(t, group_id, group);
539f7598a62SCristian Dumitrescu }
540f7598a62SCristian Dumitrescu 
541f7598a62SCristian Dumitrescu struct mailbox {
542f7598a62SCristian Dumitrescu 
543f7598a62SCristian Dumitrescu };
544f7598a62SCristian Dumitrescu 
545f7598a62SCristian Dumitrescu uint64_t
rte_swx_table_selector_mailbox_size_get(void)546f7598a62SCristian Dumitrescu rte_swx_table_selector_mailbox_size_get(void)
547f7598a62SCristian Dumitrescu {
548f7598a62SCristian Dumitrescu 	return sizeof(struct mailbox);
549f7598a62SCristian Dumitrescu }
550f7598a62SCristian Dumitrescu 
551f7598a62SCristian Dumitrescu int
rte_swx_table_selector_select(void * table,void * mailbox __rte_unused,uint8_t ** group_id_buffer,uint8_t ** selector_buffer,uint8_t ** member_id_buffer)552f7598a62SCristian Dumitrescu rte_swx_table_selector_select(void *table,
553f7598a62SCristian Dumitrescu 			      void *mailbox __rte_unused,
554f7598a62SCristian Dumitrescu 			      uint8_t **group_id_buffer,
555f7598a62SCristian Dumitrescu 			      uint8_t **selector_buffer,
556f7598a62SCristian Dumitrescu 			      uint8_t **member_id_buffer)
557f7598a62SCristian Dumitrescu {
558f7598a62SCristian Dumitrescu 	struct table *t = table;
559f7598a62SCristian Dumitrescu 	uint32_t *group_id_ptr, *member_id_ptr, group_id, member_id, selector, group_member_index;
560f7598a62SCristian Dumitrescu 
561f7598a62SCristian Dumitrescu 	group_id_ptr = (uint32_t *)&(*group_id_buffer)[t->params.group_id_offset];
562f7598a62SCristian Dumitrescu 
563f7598a62SCristian Dumitrescu 	member_id_ptr = (uint32_t *)&(*member_id_buffer)[t->params.member_id_offset];
564f7598a62SCristian Dumitrescu 
565f7598a62SCristian Dumitrescu 	group_id = *group_id_ptr & (t->params.n_groups_max - 1);
566f7598a62SCristian Dumitrescu 
567f7598a62SCristian Dumitrescu 	selector = hash(&(*selector_buffer)[t->params.selector_offset],
568f7598a62SCristian Dumitrescu 			t->params.selector_mask,
569f7598a62SCristian Dumitrescu 			t->params.selector_size,
570f7598a62SCristian Dumitrescu 			0);
571f7598a62SCristian Dumitrescu 
572f7598a62SCristian Dumitrescu 	group_member_index = selector & (t->params.n_members_per_group_max - 1);
573f7598a62SCristian Dumitrescu 
574f7598a62SCristian Dumitrescu 	member_id = t->group_table[(group_id << t->n_members_per_group_max_log2) +
575f7598a62SCristian Dumitrescu 				   group_member_index];
576f7598a62SCristian Dumitrescu 
577f7598a62SCristian Dumitrescu 	*member_id_ptr = member_id;
578f7598a62SCristian Dumitrescu 
579f7598a62SCristian Dumitrescu 	return 1;
580f7598a62SCristian Dumitrescu }
581