2 * Copyright (c) 2009 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Sepherosa Ziehau <sepherosa@gmail.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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
37 #include <sys/param.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
41 #include <sys/queue.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>
54 #include "acpi_cpu_pstate.h"
56 #define ACPI_NPSTATE_MAX 16
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 {
81 LIST_ENTRY(acpi_pst_domain) pd_link;
87 struct acpi_pst_list pd_pstlist;
89 struct sysctl_ctx_list pd_sysctl_ctx;
90 struct sysctl_oid *pd_sysctl_tree;
92 LIST_HEAD(acpi_pst_domlist, acpi_pst_domain);
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 */
98 struct acpi_pst_softc {
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;
109 ACPI_HANDLE pst_handle;
111 LIST_ENTRY(acpi_pst_softc) pst_link;
114 static int acpi_pst_probe(device_t dev);
115 static int acpi_pst_attach(device_t dev);
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);
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 *);
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);
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);
151 static struct acpi_pst_domlist acpi_pst_domains =
152 LIST_HEAD_INITIALIZER(acpi_pst_domains);
153 static int acpi_pst_domain_id;
155 static int acpi_pst_global_state;
157 static int acpi_npstates;
158 static struct acpi_pstate *acpi_pstates;
160 static const struct acpi_pst_md *acpi_pst_md;
162 static int acpi_pst_ht_reuse_domain = 1;
163 TUNABLE_INT("hw.acpi.cpu.pst.ht_reuse_domain", &acpi_pst_ht_reuse_domain);
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),
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),
193 static driver_t acpi_pst_driver = {
196 sizeof(struct acpi_pst_softc)
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);
204 acpi_pst_freq2index(int freq)
208 for (i = 0; i < acpi_npstates; ++i) {
209 if (acpi_pstates[i].st_freq == freq)
216 acpi_pst_probe(device_t dev)
223 if (acpi_disabled("cpu_pst") ||
224 acpi_get_type(dev) != ACPI_TYPE_PROCESSOR)
227 if (acpi_pst_md == NULL)
228 acpi_pst_md = acpi_pst_md_probe();
230 handle = acpi_get_handle(dev);
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
243 buf.Length = ACPI_ALLOCATE_BUFFER;
244 status = AcpiEvaluateObject(handle, "_PSD", NULL, &buf);
245 if (!ACPI_FAILURE(status)) {
246 AcpiOsFree((ACPI_OBJECT *)buf.Pointer);
254 buf.Length = ACPI_ALLOCATE_BUFFER;
255 status = AcpiEvaluateObject(handle, "_PCT", NULL, &buf);
256 if (ACPI_FAILURE(status)) {
258 device_printf(dev, "Can't get _PCT package - %s\n",
259 AcpiFormatException(status));
264 obj = (ACPI_OBJECT *)buf.Pointer;
265 if (!ACPI_PKG_VALID_EQ(obj, 2)) {
266 device_printf(dev, "Invalid _PCT package\n");
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));
284 obj = (ACPI_OBJECT *)buf.Pointer;
285 if (!ACPI_PKG_VALID(obj, 1)) {
286 device_printf(dev, "Invalid _PSS package\n");
293 device_set_desc(dev, "ACPI CPU P-State");
298 acpi_pst_attach(device_t dev)
300 struct acpi_pst_softc *sc = device_get_softc(dev), *pst;
301 struct acpi_pst_domain *dom = NULL;
305 struct acpi_pstate *pstate, *p;
306 int i, npstate, error;
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);
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.
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;
324 if (acpi_pst_domain_id > 0) {
325 device_printf(dev, "Missing _PSD for certain CPUs\n");
329 acpi_pst_domain_id = -1;
331 if (ACPI_PKG_VALID_EQ(obj, 1)) {
332 dom = acpi_pst_domain_create_pkg(dev,
333 &obj->Package.Elements[0]);
339 if (obj->Type != ACPI_TYPE_INTEGER) {
341 "Invalid _PSD package, Type 0x%x\n",
346 device_printf(dev, "Integer _PSD %ju\n",
347 (uintmax_t)obj->Integer.Value);
348 dom = acpi_pst_domain_create_int(dev,
358 AcpiOsFree(buf.Pointer);
360 if (acpi_pst_domain_id < 0) {
361 device_printf(dev, "Missing _PSD for cpu%d\n",
367 * Create a stub one processor domain for each processor
369 dom = acpi_pst_domain_alloc(acpi_pst_domain_id,
370 ACPI_PSD_COORD_SWANY, 1);
371 dom->pd_flags |= ACPI_PSTDOM_FLAG_STUB;
373 ++acpi_pst_domain_id;
376 /* Make sure that adding us will not overflow our domain */
377 acpi_pst_domain_check_nproc(dev, dom);
380 * Get control/status registers from _PCT
383 buf.Length = ACPI_ALLOCATE_BUFFER;
384 status = AcpiEvaluateObject(sc->pst_handle, "_PCT", NULL, &buf);
385 if (ACPI_FAILURE(status)) {
387 * No _PCT. See the comment in acpi_pst_probe() near
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.
395 pst = LIST_FIRST(&dom->pd_pstlist);
399 mask = get_cpumask_from_level(sc->pst_cpuid,
401 if (CPUMASK_TESTNZERO(mask)) {
402 struct acpi_pst_domain *dom1;
404 LIST_FOREACH(dom1, &acpi_pst_domains, pd_link) {
405 LIST_FOREACH(pst, &dom1->pd_pstlist,
407 if (CPUMASK_TESTBIT(mask,
414 if (pst != NULL && acpi_pst_ht_reuse_domain) {
416 * Use the same domain for CPUs in the
419 device_printf(dev, "Destroy domain%u, "
421 dom->pd_dom, dom1->pd_dom);
422 LIST_REMOVE(dom, pd_link);
423 kfree(dom, M_DEVBUF);
426 * Make sure that adding us will not
427 * overflow the domain containing
428 * siblings in the same core.
430 acpi_pst_domain_check_nproc(dev, dom);
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;
446 "No _PCT; reuse %s control/status regs\n",
447 device_get_nameunit(pst->pst_dev));
450 device_printf(dev, "Can't get _PCT package - %s\n",
451 AcpiFormatException(status));
455 obj = (ACPI_OBJECT *)buf.Pointer;
456 if (!ACPI_PKG_VALID_EQ(obj, 2)) {
457 device_printf(dev, "Invalid _PCT package\n");
462 /* Save and try allocating control register */
463 error = acpi_pst_alloc_resource(dev, obj, 0, &sc->pst_creg);
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);
474 /* Save and try allocating status register */
475 error = acpi_pst_alloc_resource(dev, obj, 1, &sc->pst_sreg);
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);
491 * Create P-State table according to _PSS
494 buf.Length = ACPI_ALLOCATE_BUFFER;
495 status = AcpiEvaluateObject(sc->pst_handle, "_PSS", NULL, &buf);
496 if (ACPI_FAILURE(status)) {
498 * No _PSS. See the comment in acpi_pst_probe() near
501 * Assume _PSS are same across all CPUs; well, they
502 * should/have to be so.
504 if (acpi_npstates > 0 && acpi_pstates != NULL) {
505 device_printf(dev, "No _PSS\n");
508 device_printf(dev, "Can't get _PSS package - %s\n",
509 AcpiFormatException(status));
513 obj = (ACPI_OBJECT *)buf.Pointer;
514 if (!ACPI_PKG_VALID(obj, 1)) {
515 device_printf(dev, "Invalid _PSS package\n");
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;
529 * If we have already created P-State table,
530 * we must make sure that number of entries
533 if (acpi_pstates != NULL && acpi_npstates != npstate) {
534 device_printf(dev, "Inconsistent # of P-States "
535 "cross Processor objects\n");
541 * Create a temporary P-State table
543 pstate = kmalloc(sizeof(*pstate) * npstate, M_TEMP, M_WAITOK);
544 for (i = 0, p = pstate; i < npstate; ++i, ++p) {
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
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);
556 kfree(pstate, M_TEMP);
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);
564 kfree(pstate, M_TEMP);
573 if (acpi_pstates == NULL) {
575 * If no P-State table is created yet,
576 * save the temporary one we just created.
578 acpi_pstates = pstate;
579 acpi_npstates = npstate;
583 for (i = 0; i < acpi_npstates; ++i) {
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);
597 * Make sure that P-State tables are same
598 * for all processors.
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);
607 kfree(pstate, M_TEMP);
611 /* By default, we start from P-State table's first entry */
615 * Adjust the usable first entry of P-State table,
616 * if there is _PPC object.
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");
629 sc->pst_sstart = obj->Integer.Value;
631 device_printf(dev, "_PPC %d\n", sc->pst_sstart);
633 /* TODO: Install notifiy handler */
635 device_printf(dev, "Invalid _PPC object\n");
644 sc->pst_state = sc->pst_sstart;
646 /* Link us with the domain */
647 sc->pst_domain = dom;
648 LIST_INSERT_HEAD(&dom->pd_pstlist, sc, pst_link);
650 if (device_get_unit(dev) == 0)
651 AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_pst_postattach, NULL);
656 static struct acpi_pst_domain *
657 acpi_pst_domain_create_pkg(device_t dev, ACPI_OBJECT *obj)
659 struct acpi_pst_domain *dom;
660 uint32_t val, domain, coord, nproc;
662 if (!ACPI_PKG_VALID_EQ(obj, 5)) {
663 device_printf(dev, "Invalid _PSD package\n");
667 /* NumberOfEntries */
668 if (acpi_PkgInt32(obj, 0, &val) != 0 || val != 5) {
669 device_printf(dev, "Invalid _PSD NumberOfEntries\n");
674 if (acpi_PkgInt32(obj, 1, &val) != 0 || val != 0) {
675 device_printf(dev, "Invalid _PSD Revision\n");
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");
686 if (!ACPI_PSD_COORD_VALID(coord)) {
687 device_printf(dev, "Invalid _PSD CoordType (%#x)\n", coord);
691 if (nproc > MAXCPU) {
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.
700 if (coord == ACPI_PSD_COORD_SWALL) {
701 device_printf(dev, "Unsupported _PSD NumProcessors "
705 } else if (nproc == 0) {
706 device_printf(dev, "_PSD NumProcessors are zero\n");
710 dom = acpi_pst_domain_find(domain);
712 if (dom->pd_flags & ACPI_PSTDOM_FLAG_INT) {
713 device_printf(dev, "Mixed Integer _PSD and "
717 if (dom->pd_coord != coord) {
718 device_printf(dev, "Inconsistent _PSD coord "
719 "information cross Processor objects\n");
722 if (dom->pd_nproc != nproc) {
723 device_printf(dev, "Inconsistent _PSD nproc "
724 "information cross Processor objects\n");
726 * Some stupid BIOSes will set wrong "# of processors",
727 * e.g. 1 for CPU w/ hyperthreading; Be lenient here.
733 dom = acpi_pst_domain_alloc(domain, coord, nproc);
735 device_printf(dev, "create pkg domain%u, coord %#x\n",
736 dom->pd_dom, dom->pd_coord);
742 static struct acpi_pst_domain *
743 acpi_pst_domain_create_int(device_t dev, uint32_t domain)
745 struct acpi_pst_domain *dom;
747 dom = acpi_pst_domain_find(domain);
749 if ((dom->pd_flags & ACPI_PSTDOM_FLAG_INT) == 0) {
750 device_printf(dev, "Mixed Package _PSD and "
754 KKASSERT(dom->pd_coord == ACPI_PSD_COORD_SWALL);
760 dom = acpi_pst_domain_alloc(domain, ACPI_PSD_COORD_SWALL, 1);
761 dom->pd_flags |= ACPI_PSTDOM_FLAG_INT;
764 device_printf(dev, "create int domain%u\n", dom->pd_dom);
769 static struct acpi_pst_domain *
770 acpi_pst_domain_find(uint32_t domain)
772 struct acpi_pst_domain *dom;
774 LIST_FOREACH(dom, &acpi_pst_domains, pd_link) {
775 if (dom->pd_flags & ACPI_PSTDOM_FLAG_STUB)
777 if (dom->pd_dom == domain)
783 static struct acpi_pst_domain *
784 acpi_pst_domain_alloc(uint32_t domain, uint32_t coord, uint32_t nproc)
786 struct acpi_pst_domain *dom;
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);
796 LIST_INSERT_HEAD(&acpi_pst_domains, dom, pd_link);
802 acpi_pst_domain_set_pstate(struct acpi_pst_domain *dom, int i)
804 const struct acpi_pstate *pstate;
805 struct acpi_pst_softc *sc;
808 KKASSERT(i >= 0 && i < acpi_npstates);
809 pstate = &acpi_pstates[i];
812 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
814 error = acpi_pst_set_pstate(sc, pstate);
816 device_printf(sc->pst_dev, "can't set "
817 "freq %d\n", pstate->st_freq);
818 /* XXX error cleanup? */
820 if (dom->pd_coord == ACPI_PSD_COORD_SWANY)
831 acpi_pst_global_set_pstate(int i)
833 struct acpi_pst_domain *dom;
835 LIST_FOREACH(dom, &acpi_pst_domains, pd_link) {
836 /* Skip dead domain */
837 if (dom->pd_flags & ACPI_PSTDOM_FLAG_DEAD)
839 acpi_pst_domain_set_pstate(dom, i);
841 acpi_pst_global_state = i;
847 acpi_pst_postattach(void *arg __unused)
849 struct acpi_pst_domain *dom;
850 struct acpi_cpu_softc *cpu;
852 int i, ndevices, error, has_domain, sstate;
856 error = devclass_get_devices(acpi_pst_devclass, &devices, &ndevices);
864 for (i = 0; i < ndevices; ++i) {
865 cpu = device_get_softc(device_get_parent(devices[i]));
866 if (cpu->glob_sysctl_tree != NULL)
869 kfree(devices, M_TEMP);
870 KKASSERT(cpu != NULL);
872 if (acpi_pst_md == NULL)
873 kprintf("ACPI: no P-State CPU driver\n");
877 LIST_FOREACH(dom, &acpi_pst_domains, pd_link) {
878 struct acpi_pst_softc *sc;
882 * Make sure that all processors belonging to this
883 * domain are located.
886 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link)
888 if (i != dom->pd_nproc) {
889 KKASSERT(i < dom->pd_nproc);
891 kprintf("ACPI: domain%u misses processors, "
892 "should be %d, got %d\n", dom->pd_dom,
894 if (dom->pd_coord == ACPI_PSD_COORD_SWALL) {
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
903 dom->pd_flags |= ACPI_PSTDOM_FLAG_DEAD;
910 * Validate P-State configurations for this domain
912 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
913 error = acpi_pst_check_csr(sc);
917 error = acpi_pst_check_pstates(sc);
922 kprintf("ACPI: domain%u P-State configuration "
923 "check failed\n", dom->pd_dom);
924 dom->pd_flags |= ACPI_PSTDOM_FLAG_DEAD;
929 * Do necssary P-State initialization
931 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
932 error = acpi_pst_init(sc);
937 kprintf("ACPI: domain%u P-State initialization "
938 "check failed\n", dom->pd_dom);
939 dom->pd_flags |= ACPI_PSTDOM_FLAG_DEAD;
945 ksnprintf(buf, sizeof(buf), "px_dom%u", dom->pd_dom);
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,
953 if (dom->pd_sysctl_tree == NULL) {
954 kprintf("ACPI: Can't create sysctl tree for domain%u",
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");
966 SYSCTL_ADD_PROC(&dom->pd_sysctl_ctx,
967 SYSCTL_CHILDREN(dom->pd_sysctl_tree),
969 CTLTYPE_STRING | CTLFLAG_RD,
970 dom, 0, acpi_pst_sysctl_members, "A",
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),
978 CTLTYPE_UINT | CTLFLAG_RW,
979 dom, 0, acpi_pst_sysctl_select,
980 "IU", "select freq");
983 if (dom->pd_state < sstate)
984 sstate = dom->pd_state;
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");
996 acpi_pst_global_set_pstate(sstate);
1001 acpi_pst_sysctl_freqs(SYSCTL_HANDLER_ARGS)
1003 struct acpi_pst_domain *dom = arg1;
1007 for (i = 0; i < acpi_npstates; ++i) {
1008 if (error == 0 && i)
1009 error = SYSCTL_OUT(req, " ", 1);
1014 if (i < dom->pd_sstart)
1019 ksnprintf(buf, sizeof(buf), pat,
1020 acpi_pstates[i].st_freq);
1021 error = SYSCTL_OUT(req, buf, strlen(buf));
1028 acpi_pst_sysctl_members(SYSCTL_HANDLER_ARGS)
1030 struct acpi_pst_domain *dom = arg1;
1031 struct acpi_pst_softc *sc;
1035 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
1038 if (error == 0 && loop)
1039 error = SYSCTL_OUT(req, " ", 1);
1041 ksnprintf(buf, sizeof(buf), "cpu%d", sc->pst_cpuid);
1042 error = SYSCTL_OUT(req, buf, strlen(buf));
1045 if (error == 0 && acpi_pst_md && acpi_pst_md->pmd_get_pstate) {
1046 const struct acpi_pstate *pstate;
1049 pstate = acpi_pst_get_pstate(sc);
1050 if (pstate == NULL) {
1053 ksnprintf(buf, sizeof(buf), "(%d)",
1057 error = SYSCTL_OUT(req, str, strlen(str));
1065 acpi_pst_sysctl_select(SYSCTL_HANDLER_ARGS)
1067 struct acpi_pst_domain *dom = arg1;
1070 KKASSERT(dom->pd_state >= 0 && dom->pd_state < acpi_npstates);
1072 freq = acpi_pstates[dom->pd_state].st_freq;
1074 error = sysctl_handle_int(oidp, &freq, 0, req);
1075 if (error || req->newptr == NULL)
1078 i = acpi_pst_freq2index(freq);
1082 acpi_pst_domain_set_pstate(dom, i);
1087 acpi_pst_sysctl_global(SYSCTL_HANDLER_ARGS)
1091 KKASSERT(acpi_pst_global_state >= 0 &&
1092 acpi_pst_global_state < acpi_npstates);
1094 freq = acpi_pstates[acpi_pst_global_state].st_freq;
1096 error = sysctl_handle_int(oidp, &freq, 0, req);
1097 if (error || req->newptr == NULL)
1100 i = acpi_pst_freq2index(freq);
1104 acpi_pst_global_set_pstate(i);
1110 acpi_pst_check_csr_handler(netmsg_t msg)
1112 struct netmsg_acpi_pst *rmsg = (struct netmsg_acpi_pst *)msg;
1115 error = acpi_pst_md->pmd_check_csr(rmsg->ctrl, rmsg->status);
1116 lwkt_replymsg(&rmsg->base.lmsg, error);
1120 acpi_pst_check_csr(struct acpi_pst_softc *sc)
1122 struct netmsg_acpi_pst msg;
1124 if (acpi_pst_md == NULL)
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;
1132 return lwkt_domsg(netisr_cpuport(sc->pst_cpuid), &msg.base.lmsg, 0);
1136 acpi_pst_check_pstates_handler(netmsg_t msg)
1140 error = acpi_pst_md->pmd_check_pstates(acpi_pstates, acpi_npstates);
1141 lwkt_replymsg(&msg->lmsg, error);
1145 acpi_pst_check_pstates(struct acpi_pst_softc *sc)
1147 struct netmsg_base msg;
1149 if (acpi_pst_md == NULL)
1152 netmsg_init(&msg, NULL, &curthread->td_msgport,
1153 MSGF_PRIORITY, acpi_pst_check_pstates_handler);
1155 return lwkt_domsg(netisr_cpuport(sc->pst_cpuid), &msg.lmsg, 0);
1159 acpi_pst_init_handler(netmsg_t msg)
1161 struct netmsg_acpi_pst *rmsg = (struct netmsg_acpi_pst *)msg;
1164 error = acpi_pst_md->pmd_init(rmsg->ctrl, rmsg->status);
1165 lwkt_replymsg(&rmsg->base.lmsg, error);
1169 acpi_pst_init(struct acpi_pst_softc *sc)
1171 struct netmsg_acpi_pst msg;
1173 if (acpi_pst_md == NULL)
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;
1181 return lwkt_domsg(netisr_cpuport(sc->pst_cpuid), &msg.base.lmsg, 0);
1185 acpi_pst_set_pstate_handler(netmsg_t msg)
1187 struct netmsg_acpi_pst *rmsg = (struct netmsg_acpi_pst *)msg;
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);
1196 acpi_pst_set_pstate(struct acpi_pst_softc *sc, const struct acpi_pstate *pstate)
1198 struct netmsg_acpi_pst msg;
1200 KKASSERT(acpi_pst_md != NULL);
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;
1208 return lwkt_domsg(netisr_cpuport(sc->pst_cpuid), &msg.base.lmsg, 0);
1212 acpi_pst_get_pstate_handler(netmsg_t msg)
1214 struct netmsg_acpi_pst *rmsg = (struct netmsg_acpi_pst *)msg;
1215 const struct acpi_pstate *pstate;
1217 pstate = acpi_pst_md->pmd_get_pstate(rmsg->status, acpi_pstates,
1219 rmsg->base.lmsg.u.ms_resultp = __DECONST(void *, pstate);
1220 lwkt_replymsg(&rmsg->base.lmsg, 0);
1223 static const struct acpi_pstate *
1224 acpi_pst_get_pstate(struct acpi_pst_softc *sc)
1226 struct netmsg_acpi_pst msg;
1228 if (acpi_pst_md == NULL)
1231 netmsg_init(&msg.base, NULL, &curthread->td_msgport,
1232 MSGF_PRIORITY, acpi_pst_get_pstate_handler);
1233 msg.status = &sc->pst_sreg;
1235 lwkt_domsg(netisr_cpuport(sc->pst_cpuid), &msg.base.lmsg, 0);
1236 return msg.base.lmsg.u.ms_resultp;
1240 acpi_pst_alloc_resource(device_t dev, ACPI_OBJECT *obj, int idx,
1241 struct acpi_pst_res *res)
1243 struct acpi_pst_softc *sc = device_get_softc(dev);
1247 error = acpi_PkgRawGas(obj, idx, &res->pr_gas);
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);
1265 acpi_pst_domain_check_nproc(device_t dev, struct acpi_pst_domain *dom)
1267 struct acpi_pst_softc *pst;
1271 LIST_FOREACH(pst, &dom->pd_pstlist, pst_link)
1273 if (i == dom->pd_nproc) {
1275 * Some stupid BIOSes will set wrong "# of processors",
1276 * e.g. 1 for CPU w/ hyperthreading; Be lenient here.
1279 device_printf(dev, "domain%u already contains %d "
1280 "P-States\n", dom->pd_dom, dom->pd_nproc);
1284 KKASSERT(i < dom->pd_nproc);