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
p_online_internal_locked(processorid_t cpun,int new_status,int * old_status)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
p_online_internal(processorid_t cpun,int new_status,int * old_status)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
p_online(processorid_t cpun,int new_status)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