ACPI P-State probing: Put _PCT evaluation error logging under bootverbose.
[dragonfly.git] / sys / dev / acpica5 / acpi_cpu_pstate.c
blob33703ecc86fb6d9450f39cb141202d0d4921f134
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/sysctl.h>
43 #include <sys/msgport2.h>
45 #include <net/netisr.h>
46 #include <net/netmsg2.h>
47 #include <net/if_var.h>
49 #include "acpi.h"
50 #include "acpivar.h"
51 #include "acpi_cpu.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 {
70 struct netmsg nmsg;
72 const ACPI_RESOURCE_GENERIC_REGISTER *ctrl;
73 const ACPI_RESOURCE_GENERIC_REGISTER *status;
76 struct acpi_pst_domain {
77 uint32_t pd_dom;
78 uint32_t pd_coord;
79 uint32_t pd_nproc;
80 LIST_ENTRY(acpi_pst_domain) pd_link;
82 uint32_t pd_flags;
84 int pd_state;
85 int pd_sstart;
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 {
97 device_t pst_dev;
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;
103 int pst_state;
104 int pst_sstart;
105 int pst_cpuid;
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),
160 /* Bus interface */
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),
176 { 0, 0 }
179 static driver_t acpi_pst_driver = {
180 "cpu_pst",
181 acpi_pst_methods,
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);
189 static __inline int
190 acpi_pst_freq2index(int freq)
192 int i;
194 for (i = 0; i < acpi_npstates; ++i) {
195 if (acpi_pstates[i].st_freq == freq)
196 return i;
198 return -1;
201 static int
202 acpi_pst_probe(device_t dev)
204 ACPI_BUFFER buf;
205 ACPI_HANDLE handle;
206 ACPI_STATUS status;
207 ACPI_OBJECT *obj;
209 if (acpi_disabled("cpu_pst") ||
210 acpi_get_type(dev) != ACPI_TYPE_PROCESSOR)
211 return ENXIO;
213 if (acpi_pst_md == NULL)
214 acpi_pst_md = acpi_pst_md_probe();
216 handle = acpi_get_handle(dev);
219 * Check _PCT package
221 buf.Pointer = NULL;
222 buf.Length = ACPI_ALLOCATE_BUFFER;
223 status = AcpiEvaluateObject(handle, "_PCT", NULL, &buf);
224 if (ACPI_FAILURE(status)) {
225 if (bootverbose) {
226 device_printf(dev, "Can't get _PCT package - %s\n",
227 AcpiFormatException(status));
229 return ENXIO;
232 obj = (ACPI_OBJECT *)buf.Pointer;
233 if (!ACPI_PKG_VALID_EQ(obj, 2)) {
234 device_printf(dev, "Invalid _PCT package\n");
235 AcpiOsFree(obj);
236 return ENXIO;
238 AcpiOsFree(obj);
241 * Check _PSS package
243 buf.Pointer = NULL;
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));
249 return ENXIO;
252 obj = (ACPI_OBJECT *)buf.Pointer;
253 if (!ACPI_PKG_VALID(obj, 1)) {
254 device_printf(dev, "Invalid _PSS package\n");
255 AcpiOsFree(obj);
256 return ENXIO;
258 AcpiOsFree(obj);
260 device_set_desc(dev, "ACPI CPU P-State");
261 return 0;
264 static int
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;
269 ACPI_BUFFER buf;
270 ACPI_STATUS status;
271 ACPI_OBJECT *obj, *reg;
272 struct acpi_pstate *pstate, *p;
273 int i, npstate;
275 sc->pst_dev = dev;
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.
285 buf.Pointer = NULL;
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]);
293 if (dom == NULL) {
294 AcpiOsFree(obj);
295 return ENXIO;
297 } else {
298 device_printf(dev, "Invalid _PSD package\n");
299 AcpiOsFree(obj);
300 return ENXIO;
303 /* Free _PSD */
304 AcpiOsFree(buf.Pointer);
305 } else {
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 */
312 i = 0;
313 LIST_FOREACH(pst, &dom->pd_pstlist, pst_link)
314 ++i;
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);
319 return ENXIO;
323 * Get control/status registers from _PCT
325 buf.Pointer = NULL;
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));
331 return ENXIO;
334 obj = (ACPI_OBJECT *)buf.Pointer;
335 if (!ACPI_PKG_VALID_EQ(obj, 2)) {
336 device_printf(dev, "Invalid _PCT package\n");
337 AcpiOsFree(obj);
338 return ENXIO;
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)
345 return ENXIO;
346 memcpy(&sc->pst_creg, reg->Buffer.Pointer + 3, sizeof(sc->pst_creg));
347 if (bootverbose) {
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)
356 return ENXIO;
357 memcpy(&sc->pst_sreg, reg->Buffer.Pointer + 3, sizeof(sc->pst_sreg));
358 if (bootverbose) {
359 device_printf(dev, "status reg %d %llx\n",
360 sc->pst_sreg.SpaceId, sc->pst_sreg.Address);
363 /* Free _PCT */
364 AcpiOsFree(obj);
367 * Create P-State table according to _PSS
369 buf.Pointer = NULL;
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));
375 return ENXIO;
378 obj = (ACPI_OBJECT *)buf.Pointer;
379 if (!ACPI_PKG_VALID(obj, 1)) {
380 device_printf(dev, "Invalid _PSS package\n");
381 AcpiOsFree(obj);
382 return ENXIO;
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
396 * is consistent.
398 if (acpi_pstates != NULL && acpi_npstates != npstate) {
399 device_printf(dev, "Inconsistent # of P-States "
400 "cross Processor objects\n");
401 AcpiOsFree(obj);
402 return ENXIO;
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) {
410 ACPI_OBJECT *pkg;
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
415 int j;
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);
420 AcpiOsFree(obj);
421 kfree(pstate, M_TEMP);
422 return ENXIO;
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);
428 AcpiOsFree(obj);
429 kfree(pstate, M_TEMP);
430 return ENXIO;
435 /* Free _PSS */
436 AcpiOsFree(obj);
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;
445 pstate = NULL;
447 if (bootverbose) {
448 for (i = 0; i < acpi_npstates; ++i) {
449 device_printf(dev,
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);
460 } else {
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);
470 return ENXIO;
472 kfree(pstate, M_TEMP);
475 /* By default, we start from P-State table's first entry */
476 sc->pst_sstart = 0;
479 * Adjust the usable first entry of P-State table,
480 * if there is _PPC object.
482 buf.Pointer = NULL;
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");
490 AcpiOsFree(obj);
491 return ENXIO;
493 sc->pst_sstart = obj->Integer.Value;
494 if (bootverbose)
495 device_printf(dev, "_PPC %d\n", sc->pst_sstart);
497 /* TODO: Install notifiy handler */
498 } else {
499 device_printf(dev, "Invalid _PPC object\n");
500 AcpiOsFree(obj);
501 return ENXIO;
504 /* Free _PPC */
505 AcpiOsFree(obj);
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);
517 return 0;
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");
528 return NULL;
531 /* NumberOfEntries */
532 if (acpi_PkgInt32(obj, 0, &val) != 0 || val != 5) {
533 device_printf(dev, "Invalid _PSD NumberOfEntries\n");
534 return NULL;
537 /* Revision */
538 if (acpi_PkgInt32(obj, 1, &val) != 0 || val != 0) {
539 device_printf(dev, "Invalid _PSD Revision\n");
540 return NULL;
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");
547 return NULL;
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
555 * here.
557 if (nproc > MAXCPU) {
558 device_printf(dev, "Unsupported _PSD NumProcessors (%d)\n",
559 nproc);
560 return NULL;
561 } else if (nproc == 0) {
562 device_printf(dev, "_PSD NumProcessors are zero\n");
563 return NULL;
566 if (!ACPI_PSD_COORD_VALID(coord)) {
567 device_printf(dev, "Invalid _PSD CoordType (%#x)\n", coord);
568 return NULL;
571 dom = acpi_pst_domain_find(domain);
572 if (dom != NULL) {
573 if (dom->pd_coord != coord || dom->pd_nproc != nproc) {
574 device_printf(dev, "Inconsistent _PSD information "
575 "cross Processor objects\n");
576 return NULL;
578 return dom;
581 dom = acpi_pst_domain_alloc(domain, coord, nproc);
582 if (bootverbose)
583 device_printf(dev, "create domain%u\n", dom->pd_dom);
585 return 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)
595 continue;
596 if (dom->pd_dom == domain)
597 return dom;
599 return NULL;
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);
617 return dom;
620 static int
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;
625 int done, error;
627 KKASSERT(i >= 0 && i < acpi_npstates);
628 pstate = &acpi_pstates[i];
630 done = 0;
631 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
632 if (!done) {
633 error = acpi_pst_set_pstate(sc, pstate);
634 if (error) {
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)
640 done = 1;
642 sc->pst_state = i;
644 dom->pd_state = i;
646 return 0;
649 static void
650 acpi_pst_postattach(void *arg __unused)
652 struct acpi_pst_domain *dom;
653 struct acpi_cpux_softc *cpux;
654 device_t *devices;
655 int i, ndevices, error, has_domain;
657 devices = NULL;
658 ndevices = 0;
659 error = devclass_get_devices(acpi_pst_devclass, &devices, &ndevices);
660 if (error)
661 return;
663 if (ndevices == 0)
664 return;
666 cpux = NULL;
667 for (i = 0; i < ndevices; ++i) {
668 cpux = device_get_softc(device_get_parent(devices[i]));
669 if (cpux->glob_sysctl_tree != NULL)
670 break;
672 kfree(devices, M_TEMP);
673 KKASSERT(cpux != NULL);
675 if (acpi_pst_md == NULL)
676 kprintf("ACPI: no P-State CPU driver\n");
678 has_domain = 0;
679 LIST_FOREACH(dom, &acpi_pst_domains, pd_link) {
680 struct acpi_pst_softc *sc;
681 char buf[32];
684 * Make sure that all processors belonging to this
685 * domain are located.
687 i = 0;
688 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link)
689 ++i;
690 if (i != dom->pd_nproc) {
691 kprintf("ACPI: domain%u misses processors, "
692 "should be %d, got %d\n", dom->pd_dom,
693 dom->pd_nproc, i);
694 dom->pd_flags |= ACPI_PSTDOM_FLAG_DEAD;
695 continue;
699 * Validate P-State configurations for this domain
701 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
702 error = acpi_pst_check_csr(sc);
703 if (error)
704 break;
706 error = acpi_pst_check_pstates(sc);
707 if (error)
708 break;
710 if (sc != NULL) {
711 kprintf("ACPI: domain%u P-State configuration "
712 "check failed\n", dom->pd_dom);
713 dom->pd_flags |= ACPI_PSTDOM_FLAG_DEAD;
714 continue;
717 has_domain = 1;
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,
726 "P-State domain");
727 if (dom->pd_sysctl_tree == NULL) {
728 kprintf("ACPI: Can't create sysctl tree for domain%u",
729 dom->pd_dom);
730 continue;
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),
742 OID_AUTO, "members",
743 CTLTYPE_STRING | CTLFLAG_RD,
744 dom, 0, acpi_pst_sysctl_members, "A",
745 "member cpus");
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),
751 OID_AUTO, "select",
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");
769 static int
770 acpi_pst_sysctl_freqs(SYSCTL_HANDLER_ARGS)
772 struct acpi_pst_domain *dom = arg1;
773 int i, error;
775 error = 0;
776 for (i = 0; i < acpi_npstates; ++i) {
777 if (error == 0 && i)
778 error = SYSCTL_OUT(req, " ", 1);
779 if (error == 0) {
780 const char *pat;
781 char buf[32];
783 if (i < dom->pd_sstart)
784 pat = "(%u)";
785 else
786 pat = "%u";
788 ksnprintf(buf, sizeof(buf), pat,
789 acpi_pstates[i].st_freq);
790 error = SYSCTL_OUT(req, buf, strlen(buf));
793 return error;
796 static int
797 acpi_pst_sysctl_members(SYSCTL_HANDLER_ARGS)
799 struct acpi_pst_domain *dom = arg1;
800 struct acpi_pst_softc *sc;
801 int loop, error;
803 loop = error = 0;
804 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
805 char buf[32];
807 if (error == 0 && loop)
808 error = SYSCTL_OUT(req, " ", 1);
809 if (error == 0) {
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;
816 const char *str;
818 pstate = acpi_pst_get_pstate(sc);
819 if (pstate == NULL) {
820 str = "(*)";
821 } else {
822 ksnprintf(buf, sizeof(buf), "(%d)",
823 pstate->st_freq);
824 str = buf;
826 error = SYSCTL_OUT(req, str, strlen(str));
828 ++loop;
830 return error;
833 static int
834 acpi_pst_sysctl_select(SYSCTL_HANDLER_ARGS)
836 struct acpi_pst_domain *dom = arg1;
837 int error, i, freq;
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)
845 return error;
847 i = acpi_pst_freq2index(freq);
848 if (i < 0)
849 return EINVAL;
851 acpi_pst_domain_set_pstate(dom, i);
852 return 0;
855 static int
856 acpi_pst_sysctl_global(SYSCTL_HANDLER_ARGS)
858 struct acpi_pst_domain *dom;
859 int error, i, freq;
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)
868 return error;
870 i = acpi_pst_freq2index(freq);
871 if (i < 0)
872 return EINVAL;
874 LIST_FOREACH(dom, &acpi_pst_domains, pd_link) {
875 /* Skip dead domain */
876 if (dom->pd_flags & ACPI_PSTDOM_FLAG_DEAD)
877 continue;
878 acpi_pst_domain_set_pstate(dom, i);
880 acpi_pst_global_state = i;
882 return 0;
885 static void
886 acpi_pst_check_csr_handler(struct netmsg *nmsg)
888 struct netmsg_acpi_pst *msg = (struct netmsg_acpi_pst *)nmsg;
889 int error;
891 error = acpi_pst_md->pmd_check_csr(msg->ctrl, msg->status);
892 lwkt_replymsg(&nmsg->nm_lmsg, error);
895 static int
896 acpi_pst_check_csr(struct acpi_pst_softc *sc)
898 struct netmsg_acpi_pst msg;
900 if (acpi_pst_md == NULL)
901 return 0;
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);
912 static void
913 acpi_pst_check_pstates_handler(struct netmsg *nmsg)
915 int error;
917 error = acpi_pst_md->pmd_check_pstates(acpi_pstates, acpi_npstates);
918 lwkt_replymsg(&nmsg->nm_lmsg, error);
921 static int
922 acpi_pst_check_pstates(struct acpi_pst_softc *sc)
924 struct netmsg nmsg;
926 if (acpi_pst_md == NULL)
927 return 0;
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);
936 static void
937 acpi_pst_set_pstate_handler(struct netmsg *nmsg)
939 struct netmsg_acpi_pst *msg = (struct netmsg_acpi_pst *)nmsg;
940 int error;
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);
947 static int
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);
954 if (bootverbose) {
955 device_printf(sc->pst_dev, "set pstate, freq %d\n",
956 pstate->st_freq);
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);
969 static void
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,
976 acpi_npstates);
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)
987 return 0;
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;