ipfw3: 'or' supports more filters
[dragonfly.git] / sys / dev / acpica / acpi_cpu_pstate.c
blob359c54fd8cf694904c03fe87014a8a4014568646
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:
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.
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.
35 #include "opt_acpi.h"
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>
47 #include <net/netisr2.h>
48 #include <net/netmsg2.h>
49 #include <net/if_var.h>
51 #include "acpi.h"
52 #include "acpivar.h"
53 #include "acpi_cpu.h"
54 #include "acpi_cpu_pstate.h"
56 #define ACPI_NPSTATE_MAX 32
58 #define ACPI_PSS_PX_NENTRY 6
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)
68 struct acpi_pst_softc;
69 LIST_HEAD(acpi_pst_list, acpi_pst_softc);
71 struct netmsg_acpi_pst {
72 struct netmsg_base base;
73 const struct acpi_pst_res *ctrl;
74 const struct acpi_pst_res *status;
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;
83 uint32_t pd_flags;
85 struct lwkt_serialize pd_serialize;
87 int pd_state;
88 struct acpi_pst_list pd_pstlist;
90 struct sysctl_ctx_list pd_sysctl_ctx;
91 struct sysctl_oid *pd_sysctl_tree;
93 LIST_HEAD(acpi_pst_domlist, acpi_pst_domain);
95 #define ACPI_PSTDOM_FLAG_STUB 0x1 /* stub domain, no _PSD */
96 #define ACPI_PSTDOM_FLAG_DEAD 0x2 /* domain can't be started */
97 #define ACPI_PSTDOM_FLAG_INT 0x4 /* domain created from Integer _PSD */
99 struct acpi_pst_softc {
100 device_t pst_dev;
101 struct acpi_cpu_softc *pst_parent;
102 struct acpi_pst_domain *pst_domain;
103 struct acpi_pst_res pst_creg;
104 struct acpi_pst_res pst_sreg;
106 int pst_state;
107 int pst_cpuid;
109 uint32_t pst_flags;
111 ACPI_HANDLE pst_handle;
113 LIST_ENTRY(acpi_pst_softc) pst_link;
116 #define ACPI_PST_FLAG_PPC 0x1
117 #define ACPI_PST_FLAG_PDL 0x2
119 static int acpi_pst_probe(device_t dev);
120 static int acpi_pst_attach(device_t dev);
121 static void acpi_pst_notify(device_t dev);
123 static void acpi_pst_postattach(void *);
124 static struct acpi_pst_domain *
125 acpi_pst_domain_create_int(device_t, uint32_t);
126 static struct acpi_pst_domain *
127 acpi_pst_domain_create_pkg(device_t, ACPI_OBJECT *);
128 static struct acpi_pst_domain *
129 acpi_pst_domain_find(uint32_t);
130 static struct acpi_pst_domain *
131 acpi_pst_domain_alloc(uint32_t, uint32_t, uint32_t);
132 static void acpi_pst_domain_set_pstate_locked(struct acpi_pst_domain *,
133 int, int *);
134 static void acpi_pst_domain_set_pstate(struct acpi_pst_domain *, int,
135 int *);
136 static void acpi_pst_domain_check_nproc(device_t, struct acpi_pst_domain *);
137 static void acpi_pst_global_set_pstate(int);
138 static void acpi_pst_global_fixup_pstate(void);
140 static int acpi_pst_check_csr(struct acpi_pst_softc *);
141 static int acpi_pst_check_pstates(struct acpi_pst_softc *);
142 static int acpi_pst_init(struct acpi_pst_softc *);
143 static int acpi_pst_set_pstate(struct acpi_pst_softc *,
144 const struct acpi_pstate *);
145 static const struct acpi_pstate *
146 acpi_pst_get_pstate(struct acpi_pst_softc *);
147 static int acpi_pst_alloc_resource(device_t, ACPI_OBJECT *, int,
148 struct acpi_pst_res *);
149 static int acpi_pst_eval_ppc(struct acpi_pst_softc *, int *);
150 static int acpi_pst_eval_pdl(struct acpi_pst_softc *, int *);
152 static void acpi_pst_check_csr_handler(netmsg_t);
153 static void acpi_pst_check_pstates_handler(netmsg_t);
154 static void acpi_pst_init_handler(netmsg_t);
155 static void acpi_pst_set_pstate_handler(netmsg_t);
156 static void acpi_pst_get_pstate_handler(netmsg_t);
158 static int acpi_pst_sysctl_freqs(SYSCTL_HANDLER_ARGS);
159 static int acpi_pst_sysctl_freqs_bin(SYSCTL_HANDLER_ARGS);
160 static int acpi_pst_sysctl_power(SYSCTL_HANDLER_ARGS);
161 static int acpi_pst_sysctl_members(SYSCTL_HANDLER_ARGS);
162 static int acpi_pst_sysctl_select(SYSCTL_HANDLER_ARGS);
163 static int acpi_pst_sysctl_global(SYSCTL_HANDLER_ARGS);
165 static struct acpi_pst_domlist acpi_pst_domains =
166 LIST_HEAD_INITIALIZER(acpi_pst_domains);
167 static int acpi_pst_domain_id;
169 static int acpi_pst_global_state;
171 static int acpi_pstate_start = -1;
172 static int acpi_pstate_count;
173 static int acpi_npstates;
174 static struct acpi_pstate *acpi_pstates;
176 static const struct acpi_pst_md *acpi_pst_md;
178 static int acpi_pst_pdl = -1;
179 TUNABLE_INT("hw.acpi.cpu.pst.pdl", &acpi_pst_pdl);
181 static int acpi_pst_ht_reuse_domain = 1;
182 TUNABLE_INT("hw.acpi.cpu.pst.ht_reuse_domain", &acpi_pst_ht_reuse_domain);
184 static int acpi_pst_force_pkg_domain = 0;
185 TUNABLE_INT("hw.acpi.cpu.pst.force_pkg_domain", &acpi_pst_force_pkg_domain);
187 static int acpi_pst_handle_notify = 1;
188 TUNABLE_INT("hw.acpi.cpu.pst.handle_notify", &acpi_pst_handle_notify);
191 * Force CPU package power domain for Intel CPUs.
193 * As of this write (14 July 2015), all Intel CPUs only have CPU package
194 * power domain.
196 static int acpi_pst_intel_pkg_domain = 1;
197 TUNABLE_INT("hw.acpi.cpu.pst.intel_pkg_domain", &acpi_pst_intel_pkg_domain);
199 static device_method_t acpi_pst_methods[] = {
200 /* Device interface */
201 DEVMETHOD(device_probe, acpi_pst_probe),
202 DEVMETHOD(device_attach, acpi_pst_attach),
203 DEVMETHOD(device_detach, bus_generic_detach),
204 DEVMETHOD(device_shutdown, bus_generic_shutdown),
205 DEVMETHOD(device_suspend, bus_generic_suspend),
206 DEVMETHOD(device_resume, bus_generic_resume),
208 /* Bus interface */
209 DEVMETHOD(bus_add_child, bus_generic_add_child),
210 DEVMETHOD(bus_print_child, bus_generic_print_child),
211 DEVMETHOD(bus_read_ivar, bus_generic_read_ivar),
212 DEVMETHOD(bus_write_ivar, bus_generic_write_ivar),
213 DEVMETHOD(bus_get_resource_list, bus_generic_get_resource_list),
214 DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
215 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
216 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
217 DEVMETHOD(bus_release_resource, bus_generic_release_resource),
218 DEVMETHOD(bus_driver_added, bus_generic_driver_added),
219 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
220 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
221 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
222 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
224 DEVMETHOD_END
227 static driver_t acpi_pst_driver = {
228 "cpu_pst",
229 acpi_pst_methods,
230 sizeof(struct acpi_pst_softc)
233 static devclass_t acpi_pst_devclass;
234 DRIVER_MODULE(cpu_pst, cpu, acpi_pst_driver, acpi_pst_devclass, NULL, NULL);
235 MODULE_DEPEND(cpu_pst, acpi, 1, 1, 1);
237 static __inline int
238 acpi_pst_freq2index(int freq)
240 int i;
242 for (i = 0; i < acpi_npstates; ++i) {
243 if (acpi_pstates[i].st_freq == freq)
244 return i;
246 return -1;
249 static int
250 acpi_pst_probe(device_t dev)
252 ACPI_BUFFER buf;
253 ACPI_HANDLE handle;
254 ACPI_STATUS status;
255 ACPI_OBJECT *obj;
257 if (acpi_disabled("cpu_pst") ||
258 acpi_get_type(dev) != ACPI_TYPE_PROCESSOR)
259 return ENXIO;
261 if (acpi_pst_md == NULL)
262 acpi_pst_md = acpi_pst_md_probe();
264 handle = acpi_get_handle(dev);
267 * Check _PSD package
269 * NOTE:
270 * Some BIOSes do not expose _PCT for the second thread of
271 * CPU cores. In this case, _PSD should be enough to get the
272 * P-state of the second thread working, since it must have
273 * the same _PCT and _PSS as the first thread in the same
274 * core.
276 buf.Pointer = NULL;
277 buf.Length = ACPI_ALLOCATE_BUFFER;
278 status = AcpiEvaluateObject(handle, "_PSD", NULL, &buf);
279 if (!ACPI_FAILURE(status)) {
280 AcpiOsFree((ACPI_OBJECT *)buf.Pointer);
281 goto done;
285 * Check _PCT package
287 buf.Pointer = NULL;
288 buf.Length = ACPI_ALLOCATE_BUFFER;
289 status = AcpiEvaluateObject(handle, "_PCT", NULL, &buf);
290 if (ACPI_FAILURE(status)) {
291 if (bootverbose) {
292 device_printf(dev, "Can't get _PCT package - %s\n",
293 AcpiFormatException(status));
295 return ENXIO;
298 obj = (ACPI_OBJECT *)buf.Pointer;
299 if (!ACPI_PKG_VALID_EQ(obj, 2)) {
300 device_printf(dev, "Invalid _PCT package\n");
301 AcpiOsFree(obj);
302 return ENXIO;
304 AcpiOsFree(obj);
307 * Check _PSS package
309 buf.Pointer = NULL;
310 buf.Length = ACPI_ALLOCATE_BUFFER;
311 status = AcpiEvaluateObject(handle, "_PSS", NULL, &buf);
312 if (ACPI_FAILURE(status)) {
313 device_printf(dev, "Can't get _PSS package - %s\n",
314 AcpiFormatException(status));
315 return ENXIO;
318 obj = (ACPI_OBJECT *)buf.Pointer;
319 if (!ACPI_PKG_VALID(obj, 1)) {
320 device_printf(dev, "Invalid _PSS package\n");
321 AcpiOsFree(obj);
322 return ENXIO;
324 AcpiOsFree(obj);
326 done:
327 device_set_desc(dev, "ACPI CPU P-State");
328 return 0;
331 static int
332 acpi_pst_attach(device_t dev)
334 struct acpi_pst_softc *sc = device_get_softc(dev);
335 struct acpi_pst_domain *dom = NULL;
336 ACPI_BUFFER buf;
337 ACPI_STATUS status;
338 ACPI_OBJECT *obj;
339 struct acpi_pstate *pstate, *p;
340 int i, npstate, error, sstart, scount;
342 sc->pst_dev = dev;
343 sc->pst_parent = device_get_softc(device_get_parent(dev));
344 sc->pst_handle = acpi_get_handle(dev);
345 sc->pst_cpuid = acpi_get_magic(dev);
348 * If there is a _PSD, then we create procossor domain
349 * accordingly. If there is no _PSD, we just fake a
350 * default processor domain0.
352 buf.Pointer = NULL;
353 buf.Length = ACPI_ALLOCATE_BUFFER;
354 status = AcpiEvaluateObject(sc->pst_handle, "_PSD", NULL, &buf);
355 if (!ACPI_FAILURE(status)) {
356 obj = (ACPI_OBJECT *)buf.Pointer;
358 if (acpi_pst_domain_id > 0) {
359 device_printf(dev, "Missing _PSD for certain CPUs\n");
360 AcpiOsFree(obj);
361 return ENXIO;
363 acpi_pst_domain_id = -1;
365 if (ACPI_PKG_VALID_EQ(obj, 1)) {
366 dom = acpi_pst_domain_create_pkg(dev,
367 &obj->Package.Elements[0]);
368 if (dom == NULL) {
369 AcpiOsFree(obj);
370 return ENXIO;
372 } else {
373 if (obj->Type != ACPI_TYPE_INTEGER) {
374 device_printf(dev,
375 "Invalid _PSD package, Type 0x%x\n",
376 obj->Type);
377 AcpiOsFree(obj);
378 return ENXIO;
379 } else {
380 device_printf(dev, "Integer _PSD %ju\n",
381 (uintmax_t)obj->Integer.Value);
382 dom = acpi_pst_domain_create_int(dev,
383 obj->Integer.Value);
384 if (dom == NULL) {
385 AcpiOsFree(obj);
386 return ENXIO;
391 /* Free _PSD */
392 AcpiOsFree(buf.Pointer);
393 } else {
394 if (acpi_pst_domain_id < 0) {
395 device_printf(dev, "Missing _PSD for cpu%d\n",
396 sc->pst_cpuid);
397 return ENXIO;
401 * Create a stub one processor domain for each processor
403 dom = acpi_pst_domain_alloc(acpi_pst_domain_id,
404 ACPI_PSD_COORD_SWANY, 1);
405 dom->pd_flags |= ACPI_PSTDOM_FLAG_STUB;
407 ++acpi_pst_domain_id;
410 /* Make sure that adding us will not overflow our domain */
411 acpi_pst_domain_check_nproc(dev, dom);
414 * Get control/status registers from _PCT
416 buf.Pointer = NULL;
417 buf.Length = ACPI_ALLOCATE_BUFFER;
418 status = AcpiEvaluateObject(sc->pst_handle, "_PCT", NULL, &buf);
419 if (ACPI_FAILURE(status)) {
420 struct acpi_pst_softc *pst;
423 * No _PCT. See the comment in acpi_pst_probe() near
424 * _PSD check.
426 * Use control/status registers of another CPU in the
427 * same domain, or in the same core, if the type of
428 * these registers are "Fixed Hardware", e.g. on most
429 * of the model Intel CPUs.
431 pst = LIST_FIRST(&dom->pd_pstlist);
432 if (pst == NULL) {
433 cpumask_t mask;
435 mask = get_cpumask_from_level(sc->pst_cpuid,
436 CORE_LEVEL);
437 if (CPUMASK_TESTNZERO(mask)) {
438 struct acpi_pst_domain *dom1;
440 LIST_FOREACH(dom1, &acpi_pst_domains, pd_link) {
441 LIST_FOREACH(pst, &dom1->pd_pstlist,
442 pst_link) {
443 if (CPUMASK_TESTBIT(mask,
444 pst->pst_cpuid))
445 break;
447 if (pst != NULL)
448 break;
450 if (pst != NULL && acpi_pst_ht_reuse_domain) {
452 * Use the same domain for CPUs in the
453 * same core.
455 device_printf(dev, "Destroy domain%u, "
456 "reuse domain%u\n",
457 dom->pd_dom, dom1->pd_dom);
458 LIST_REMOVE(dom, pd_link);
459 kfree(dom, M_DEVBUF);
460 dom = dom1;
462 * Make sure that adding us will not
463 * overflow the domain containing
464 * siblings in the same core.
466 acpi_pst_domain_check_nproc(dev, dom);
470 if (pst != NULL &&
471 pst->pst_creg.pr_res == NULL &&
472 pst->pst_creg.pr_rid == 0 &&
473 pst->pst_creg.pr_gas.SpaceId ==
474 ACPI_ADR_SPACE_FIXED_HARDWARE &&
475 pst->pst_sreg.pr_res == NULL &&
476 pst->pst_sreg.pr_rid == 0 &&
477 pst->pst_sreg.pr_gas.SpaceId ==
478 ACPI_ADR_SPACE_FIXED_HARDWARE) {
479 sc->pst_creg = pst->pst_creg;
480 sc->pst_sreg = pst->pst_sreg;
481 device_printf(dev,
482 "No _PCT; reuse %s control/status regs\n",
483 device_get_nameunit(pst->pst_dev));
484 goto fetch_pss;
486 device_printf(dev, "Can't get _PCT package - %s\n",
487 AcpiFormatException(status));
488 return ENXIO;
491 obj = (ACPI_OBJECT *)buf.Pointer;
492 if (!ACPI_PKG_VALID_EQ(obj, 2)) {
493 device_printf(dev, "Invalid _PCT package\n");
494 AcpiOsFree(obj);
495 return ENXIO;
498 /* Save and try allocating control register */
499 error = acpi_pst_alloc_resource(dev, obj, 0, &sc->pst_creg);
500 if (error) {
501 AcpiOsFree(obj);
502 return error;
504 if (bootverbose) {
505 device_printf(dev, "control reg %d %jx\n",
506 sc->pst_creg.pr_gas.SpaceId,
507 (uintmax_t)sc->pst_creg.pr_gas.Address);
510 /* Save and try allocating status register */
511 error = acpi_pst_alloc_resource(dev, obj, 1, &sc->pst_sreg);
512 if (error) {
513 AcpiOsFree(obj);
514 return error;
516 if (bootverbose) {
517 device_printf(dev, "status reg %d %jx\n",
518 sc->pst_sreg.pr_gas.SpaceId,
519 (uintmax_t)sc->pst_sreg.pr_gas.Address);
522 /* Free _PCT */
523 AcpiOsFree(obj);
525 fetch_pss:
527 * Create P-State table according to _PSS
529 buf.Pointer = NULL;
530 buf.Length = ACPI_ALLOCATE_BUFFER;
531 status = AcpiEvaluateObject(sc->pst_handle, "_PSS", NULL, &buf);
532 if (ACPI_FAILURE(status)) {
534 * No _PSS. See the comment in acpi_pst_probe() near
535 * _PSD check.
537 * Assume _PSS are same across all CPUs; well, they
538 * should/have to be so.
540 if (acpi_npstates > 0 && acpi_pstates != NULL) {
541 device_printf(dev, "No _PSS\n");
542 goto fetch_ppc;
544 device_printf(dev, "Can't get _PSS package - %s\n",
545 AcpiFormatException(status));
546 return ENXIO;
549 obj = (ACPI_OBJECT *)buf.Pointer;
550 if (!ACPI_PKG_VALID(obj, 1)) {
551 device_printf(dev, "Invalid _PSS package\n");
552 AcpiOsFree(obj);
553 return ENXIO;
556 /* Don't create too many P-States */
557 npstate = obj->Package.Count;
558 if (npstate > ACPI_NPSTATE_MAX) {
559 device_printf(dev, "Too many P-States, %d->%d\n",
560 npstate, ACPI_NPSTATE_MAX);
561 npstate = ACPI_NPSTATE_MAX;
565 * If we have already created P-State table,
566 * we must make sure that number of entries
567 * is consistent.
569 if (acpi_pstates != NULL && acpi_npstates != npstate) {
570 device_printf(dev, "Inconsistent # of P-States "
571 "cross Processor objects\n");
572 AcpiOsFree(obj);
573 return ENXIO;
577 * Create a temporary P-State table
579 pstate = kmalloc(sizeof(*pstate) * npstate, M_TEMP, M_WAITOK);
580 for (i = 0, p = pstate; i < npstate; ++i, ++p) {
581 ACPI_OBJECT *pkg;
582 uint32_t *ptr[ACPI_PSS_PX_NENTRY] = {
583 &p->st_freq, &p->st_power, &p->st_xsit_lat,
584 &p->st_bm_lat, &p->st_cval, &p->st_sval
586 int j;
588 pkg = &obj->Package.Elements[i];
589 if (!ACPI_PKG_VALID(pkg, ACPI_PSS_PX_NENTRY)) {
590 device_printf(dev, "Invalud _PSS P%d\n", i);
591 AcpiOsFree(obj);
592 kfree(pstate, M_TEMP);
593 return ENXIO;
595 for (j = 0; j < ACPI_PSS_PX_NENTRY; ++j) {
596 if (acpi_PkgInt32(pkg, j, ptr[j]) != 0) {
597 device_printf(dev, "Can't extract "
598 "_PSS P%d %dth entry\n", i, j);
599 AcpiOsFree(obj);
600 kfree(pstate, M_TEMP);
601 return ENXIO;
606 /* Free _PSS */
607 AcpiOsFree(obj);
609 if (acpi_pstates == NULL) {
611 * If no P-State table is created yet,
612 * save the temporary one we just created.
614 acpi_pstates = pstate;
615 acpi_npstates = npstate;
616 pstate = NULL;
618 if (bootverbose) {
619 for (i = 0; i < acpi_npstates; ++i) {
620 device_printf(dev,
621 "freq %u, pwr %u, xlat %u, blat %u, "
622 "cv %08x, sv %08x\n",
623 acpi_pstates[i].st_freq,
624 acpi_pstates[i].st_power,
625 acpi_pstates[i].st_xsit_lat,
626 acpi_pstates[i].st_bm_lat,
627 acpi_pstates[i].st_cval,
628 acpi_pstates[i].st_sval);
631 } else {
633 * Make sure that P-State tables are same
634 * for all processors.
636 if (memcmp(pstate, acpi_pstates,
637 sizeof(*pstate) * npstate) != 0) {
638 device_printf(dev, "Inconsistent _PSS "
639 "cross Processor objects\n");
640 #if 0
642 * Some BIOSes create different P-State tables;
643 * just trust the one from the BSP and move on.
645 kfree(pstate, M_TEMP);
646 return ENXIO;
647 #endif
649 kfree(pstate, M_TEMP);
652 fetch_ppc:
653 /* By default, we start from P-State table's first entry */
654 sstart = 0;
657 * Adjust the usable first entry of P-State table,
658 * if there is _PPC object.
660 error = acpi_pst_eval_ppc(sc, &sstart);
661 if (error && error != ENOENT)
662 return error;
663 else if (!error)
664 sc->pst_flags |= ACPI_PST_FLAG_PPC;
665 if (acpi_pstate_start < 0) {
666 acpi_pstate_start = sstart;
667 } else if (acpi_pstate_start != sstart) {
668 device_printf(dev, "_PPC mismatch, was %d, now %d\n",
669 acpi_pstate_start, sstart);
670 if (acpi_pstate_start < sstart) {
671 device_printf(dev, "_PPC %d -> %d\n",
672 acpi_pstate_start, sstart);
673 acpi_pstate_start = sstart;
678 * By default, we assume number of usable P-States is same as
679 * number of P-States.
681 scount = acpi_npstates;
684 * Allow users to override or set _PDL
686 if (acpi_pst_pdl >= 0) {
687 if (acpi_pst_pdl < acpi_npstates) {
688 if (bootverbose) {
689 device_printf(dev, "_PDL override %d\n",
690 acpi_pst_pdl);
692 scount = acpi_pst_pdl + 1;
693 goto proc_pdl;
694 } else {
695 device_printf(dev, "Invalid _PDL override %d, "
696 "must be less than %d\n", acpi_pst_pdl,
697 acpi_npstates);
702 * Adjust the number of usable entries in P-State table,
703 * if there is _PDL object.
705 error = acpi_pst_eval_pdl(sc, &scount);
706 if (error && error != ENOENT)
707 return error;
708 else if (!error)
709 sc->pst_flags |= ACPI_PST_FLAG_PDL;
710 proc_pdl:
711 if (acpi_pstate_count == 0) {
712 acpi_pstate_count = scount;
713 } else if (acpi_pstate_count != scount) {
714 device_printf(dev, "_PDL mismatch, was %d, now %d\n",
715 acpi_pstate_count, scount);
716 if (acpi_pstate_count > scount) {
717 device_printf(dev, "_PDL %d -> %d\n",
718 acpi_pstate_count, scount);
719 acpi_pstate_count = scount;
724 * Some CPUs only have package P-states, but some BIOSes put each
725 * hyperthread to its own P-state domain; allow user to override.
727 if (LIST_EMPTY(&dom->pd_pstlist) &&
728 (acpi_pst_force_pkg_domain ||
729 (cpu_vendor_id == CPU_VENDOR_INTEL &&
730 acpi_pst_intel_pkg_domain))) {
731 cpumask_t mask;
733 mask = get_cpumask_from_level(sc->pst_cpuid, CHIP_LEVEL);
734 if (CPUMASK_TESTNZERO(mask)) {
735 struct acpi_pst_softc *pst = NULL;
736 struct acpi_pst_domain *dom1;
738 LIST_FOREACH(dom1, &acpi_pst_domains, pd_link) {
739 LIST_FOREACH(pst, &dom1->pd_pstlist,
740 pst_link) {
741 if (CPUMASK_TESTBIT(mask,
742 pst->pst_cpuid))
743 break;
745 if (pst != NULL)
746 break;
748 if (pst != NULL &&
749 memcmp(&pst->pst_creg, &sc->pst_creg,
750 sizeof(sc->pst_creg)) == 0 &&
751 memcmp(&pst->pst_sreg, &sc->pst_sreg,
752 sizeof(sc->pst_sreg)) == 0) {
754 * Use the same domain for CPUs in the
755 * same package.
757 device_printf(dev, "Destroy domain%u, "
758 "force pkg domain%u\n",
759 dom->pd_dom, dom1->pd_dom);
760 LIST_REMOVE(dom, pd_link);
761 kfree(dom, M_DEVBUF);
762 dom = dom1;
764 * Make sure that adding us will not
765 * overflow the domain containing
766 * siblings in the same package.
768 acpi_pst_domain_check_nproc(dev, dom);
773 /* Link us with the domain */
774 sc->pst_domain = dom;
775 LIST_INSERT_HEAD(&dom->pd_pstlist, sc, pst_link);
777 if (device_get_unit(dev) == 0)
778 AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_pst_postattach, NULL);
780 if (sc->pst_flags & (ACPI_PST_FLAG_PPC | ACPI_PST_FLAG_PDL))
781 sc->pst_parent->cpu_pst_notify = acpi_pst_notify;
783 return 0;
786 static struct acpi_pst_domain *
787 acpi_pst_domain_create_pkg(device_t dev, ACPI_OBJECT *obj)
789 struct acpi_pst_domain *dom;
790 uint32_t val, domain, coord, nproc;
792 if (!ACPI_PKG_VALID_EQ(obj, 5)) {
793 device_printf(dev, "Invalid _PSD package\n");
794 return NULL;
797 /* NumberOfEntries */
798 if (acpi_PkgInt32(obj, 0, &val) != 0 || val != 5) {
799 device_printf(dev, "Invalid _PSD NumberOfEntries\n");
800 return NULL;
803 /* Revision */
804 if (acpi_PkgInt32(obj, 1, &val) != 0 || val != 0) {
805 device_printf(dev, "Invalid _PSD Revision\n");
806 return NULL;
809 if (acpi_PkgInt32(obj, 2, &domain) != 0 ||
810 acpi_PkgInt32(obj, 3, &coord) != 0 ||
811 acpi_PkgInt32(obj, 4, &nproc) != 0) {
812 device_printf(dev, "Can't extract _PSD package\n");
813 return NULL;
816 if (!ACPI_PSD_COORD_VALID(coord)) {
817 device_printf(dev, "Invalid _PSD CoordType (%#x)\n", coord);
818 return NULL;
821 if (nproc > MAXCPU) {
823 * If NumProcessors is greater than MAXCPU
824 * and domain's coordination is SWALL, then
825 * we will never be able to start all CPUs
826 * within this domain, and power state
827 * transition will never be completed, so we
828 * just bail out here.
830 if (coord == ACPI_PSD_COORD_SWALL) {
831 device_printf(dev, "Unsupported _PSD NumProcessors "
832 "(%d)\n", nproc);
833 return NULL;
835 } else if (nproc == 0) {
836 device_printf(dev, "_PSD NumProcessors are zero\n");
837 return NULL;
840 dom = acpi_pst_domain_find(domain);
841 if (dom != NULL) {
842 if (dom->pd_flags & ACPI_PSTDOM_FLAG_INT) {
843 device_printf(dev, "Mixed Integer _PSD and "
844 "Package _PSD\n");
845 return NULL;
847 if (dom->pd_coord != coord) {
848 device_printf(dev, "Inconsistent _PSD coord "
849 "information cross Processor objects\n");
850 return NULL;
852 if (dom->pd_nproc != nproc) {
853 device_printf(dev, "Inconsistent _PSD nproc "
854 "information cross Processor objects\n");
856 * Some stupid BIOSes will set wrong "# of processors",
857 * e.g. 1 for CPU w/ hyperthreading; Be lenient here.
860 return dom;
863 dom = acpi_pst_domain_alloc(domain, coord, nproc);
864 if (bootverbose) {
865 device_printf(dev, "create pkg domain%u, coord %#x\n",
866 dom->pd_dom, dom->pd_coord);
869 return dom;
872 static struct acpi_pst_domain *
873 acpi_pst_domain_create_int(device_t dev, uint32_t domain)
875 struct acpi_pst_domain *dom;
877 dom = acpi_pst_domain_find(domain);
878 if (dom != NULL) {
879 if ((dom->pd_flags & ACPI_PSTDOM_FLAG_INT) == 0) {
880 device_printf(dev, "Mixed Package _PSD and "
881 "Integer _PSD\n");
882 return NULL;
884 KKASSERT(dom->pd_coord == ACPI_PSD_COORD_SWALL);
886 dom->pd_nproc++;
887 return dom;
890 dom = acpi_pst_domain_alloc(domain, ACPI_PSD_COORD_SWALL, 1);
891 dom->pd_flags |= ACPI_PSTDOM_FLAG_INT;
893 if (bootverbose)
894 device_printf(dev, "create int domain%u\n", dom->pd_dom);
896 return dom;
899 static struct acpi_pst_domain *
900 acpi_pst_domain_find(uint32_t domain)
902 struct acpi_pst_domain *dom;
904 LIST_FOREACH(dom, &acpi_pst_domains, pd_link) {
905 if (dom->pd_flags & ACPI_PSTDOM_FLAG_STUB)
906 continue;
907 if (dom->pd_dom == domain)
908 return dom;
910 return NULL;
913 static struct acpi_pst_domain *
914 acpi_pst_domain_alloc(uint32_t domain, uint32_t coord, uint32_t nproc)
916 struct acpi_pst_domain *dom;
918 dom = kmalloc(sizeof(*dom), M_DEVBUF, M_WAITOK | M_ZERO);
919 dom->pd_dom = domain;
920 dom->pd_coord = coord;
921 dom->pd_nproc = nproc;
922 LIST_INIT(&dom->pd_pstlist);
923 lwkt_serialize_init(&dom->pd_serialize);
925 LIST_INSERT_HEAD(&acpi_pst_domains, dom, pd_link);
927 return dom;
930 static void
931 acpi_pst_domain_set_pstate_locked(struct acpi_pst_domain *dom, int i, int *global)
933 const struct acpi_pstate *pstate;
934 struct acpi_pst_softc *sc;
935 int done, error;
937 ASSERT_SERIALIZED(&dom->pd_serialize);
939 KKASSERT(i >= 0 && i < acpi_npstates);
940 pstate = &acpi_pstates[i];
942 done = 0;
943 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
944 if (!done) {
945 error = acpi_pst_set_pstate(sc, pstate);
946 if (error) {
947 device_printf(sc->pst_dev, "can't set "
948 "freq %d\n", pstate->st_freq);
949 /* XXX error cleanup? */
951 if (dom->pd_coord == ACPI_PSD_COORD_SWANY)
952 done = 1;
954 sc->pst_state = i;
956 dom->pd_state = i;
958 if (global != NULL)
959 *global = i;
962 static void
963 acpi_pst_domain_set_pstate(struct acpi_pst_domain *dom, int i, int *global)
965 lwkt_serialize_enter(&dom->pd_serialize);
966 acpi_pst_domain_set_pstate_locked(dom, i, global);
967 lwkt_serialize_exit(&dom->pd_serialize);
970 static void
971 acpi_pst_global_set_pstate(int i)
973 struct acpi_pst_domain *dom;
974 int *global = &acpi_pst_global_state;
976 LIST_FOREACH(dom, &acpi_pst_domains, pd_link) {
977 /* Skip dead domain */
978 if (dom->pd_flags & ACPI_PSTDOM_FLAG_DEAD)
979 continue;
980 acpi_pst_domain_set_pstate(dom, i, global);
981 global = NULL;
985 static void
986 acpi_pst_global_fixup_pstate(void)
988 struct acpi_pst_domain *dom;
989 int *global = &acpi_pst_global_state;
990 int sstart, scount;
992 sstart = acpi_pstate_start;
993 scount = acpi_pstate_count;
995 LIST_FOREACH(dom, &acpi_pst_domains, pd_link) {
996 int i = -1;
998 /* Skip dead domain */
999 if (dom->pd_flags & ACPI_PSTDOM_FLAG_DEAD)
1000 continue;
1002 lwkt_serialize_enter(&dom->pd_serialize);
1004 if (global != NULL) {
1005 if (*global < sstart)
1006 *global = sstart;
1007 else if (*global >= scount)
1008 *global = scount - 1;
1009 global = NULL;
1011 if (dom->pd_state < sstart)
1012 i = sstart;
1013 else if (dom->pd_state >= scount)
1014 i = scount - 1;
1015 if (i >= 0)
1016 acpi_pst_domain_set_pstate_locked(dom, i, NULL);
1018 lwkt_serialize_exit(&dom->pd_serialize);
1022 static void
1023 acpi_pst_postattach(void *arg __unused)
1025 struct acpi_pst_domain *dom;
1026 struct acpi_cpu_softc *cpu;
1027 device_t *devices;
1028 int i, ndevices, error, has_domain;
1030 devices = NULL;
1031 ndevices = 0;
1032 error = devclass_get_devices(acpi_pst_devclass, &devices, &ndevices);
1033 if (error)
1034 return;
1036 if (ndevices == 0)
1037 return;
1039 cpu = NULL;
1040 for (i = 0; i < ndevices; ++i) {
1041 cpu = device_get_softc(device_get_parent(devices[i]));
1042 if (cpu->glob_sysctl_tree != NULL)
1043 break;
1045 kfree(devices, M_TEMP);
1046 KKASSERT(cpu != NULL);
1048 if (acpi_pst_md == NULL)
1049 kprintf("ACPI: no P-State CPU driver\n");
1051 has_domain = 0;
1052 LIST_FOREACH(dom, &acpi_pst_domains, pd_link) {
1053 struct acpi_pst_softc *sc;
1054 char buf[32];
1056 dom->pd_state = acpi_pstate_start;
1059 * Make sure that all processors belonging to this
1060 * domain are located.
1062 i = 0;
1063 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
1064 sc->pst_state = acpi_pstate_start;
1065 ++i;
1067 if (i != dom->pd_nproc) {
1068 KKASSERT(i < dom->pd_nproc);
1070 kprintf("ACPI: domain%u misses processors, "
1071 "should be %d, got %d\n", dom->pd_dom,
1072 dom->pd_nproc, i);
1073 if (dom->pd_coord == ACPI_PSD_COORD_SWALL) {
1075 * If this domain's coordination is
1076 * SWALL and we don't see all of the
1077 * member CPUs of this domain, then
1078 * the P-State transition will never
1079 * be completed, so just leave this
1080 * domain out.
1082 dom->pd_flags |= ACPI_PSTDOM_FLAG_DEAD;
1083 continue;
1085 dom->pd_nproc = i;
1089 * Validate P-State configurations for this domain
1091 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
1092 error = acpi_pst_check_csr(sc);
1093 if (error)
1094 break;
1096 error = acpi_pst_check_pstates(sc);
1097 if (error)
1098 break;
1100 if (sc != NULL) {
1101 kprintf("ACPI: domain%u P-State configuration "
1102 "check failed\n", dom->pd_dom);
1103 dom->pd_flags |= ACPI_PSTDOM_FLAG_DEAD;
1104 continue;
1108 * Do necssary P-State initialization
1110 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
1111 error = acpi_pst_init(sc);
1112 if (error)
1113 break;
1115 if (sc != NULL) {
1116 kprintf("ACPI: domain%u P-State initialization "
1117 "check failed\n", dom->pd_dom);
1118 dom->pd_flags |= ACPI_PSTDOM_FLAG_DEAD;
1119 continue;
1122 has_domain = 1;
1124 ksnprintf(buf, sizeof(buf), "px_dom%u", dom->pd_dom);
1126 sysctl_ctx_init(&dom->pd_sysctl_ctx);
1127 dom->pd_sysctl_tree =
1128 SYSCTL_ADD_NODE(&dom->pd_sysctl_ctx,
1129 SYSCTL_CHILDREN(cpu->glob_sysctl_tree),
1130 OID_AUTO, buf, CTLFLAG_RD, 0,
1131 "P-State domain");
1132 if (dom->pd_sysctl_tree == NULL) {
1133 kprintf("ACPI: Can't create sysctl tree for domain%u",
1134 dom->pd_dom);
1135 continue;
1138 SYSCTL_ADD_PROC(&dom->pd_sysctl_ctx,
1139 SYSCTL_CHILDREN(dom->pd_sysctl_tree),
1140 OID_AUTO, "available",
1141 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_SKIP,
1142 dom, 0, acpi_pst_sysctl_freqs, "A",
1143 "available frequencies");
1145 SYSCTL_ADD_PROC(&dom->pd_sysctl_ctx,
1146 SYSCTL_CHILDREN(dom->pd_sysctl_tree),
1147 OID_AUTO, "avail",
1148 CTLTYPE_OPAQUE | CTLFLAG_RD,
1149 dom, 0, acpi_pst_sysctl_freqs_bin, "IU",
1150 "available frequencies");
1152 SYSCTL_ADD_PROC(&dom->pd_sysctl_ctx,
1153 SYSCTL_CHILDREN(dom->pd_sysctl_tree),
1154 OID_AUTO, "power",
1155 CTLTYPE_OPAQUE | CTLFLAG_RD,
1156 dom, 0, acpi_pst_sysctl_power, "IU",
1157 "power of available frequencies");
1159 SYSCTL_ADD_PROC(&dom->pd_sysctl_ctx,
1160 SYSCTL_CHILDREN(dom->pd_sysctl_tree),
1161 OID_AUTO, "members",
1162 CTLTYPE_STRING | CTLFLAG_RD,
1163 dom, 0, acpi_pst_sysctl_members, "A",
1164 "member cpus");
1166 if (acpi_pst_md != NULL &&
1167 acpi_pst_md->pmd_set_pstate != NULL) {
1168 SYSCTL_ADD_PROC(&dom->pd_sysctl_ctx,
1169 SYSCTL_CHILDREN(dom->pd_sysctl_tree),
1170 OID_AUTO, "select",
1171 CTLTYPE_UINT | CTLFLAG_RW,
1172 dom, 0, acpi_pst_sysctl_select,
1173 "IU", "select freq");
1177 if (has_domain && acpi_pst_md != NULL &&
1178 acpi_pst_md->pmd_set_pstate != NULL) {
1179 SYSCTL_ADD_PROC(&cpu->glob_sysctl_ctx,
1180 SYSCTL_CHILDREN(cpu->glob_sysctl_tree),
1181 OID_AUTO, "px_global",
1182 CTLTYPE_UINT | CTLFLAG_RW,
1183 NULL, 0, acpi_pst_sysctl_global,
1184 "IU", "select freq for all domains");
1185 SYSCTL_ADD_INT(&cpu->glob_sysctl_ctx,
1186 SYSCTL_CHILDREN(cpu->glob_sysctl_tree),
1187 OID_AUTO, "px_handle_notify", CTLFLAG_RW,
1188 &acpi_pst_handle_notify, 0,
1189 "handle type 0x80 notify");
1191 acpi_pst_global_set_pstate(acpi_pstate_start);
1195 static int
1196 acpi_pst_sysctl_freqs(SYSCTL_HANDLER_ARGS)
1198 int i, error, sstart, scount;
1200 error = 0;
1201 sstart = acpi_pstate_start;
1202 scount = acpi_pstate_count;
1203 for (i = 0; i < acpi_npstates; ++i) {
1204 if (error == 0 && i)
1205 error = SYSCTL_OUT(req, " ", 1);
1206 if (error == 0) {
1207 const char *pat;
1208 char buf[32];
1210 if (i < sstart || i >= scount)
1211 pat = "(%u)";
1212 else
1213 pat = "%u";
1215 ksnprintf(buf, sizeof(buf), pat,
1216 acpi_pstates[i].st_freq);
1217 error = SYSCTL_OUT(req, buf, strlen(buf));
1220 return error;
1223 static int
1224 acpi_pst_sysctl_freqs_bin(SYSCTL_HANDLER_ARGS)
1226 uint32_t freqs[ACPI_NPSTATE_MAX];
1227 int cnt, i, sstart, scount;
1229 sstart = acpi_pstate_start;
1230 scount = acpi_pstate_count;
1232 cnt = scount - sstart;
1233 for (i = 0; i < cnt; ++i)
1234 freqs[i] = acpi_pstates[sstart + i].st_freq;
1236 return sysctl_handle_opaque(oidp, freqs, cnt * sizeof(freqs[0]), req);
1239 static int
1240 acpi_pst_sysctl_power(SYSCTL_HANDLER_ARGS)
1242 uint32_t power[ACPI_NPSTATE_MAX];
1243 int cnt, i, sstart, scount;
1245 sstart = acpi_pstate_start;
1246 scount = acpi_pstate_count;
1248 cnt = scount - sstart;
1249 for (i = 0; i < cnt; ++i)
1250 power[i] = acpi_pstates[sstart + i].st_power;
1252 return sysctl_handle_opaque(oidp, power, cnt * sizeof(power[0]), req);
1255 static int
1256 acpi_pst_sysctl_members(SYSCTL_HANDLER_ARGS)
1258 struct acpi_pst_domain *dom = arg1;
1259 struct acpi_pst_softc *sc;
1260 int loop, error;
1262 loop = error = 0;
1263 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
1264 char buf[32];
1266 if (error == 0 && loop)
1267 error = SYSCTL_OUT(req, " ", 1);
1268 if (error == 0) {
1269 ksnprintf(buf, sizeof(buf), "cpu%d", sc->pst_cpuid);
1270 error = SYSCTL_OUT(req, buf, strlen(buf));
1273 if (error == 0 && acpi_pst_md && acpi_pst_md->pmd_get_pstate) {
1274 const struct acpi_pstate *pstate;
1275 const char *str;
1277 pstate = acpi_pst_get_pstate(sc);
1278 if (pstate == NULL) {
1279 str = "(*)";
1280 } else {
1281 ksnprintf(buf, sizeof(buf), "(%d)",
1282 pstate->st_freq);
1283 str = buf;
1285 error = SYSCTL_OUT(req, str, strlen(str));
1287 ++loop;
1289 return error;
1292 static int
1293 acpi_pst_sysctl_select(SYSCTL_HANDLER_ARGS)
1295 struct acpi_pst_domain *dom = arg1;
1296 int error, i, freq;
1298 KKASSERT(dom->pd_state >= 0 && dom->pd_state < acpi_npstates);
1300 freq = acpi_pstates[dom->pd_state].st_freq;
1302 error = sysctl_handle_int(oidp, &freq, 0, req);
1303 if (error || req->newptr == NULL)
1304 return error;
1306 i = acpi_pst_freq2index(freq);
1307 if (i < 0)
1308 return EINVAL;
1310 acpi_pst_domain_set_pstate(dom, i, NULL);
1311 return 0;
1314 static int
1315 acpi_pst_sysctl_global(SYSCTL_HANDLER_ARGS)
1317 int error, i, freq;
1319 KKASSERT(acpi_pst_global_state >= 0 &&
1320 acpi_pst_global_state < acpi_npstates);
1322 freq = acpi_pstates[acpi_pst_global_state].st_freq;
1324 error = sysctl_handle_int(oidp, &freq, 0, req);
1325 if (error || req->newptr == NULL)
1326 return error;
1328 i = acpi_pst_freq2index(freq);
1329 if (i < 0)
1330 return EINVAL;
1332 acpi_pst_global_set_pstate(i);
1334 return 0;
1337 static void
1338 acpi_pst_check_csr_handler(netmsg_t msg)
1340 struct netmsg_acpi_pst *rmsg = (struct netmsg_acpi_pst *)msg;
1341 int error;
1343 error = acpi_pst_md->pmd_check_csr(rmsg->ctrl, rmsg->status);
1344 lwkt_replymsg(&rmsg->base.lmsg, error);
1347 static int
1348 acpi_pst_check_csr(struct acpi_pst_softc *sc)
1350 struct netmsg_acpi_pst msg;
1352 if (acpi_pst_md == NULL)
1353 return 0;
1355 netmsg_init(&msg.base, NULL, &curthread->td_msgport,
1356 MSGF_PRIORITY, acpi_pst_check_csr_handler);
1357 msg.ctrl = &sc->pst_creg;
1358 msg.status = &sc->pst_sreg;
1360 return lwkt_domsg(netisr_cpuport(sc->pst_cpuid), &msg.base.lmsg, 0);
1363 static void
1364 acpi_pst_check_pstates_handler(netmsg_t msg)
1366 int error;
1368 error = acpi_pst_md->pmd_check_pstates(acpi_pstates, acpi_npstates);
1369 lwkt_replymsg(&msg->lmsg, error);
1372 static int
1373 acpi_pst_check_pstates(struct acpi_pst_softc *sc)
1375 struct netmsg_base msg;
1377 if (acpi_pst_md == NULL)
1378 return 0;
1380 netmsg_init(&msg, NULL, &curthread->td_msgport,
1381 MSGF_PRIORITY, acpi_pst_check_pstates_handler);
1383 return lwkt_domsg(netisr_cpuport(sc->pst_cpuid), &msg.lmsg, 0);
1386 static void
1387 acpi_pst_init_handler(netmsg_t msg)
1389 struct netmsg_acpi_pst *rmsg = (struct netmsg_acpi_pst *)msg;
1390 int error;
1392 error = acpi_pst_md->pmd_init(rmsg->ctrl, rmsg->status);
1393 lwkt_replymsg(&rmsg->base.lmsg, error);
1396 static int
1397 acpi_pst_init(struct acpi_pst_softc *sc)
1399 struct netmsg_acpi_pst msg;
1401 if (acpi_pst_md == NULL)
1402 return 0;
1404 netmsg_init(&msg.base, NULL, &curthread->td_msgport,
1405 MSGF_PRIORITY, acpi_pst_init_handler);
1406 msg.ctrl = &sc->pst_creg;
1407 msg.status = &sc->pst_sreg;
1409 return lwkt_domsg(netisr_cpuport(sc->pst_cpuid), &msg.base.lmsg, 0);
1412 static void
1413 acpi_pst_set_pstate_handler(netmsg_t msg)
1415 struct netmsg_acpi_pst *rmsg = (struct netmsg_acpi_pst *)msg;
1416 int error;
1418 error = acpi_pst_md->pmd_set_pstate(rmsg->ctrl, rmsg->status,
1419 rmsg->base.lmsg.u.ms_resultp);
1420 lwkt_replymsg(&rmsg->base.lmsg, error);
1423 static int
1424 acpi_pst_set_pstate(struct acpi_pst_softc *sc, const struct acpi_pstate *pstate)
1426 struct netmsg_acpi_pst msg;
1428 KKASSERT(acpi_pst_md != NULL);
1430 netmsg_init(&msg.base, NULL, &curthread->td_msgport,
1431 MSGF_PRIORITY, acpi_pst_set_pstate_handler);
1432 msg.base.lmsg.u.ms_resultp = __DECONST(void *, pstate);
1433 msg.ctrl = &sc->pst_creg;
1434 msg.status = &sc->pst_sreg;
1436 return lwkt_domsg(netisr_cpuport(sc->pst_cpuid), &msg.base.lmsg, 0);
1439 static void
1440 acpi_pst_get_pstate_handler(netmsg_t msg)
1442 struct netmsg_acpi_pst *rmsg = (struct netmsg_acpi_pst *)msg;
1443 const struct acpi_pstate *pstate;
1445 pstate = acpi_pst_md->pmd_get_pstate(rmsg->status, acpi_pstates,
1446 acpi_npstates);
1447 rmsg->base.lmsg.u.ms_resultp = __DECONST(void *, pstate);
1448 lwkt_replymsg(&rmsg->base.lmsg, 0);
1451 static const struct acpi_pstate *
1452 acpi_pst_get_pstate(struct acpi_pst_softc *sc)
1454 struct netmsg_acpi_pst msg;
1456 if (acpi_pst_md == NULL)
1457 return 0;
1459 netmsg_init(&msg.base, NULL, &curthread->td_msgport,
1460 MSGF_PRIORITY, acpi_pst_get_pstate_handler);
1461 msg.status = &sc->pst_sreg;
1463 lwkt_domsg(netisr_cpuport(sc->pst_cpuid), &msg.base.lmsg, 0);
1464 return msg.base.lmsg.u.ms_resultp;
1467 static int
1468 acpi_pst_alloc_resource(device_t dev, ACPI_OBJECT *obj, int idx,
1469 struct acpi_pst_res *res)
1471 struct acpi_pst_softc *sc = device_get_softc(dev);
1472 int error, type;
1474 /* Save GAS */
1475 error = acpi_PkgRawGas(obj, idx, &res->pr_gas);
1476 if (error)
1477 return error;
1479 /* Allocate resource, if possible */
1480 res->pr_rid = sc->pst_parent->cpu_next_rid;
1481 acpi_bus_alloc_gas(dev, &type, &res->pr_rid, &res->pr_gas, &res->pr_res, 0);
1482 if (res->pr_res != NULL) {
1483 sc->pst_parent->cpu_next_rid++;
1484 res->pr_bt = rman_get_bustag(res->pr_res);
1485 res->pr_bh = rman_get_bushandle(res->pr_res);
1486 } else {
1487 res->pr_rid = 0;
1489 return 0;
1492 static void
1493 acpi_pst_domain_check_nproc(device_t dev, struct acpi_pst_domain *dom)
1495 struct acpi_pst_softc *pst;
1496 int i;
1498 i = 0;
1499 LIST_FOREACH(pst, &dom->pd_pstlist, pst_link)
1500 ++i;
1501 if (i == dom->pd_nproc) {
1503 * Some stupid BIOSes will set wrong "# of processors",
1504 * e.g. 1 for CPU w/ hyperthreading; Be lenient here.
1506 if (bootverbose) {
1507 device_printf(dev, "domain%u already contains %d "
1508 "P-States\n", dom->pd_dom, dom->pd_nproc);
1510 dom->pd_nproc++;
1512 KKASSERT(i < dom->pd_nproc);
1515 static int
1516 acpi_pst_eval_ppc(struct acpi_pst_softc *sc, int *sstart)
1518 ACPI_BUFFER buf;
1519 ACPI_STATUS status;
1520 ACPI_OBJECT *obj;
1522 buf.Pointer = NULL;
1523 buf.Length = ACPI_ALLOCATE_BUFFER;
1524 status = AcpiEvaluateObject(sc->pst_handle, "_PPC", NULL, &buf);
1525 if (!ACPI_FAILURE(status)) {
1526 ACPI_OBJECT_LIST arglist;
1527 ACPI_OBJECT arg[2];
1529 obj = (ACPI_OBJECT *)buf.Pointer;
1530 if (obj->Type == ACPI_TYPE_INTEGER) {
1531 if (obj->Integer.Value >= acpi_npstates) {
1532 device_printf(sc->pst_dev,
1533 "Invalid _PPC value\n");
1534 AcpiOsFree(obj);
1535 return ENXIO;
1537 *sstart = obj->Integer.Value;
1538 if (bootverbose) {
1539 device_printf(sc->pst_dev, "_PPC %d\n",
1540 *sstart);
1542 } else {
1543 device_printf(sc->pst_dev, "Invalid _PPC object\n");
1544 AcpiOsFree(obj);
1545 return ENXIO;
1548 /* Free _PPC */
1549 AcpiOsFree(obj);
1551 /* _PPC has been successfully processed */
1552 arglist.Pointer = arg;
1553 arglist.Count = 2;
1554 arg[0].Type = ACPI_TYPE_INTEGER;
1555 arg[0].Integer.Value = 0x80;
1556 arg[1].Type = ACPI_TYPE_INTEGER;
1557 arg[1].Integer.Value = 0;
1558 AcpiEvaluateObject(sc->pst_handle, "_OST", &arglist, NULL);
1560 return 0;
1562 return ENOENT;
1565 static int
1566 acpi_pst_eval_pdl(struct acpi_pst_softc *sc, int *scount)
1568 ACPI_BUFFER buf;
1569 ACPI_STATUS status;
1570 ACPI_OBJECT *obj;
1572 buf.Pointer = NULL;
1573 buf.Length = ACPI_ALLOCATE_BUFFER;
1574 status = AcpiEvaluateObject(sc->pst_handle, "_PDL", NULL, &buf);
1575 if (!ACPI_FAILURE(status)) {
1576 obj = (ACPI_OBJECT *)buf.Pointer;
1577 if (obj->Type == ACPI_TYPE_INTEGER) {
1578 if (obj->Integer.Value >= acpi_npstates) {
1579 device_printf(sc->pst_dev,
1580 "Invalid _PDL value\n");
1581 AcpiOsFree(obj);
1582 return ENXIO;
1584 if (obj->Integer.Value >= acpi_pstate_start) {
1585 *scount = obj->Integer.Value + 1;
1586 if (bootverbose) {
1587 device_printf(sc->pst_dev, "_PDL %d\n",
1588 *scount);
1590 } else {
1591 /* Prefer _PPC as stated in ACPI 5.1 8.4.4.6 */
1592 device_printf(sc->pst_dev, "conflict _PDL %ju "
1593 "and _PPC %d, ignore\n",
1594 (uintmax_t)obj->Integer.Value,
1595 acpi_pstate_start);
1597 } else {
1598 device_printf(sc->pst_dev, "Invalid _PDL object\n");
1599 AcpiOsFree(obj);
1600 return ENXIO;
1603 /* Free _PDL */
1604 AcpiOsFree(obj);
1606 return 0;
1608 return ENOENT;
1612 * Notify is serialized by acpi task thread.
1614 static void
1615 acpi_pst_notify(device_t dev)
1617 struct acpi_pst_softc *sc = device_get_softc(dev);
1618 boolean_t fixup = FALSE;
1620 if (!acpi_pst_handle_notify)
1621 return;
1624 * NOTE:
1625 * _PPC and _PDL evaluation order is critical. _PDL
1626 * evaluation depends on _PPC evaluation.
1628 if (sc->pst_flags & ACPI_PST_FLAG_PPC) {
1629 int sstart = acpi_pstate_start;
1631 acpi_pst_eval_ppc(sc, &sstart);
1632 if (acpi_pstate_start != sstart && sc->pst_cpuid == 0) {
1633 acpi_pstate_start = sstart;
1634 fixup = TRUE;
1637 if (sc->pst_flags & ACPI_PST_FLAG_PDL) {
1638 int scount = acpi_pstate_count;
1640 acpi_pst_eval_pdl(sc, &scount);
1641 if (acpi_pstate_count != scount && sc->pst_cpuid == 0) {
1642 acpi_pstate_count = scount;
1643 fixup = TRUE;
1647 if (fixup && acpi_pst_md != NULL &&
1648 acpi_pst_md->pmd_set_pstate != NULL)
1649 acpi_pst_global_fixup_pstate();