xref: /illumos-gate/usr/src/uts/common/syscall/p_online.c (revision a5f69788de7ac07553de47f7fec8c05a9a94c105)
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