/* $NetBSD: subr_kcpuset.c,v 1.20 2023/09/23 18:21:11 ad Exp $ */
/*-
* Copyright (c) 2011, 2023 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Mindaugas Rasiukevicius.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Kernel CPU set implementation.
*
* Interface can be used by kernel subsystems as a unified dynamic CPU
* bitset implementation handling many CPUs. Facility also supports early
* use by MD code on boot, as it fixups bitsets on further boot.
*
* TODO:
* - Handle "reverse" bitset on fixup/grow.
*/
/*
* The size of whole bitset fields and amount of fields.
* The whole size must statically initialise for early case.
*/
static size_t kc_bitsize __read_mostly = KC_BITSIZE_EARLY;
static size_t kc_nfields __read_mostly = KC_NFIELDS_EARLY;
static size_t kc_memsize __read_mostly;
static kcpuset_t * kcpuset_create_raw(bool);
/*
* kcpuset_sysinit: initialize the subsystem, transfer early boot cases
* to dynamically allocated sets.
*/
void
kcpuset_sysinit(void)
{
kcpuset_t *kc_dynamic[KC_SAVE_NITEMS], *kcp;
int i, s;
/* First, pre-allocate kcpuset entries. */
for (i = 0; i < kc_last_idx; i++) {
kcp = kcpuset_create_raw(true);
kc_dynamic[i] = kcp;
}
/*
* Prepare to convert all early noted kcpuset uses to dynamic sets.
* All processors, except the one we are currently running (primary),
* must not be spinned yet. Since MD facilities can use kcpuset,
* raise the IPL to high.
*/
KASSERT(mp_online == false);
s = splhigh();
for (i = 0; i < kc_last_idx; i++) {
/*
* Transfer the bits from early static storage to the kcpuset.
*/
KASSERT(kc_bitsize >= KC_BITSIZE_EARLY);
memcpy(kc_dynamic[i], &kc_bits_early[i], KC_BITSIZE_EARLY);
/*
* Store the new pointer, pointing to the allocated kcpuset.
* Note: we are not in an interrupt context and it is the only
* CPU running - thus store is safe (e.g. no need for pointer
* variable to be volatile).
*/
*kc_noted_early[i] = kc_dynamic[i];
}
kc_initialised = true;
kc_last_idx = 0;
splx(s);
}
/*
* kcpuset_early_ptr: note an early boot use by saving the pointer and
* returning a pointer to a static, temporary bit field.
*/
static kcpuset_t *
kcpuset_early_ptr(kcpuset_t **kcptr)
{
kcpuset_t *kcp;
int s;
s = splhigh();
if (kc_last_idx < KC_SAVE_NITEMS) {
/*
* Save the pointer, return pointer to static early field.
* Need to zero it out.
*/
kc_noted_early[kc_last_idx] = kcptr;
kcp = (kcpuset_t *)&kc_bits_early[kc_last_idx];
kc_last_idx++;
memset(kcp, 0, KC_BITSIZE_EARLY);
KASSERT(kc_bitsize == KC_BITSIZE_EARLY);
} else {
panic("kcpuset(9): all early-use entries exhausted; "
"increase KC_SAVE_NITEMS\n");
}
splx(s);
return kcp;
}
/*
* Routines to create or destroy the CPU set.
* Early boot case is handled.
*/