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