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 "%Z%%M% %I% %E% 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