Annotation of src/sys/kern/subr_kcpuset.c, Revision 1.10.2.1
1.10.2.1! tls 1: /* $NetBSD: subr_kcpuset.c,v 1.11 2014/05/19 20:39:23 rmind Exp $ */
1.1 rmind 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>
1.10.2.1! tls 44: __KERNEL_RCSID(0, "$NetBSD: subr_kcpuset.c,v 1.11 2014/05/19 20:39:23 rmind Exp $");
1.1 rmind 45:
46: #include <sys/param.h>
47: #include <sys/types.h>
48:
49: #include <sys/atomic.h>
50: #include <sys/sched.h>
51: #include <sys/kcpuset.h>
52: #include <sys/pool.h>
53:
54: /* Number of CPUs to support. */
55: #define KC_MAXCPUS roundup2(MAXCPUS, 32)
56:
57: /*
58: * Structure of dynamic CPU set in the kernel.
59: */
60: struct kcpuset {
61: uint32_t bits[0];
62: };
63:
64: typedef struct kcpuset_impl {
65: /* Reference count. */
66: u_int kc_refcnt;
67: /* Next to free, if non-NULL (used when multiple references). */
68: struct kcpuset * kc_next;
69: /* Actual variable-sized field of bits. */
70: struct kcpuset kc_field;
71: } kcpuset_impl_t;
72:
73: #define KC_BITS_OFF (offsetof(struct kcpuset_impl, kc_field))
74: #define KC_GETSTRUCT(b) ((kcpuset_impl_t *)((char *)(b) - KC_BITS_OFF))
1.9 matt 75: #define KC_GETCSTRUCT(b) ((const kcpuset_impl_t *)((const char *)(b) - KC_BITS_OFF))
1.1 rmind 76:
77: /* Sizes of a single bitset. */
78: #define KC_SHIFT 5
79: #define KC_MASK 31
80:
81: /* An array of noted early kcpuset creations and data. */
82: #define KC_SAVE_NITEMS 8
83:
84: /* Structures for early boot mechanism (must be statically initialised). */
85: static kcpuset_t ** kc_noted_early[KC_SAVE_NITEMS];
86: static uint32_t kc_bits_early[KC_SAVE_NITEMS];
87: static int kc_last_idx = 0;
88: static bool kc_initialised = false;
89:
90: #define KC_BITSIZE_EARLY sizeof(kc_bits_early[0])
1.4 rmind 91: #define KC_NFIELDS_EARLY 1
1.1 rmind 92:
93: /*
94: * The size of whole bitset fields and amount of fields.
95: * The whole size must statically initialise for early case.
96: */
97: static size_t kc_bitsize __read_mostly = KC_BITSIZE_EARLY;
98: static size_t kc_nfields __read_mostly = KC_NFIELDS_EARLY;
99:
100: static pool_cache_t kc_cache __read_mostly;
101:
1.3 rmind 102: static kcpuset_t * kcpuset_create_raw(bool);
1.1 rmind 103:
104: /*
105: * kcpuset_sysinit: initialize the subsystem, transfer early boot cases
106: * to dynamically allocated sets.
107: */
108: void
109: kcpuset_sysinit(void)
110: {
111: kcpuset_t *kc_dynamic[KC_SAVE_NITEMS], *kcp;
112: int i, s;
113:
114: /* Set a kcpuset_t sizes. */
115: kc_nfields = (KC_MAXCPUS >> KC_SHIFT);
116: kc_bitsize = sizeof(uint32_t) * kc_nfields;
1.4 rmind 117: KASSERT(kc_nfields != 0 && kc_bitsize != 0);
1.1 rmind 118:
119: kc_cache = pool_cache_init(sizeof(kcpuset_impl_t) + kc_bitsize,
120: coherency_unit, 0, 0, "kcpuset", NULL, IPL_NONE, NULL, NULL, NULL);
121:
122: /* First, pre-allocate kcpuset entries. */
123: for (i = 0; i < kc_last_idx; i++) {
1.3 rmind 124: kcp = kcpuset_create_raw(true);
1.1 rmind 125: kc_dynamic[i] = kcp;
126: }
127:
128: /*
129: * Prepare to convert all early noted kcpuset uses to dynamic sets.
130: * All processors, except the one we are currently running (primary),
131: * must not be spinned yet. Since MD facilities can use kcpuset,
132: * raise the IPL to high.
133: */
134: KASSERT(mp_online == false);
135:
136: s = splhigh();
137: for (i = 0; i < kc_last_idx; i++) {
138: /*
139: * Transfer the bits from early static storage to the kcpuset.
140: */
141: KASSERT(kc_bitsize >= KC_BITSIZE_EARLY);
142: memcpy(kc_dynamic[i], &kc_bits_early[i], KC_BITSIZE_EARLY);
143:
144: /*
145: * Store the new pointer, pointing to the allocated kcpuset.
146: * Note: we are not in an interrupt context and it is the only
147: * CPU running - thus store is safe (e.g. no need for pointer
148: * variable to be volatile).
149: */
150: *kc_noted_early[i] = kc_dynamic[i];
151: }
152: kc_initialised = true;
153: kc_last_idx = 0;
154: splx(s);
155: }
156:
157: /*
158: * kcpuset_early_ptr: note an early boot use by saving the pointer and
159: * returning a pointer to a static, temporary bit field.
160: */
161: static kcpuset_t *
162: kcpuset_early_ptr(kcpuset_t **kcptr)
163: {
164: kcpuset_t *kcp;
165: int s;
166:
167: s = splhigh();
168: if (kc_last_idx < KC_SAVE_NITEMS) {
169: /*
170: * Save the pointer, return pointer to static early field.
171: * Need to zero it out.
172: */
1.5 rmind 173: kc_noted_early[kc_last_idx] = kcptr;
1.1 rmind 174: kcp = (kcpuset_t *)&kc_bits_early[kc_last_idx];
1.5 rmind 175: kc_last_idx++;
1.1 rmind 176: memset(kcp, 0, KC_BITSIZE_EARLY);
177: KASSERT(kc_bitsize == KC_BITSIZE_EARLY);
178: } else {
179: panic("kcpuset(9): all early-use entries exhausted; "
180: "increase KC_SAVE_NITEMS\n");
181: }
182: splx(s);
183:
184: return kcp;
185: }
186:
187: /*
188: * Routines to create or destroy the CPU set.
189: * Early boot case is handled.
190: */
191:
192: static kcpuset_t *
1.3 rmind 193: kcpuset_create_raw(bool zero)
1.1 rmind 194: {
195: kcpuset_impl_t *kc;
196:
197: kc = pool_cache_get(kc_cache, PR_WAITOK);
198: kc->kc_refcnt = 1;
199: kc->kc_next = NULL;
200:
1.3 rmind 201: if (zero) {
202: memset(&kc->kc_field, 0, kc_bitsize);
203: }
204:
1.1 rmind 205: /* Note: return pointer to the actual field of bits. */
206: KASSERT((uint8_t *)kc + KC_BITS_OFF == (uint8_t *)&kc->kc_field);
207: return &kc->kc_field;
208: }
209:
210: void
1.3 rmind 211: kcpuset_create(kcpuset_t **retkcp, bool zero)
1.1 rmind 212: {
213: if (__predict_false(!kc_initialised)) {
214: /* Early boot use - special case. */
215: *retkcp = kcpuset_early_ptr(retkcp);
216: return;
217: }
1.3 rmind 218: *retkcp = kcpuset_create_raw(zero);
1.1 rmind 219: }
220:
221: void
1.9 matt 222: kcpuset_clone(kcpuset_t **retkcp, const kcpuset_t *kcp)
223: {
224: kcpuset_create(retkcp, false);
225: memcpy(*retkcp, kcp, kc_bitsize);
226: }
227:
228: void
1.1 rmind 229: kcpuset_destroy(kcpuset_t *kcp)
230: {
1.2 rmind 231: kcpuset_impl_t *kc;
1.1 rmind 232:
233: KASSERT(kc_initialised);
234: KASSERT(kcp != NULL);
235:
236: do {
1.2 rmind 237: kc = KC_GETSTRUCT(kcp);
238: kcp = kc->kc_next;
1.1 rmind 239: pool_cache_put(kc_cache, kc);
1.2 rmind 240: } while (kcp);
1.1 rmind 241: }
242:
243: /*
1.4 rmind 244: * Routines to reference/unreference the CPU set.
1.1 rmind 245: * Note: early boot case is not supported by these routines.
246: */
247:
248: void
249: kcpuset_use(kcpuset_t *kcp)
250: {
251: kcpuset_impl_t *kc = KC_GETSTRUCT(kcp);
252:
253: KASSERT(kc_initialised);
254: atomic_inc_uint(&kc->kc_refcnt);
255: }
256:
257: void
258: kcpuset_unuse(kcpuset_t *kcp, kcpuset_t **lst)
259: {
260: kcpuset_impl_t *kc = KC_GETSTRUCT(kcp);
261:
262: KASSERT(kc_initialised);
263: KASSERT(kc->kc_refcnt > 0);
264:
265: if (atomic_dec_uint_nv(&kc->kc_refcnt) != 0) {
266: return;
267: }
268: KASSERT(kc->kc_next == NULL);
269: if (lst == NULL) {
270: kcpuset_destroy(kcp);
271: return;
272: }
273: kc->kc_next = *lst;
274: *lst = kcp;
275: }
276:
277: /*
278: * Routines to transfer the CPU set from / to userspace.
279: * Note: early boot case is not supported by these routines.
280: */
281:
282: int
283: kcpuset_copyin(const cpuset_t *ucp, kcpuset_t *kcp, size_t len)
284: {
1.10 martin 285: kcpuset_impl_t *kc __diagused = KC_GETSTRUCT(kcp);
1.1 rmind 286:
287: KASSERT(kc_initialised);
288: KASSERT(kc->kc_refcnt > 0);
289: KASSERT(kc->kc_next == NULL);
290:
1.5 rmind 291: if (len > kc_bitsize) { /* XXX */
1.1 rmind 292: return EINVAL;
293: }
1.5 rmind 294: return copyin(ucp, kcp, len);
1.1 rmind 295: }
296:
297: int
298: kcpuset_copyout(kcpuset_t *kcp, cpuset_t *ucp, size_t len)
299: {
1.10 martin 300: kcpuset_impl_t *kc __diagused = KC_GETSTRUCT(kcp);
1.1 rmind 301:
302: KASSERT(kc_initialised);
303: KASSERT(kc->kc_refcnt > 0);
304: KASSERT(kc->kc_next == NULL);
305:
1.5 rmind 306: if (len > kc_bitsize) { /* XXX */
1.1 rmind 307: return EINVAL;
308: }
1.5 rmind 309: return copyout(kcp, ucp, len);
1.1 rmind 310: }
311:
1.6 rmind 312: void
1.8 rmind 313: kcpuset_export_u32(const kcpuset_t *kcp, uint32_t *bitfield, size_t len)
1.6 rmind 314: {
315: size_t rlen = MIN(kc_bitsize, len);
316:
317: KASSERT(kcp != NULL);
318: memcpy(bitfield, kcp->bits, rlen);
319: }
320:
1.1 rmind 321: /*
1.4 rmind 322: * Routines to change bit field - zero, fill, copy, set, unset, etc.
1.1 rmind 323: */
1.4 rmind 324:
1.1 rmind 325: void
326: kcpuset_zero(kcpuset_t *kcp)
327: {
328:
329: KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_refcnt > 0);
330: KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_next == NULL);
331: memset(kcp, 0, kc_bitsize);
332: }
333:
334: void
335: kcpuset_fill(kcpuset_t *kcp)
336: {
337:
338: KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_refcnt > 0);
339: KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_next == NULL);
340: memset(kcp, ~0, kc_bitsize);
341: }
342:
343: void
1.9 matt 344: kcpuset_copy(kcpuset_t *dkcp, const kcpuset_t *skcp)
1.4 rmind 345: {
346:
347: KASSERT(!kc_initialised || KC_GETSTRUCT(dkcp)->kc_refcnt > 0);
348: KASSERT(!kc_initialised || KC_GETSTRUCT(dkcp)->kc_next == NULL);
349: memcpy(dkcp, skcp, kc_bitsize);
350: }
351:
352: void
1.1 rmind 353: kcpuset_set(kcpuset_t *kcp, cpuid_t i)
354: {
355: const size_t j = i >> KC_SHIFT;
356:
357: KASSERT(!kc_initialised || KC_GETSTRUCT(kcp)->kc_next == NULL);
358: KASSERT(j < kc_nfields);
359:
360: kcp->bits[j] |= 1 << (i & KC_MASK);
361: }
362:
363: void
364: kcpuset_clear(kcpuset_t *kcp, cpuid_t i)
365: {
366: const size_t j = i >> KC_SHIFT;
367:
1.9 matt 368: KASSERT(!kc_initialised || KC_GETCSTRUCT(kcp)->kc_next == NULL);
1.1 rmind 369: KASSERT(j < kc_nfields);
370:
371: kcp->bits[j] &= ~(1 << (i & KC_MASK));
372: }
373:
1.4 rmind 374: bool
1.9 matt 375: kcpuset_isset(const kcpuset_t *kcp, cpuid_t i)
1.1 rmind 376: {
377: const size_t j = i >> KC_SHIFT;
378:
379: KASSERT(kcp != NULL);
1.9 matt 380: KASSERT(!kc_initialised || KC_GETCSTRUCT(kcp)->kc_refcnt > 0);
381: KASSERT(!kc_initialised || KC_GETCSTRUCT(kcp)->kc_next == NULL);
1.1 rmind 382: KASSERT(j < kc_nfields);
383:
384: return ((1 << (i & KC_MASK)) & kcp->bits[j]) != 0;
385: }
386:
387: bool
1.9 matt 388: kcpuset_isotherset(const kcpuset_t *kcp, cpuid_t i)
1.4 rmind 389: {
390: const size_t j2 = i >> KC_SHIFT;
391: const uint32_t mask = ~(1 << (i & KC_MASK));
392:
393: for (size_t j = 0; j < kc_nfields; j++) {
394: const uint32_t bits = kcp->bits[j];
395: if (bits && (j != j2 || (bits & mask) != 0)) {
396: return true;
397: }
398: }
399: return false;
400: }
401:
402: bool
1.9 matt 403: kcpuset_iszero(const kcpuset_t *kcp)
1.1 rmind 404: {
405:
406: for (size_t j = 0; j < kc_nfields; j++) {
407: if (kcp->bits[j] != 0) {
408: return false;
409: }
410: }
411: return true;
412: }
413:
414: bool
415: kcpuset_match(const kcpuset_t *kcp1, const kcpuset_t *kcp2)
416: {
417:
418: return memcmp(kcp1, kcp2, kc_bitsize) == 0;
419: }
1.3 rmind 420:
1.9 matt 421: bool
422: kcpuset_intersecting_p(const kcpuset_t *kcp1, const kcpuset_t *kcp2)
423: {
424:
425: for (size_t j = 0; j < kc_nfields; j++) {
426: if (kcp1->bits[j] & kcp2->bits[j])
427: return true;
428: }
429: return false;
430: }
431:
432: cpuid_t
433: kcpuset_ffs(const kcpuset_t *kcp)
434: {
435:
436: for (size_t j = 0; j < kc_nfields; j++) {
437: if (kcp->bits[j])
438: return 32 * j + ffs(kcp->bits[j]);
439: }
440: return 0;
441: }
442:
443: cpuid_t
444: kcpuset_ffs_intersecting(const kcpuset_t *kcp1, const kcpuset_t *kcp2)
445: {
446:
447: for (size_t j = 0; j < kc_nfields; j++) {
448: uint32_t bits = kcp1->bits[j] & kcp2->bits[j];
449: if (bits)
450: return 32 * j + ffs(bits);
451: }
452: return 0;
453: }
454:
1.3 rmind 455: void
1.9 matt 456: kcpuset_merge(kcpuset_t *kcp1, const kcpuset_t *kcp2)
1.3 rmind 457: {
458:
459: for (size_t j = 0; j < kc_nfields; j++) {
460: kcp1->bits[j] |= kcp2->bits[j];
461: }
462: }
463:
1.5 rmind 464: void
1.9 matt 465: kcpuset_intersect(kcpuset_t *kcp1, const kcpuset_t *kcp2)
1.5 rmind 466: {
467:
468: for (size_t j = 0; j < kc_nfields; j++) {
469: kcp1->bits[j] &= kcp2->bits[j];
470: }
471: }
472:
1.9 matt 473: void
474: kcpuset_remove(kcpuset_t *kcp1, const kcpuset_t *kcp2)
475: {
476:
477: for (size_t j = 0; j < kc_nfields; j++) {
478: kcp1->bits[j] &= ~kcp2->bits[j];
479: }
480: }
481:
1.4 rmind 482: int
1.10.2.1! tls 483: kcpuset_countset(const kcpuset_t *kcp)
1.4 rmind 484: {
485: int count = 0;
486:
487: for (size_t j = 0; j < kc_nfields; j++) {
488: count += popcount32(kcp->bits[j]);
489: }
490: return count;
491: }
492:
1.3 rmind 493: /*
494: * Routines to set/clear the flags atomically.
495: */
496:
497: void
498: kcpuset_atomic_set(kcpuset_t *kcp, cpuid_t i)
499: {
500: const size_t j = i >> KC_SHIFT;
501:
502: KASSERT(j < kc_nfields);
503: atomic_or_32(&kcp->bits[j], 1 << (i & KC_MASK));
504: }
505:
506: void
507: kcpuset_atomic_clear(kcpuset_t *kcp, cpuid_t i)
508: {
509: const size_t j = i >> KC_SHIFT;
510:
511: KASSERT(j < kc_nfields);
512: atomic_and_32(&kcp->bits[j], ~(1 << (i & KC_MASK)));
513: }
1.9 matt 514:
515: void
516: kcpuset_atomicly_intersect(kcpuset_t *kcp1, const kcpuset_t *kcp2)
517: {
518:
519: for (size_t j = 0; j < kc_nfields; j++) {
520: if (kcp2->bits[j])
521: atomic_and_32(&kcp1->bits[j], kcp2->bits[j]);
522: }
523: }
524:
525: void
526: kcpuset_atomicly_merge(kcpuset_t *kcp1, const kcpuset_t *kcp2)
527: {
528:
529: for (size_t j = 0; j < kc_nfields; j++) {
530: if (kcp2->bits[j])
531: atomic_or_32(&kcp1->bits[j], kcp2->bits[j]);
532: }
533: }
534:
535: void
536: kcpuset_atomicly_remove(kcpuset_t *kcp1, const kcpuset_t *kcp2)
537: {
538:
539: for (size_t j = 0; j < kc_nfields; j++) {
540: if (kcp2->bits[j])
541: atomic_and_32(&kcp1->bits[j], ~kcp2->bits[j]);
542: }
543: }
CVSweb <webmaster@jp.NetBSD.org>