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>
46 #include <net/netisr2.h>
47 #include <net/netmsg2.h>
48 #include <net/if_var.h>
53 #include "acpi_cpu_pstate.h"
55 #define ACPI_NPSTATE_MAX 16
57 #define ACPI_PSS_PX_NENTRY 6
59 #define ACPI_PSD_COORD_SWALL 0xfc
60 #define ACPI_PSD_COORD_SWANY 0xfd
61 #define ACPI_PSD_COORD_HWALL 0xfe
62 #define ACPI_PSD_COORD_VALID(coord) \
63 ((coord) == ACPI_PSD_COORD_SWALL || \
64 (coord) == ACPI_PSD_COORD_SWANY || \
65 (coord) == ACPI_PSD_COORD_HWALL)
67 struct acpi_pst_softc;
68 LIST_HEAD(acpi_pst_list, acpi_pst_softc);
70 struct netmsg_acpi_pst {
71 struct netmsg_base base;
72 const struct acpi_pst_res *ctrl;
73 const struct acpi_pst_res *status;
76 struct acpi_pst_domain {
80 LIST_ENTRY(acpi_pst_domain) pd_link;
86 struct acpi_pst_list pd_pstlist;
88 struct sysctl_ctx_list pd_sysctl_ctx;
89 struct sysctl_oid *pd_sysctl_tree;
91 LIST_HEAD(acpi_pst_domlist, acpi_pst_domain);
93 #define ACPI_PSTDOM_FLAG_STUB 0x1 /* stub domain, no _PSD */
94 #define ACPI_PSTDOM_FLAG_DEAD 0x2 /* domain can't be started */
95 #define ACPI_PSTDOM_FLAG_INT 0x4 /* domain created from Integer _PSD */
97 struct acpi_pst_softc {
99 struct acpi_cpu_softc *pst_parent;
100 struct acpi_pst_domain *pst_domain;
101 struct acpi_pst_res pst_creg;
102 struct acpi_pst_res pst_sreg;
108 ACPI_HANDLE pst_handle;
110 LIST_ENTRY(acpi_pst_softc) pst_link;
113 static int acpi_pst_probe(device_t dev);
114 static int acpi_pst_attach(device_t dev);
116 static void acpi_pst_postattach(void *);
117 static struct acpi_pst_domain *
118 acpi_pst_domain_create_int(device_t, uint32_t);
119 static struct acpi_pst_domain *
120 acpi_pst_domain_create_pkg(device_t, ACPI_OBJECT *);
121 static struct acpi_pst_domain *
122 acpi_pst_domain_find(uint32_t);
123 static struct acpi_pst_domain *
124 acpi_pst_domain_alloc(uint32_t, uint32_t, uint32_t);
125 static int acpi_pst_domain_set_pstate(struct acpi_pst_domain *, int);
126 static int acpi_pst_global_set_pstate(int);
128 static int acpi_pst_check_csr(struct acpi_pst_softc *);
129 static int acpi_pst_check_pstates(struct acpi_pst_softc *);
130 static int acpi_pst_init(struct acpi_pst_softc *);
131 static int acpi_pst_set_pstate(struct acpi_pst_softc *,
132 const struct acpi_pstate *);
133 static const struct acpi_pstate *
134 acpi_pst_get_pstate(struct acpi_pst_softc *);
135 static int acpi_pst_alloc_resource(device_t, ACPI_OBJECT *, int,
136 struct acpi_pst_res *);
138 static void acpi_pst_check_csr_handler(netmsg_t);
139 static void acpi_pst_check_pstates_handler(netmsg_t);
140 static void acpi_pst_init_handler(netmsg_t);
141 static void acpi_pst_set_pstate_handler(netmsg_t);
142 static void acpi_pst_get_pstate_handler(netmsg_t);
144 static int acpi_pst_sysctl_freqs(SYSCTL_HANDLER_ARGS);
145 static int acpi_pst_sysctl_members(SYSCTL_HANDLER_ARGS);
146 static int acpi_pst_sysctl_select(SYSCTL_HANDLER_ARGS);
147 static int acpi_pst_sysctl_global(SYSCTL_HANDLER_ARGS);
149 static struct acpi_pst_domlist acpi_pst_domains =
150 LIST_HEAD_INITIALIZER(acpi_pst_domains);
151 static int acpi_pst_domain_id;
153 static int acpi_pst_global_state;
155 static int acpi_npstates;
156 static struct acpi_pstate *acpi_pstates;
158 static const struct acpi_pst_md *acpi_pst_md;
160 static device_method_t acpi_pst_methods[] = {
161 /* Device interface */
162 DEVMETHOD(device_probe, acpi_pst_probe),
163 DEVMETHOD(device_attach, acpi_pst_attach),
164 DEVMETHOD(device_detach, bus_generic_detach),
165 DEVMETHOD(device_shutdown, bus_generic_shutdown),
166 DEVMETHOD(device_suspend, bus_generic_suspend),
167 DEVMETHOD(device_resume, bus_generic_resume),
170 DEVMETHOD(bus_add_child, bus_generic_add_child),
171 DEVMETHOD(bus_print_child, bus_generic_print_child),
172 DEVMETHOD(bus_read_ivar, bus_generic_read_ivar),
173 DEVMETHOD(bus_write_ivar, bus_generic_write_ivar),
174 DEVMETHOD(bus_get_resource_list, bus_generic_get_resource_list),
175 DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
176 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
177 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
178 DEVMETHOD(bus_release_resource, bus_generic_release_resource),
179 DEVMETHOD(bus_driver_added, bus_generic_driver_added),
180 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
181 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
182 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
183 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
188 static driver_t acpi_pst_driver = {
191 sizeof(struct acpi_pst_softc)
194 static devclass_t acpi_pst_devclass;
195 DRIVER_MODULE(cpu_pst, cpu, acpi_pst_driver, acpi_pst_devclass, NULL, NULL);
196 MODULE_DEPEND(cpu_pst, acpi, 1, 1, 1);
199 acpi_pst_freq2index(int freq)
203 for (i = 0; i < acpi_npstates; ++i) {
204 if (acpi_pstates[i].st_freq == freq)
211 acpi_pst_probe(device_t dev)
218 if (acpi_disabled("cpu_pst") ||
219 acpi_get_type(dev) != ACPI_TYPE_PROCESSOR)
222 if (acpi_pst_md == NULL)
223 acpi_pst_md = acpi_pst_md_probe();
225 handle = acpi_get_handle(dev);
231 buf.Length = ACPI_ALLOCATE_BUFFER;
232 status = AcpiEvaluateObject(handle, "_PCT", NULL, &buf);
233 if (ACPI_FAILURE(status)) {
235 device_printf(dev, "Can't get _PCT package - %s\n",
236 AcpiFormatException(status));
241 obj = (ACPI_OBJECT *)buf.Pointer;
242 if (!ACPI_PKG_VALID_EQ(obj, 2)) {
243 device_printf(dev, "Invalid _PCT package\n");
253 buf.Length = ACPI_ALLOCATE_BUFFER;
254 status = AcpiEvaluateObject(handle, "_PSS", NULL, &buf);
255 if (ACPI_FAILURE(status)) {
256 device_printf(dev, "Can't get _PSS package - %s\n",
257 AcpiFormatException(status));
261 obj = (ACPI_OBJECT *)buf.Pointer;
262 if (!ACPI_PKG_VALID(obj, 1)) {
263 device_printf(dev, "Invalid _PSS package\n");
269 device_set_desc(dev, "ACPI CPU P-State");
274 acpi_pst_attach(device_t dev)
276 struct acpi_pst_softc *sc = device_get_softc(dev), *pst;
277 struct acpi_pst_domain *dom = NULL;
281 struct acpi_pstate *pstate, *p;
282 int i, npstate, error;
285 sc->pst_parent = device_get_softc(device_get_parent(dev));
286 sc->pst_handle = acpi_get_handle(dev);
287 sc->pst_cpuid = acpi_get_magic(dev);
290 * If there is a _PSD, then we create procossor domain
291 * accordingly. If there is no _PSD, we just fake a
292 * default processor domain0.
295 buf.Length = ACPI_ALLOCATE_BUFFER;
296 status = AcpiEvaluateObject(sc->pst_handle, "_PSD", NULL, &buf);
297 if (!ACPI_FAILURE(status)) {
298 obj = (ACPI_OBJECT *)buf.Pointer;
300 if (acpi_pst_domain_id > 0) {
301 device_printf(dev, "Missing _PSD for certain CPUs\n");
305 acpi_pst_domain_id = -1;
307 if (ACPI_PKG_VALID_EQ(obj, 1)) {
308 dom = acpi_pst_domain_create_pkg(dev,
309 &obj->Package.Elements[0]);
315 if (obj->Type != ACPI_TYPE_INTEGER) {
317 "Invalid _PSD package, Type 0x%x\n",
322 device_printf(dev, "Integer _PSD %ju\n",
323 (uintmax_t)obj->Integer.Value);
324 dom = acpi_pst_domain_create_int(dev,
334 AcpiOsFree(buf.Pointer);
336 if (acpi_pst_domain_id < 0) {
337 device_printf(dev, "Missing _PSD for cpu%d\n",
343 * Create a stub one processor domain for each processor
345 dom = acpi_pst_domain_alloc(acpi_pst_domain_id,
346 ACPI_PSD_COORD_SWANY, 1);
347 dom->pd_flags |= ACPI_PSTDOM_FLAG_STUB;
349 ++acpi_pst_domain_id;
352 /* Make sure that adding us will not overflow our domain */
354 LIST_FOREACH(pst, &dom->pd_pstlist, pst_link)
356 if (i == dom->pd_nproc) {
357 device_printf(dev, "Domain%u already contains %d P-States, "
358 "invalid _PSD package\n",
359 dom->pd_dom, dom->pd_nproc);
362 * Some stupid BIOSes will set wrong "# of processors",
363 * e.g. 1 for CPU w/ hyperthreading; Be lenient here.
370 KKASSERT(i < dom->pd_nproc);
373 * Get control/status registers from _PCT
376 buf.Length = ACPI_ALLOCATE_BUFFER;
377 status = AcpiEvaluateObject(sc->pst_handle, "_PCT", NULL, &buf);
378 if (ACPI_FAILURE(status)) {
379 device_printf(dev, "Can't get _PCT package - %s\n",
380 AcpiFormatException(status));
384 obj = (ACPI_OBJECT *)buf.Pointer;
385 if (!ACPI_PKG_VALID_EQ(obj, 2)) {
386 device_printf(dev, "Invalid _PCT package\n");
391 /* Save and try allocating control register */
392 error = acpi_pst_alloc_resource(dev, obj, 0, &sc->pst_creg);
398 device_printf(dev, "control reg %d %jx\n",
399 sc->pst_creg.pr_gas.SpaceId,
400 (uintmax_t)sc->pst_creg.pr_gas.Address);
403 /* Save and try allocating status register */
404 error = acpi_pst_alloc_resource(dev, obj, 1, &sc->pst_sreg);
410 device_printf(dev, "status reg %d %jx\n",
411 sc->pst_sreg.pr_gas.SpaceId,
412 (uintmax_t)sc->pst_sreg.pr_gas.Address);
419 * Create P-State table according to _PSS
422 buf.Length = ACPI_ALLOCATE_BUFFER;
423 status = AcpiEvaluateObject(sc->pst_handle, "_PSS", NULL, &buf);
424 if (ACPI_FAILURE(status)) {
425 device_printf(dev, "Can't get _PSS package - %s\n",
426 AcpiFormatException(status));
430 obj = (ACPI_OBJECT *)buf.Pointer;
431 if (!ACPI_PKG_VALID(obj, 1)) {
432 device_printf(dev, "Invalid _PSS package\n");
437 /* Don't create too many P-States */
438 npstate = obj->Package.Count;
439 if (npstate > ACPI_NPSTATE_MAX) {
440 device_printf(dev, "Too many P-States, %d->%d\n",
441 npstate, ACPI_NPSTATE_MAX);
442 npstate = ACPI_NPSTATE_MAX;
446 * If we have already created P-State table,
447 * we must make sure that number of entries
450 if (acpi_pstates != NULL && acpi_npstates != npstate) {
451 device_printf(dev, "Inconsistent # of P-States "
452 "cross Processor objects\n");
458 * Create a temporary P-State table
460 pstate = kmalloc(sizeof(*pstate) * npstate, M_TEMP, M_WAITOK);
461 for (i = 0, p = pstate; i < npstate; ++i, ++p) {
463 uint32_t *ptr[ACPI_PSS_PX_NENTRY] = {
464 &p->st_freq, &p->st_power, &p->st_xsit_lat,
465 &p->st_bm_lat, &p->st_cval, &p->st_sval
469 pkg = &obj->Package.Elements[i];
470 if (!ACPI_PKG_VALID(pkg, ACPI_PSS_PX_NENTRY)) {
471 device_printf(dev, "Invalud _PSS P%d\n", i);
473 kfree(pstate, M_TEMP);
476 for (j = 0; j < ACPI_PSS_PX_NENTRY; ++j) {
477 if (acpi_PkgInt32(pkg, j, ptr[j]) != 0) {
478 device_printf(dev, "Can't extract "
479 "_PSS P%d %dth entry\n", i, j);
481 kfree(pstate, M_TEMP);
490 if (acpi_pstates == NULL) {
492 * If no P-State table is created yet,
493 * save the temporary one we just created.
495 acpi_pstates = pstate;
496 acpi_npstates = npstate;
500 for (i = 0; i < acpi_npstates; ++i) {
502 "freq %u, pwr %u, xlat %u, blat %u, "
503 "cv %08x, sv %08x\n",
504 acpi_pstates[i].st_freq,
505 acpi_pstates[i].st_power,
506 acpi_pstates[i].st_xsit_lat,
507 acpi_pstates[i].st_bm_lat,
508 acpi_pstates[i].st_cval,
509 acpi_pstates[i].st_sval);
514 * Make sure that P-State tables are same
515 * for all processors.
517 if (memcmp(pstate, acpi_pstates,
518 sizeof(*pstate) * npstate) != 0) {
519 device_printf(dev, "Inconsistent _PSS "
520 "cross Processor objects\n");
521 kfree(pstate, M_TEMP);
524 kfree(pstate, M_TEMP);
527 /* By default, we start from P-State table's first entry */
531 * Adjust the usable first entry of P-State table,
532 * if there is _PPC object.
535 buf.Length = ACPI_ALLOCATE_BUFFER;
536 status = AcpiEvaluateObject(sc->pst_handle, "_PPC", NULL, &buf);
537 if (!ACPI_FAILURE(status)) {
538 obj = (ACPI_OBJECT *)buf.Pointer;
539 if (obj->Type == ACPI_TYPE_INTEGER) {
540 if (obj->Integer.Value >= acpi_npstates) {
541 device_printf(dev, "Invalid _PPC value\n");
545 sc->pst_sstart = obj->Integer.Value;
547 device_printf(dev, "_PPC %d\n", sc->pst_sstart);
549 /* TODO: Install notifiy handler */
551 device_printf(dev, "Invalid _PPC object\n");
560 sc->pst_state = sc->pst_sstart;
562 /* Link us with the domain */
563 sc->pst_domain = dom;
564 LIST_INSERT_HEAD(&dom->pd_pstlist, sc, pst_link);
566 if (device_get_unit(dev) == 0)
567 AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_pst_postattach, NULL);
572 static struct acpi_pst_domain *
573 acpi_pst_domain_create_pkg(device_t dev, ACPI_OBJECT *obj)
575 struct acpi_pst_domain *dom;
576 uint32_t val, domain, coord, nproc;
578 if (!ACPI_PKG_VALID_EQ(obj, 5)) {
579 device_printf(dev, "Invalid _PSD package\n");
583 /* NumberOfEntries */
584 if (acpi_PkgInt32(obj, 0, &val) != 0 || val != 5) {
585 device_printf(dev, "Invalid _PSD NumberOfEntries\n");
590 if (acpi_PkgInt32(obj, 1, &val) != 0 || val != 0) {
591 device_printf(dev, "Invalid _PSD Revision\n");
595 if (acpi_PkgInt32(obj, 2, &domain) != 0 ||
596 acpi_PkgInt32(obj, 3, &coord) != 0 ||
597 acpi_PkgInt32(obj, 4, &nproc) != 0) {
598 device_printf(dev, "Can't extract _PSD package\n");
602 if (!ACPI_PSD_COORD_VALID(coord)) {
603 device_printf(dev, "Invalid _PSD CoordType (%#x)\n", coord);
607 if (nproc > MAXCPU) {
609 * If NumProcessors is greater than MAXCPU
610 * and domain's coordination is SWALL, then
611 * we will never be able to start all CPUs
612 * within this domain, and power state
613 * transition will never be completed, so we
614 * just bail out here.
616 if (coord == ACPI_PSD_COORD_SWALL) {
617 device_printf(dev, "Unsupported _PSD NumProcessors "
621 } else if (nproc == 0) {
622 device_printf(dev, "_PSD NumProcessors are zero\n");
626 dom = acpi_pst_domain_find(domain);
628 if (dom->pd_flags & ACPI_PSTDOM_FLAG_INT) {
629 device_printf(dev, "Mixed Integer _PSD and "
633 if (dom->pd_coord != coord) {
634 device_printf(dev, "Inconsistent _PSD coord "
635 "information cross Processor objects\n");
638 if (dom->pd_nproc != nproc) {
639 device_printf(dev, "Inconsistent _PSD nproc "
640 "information cross Processor objects\n");
642 * Some stupid BIOSes will set wrong "# of processors",
643 * e.g. 1 for CPU w/ hyperthreading; Be lenient here.
649 dom = acpi_pst_domain_alloc(domain, coord, nproc);
651 device_printf(dev, "create pkg domain%u, coord %#x\n",
652 dom->pd_dom, dom->pd_coord);
658 static struct acpi_pst_domain *
659 acpi_pst_domain_create_int(device_t dev, uint32_t domain)
661 struct acpi_pst_domain *dom;
663 dom = acpi_pst_domain_find(domain);
665 if ((dom->pd_flags & ACPI_PSTDOM_FLAG_INT) == 0) {
666 device_printf(dev, "Mixed Package _PSD and "
670 KKASSERT(dom->pd_coord == ACPI_PSD_COORD_SWALL);
676 dom = acpi_pst_domain_alloc(domain, ACPI_PSD_COORD_SWALL, 1);
677 dom->pd_flags |= ACPI_PSTDOM_FLAG_INT;
680 device_printf(dev, "create int domain%u\n", dom->pd_dom);
685 static struct acpi_pst_domain *
686 acpi_pst_domain_find(uint32_t domain)
688 struct acpi_pst_domain *dom;
690 LIST_FOREACH(dom, &acpi_pst_domains, pd_link) {
691 if (dom->pd_flags & ACPI_PSTDOM_FLAG_STUB)
693 if (dom->pd_dom == domain)
699 static struct acpi_pst_domain *
700 acpi_pst_domain_alloc(uint32_t domain, uint32_t coord, uint32_t nproc)
702 struct acpi_pst_domain *dom;
704 dom = kmalloc(sizeof(*dom), M_DEVBUF, M_WAITOK | M_ZERO);
705 dom->pd_dom = domain;
706 dom->pd_coord = coord;
707 dom->pd_nproc = nproc;
708 dom->pd_state = 0; /* XXX */
709 dom->pd_sstart = 0; /* XXX */
710 LIST_INIT(&dom->pd_pstlist);
712 LIST_INSERT_HEAD(&acpi_pst_domains, dom, pd_link);
718 acpi_pst_domain_set_pstate(struct acpi_pst_domain *dom, int i)
720 const struct acpi_pstate *pstate;
721 struct acpi_pst_softc *sc;
724 KKASSERT(i >= 0 && i < acpi_npstates);
725 pstate = &acpi_pstates[i];
728 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
730 error = acpi_pst_set_pstate(sc, pstate);
732 device_printf(sc->pst_dev, "can't set "
733 "freq %d\n", pstate->st_freq);
734 /* XXX error cleanup? */
736 if (dom->pd_coord == ACPI_PSD_COORD_SWANY)
747 acpi_pst_global_set_pstate(int i)
749 struct acpi_pst_domain *dom;
751 LIST_FOREACH(dom, &acpi_pst_domains, pd_link) {
752 /* Skip dead domain */
753 if (dom->pd_flags & ACPI_PSTDOM_FLAG_DEAD)
755 acpi_pst_domain_set_pstate(dom, i);
757 acpi_pst_global_state = i;
763 acpi_pst_postattach(void *arg __unused)
765 struct acpi_pst_domain *dom;
766 struct acpi_cpu_softc *cpu;
768 int i, ndevices, error, has_domain, sstate;
772 error = devclass_get_devices(acpi_pst_devclass, &devices, &ndevices);
780 for (i = 0; i < ndevices; ++i) {
781 cpu = device_get_softc(device_get_parent(devices[i]));
782 if (cpu->glob_sysctl_tree != NULL)
785 kfree(devices, M_TEMP);
786 KKASSERT(cpu != NULL);
788 if (acpi_pst_md == NULL)
789 kprintf("ACPI: no P-State CPU driver\n");
793 LIST_FOREACH(dom, &acpi_pst_domains, pd_link) {
794 struct acpi_pst_softc *sc;
798 * Make sure that all processors belonging to this
799 * domain are located.
802 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link)
804 if (i != dom->pd_nproc) {
805 KKASSERT(i < dom->pd_nproc);
807 kprintf("ACPI: domain%u misses processors, "
808 "should be %d, got %d\n", dom->pd_dom,
810 if (dom->pd_coord == ACPI_PSD_COORD_SWALL) {
812 * If this domain's coordination is
813 * SWALL and we don't see all of the
814 * member CPUs of this domain, then
815 * the P-State transition will never
816 * be completed, so just leave this
819 dom->pd_flags |= ACPI_PSTDOM_FLAG_DEAD;
826 * Validate P-State configurations for this domain
828 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
829 error = acpi_pst_check_csr(sc);
833 error = acpi_pst_check_pstates(sc);
838 kprintf("ACPI: domain%u P-State configuration "
839 "check failed\n", dom->pd_dom);
840 dom->pd_flags |= ACPI_PSTDOM_FLAG_DEAD;
845 * Do necssary P-State initialization
847 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
848 error = acpi_pst_init(sc);
853 kprintf("ACPI: domain%u P-State initialization "
854 "check failed\n", dom->pd_dom);
855 dom->pd_flags |= ACPI_PSTDOM_FLAG_DEAD;
861 ksnprintf(buf, sizeof(buf), "px_dom%u", dom->pd_dom);
863 sysctl_ctx_init(&dom->pd_sysctl_ctx);
864 dom->pd_sysctl_tree =
865 SYSCTL_ADD_NODE(&dom->pd_sysctl_ctx,
866 SYSCTL_CHILDREN(cpu->glob_sysctl_tree),
867 OID_AUTO, buf, CTLFLAG_RD, 0,
869 if (dom->pd_sysctl_tree == NULL) {
870 kprintf("ACPI: Can't create sysctl tree for domain%u",
875 SYSCTL_ADD_PROC(&dom->pd_sysctl_ctx,
876 SYSCTL_CHILDREN(dom->pd_sysctl_tree),
877 OID_AUTO, "available",
878 CTLTYPE_STRING | CTLFLAG_RD,
879 dom, 0, acpi_pst_sysctl_freqs, "A",
880 "available frequencies");
882 SYSCTL_ADD_PROC(&dom->pd_sysctl_ctx,
883 SYSCTL_CHILDREN(dom->pd_sysctl_tree),
885 CTLTYPE_STRING | CTLFLAG_RD,
886 dom, 0, acpi_pst_sysctl_members, "A",
889 if (acpi_pst_md != NULL &&
890 acpi_pst_md->pmd_set_pstate != NULL) {
891 SYSCTL_ADD_PROC(&dom->pd_sysctl_ctx,
892 SYSCTL_CHILDREN(dom->pd_sysctl_tree),
894 CTLTYPE_UINT | CTLFLAG_RW,
895 dom, 0, acpi_pst_sysctl_select,
896 "IU", "select freq");
899 if (dom->pd_state < sstate)
900 sstate = dom->pd_state;
903 if (has_domain && acpi_pst_md != NULL &&
904 acpi_pst_md->pmd_set_pstate != NULL) {
905 SYSCTL_ADD_PROC(&cpu->glob_sysctl_ctx,
906 SYSCTL_CHILDREN(cpu->glob_sysctl_tree),
907 OID_AUTO, "px_global",
908 CTLTYPE_UINT | CTLFLAG_RW,
909 NULL, 0, acpi_pst_sysctl_global,
910 "IU", "select freq for all domains");
912 acpi_pst_global_set_pstate(sstate);
917 acpi_pst_sysctl_freqs(SYSCTL_HANDLER_ARGS)
919 struct acpi_pst_domain *dom = arg1;
923 for (i = 0; i < acpi_npstates; ++i) {
925 error = SYSCTL_OUT(req, " ", 1);
930 if (i < dom->pd_sstart)
935 ksnprintf(buf, sizeof(buf), pat,
936 acpi_pstates[i].st_freq);
937 error = SYSCTL_OUT(req, buf, strlen(buf));
944 acpi_pst_sysctl_members(SYSCTL_HANDLER_ARGS)
946 struct acpi_pst_domain *dom = arg1;
947 struct acpi_pst_softc *sc;
951 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
954 if (error == 0 && loop)
955 error = SYSCTL_OUT(req, " ", 1);
957 ksnprintf(buf, sizeof(buf), "cpu%d", sc->pst_cpuid);
958 error = SYSCTL_OUT(req, buf, strlen(buf));
961 if (error == 0 && acpi_pst_md && acpi_pst_md->pmd_get_pstate) {
962 const struct acpi_pstate *pstate;
965 pstate = acpi_pst_get_pstate(sc);
966 if (pstate == NULL) {
969 ksnprintf(buf, sizeof(buf), "(%d)",
973 error = SYSCTL_OUT(req, str, strlen(str));
981 acpi_pst_sysctl_select(SYSCTL_HANDLER_ARGS)
983 struct acpi_pst_domain *dom = arg1;
986 KKASSERT(dom->pd_state >= 0 && dom->pd_state < acpi_npstates);
988 freq = acpi_pstates[dom->pd_state].st_freq;
990 error = sysctl_handle_int(oidp, &freq, 0, req);
991 if (error || req->newptr == NULL)
994 i = acpi_pst_freq2index(freq);
998 acpi_pst_domain_set_pstate(dom, i);
1003 acpi_pst_sysctl_global(SYSCTL_HANDLER_ARGS)
1007 KKASSERT(acpi_pst_global_state >= 0 &&
1008 acpi_pst_global_state < acpi_npstates);
1010 freq = acpi_pstates[acpi_pst_global_state].st_freq;
1012 error = sysctl_handle_int(oidp, &freq, 0, req);
1013 if (error || req->newptr == NULL)
1016 i = acpi_pst_freq2index(freq);
1020 acpi_pst_global_set_pstate(i);
1026 acpi_pst_check_csr_handler(netmsg_t msg)
1028 struct netmsg_acpi_pst *rmsg = (struct netmsg_acpi_pst *)msg;
1031 error = acpi_pst_md->pmd_check_csr(rmsg->ctrl, rmsg->status);
1032 lwkt_replymsg(&rmsg->base.lmsg, error);
1036 acpi_pst_check_csr(struct acpi_pst_softc *sc)
1038 struct netmsg_acpi_pst msg;
1040 if (acpi_pst_md == NULL)
1043 netmsg_init(&msg.base, NULL, &curthread->td_msgport,
1044 MSGF_PRIORITY, acpi_pst_check_csr_handler);
1045 msg.ctrl = &sc->pst_creg;
1046 msg.status = &sc->pst_sreg;
1048 return lwkt_domsg(netisr_cpuport(sc->pst_cpuid), &msg.base.lmsg, 0);
1052 acpi_pst_check_pstates_handler(netmsg_t msg)
1056 error = acpi_pst_md->pmd_check_pstates(acpi_pstates, acpi_npstates);
1057 lwkt_replymsg(&msg->lmsg, error);
1061 acpi_pst_check_pstates(struct acpi_pst_softc *sc)
1063 struct netmsg_base msg;
1065 if (acpi_pst_md == NULL)
1068 netmsg_init(&msg, NULL, &curthread->td_msgport,
1069 MSGF_PRIORITY, acpi_pst_check_pstates_handler);
1071 return lwkt_domsg(netisr_cpuport(sc->pst_cpuid), &msg.lmsg, 0);
1075 acpi_pst_init_handler(netmsg_t msg)
1077 struct netmsg_acpi_pst *rmsg = (struct netmsg_acpi_pst *)msg;
1080 error = acpi_pst_md->pmd_init(rmsg->ctrl, rmsg->status);
1081 lwkt_replymsg(&rmsg->base.lmsg, error);
1085 acpi_pst_init(struct acpi_pst_softc *sc)
1087 struct netmsg_acpi_pst msg;
1089 if (acpi_pst_md == NULL)
1092 netmsg_init(&msg.base, NULL, &curthread->td_msgport,
1093 MSGF_PRIORITY, acpi_pst_init_handler);
1094 msg.ctrl = &sc->pst_creg;
1095 msg.status = &sc->pst_sreg;
1097 return lwkt_domsg(netisr_cpuport(sc->pst_cpuid), &msg.base.lmsg, 0);
1101 acpi_pst_set_pstate_handler(netmsg_t msg)
1103 struct netmsg_acpi_pst *rmsg = (struct netmsg_acpi_pst *)msg;
1106 error = acpi_pst_md->pmd_set_pstate(rmsg->ctrl, rmsg->status,
1107 rmsg->base.lmsg.u.ms_resultp);
1108 lwkt_replymsg(&rmsg->base.lmsg, error);
1112 acpi_pst_set_pstate(struct acpi_pst_softc *sc, const struct acpi_pstate *pstate)
1114 struct netmsg_acpi_pst msg;
1116 KKASSERT(acpi_pst_md != NULL);
1118 netmsg_init(&msg.base, NULL, &curthread->td_msgport,
1119 MSGF_PRIORITY, acpi_pst_set_pstate_handler);
1120 msg.base.lmsg.u.ms_resultp = __DECONST(void *, pstate);
1121 msg.ctrl = &sc->pst_creg;
1122 msg.status = &sc->pst_sreg;
1124 return lwkt_domsg(netisr_cpuport(sc->pst_cpuid), &msg.base.lmsg, 0);
1128 acpi_pst_get_pstate_handler(netmsg_t msg)
1130 struct netmsg_acpi_pst *rmsg = (struct netmsg_acpi_pst *)msg;
1131 const struct acpi_pstate *pstate;
1133 pstate = acpi_pst_md->pmd_get_pstate(rmsg->status, acpi_pstates,
1135 rmsg->base.lmsg.u.ms_resultp = __DECONST(void *, pstate);
1136 lwkt_replymsg(&rmsg->base.lmsg, 0);
1139 static const struct acpi_pstate *
1140 acpi_pst_get_pstate(struct acpi_pst_softc *sc)
1142 struct netmsg_acpi_pst msg;
1144 if (acpi_pst_md == NULL)
1147 netmsg_init(&msg.base, NULL, &curthread->td_msgport,
1148 MSGF_PRIORITY, acpi_pst_get_pstate_handler);
1149 msg.status = &sc->pst_sreg;
1151 lwkt_domsg(netisr_cpuport(sc->pst_cpuid), &msg.base.lmsg, 0);
1152 return msg.base.lmsg.u.ms_resultp;
1156 acpi_pst_alloc_resource(device_t dev, ACPI_OBJECT *obj, int idx,
1157 struct acpi_pst_res *res)
1159 struct acpi_pst_softc *sc = device_get_softc(dev);
1163 error = acpi_PkgRawGas(obj, idx, &res->pr_gas);
1167 /* Allocate resource, if possible */
1168 res->pr_rid = sc->pst_parent->cpu_next_rid;
1169 acpi_bus_alloc_gas(dev, &type, &res->pr_rid, &res->pr_gas, &res->pr_res, 0);
1170 if (res->pr_res != NULL) {
1171 sc->pst_parent->cpu_next_rid++;
1172 res->pr_bt = rman_get_bustag(res->pr_res);
1173 res->pr_bh = rman_get_bushandle(res->pr_res);