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>
42 #include <sys/sysctl.h>
43 #include <sys/msgport2.h>
45 #include <net/netisr.h>
46 #include <net/netmsg2.h>
47 #include <net/if_var.h>
52 #include "acpi_cpu_pstate.h"
54 #define ACPI_NPSTATE_MAX 16
56 #define ACPI_PSS_PX_NENTRY 6
58 #define ACPI_PSD_COORD_SWALL 0xfc
59 #define ACPI_PSD_COORD_SWANY 0xfd
60 #define ACPI_PSD_COORD_HWALL 0xfe
61 #define ACPI_PSD_COORD_VALID(coord) \
62 ((coord) == ACPI_PSD_COORD_SWALL || \
63 (coord) == ACPI_PSD_COORD_SWANY || \
64 (coord) == ACPI_PSD_COORD_HWALL)
66 struct acpi_pst_softc;
67 LIST_HEAD(acpi_pst_list, acpi_pst_softc);
69 struct netmsg_acpi_pst {
72 const ACPI_RESOURCE_GENERIC_REGISTER *ctrl;
73 const ACPI_RESOURCE_GENERIC_REGISTER *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 */
96 struct acpi_pst_softc {
98 struct acpi_cpux_softc *pst_parent;
99 struct acpi_pst_domain *pst_domain;
100 ACPI_RESOURCE_GENERIC_REGISTER pst_creg;
101 ACPI_RESOURCE_GENERIC_REGISTER pst_sreg;
107 ACPI_HANDLE pst_handle;
109 LIST_ENTRY(acpi_pst_softc) pst_link;
112 static int acpi_pst_probe(device_t dev);
113 static int acpi_pst_attach(device_t dev);
115 static void acpi_pst_postattach(void *);
116 static struct acpi_pst_domain *
117 acpi_pst_domain_create(device_t, ACPI_OBJECT *);
118 static struct acpi_pst_domain *
119 acpi_pst_domain_find(uint32_t);
120 static struct acpi_pst_domain *
121 acpi_pst_domain_alloc(uint32_t, uint32_t, uint32_t);
122 static int acpi_pst_domain_set_pstate(struct acpi_pst_domain *, int);
124 static int acpi_pst_check_csr(struct acpi_pst_softc *);
125 static int acpi_pst_check_pstates(struct acpi_pst_softc *);
126 static int acpi_pst_set_pstate(struct acpi_pst_softc *,
127 const struct acpi_pstate *);
128 static const struct acpi_pstate *
129 acpi_pst_get_pstate(struct acpi_pst_softc *);
131 static void acpi_pst_check_csr_handler(struct netmsg *);
132 static void acpi_pst_check_pstates_handler(struct netmsg *);
133 static void acpi_pst_set_pstate_handler(struct netmsg *);
134 static void acpi_pst_get_pstate_handler(struct netmsg *);
136 static int acpi_pst_sysctl_freqs(SYSCTL_HANDLER_ARGS);
137 static int acpi_pst_sysctl_members(SYSCTL_HANDLER_ARGS);
138 static int acpi_pst_sysctl_select(SYSCTL_HANDLER_ARGS);
139 static int acpi_pst_sysctl_global(SYSCTL_HANDLER_ARGS);
141 static struct acpi_pst_domlist acpi_pst_domains =
142 LIST_HEAD_INITIALIZER(acpi_pst_domains);
144 static int acpi_pst_global_state;
146 static int acpi_npstates;
147 static struct acpi_pstate *acpi_pstates;
149 static const struct acpi_pst_md *acpi_pst_md;
151 static device_method_t acpi_pst_methods[] = {
152 /* Device interface */
153 DEVMETHOD(device_probe, acpi_pst_probe),
154 DEVMETHOD(device_attach, acpi_pst_attach),
155 DEVMETHOD(device_detach, bus_generic_detach),
156 DEVMETHOD(device_shutdown, bus_generic_shutdown),
157 DEVMETHOD(device_suspend, bus_generic_suspend),
158 DEVMETHOD(device_resume, bus_generic_resume),
161 DEVMETHOD(bus_add_child, bus_generic_add_child),
162 DEVMETHOD(bus_print_child, bus_generic_print_child),
163 DEVMETHOD(bus_read_ivar, bus_generic_read_ivar),
164 DEVMETHOD(bus_write_ivar, bus_generic_write_ivar),
165 DEVMETHOD(bus_get_resource_list, bus_generic_get_resource_list),
166 DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
167 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
168 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
169 DEVMETHOD(bus_release_resource, bus_generic_release_resource),
170 DEVMETHOD(bus_driver_added, bus_generic_driver_added),
171 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
172 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
173 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
174 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
179 static driver_t acpi_pst_driver = {
182 sizeof(struct acpi_pst_softc)
185 static devclass_t acpi_pst_devclass;
186 DRIVER_MODULE(cpu_pst, cpu, acpi_pst_driver, acpi_pst_devclass, 0, 0);
187 MODULE_DEPEND(cpu_pst, acpi, 1, 1, 1);
190 acpi_pst_freq2index(int freq)
194 for (i = 0; i < acpi_npstates; ++i) {
195 if (acpi_pstates[i].st_freq == freq)
202 acpi_pst_probe(device_t dev)
209 if (acpi_disabled("cpu_pst") ||
210 acpi_get_type(dev) != ACPI_TYPE_PROCESSOR)
213 if (acpi_pst_md == NULL)
214 acpi_pst_md = acpi_pst_md_probe();
216 handle = acpi_get_handle(dev);
222 buf.Length = ACPI_ALLOCATE_BUFFER;
223 status = AcpiEvaluateObject(handle, "_PCT", NULL, &buf);
224 if (ACPI_FAILURE(status)) {
226 device_printf(dev, "Can't get _PCT package - %s\n",
227 AcpiFormatException(status));
232 obj = (ACPI_OBJECT *)buf.Pointer;
233 if (!ACPI_PKG_VALID_EQ(obj, 2)) {
234 device_printf(dev, "Invalid _PCT package\n");
244 buf.Length = ACPI_ALLOCATE_BUFFER;
245 status = AcpiEvaluateObject(handle, "_PSS", NULL, &buf);
246 if (ACPI_FAILURE(status)) {
247 device_printf(dev, "Can't get _PSS package - %s\n",
248 AcpiFormatException(status));
252 obj = (ACPI_OBJECT *)buf.Pointer;
253 if (!ACPI_PKG_VALID(obj, 1)) {
254 device_printf(dev, "Invalid _PSS package\n");
260 device_set_desc(dev, "ACPI CPU P-State");
265 acpi_pst_attach(device_t dev)
267 struct acpi_pst_softc *sc = device_get_softc(dev), *pst;
268 struct acpi_pst_domain *dom = NULL;
271 ACPI_OBJECT *obj, *reg;
272 struct acpi_pstate *pstate, *p;
276 sc->pst_parent = device_get_softc(device_get_parent(dev));
277 sc->pst_handle = acpi_get_handle(dev);
278 sc->pst_cpuid = acpi_get_magic(dev);
281 * If there is a _PSD, then we create procossor domain
282 * accordingly. If there is no _PSD, we just fake a
283 * default processor domain0.
286 buf.Length = ACPI_ALLOCATE_BUFFER;
287 status = AcpiEvaluateObject(sc->pst_handle, "_PSD", NULL, &buf);
288 if (!ACPI_FAILURE(status)) {
289 obj = (ACPI_OBJECT *)buf.Pointer;
290 if (ACPI_PKG_VALID_EQ(obj, 1)) {
291 dom = acpi_pst_domain_create(dev,
292 &obj->Package.Elements[0]);
298 device_printf(dev, "Invalid _PSD package\n");
304 AcpiOsFree(buf.Pointer);
306 /* Create a stub one processor domain */
307 dom = acpi_pst_domain_alloc(0, ACPI_PSD_COORD_SWANY, 1);
308 dom->pd_flags |= ACPI_PSTDOM_FLAG_STUB;
311 /* Make sure that adding us will not overflow our domain */
313 LIST_FOREACH(pst, &dom->pd_pstlist, pst_link)
315 if (i == dom->pd_nproc) {
316 device_printf(dev, "Domain%u already contains %d P-States, "
317 "invalid _PSD package\n",
318 dom->pd_dom, dom->pd_nproc);
323 * Get control/status registers from _PCT
326 buf.Length = ACPI_ALLOCATE_BUFFER;
327 status = AcpiEvaluateObject(sc->pst_handle, "_PCT", NULL, &buf);
328 if (ACPI_FAILURE(status)) {
329 device_printf(dev, "Can't get _PCT package - %s\n",
330 AcpiFormatException(status));
334 obj = (ACPI_OBJECT *)buf.Pointer;
335 if (!ACPI_PKG_VALID_EQ(obj, 2)) {
336 device_printf(dev, "Invalid _PCT package\n");
341 /* Save control register */
342 reg = &obj->Package.Elements[0];
343 if (reg->Type != ACPI_TYPE_BUFFER || reg->Buffer.Pointer == NULL ||
344 reg->Buffer.Length < sizeof(sc->pst_creg) + 3)
346 memcpy(&sc->pst_creg, reg->Buffer.Pointer + 3, sizeof(sc->pst_creg));
348 device_printf(dev, "control reg %d %llx\n",
349 sc->pst_creg.SpaceId, sc->pst_creg.Address);
352 /* Save status register */
353 reg = &obj->Package.Elements[1];
354 if (reg->Type != ACPI_TYPE_BUFFER || reg->Buffer.Pointer == NULL ||
355 reg->Buffer.Length < sizeof(sc->pst_sreg) + 3)
357 memcpy(&sc->pst_sreg, reg->Buffer.Pointer + 3, sizeof(sc->pst_sreg));
359 device_printf(dev, "status reg %d %llx\n",
360 sc->pst_sreg.SpaceId, sc->pst_sreg.Address);
367 * Create P-State table according to _PSS
370 buf.Length = ACPI_ALLOCATE_BUFFER;
371 status = AcpiEvaluateObject(sc->pst_handle, "_PSS", NULL, &buf);
372 if (ACPI_FAILURE(status)) {
373 device_printf(dev, "Can't get _PSS package - %s\n",
374 AcpiFormatException(status));
378 obj = (ACPI_OBJECT *)buf.Pointer;
379 if (!ACPI_PKG_VALID(obj, 1)) {
380 device_printf(dev, "Invalid _PSS package\n");
385 /* Don't create too many P-States */
386 npstate = obj->Package.Count;
387 if (npstate > ACPI_NPSTATE_MAX) {
388 device_printf(dev, "Too many P-States, %d->%d\n",
389 npstate, ACPI_NPSTATE_MAX);
390 npstate = ACPI_NPSTATE_MAX;
394 * If we have already created P-State table,
395 * we must make sure that number of entries
398 if (acpi_pstates != NULL && acpi_npstates != npstate) {
399 device_printf(dev, "Inconsistent # of P-States "
400 "cross Processor objects\n");
406 * Create a temporary P-State table
408 pstate = kmalloc(sizeof(*pstate) * npstate, M_TEMP, M_WAITOK);
409 for (i = 0, p = pstate; i < npstate; ++i, ++p) {
411 uint32_t *ptr[ACPI_PSS_PX_NENTRY] = {
412 &p->st_freq, &p->st_power, &p->st_xsit_lat,
413 &p->st_bm_lat, &p->st_cval, &p->st_sval
417 pkg = &obj->Package.Elements[i];
418 if (!ACPI_PKG_VALID(pkg, ACPI_PSS_PX_NENTRY)) {
419 device_printf(dev, "Invalud _PSS P%d\n", i);
421 kfree(pstate, M_TEMP);
424 for (j = 0; j < ACPI_PSS_PX_NENTRY; ++j) {
425 if (acpi_PkgInt32(pkg, j, ptr[j]) != 0) {
426 device_printf(dev, "Can't extract "
427 "_PSS P%d %dth entry\n", i, j);
429 kfree(pstate, M_TEMP);
438 if (acpi_pstates == NULL) {
440 * If no P-State table is created yet,
441 * save the temporary one we just created.
443 acpi_pstates = pstate;
444 acpi_npstates = npstate;
448 for (i = 0; i < acpi_npstates; ++i) {
450 "freq %u, pwr %u, xlat %u, blat %u, "
451 "cv %08x, sv %08x\n",
452 acpi_pstates[i].st_freq,
453 acpi_pstates[i].st_power,
454 acpi_pstates[i].st_xsit_lat,
455 acpi_pstates[i].st_bm_lat,
456 acpi_pstates[i].st_cval,
457 acpi_pstates[i].st_sval);
462 * Make sure that P-State tables are same
463 * for all processors.
465 if (memcmp(pstate, acpi_pstates,
466 sizeof(*pstate) * npstate) != 0) {
467 device_printf(dev, "Inconsistent _PSS "
468 "cross Processor objects\n");
469 kfree(pstate, M_TEMP);
472 kfree(pstate, M_TEMP);
475 /* By default, we start from P-State table's first entry */
479 * Adjust the usable first entry of P-State table,
480 * if there is _PPC object.
483 buf.Length = ACPI_ALLOCATE_BUFFER;
484 status = AcpiEvaluateObject(sc->pst_handle, "_PPC", NULL, &buf);
485 if (!ACPI_FAILURE(status)) {
486 obj = (ACPI_OBJECT *)buf.Pointer;
487 if (obj->Type == ACPI_TYPE_INTEGER) {
488 if (obj->Integer.Value >= acpi_npstates) {
489 device_printf(dev, "Invalid _PPC value\n");
493 sc->pst_sstart = obj->Integer.Value;
495 device_printf(dev, "_PPC %d\n", sc->pst_sstart);
497 /* TODO: Install notifiy handler */
499 device_printf(dev, "Invalid _PPC object\n");
508 sc->pst_state = sc->pst_sstart;
510 /* Link us with the domain */
511 sc->pst_domain = dom;
512 LIST_INSERT_HEAD(&dom->pd_pstlist, sc, pst_link);
514 if (device_get_unit(dev) == 0)
515 AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_pst_postattach, NULL);
520 static struct acpi_pst_domain *
521 acpi_pst_domain_create(device_t dev, ACPI_OBJECT *obj)
523 struct acpi_pst_domain *dom;
524 uint32_t val, domain, coord, nproc;
526 if (!ACPI_PKG_VALID_EQ(obj, 5)) {
527 device_printf(dev, "Invalid _PSD package\n");
531 /* NumberOfEntries */
532 if (acpi_PkgInt32(obj, 0, &val) != 0 || val != 5) {
533 device_printf(dev, "Invalid _PSD NumberOfEntries\n");
538 if (acpi_PkgInt32(obj, 1, &val) != 0 || val != 0) {
539 device_printf(dev, "Invalid _PSD Revision\n");
543 if (acpi_PkgInt32(obj, 2, &domain) != 0 ||
544 acpi_PkgInt32(obj, 3, &coord) != 0 ||
545 acpi_PkgInt32(obj, 4, &nproc) != 0) {
546 device_printf(dev, "Can't extract _PSD package\n");
551 * If NumProcessors is greater than MAXCPU,
552 * then we will never start all CPUs within
553 * this domain, and power state transition
554 * will never happen, so we just bail out
557 if (nproc > MAXCPU) {
558 device_printf(dev, "Unsupported _PSD NumProcessors (%d)\n",
561 } else if (nproc == 0) {
562 device_printf(dev, "_PSD NumProcessors are zero\n");
566 if (!ACPI_PSD_COORD_VALID(coord)) {
567 device_printf(dev, "Invalid _PSD CoordType (%#x)\n", coord);
571 dom = acpi_pst_domain_find(domain);
573 if (dom->pd_coord != coord || dom->pd_nproc != nproc) {
574 device_printf(dev, "Inconsistent _PSD information "
575 "cross Processor objects\n");
581 dom = acpi_pst_domain_alloc(domain, coord, nproc);
583 device_printf(dev, "create domain%u\n", dom->pd_dom);
588 static struct acpi_pst_domain *
589 acpi_pst_domain_find(uint32_t domain)
591 struct acpi_pst_domain *dom;
593 LIST_FOREACH(dom, &acpi_pst_domains, pd_link) {
594 if (dom->pd_flags & ACPI_PSTDOM_FLAG_STUB)
596 if (dom->pd_dom == domain)
602 static struct acpi_pst_domain *
603 acpi_pst_domain_alloc(uint32_t domain, uint32_t coord, uint32_t nproc)
605 struct acpi_pst_domain *dom;
607 dom = kmalloc(sizeof(*dom), M_DEVBUF, M_WAITOK | M_ZERO);
608 dom->pd_dom = domain;
609 dom->pd_coord = coord;
610 dom->pd_nproc = nproc;
611 dom->pd_state = 0; /* XXX */
612 dom->pd_sstart = 0; /* XXX */
613 LIST_INIT(&dom->pd_pstlist);
615 LIST_INSERT_HEAD(&acpi_pst_domains, dom, pd_link);
621 acpi_pst_domain_set_pstate(struct acpi_pst_domain *dom, int i)
623 const struct acpi_pstate *pstate;
624 struct acpi_pst_softc *sc;
627 KKASSERT(i >= 0 && i < acpi_npstates);
628 pstate = &acpi_pstates[i];
631 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
633 error = acpi_pst_set_pstate(sc, pstate);
635 device_printf(sc->pst_dev, "can't set "
636 "freq %d\n", pstate->st_freq);
637 /* XXX error cleanup? */
639 if (dom->pd_coord == ACPI_PSD_COORD_SWANY)
650 acpi_pst_postattach(void *arg __unused)
652 struct acpi_pst_domain *dom;
653 struct acpi_cpux_softc *cpux;
655 int i, ndevices, error, has_domain;
659 error = devclass_get_devices(acpi_pst_devclass, &devices, &ndevices);
667 for (i = 0; i < ndevices; ++i) {
668 cpux = device_get_softc(device_get_parent(devices[i]));
669 if (cpux->glob_sysctl_tree != NULL)
672 kfree(devices, M_TEMP);
673 KKASSERT(cpux != NULL);
675 if (acpi_pst_md == NULL)
676 kprintf("ACPI: no P-State CPU driver\n");
679 LIST_FOREACH(dom, &acpi_pst_domains, pd_link) {
680 struct acpi_pst_softc *sc;
684 * Make sure that all processors belonging to this
685 * domain are located.
688 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link)
690 if (i != dom->pd_nproc) {
691 kprintf("ACPI: domain%u misses processors, "
692 "should be %d, got %d\n", dom->pd_dom,
694 dom->pd_flags |= ACPI_PSTDOM_FLAG_DEAD;
699 * Validate P-State configurations for this domain
701 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
702 error = acpi_pst_check_csr(sc);
706 error = acpi_pst_check_pstates(sc);
711 kprintf("ACPI: domain%u P-State configuration "
712 "check failed\n", dom->pd_dom);
713 dom->pd_flags |= ACPI_PSTDOM_FLAG_DEAD;
719 ksnprintf(buf, sizeof(buf), "px_dom%u", dom->pd_dom);
721 sysctl_ctx_init(&dom->pd_sysctl_ctx);
722 dom->pd_sysctl_tree =
723 SYSCTL_ADD_NODE(&dom->pd_sysctl_ctx,
724 SYSCTL_CHILDREN(cpux->glob_sysctl_tree),
725 OID_AUTO, buf, CTLFLAG_RD, 0,
727 if (dom->pd_sysctl_tree == NULL) {
728 kprintf("ACPI: Can't create sysctl tree for domain%u",
733 SYSCTL_ADD_PROC(&dom->pd_sysctl_ctx,
734 SYSCTL_CHILDREN(dom->pd_sysctl_tree),
735 OID_AUTO, "available",
736 CTLTYPE_STRING | CTLFLAG_RD,
737 dom, 0, acpi_pst_sysctl_freqs, "A",
738 "available frequencies");
740 SYSCTL_ADD_PROC(&dom->pd_sysctl_ctx,
741 SYSCTL_CHILDREN(dom->pd_sysctl_tree),
743 CTLTYPE_STRING | CTLFLAG_RD,
744 dom, 0, acpi_pst_sysctl_members, "A",
747 if (acpi_pst_md != NULL &&
748 acpi_pst_md->pmd_set_pstate != NULL) {
749 SYSCTL_ADD_PROC(&dom->pd_sysctl_ctx,
750 SYSCTL_CHILDREN(dom->pd_sysctl_tree),
752 CTLTYPE_UINT | CTLFLAG_RW,
753 dom, 0, acpi_pst_sysctl_select,
754 "IU", "select freq");
758 if (has_domain && acpi_pst_md != NULL &&
759 acpi_pst_md->pmd_set_pstate != NULL) {
760 SYSCTL_ADD_PROC(&cpux->glob_sysctl_ctx,
761 SYSCTL_CHILDREN(cpux->glob_sysctl_tree),
762 OID_AUTO, "px_global",
763 CTLTYPE_UINT | CTLFLAG_RW,
764 NULL, 0, acpi_pst_sysctl_global,
765 "IU", "select freq for all domains");
770 acpi_pst_sysctl_freqs(SYSCTL_HANDLER_ARGS)
772 struct acpi_pst_domain *dom = arg1;
776 for (i = 0; i < acpi_npstates; ++i) {
778 error = SYSCTL_OUT(req, " ", 1);
783 if (i < dom->pd_sstart)
788 ksnprintf(buf, sizeof(buf), pat,
789 acpi_pstates[i].st_freq);
790 error = SYSCTL_OUT(req, buf, strlen(buf));
797 acpi_pst_sysctl_members(SYSCTL_HANDLER_ARGS)
799 struct acpi_pst_domain *dom = arg1;
800 struct acpi_pst_softc *sc;
804 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
807 if (error == 0 && loop)
808 error = SYSCTL_OUT(req, " ", 1);
810 ksnprintf(buf, sizeof(buf), "cpu%d", sc->pst_cpuid);
811 error = SYSCTL_OUT(req, buf, strlen(buf));
814 if (error == 0 && acpi_pst_md && acpi_pst_md->pmd_get_pstate) {
815 const struct acpi_pstate *pstate;
818 pstate = acpi_pst_get_pstate(sc);
819 if (pstate == NULL) {
822 ksnprintf(buf, sizeof(buf), "(%d)",
826 error = SYSCTL_OUT(req, str, strlen(str));
834 acpi_pst_sysctl_select(SYSCTL_HANDLER_ARGS)
836 struct acpi_pst_domain *dom = arg1;
839 KKASSERT(dom->pd_state >= 0 && dom->pd_state < acpi_npstates);
841 freq = acpi_pstates[dom->pd_state].st_freq;
843 error = sysctl_handle_int(oidp, &freq, 0, req);
844 if (error || req->newptr == NULL)
847 i = acpi_pst_freq2index(freq);
851 acpi_pst_domain_set_pstate(dom, i);
856 acpi_pst_sysctl_global(SYSCTL_HANDLER_ARGS)
858 struct acpi_pst_domain *dom;
861 KKASSERT(acpi_pst_global_state >= 0 &&
862 acpi_pst_global_state < acpi_npstates);
864 freq = acpi_pstates[acpi_pst_global_state].st_freq;
866 error = sysctl_handle_int(oidp, &freq, 0, req);
867 if (error || req->newptr == NULL)
870 i = acpi_pst_freq2index(freq);
874 LIST_FOREACH(dom, &acpi_pst_domains, pd_link) {
875 /* Skip dead domain */
876 if (dom->pd_flags & ACPI_PSTDOM_FLAG_DEAD)
878 acpi_pst_domain_set_pstate(dom, i);
880 acpi_pst_global_state = i;
886 acpi_pst_check_csr_handler(struct netmsg *nmsg)
888 struct netmsg_acpi_pst *msg = (struct netmsg_acpi_pst *)nmsg;
891 error = acpi_pst_md->pmd_check_csr(msg->ctrl, msg->status);
892 lwkt_replymsg(&nmsg->nm_lmsg, error);
896 acpi_pst_check_csr(struct acpi_pst_softc *sc)
898 struct netmsg_acpi_pst msg;
900 if (acpi_pst_md == NULL)
903 netmsg_init(&msg.nmsg, &curthread->td_msgport,
904 MSGF_MPSAFE | MSGF_PRIORITY,
905 acpi_pst_check_csr_handler);
906 msg.ctrl = &sc->pst_creg;
907 msg.status = &sc->pst_sreg;
909 return lwkt_domsg(cpu_portfn(sc->pst_cpuid), &msg.nmsg.nm_lmsg, 0);
913 acpi_pst_check_pstates_handler(struct netmsg *nmsg)
917 error = acpi_pst_md->pmd_check_pstates(acpi_pstates, acpi_npstates);
918 lwkt_replymsg(&nmsg->nm_lmsg, error);
922 acpi_pst_check_pstates(struct acpi_pst_softc *sc)
926 if (acpi_pst_md == NULL)
929 netmsg_init(&nmsg, &curthread->td_msgport,
930 MSGF_MPSAFE | MSGF_PRIORITY,
931 acpi_pst_check_pstates_handler);
933 return lwkt_domsg(cpu_portfn(sc->pst_cpuid), &nmsg.nm_lmsg, 0);
937 acpi_pst_set_pstate_handler(struct netmsg *nmsg)
939 struct netmsg_acpi_pst *msg = (struct netmsg_acpi_pst *)nmsg;
942 error = acpi_pst_md->pmd_set_pstate(msg->ctrl, msg->status,
943 nmsg->nm_lmsg.u.ms_resultp);
944 lwkt_replymsg(&nmsg->nm_lmsg, error);
948 acpi_pst_set_pstate(struct acpi_pst_softc *sc, const struct acpi_pstate *pstate)
950 struct netmsg_acpi_pst msg;
952 KKASSERT(acpi_pst_md != NULL);
955 device_printf(sc->pst_dev, "set pstate, freq %d\n",
959 netmsg_init(&msg.nmsg, &curthread->td_msgport,
960 MSGF_MPSAFE | MSGF_PRIORITY,
961 acpi_pst_set_pstate_handler);
962 msg.nmsg.nm_lmsg.u.ms_resultp = __DECONST(void *, pstate);
963 msg.ctrl = &sc->pst_creg;
964 msg.status = &sc->pst_sreg;
966 return lwkt_domsg(cpu_portfn(sc->pst_cpuid), &msg.nmsg.nm_lmsg, 0);
970 acpi_pst_get_pstate_handler(struct netmsg *nmsg)
972 struct netmsg_acpi_pst *msg = (struct netmsg_acpi_pst *)nmsg;
973 const struct acpi_pstate *pstate;
975 pstate = acpi_pst_md->pmd_get_pstate(msg->status, acpi_pstates,
977 nmsg->nm_lmsg.u.ms_resultp = __DECONST(void *, pstate);
978 lwkt_replymsg(&nmsg->nm_lmsg, 0);
981 static const struct acpi_pstate *
982 acpi_pst_get_pstate(struct acpi_pst_softc *sc)
984 struct netmsg_acpi_pst msg;
986 if (acpi_pst_md == NULL)
989 netmsg_init(&msg.nmsg, &curthread->td_msgport,
990 MSGF_MPSAFE | MSGF_PRIORITY,
991 acpi_pst_get_pstate_handler);
992 msg.status = &sc->pst_sreg;
994 lwkt_domsg(cpu_portfn(sc->pst_cpuid), &msg.nmsg.nm_lmsg, 0);
995 return msg.nmsg.nm_lmsg.u.ms_resultp;