#include <sys/types.h>
#include <sys/param.h>
#include <sys/var.h>
#include <sys/thread.h>
#include <sys/cpuvar.h>
#include <sys/kstat.h>
#include <sys/uadmin.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/cmn_err.h>
#include <sys/procset.h>
#include <sys/processor.h>
#include <sys/debug.h>
#include <sys/policy.h>
#include <sys/smt.h>
int
p_online_internal_locked(processorid_t cpun, int new_status, int *old_status)
{
cpu_t *cp;
int status;
int error = 0;
int flags = 0;
ASSERT(MUTEX_HELD(&cpu_lock));
if (cpun == P_ALL_SIBLINGS) {
if (new_status != P_DISABLED) {
error = EINVAL;
goto out;
}
return (smt_disable());
}
if ((cp = cpu_get(cpun)) == NULL) {
error = EINVAL;
goto out;
}
if (new_status & P_FORCED)
flags = CPU_FORCED;
*old_status = status = cpu_get_state(cp);
new_status &= ~P_FORCED;
switch (new_status) {
case P_STATUS:
goto out;
case P_ONLINE:
case P_OFFLINE:
case P_NOINTR:
case P_FAULTED:
case P_SPARE:
if (secpolicy_ponline(CRED()) != 0)
error = EPERM;
break;
case P_DISABLED:
default:
error = EINVAL;
break;
}
if (error)
goto out;
if (status == new_status)
goto out;
switch (new_status) {
case P_ONLINE:
switch (status) {
case P_POWEROFF:
if (error = cpu_poweron(cp))
break;
ASSERT(cpu_get_state(cp) == P_OFFLINE);
case P_DISABLED:
case P_OFFLINE:
case P_FAULTED:
case P_SPARE:
error = cpu_online(cp, flags);
break;
case P_NOINTR:
cpu_intr_enable(cp);
break;
}
break;
case P_OFFLINE:
switch (status) {
case P_NOINTR:
cpu_intr_enable(cp);
case P_ONLINE:
case P_DISABLED:
case P_FAULTED:
case P_SPARE:
error = cpu_offline(cp, flags);
break;
case P_POWEROFF:
error = cpu_poweron(cp);
break;
}
break;
case P_NOINTR:
switch (status) {
case P_POWEROFF:
if (error = cpu_poweron(cp))
break;
ASSERT(cpu_get_state(cp) == P_OFFLINE);
case P_DISABLED:
case P_OFFLINE:
case P_FAULTED:
case P_SPARE:
if (error = cpu_online(cp, flags))
break;
case P_ONLINE:
error = cpu_intr_disable(cp);
break;
}
break;
case P_FAULTED:
switch (status) {
case P_POWEROFF:
if (error = cpu_poweron(cp))
break;
ASSERT(cpu_get_state(cp) == P_OFFLINE);
case P_DISABLED:
case P_OFFLINE:
case P_ONLINE:
case P_NOINTR:
case P_SPARE:
error = cpu_faulted(cp, flags);
break;
}
break;
case P_SPARE:
switch (status) {
case P_POWEROFF:
if (error = cpu_poweron(cp))
break;
ASSERT(cpu_get_state(cp) == P_OFFLINE);
case P_DISABLED:
case P_OFFLINE:
case P_FAULTED:
case P_ONLINE:
case P_NOINTR:
error = cpu_spare(cp, flags);
break;
}
break;
}
out:
return (error);
}
int
p_online_internal(processorid_t cpun, int new_status, int *old_status)
{
int rc;
mutex_enter(&cpu_lock);
rc = p_online_internal_locked(cpun, new_status, old_status);
mutex_exit(&cpu_lock);
return (rc);
}
int
p_online(processorid_t cpun, int new_status)
{
int ret;
int old_status;
ret = p_online_internal(cpun, new_status, &old_status);
if (ret != 0)
return (set_errno(ret));
return (old_status);
}