/*-
* Copyright (c) 2007, 2008, 2009, 2010, 2012, 2019 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Andrew Doran.
*
* 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.
*/
/*-
* Copyright (c)2007 YAMAMOTO Takashi,
* All rights reserved.
*
* 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 AUTHOR 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 AUTHOR 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.
*/
/*
* CPU related routines not shared with rump.
*/
/*
* If the port has stated that cpu_data is the first thing in cpu_info,
* verify that the claim is true. This will prevent them from getting out
* of sync.
*/
#ifdef __HAVE_CPU_DATA_FIRST
CTASSERT(offsetof(struct cpu_info, ci_data) == 0);
#else
CTASSERT(offsetof(struct cpu_info, ci_data) != 0);
#endif
int (*compat_cpuctl_ioctl)(struct lwp *, u_long, void *) = (void *)enosys;
/*
* Thread that made the cross call (separate context) holds
* cpu_lock on our behalf.
*/
spc = &ci->ci_schedstate;
s = splsched();
spc->spc_flags |= SPCF_OFFLINE;
splx(s);
/* Take the first available CPU for the migration. */
for (CPU_INFO_FOREACH(cii, target_ci)) {
mspc = &target_ci->ci_schedstate;
if ((mspc->spc_flags & SPCF_OFFLINE) == 0)
break;
}
KASSERT(target_ci != NULL);
/*
* Migrate all non-bound threads to the other CPU. Note that this
* runs from the xcall thread, thus handling of LSONPROC is not needed.
*/
mutex_enter(&proc_lock);
LIST_FOREACH(l, &alllwp, l_list) {
struct cpu_info *mci;
lwp_lock(l);
if (l->l_cpu != ci || (l->l_pflag & (LP_BOUND | LP_INTR))) {
lwp_unlock(l);
continue;
}
/* Regular case - no affinity. */
if (l->l_affinity == NULL) {
lwp_migrate(l, target_ci);
continue;
}
/* Affinity is set, find an online CPU in the set. */
for (CPU_INFO_FOREACH(cii, mci)) {
mspc = &mci->ci_schedstate;
if ((mspc->spc_flags & SPCF_OFFLINE) == 0 &&
kcpuset_isset(l->l_affinity, cpu_index(mci)))
break;
}
if (mci == NULL) {
lwp_unlock(l);
mutex_exit(&proc_lock);
goto fail;
}
lwp_migrate(l, mci);
}
mutex_exit(&proc_lock);
if (online) {
if ((spc->spc_flags & SPCF_OFFLINE) == 0)
return 0;
func = (xcfunc_t)cpu_xc_online;
} else {
if ((spc->spc_flags & SPCF_OFFLINE) != 0)
return 0;
nonline = 0;
/*
* Ensure that at least one CPU within the processor set
* stays online. Revisit this later.
*/
for (CPU_INFO_FOREACH(cii, ci2)) {
if ((ci2->ci_schedstate.spc_flags & SPCF_OFFLINE) != 0)
continue;
if (ci2->ci_schedstate.spc_psid != spc->spc_psid)
continue;
nonline++;
}
if (nonline == 1)
return EBUSY;
func = (xcfunc_t)cpu_xc_offline;
}
where = xc_unicast(0, func, ci, NULL, ci);
xc_wait(where);
if (online) {
KASSERT((spc->spc_flags & SPCF_OFFLINE) == 0);
ncpuonline++;
} else {
if ((spc->spc_flags & SPCF_OFFLINE) == 0) {
/* If was not set offline, then it is busy */
return EBUSY;
}
ncpuonline--;
}
spc->spc_lastmod = time_second;
return 0;
}
bool
cpu_is_type(struct cpu_info *ci, int wanted)
{
if (intr) {
if ((spc->spc_flags & SPCF_NOINTR) == 0)
return 0;
func = (xcfunc_t)cpu_xc_intr;
} else {
if (CPU_IS_PRIMARY(ci)) /* XXX kern/45117 */
return EINVAL;
if ((spc->spc_flags & SPCF_NOINTR) != 0)
return 0;
/*
* Ensure that at least one CPU within the system
* is handing device interrupts.
*/
nintr = 0;
for (CPU_INFO_FOREACH(cii, ci2)) {
if ((ci2->ci_schedstate.spc_flags & SPCF_NOINTR) != 0)
continue;
if (ci2 == ci)
continue;
nintr++;
}
if (nintr == 0)
return EBUSY;
func = (xcfunc_t)cpu_xc_nointr;
}
where = xc_unicast(0, func, ci, NULL, ci);
xc_wait(where);
if (intr) {
KASSERT((spc->spc_flags & SPCF_NOINTR) == 0);
} else if ((spc->spc_flags & SPCF_NOINTR) == 0) {
/* If was not set offline, then it is busy */
return EBUSY;
}
/* Direct interrupts away from the CPU and record the change. */
cpu_intr_redistribute();
spc->spc_lastmod = time_second;
return 0;
}
#else /* __HAVE_INTR_CONTROL */
int
cpu_setintr(struct cpu_info *ci, bool intr)
{