Home | History | Annotate | Download | only in syscall
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*
     23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"@(#)p_online.c	1.17	05/06/08 SMI"
     28 
     29 #include <sys/types.h>
     30 #include <sys/param.h>
     31 #include <sys/var.h>
     32 #include <sys/thread.h>
     33 #include <sys/cpuvar.h>
     34 #include <sys/kstat.h>
     35 #include <sys/uadmin.h>
     36 #include <sys/systm.h>
     37 #include <sys/errno.h>
     38 #include <sys/cmn_err.h>
     39 #include <sys/procset.h>
     40 #include <sys/processor.h>
     41 #include <sys/debug.h>
     42 #include <sys/policy.h>
     43 
     44 /*
     45  * CPU state diagram
     46  *
     47  *                   P_SPARE
     48  * P_POWEROFF <---> P_OFFLINE <---> P_ONLINE <---> P_NOINTR
     49  *                  P_FAULTED
     50  */
     51 int
     52 p_online_internal(processorid_t cpun, int new_status, int *old_status)
     53 {
     54 	cpu_t	*cp;
     55 	int	status;
     56 	int	error = 0;
     57 	int	flags = 0;
     58 
     59 	/*
     60 	 * Try to get a pointer to the requested CPU structure.
     61 	 */
     62 	mutex_enter(&cpu_lock);		/* protects CPU states */
     63 	if ((cp = cpu_get(cpun)) == NULL) {
     64 		error = EINVAL;
     65 		goto out;
     66 	}
     67 
     68 	if (new_status & P_FORCED)
     69 		flags = CPU_FORCED;
     70 	*old_status = status = cpu_get_state(cp); /* get processor status */
     71 	new_status &= ~P_FORCED;
     72 
     73 	/*
     74 	 * Perform credentials check.
     75 	 */
     76 	switch (new_status) {
     77 	case P_STATUS:
     78 		goto out;
     79 	case P_ONLINE:
     80 	case P_OFFLINE:
     81 	case P_NOINTR:
     82 	case P_FAULTED:
     83 	case P_SPARE:
     84 		if (secpolicy_ponline(CRED()) != 0)
     85 			error = EPERM;
     86 		break;
     87 	default:
     88 		error = EINVAL;
     89 	}
     90 
     91 	if (error)
     92 		goto out;
     93 
     94 	/*
     95 	 * return 0 if the CPU is already in the desired new state.
     96 	 */
     97 	if (status == new_status)
     98 		goto out;
     99 
    100 	switch (new_status) {
    101 	case P_ONLINE:
    102 		switch (status) {
    103 		case P_POWEROFF:
    104 			/*
    105 			 * If CPU is powered off, power it on.
    106 			 */
    107 			if (error = cpu_poweron(cp))
    108 				break;
    109 			ASSERT(cpu_get_state(cp) == P_OFFLINE);
    110 			/* FALLTHROUGH */
    111 		case P_OFFLINE:
    112 		case P_FAULTED:
    113 		case P_SPARE:
    114 			/*
    115 			 * If CPU is in one of the offline states,
    116 			 * bring it online.
    117 			 */
    118 			error = cpu_online(cp);
    119 			break;
    120 		case P_NOINTR:
    121 			cpu_intr_enable(cp);
    122 			break;
    123 		}
    124 		break;
    125 
    126 	case P_OFFLINE:
    127 		switch (status) {
    128 		case P_NOINTR:
    129 			/*
    130 			 * Before we take the CPU offline, we first enable I/O
    131 			 * interrupts.
    132 			 */
    133 			cpu_intr_enable(cp);
    134 			/* FALLTHROUGH */
    135 		case P_ONLINE:
    136 		case P_FAULTED:
    137 		case P_SPARE:
    138 			/*
    139 			 * CPU is online, or in a special offline state.
    140 			 * Take it offline.
    141 			 */
    142 			error = cpu_offline(cp, flags);
    143 			break;
    144 		case P_POWEROFF:
    145 			/*
    146 			 * If CPU is powered off, power it on.
    147 			 */
    148 			error = cpu_poweron(cp);
    149 		}
    150 		break;
    151 
    152 	case P_NOINTR:
    153 		switch (status) {
    154 		case P_POWEROFF:
    155 			/*
    156 			 * if CPU is powered off, power it on.
    157 			 */
    158 			if (error = cpu_poweron(cp))
    159 				break;
    160 			ASSERT(cpu_get_state(cp) == P_OFFLINE);
    161 			/* FALLTHROUGH */
    162 		case P_OFFLINE:
    163 		case P_FAULTED:
    164 		case P_SPARE:
    165 			/*
    166 			 * First, bring the CPU online.
    167 			 */
    168 			if (error = cpu_online(cp))
    169 				break;
    170 			/* FALLTHROUGH */
    171 		case P_ONLINE:
    172 			/*
    173 			 * CPU is now online.  Try to disable interrupts.
    174 			 */
    175 			error = cpu_intr_disable(cp);
    176 		}
    177 		break;
    178 
    179 	case P_FAULTED:
    180 		switch (status) {
    181 		case P_POWEROFF:
    182 			/*
    183 			 * If CPU is powered off, power it on.
    184 			 */
    185 			if (error = cpu_poweron(cp))
    186 				break;
    187 			ASSERT(cpu_get_state(cp) == P_OFFLINE);
    188 			/*FALLTHROUGH*/
    189 		case P_OFFLINE:
    190 		case P_SPARE:
    191 		case P_ONLINE:
    192 		case P_NOINTR:
    193 			/*
    194 			 * Mark this CPU as faulted.
    195 			 */
    196 			error = cpu_faulted(cp, flags);
    197 		}
    198 		break;
    199 
    200 	case P_SPARE:
    201 		switch (status) {
    202 		case P_POWEROFF:
    203 			/*
    204 			 * If CPU is powered off, power it on.
    205 			 */
    206 			if (error = cpu_poweron(cp))
    207 				break;
    208 			ASSERT(cpu_get_state(cp) == P_OFFLINE);
    209 			/*FALLTHROUGH*/
    210 		case P_OFFLINE:
    211 		case P_FAULTED:
    212 		case P_ONLINE:
    213 		case P_NOINTR:
    214 			/*
    215 			 * Mark this CPU as a spare.
    216 			 */
    217 			error = cpu_spare(cp, flags);
    218 		}
    219 		break;
    220 	}
    221 out:
    222 	mutex_exit(&cpu_lock);
    223 	return (error);
    224 }
    225 
    226 /*
    227  * p_online(2) - get/change processor operational status.
    228  *
    229  *   As noted in os/cpu.c, the P_ONLINE and other state constants are for use
    230  *   only in this system call path and other paths conveying CPU state to
    231  *   userland.  In general, other kernel consumers should be using the accessor
    232  *   functions in uts/common/os/cpu.c.
    233  */
    234 int
    235 p_online(processorid_t cpun, int new_status)
    236 {
    237 	int ret;
    238 	int old_status;
    239 
    240 	ret = p_online_internal(cpun, new_status, &old_status);
    241 	if (ret != 0)
    242 		return (set_errno(ret));
    243 	return (old_status);
    244 }
    245