xref: /dpdk/examples/l2fwd-cat/cat.c (revision 2c8490a88f090bd7b996f25e6e23ac03d8f644fc)
13998e2a0SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
23998e2a0SBruce Richardson  * Copyright(c) 2016 Intel Corporation
3f6baccbcSWojciech Andralojc  */
4f6baccbcSWojciech Andralojc 
5*2c8490a8SKevin Traynor #include <ctype.h>
6*2c8490a8SKevin Traynor #include <errno.h>
7f6baccbcSWojciech Andralojc #include <getopt.h>
8f6baccbcSWojciech Andralojc #include <inttypes.h>
9f6baccbcSWojciech Andralojc #include <limits.h>
10f6baccbcSWojciech Andralojc #include <sched.h>
11f6baccbcSWojciech Andralojc #include <signal.h>
12f6baccbcSWojciech Andralojc #include <stdio.h>
13f6baccbcSWojciech Andralojc 
14f6baccbcSWojciech Andralojc #include <rte_common.h>
15f6baccbcSWojciech Andralojc #include <rte_memcpy.h>
16f6baccbcSWojciech Andralojc 
17f6baccbcSWojciech Andralojc #include <pqos.h>
18f6baccbcSWojciech Andralojc 
19f6baccbcSWojciech Andralojc #include "cat.h"
20f6baccbcSWojciech Andralojc 
21f6baccbcSWojciech Andralojc #define BITS_PER_HEX		4
22f6baccbcSWojciech Andralojc #define PQOS_MAX_SOCKETS	8
23f6baccbcSWojciech Andralojc #define PQOS_MAX_SOCKET_CORES	64
24f6baccbcSWojciech Andralojc #define PQOS_MAX_CORES		(PQOS_MAX_SOCKET_CORES * PQOS_MAX_SOCKETS)
25f6baccbcSWojciech Andralojc 
26f6baccbcSWojciech Andralojc static const struct pqos_cap *m_cap;
27f6baccbcSWojciech Andralojc static const struct pqos_cpuinfo *m_cpu;
28f6baccbcSWojciech Andralojc static const struct pqos_capability *m_cap_l3ca;
297a08b1d8SVladimir Kuramshin #if PQOS_VERSION <= 103
30f6baccbcSWojciech Andralojc static unsigned m_sockets[PQOS_MAX_SOCKETS];
317a08b1d8SVladimir Kuramshin #else
327a08b1d8SVladimir Kuramshin static unsigned int *m_sockets;
337a08b1d8SVladimir Kuramshin #endif
34f6baccbcSWojciech Andralojc static unsigned m_sock_count;
35f6baccbcSWojciech Andralojc static struct cat_config m_config[PQOS_MAX_CORES];
36f6baccbcSWojciech Andralojc static unsigned m_config_count;
37f6baccbcSWojciech Andralojc 
38f6baccbcSWojciech Andralojc static unsigned
bits_count(uint64_t bitmask)39f6baccbcSWojciech Andralojc bits_count(uint64_t bitmask)
40f6baccbcSWojciech Andralojc {
41f6baccbcSWojciech Andralojc 	unsigned count = 0;
42f6baccbcSWojciech Andralojc 
43f6baccbcSWojciech Andralojc 	for (; bitmask != 0; count++)
44f6baccbcSWojciech Andralojc 		bitmask &= bitmask - 1;
45f6baccbcSWojciech Andralojc 
46f6baccbcSWojciech Andralojc 	return count;
47f6baccbcSWojciech Andralojc }
48f6baccbcSWojciech Andralojc 
49f6baccbcSWojciech Andralojc /*
50f6baccbcSWojciech Andralojc  * Parse elem, the elem could be single number/range or '(' ')' group
51f6baccbcSWojciech Andralojc  * 1) A single number elem, it's just a simple digit. e.g. 9
52f6baccbcSWojciech Andralojc  * 2) A single range elem, two digits with a '-' between. e.g. 2-6
53f6baccbcSWojciech Andralojc  * 3) A group elem, combines multiple 1) or 2) with '( )'. e.g (0,2-4,6)
54f6baccbcSWojciech Andralojc  *    Within group elem, '-' used for a range separator;
55f6baccbcSWojciech Andralojc  *                       ',' used for a single number.
56f6baccbcSWojciech Andralojc  */
57f6baccbcSWojciech Andralojc static int
parse_set(const char * input,rte_cpuset_t * cpusetp)58f6baccbcSWojciech Andralojc parse_set(const char *input, rte_cpuset_t *cpusetp)
59f6baccbcSWojciech Andralojc {
60f6baccbcSWojciech Andralojc 	unsigned idx;
61f6baccbcSWojciech Andralojc 	const char *str = input;
62f6baccbcSWojciech Andralojc 	char *end = NULL;
63f6baccbcSWojciech Andralojc 	unsigned min, max;
64f6baccbcSWojciech Andralojc 	const unsigned num = PQOS_MAX_CORES;
65f6baccbcSWojciech Andralojc 
66f6baccbcSWojciech Andralojc 	CPU_ZERO(cpusetp);
67f6baccbcSWojciech Andralojc 
68f6baccbcSWojciech Andralojc 	while (isblank(*str))
69f6baccbcSWojciech Andralojc 		str++;
70f6baccbcSWojciech Andralojc 
71f6baccbcSWojciech Andralojc 	/* only digit or left bracket is qualify for start point */
72f6baccbcSWojciech Andralojc 	if ((!isdigit(*str) && *str != '(') || *str == '\0')
73f6baccbcSWojciech Andralojc 		return -1;
74f6baccbcSWojciech Andralojc 
75f6baccbcSWojciech Andralojc 	/* process single number or single range of number */
76f6baccbcSWojciech Andralojc 	if (*str != '(') {
77f6baccbcSWojciech Andralojc 		errno = 0;
78f6baccbcSWojciech Andralojc 		idx = strtoul(str, &end, 10);
79f6baccbcSWojciech Andralojc 
80f6baccbcSWojciech Andralojc 		if (errno || end == NULL || idx >= num)
81f6baccbcSWojciech Andralojc 			return -1;
82f6baccbcSWojciech Andralojc 
83f6baccbcSWojciech Andralojc 		while (isblank(*end))
84f6baccbcSWojciech Andralojc 			end++;
85f6baccbcSWojciech Andralojc 
86f6baccbcSWojciech Andralojc 		min = idx;
87f6baccbcSWojciech Andralojc 		max = idx;
88f6baccbcSWojciech Andralojc 		if (*end == '-') {
89f6baccbcSWojciech Andralojc 			/* process single <number>-<number> */
90f6baccbcSWojciech Andralojc 			end++;
91f6baccbcSWojciech Andralojc 			while (isblank(*end))
92f6baccbcSWojciech Andralojc 				end++;
93f6baccbcSWojciech Andralojc 			if (!isdigit(*end))
94f6baccbcSWojciech Andralojc 				return -1;
95f6baccbcSWojciech Andralojc 
96f6baccbcSWojciech Andralojc 			errno = 0;
97f6baccbcSWojciech Andralojc 			idx = strtoul(end, &end, 10);
98f6baccbcSWojciech Andralojc 			if (errno || end == NULL || idx >= num)
99f6baccbcSWojciech Andralojc 				return -1;
100f6baccbcSWojciech Andralojc 			max = idx;
101f6baccbcSWojciech Andralojc 			while (isblank(*end))
102f6baccbcSWojciech Andralojc 				end++;
103f6baccbcSWojciech Andralojc 			if (*end != ',' && *end != '\0')
104f6baccbcSWojciech Andralojc 				return -1;
105f6baccbcSWojciech Andralojc 		}
106f6baccbcSWojciech Andralojc 
107f6baccbcSWojciech Andralojc 		if (*end != ',' && *end != '\0' && *end != '@')
108f6baccbcSWojciech Andralojc 			return -1;
109f6baccbcSWojciech Andralojc 
110f6baccbcSWojciech Andralojc 		for (idx = RTE_MIN(min, max); idx <= RTE_MAX(min, max);
111f6baccbcSWojciech Andralojc 				idx++)
112f6baccbcSWojciech Andralojc 			CPU_SET(idx, cpusetp);
113f6baccbcSWojciech Andralojc 
114f6baccbcSWojciech Andralojc 		return end - input;
115f6baccbcSWojciech Andralojc 	}
116f6baccbcSWojciech Andralojc 
117f6baccbcSWojciech Andralojc 	/* process set within bracket */
118f6baccbcSWojciech Andralojc 	str++;
119f6baccbcSWojciech Andralojc 	while (isblank(*str))
120f6baccbcSWojciech Andralojc 		str++;
121f6baccbcSWojciech Andralojc 	if (*str == '\0')
122f6baccbcSWojciech Andralojc 		return -1;
123f6baccbcSWojciech Andralojc 
124f6baccbcSWojciech Andralojc 	min = PQOS_MAX_CORES;
125f6baccbcSWojciech Andralojc 	do {
126f6baccbcSWojciech Andralojc 
127f6baccbcSWojciech Andralojc 		/* go ahead to the first digit */
128f6baccbcSWojciech Andralojc 		while (isblank(*str))
129f6baccbcSWojciech Andralojc 			str++;
130f6baccbcSWojciech Andralojc 		if (!isdigit(*str))
131f6baccbcSWojciech Andralojc 			return -1;
132f6baccbcSWojciech Andralojc 
133f6baccbcSWojciech Andralojc 		/* get the digit value */
134f6baccbcSWojciech Andralojc 		errno = 0;
135f6baccbcSWojciech Andralojc 		idx = strtoul(str, &end, 10);
136f6baccbcSWojciech Andralojc 		if (errno || end == NULL || idx >= num)
137f6baccbcSWojciech Andralojc 			return -1;
138f6baccbcSWojciech Andralojc 
139f6baccbcSWojciech Andralojc 		/* go ahead to separator '-',',' and ')' */
140f6baccbcSWojciech Andralojc 		while (isblank(*end))
141f6baccbcSWojciech Andralojc 			end++;
142f6baccbcSWojciech Andralojc 		if (*end == '-') {
143f6baccbcSWojciech Andralojc 			if (min == PQOS_MAX_CORES)
144f6baccbcSWojciech Andralojc 				min = idx;
145f6baccbcSWojciech Andralojc 			else /* avoid continuous '-' */
146f6baccbcSWojciech Andralojc 				return -1;
147f6baccbcSWojciech Andralojc 		} else if ((*end == ',') || (*end == ')')) {
148f6baccbcSWojciech Andralojc 			max = idx;
149f6baccbcSWojciech Andralojc 			if (min == PQOS_MAX_CORES)
150f6baccbcSWojciech Andralojc 				min = idx;
151f6baccbcSWojciech Andralojc 			for (idx = RTE_MIN(min, max); idx <= RTE_MAX(min, max);
152f6baccbcSWojciech Andralojc 					idx++)
153f6baccbcSWojciech Andralojc 				CPU_SET(idx, cpusetp);
154f6baccbcSWojciech Andralojc 
155f6baccbcSWojciech Andralojc 			min = PQOS_MAX_CORES;
156f6baccbcSWojciech Andralojc 		} else
157f6baccbcSWojciech Andralojc 			return -1;
158f6baccbcSWojciech Andralojc 
159f6baccbcSWojciech Andralojc 		str = end + 1;
160f6baccbcSWojciech Andralojc 	} while (*end != '\0' && *end != ')');
161f6baccbcSWojciech Andralojc 
162f6baccbcSWojciech Andralojc 	return str - input;
163f6baccbcSWojciech Andralojc }
164f6baccbcSWojciech Andralojc 
165f6baccbcSWojciech Andralojc /* Test if bitmask is contiguous */
166f6baccbcSWojciech Andralojc static int
is_contiguous(uint64_t bitmask)167f6baccbcSWojciech Andralojc is_contiguous(uint64_t bitmask)
168f6baccbcSWojciech Andralojc {
169f6baccbcSWojciech Andralojc 	/* check if bitmask is contiguous */
170f6baccbcSWojciech Andralojc 	unsigned i = 0;
171f6baccbcSWojciech Andralojc 	unsigned j = 0;
172f6baccbcSWojciech Andralojc 	const unsigned max_idx = (sizeof(bitmask) * CHAR_BIT);
173f6baccbcSWojciech Andralojc 
174f6baccbcSWojciech Andralojc 	if (bitmask == 0)
175f6baccbcSWojciech Andralojc 		return 0;
176f6baccbcSWojciech Andralojc 
177f6baccbcSWojciech Andralojc 	for (i = 0; i < max_idx; i++) {
178f6baccbcSWojciech Andralojc 		if (((1ULL << i) & bitmask) != 0)
179f6baccbcSWojciech Andralojc 			j++;
180f6baccbcSWojciech Andralojc 		else if (j > 0)
181f6baccbcSWojciech Andralojc 			break;
182f6baccbcSWojciech Andralojc 	}
183f6baccbcSWojciech Andralojc 
184f6baccbcSWojciech Andralojc 	if (bits_count(bitmask) != j) {
185f6baccbcSWojciech Andralojc 		printf("PQOS: mask 0x%llx is not contiguous.\n",
186f6baccbcSWojciech Andralojc 			(unsigned long long)bitmask);
187f6baccbcSWojciech Andralojc 		return 0;
188f6baccbcSWojciech Andralojc 	}
189f6baccbcSWojciech Andralojc 
190f6baccbcSWojciech Andralojc 	return 1;
191f6baccbcSWojciech Andralojc }
192f6baccbcSWojciech Andralojc 
193f6baccbcSWojciech Andralojc /*
194f6baccbcSWojciech Andralojc  * The format pattern: --l3ca='<cbm@cpus>[,<(ccbm,dcbm)@cpus>...]'
195f6baccbcSWojciech Andralojc  * cbm could be a single mask or for a CDP enabled system, a group of two masks
196f6baccbcSWojciech Andralojc  * ("code cbm" and "data cbm")
197f6baccbcSWojciech Andralojc  * '(' and ')' are necessary if it's a group.
198f6baccbcSWojciech Andralojc  * cpus could be a single digit/range or a group.
199f6baccbcSWojciech Andralojc  * '(' and ')' are necessary if it's a group.
200f6baccbcSWojciech Andralojc  *
201f6baccbcSWojciech Andralojc  * e.g. '0x00F00@(1,3), 0x0FF00@(4-6), 0xF0000@7'
202f6baccbcSWojciech Andralojc  * - CPUs 1 and 3 share its 4 ways with CPUs 4, 5 and 6;
203f6baccbcSWojciech Andralojc  * - CPUs 4,5 and 6 share half (4 out of 8 ways) of its L3 with 1 and 3;
204f6baccbcSWojciech Andralojc  * - CPUs 4,5 and 6 have exclusive access to 4 out of  8 ways;
205f6baccbcSWojciech Andralojc  * - CPU 7 has exclusive access to all of its 4 ways;
206f6baccbcSWojciech Andralojc  *
207f6baccbcSWojciech Andralojc  * e.g. '(0x00C00,0x00300)@(1,3)' for a CDP enabled system
208f6baccbcSWojciech Andralojc  * - cpus 1 and 3 have access to 2 ways for code and 2 ways for data,
209f6baccbcSWojciech Andralojc  *   code and data ways are not overlapping.;
210f6baccbcSWojciech Andralojc  */
211f6baccbcSWojciech Andralojc static int
parse_l3ca(const char * l3ca)212f6baccbcSWojciech Andralojc parse_l3ca(const char *l3ca)
213f6baccbcSWojciech Andralojc {
214f6baccbcSWojciech Andralojc 	unsigned idx = 0;
215f6baccbcSWojciech Andralojc 	const char *cbm_start = NULL;
216f6baccbcSWojciech Andralojc 	char *cbm_end = NULL;
217f6baccbcSWojciech Andralojc 	const char *end = NULL;
218f6baccbcSWojciech Andralojc 	int offset;
219f6baccbcSWojciech Andralojc 	rte_cpuset_t cpuset;
220f6baccbcSWojciech Andralojc 	uint64_t mask = 0;
221f6baccbcSWojciech Andralojc 	uint64_t cmask = 0;
222f6baccbcSWojciech Andralojc 
223f6baccbcSWojciech Andralojc 	if (l3ca == NULL)
224f6baccbcSWojciech Andralojc 		goto err;
225f6baccbcSWojciech Andralojc 
226f6baccbcSWojciech Andralojc 	/* Get cbm */
227f6baccbcSWojciech Andralojc 	do {
228f6baccbcSWojciech Andralojc 		CPU_ZERO(&cpuset);
229f6baccbcSWojciech Andralojc 		mask = 0;
230f6baccbcSWojciech Andralojc 		cmask = 0;
231f6baccbcSWojciech Andralojc 
232f6baccbcSWojciech Andralojc 		while (isblank(*l3ca))
233f6baccbcSWojciech Andralojc 			l3ca++;
234f6baccbcSWojciech Andralojc 
235f6baccbcSWojciech Andralojc 		if (*l3ca == '\0')
236f6baccbcSWojciech Andralojc 			goto err;
237f6baccbcSWojciech Andralojc 
238f6baccbcSWojciech Andralojc 		/* record mask_set start point */
239f6baccbcSWojciech Andralojc 		cbm_start = l3ca;
240f6baccbcSWojciech Andralojc 
241f6baccbcSWojciech Andralojc 		/* go across a complete bracket */
242f6baccbcSWojciech Andralojc 		if (*cbm_start == '(') {
243f6baccbcSWojciech Andralojc 			l3ca += strcspn(l3ca, ")");
244f6baccbcSWojciech Andralojc 			if (*l3ca++ == '\0')
245f6baccbcSWojciech Andralojc 				goto err;
246f6baccbcSWojciech Andralojc 		}
247f6baccbcSWojciech Andralojc 
248f6baccbcSWojciech Andralojc 		/* scan the separator '@', ','(next) or '\0'(finish) */
249f6baccbcSWojciech Andralojc 		l3ca += strcspn(l3ca, "@,");
250f6baccbcSWojciech Andralojc 
2517a08b1d8SVladimir Kuramshin 		if (*l3ca != '@')
2527a08b1d8SVladimir Kuramshin 			goto err;
2537a08b1d8SVladimir Kuramshin 
254f6baccbcSWojciech Andralojc 		/* explicit assign cpu_set */
255f6baccbcSWojciech Andralojc 		offset = parse_set(l3ca + 1, &cpuset);
256f6baccbcSWojciech Andralojc 		if (offset < 0 || CPU_COUNT(&cpuset) == 0)
257f6baccbcSWojciech Andralojc 			goto err;
258f6baccbcSWojciech Andralojc 
259f6baccbcSWojciech Andralojc 		end = l3ca + 1 + offset;
260f6baccbcSWojciech Andralojc 
261f6baccbcSWojciech Andralojc 		if (*end != ',' && *end != '\0')
262f6baccbcSWojciech Andralojc 			goto err;
263f6baccbcSWojciech Andralojc 
264f6baccbcSWojciech Andralojc 		/* parse mask_set from start point */
265f6baccbcSWojciech Andralojc 		if (*cbm_start == '(') {
266f6baccbcSWojciech Andralojc 			cbm_start++;
267f6baccbcSWojciech Andralojc 
268f6baccbcSWojciech Andralojc 			while (isblank(*cbm_start))
269f6baccbcSWojciech Andralojc 				cbm_start++;
270f6baccbcSWojciech Andralojc 
271f6baccbcSWojciech Andralojc 			if (!isxdigit(*cbm_start))
272f6baccbcSWojciech Andralojc 				goto err;
273f6baccbcSWojciech Andralojc 
274f6baccbcSWojciech Andralojc 			errno = 0;
275f6baccbcSWojciech Andralojc 			cmask = strtoul(cbm_start, &cbm_end, 16);
276f6baccbcSWojciech Andralojc 			if (errno != 0 || cbm_end == NULL || cmask == 0)
277f6baccbcSWojciech Andralojc 				goto err;
278f6baccbcSWojciech Andralojc 
279f6baccbcSWojciech Andralojc 			while (isblank(*cbm_end))
280f6baccbcSWojciech Andralojc 				cbm_end++;
281f6baccbcSWojciech Andralojc 
282f6baccbcSWojciech Andralojc 			if (*cbm_end != ',')
283f6baccbcSWojciech Andralojc 				goto err;
284f6baccbcSWojciech Andralojc 
285f6baccbcSWojciech Andralojc 			cbm_end++;
286f6baccbcSWojciech Andralojc 
287f6baccbcSWojciech Andralojc 			while (isblank(*cbm_end))
288f6baccbcSWojciech Andralojc 				cbm_end++;
289f6baccbcSWojciech Andralojc 
290f6baccbcSWojciech Andralojc 			if (!isxdigit(*cbm_end))
291f6baccbcSWojciech Andralojc 				goto err;
292f6baccbcSWojciech Andralojc 
293f6baccbcSWojciech Andralojc 			errno = 0;
294f6baccbcSWojciech Andralojc 			mask = strtoul(cbm_end, &cbm_end, 16);
295f6baccbcSWojciech Andralojc 			if (errno != 0 || cbm_end == NULL || mask == 0)
296f6baccbcSWojciech Andralojc 				goto err;
297f6baccbcSWojciech Andralojc 		} else {
298f6baccbcSWojciech Andralojc 			while (isblank(*cbm_start))
299f6baccbcSWojciech Andralojc 				cbm_start++;
300f6baccbcSWojciech Andralojc 
301f6baccbcSWojciech Andralojc 			if (!isxdigit(*cbm_start))
302f6baccbcSWojciech Andralojc 				goto err;
303f6baccbcSWojciech Andralojc 
304f6baccbcSWojciech Andralojc 			errno = 0;
305f6baccbcSWojciech Andralojc 			mask = strtoul(cbm_start, &cbm_end, 16);
306f6baccbcSWojciech Andralojc 			if (errno != 0 || cbm_end == NULL || mask == 0)
307f6baccbcSWojciech Andralojc 				goto err;
308f6baccbcSWojciech Andralojc 
309f6baccbcSWojciech Andralojc 		}
310f6baccbcSWojciech Andralojc 
311f6baccbcSWojciech Andralojc 		if (mask == 0 || is_contiguous(mask) == 0)
312f6baccbcSWojciech Andralojc 			goto err;
313f6baccbcSWojciech Andralojc 
314f6baccbcSWojciech Andralojc 		if (cmask != 0 && is_contiguous(cmask) == 0)
315f6baccbcSWojciech Andralojc 			goto err;
316f6baccbcSWojciech Andralojc 
317f6baccbcSWojciech Andralojc 		rte_memcpy(&m_config[idx].cpumask,
318f6baccbcSWojciech Andralojc 			&cpuset, sizeof(rte_cpuset_t));
319f6baccbcSWojciech Andralojc 
320f6baccbcSWojciech Andralojc 		if (cmask != 0) {
321f6baccbcSWojciech Andralojc 			m_config[idx].cdp = 1;
322f6baccbcSWojciech Andralojc 			m_config[idx].code_mask = cmask;
323f6baccbcSWojciech Andralojc 			m_config[idx].data_mask = mask;
324f6baccbcSWojciech Andralojc 		} else
325f6baccbcSWojciech Andralojc 			m_config[idx].mask = mask;
326f6baccbcSWojciech Andralojc 
327f6baccbcSWojciech Andralojc 		m_config_count++;
328f6baccbcSWojciech Andralojc 
329f6baccbcSWojciech Andralojc 		l3ca = end + 1;
330f6baccbcSWojciech Andralojc 		idx++;
331f6baccbcSWojciech Andralojc 	} while (*end != '\0' && idx < PQOS_MAX_CORES);
332f6baccbcSWojciech Andralojc 
333f6baccbcSWojciech Andralojc 	return 0;
334f6baccbcSWojciech Andralojc 
335f6baccbcSWojciech Andralojc err:
336f6baccbcSWojciech Andralojc 	return -EINVAL;
337f6baccbcSWojciech Andralojc }
338f6baccbcSWojciech Andralojc 
339f6baccbcSWojciech Andralojc static int
check_cpus_overlapping(void)340f6baccbcSWojciech Andralojc check_cpus_overlapping(void)
341f6baccbcSWojciech Andralojc {
342f6baccbcSWojciech Andralojc 	unsigned i = 0;
343f6baccbcSWojciech Andralojc 	unsigned j = 0;
344f6baccbcSWojciech Andralojc 	rte_cpuset_t mask;
345f6baccbcSWojciech Andralojc 
346f6baccbcSWojciech Andralojc 	CPU_ZERO(&mask);
347f6baccbcSWojciech Andralojc 
348f6baccbcSWojciech Andralojc 	for (i = 0; i < m_config_count; i++) {
349f6baccbcSWojciech Andralojc 		for (j = i + 1; j < m_config_count; j++) {
350d51e5ec7SBruce Richardson 			RTE_CPU_AND(&mask,
351f6baccbcSWojciech Andralojc 				&m_config[i].cpumask,
352f6baccbcSWojciech Andralojc 				&m_config[j].cpumask);
353f6baccbcSWojciech Andralojc 
354f6baccbcSWojciech Andralojc 			if (CPU_COUNT(&mask) != 0) {
355f6baccbcSWojciech Andralojc 				printf("PQOS: Requested CPUs sets are "
356f6baccbcSWojciech Andralojc 					"overlapping.\n");
357f6baccbcSWojciech Andralojc 				return -EINVAL;
358f6baccbcSWojciech Andralojc 			}
359f6baccbcSWojciech Andralojc 		}
360f6baccbcSWojciech Andralojc 	}
361f6baccbcSWojciech Andralojc 
362f6baccbcSWojciech Andralojc 	return 0;
363f6baccbcSWojciech Andralojc }
364f6baccbcSWojciech Andralojc 
365f6baccbcSWojciech Andralojc static int
check_cpus(void)366f6baccbcSWojciech Andralojc check_cpus(void)
367f6baccbcSWojciech Andralojc {
368f6baccbcSWojciech Andralojc 	unsigned i = 0;
369f6baccbcSWojciech Andralojc 	unsigned cpu_id = 0;
370f6baccbcSWojciech Andralojc 	unsigned cos_id = 0;
371f6baccbcSWojciech Andralojc 	int ret = 0;
372f6baccbcSWojciech Andralojc 
373f6baccbcSWojciech Andralojc 	for (i = 0; i < m_config_count; i++) {
374f6baccbcSWojciech Andralojc 		for (cpu_id = 0; cpu_id < PQOS_MAX_CORES; cpu_id++) {
375f6baccbcSWojciech Andralojc 			if (CPU_ISSET(cpu_id, &m_config[i].cpumask) != 0) {
376f6baccbcSWojciech Andralojc 
377f6baccbcSWojciech Andralojc 				ret = pqos_cpu_check_core(m_cpu, cpu_id);
378f6baccbcSWojciech Andralojc 				if (ret != PQOS_RETVAL_OK) {
379f6baccbcSWojciech Andralojc 					printf("PQOS: %u is not a valid "
380f6baccbcSWojciech Andralojc 						"logical core id.\n", cpu_id);
381f6baccbcSWojciech Andralojc 					ret = -ENODEV;
382f6baccbcSWojciech Andralojc 					goto exit;
383f6baccbcSWojciech Andralojc 				}
384f6baccbcSWojciech Andralojc 
3857a08b1d8SVladimir Kuramshin #if PQOS_VERSION <= 103
386f6baccbcSWojciech Andralojc 				ret = pqos_l3ca_assoc_get(cpu_id, &cos_id);
3877a08b1d8SVladimir Kuramshin #else
3887a08b1d8SVladimir Kuramshin 				ret = pqos_alloc_assoc_get(cpu_id, &cos_id);
3897a08b1d8SVladimir Kuramshin #endif
390f6baccbcSWojciech Andralojc 				if (ret != PQOS_RETVAL_OK) {
391f6baccbcSWojciech Andralojc 					printf("PQOS: Failed to read COS "
392f6baccbcSWojciech Andralojc 						"associated to cpu %u.\n",
393f6baccbcSWojciech Andralojc 						cpu_id);
394f6baccbcSWojciech Andralojc 					ret = -EFAULT;
395f6baccbcSWojciech Andralojc 					goto exit;
396f6baccbcSWojciech Andralojc 				}
397f6baccbcSWojciech Andralojc 
398f6baccbcSWojciech Andralojc 				/*
399f6baccbcSWojciech Andralojc 				 * Check if COS assigned to lcore is different
400f6baccbcSWojciech Andralojc 				 * then default one (#0)
401f6baccbcSWojciech Andralojc 				 */
402f6baccbcSWojciech Andralojc 				if (cos_id != 0) {
403f6baccbcSWojciech Andralojc 					printf("PQOS: cpu %u has already "
404f6baccbcSWojciech Andralojc 						"associated COS#%u. "
405f6baccbcSWojciech Andralojc 						"Please reset L3CA.\n",
406f6baccbcSWojciech Andralojc 						cpu_id, cos_id);
407f6baccbcSWojciech Andralojc 					ret = -EBUSY;
408f6baccbcSWojciech Andralojc 					goto exit;
409f6baccbcSWojciech Andralojc 				}
410f6baccbcSWojciech Andralojc 			}
411f6baccbcSWojciech Andralojc 		}
412f6baccbcSWojciech Andralojc 	}
413f6baccbcSWojciech Andralojc 
414f6baccbcSWojciech Andralojc exit:
415f6baccbcSWojciech Andralojc 	return ret;
416f6baccbcSWojciech Andralojc }
417f6baccbcSWojciech Andralojc 
418f6baccbcSWojciech Andralojc static int
check_cdp(void)419f6baccbcSWojciech Andralojc check_cdp(void)
420f6baccbcSWojciech Andralojc {
421f6baccbcSWojciech Andralojc 	unsigned i = 0;
422f6baccbcSWojciech Andralojc 
423f6baccbcSWojciech Andralojc 	for (i = 0; i < m_config_count; i++) {
424f6baccbcSWojciech Andralojc 		if (m_config[i].cdp == 1 && m_cap_l3ca->u.l3ca->cdp_on == 0) {
425f6baccbcSWojciech Andralojc 			if (m_cap_l3ca->u.l3ca->cdp == 0) {
426f6baccbcSWojciech Andralojc 				printf("PQOS: CDP requested but not "
427f6baccbcSWojciech Andralojc 					"supported.\n");
428f6baccbcSWojciech Andralojc 			} else {
429f6baccbcSWojciech Andralojc 				printf("PQOS: CDP requested but not enabled. "
430f6baccbcSWojciech Andralojc 					"Please enable CDP.\n");
431f6baccbcSWojciech Andralojc 			}
432f6baccbcSWojciech Andralojc 			return -ENOTSUP;
433f6baccbcSWojciech Andralojc 		}
434f6baccbcSWojciech Andralojc 	}
435f6baccbcSWojciech Andralojc 
436f6baccbcSWojciech Andralojc 	return 0;
437f6baccbcSWojciech Andralojc }
438f6baccbcSWojciech Andralojc 
439f6baccbcSWojciech Andralojc static int
check_cbm_len_and_contention(void)440f6baccbcSWojciech Andralojc check_cbm_len_and_contention(void)
441f6baccbcSWojciech Andralojc {
442f6baccbcSWojciech Andralojc 	unsigned i = 0;
443f6baccbcSWojciech Andralojc 	uint64_t mask = 0;
444f6baccbcSWojciech Andralojc 	const uint64_t not_cbm = (UINT64_MAX << (m_cap_l3ca->u.l3ca->num_ways));
445f6baccbcSWojciech Andralojc 	const uint64_t cbm_contention_mask = m_cap_l3ca->u.l3ca->way_contention;
446f6baccbcSWojciech Andralojc 	int ret = 0;
447f6baccbcSWojciech Andralojc 
448f6baccbcSWojciech Andralojc 	for (i = 0; i < m_config_count; i++) {
449f6baccbcSWojciech Andralojc 		if (m_config[i].cdp == 1)
450f6baccbcSWojciech Andralojc 			mask = m_config[i].code_mask | m_config[i].data_mask;
451f6baccbcSWojciech Andralojc 		else
452f6baccbcSWojciech Andralojc 			mask = m_config[i].mask;
453f6baccbcSWojciech Andralojc 
454f6baccbcSWojciech Andralojc 		if ((mask & not_cbm) != 0) {
455f6baccbcSWojciech Andralojc 			printf("PQOS: One or more of requested CBM masks not "
456f6baccbcSWojciech Andralojc 				"supported by system (too long).\n");
457f6baccbcSWojciech Andralojc 			ret = -ENOTSUP;
458f6baccbcSWojciech Andralojc 			break;
459f6baccbcSWojciech Andralojc 		}
460f6baccbcSWojciech Andralojc 
461f6baccbcSWojciech Andralojc 		/* Just a warning */
462f6baccbcSWojciech Andralojc 		if ((mask & cbm_contention_mask) != 0) {
463f6baccbcSWojciech Andralojc 			printf("PQOS: One or more of requested CBM  masks "
464f6baccbcSWojciech Andralojc 				"overlap CBM contention mask.\n");
465f6baccbcSWojciech Andralojc 			break;
466f6baccbcSWojciech Andralojc 		}
467f6baccbcSWojciech Andralojc 
468f6baccbcSWojciech Andralojc 	}
469f6baccbcSWojciech Andralojc 
470f6baccbcSWojciech Andralojc 	return ret;
471f6baccbcSWojciech Andralojc }
472f6baccbcSWojciech Andralojc 
473f6baccbcSWojciech Andralojc static int
check_and_select_classes(unsigned cos_id_map[][PQOS_MAX_SOCKETS])474f6baccbcSWojciech Andralojc check_and_select_classes(unsigned cos_id_map[][PQOS_MAX_SOCKETS])
475f6baccbcSWojciech Andralojc {
476f6baccbcSWojciech Andralojc 	unsigned i = 0;
477f6baccbcSWojciech Andralojc 	unsigned j = 0;
478f6baccbcSWojciech Andralojc 	unsigned phy_pkg_id = 0;
479f6baccbcSWojciech Andralojc 	unsigned cos_id = 0;
480f6baccbcSWojciech Andralojc 	unsigned cpu_id = 0;
481f6baccbcSWojciech Andralojc 	unsigned phy_pkg_lcores[PQOS_MAX_SOCKETS][m_config_count];
482f6baccbcSWojciech Andralojc 	const unsigned cos_num = m_cap_l3ca->u.l3ca->num_classes;
483f6baccbcSWojciech Andralojc 	unsigned used_cos_table[PQOS_MAX_SOCKETS][cos_num];
484f6baccbcSWojciech Andralojc 	int ret = 0;
485f6baccbcSWojciech Andralojc 
486f6baccbcSWojciech Andralojc 	memset(phy_pkg_lcores, 0, sizeof(phy_pkg_lcores));
487f6baccbcSWojciech Andralojc 	memset(used_cos_table, 0, sizeof(used_cos_table));
488f6baccbcSWojciech Andralojc 
489f6baccbcSWojciech Andralojc 	/* detect currently used COS */
490f6baccbcSWojciech Andralojc 	for (j = 0; j < m_cpu->num_cores; j++) {
491f6baccbcSWojciech Andralojc 		cpu_id = m_cpu->cores[j].lcore;
492f6baccbcSWojciech Andralojc 
4937a08b1d8SVladimir Kuramshin #if PQOS_VERSION <= 103
494f6baccbcSWojciech Andralojc 		ret = pqos_l3ca_assoc_get(cpu_id, &cos_id);
4957a08b1d8SVladimir Kuramshin #else
4967a08b1d8SVladimir Kuramshin 		ret = pqos_alloc_assoc_get(cpu_id, &cos_id);
4977a08b1d8SVladimir Kuramshin #endif
498f6baccbcSWojciech Andralojc 		if (ret != PQOS_RETVAL_OK) {
499f6baccbcSWojciech Andralojc 			printf("PQOS: Failed to read COS associated to "
500f6baccbcSWojciech Andralojc 				"cpu %u on phy_pkg %u.\n", cpu_id, phy_pkg_id);
501f6baccbcSWojciech Andralojc 			ret = -EFAULT;
502f6baccbcSWojciech Andralojc 			goto exit;
503f6baccbcSWojciech Andralojc 		}
504f6baccbcSWojciech Andralojc 
505f6baccbcSWojciech Andralojc 		ret = pqos_cpu_get_socketid(m_cpu, cpu_id, &phy_pkg_id);
506f6baccbcSWojciech Andralojc 		if (ret != PQOS_RETVAL_OK) {
507f6baccbcSWojciech Andralojc 			printf("PQOS: Failed to get socket for cpu %u\n",
508f6baccbcSWojciech Andralojc 				cpu_id);
509f6baccbcSWojciech Andralojc 			ret = -EFAULT;
510f6baccbcSWojciech Andralojc 			goto exit;
511f6baccbcSWojciech Andralojc 		}
512f6baccbcSWojciech Andralojc 
513f6baccbcSWojciech Andralojc 		/* Mark COS as used */
514f6baccbcSWojciech Andralojc 		if (used_cos_table[phy_pkg_id][cos_id] == 0)
515f6baccbcSWojciech Andralojc 			used_cos_table[phy_pkg_id][cos_id]++;
516f6baccbcSWojciech Andralojc 	}
517f6baccbcSWojciech Andralojc 
518f6baccbcSWojciech Andralojc 	/* look for avail. COS to fulfill requested config */
519f6baccbcSWojciech Andralojc 	for (i = 0; i < m_config_count; i++) {
520f6baccbcSWojciech Andralojc 		for (j = 0; j < m_cpu->num_cores; j++) {
521f6baccbcSWojciech Andralojc 			cpu_id = m_cpu->cores[j].lcore;
522f6baccbcSWojciech Andralojc 			if (CPU_ISSET(cpu_id, &m_config[i].cpumask) == 0)
523f6baccbcSWojciech Andralojc 				continue;
524f6baccbcSWojciech Andralojc 
525f6baccbcSWojciech Andralojc 			ret = pqos_cpu_get_socketid(m_cpu, cpu_id, &phy_pkg_id);
526f6baccbcSWojciech Andralojc 			if (ret != PQOS_RETVAL_OK) {
527f6baccbcSWojciech Andralojc 				printf("PQOS: Failed to get socket for "
528f6baccbcSWojciech Andralojc 					"cpu %u\n", cpu_id);
529f6baccbcSWojciech Andralojc 				ret = -EFAULT;
530f6baccbcSWojciech Andralojc 				goto exit;
531f6baccbcSWojciech Andralojc 			}
532f6baccbcSWojciech Andralojc 
533f6baccbcSWojciech Andralojc 			/*
534f6baccbcSWojciech Andralojc 			 * Check if we already have COS selected
535f6baccbcSWojciech Andralojc 			 * to be used for that group on that socket
536f6baccbcSWojciech Andralojc 			 */
537f6baccbcSWojciech Andralojc 			if (phy_pkg_lcores[phy_pkg_id][i] != 0)
538f6baccbcSWojciech Andralojc 				continue;
539f6baccbcSWojciech Andralojc 
540f6baccbcSWojciech Andralojc 			phy_pkg_lcores[phy_pkg_id][i]++;
541f6baccbcSWojciech Andralojc 
542f6baccbcSWojciech Andralojc 			/* Search for avail. COS to be used on that socket */
543f6baccbcSWojciech Andralojc 			for (cos_id = 0; cos_id < cos_num; cos_id++) {
544f6baccbcSWojciech Andralojc 				if (used_cos_table[phy_pkg_id][cos_id] == 0) {
545f6baccbcSWojciech Andralojc 					used_cos_table[phy_pkg_id][cos_id]++;
546f6baccbcSWojciech Andralojc 					cos_id_map[i][phy_pkg_id] = cos_id;
547f6baccbcSWojciech Andralojc 					break;
548f6baccbcSWojciech Andralojc 				}
549f6baccbcSWojciech Andralojc 			}
550f6baccbcSWojciech Andralojc 
551f6baccbcSWojciech Andralojc 			/* If there is no COS available ...*/
552f6baccbcSWojciech Andralojc 			if (cos_id == cos_num) {
553f6baccbcSWojciech Andralojc 				ret = -E2BIG;
554f6baccbcSWojciech Andralojc 				goto exit;
555f6baccbcSWojciech Andralojc 			}
556f6baccbcSWojciech Andralojc 		}
557f6baccbcSWojciech Andralojc 	}
558f6baccbcSWojciech Andralojc 
559f6baccbcSWojciech Andralojc exit:
560f6baccbcSWojciech Andralojc 	if (ret != 0)
561f6baccbcSWojciech Andralojc 		printf("PQOS: Not enough available COS to configure "
562f6baccbcSWojciech Andralojc 			"requested configuration.\n");
563f6baccbcSWojciech Andralojc 
564f6baccbcSWojciech Andralojc 	return ret;
565f6baccbcSWojciech Andralojc }
566f6baccbcSWojciech Andralojc 
567f6baccbcSWojciech Andralojc static int
configure_cat(unsigned cos_id_map[][PQOS_MAX_SOCKETS])568f6baccbcSWojciech Andralojc configure_cat(unsigned cos_id_map[][PQOS_MAX_SOCKETS])
569f6baccbcSWojciech Andralojc {
570f6baccbcSWojciech Andralojc 	unsigned phy_pkg_id = 0;
571f6baccbcSWojciech Andralojc 	unsigned cpu_id = 0;
572f6baccbcSWojciech Andralojc 	unsigned cos_id = 0;
573f6baccbcSWojciech Andralojc 	unsigned i = 0;
574f6baccbcSWojciech Andralojc 	unsigned j = 0;
575f6baccbcSWojciech Andralojc 	struct pqos_l3ca l3ca = {0};
576f6baccbcSWojciech Andralojc 	int ret = 0;
577f6baccbcSWojciech Andralojc 
578f6baccbcSWojciech Andralojc 	for (i = 0; i < m_config_count; i++) {
579f6baccbcSWojciech Andralojc 		memset(&l3ca, 0, sizeof(l3ca));
580f6baccbcSWojciech Andralojc 
581f6baccbcSWojciech Andralojc 		l3ca.cdp = m_config[i].cdp;
582f6baccbcSWojciech Andralojc 		if (m_config[i].cdp == 1) {
5837a08b1d8SVladimir Kuramshin #if PQOS_VERSION <= 103
584f6baccbcSWojciech Andralojc 			l3ca.code_mask = m_config[i].code_mask;
585f6baccbcSWojciech Andralojc 			l3ca.data_mask = m_config[i].data_mask;
5867a08b1d8SVladimir Kuramshin #else
5877a08b1d8SVladimir Kuramshin 			l3ca.u.s.code_mask = m_config[i].code_mask;
5887a08b1d8SVladimir Kuramshin 			l3ca.u.s.data_mask = m_config[i].data_mask;
5897a08b1d8SVladimir Kuramshin #endif
590f6baccbcSWojciech Andralojc 		} else
5917a08b1d8SVladimir Kuramshin #if PQOS_VERSION <= 103
592f6baccbcSWojciech Andralojc 			l3ca.ways_mask = m_config[i].mask;
5937a08b1d8SVladimir Kuramshin #else
5947a08b1d8SVladimir Kuramshin 			l3ca.u.ways_mask = m_config[i].mask;
5957a08b1d8SVladimir Kuramshin #endif
596f6baccbcSWojciech Andralojc 
597f6baccbcSWojciech Andralojc 		for (j = 0; j < m_sock_count; j++) {
598f6baccbcSWojciech Andralojc 			phy_pkg_id = m_sockets[j];
599f6baccbcSWojciech Andralojc 			if (cos_id_map[i][phy_pkg_id] == 0)
600f6baccbcSWojciech Andralojc 				continue;
601f6baccbcSWojciech Andralojc 
602f6baccbcSWojciech Andralojc 			l3ca.class_id = cos_id_map[i][phy_pkg_id];
603f6baccbcSWojciech Andralojc 
604f6baccbcSWojciech Andralojc 			ret = pqos_l3ca_set(phy_pkg_id, 1, &l3ca);
605f6baccbcSWojciech Andralojc 			if (ret != PQOS_RETVAL_OK) {
606f6baccbcSWojciech Andralojc 				printf("PQOS: Failed to set COS %u on "
607f6baccbcSWojciech Andralojc 					"phy_pkg %u.\n", l3ca.class_id,
608f6baccbcSWojciech Andralojc 					phy_pkg_id);
609f6baccbcSWojciech Andralojc 				ret = -EFAULT;
610f6baccbcSWojciech Andralojc 				goto exit;
611f6baccbcSWojciech Andralojc 			}
612f6baccbcSWojciech Andralojc 		}
613f6baccbcSWojciech Andralojc 	}
614f6baccbcSWojciech Andralojc 
615f6baccbcSWojciech Andralojc 	for (i = 0; i < m_config_count; i++) {
616f6baccbcSWojciech Andralojc 		for (j = 0; j < m_cpu->num_cores; j++) {
617f6baccbcSWojciech Andralojc 			cpu_id = m_cpu->cores[j].lcore;
618f6baccbcSWojciech Andralojc 			if (CPU_ISSET(cpu_id, &m_config[i].cpumask) == 0)
619f6baccbcSWojciech Andralojc 				continue;
620f6baccbcSWojciech Andralojc 
621f6baccbcSWojciech Andralojc 			ret = pqos_cpu_get_socketid(m_cpu, cpu_id, &phy_pkg_id);
622f6baccbcSWojciech Andralojc 			if (ret != PQOS_RETVAL_OK) {
623f6baccbcSWojciech Andralojc 				printf("PQOS: Failed to get socket for "
624f6baccbcSWojciech Andralojc 					"cpu %u\n", cpu_id);
625f6baccbcSWojciech Andralojc 				ret = -EFAULT;
626f6baccbcSWojciech Andralojc 				goto exit;
627f6baccbcSWojciech Andralojc 			}
628f6baccbcSWojciech Andralojc 
629f6baccbcSWojciech Andralojc 			cos_id = cos_id_map[i][phy_pkg_id];
630f6baccbcSWojciech Andralojc 
6317a08b1d8SVladimir Kuramshin #if PQOS_VERSION <= 103
632f6baccbcSWojciech Andralojc 			ret = pqos_l3ca_assoc_set(cpu_id, cos_id);
6337a08b1d8SVladimir Kuramshin #else
6347a08b1d8SVladimir Kuramshin 			ret = pqos_alloc_assoc_set(cpu_id, cos_id);
6357a08b1d8SVladimir Kuramshin #endif
636f6baccbcSWojciech Andralojc 			if (ret != PQOS_RETVAL_OK) {
637f6baccbcSWojciech Andralojc 				printf("PQOS: Failed to associate COS %u to "
638f6baccbcSWojciech Andralojc 					"cpu %u\n", cos_id, cpu_id);
639f6baccbcSWojciech Andralojc 				ret = -EFAULT;
640f6baccbcSWojciech Andralojc 				goto exit;
641f6baccbcSWojciech Andralojc 			}
642f6baccbcSWojciech Andralojc 		}
643f6baccbcSWojciech Andralojc 	}
644f6baccbcSWojciech Andralojc 
645f6baccbcSWojciech Andralojc exit:
646f6baccbcSWojciech Andralojc 	return ret;
647f6baccbcSWojciech Andralojc }
648f6baccbcSWojciech Andralojc 
649f6baccbcSWojciech Andralojc 
650f6baccbcSWojciech Andralojc /* Parse the argument given in the command line of the application */
651f6baccbcSWojciech Andralojc static int
parse_args(int argc,char ** argv)652f6baccbcSWojciech Andralojc parse_args(int argc, char **argv)
653f6baccbcSWojciech Andralojc {
654f6baccbcSWojciech Andralojc 	int opt = 0;
655f6baccbcSWojciech Andralojc 	int retval = 0;
656f6baccbcSWojciech Andralojc 	int oldopterr = 0;
657f6baccbcSWojciech Andralojc 	char **argvopt = argv;
658f6baccbcSWojciech Andralojc 	char *prgname = argv[0];
659f6baccbcSWojciech Andralojc 
660f6baccbcSWojciech Andralojc 	static struct option lgopts[] = {
661f6baccbcSWojciech Andralojc 		{ "l3ca", required_argument, 0, 0 },
662f6baccbcSWojciech Andralojc 		{ NULL, 0, 0, 0 }
663f6baccbcSWojciech Andralojc 	};
664f6baccbcSWojciech Andralojc 
665f6baccbcSWojciech Andralojc 	/* Disable printing messages within getopt() */
666f6baccbcSWojciech Andralojc 	oldopterr = opterr;
667f6baccbcSWojciech Andralojc 	opterr = 0;
668f6baccbcSWojciech Andralojc 
669f6baccbcSWojciech Andralojc 	opt = getopt_long(argc, argvopt, "", lgopts, NULL);
670f6baccbcSWojciech Andralojc 	if (opt == 0) {
671f6baccbcSWojciech Andralojc 		retval = parse_l3ca(optarg);
672f6baccbcSWojciech Andralojc 		if (retval != 0) {
673f6baccbcSWojciech Andralojc 			printf("PQOS: Invalid L3CA parameters!\n");
674f6baccbcSWojciech Andralojc 			goto exit;
675f6baccbcSWojciech Andralojc 		}
676f6baccbcSWojciech Andralojc 
677f6baccbcSWojciech Andralojc 		argv[optind - 1] = prgname;
678f6baccbcSWojciech Andralojc 		retval = optind - 1;
679f6baccbcSWojciech Andralojc 	} else
680f6baccbcSWojciech Andralojc 		retval = 0;
681f6baccbcSWojciech Andralojc 
682f6baccbcSWojciech Andralojc exit:
683f6baccbcSWojciech Andralojc 	/* reset getopt lib */
6849d5ca532SKeith Wiles 	optind = 1;
685f6baccbcSWojciech Andralojc 
686f6baccbcSWojciech Andralojc 	/* Restore opterr value */
687f6baccbcSWojciech Andralojc 	opterr = oldopterr;
688f6baccbcSWojciech Andralojc 
689f6baccbcSWojciech Andralojc 	return retval;
690f6baccbcSWojciech Andralojc }
691f6baccbcSWojciech Andralojc 
692f6baccbcSWojciech Andralojc static void
print_cmd_line_config(void)693f6baccbcSWojciech Andralojc print_cmd_line_config(void)
694f6baccbcSWojciech Andralojc {
695f6baccbcSWojciech Andralojc 	char cpustr[PQOS_MAX_CORES * 3] = {0};
696f6baccbcSWojciech Andralojc 	unsigned i = 0;
697f6baccbcSWojciech Andralojc 	unsigned j = 0;
698f6baccbcSWojciech Andralojc 
699f6baccbcSWojciech Andralojc 	for (i = 0; i < m_config_count; i++) {
700f6baccbcSWojciech Andralojc 		unsigned len = 0;
701f6baccbcSWojciech Andralojc 		memset(cpustr, 0, sizeof(cpustr));
702f6baccbcSWojciech Andralojc 
703f6baccbcSWojciech Andralojc 		/* Generate CPU list */
704f6baccbcSWojciech Andralojc 		for (j = 0; j < PQOS_MAX_CORES; j++) {
705f6baccbcSWojciech Andralojc 			if (CPU_ISSET(j, &m_config[i].cpumask) != 1)
706f6baccbcSWojciech Andralojc 				continue;
707f6baccbcSWojciech Andralojc 
708f6baccbcSWojciech Andralojc 			len += snprintf(cpustr + len, sizeof(cpustr) - len - 1,
709f6baccbcSWojciech Andralojc 				"%u,", j);
710f6baccbcSWojciech Andralojc 
711f6baccbcSWojciech Andralojc 			if (len >= sizeof(cpustr) - 1)
712f6baccbcSWojciech Andralojc 				break;
713f6baccbcSWojciech Andralojc 		}
714f6baccbcSWojciech Andralojc 
715f6baccbcSWojciech Andralojc 		if (m_config[i].cdp == 1) {
716f6baccbcSWojciech Andralojc 			printf("PQOS: CPUs: %s cMASK: 0x%llx, dMASK: "
717f6baccbcSWojciech Andralojc 				"0x%llx\n", cpustr,
718f6baccbcSWojciech Andralojc 				(unsigned long long)m_config[i].code_mask,
719f6baccbcSWojciech Andralojc 				(unsigned long long)m_config[i].data_mask);
720f6baccbcSWojciech Andralojc 		} else {
721f6baccbcSWojciech Andralojc 			printf("PQOS: CPUs: %s MASK: 0x%llx\n", cpustr,
722f6baccbcSWojciech Andralojc 					(unsigned long long)m_config[i].mask);
723f6baccbcSWojciech Andralojc 		}
724f6baccbcSWojciech Andralojc 	}
725f6baccbcSWojciech Andralojc }
726f6baccbcSWojciech Andralojc 
727f6baccbcSWojciech Andralojc /**
728f6baccbcSWojciech Andralojc  * @brief Prints CAT configuration
729f6baccbcSWojciech Andralojc  */
730f6baccbcSWojciech Andralojc static void
print_cat_config(void)731f6baccbcSWojciech Andralojc print_cat_config(void)
732f6baccbcSWojciech Andralojc {
733f6baccbcSWojciech Andralojc 	int ret = PQOS_RETVAL_OK;
734f6baccbcSWojciech Andralojc 	unsigned i = 0;
735f6baccbcSWojciech Andralojc 
736f6baccbcSWojciech Andralojc 	for (i = 0; i < m_sock_count; i++) {
737f6baccbcSWojciech Andralojc 		struct pqos_l3ca tab[PQOS_MAX_L3CA_COS] = {{0} };
738f6baccbcSWojciech Andralojc 		unsigned num = 0;
739f6baccbcSWojciech Andralojc 		unsigned n = 0;
740f6baccbcSWojciech Andralojc 
741f6baccbcSWojciech Andralojc 		ret = pqos_l3ca_get(m_sockets[i], PQOS_MAX_L3CA_COS, &num, tab);
742f6baccbcSWojciech Andralojc 		if (ret != PQOS_RETVAL_OK) {
743f6baccbcSWojciech Andralojc 			printf("PQOS: Error retrieving COS!\n");
744f6baccbcSWojciech Andralojc 			return;
745f6baccbcSWojciech Andralojc 		}
746f6baccbcSWojciech Andralojc 
747f6baccbcSWojciech Andralojc 		printf("PQOS: COS definitions for Socket %u:\n", m_sockets[i]);
748f6baccbcSWojciech Andralojc 		for (n = 0; n < num; n++) {
749f6baccbcSWojciech Andralojc 			if (tab[n].cdp == 1) {
750f6baccbcSWojciech Andralojc 				printf("PQOS: COS: %u, cMASK: 0x%llx, "
751f6baccbcSWojciech Andralojc 					"dMASK: 0x%llx\n", tab[n].class_id,
7527a08b1d8SVladimir Kuramshin #if PQOS_VERSION <= 103
753f6baccbcSWojciech Andralojc 					(unsigned long long)tab[n].code_mask,
754f6baccbcSWojciech Andralojc 					(unsigned long long)tab[n].data_mask);
7557a08b1d8SVladimir Kuramshin #else
7567a08b1d8SVladimir Kuramshin 					(unsigned long long)tab[n].u.s.code_mask,
7577a08b1d8SVladimir Kuramshin 					(unsigned long long)tab[n].u.s.data_mask);
7587a08b1d8SVladimir Kuramshin #endif
759f6baccbcSWojciech Andralojc 			} else {
760f6baccbcSWojciech Andralojc 				printf("PQOS: COS: %u, MASK: 0x%llx\n",
761f6baccbcSWojciech Andralojc 					tab[n].class_id,
7627a08b1d8SVladimir Kuramshin #if PQOS_VERSION <= 103
763f6baccbcSWojciech Andralojc 					(unsigned long long)tab[n].ways_mask);
7647a08b1d8SVladimir Kuramshin #else
7657a08b1d8SVladimir Kuramshin 					(unsigned long long)tab[n].u.ways_mask);
7667a08b1d8SVladimir Kuramshin #endif
767f6baccbcSWojciech Andralojc 			}
768f6baccbcSWojciech Andralojc 		}
769f6baccbcSWojciech Andralojc 	}
770f6baccbcSWojciech Andralojc 
771f6baccbcSWojciech Andralojc 	for (i = 0; i < m_sock_count; i++) {
7727a08b1d8SVladimir Kuramshin #if PQOS_VERSION <= 103
773f6baccbcSWojciech Andralojc 		unsigned lcores[PQOS_MAX_SOCKET_CORES] = {0};
7747a08b1d8SVladimir Kuramshin #else
7757a08b1d8SVladimir Kuramshin 		unsigned int *lcores = NULL;
7767a08b1d8SVladimir Kuramshin #endif
777f6baccbcSWojciech Andralojc 		unsigned lcount = 0;
778f6baccbcSWojciech Andralojc 		unsigned n = 0;
779f6baccbcSWojciech Andralojc 
7807a08b1d8SVladimir Kuramshin #if PQOS_VERSION <= 103
781f6baccbcSWojciech Andralojc 		ret = pqos_cpu_get_cores(m_cpu, m_sockets[i],
782f6baccbcSWojciech Andralojc 				PQOS_MAX_SOCKET_CORES, &lcount, &lcores[0]);
783f6baccbcSWojciech Andralojc 		if (ret != PQOS_RETVAL_OK) {
7847a08b1d8SVladimir Kuramshin #else
7857a08b1d8SVladimir Kuramshin 		lcores = pqos_cpu_get_cores(m_cpu, m_sockets[i],
7867a08b1d8SVladimir Kuramshin 				&lcount);
7877a08b1d8SVladimir Kuramshin 		if (lcores == NULL || lcount == 0) {
7887a08b1d8SVladimir Kuramshin #endif
789f6baccbcSWojciech Andralojc 			printf("PQOS: Error retrieving core information!\n");
790f6baccbcSWojciech Andralojc 			return;
791f6baccbcSWojciech Andralojc 		}
792f6baccbcSWojciech Andralojc 
793f6baccbcSWojciech Andralojc 		printf("PQOS: CPU information for socket %u:\n", m_sockets[i]);
794f6baccbcSWojciech Andralojc 		for (n = 0; n < lcount; n++) {
795f6baccbcSWojciech Andralojc 			unsigned class_id = 0;
796f6baccbcSWojciech Andralojc 
7977a08b1d8SVladimir Kuramshin #if PQOS_VERSION <= 103
798f6baccbcSWojciech Andralojc 			ret = pqos_l3ca_assoc_get(lcores[n], &class_id);
7997a08b1d8SVladimir Kuramshin #else
8007a08b1d8SVladimir Kuramshin 			ret = pqos_alloc_assoc_get(lcores[n], &class_id);
8017a08b1d8SVladimir Kuramshin #endif
802f6baccbcSWojciech Andralojc 			if (ret == PQOS_RETVAL_OK)
803f6baccbcSWojciech Andralojc 				printf("PQOS: CPU: %u, COS: %u\n", lcores[n],
804f6baccbcSWojciech Andralojc 					class_id);
805f6baccbcSWojciech Andralojc 			else
806f6baccbcSWojciech Andralojc 				printf("PQOS: CPU: %u, ERROR\n", lcores[n]);
807f6baccbcSWojciech Andralojc 		}
8087a08b1d8SVladimir Kuramshin 
8097a08b1d8SVladimir Kuramshin #if PQOS_VERSION > 103
8107a08b1d8SVladimir Kuramshin 		free(lcores);
8117a08b1d8SVladimir Kuramshin #endif
812f6baccbcSWojciech Andralojc 	}
813f6baccbcSWojciech Andralojc 
814f6baccbcSWojciech Andralojc }
815f6baccbcSWojciech Andralojc 
816f6baccbcSWojciech Andralojc static int
817f6baccbcSWojciech Andralojc cat_validate(void)
818f6baccbcSWojciech Andralojc {
819f6baccbcSWojciech Andralojc 	int ret = 0;
820f6baccbcSWojciech Andralojc 
821f6baccbcSWojciech Andralojc 	ret = check_cpus();
822f6baccbcSWojciech Andralojc 	if (ret != 0)
823f6baccbcSWojciech Andralojc 		return ret;
824f6baccbcSWojciech Andralojc 
825f6baccbcSWojciech Andralojc 	ret = check_cdp();
826f6baccbcSWojciech Andralojc 	if (ret != 0)
827f6baccbcSWojciech Andralojc 		return ret;
828f6baccbcSWojciech Andralojc 
829f6baccbcSWojciech Andralojc 	ret = check_cbm_len_and_contention();
830f6baccbcSWojciech Andralojc 	if (ret != 0)
831f6baccbcSWojciech Andralojc 		return ret;
832f6baccbcSWojciech Andralojc 
833f6baccbcSWojciech Andralojc 	ret = check_cpus_overlapping();
834f6baccbcSWojciech Andralojc 	if (ret != 0)
835f6baccbcSWojciech Andralojc 		return ret;
836f6baccbcSWojciech Andralojc 
837f6baccbcSWojciech Andralojc 	return 0;
838f6baccbcSWojciech Andralojc }
839f6baccbcSWojciech Andralojc 
840f6baccbcSWojciech Andralojc static int
841f6baccbcSWojciech Andralojc cat_set(void)
842f6baccbcSWojciech Andralojc {
843f6baccbcSWojciech Andralojc 	int ret = 0;
844f6baccbcSWojciech Andralojc 	unsigned cos_id_map[m_config_count][PQOS_MAX_SOCKETS];
845f6baccbcSWojciech Andralojc 
846f6baccbcSWojciech Andralojc 	memset(cos_id_map, 0, sizeof(cos_id_map));
847f6baccbcSWojciech Andralojc 
848f6baccbcSWojciech Andralojc 	ret = check_and_select_classes(cos_id_map);
849f6baccbcSWojciech Andralojc 	if (ret != 0)
850f6baccbcSWojciech Andralojc 		return ret;
851f6baccbcSWojciech Andralojc 
852f6baccbcSWojciech Andralojc 	ret = configure_cat(cos_id_map);
853f6baccbcSWojciech Andralojc 	if (ret != 0)
854f6baccbcSWojciech Andralojc 		return ret;
855f6baccbcSWojciech Andralojc 
856f6baccbcSWojciech Andralojc 	return 0;
857f6baccbcSWojciech Andralojc }
858f6baccbcSWojciech Andralojc 
859f6baccbcSWojciech Andralojc static void
860f6baccbcSWojciech Andralojc cat_fini(void)
861f6baccbcSWojciech Andralojc {
862f6baccbcSWojciech Andralojc 	int ret = 0;
863f6baccbcSWojciech Andralojc 
864f6baccbcSWojciech Andralojc 	printf("PQOS: Shutting down PQoS library...\n");
865f6baccbcSWojciech Andralojc 
866f6baccbcSWojciech Andralojc 	/* deallocate all the resources */
867f6baccbcSWojciech Andralojc 	ret = pqos_fini();
868f6baccbcSWojciech Andralojc 	if (ret != PQOS_RETVAL_OK && ret != PQOS_RETVAL_INIT)
869f6baccbcSWojciech Andralojc 		printf("PQOS: Error shutting down PQoS library!\n");
870f6baccbcSWojciech Andralojc 
871f6baccbcSWojciech Andralojc 	m_cap = NULL;
872f6baccbcSWojciech Andralojc 	m_cpu = NULL;
873f6baccbcSWojciech Andralojc 	m_cap_l3ca = NULL;
8747a08b1d8SVladimir Kuramshin #if PQOS_VERSION <= 103
875f6baccbcSWojciech Andralojc 	memset(m_sockets, 0, sizeof(m_sockets));
8767a08b1d8SVladimir Kuramshin #else
8777a08b1d8SVladimir Kuramshin 	free(m_sockets);
8787a08b1d8SVladimir Kuramshin #endif
879f6baccbcSWojciech Andralojc 	m_sock_count = 0;
880f6baccbcSWojciech Andralojc 	memset(m_config, 0, sizeof(m_config));
881f6baccbcSWojciech Andralojc 	m_config_count = 0;
882f6baccbcSWojciech Andralojc }
883f6baccbcSWojciech Andralojc 
884f6baccbcSWojciech Andralojc void
885f6baccbcSWojciech Andralojc cat_exit(void)
886f6baccbcSWojciech Andralojc {
887f6baccbcSWojciech Andralojc 	unsigned i = 0;
888f6baccbcSWojciech Andralojc 	unsigned j = 0;
889f6baccbcSWojciech Andralojc 	unsigned cpu_id = 0;
890f6baccbcSWojciech Andralojc 	int ret = 0;
891f6baccbcSWojciech Andralojc 
892f6baccbcSWojciech Andralojc 	/* if lib is not initialized, do nothing */
893f6baccbcSWojciech Andralojc 	if (m_cap == NULL && m_cpu == NULL)
894f6baccbcSWojciech Andralojc 		return;
895f6baccbcSWojciech Andralojc 
896f6baccbcSWojciech Andralojc 	printf("PQOS: Reverting CAT configuration...\n");
897f6baccbcSWojciech Andralojc 
898f6baccbcSWojciech Andralojc 	for (i = 0; i < m_config_count; i++) {
899f6baccbcSWojciech Andralojc 		for (j = 0; j < m_cpu->num_cores; j++) {
900f6baccbcSWojciech Andralojc 			cpu_id = m_cpu->cores[j].lcore;
901f6baccbcSWojciech Andralojc 			if (CPU_ISSET(cpu_id, &m_config[i].cpumask) == 0)
902f6baccbcSWojciech Andralojc 				continue;
903f6baccbcSWojciech Andralojc 
9047a08b1d8SVladimir Kuramshin #if PQOS_VERSION <= 103
905f6baccbcSWojciech Andralojc 			ret = pqos_l3ca_assoc_set(cpu_id, 0);
9067a08b1d8SVladimir Kuramshin #else
9077a08b1d8SVladimir Kuramshin 			ret = pqos_alloc_assoc_set(cpu_id, 0);
9087a08b1d8SVladimir Kuramshin #endif
909f6baccbcSWojciech Andralojc 			if (ret != PQOS_RETVAL_OK) {
910f6baccbcSWojciech Andralojc 				printf("PQOS: Failed to associate COS 0 to "
911f6baccbcSWojciech Andralojc 					"cpu %u\n", cpu_id);
912f6baccbcSWojciech Andralojc 			}
913f6baccbcSWojciech Andralojc 		}
914f6baccbcSWojciech Andralojc 	}
915f6baccbcSWojciech Andralojc 
916f6baccbcSWojciech Andralojc 	cat_fini();
917f6baccbcSWojciech Andralojc }
918f6baccbcSWojciech Andralojc 
919f6baccbcSWojciech Andralojc static void
920f6baccbcSWojciech Andralojc signal_handler(int signum)
921f6baccbcSWojciech Andralojc {
922f6baccbcSWojciech Andralojc 	if (signum == SIGINT || signum == SIGTERM) {
923f6baccbcSWojciech Andralojc 		printf("\nPQOS: Signal %d received, preparing to exit...\n",
924f6baccbcSWojciech Andralojc 				signum);
925f6baccbcSWojciech Andralojc 
926f6baccbcSWojciech Andralojc 		cat_exit();
927f6baccbcSWojciech Andralojc 
928f6baccbcSWojciech Andralojc 		/* exit with the expected status */
929f6baccbcSWojciech Andralojc 		signal(signum, SIG_DFL);
930f6baccbcSWojciech Andralojc 		kill(getpid(), signum);
931f6baccbcSWojciech Andralojc 	}
932f6baccbcSWojciech Andralojc }
933f6baccbcSWojciech Andralojc 
934f6baccbcSWojciech Andralojc int
935f6baccbcSWojciech Andralojc cat_init(int argc, char **argv)
936f6baccbcSWojciech Andralojc {
937f6baccbcSWojciech Andralojc 	int ret = 0;
938f6baccbcSWojciech Andralojc 	int args_num = 0;
939f6baccbcSWojciech Andralojc 	struct pqos_config cfg = {0};
940f6baccbcSWojciech Andralojc 
941f6baccbcSWojciech Andralojc 	if (m_cap != NULL || m_cpu != NULL) {
942f6baccbcSWojciech Andralojc 		printf("PQOS: CAT module already initialized!\n");
943f6baccbcSWojciech Andralojc 		return -EEXIST;
944f6baccbcSWojciech Andralojc 	}
945f6baccbcSWojciech Andralojc 
946f6baccbcSWojciech Andralojc 	/* Parse cmd line args */
947f6baccbcSWojciech Andralojc 	ret = parse_args(argc, argv);
948f6baccbcSWojciech Andralojc 
949f6baccbcSWojciech Andralojc 	if (ret <= 0)
950f6baccbcSWojciech Andralojc 		goto err;
951f6baccbcSWojciech Andralojc 
952f6baccbcSWojciech Andralojc 	args_num = ret;
953f6baccbcSWojciech Andralojc 
954f6baccbcSWojciech Andralojc 	/* Print cmd line configuration */
955f6baccbcSWojciech Andralojc 	print_cmd_line_config();
956f6baccbcSWojciech Andralojc 
957f6baccbcSWojciech Andralojc 	/* PQoS Initialization - Check and initialize CAT capability */
958f6baccbcSWojciech Andralojc 	cfg.fd_log = STDOUT_FILENO;
959f6baccbcSWojciech Andralojc 	cfg.verbose = 0;
9607a08b1d8SVladimir Kuramshin #if PQOS_VERSION <= 103
961f6baccbcSWojciech Andralojc 	cfg.cdp_cfg = PQOS_REQUIRE_CDP_ANY;
9627a08b1d8SVladimir Kuramshin #endif
963f6baccbcSWojciech Andralojc 	ret = pqos_init(&cfg);
964f6baccbcSWojciech Andralojc 	if (ret != PQOS_RETVAL_OK) {
965f6baccbcSWojciech Andralojc 		printf("PQOS: Error initializing PQoS library!\n");
966f6baccbcSWojciech Andralojc 		ret = -EFAULT;
967f6baccbcSWojciech Andralojc 		goto err;
968f6baccbcSWojciech Andralojc 	}
969f6baccbcSWojciech Andralojc 
970f6baccbcSWojciech Andralojc 	/* Get capability and CPU info pointer */
971f6baccbcSWojciech Andralojc 	ret = pqos_cap_get(&m_cap, &m_cpu);
972f6baccbcSWojciech Andralojc 	if (ret != PQOS_RETVAL_OK || m_cap == NULL || m_cpu == NULL) {
973f6baccbcSWojciech Andralojc 		printf("PQOS: Error retrieving PQoS capabilities!\n");
974f6baccbcSWojciech Andralojc 		ret = -EFAULT;
975f6baccbcSWojciech Andralojc 		goto err;
976f6baccbcSWojciech Andralojc 	}
977f6baccbcSWojciech Andralojc 
978f6baccbcSWojciech Andralojc 	/* Get L3CA capabilities */
979f6baccbcSWojciech Andralojc 	ret = pqos_cap_get_type(m_cap, PQOS_CAP_TYPE_L3CA, &m_cap_l3ca);
980f6baccbcSWojciech Andralojc 	if (ret != PQOS_RETVAL_OK || m_cap_l3ca == NULL) {
981f6baccbcSWojciech Andralojc 		printf("PQOS: Error retrieving PQOS_CAP_TYPE_L3CA "
982f6baccbcSWojciech Andralojc 			"capabilities!\n");
983f6baccbcSWojciech Andralojc 		ret = -EFAULT;
984f6baccbcSWojciech Andralojc 		goto err;
985f6baccbcSWojciech Andralojc 	}
986f6baccbcSWojciech Andralojc 
987f6baccbcSWojciech Andralojc 	/* Get CPU socket information */
9887a08b1d8SVladimir Kuramshin #if PQOS_VERSION <= 103
989f6baccbcSWojciech Andralojc 	ret = pqos_cpu_get_sockets(m_cpu, PQOS_MAX_SOCKETS, &m_sock_count,
990f6baccbcSWojciech Andralojc 		m_sockets);
991f6baccbcSWojciech Andralojc 	if (ret != PQOS_RETVAL_OK) {
9927a08b1d8SVladimir Kuramshin #else
9937a08b1d8SVladimir Kuramshin 	m_sockets = pqos_cpu_get_sockets(m_cpu, &m_sock_count);
9947a08b1d8SVladimir Kuramshin 	if (m_sockets == NULL) {
9957a08b1d8SVladimir Kuramshin #endif
996f6baccbcSWojciech Andralojc 		printf("PQOS: Error retrieving CPU socket information!\n");
997f6baccbcSWojciech Andralojc 		ret = -EFAULT;
998f6baccbcSWojciech Andralojc 		goto err;
999f6baccbcSWojciech Andralojc 	}
1000f6baccbcSWojciech Andralojc 
1001f6baccbcSWojciech Andralojc 	/* Validate cmd line configuration */
1002f6baccbcSWojciech Andralojc 	ret = cat_validate();
1003f6baccbcSWojciech Andralojc 	if (ret != 0) {
1004f6baccbcSWojciech Andralojc 		printf("PQOS: Requested CAT configuration is not valid!\n");
1005f6baccbcSWojciech Andralojc 		goto err;
1006f6baccbcSWojciech Andralojc 	}
1007f6baccbcSWojciech Andralojc 
1008f6baccbcSWojciech Andralojc 	/* configure system */
1009f6baccbcSWojciech Andralojc 	ret = cat_set();
1010f6baccbcSWojciech Andralojc 	if (ret != 0) {
1011f6baccbcSWojciech Andralojc 		printf("PQOS: Failed to configure CAT!\n");
1012f6baccbcSWojciech Andralojc 		goto err;
1013f6baccbcSWojciech Andralojc 	}
1014f6baccbcSWojciech Andralojc 
1015f6baccbcSWojciech Andralojc 	signal(SIGINT, signal_handler);
1016f6baccbcSWojciech Andralojc 	signal(SIGTERM, signal_handler);
1017f6baccbcSWojciech Andralojc 
1018f6baccbcSWojciech Andralojc 	ret = atexit(cat_exit);
1019f6baccbcSWojciech Andralojc 	if (ret != 0) {
1020f6baccbcSWojciech Andralojc 		printf("PQOS: Cannot set exit function\n");
1021f6baccbcSWojciech Andralojc 		goto err;
1022f6baccbcSWojciech Andralojc 	}
1023f6baccbcSWojciech Andralojc 
1024f6baccbcSWojciech Andralojc 	/* Print CAT configuration */
1025f6baccbcSWojciech Andralojc 	print_cat_config();
1026f6baccbcSWojciech Andralojc 
1027f6baccbcSWojciech Andralojc 	return args_num;
1028f6baccbcSWojciech Andralojc 
1029f6baccbcSWojciech Andralojc err:
1030f6baccbcSWojciech Andralojc 	/* deallocate all the resources */
1031f6baccbcSWojciech Andralojc 	cat_fini();
1032f6baccbcSWojciech Andralojc 	return ret;
1033f6baccbcSWojciech Andralojc }
1034