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