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