subr_kcpuset.c revision 1.19 1 /* $NetBSD: subr_kcpuset.c,v 1.19 2023/09/12 16:17:21 ad Exp $ */
2
3 /*-
4 * Copyright (c) 2011 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Mindaugas Rasiukevicius.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * Kernel CPU set implementation.
34 *
35 * Interface can be used by kernel subsystems as a unified dynamic CPU
36 * bitset implementation handling many CPUs. Facility also supports early
37 * use by MD code on boot, as it fixups bitsets on further boot.
38 *
39 * TODO:
40 * - Handle "reverse" bitset on fixup/grow.
41 */
42
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: subr_kcpuset.c,v 1.19 2023/09/12 16:17:21 ad Exp $");
45
46 #include <sys/param.h>
47 #include <sys/types.h>
48
49 #include <sys/atomic.h>
50 #include <sys/intr.h>
51 #include <sys/sched.h>
52 #include <sys/kcpuset.h>
53 #include <sys/pool.h>
54
55 /* Number of CPUs to support. */
56 #define KC_MAXCPUS roundup2(MAXCPUS, 32)
57
58 /*
59 * Structure of dynamic CPU set in the kernel.
60 */
61 struct kcpuset {
62 uint32_t bits[0];
63 };
64
65 typedef struct kcpuset_impl {
66 /* Reference count. */
67 u_int kc_refcnt;
68 /* Next to free, if non-NULL (used when multiple references). */
69 struct kcpuset * kc_next;
70 /* Actual variable-sized field of bits. */
71 struct kcpuset kc_field;
72 } kcpuset_impl_t;
73
74 #define KC_BITS_OFF (offsetof(struct kcpuset_impl, kc_field))
75 #define KC_GETSTRUCT(b) ((kcpuset_impl_t *)((char *)(b) - KC_BITS_OFF))
76 #define KC_GETCSTRUCT(b) ((const kcpuset_impl_t *)((const char *)(b) - KC_BITS_OFF))
77
78 /* Sizes of a single bitset. */
79 #define KC_SHIFT 5
80 #define KC_MASK 31
81
82 /* An array of noted early kcpuset creations and data. */
83 #define KC_SAVE_NITEMS 8
84
85 /* Structures for early boot mechanism (must be statically initialised). */
86 static kcpuset_t ** kc_noted_early[KC_SAVE_NITEMS];
87 static uint32_t kc_bits_early[KC_SAVE_NITEMS];
88 static int kc_last_idx = 0;
89 static bool kc_initialised = false;
90
91 #define KC_BITSIZE_EARLY sizeof(kc_bits_early[0])
92 #define KC_NFIELDS_EARLY 1
93
94 /*
95 * The size of whole bitset fields and amount of fields.
96 * The whole size must statically initialise for early case.
97 */
98 static size_t kc_bitsize __read_mostly = KC_BITSIZE_EARLY;
99 static size_t kc_nfields __read_mostly = KC_NFIELDS_EARLY;
100
101 static pool_cache_t kc_cache __read_mostly;
102
103 static kcpuset_t * kcpuset_create_raw(bool);
104
105 /*
106 * kcpuset_sysinit: initialize the subsystem, transfer early boot cases
107 * to dynamically allocated sets.
108 */
109 void
110 kcpuset_sysinit(void)
111 {
112 kcpuset_t *kc_dynamic[KC_SAVE_NITEMS], *kcp;
113 int i, s;
114
115 /* Set a kcpuset_t sizes. */
116 kc_nfields = (KC_MAXCPUS >> KC_SHIFT);
117 kc_bitsize = sizeof(uint32_t) * kc_nfields;
118 KASSERT(kc_nfields != 0);
119 KASSERT(kc_bitsize != 0);
120
121 kc_cache = pool_cache_init(sizeof(kcpuset_impl_t) + kc_bitsize,
122 coherency_unit, 0, 0, "kcpuset", NULL, IPL_NONE, NULL, NULL, NULL);
123
124 /* First, pre-allocate kcpuset entries. */
125 for (i = 0; i < kc_last_idx; i++) {
126 kcp = kcpuset_create_raw(true);
127 kc_dynamic[i] = kcp;
128 }
129
130 /*
131 * Prepare to convert all early noted kcpuset uses to dynamic sets.
132 * All processors, except the one we are currently running (primary),
133 * must not be spinned yet. Since MD facilities can use kcpuset,
134 * raise the IPL to high.
135 */
136 KASSERT(mp_online == false);
137
138 s = splhigh();
139 for (i = 0; i < kc_last_idx; i++) {
140 /*
141 * Transfer the bits from early static storage to the kcpuset.
142 */
143 KASSERT(kc_bitsize >= KC_BITSIZE_EARLY);
144 memcpy(kc_dynamic[i], &kc_bits_early[i], KC_BITSIZE_EARLY);
145
146 /*
147 * Store the new pointer, pointing to the allocated kcpuset.
148 * Note: we are not in an interrupt context and it is the only
149 * CPU running - thus store is safe (e.g. no need for pointer
150 * variable to be volatile).
151 */
152 *kc_noted_early[i] = kc_dynamic[i];
153 }
154 kc_initialised = true;
155 kc_last_idx = 0;
156 splx(s);
157 }
158
159 /*
160 * kcpuset_early_ptr: note an early boot use by saving the pointer and
161 * returning a pointer to a static, temporary bit field.
162 */
163 static kcpuset_t *
164 kcpuset_early_ptr(kcpuset_t **kcptr)
165 {
166 kcpuset_t *kcp;
167 int s;
168
169 s = splhigh();
170 if (kc_last_idx < KC_SAVE_NITEMS) {
171 /*
172 * Save the pointer, return pointer to static early field.
173 * Need to zero it out.
174 */
175 kc_noted_early[kc_last_idx] = kcptr;
176 kcp = (kcpuset_t *)&kc_bits_early[kc_last_idx];
177 kc_last_idx++;
178 memset(kcp, 0, KC_BITSIZE_EARLY);
179 KASSERT(kc_bitsize == KC_BITSIZE_EARLY);
180 } else {
181 panic("kcpuset(9): all early-use entries exhausted; "
182 "increase KC_SAVE_NITEMS\n");
183 }
184 splx(s);
185
186 return kcp;
187 }
188
189 /*
190 * Routines to create or destroy the CPU set.
191 * Early boot case is handled.
192 */
193
194 static kcpuset_t *
195 kcpuset_create_raw(bool zero)
196 {
197 kcpuset_impl_t *kc;
198
199 kc = pool_cache_get(kc_cache, PR_WAITOK);
200 kc->kc_refcnt = 1;
201 kc->kc_next = NULL;
202
203 if (zero) {
204 memset(&kc->kc_field, 0, kc_bitsize);
205 }
206
207 /* Note: return pointer to the actual field of bits. */
208 KASSERT((uint8_t *)kc + KC_BITS_OFF == (uint8_t *)&kc->kc_field);
209 return &kc->kc_field;
210 }
211
212 void
213 kcpuset_create(kcpuset_t **retkcp, bool zero)
214 {
215 if (__predict_false(!kc_initialised)) {
216 /* Early boot use - special case. */
217 *retkcp = kcpuset_early_ptr(retkcp);
218 return;
219 }
220 *retkcp = kcpuset_create_raw(zero);
221 }
222
223 void
224 kcpuset_clone(kcpuset_t **retkcp, const kcpuset_t *kcp)
225 {
226 kcpuset_create(retkcp, false);
227 memcpy(*retkcp, kcp, kc_bitsize);
228 }
229
230 void
231 kcpuset_destroy(kcpuset_t *kcp)
232 {
233 kcpuset_impl_t *kc;
234
235 KASSERT(kc_initialised);
236 KASSERT(kcp != NULL);
237
238 do {
239 kc = KC_GETSTRUCT(kcp);
240 kcp = kc->kc_next;
241 pool_cache_put(kc_cache, kc);
242 } while (kcp);
243 }
244
245 /*
246 * Routines to reference/unreference the CPU set.
247 * Note: early boot case is not supported by these routines.
248 */
249
250 void
251 kcpuset_use(kcpuset_t *kcp)
252 {
253 kcpuset_impl_t *kc = KC_GETSTRUCT(kcp);
254
255 KASSERT(kc_initialised);
256 atomic_inc_uint(&kc->kc_refcnt);
257 }
258
259 void
260 kcpuset_unuse(kcpuset_t *kcp, kcpuset_t **lst)
261 {
262 kcpuset_impl_t *kc = KC_GETSTRUCT(kcp);
263
264 KASSERT(kc_initialised);
265 KASSERT(kc->kc_refcnt > 0);
266
267 membar_release();
268 if (atomic_dec_uint_nv(&kc->kc_refcnt) != 0) {
269 return;
270 }
271 membar_acquire();
272 KASSERT(kc->kc_next == NULL);
273 if (lst == NULL) {
274 kcpuset_destroy(kcp);
275 return;
276 }
277 kc->kc_next = *lst;
278 *lst = kcp;
279 }
280
281 /*
282 * Routines to transfer the CPU set from / to userspace.
283 * Note: early boot case is not supported by these routines.
284 */
285
286 int
287 kcpuset_copyin(const cpuset_t *ucp, kcpuset_t *kcp, size_t len)
288 {
289 kcpuset_impl_t *kc __diagused = KC_GETSTRUCT(kcp);
290
291 KASSERT(kc_initialised);
292 KASSERT(kc->kc_refcnt > 0);
293 KASSERT(kc->kc_next == NULL);
294
295 if (len > kc_bitsize) { /* XXX */
296 return EINVAL;
297 }
298 return copyin(ucp, kcp, len);
299 }
300
301 int
302 kcpuset_copyout(kcpuset_t *kcp, cpuset_t *ucp, size_t len)
303 {
304 kcpuset_impl_t *kc __diagused = KC_GETSTRUCT(kcp);
305
306 KASSERT(kc_initialised);
307 KASSERT(kc->kc_refcnt > 0);
308 KASSERT(kc->kc_next == NULL);
309
310 if (len > kc_bitsize) { /* XXX */
311 return EINVAL;
312 }
313 return copyout(kcp, ucp, len);
314 }
315
316 void
317 kcpuset_export_u32(const kcpuset_t *kcp, uint32_t *bitfield, size_t len)
318 {
319 size_t rlen = MIN(kc_bitsize, len);
320
321 KASSERT(kcp != NULL);
322 memcpy(bitfield, kcp->bits, rlen);
323 }
324
325 /*
326 * Routines to change bit field - zero, fill, copy, set, unset, etc.
327 */
328
329 void
330 kcpuset_zero(kcpuset_t *kcp)
331 {
332
333 KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_refcnt > 0);
334 KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_next == NULL);
335 memset(kcp, 0, kc_bitsize);
336 }
337
338 void
339 kcpuset_fill(kcpuset_t *kcp)
340 {
341
342 KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_refcnt > 0);
343 KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_next == NULL);
344 memset(kcp, ~0, kc_bitsize);
345 }
346
347 void
348 kcpuset_copy(kcpuset_t *dkcp, const kcpuset_t *skcp)
349 {
350
351 KASSERT(!kc_initialised || KC_GETSTRUCT(dkcp)->kc_refcnt > 0);
352 KASSERT(!kc_initialised || KC_GETSTRUCT(dkcp)->kc_next == NULL);
353 memcpy(dkcp, skcp, kc_bitsize);
354 }
355
356 void
357 kcpuset_set(kcpuset_t *kcp, cpuid_t i)
358 {
359 const size_t j = i >> KC_SHIFT;
360
361 KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_next == NULL);
362 KASSERT(j < kc_nfields);
363
364 kcp->bits[j] |= __BIT(i & KC_MASK);
365 }
366
367 void
368 kcpuset_clear(kcpuset_t *kcp, cpuid_t i)
369 {
370 const size_t j = i >> KC_SHIFT;
371
372 KASSERT(!kc_initialised || KC_GETCSTRUCT(kcp)->kc_next == NULL);
373 KASSERT(j < kc_nfields);
374
375 kcp->bits[j] &= ~(__BIT(i & KC_MASK));
376 }
377
378 bool
379 kcpuset_isset(const kcpuset_t *kcp, cpuid_t i)
380 {
381 const size_t j = i >> KC_SHIFT;
382
383 KASSERT(kcp != NULL);
384 KASSERT(!kc_initialised || KC_GETCSTRUCT(kcp)->kc_refcnt > 0);
385 KASSERT(!kc_initialised || KC_GETCSTRUCT(kcp)->kc_next == NULL);
386 KASSERT(j < kc_nfields);
387
388 return ((__BIT(i & KC_MASK)) & kcp->bits[j]) != 0;
389 }
390
391 bool
392 kcpuset_isotherset(const kcpuset_t *kcp, cpuid_t i)
393 {
394 const size_t j2 = i >> KC_SHIFT;
395 const uint32_t mask = ~(__BIT(i & KC_MASK));
396
397 for (size_t j = 0; j < kc_nfields; j++) {
398 const uint32_t bits = kcp->bits[j];
399 if (bits && (j != j2 || (bits & mask) != 0)) {
400 return true;
401 }
402 }
403 return false;
404 }
405
406 bool
407 kcpuset_iszero(const kcpuset_t *kcp)
408 {
409
410 for (size_t j = 0; j < kc_nfields; j++) {
411 if (kcp->bits[j] != 0) {
412 return false;
413 }
414 }
415 return true;
416 }
417
418 bool
419 kcpuset_match(const kcpuset_t *kcp1, const kcpuset_t *kcp2)
420 {
421
422 return memcmp(kcp1, kcp2, kc_bitsize) == 0;
423 }
424
425 bool
426 kcpuset_intersecting_p(const kcpuset_t *kcp1, const kcpuset_t *kcp2)
427 {
428
429 for (size_t j = 0; j < kc_nfields; j++) {
430 if (kcp1->bits[j] & kcp2->bits[j])
431 return true;
432 }
433 return false;
434 }
435
436 cpuid_t
437 kcpuset_ffs(const kcpuset_t *kcp)
438 {
439
440 for (size_t j = 0; j < kc_nfields; j++) {
441 if (kcp->bits[j])
442 return 32 * j + ffs(kcp->bits[j]);
443 }
444 return 0;
445 }
446
447 cpuid_t
448 kcpuset_ffs_intersecting(const kcpuset_t *kcp1, const kcpuset_t *kcp2)
449 {
450
451 for (size_t j = 0; j < kc_nfields; j++) {
452 uint32_t bits = kcp1->bits[j] & kcp2->bits[j];
453 if (bits)
454 return 32 * j + ffs(bits);
455 }
456 return 0;
457 }
458
459 void
460 kcpuset_merge(kcpuset_t *kcp1, const kcpuset_t *kcp2)
461 {
462
463 for (size_t j = 0; j < kc_nfields; j++) {
464 kcp1->bits[j] |= kcp2->bits[j];
465 }
466 }
467
468 void
469 kcpuset_intersect(kcpuset_t *kcp1, const kcpuset_t *kcp2)
470 {
471
472 for (size_t j = 0; j < kc_nfields; j++) {
473 kcp1->bits[j] &= kcp2->bits[j];
474 }
475 }
476
477 void
478 kcpuset_remove(kcpuset_t *kcp1, const kcpuset_t *kcp2)
479 {
480
481 for (size_t j = 0; j < kc_nfields; j++) {
482 kcp1->bits[j] &= ~kcp2->bits[j];
483 }
484 }
485
486 int
487 kcpuset_countset(const kcpuset_t *kcp)
488 {
489 int count = 0;
490
491 for (size_t j = 0; j < kc_nfields; j++) {
492 count += popcount32(kcp->bits[j]);
493 }
494 return count;
495 }
496
497 /*
498 * Routines to set/clear the flags atomically.
499 */
500
501 void
502 kcpuset_atomic_set(kcpuset_t *kcp, cpuid_t i)
503 {
504 const size_t j = i >> KC_SHIFT;
505
506 KASSERT(j < kc_nfields);
507 atomic_or_32(&kcp->bits[j], __BIT(i & KC_MASK));
508 }
509
510 void
511 kcpuset_atomic_clear(kcpuset_t *kcp, cpuid_t i)
512 {
513 const size_t j = i >> KC_SHIFT;
514
515 KASSERT(j < kc_nfields);
516 atomic_and_32(&kcp->bits[j], ~(__BIT(i & KC_MASK)));
517 }
518
519 void
520 kcpuset_atomicly_intersect(kcpuset_t *kcp1, const kcpuset_t *kcp2)
521 {
522
523 for (size_t j = 0; j < kc_nfields; j++) {
524 if (kcp2->bits[j])
525 atomic_and_32(&kcp1->bits[j], kcp2->bits[j]);
526 }
527 }
528
529 void
530 kcpuset_atomicly_merge(kcpuset_t *kcp1, const kcpuset_t *kcp2)
531 {
532
533 for (size_t j = 0; j < kc_nfields; j++) {
534 if (kcp2->bits[j])
535 atomic_or_32(&kcp1->bits[j], kcp2->bits[j]);
536 }
537 }
538
539 void
540 kcpuset_atomicly_remove(kcpuset_t *kcp1, const kcpuset_t *kcp2)
541 {
542
543 for (size_t j = 0; j < kc_nfields; j++) {
544 if (kcp2->bits[j])
545 atomic_and_32(&kcp1->bits[j], ~kcp2->bits[j]);
546 }
547 }
548