1488570ebSJim Harris /* SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse * Copyright (C) 2017 Intel Corporation. All rights reserved.
3601bcbcfSTomasz Kulasek * All rights reserved.
4601bcbcfSTomasz Kulasek */
5601bcbcfSTomasz Kulasek
6601bcbcfSTomasz Kulasek #include "spdk/cpuset.h"
7601bcbcfSTomasz Kulasek #include "spdk/log.h"
8601bcbcfSTomasz Kulasek
9601bcbcfSTomasz Kulasek struct spdk_cpuset *
spdk_cpuset_alloc(void)10601bcbcfSTomasz Kulasek spdk_cpuset_alloc(void)
11601bcbcfSTomasz Kulasek {
12746549cfSCody Cheng return (struct spdk_cpuset *)calloc(1, sizeof(struct spdk_cpuset));
13601bcbcfSTomasz Kulasek }
14601bcbcfSTomasz Kulasek
15601bcbcfSTomasz Kulasek void
spdk_cpuset_free(struct spdk_cpuset * set)16601bcbcfSTomasz Kulasek spdk_cpuset_free(struct spdk_cpuset *set)
17601bcbcfSTomasz Kulasek {
18601bcbcfSTomasz Kulasek free(set);
19601bcbcfSTomasz Kulasek }
20601bcbcfSTomasz Kulasek
21601bcbcfSTomasz Kulasek bool
spdk_cpuset_equal(const struct spdk_cpuset * set1,const struct spdk_cpuset * set2)22601bcbcfSTomasz Kulasek spdk_cpuset_equal(const struct spdk_cpuset *set1, const struct spdk_cpuset *set2)
23601bcbcfSTomasz Kulasek {
24601bcbcfSTomasz Kulasek assert(set1 != NULL);
25601bcbcfSTomasz Kulasek assert(set2 != NULL);
26601bcbcfSTomasz Kulasek return memcmp(set1->cpus, set2->cpus, sizeof(set2->cpus)) == 0;
27601bcbcfSTomasz Kulasek }
28601bcbcfSTomasz Kulasek
29601bcbcfSTomasz Kulasek void
spdk_cpuset_copy(struct spdk_cpuset * dst,const struct spdk_cpuset * src)3060d48787SDarek Stojaczyk spdk_cpuset_copy(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
31601bcbcfSTomasz Kulasek {
3260d48787SDarek Stojaczyk assert(dst != NULL);
3360d48787SDarek Stojaczyk assert(src != NULL);
3460d48787SDarek Stojaczyk memcpy(&dst->cpus, &src->cpus, sizeof(src->cpus));
35601bcbcfSTomasz Kulasek }
36601bcbcfSTomasz Kulasek
37601bcbcfSTomasz Kulasek void
spdk_cpuset_negate(struct spdk_cpuset * set)38ebce385dSTomasz Kulasek spdk_cpuset_negate(struct spdk_cpuset *set)
39ebce385dSTomasz Kulasek {
40ebce385dSTomasz Kulasek unsigned int i;
41ebce385dSTomasz Kulasek assert(set != NULL);
42ebce385dSTomasz Kulasek for (i = 0; i < sizeof(set->cpus); i++) {
43ebce385dSTomasz Kulasek set->cpus[i] = ~set->cpus[i];
44ebce385dSTomasz Kulasek }
45ebce385dSTomasz Kulasek }
46ebce385dSTomasz Kulasek
47ebce385dSTomasz Kulasek void
spdk_cpuset_and(struct spdk_cpuset * dst,const struct spdk_cpuset * src)4860d48787SDarek Stojaczyk spdk_cpuset_and(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
49601bcbcfSTomasz Kulasek {
50601bcbcfSTomasz Kulasek unsigned int i;
5160d48787SDarek Stojaczyk assert(dst != NULL);
5260d48787SDarek Stojaczyk assert(src != NULL);
5360d48787SDarek Stojaczyk for (i = 0; i < sizeof(src->cpus); i++) {
5460d48787SDarek Stojaczyk dst->cpus[i] &= src->cpus[i];
55601bcbcfSTomasz Kulasek }
56601bcbcfSTomasz Kulasek }
57601bcbcfSTomasz Kulasek
58601bcbcfSTomasz Kulasek void
spdk_cpuset_or(struct spdk_cpuset * dst,const struct spdk_cpuset * src)5960d48787SDarek Stojaczyk spdk_cpuset_or(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
60601bcbcfSTomasz Kulasek {
61601bcbcfSTomasz Kulasek unsigned int i;
6260d48787SDarek Stojaczyk assert(dst != NULL);
6360d48787SDarek Stojaczyk assert(src != NULL);
6460d48787SDarek Stojaczyk for (i = 0; i < sizeof(src->cpus); i++) {
6560d48787SDarek Stojaczyk dst->cpus[i] |= src->cpus[i];
66601bcbcfSTomasz Kulasek }
67601bcbcfSTomasz Kulasek }
68601bcbcfSTomasz Kulasek
69601bcbcfSTomasz Kulasek void
spdk_cpuset_xor(struct spdk_cpuset * dst,const struct spdk_cpuset * src)7060d48787SDarek Stojaczyk spdk_cpuset_xor(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
71ebce385dSTomasz Kulasek {
72ebce385dSTomasz Kulasek unsigned int i;
7360d48787SDarek Stojaczyk assert(dst != NULL);
7460d48787SDarek Stojaczyk assert(src != NULL);
7560d48787SDarek Stojaczyk for (i = 0; i < sizeof(src->cpus); i++) {
7660d48787SDarek Stojaczyk dst->cpus[i] ^= src->cpus[i];
77ebce385dSTomasz Kulasek }
78ebce385dSTomasz Kulasek }
79ebce385dSTomasz Kulasek
80ebce385dSTomasz Kulasek void
spdk_cpuset_zero(struct spdk_cpuset * set)81601bcbcfSTomasz Kulasek spdk_cpuset_zero(struct spdk_cpuset *set)
82601bcbcfSTomasz Kulasek {
83601bcbcfSTomasz Kulasek assert(set != NULL);
84601bcbcfSTomasz Kulasek memset(set->cpus, 0, sizeof(set->cpus));
85601bcbcfSTomasz Kulasek }
86601bcbcfSTomasz Kulasek
87601bcbcfSTomasz Kulasek void
spdk_cpuset_set_cpu(struct spdk_cpuset * set,uint32_t cpu,bool state)88601bcbcfSTomasz Kulasek spdk_cpuset_set_cpu(struct spdk_cpuset *set, uint32_t cpu, bool state)
89601bcbcfSTomasz Kulasek {
90601bcbcfSTomasz Kulasek assert(set != NULL);
91601bcbcfSTomasz Kulasek assert(cpu < sizeof(set->cpus) * 8);
92601bcbcfSTomasz Kulasek if (state) {
93601bcbcfSTomasz Kulasek set->cpus[cpu / 8] |= (1U << (cpu % 8));
94601bcbcfSTomasz Kulasek } else {
95601bcbcfSTomasz Kulasek set->cpus[cpu / 8] &= ~(1U << (cpu % 8));
96601bcbcfSTomasz Kulasek }
97601bcbcfSTomasz Kulasek }
98601bcbcfSTomasz Kulasek
99601bcbcfSTomasz Kulasek bool
spdk_cpuset_get_cpu(const struct spdk_cpuset * set,uint32_t cpu)100601bcbcfSTomasz Kulasek spdk_cpuset_get_cpu(const struct spdk_cpuset *set, uint32_t cpu)
101601bcbcfSTomasz Kulasek {
102601bcbcfSTomasz Kulasek assert(set != NULL);
103601bcbcfSTomasz Kulasek assert(cpu < sizeof(set->cpus) * 8);
104601bcbcfSTomasz Kulasek return (set->cpus[cpu / 8] >> (cpu % 8)) & 1U;
105601bcbcfSTomasz Kulasek }
106601bcbcfSTomasz Kulasek
107*cdeecfb8SJim Harris void
spdk_cpuset_for_each_cpu(const struct spdk_cpuset * set,void (* fn)(void * ctx,uint32_t cpu),void * ctx)108*cdeecfb8SJim Harris spdk_cpuset_for_each_cpu(const struct spdk_cpuset *set,
109*cdeecfb8SJim Harris void (*fn)(void *ctx, uint32_t cpu), void *ctx)
110601bcbcfSTomasz Kulasek {
111601bcbcfSTomasz Kulasek uint8_t n;
112b1923f4dSJim Harris unsigned int i, j;
113601bcbcfSTomasz Kulasek for (i = 0; i < sizeof(set->cpus); i++) {
114601bcbcfSTomasz Kulasek n = set->cpus[i];
115b1923f4dSJim Harris for (j = 0; j < 8; j++) {
116b1923f4dSJim Harris if (n & (1 << j)) {
117*cdeecfb8SJim Harris fn(ctx, i * 8 + j);
118601bcbcfSTomasz Kulasek }
119601bcbcfSTomasz Kulasek }
120b1923f4dSJim Harris }
121*cdeecfb8SJim Harris }
122*cdeecfb8SJim Harris
123*cdeecfb8SJim Harris static void
count_fn(void * ctx,uint32_t cpu)124*cdeecfb8SJim Harris count_fn(void *ctx, uint32_t cpu)
125*cdeecfb8SJim Harris {
126*cdeecfb8SJim Harris uint32_t *count = ctx;
127*cdeecfb8SJim Harris
128*cdeecfb8SJim Harris (*count)++;
129*cdeecfb8SJim Harris }
130*cdeecfb8SJim Harris
131*cdeecfb8SJim Harris uint32_t
spdk_cpuset_count(const struct spdk_cpuset * set)132*cdeecfb8SJim Harris spdk_cpuset_count(const struct spdk_cpuset *set)
133*cdeecfb8SJim Harris {
134*cdeecfb8SJim Harris uint32_t count = 0;
135*cdeecfb8SJim Harris
136*cdeecfb8SJim Harris spdk_cpuset_for_each_cpu(set, count_fn, &count);
137601bcbcfSTomasz Kulasek return count;
138601bcbcfSTomasz Kulasek }
139601bcbcfSTomasz Kulasek
140e7285749SPawel Wodkowski const char *
spdk_cpuset_fmt(struct spdk_cpuset * set)141601bcbcfSTomasz Kulasek spdk_cpuset_fmt(struct spdk_cpuset *set)
142601bcbcfSTomasz Kulasek {
143601bcbcfSTomasz Kulasek uint32_t lcore, lcore_max = 0;
144601bcbcfSTomasz Kulasek int val, i, n;
145601bcbcfSTomasz Kulasek char *ptr;
146601bcbcfSTomasz Kulasek static const char *hex = "0123456789abcdef";
147601bcbcfSTomasz Kulasek
148601bcbcfSTomasz Kulasek assert(set != NULL);
149601bcbcfSTomasz Kulasek
150601bcbcfSTomasz Kulasek for (lcore = 0; lcore < sizeof(set->cpus) * 8; lcore++) {
151601bcbcfSTomasz Kulasek if (spdk_cpuset_get_cpu(set, lcore)) {
152601bcbcfSTomasz Kulasek lcore_max = lcore;
153601bcbcfSTomasz Kulasek }
154601bcbcfSTomasz Kulasek }
155601bcbcfSTomasz Kulasek
156601bcbcfSTomasz Kulasek ptr = set->str;
157601bcbcfSTomasz Kulasek n = lcore_max / 8;
158601bcbcfSTomasz Kulasek val = set->cpus[n];
159601bcbcfSTomasz Kulasek
160601bcbcfSTomasz Kulasek /* Store first number only if it is not leading zero */
161601bcbcfSTomasz Kulasek if ((val & 0xf0) != 0) {
162601bcbcfSTomasz Kulasek *(ptr++) = hex[(val & 0xf0) >> 4];
163601bcbcfSTomasz Kulasek }
164601bcbcfSTomasz Kulasek *(ptr++) = hex[val & 0x0f];
165601bcbcfSTomasz Kulasek
166601bcbcfSTomasz Kulasek for (i = n - 1; i >= 0; i--) {
167601bcbcfSTomasz Kulasek val = set->cpus[i];
168601bcbcfSTomasz Kulasek *(ptr++) = hex[(val & 0xf0) >> 4];
169601bcbcfSTomasz Kulasek *(ptr++) = hex[val & 0x0f];
170601bcbcfSTomasz Kulasek }
171601bcbcfSTomasz Kulasek *ptr = '\0';
172601bcbcfSTomasz Kulasek
173601bcbcfSTomasz Kulasek return set->str;
174601bcbcfSTomasz Kulasek }
175601bcbcfSTomasz Kulasek
176601bcbcfSTomasz Kulasek static int
hex_value(uint8_t c)177601bcbcfSTomasz Kulasek hex_value(uint8_t c)
178601bcbcfSTomasz Kulasek {
179601bcbcfSTomasz Kulasek #define V(x, y) [x] = y + 1
180601bcbcfSTomasz Kulasek static const int8_t val[256] = {
181601bcbcfSTomasz Kulasek V('0', 0), V('1', 1), V('2', 2), V('3', 3), V('4', 4),
182601bcbcfSTomasz Kulasek V('5', 5), V('6', 6), V('7', 7), V('8', 8), V('9', 9),
183601bcbcfSTomasz Kulasek V('A', 0xA), V('B', 0xB), V('C', 0xC), V('D', 0xD), V('E', 0xE), V('F', 0xF),
184601bcbcfSTomasz Kulasek V('a', 0xA), V('b', 0xB), V('c', 0xC), V('d', 0xD), V('e', 0xE), V('f', 0xF),
185601bcbcfSTomasz Kulasek };
186601bcbcfSTomasz Kulasek #undef V
187601bcbcfSTomasz Kulasek
188601bcbcfSTomasz Kulasek return val[c] - 1;
189601bcbcfSTomasz Kulasek }
190601bcbcfSTomasz Kulasek
191601bcbcfSTomasz Kulasek static int
parse_list(const char * mask,struct spdk_cpuset * set)192601bcbcfSTomasz Kulasek parse_list(const char *mask, struct spdk_cpuset *set)
193601bcbcfSTomasz Kulasek {
194601bcbcfSTomasz Kulasek char *end;
195601bcbcfSTomasz Kulasek const char *ptr = mask;
196601bcbcfSTomasz Kulasek uint32_t lcore;
197601bcbcfSTomasz Kulasek uint32_t lcore_min, lcore_max;
198601bcbcfSTomasz Kulasek
199601bcbcfSTomasz Kulasek spdk_cpuset_zero(set);
200601bcbcfSTomasz Kulasek lcore_min = UINT32_MAX;
201601bcbcfSTomasz Kulasek
202601bcbcfSTomasz Kulasek ptr++;
203601bcbcfSTomasz Kulasek end = (char *)ptr;
204601bcbcfSTomasz Kulasek do {
205601bcbcfSTomasz Kulasek while (isblank(*ptr)) {
206601bcbcfSTomasz Kulasek ptr++;
207601bcbcfSTomasz Kulasek }
208601bcbcfSTomasz Kulasek if (*ptr == '\0' || *ptr == ']' || *ptr == '-' || *ptr == ',') {
209601bcbcfSTomasz Kulasek goto invalid_character;
210601bcbcfSTomasz Kulasek }
211601bcbcfSTomasz Kulasek
212601bcbcfSTomasz Kulasek errno = 0;
213601bcbcfSTomasz Kulasek lcore = strtoul(ptr, &end, 10);
214601bcbcfSTomasz Kulasek if (errno) {
215601bcbcfSTomasz Kulasek SPDK_ERRLOG("Conversion of core mask in '%s' failed\n", mask);
216601bcbcfSTomasz Kulasek return -1;
217601bcbcfSTomasz Kulasek }
218601bcbcfSTomasz Kulasek
219601bcbcfSTomasz Kulasek if (lcore >= sizeof(set->cpus) * 8) {
220601bcbcfSTomasz Kulasek SPDK_ERRLOG("Core number %" PRIu32 " is out of range in '%s'\n", lcore, mask);
221601bcbcfSTomasz Kulasek return -1;
222601bcbcfSTomasz Kulasek }
223601bcbcfSTomasz Kulasek
224601bcbcfSTomasz Kulasek while (isblank(*end)) {
225601bcbcfSTomasz Kulasek end++;
226601bcbcfSTomasz Kulasek }
227601bcbcfSTomasz Kulasek
228601bcbcfSTomasz Kulasek if (*end == '-') {
229601bcbcfSTomasz Kulasek lcore_min = lcore;
230601bcbcfSTomasz Kulasek } else if (*end == ',' || *end == ']') {
231601bcbcfSTomasz Kulasek lcore_max = lcore;
232601bcbcfSTomasz Kulasek if (lcore_min == UINT32_MAX) {
233601bcbcfSTomasz Kulasek lcore_min = lcore;
234601bcbcfSTomasz Kulasek }
235601bcbcfSTomasz Kulasek if (lcore_min > lcore_max) {
236601bcbcfSTomasz Kulasek SPDK_ERRLOG("Invalid range of CPUs (%" PRIu32 " > %" PRIu32 ")\n",
237601bcbcfSTomasz Kulasek lcore_min, lcore_max);
238601bcbcfSTomasz Kulasek return -1;
239601bcbcfSTomasz Kulasek }
240601bcbcfSTomasz Kulasek for (lcore = lcore_min; lcore <= lcore_max; lcore++) {
241601bcbcfSTomasz Kulasek spdk_cpuset_set_cpu(set, lcore, true);
242601bcbcfSTomasz Kulasek }
243601bcbcfSTomasz Kulasek lcore_min = UINT32_MAX;
244601bcbcfSTomasz Kulasek } else {
245601bcbcfSTomasz Kulasek goto invalid_character;
246601bcbcfSTomasz Kulasek }
247601bcbcfSTomasz Kulasek
248601bcbcfSTomasz Kulasek ptr = end + 1;
249601bcbcfSTomasz Kulasek
250601bcbcfSTomasz Kulasek } while (*end != ']');
251601bcbcfSTomasz Kulasek
252601bcbcfSTomasz Kulasek return 0;
253601bcbcfSTomasz Kulasek
254601bcbcfSTomasz Kulasek invalid_character:
255601bcbcfSTomasz Kulasek if (*end == '\0') {
256601bcbcfSTomasz Kulasek SPDK_ERRLOG("Unexpected end of core list '%s'\n", mask);
257601bcbcfSTomasz Kulasek } else {
258601bcbcfSTomasz Kulasek SPDK_ERRLOG("Parsing of core list '%s' failed on character '%c'\n", mask, *end);
259601bcbcfSTomasz Kulasek }
260601bcbcfSTomasz Kulasek return -1;
261601bcbcfSTomasz Kulasek }
262601bcbcfSTomasz Kulasek
263601bcbcfSTomasz Kulasek static int
parse_mask(const char * mask,struct spdk_cpuset * set,size_t len)264601bcbcfSTomasz Kulasek parse_mask(const char *mask, struct spdk_cpuset *set, size_t len)
265601bcbcfSTomasz Kulasek {
266601bcbcfSTomasz Kulasek int i, j;
267601bcbcfSTomasz Kulasek char c;
268601bcbcfSTomasz Kulasek int val;
269601bcbcfSTomasz Kulasek uint32_t lcore = 0;
270601bcbcfSTomasz Kulasek
271601bcbcfSTomasz Kulasek if (mask[0] == '0' && (mask[1] == 'x' || mask[1] == 'X')) {
272601bcbcfSTomasz Kulasek mask += 2;
273601bcbcfSTomasz Kulasek len -= 2;
274601bcbcfSTomasz Kulasek }
275601bcbcfSTomasz Kulasek
276601bcbcfSTomasz Kulasek spdk_cpuset_zero(set);
277601bcbcfSTomasz Kulasek for (i = len - 1; i >= 0; i--) {
278601bcbcfSTomasz Kulasek c = mask[i];
279a44a9620SJim Harris if (c == ',') {
280a44a9620SJim Harris /* Linux puts comma delimiters in its cpumasks, just skip them. */
281a44a9620SJim Harris continue;
282a44a9620SJim Harris }
283601bcbcfSTomasz Kulasek val = hex_value(c);
284601bcbcfSTomasz Kulasek if (val < 0) {
285601bcbcfSTomasz Kulasek /* Invalid character */
286601bcbcfSTomasz Kulasek SPDK_ERRLOG("Invalid character in core mask '%s' (%c)\n", mask, c);
287601bcbcfSTomasz Kulasek return -1;
288601bcbcfSTomasz Kulasek }
289150339ccSJim Harris for (j = 0; j < 4 && lcore < SPDK_CPUSET_SIZE; j++, lcore++) {
290601bcbcfSTomasz Kulasek if ((1 << j) & val) {
291601bcbcfSTomasz Kulasek spdk_cpuset_set_cpu(set, lcore, true);
292601bcbcfSTomasz Kulasek }
293601bcbcfSTomasz Kulasek }
294601bcbcfSTomasz Kulasek }
295601bcbcfSTomasz Kulasek
296601bcbcfSTomasz Kulasek return 0;
297601bcbcfSTomasz Kulasek }
298601bcbcfSTomasz Kulasek
299601bcbcfSTomasz Kulasek int
spdk_cpuset_parse(struct spdk_cpuset * set,const char * mask)300601bcbcfSTomasz Kulasek spdk_cpuset_parse(struct spdk_cpuset *set, const char *mask)
301601bcbcfSTomasz Kulasek {
302601bcbcfSTomasz Kulasek int ret;
303601bcbcfSTomasz Kulasek size_t len;
304601bcbcfSTomasz Kulasek
305601bcbcfSTomasz Kulasek if (mask == NULL || set == NULL) {
306601bcbcfSTomasz Kulasek return -1;
307601bcbcfSTomasz Kulasek }
308601bcbcfSTomasz Kulasek
309601bcbcfSTomasz Kulasek while (isblank(*mask)) {
310601bcbcfSTomasz Kulasek mask++;
311601bcbcfSTomasz Kulasek }
312601bcbcfSTomasz Kulasek
313601bcbcfSTomasz Kulasek len = strlen(mask);
314601bcbcfSTomasz Kulasek while (len > 0 && isblank(mask[len - 1])) {
315601bcbcfSTomasz Kulasek len--;
316601bcbcfSTomasz Kulasek }
317601bcbcfSTomasz Kulasek
318601bcbcfSTomasz Kulasek if (len == 0) {
319601bcbcfSTomasz Kulasek return -1;
320601bcbcfSTomasz Kulasek }
321601bcbcfSTomasz Kulasek
322601bcbcfSTomasz Kulasek if (mask[0] == '[') {
323601bcbcfSTomasz Kulasek ret = parse_list(mask, set);
324601bcbcfSTomasz Kulasek } else {
325601bcbcfSTomasz Kulasek ret = parse_mask(mask, set, len);
326601bcbcfSTomasz Kulasek }
327601bcbcfSTomasz Kulasek
328601bcbcfSTomasz Kulasek return ret;
329601bcbcfSTomasz Kulasek }
330