xref: /dragonfly/sys/dev/acpica/acpi_cpu_pstate.c (revision f86988f7)
1 /*
2  * Copyright (c) 2009 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Sepherosa Ziehau <sepherosa@gmail.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include "opt_acpi.h"
36 
37 #include <sys/param.h>
38 #include <sys/bus.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
41 #include <sys/queue.h>
42 #include <sys/rman.h>
43 #include <sys/sysctl.h>
44 #include <sys/msgport2.h>
45 #include <sys/cpu_topology.h>
46 
47 #include <net/netisr2.h>
48 #include <net/netmsg2.h>
49 #include <net/if_var.h>
50 
51 #include "acpi.h"
52 #include "acpivar.h"
53 #include "acpi_cpu.h"
54 #include "acpi_cpu_pstate.h"
55 
56 #define ACPI_NPSTATE_MAX	16
57 
58 #define ACPI_PSS_PX_NENTRY	6
59 
60 #define ACPI_PSD_COORD_SWALL	0xfc
61 #define ACPI_PSD_COORD_SWANY	0xfd
62 #define ACPI_PSD_COORD_HWALL	0xfe
63 #define ACPI_PSD_COORD_VALID(coord) \
64 	((coord) == ACPI_PSD_COORD_SWALL || \
65 	 (coord) == ACPI_PSD_COORD_SWANY || \
66 	 (coord) == ACPI_PSD_COORD_HWALL)
67 
68 struct acpi_pst_softc;
69 LIST_HEAD(acpi_pst_list, acpi_pst_softc);
70 
71 struct netmsg_acpi_pst {
72 	struct netmsg_base base;
73 	const struct acpi_pst_res *ctrl;
74 	const struct acpi_pst_res *status;
75 };
76 
77 struct acpi_pst_domain {
78 	uint32_t		pd_dom;
79 	uint32_t		pd_coord;
80 	uint32_t		pd_nproc;
81 	LIST_ENTRY(acpi_pst_domain) pd_link;
82 
83 	uint32_t		pd_flags;
84 
85 	int			pd_state;
86 	int			pd_sstart;
87 	struct acpi_pst_list	pd_pstlist;
88 
89 	struct sysctl_ctx_list	pd_sysctl_ctx;
90 	struct sysctl_oid	*pd_sysctl_tree;
91 };
92 LIST_HEAD(acpi_pst_domlist, acpi_pst_domain);
93 
94 #define ACPI_PSTDOM_FLAG_STUB	0x1	/* stub domain, no _PSD */
95 #define ACPI_PSTDOM_FLAG_DEAD	0x2	/* domain can't be started */
96 #define ACPI_PSTDOM_FLAG_INT	0x4	/* domain created from Integer _PSD */
97 
98 struct acpi_pst_softc {
99 	device_t		pst_dev;
100 	struct acpi_cpu_softc	*pst_parent;
101 	struct acpi_pst_domain	*pst_domain;
102 	struct acpi_pst_res	pst_creg;
103 	struct acpi_pst_res	pst_sreg;
104 
105 	int			pst_state;
106 	int			pst_sstart;
107 	int			pst_cpuid;
108 
109 	ACPI_HANDLE		pst_handle;
110 
111 	LIST_ENTRY(acpi_pst_softc) pst_link;
112 };
113 
114 static int	acpi_pst_probe(device_t dev);
115 static int	acpi_pst_attach(device_t dev);
116 
117 static void	acpi_pst_postattach(void *);
118 static struct acpi_pst_domain *
119 		acpi_pst_domain_create_int(device_t, uint32_t);
120 static struct acpi_pst_domain *
121 		acpi_pst_domain_create_pkg(device_t, ACPI_OBJECT *);
122 static struct acpi_pst_domain *
123 		acpi_pst_domain_find(uint32_t);
124 static struct acpi_pst_domain *
125 		acpi_pst_domain_alloc(uint32_t, uint32_t, uint32_t);
126 static int	acpi_pst_domain_set_pstate(struct acpi_pst_domain *, int);
127 static void	acpi_pst_domain_check_nproc(device_t, struct acpi_pst_domain *);
128 static int	acpi_pst_global_set_pstate(int);
129 
130 static int	acpi_pst_check_csr(struct acpi_pst_softc *);
131 static int	acpi_pst_check_pstates(struct acpi_pst_softc *);
132 static int	acpi_pst_init(struct acpi_pst_softc *);
133 static int	acpi_pst_set_pstate(struct acpi_pst_softc *,
134 		    const struct acpi_pstate *);
135 static const struct acpi_pstate *
136 		acpi_pst_get_pstate(struct acpi_pst_softc *);
137 static int	acpi_pst_alloc_resource(device_t, ACPI_OBJECT *, int,
138 		    struct acpi_pst_res *);
139 
140 static void	acpi_pst_check_csr_handler(netmsg_t);
141 static void	acpi_pst_check_pstates_handler(netmsg_t);
142 static void	acpi_pst_init_handler(netmsg_t);
143 static void	acpi_pst_set_pstate_handler(netmsg_t);
144 static void	acpi_pst_get_pstate_handler(netmsg_t);
145 
146 static int	acpi_pst_sysctl_freqs(SYSCTL_HANDLER_ARGS);
147 static int	acpi_pst_sysctl_members(SYSCTL_HANDLER_ARGS);
148 static int	acpi_pst_sysctl_select(SYSCTL_HANDLER_ARGS);
149 static int	acpi_pst_sysctl_global(SYSCTL_HANDLER_ARGS);
150 
151 static struct acpi_pst_domlist	acpi_pst_domains =
152 	LIST_HEAD_INITIALIZER(acpi_pst_domains);
153 static int			acpi_pst_domain_id;
154 
155 static int			acpi_pst_global_state;
156 
157 static int			acpi_npstates;
158 static struct acpi_pstate	*acpi_pstates;
159 
160 static const struct acpi_pst_md	*acpi_pst_md;
161 
162 static int			acpi_pst_ht_reuse_domain = 1;
163 TUNABLE_INT("hw.acpi.cpu.pst.ht_reuse_domain", &acpi_pst_ht_reuse_domain);
164 
165 static device_method_t acpi_pst_methods[] = {
166 	/* Device interface */
167 	DEVMETHOD(device_probe,			acpi_pst_probe),
168 	DEVMETHOD(device_attach,		acpi_pst_attach),
169 	DEVMETHOD(device_detach,		bus_generic_detach),
170 	DEVMETHOD(device_shutdown,		bus_generic_shutdown),
171 	DEVMETHOD(device_suspend,		bus_generic_suspend),
172 	DEVMETHOD(device_resume,		bus_generic_resume),
173 
174 	/* Bus interface */
175 	DEVMETHOD(bus_add_child,		bus_generic_add_child),
176 	DEVMETHOD(bus_print_child,		bus_generic_print_child),
177 	DEVMETHOD(bus_read_ivar,		bus_generic_read_ivar),
178 	DEVMETHOD(bus_write_ivar,		bus_generic_write_ivar),
179 	DEVMETHOD(bus_get_resource_list,	bus_generic_get_resource_list),
180 	DEVMETHOD(bus_set_resource,		bus_generic_rl_set_resource),
181 	DEVMETHOD(bus_get_resource,		bus_generic_rl_get_resource),
182 	DEVMETHOD(bus_alloc_resource,		bus_generic_alloc_resource),
183 	DEVMETHOD(bus_release_resource,		bus_generic_release_resource),
184 	DEVMETHOD(bus_driver_added,		bus_generic_driver_added),
185 	DEVMETHOD(bus_activate_resource,	bus_generic_activate_resource),
186 	DEVMETHOD(bus_deactivate_resource,	bus_generic_deactivate_resource),
187 	DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
188 	DEVMETHOD(bus_teardown_intr,		bus_generic_teardown_intr),
189 
190 	DEVMETHOD_END
191 };
192 
193 static driver_t acpi_pst_driver = {
194 	"cpu_pst",
195 	acpi_pst_methods,
196 	sizeof(struct acpi_pst_softc)
197 };
198 
199 static devclass_t acpi_pst_devclass;
200 DRIVER_MODULE(cpu_pst, cpu, acpi_pst_driver, acpi_pst_devclass, NULL, NULL);
201 MODULE_DEPEND(cpu_pst, acpi, 1, 1, 1);
202 
203 static __inline int
204 acpi_pst_freq2index(int freq)
205 {
206 	int i;
207 
208 	for (i = 0; i < acpi_npstates; ++i) {
209 		if (acpi_pstates[i].st_freq == freq)
210 			return i;
211 	}
212 	return -1;
213 }
214 
215 static int
216 acpi_pst_probe(device_t dev)
217 {
218 	ACPI_BUFFER buf;
219 	ACPI_HANDLE handle;
220 	ACPI_STATUS status;
221 	ACPI_OBJECT *obj;
222 
223 	if (acpi_disabled("cpu_pst") ||
224 	    acpi_get_type(dev) != ACPI_TYPE_PROCESSOR)
225 		return ENXIO;
226 
227 	if (acpi_pst_md == NULL)
228 		acpi_pst_md = acpi_pst_md_probe();
229 
230 	handle = acpi_get_handle(dev);
231 
232 	/*
233 	 * Check _PSD package
234 	 *
235 	 * NOTE:
236 	 * Some BIOSes do not expose _PCT for the second thread of
237 	 * CPU cores.  In this case, _PSD should be enough to get the
238 	 * P-state of the second thread working, since it must have
239 	 * the same _PCT and _PSS as the first thread in the same
240 	 * core.
241 	 */
242 	buf.Pointer = NULL;
243 	buf.Length = ACPI_ALLOCATE_BUFFER;
244 	status = AcpiEvaluateObject(handle, "_PSD", NULL, &buf);
245 	if (!ACPI_FAILURE(status)) {
246 		AcpiOsFree((ACPI_OBJECT *)buf.Pointer);
247 		goto done;
248 	}
249 
250 	/*
251 	 * Check _PCT package
252 	 */
253 	buf.Pointer = NULL;
254 	buf.Length = ACPI_ALLOCATE_BUFFER;
255 	status = AcpiEvaluateObject(handle, "_PCT", NULL, &buf);
256 	if (ACPI_FAILURE(status)) {
257 		if (bootverbose) {
258 			device_printf(dev, "Can't get _PCT package - %s\n",
259 				      AcpiFormatException(status));
260 		}
261 		return ENXIO;
262 	}
263 
264 	obj = (ACPI_OBJECT *)buf.Pointer;
265 	if (!ACPI_PKG_VALID_EQ(obj, 2)) {
266 		device_printf(dev, "Invalid _PCT package\n");
267 		AcpiOsFree(obj);
268 		return ENXIO;
269 	}
270 	AcpiOsFree(obj);
271 
272 	/*
273 	 * Check _PSS package
274 	 */
275 	buf.Pointer = NULL;
276 	buf.Length = ACPI_ALLOCATE_BUFFER;
277 	status = AcpiEvaluateObject(handle, "_PSS", NULL, &buf);
278 	if (ACPI_FAILURE(status)) {
279 		device_printf(dev, "Can't get _PSS package - %s\n",
280 			      AcpiFormatException(status));
281 		return ENXIO;
282 	}
283 
284 	obj = (ACPI_OBJECT *)buf.Pointer;
285 	if (!ACPI_PKG_VALID(obj, 1)) {
286 		device_printf(dev, "Invalid _PSS package\n");
287 		AcpiOsFree(obj);
288 		return ENXIO;
289 	}
290 	AcpiOsFree(obj);
291 
292 done:
293 	device_set_desc(dev, "ACPI CPU P-State");
294 	return 0;
295 }
296 
297 static int
298 acpi_pst_attach(device_t dev)
299 {
300 	struct acpi_pst_softc *sc = device_get_softc(dev), *pst;
301 	struct acpi_pst_domain *dom = NULL;
302 	ACPI_BUFFER buf;
303 	ACPI_STATUS status;
304 	ACPI_OBJECT *obj;
305 	struct acpi_pstate *pstate, *p;
306 	int i, npstate, error;
307 
308 	sc->pst_dev = dev;
309 	sc->pst_parent = device_get_softc(device_get_parent(dev));
310 	sc->pst_handle = acpi_get_handle(dev);
311 	sc->pst_cpuid = acpi_get_magic(dev);
312 
313 	/*
314 	 * If there is a _PSD, then we create procossor domain
315 	 * accordingly.  If there is no _PSD, we just fake a
316 	 * default processor domain0.
317 	 */
318 	buf.Pointer = NULL;
319 	buf.Length = ACPI_ALLOCATE_BUFFER;
320 	status = AcpiEvaluateObject(sc->pst_handle, "_PSD", NULL, &buf);
321 	if (!ACPI_FAILURE(status)) {
322 		obj = (ACPI_OBJECT *)buf.Pointer;
323 
324 		if (acpi_pst_domain_id > 0) {
325 			device_printf(dev, "Missing _PSD for certain CPUs\n");
326 			AcpiOsFree(obj);
327 			return ENXIO;
328 		}
329 		acpi_pst_domain_id = -1;
330 
331 		if (ACPI_PKG_VALID_EQ(obj, 1)) {
332 			dom = acpi_pst_domain_create_pkg(dev,
333 				&obj->Package.Elements[0]);
334 			if (dom == NULL) {
335 				AcpiOsFree(obj);
336 				return ENXIO;
337 			}
338 		} else {
339 			if (obj->Type != ACPI_TYPE_INTEGER) {
340 				device_printf(dev,
341 				    "Invalid _PSD package, Type 0x%x\n",
342 				    obj->Type);
343 				AcpiOsFree(obj);
344 				return ENXIO;
345 			} else {
346 				device_printf(dev, "Integer _PSD %ju\n",
347 				    (uintmax_t)obj->Integer.Value);
348 				dom = acpi_pst_domain_create_int(dev,
349 				    obj->Integer.Value);
350 				if (dom == NULL) {
351 					AcpiOsFree(obj);
352 					return ENXIO;
353 				}
354 			}
355 		}
356 
357 		/* Free _PSD */
358 		AcpiOsFree(buf.Pointer);
359 	} else {
360 		if (acpi_pst_domain_id < 0) {
361 			device_printf(dev, "Missing _PSD for cpu%d\n",
362 			    sc->pst_cpuid);
363 			return ENXIO;
364 		}
365 
366 		/*
367 		 * Create a stub one processor domain for each processor
368 		 */
369 		dom = acpi_pst_domain_alloc(acpi_pst_domain_id,
370 			ACPI_PSD_COORD_SWANY, 1);
371 		dom->pd_flags |= ACPI_PSTDOM_FLAG_STUB;
372 
373 		++acpi_pst_domain_id;
374 	}
375 
376 	/* Make sure that adding us will not overflow our domain */
377 	acpi_pst_domain_check_nproc(dev, dom);
378 
379 	/*
380 	 * Get control/status registers from _PCT
381 	 */
382 	buf.Pointer = NULL;
383 	buf.Length = ACPI_ALLOCATE_BUFFER;
384 	status = AcpiEvaluateObject(sc->pst_handle, "_PCT", NULL, &buf);
385 	if (ACPI_FAILURE(status)) {
386 		/*
387 		 * No _PCT.  See the comment in acpi_pst_probe() near
388 		 * _PSD check.
389 		 *
390 		 * Use control/status registers of another CPU in the
391 		 * same domain, or in the same core, if the type of
392 		 * these registers are "Fixed Hardware", e.g. on most
393 		 * of the model Intel CPUs.
394 		 */
395 		pst = LIST_FIRST(&dom->pd_pstlist);
396 		if (pst == NULL) {
397 			cpumask_t mask;
398 
399 			mask = get_cpumask_from_level(sc->pst_cpuid,
400 			    CORE_LEVEL);
401 			if (CPUMASK_TESTNZERO(mask)) {
402 				struct acpi_pst_domain *dom1;
403 
404 				LIST_FOREACH(dom1, &acpi_pst_domains, pd_link) {
405 					LIST_FOREACH(pst, &dom1->pd_pstlist,
406 					    pst_link) {
407 						if (CPUMASK_TESTBIT(mask,
408 						    pst->pst_cpuid))
409 							break;
410 					}
411 					if (pst != NULL)
412 						break;
413 				}
414 				if (pst != NULL && acpi_pst_ht_reuse_domain) {
415 					/*
416 					 * Use the same domain for CPUs in the
417 					 * same core.
418 					 */
419 					device_printf(dev, "Destroy domain%u, "
420 					    "reuse domain%u\n",
421 					    dom->pd_dom, dom1->pd_dom);
422 					LIST_REMOVE(dom, pd_link);
423 					kfree(dom, M_DEVBUF);
424 					dom = dom1;
425 					/*
426 					 * Make sure that adding us will not
427 					 * overflow the domain containing
428 					 * siblings in the same core.
429 					 */
430 					acpi_pst_domain_check_nproc(dev, dom);
431 				}
432 			}
433 		}
434 		if (pst != NULL &&
435 		    pst->pst_creg.pr_res == NULL &&
436 		    pst->pst_creg.pr_rid == 0 &&
437 		    pst->pst_creg.pr_gas.SpaceId ==
438 		    ACPI_ADR_SPACE_FIXED_HARDWARE &&
439 		    pst->pst_sreg.pr_res == NULL &&
440 		    pst->pst_sreg.pr_rid == 0 &&
441 		    pst->pst_sreg.pr_gas.SpaceId ==
442 		    ACPI_ADR_SPACE_FIXED_HARDWARE) {
443 			sc->pst_creg = pst->pst_creg;
444 			sc->pst_sreg = pst->pst_sreg;
445 			device_printf(dev,
446 			    "No _PCT; reuse %s control/status regs\n",
447 			    device_get_nameunit(pst->pst_dev));
448 			goto fetch_pss;
449 		}
450 		device_printf(dev, "Can't get _PCT package - %s\n",
451 			      AcpiFormatException(status));
452 		return ENXIO;
453 	}
454 
455 	obj = (ACPI_OBJECT *)buf.Pointer;
456 	if (!ACPI_PKG_VALID_EQ(obj, 2)) {
457 		device_printf(dev, "Invalid _PCT package\n");
458 		AcpiOsFree(obj);
459 		return ENXIO;
460 	}
461 
462 	/* Save and try allocating control register */
463 	error = acpi_pst_alloc_resource(dev, obj, 0, &sc->pst_creg);
464 	if (error) {
465 		AcpiOsFree(obj);
466 		return error;
467 	}
468 	if (bootverbose) {
469 		device_printf(dev, "control reg %d %jx\n",
470 			      sc->pst_creg.pr_gas.SpaceId,
471 			      (uintmax_t)sc->pst_creg.pr_gas.Address);
472 	}
473 
474 	/* Save and try allocating status register */
475 	error = acpi_pst_alloc_resource(dev, obj, 1, &sc->pst_sreg);
476 	if (error) {
477 		AcpiOsFree(obj);
478 		return error;
479 	}
480 	if (bootverbose) {
481 		device_printf(dev, "status reg %d %jx\n",
482 			      sc->pst_sreg.pr_gas.SpaceId,
483 			      (uintmax_t)sc->pst_sreg.pr_gas.Address);
484 	}
485 
486 	/* Free _PCT */
487 	AcpiOsFree(obj);
488 
489 fetch_pss:
490 	/*
491 	 * Create P-State table according to _PSS
492 	 */
493 	buf.Pointer = NULL;
494 	buf.Length = ACPI_ALLOCATE_BUFFER;
495 	status = AcpiEvaluateObject(sc->pst_handle, "_PSS", NULL, &buf);
496 	if (ACPI_FAILURE(status)) {
497 		/*
498 		 * No _PSS.  See the comment in acpi_pst_probe() near
499 		 * _PSD check.
500 		 *
501 		 * Assume _PSS are same across all CPUs; well, they
502 		 * should/have to be so.
503 		 */
504 		if (acpi_npstates > 0 && acpi_pstates != NULL) {
505 			device_printf(dev, "No _PSS\n");
506 			goto fetch_ppc;
507 		}
508 		device_printf(dev, "Can't get _PSS package - %s\n",
509 			      AcpiFormatException(status));
510 		return ENXIO;
511 	}
512 
513 	obj = (ACPI_OBJECT *)buf.Pointer;
514 	if (!ACPI_PKG_VALID(obj, 1)) {
515 		device_printf(dev, "Invalid _PSS package\n");
516 		AcpiOsFree(obj);
517 		return ENXIO;
518 	}
519 
520 	/* Don't create too many P-States */
521 	npstate = obj->Package.Count;
522 	if (npstate > ACPI_NPSTATE_MAX) {
523 		device_printf(dev, "Too many P-States, %d->%d\n",
524 			      npstate, ACPI_NPSTATE_MAX);
525 		npstate = ACPI_NPSTATE_MAX;
526 	}
527 
528 	/*
529 	 * If we have already created P-State table,
530 	 * we must make sure that number of entries
531 	 * is consistent.
532 	 */
533 	if (acpi_pstates != NULL && acpi_npstates != npstate) {
534 		device_printf(dev, "Inconsistent # of P-States "
535 			      "cross Processor objects\n");
536 		AcpiOsFree(obj);
537 		return ENXIO;
538 	}
539 
540 	/*
541 	 * Create a temporary P-State table
542 	 */
543 	pstate = kmalloc(sizeof(*pstate) * npstate, M_TEMP, M_WAITOK);
544 	for (i = 0, p = pstate; i < npstate; ++i, ++p) {
545 		ACPI_OBJECT *pkg;
546 		uint32_t *ptr[ACPI_PSS_PX_NENTRY] = {
547 			&p->st_freq, &p->st_power, &p->st_xsit_lat,
548 			&p->st_bm_lat, &p->st_cval, &p->st_sval
549 		};
550 		int j;
551 
552 		pkg = &obj->Package.Elements[i];
553 		if (!ACPI_PKG_VALID(pkg, ACPI_PSS_PX_NENTRY)) {
554 			device_printf(dev, "Invalud _PSS P%d\n", i);
555 			AcpiOsFree(obj);
556 			kfree(pstate, M_TEMP);
557 			return ENXIO;
558 		}
559 		for (j = 0; j < ACPI_PSS_PX_NENTRY; ++j) {
560 			if (acpi_PkgInt32(pkg, j, ptr[j]) != 0) {
561 				device_printf(dev, "Can't extract "
562 					      "_PSS P%d %dth entry\n", i, j);
563 				AcpiOsFree(obj);
564 				kfree(pstate, M_TEMP);
565 				return ENXIO;
566 			}
567 		}
568 	}
569 
570 	/* Free _PSS */
571 	AcpiOsFree(obj);
572 
573 	if (acpi_pstates == NULL) {
574 		/*
575 		 * If no P-State table is created yet,
576 		 * save the temporary one we just created.
577 		 */
578 		acpi_pstates = pstate;
579 		acpi_npstates = npstate;
580 		pstate = NULL;
581 
582 		if (bootverbose) {
583 			for (i = 0; i < acpi_npstates; ++i) {
584 				device_printf(dev,
585 				"freq %u, pwr %u, xlat %u, blat %u, "
586 				"cv %08x, sv %08x\n",
587 				acpi_pstates[i].st_freq,
588 				acpi_pstates[i].st_power,
589 				acpi_pstates[i].st_xsit_lat,
590 				acpi_pstates[i].st_bm_lat,
591 				acpi_pstates[i].st_cval,
592 				acpi_pstates[i].st_sval);
593 			}
594 		}
595 	} else {
596 		/*
597 		 * Make sure that P-State tables are same
598 		 * for all processors.
599 		 */
600 		if (memcmp(pstate, acpi_pstates,
601 			   sizeof(*pstate) * npstate) != 0) {
602 			device_printf(dev, "Inconsistent _PSS "
603 				      "cross Processor objects\n");
604 			kfree(pstate, M_TEMP);
605 			return ENXIO;
606 		}
607 		kfree(pstate, M_TEMP);
608 	}
609 
610 fetch_ppc:
611 	/* By default, we start from P-State table's first entry */
612 	sc->pst_sstart = 0;
613 
614 	/*
615 	 * Adjust the usable first entry of P-State table,
616 	 * if there is _PPC object.
617 	 */
618 	buf.Pointer = NULL;
619 	buf.Length = ACPI_ALLOCATE_BUFFER;
620 	status = AcpiEvaluateObject(sc->pst_handle, "_PPC", NULL, &buf);
621 	if (!ACPI_FAILURE(status)) {
622 		obj = (ACPI_OBJECT *)buf.Pointer;
623 		if (obj->Type == ACPI_TYPE_INTEGER) {
624 			if (obj->Integer.Value >= acpi_npstates) {
625 				device_printf(dev, "Invalid _PPC value\n");
626 				AcpiOsFree(obj);
627 				return ENXIO;
628 			}
629 			sc->pst_sstart = obj->Integer.Value;
630 			if (bootverbose)
631 				device_printf(dev, "_PPC %d\n", sc->pst_sstart);
632 
633 			/* TODO: Install notifiy handler */
634 		} else {
635 			device_printf(dev, "Invalid _PPC object\n");
636 			AcpiOsFree(obj);
637 			return ENXIO;
638 		}
639 
640 		/* Free _PPC */
641 		AcpiOsFree(obj);
642 	}
643 
644 	sc->pst_state = sc->pst_sstart;
645 
646 	/* Link us with the domain */
647 	sc->pst_domain = dom;
648 	LIST_INSERT_HEAD(&dom->pd_pstlist, sc, pst_link);
649 
650 	if (device_get_unit(dev) == 0)
651 		AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_pst_postattach, NULL);
652 
653 	return 0;
654 }
655 
656 static struct acpi_pst_domain *
657 acpi_pst_domain_create_pkg(device_t dev, ACPI_OBJECT *obj)
658 {
659 	struct acpi_pst_domain *dom;
660 	uint32_t val, domain, coord, nproc;
661 
662 	if (!ACPI_PKG_VALID_EQ(obj, 5)) {
663 		device_printf(dev, "Invalid _PSD package\n");
664 		return NULL;
665 	}
666 
667 	/* NumberOfEntries */
668 	if (acpi_PkgInt32(obj, 0, &val) != 0 || val != 5) {
669 		device_printf(dev, "Invalid _PSD NumberOfEntries\n");
670 		return NULL;
671 	}
672 
673 	/* Revision */
674 	if (acpi_PkgInt32(obj, 1, &val) != 0 || val != 0) {
675 		device_printf(dev, "Invalid _PSD Revision\n");
676 		return NULL;
677 	}
678 
679 	if (acpi_PkgInt32(obj, 2, &domain) != 0 ||
680 	    acpi_PkgInt32(obj, 3, &coord) != 0 ||
681 	    acpi_PkgInt32(obj, 4, &nproc) != 0) {
682 		device_printf(dev, "Can't extract _PSD package\n");
683 		return NULL;
684 	}
685 
686 	if (!ACPI_PSD_COORD_VALID(coord)) {
687 		device_printf(dev, "Invalid _PSD CoordType (%#x)\n", coord);
688 		return NULL;
689 	}
690 
691 	if (nproc > MAXCPU) {
692 		/*
693 		 * If NumProcessors is greater than MAXCPU
694 		 * and domain's coordination is SWALL, then
695 		 * we will never be able to start all CPUs
696 		 * within this domain, and power state
697 		 * transition will never be completed, so we
698 		 * just bail out here.
699 		 */
700 		if (coord == ACPI_PSD_COORD_SWALL) {
701 			device_printf(dev, "Unsupported _PSD NumProcessors "
702 				      "(%d)\n", nproc);
703 			return NULL;
704 		}
705 	} else if (nproc == 0) {
706 		device_printf(dev, "_PSD NumProcessors are zero\n");
707 		return NULL;
708 	}
709 
710 	dom = acpi_pst_domain_find(domain);
711 	if (dom != NULL) {
712 		if (dom->pd_flags & ACPI_PSTDOM_FLAG_INT) {
713 			device_printf(dev, "Mixed Integer _PSD and "
714 			    "Package _PSD\n");
715 			return NULL;
716 		}
717 		if (dom->pd_coord != coord) {
718 			device_printf(dev, "Inconsistent _PSD coord "
719 			    "information cross Processor objects\n");
720 			return NULL;
721 		}
722 		if (dom->pd_nproc != nproc) {
723 			device_printf(dev, "Inconsistent _PSD nproc "
724 			    "information cross Processor objects\n");
725 			/*
726 			 * Some stupid BIOSes will set wrong "# of processors",
727 			 * e.g. 1 for CPU w/ hyperthreading; Be lenient here.
728 			 */
729 		}
730 		return dom;
731 	}
732 
733 	dom = acpi_pst_domain_alloc(domain, coord, nproc);
734 	if (bootverbose) {
735 		device_printf(dev, "create pkg domain%u, coord %#x\n",
736 		    dom->pd_dom, dom->pd_coord);
737 	}
738 
739 	return dom;
740 }
741 
742 static struct acpi_pst_domain *
743 acpi_pst_domain_create_int(device_t dev, uint32_t domain)
744 {
745 	struct acpi_pst_domain *dom;
746 
747 	dom = acpi_pst_domain_find(domain);
748 	if (dom != NULL) {
749 		if ((dom->pd_flags & ACPI_PSTDOM_FLAG_INT) == 0) {
750 			device_printf(dev, "Mixed Package _PSD and "
751 			    "Integer _PSD\n");
752 			return NULL;
753 		}
754 		KKASSERT(dom->pd_coord == ACPI_PSD_COORD_SWALL);
755 
756 		dom->pd_nproc++;
757 		return dom;
758 	}
759 
760 	dom = acpi_pst_domain_alloc(domain, ACPI_PSD_COORD_SWALL, 1);
761 	dom->pd_flags |= ACPI_PSTDOM_FLAG_INT;
762 
763 	if (bootverbose)
764 		device_printf(dev, "create int domain%u\n", dom->pd_dom);
765 
766 	return dom;
767 }
768 
769 static struct acpi_pst_domain *
770 acpi_pst_domain_find(uint32_t domain)
771 {
772 	struct acpi_pst_domain *dom;
773 
774 	LIST_FOREACH(dom, &acpi_pst_domains, pd_link) {
775 		if (dom->pd_flags & ACPI_PSTDOM_FLAG_STUB)
776 			continue;
777 		if (dom->pd_dom == domain)
778 			return dom;
779 	}
780 	return NULL;
781 }
782 
783 static struct acpi_pst_domain *
784 acpi_pst_domain_alloc(uint32_t domain, uint32_t coord, uint32_t nproc)
785 {
786 	struct acpi_pst_domain *dom;
787 
788 	dom = kmalloc(sizeof(*dom), M_DEVBUF, M_WAITOK | M_ZERO);
789 	dom->pd_dom = domain;
790 	dom->pd_coord = coord;
791 	dom->pd_nproc = nproc;
792 	dom->pd_state = 0; /* XXX */
793 	dom->pd_sstart = 0; /* XXX */
794 	LIST_INIT(&dom->pd_pstlist);
795 
796 	LIST_INSERT_HEAD(&acpi_pst_domains, dom, pd_link);
797 
798 	return dom;
799 }
800 
801 static int
802 acpi_pst_domain_set_pstate(struct acpi_pst_domain *dom, int i)
803 {
804 	const struct acpi_pstate *pstate;
805 	struct acpi_pst_softc *sc;
806 	int done, error;
807 
808 	KKASSERT(i >= 0 && i < acpi_npstates);
809 	pstate = &acpi_pstates[i];
810 
811 	done = 0;
812 	LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
813 		if (!done) {
814 			error = acpi_pst_set_pstate(sc, pstate);
815 			if (error) {
816 				device_printf(sc->pst_dev, "can't set "
817 					      "freq %d\n", pstate->st_freq);
818 				/* XXX error cleanup? */
819 			}
820 			if (dom->pd_coord == ACPI_PSD_COORD_SWANY)
821 				done = 1;
822 		}
823 		sc->pst_state = i;
824 	}
825 	dom->pd_state = i;
826 
827 	return 0;
828 }
829 
830 static int
831 acpi_pst_global_set_pstate(int i)
832 {
833 	struct acpi_pst_domain *dom;
834 
835 	LIST_FOREACH(dom, &acpi_pst_domains, pd_link) {
836 		/* Skip dead domain */
837 		if (dom->pd_flags & ACPI_PSTDOM_FLAG_DEAD)
838 			continue;
839 		acpi_pst_domain_set_pstate(dom, i);
840 	}
841 	acpi_pst_global_state = i;
842 
843 	return 0;
844 }
845 
846 static void
847 acpi_pst_postattach(void *arg __unused)
848 {
849 	struct acpi_pst_domain *dom;
850 	struct acpi_cpu_softc *cpu;
851 	device_t *devices;
852 	int i, ndevices, error, has_domain, sstate;
853 
854 	devices = NULL;
855 	ndevices = 0;
856 	error = devclass_get_devices(acpi_pst_devclass, &devices, &ndevices);
857 	if (error)
858 		return;
859 
860 	if (ndevices == 0)
861 		return;
862 
863 	cpu = NULL;
864 	for (i = 0; i < ndevices; ++i) {
865 		cpu = device_get_softc(device_get_parent(devices[i]));
866 		if (cpu->glob_sysctl_tree != NULL)
867 			break;
868 	}
869 	kfree(devices, M_TEMP);
870 	KKASSERT(cpu != NULL);
871 
872 	if (acpi_pst_md == NULL)
873 		kprintf("ACPI: no P-State CPU driver\n");
874 
875 	sstate = 0x7fffffff;
876 	has_domain = 0;
877 	LIST_FOREACH(dom, &acpi_pst_domains, pd_link) {
878 		struct acpi_pst_softc *sc;
879 		char buf[32];
880 
881 		/*
882 		 * Make sure that all processors belonging to this
883 		 * domain are located.
884 		 */
885 		i = 0;
886 		LIST_FOREACH(sc, &dom->pd_pstlist, pst_link)
887 			++i;
888 		if (i != dom->pd_nproc) {
889 			KKASSERT(i < dom->pd_nproc);
890 
891 			kprintf("ACPI: domain%u misses processors, "
892 				"should be %d, got %d\n", dom->pd_dom,
893 				dom->pd_nproc, i);
894 			if (dom->pd_coord == ACPI_PSD_COORD_SWALL) {
895 				/*
896 				 * If this domain's coordination is
897 				 * SWALL and we don't see all of the
898 				 * member CPUs of this domain, then
899 				 * the P-State transition will never
900 				 * be completed, so just leave this
901 				 * domain out.
902 				 */
903 				dom->pd_flags |= ACPI_PSTDOM_FLAG_DEAD;
904 				continue;
905 			}
906 			dom->pd_nproc = i;
907 		}
908 
909 		/*
910 		 * Validate P-State configurations for this domain
911 		 */
912 		LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
913 			error = acpi_pst_check_csr(sc);
914 			if (error)
915 				break;
916 
917 			error = acpi_pst_check_pstates(sc);
918 			if (error)
919 				break;
920 		}
921 		if (sc != NULL) {
922 			kprintf("ACPI: domain%u P-State configuration "
923 				"check failed\n", dom->pd_dom);
924 			dom->pd_flags |= ACPI_PSTDOM_FLAG_DEAD;
925 			continue;
926 		}
927 
928 		/*
929 		 * Do necssary P-State initialization
930 		 */
931 		LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
932 			error = acpi_pst_init(sc);
933 			if (error)
934 				break;
935 		}
936 		if (sc != NULL) {
937 			kprintf("ACPI: domain%u P-State initialization "
938 				"check failed\n", dom->pd_dom);
939 			dom->pd_flags |= ACPI_PSTDOM_FLAG_DEAD;
940 			continue;
941 		}
942 
943 		has_domain = 1;
944 
945 		ksnprintf(buf, sizeof(buf), "px_dom%u", dom->pd_dom);
946 
947 		sysctl_ctx_init(&dom->pd_sysctl_ctx);
948 		dom->pd_sysctl_tree =
949 		SYSCTL_ADD_NODE(&dom->pd_sysctl_ctx,
950 			SYSCTL_CHILDREN(cpu->glob_sysctl_tree),
951 			OID_AUTO, buf, CTLFLAG_RD, 0,
952 			"P-State domain");
953 		if (dom->pd_sysctl_tree == NULL) {
954 			kprintf("ACPI: Can't create sysctl tree for domain%u",
955 				dom->pd_dom);
956 			continue;
957 		}
958 
959 		SYSCTL_ADD_PROC(&dom->pd_sysctl_ctx,
960 				SYSCTL_CHILDREN(dom->pd_sysctl_tree),
961 				OID_AUTO, "available",
962 				CTLTYPE_STRING | CTLFLAG_RD,
963 				dom, 0, acpi_pst_sysctl_freqs, "A",
964 				"available frequencies");
965 
966 		SYSCTL_ADD_PROC(&dom->pd_sysctl_ctx,
967 				SYSCTL_CHILDREN(dom->pd_sysctl_tree),
968 				OID_AUTO, "members",
969 				CTLTYPE_STRING | CTLFLAG_RD,
970 				dom, 0, acpi_pst_sysctl_members, "A",
971 				"member cpus");
972 
973 		if (acpi_pst_md != NULL &&
974 		    acpi_pst_md->pmd_set_pstate != NULL) {
975 			SYSCTL_ADD_PROC(&dom->pd_sysctl_ctx,
976 					SYSCTL_CHILDREN(dom->pd_sysctl_tree),
977 					OID_AUTO, "select",
978 					CTLTYPE_UINT | CTLFLAG_RW,
979 					dom, 0, acpi_pst_sysctl_select,
980 					"IU", "select freq");
981 		}
982 
983 		if (dom->pd_state < sstate)
984 			sstate = dom->pd_state;
985 	}
986 
987 	if (has_domain && acpi_pst_md != NULL &&
988 	    acpi_pst_md->pmd_set_pstate != NULL) {
989 		SYSCTL_ADD_PROC(&cpu->glob_sysctl_ctx,
990 				SYSCTL_CHILDREN(cpu->glob_sysctl_tree),
991 				OID_AUTO, "px_global",
992 				CTLTYPE_UINT | CTLFLAG_RW,
993 				NULL, 0, acpi_pst_sysctl_global,
994 				"IU", "select freq for all domains");
995 
996 		acpi_pst_global_set_pstate(sstate);
997 	}
998 }
999 
1000 static int
1001 acpi_pst_sysctl_freqs(SYSCTL_HANDLER_ARGS)
1002 {
1003 	struct acpi_pst_domain *dom = arg1;
1004 	int i, error;
1005 
1006 	error = 0;
1007 	for (i = 0; i < acpi_npstates; ++i) {
1008 		if (error == 0 && i)
1009 			error = SYSCTL_OUT(req, " ", 1);
1010 		if (error == 0) {
1011 			const char *pat;
1012 			char buf[32];
1013 
1014 			if (i < dom->pd_sstart)
1015 				pat = "(%u)";
1016 			else
1017 				pat = "%u";
1018 
1019 			ksnprintf(buf, sizeof(buf), pat,
1020 				  acpi_pstates[i].st_freq);
1021 			error = SYSCTL_OUT(req, buf, strlen(buf));
1022 		}
1023 	}
1024 	return error;
1025 }
1026 
1027 static int
1028 acpi_pst_sysctl_members(SYSCTL_HANDLER_ARGS)
1029 {
1030 	struct acpi_pst_domain *dom = arg1;
1031 	struct acpi_pst_softc *sc;
1032 	int loop, error;
1033 
1034 	loop = error = 0;
1035 	LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
1036 		char buf[32];
1037 
1038 		if (error == 0 && loop)
1039 			error = SYSCTL_OUT(req, " ", 1);
1040 		if (error == 0) {
1041 			ksnprintf(buf, sizeof(buf), "cpu%d", sc->pst_cpuid);
1042 			error = SYSCTL_OUT(req, buf, strlen(buf));
1043 		}
1044 
1045 		if (error == 0 && acpi_pst_md && acpi_pst_md->pmd_get_pstate) {
1046 			const struct acpi_pstate *pstate;
1047 			const char *str;
1048 
1049 			pstate = acpi_pst_get_pstate(sc);
1050 			if (pstate == NULL) {
1051 				str = "(*)";
1052 			} else {
1053 				ksnprintf(buf, sizeof(buf), "(%d)",
1054 					  pstate->st_freq);
1055 				str = buf;
1056 			}
1057 			error = SYSCTL_OUT(req, str, strlen(str));
1058 		}
1059 		++loop;
1060 	}
1061 	return error;
1062 }
1063 
1064 static int
1065 acpi_pst_sysctl_select(SYSCTL_HANDLER_ARGS)
1066 {
1067 	struct acpi_pst_domain *dom = arg1;
1068 	int error, i, freq;
1069 
1070 	KKASSERT(dom->pd_state >= 0 && dom->pd_state < acpi_npstates);
1071 
1072 	freq = acpi_pstates[dom->pd_state].st_freq;
1073 
1074 	error = sysctl_handle_int(oidp, &freq, 0, req);
1075 	if (error || req->newptr == NULL)
1076 		return error;
1077 
1078 	i = acpi_pst_freq2index(freq);
1079 	if (i < 0)
1080 		return EINVAL;
1081 
1082 	acpi_pst_domain_set_pstate(dom, i);
1083 	return 0;
1084 }
1085 
1086 static int
1087 acpi_pst_sysctl_global(SYSCTL_HANDLER_ARGS)
1088 {
1089 	int error, i, freq;
1090 
1091 	KKASSERT(acpi_pst_global_state >= 0 &&
1092 		 acpi_pst_global_state < acpi_npstates);
1093 
1094 	freq = acpi_pstates[acpi_pst_global_state].st_freq;
1095 
1096 	error = sysctl_handle_int(oidp, &freq, 0, req);
1097 	if (error || req->newptr == NULL)
1098 		return error;
1099 
1100 	i = acpi_pst_freq2index(freq);
1101 	if (i < 0)
1102 		return EINVAL;
1103 
1104 	acpi_pst_global_set_pstate(i);
1105 
1106 	return 0;
1107 }
1108 
1109 static void
1110 acpi_pst_check_csr_handler(netmsg_t msg)
1111 {
1112 	struct netmsg_acpi_pst *rmsg = (struct netmsg_acpi_pst *)msg;
1113 	int error;
1114 
1115 	error = acpi_pst_md->pmd_check_csr(rmsg->ctrl, rmsg->status);
1116 	lwkt_replymsg(&rmsg->base.lmsg, error);
1117 }
1118 
1119 static int
1120 acpi_pst_check_csr(struct acpi_pst_softc *sc)
1121 {
1122 	struct netmsg_acpi_pst msg;
1123 
1124 	if (acpi_pst_md == NULL)
1125 		return 0;
1126 
1127 	netmsg_init(&msg.base, NULL, &curthread->td_msgport,
1128 		    MSGF_PRIORITY, acpi_pst_check_csr_handler);
1129 	msg.ctrl = &sc->pst_creg;
1130 	msg.status = &sc->pst_sreg;
1131 
1132 	return lwkt_domsg(netisr_cpuport(sc->pst_cpuid), &msg.base.lmsg, 0);
1133 }
1134 
1135 static void
1136 acpi_pst_check_pstates_handler(netmsg_t msg)
1137 {
1138 	int error;
1139 
1140 	error = acpi_pst_md->pmd_check_pstates(acpi_pstates, acpi_npstates);
1141 	lwkt_replymsg(&msg->lmsg, error);
1142 }
1143 
1144 static int
1145 acpi_pst_check_pstates(struct acpi_pst_softc *sc)
1146 {
1147 	struct netmsg_base msg;
1148 
1149 	if (acpi_pst_md == NULL)
1150 		return 0;
1151 
1152 	netmsg_init(&msg, NULL, &curthread->td_msgport,
1153 		    MSGF_PRIORITY, acpi_pst_check_pstates_handler);
1154 
1155 	return lwkt_domsg(netisr_cpuport(sc->pst_cpuid), &msg.lmsg, 0);
1156 }
1157 
1158 static void
1159 acpi_pst_init_handler(netmsg_t msg)
1160 {
1161 	struct netmsg_acpi_pst *rmsg = (struct netmsg_acpi_pst *)msg;
1162 	int error;
1163 
1164 	error = acpi_pst_md->pmd_init(rmsg->ctrl, rmsg->status);
1165 	lwkt_replymsg(&rmsg->base.lmsg, error);
1166 }
1167 
1168 static int
1169 acpi_pst_init(struct acpi_pst_softc *sc)
1170 {
1171 	struct netmsg_acpi_pst msg;
1172 
1173 	if (acpi_pst_md == NULL)
1174 		return 0;
1175 
1176 	netmsg_init(&msg.base, NULL, &curthread->td_msgport,
1177 		    MSGF_PRIORITY, acpi_pst_init_handler);
1178 	msg.ctrl = &sc->pst_creg;
1179 	msg.status = &sc->pst_sreg;
1180 
1181 	return lwkt_domsg(netisr_cpuport(sc->pst_cpuid), &msg.base.lmsg, 0);
1182 }
1183 
1184 static void
1185 acpi_pst_set_pstate_handler(netmsg_t msg)
1186 {
1187 	struct netmsg_acpi_pst *rmsg = (struct netmsg_acpi_pst *)msg;
1188 	int error;
1189 
1190 	error = acpi_pst_md->pmd_set_pstate(rmsg->ctrl, rmsg->status,
1191 					    rmsg->base.lmsg.u.ms_resultp);
1192 	lwkt_replymsg(&rmsg->base.lmsg, error);
1193 }
1194 
1195 static int
1196 acpi_pst_set_pstate(struct acpi_pst_softc *sc, const struct acpi_pstate *pstate)
1197 {
1198 	struct netmsg_acpi_pst msg;
1199 
1200 	KKASSERT(acpi_pst_md != NULL);
1201 
1202 	netmsg_init(&msg.base, NULL, &curthread->td_msgport,
1203 		    MSGF_PRIORITY, acpi_pst_set_pstate_handler);
1204 	msg.base.lmsg.u.ms_resultp = __DECONST(void *, pstate);
1205 	msg.ctrl = &sc->pst_creg;
1206 	msg.status = &sc->pst_sreg;
1207 
1208 	return lwkt_domsg(netisr_cpuport(sc->pst_cpuid), &msg.base.lmsg, 0);
1209 }
1210 
1211 static void
1212 acpi_pst_get_pstate_handler(netmsg_t msg)
1213 {
1214 	struct netmsg_acpi_pst *rmsg = (struct netmsg_acpi_pst *)msg;
1215 	const struct acpi_pstate *pstate;
1216 
1217 	pstate = acpi_pst_md->pmd_get_pstate(rmsg->status, acpi_pstates,
1218 					     acpi_npstates);
1219 	rmsg->base.lmsg.u.ms_resultp = __DECONST(void *, pstate);
1220 	lwkt_replymsg(&rmsg->base.lmsg, 0);
1221 }
1222 
1223 static const struct acpi_pstate *
1224 acpi_pst_get_pstate(struct acpi_pst_softc *sc)
1225 {
1226 	struct netmsg_acpi_pst msg;
1227 
1228 	if (acpi_pst_md == NULL)
1229 		return 0;
1230 
1231 	netmsg_init(&msg.base, NULL, &curthread->td_msgport,
1232 		    MSGF_PRIORITY, acpi_pst_get_pstate_handler);
1233 	msg.status = &sc->pst_sreg;
1234 
1235 	lwkt_domsg(netisr_cpuport(sc->pst_cpuid), &msg.base.lmsg, 0);
1236 	return msg.base.lmsg.u.ms_resultp;
1237 }
1238 
1239 static int
1240 acpi_pst_alloc_resource(device_t dev, ACPI_OBJECT *obj, int idx,
1241 			struct acpi_pst_res *res)
1242 {
1243 	struct acpi_pst_softc *sc = device_get_softc(dev);
1244 	int error, type;
1245 
1246 	/* Save GAS */
1247 	error = acpi_PkgRawGas(obj, idx, &res->pr_gas);
1248 	if (error)
1249 		return error;
1250 
1251 	/* Allocate resource, if possible */
1252 	res->pr_rid = sc->pst_parent->cpu_next_rid;
1253 	acpi_bus_alloc_gas(dev, &type, &res->pr_rid, &res->pr_gas, &res->pr_res, 0);
1254 	if (res->pr_res != NULL) {
1255 		sc->pst_parent->cpu_next_rid++;
1256 		res->pr_bt = rman_get_bustag(res->pr_res);
1257 		res->pr_bh = rman_get_bushandle(res->pr_res);
1258 	} else {
1259 		res->pr_rid = 0;
1260 	}
1261 	return 0;
1262 }
1263 
1264 static void
1265 acpi_pst_domain_check_nproc(device_t dev, struct acpi_pst_domain *dom)
1266 {
1267 	struct acpi_pst_softc *pst;
1268 	int i;
1269 
1270 	i = 0;
1271 	LIST_FOREACH(pst, &dom->pd_pstlist, pst_link)
1272 		++i;
1273 	if (i == dom->pd_nproc) {
1274 		/*
1275 		 * Some stupid BIOSes will set wrong "# of processors",
1276 		 * e.g. 1 for CPU w/ hyperthreading; Be lenient here.
1277 		 */
1278 		if (bootverbose) {
1279 			device_printf(dev, "domain%u already contains %d "
1280 			    "P-States\n", dom->pd_dom, dom->pd_nproc);
1281 		}
1282 		dom->pd_nproc++;
1283 	}
1284 	KKASSERT(i < dom->pd_nproc);
1285 }
1286