Sync ACPI with FreeBSD 7.2
[dragonfly.git] / sys / dev / acpica5 / acpi_cpu_pstate.c
blob5e436c8eda20879510fb0a6fdcbe0756319fa282
1 /*
2 * Copyright (c) 2009 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Sepherosa Ziehau <sepherosa@gmail.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
35 #include "opt_acpi.h"
37 #include <sys/param.h>
38 #include <sys/bus.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
41 #include <sys/queue.h>
42 #include <sys/rman.h>
43 #include <sys/sysctl.h>
44 #include <sys/msgport2.h>
46 #include <net/netisr.h>
47 #include <net/netmsg2.h>
48 #include <net/if_var.h>
50 #include "acpi.h"
51 #include "acpivar.h"
52 #include "acpi_cpu.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 nmsg;
73 const struct acpi_pst_res *ctrl;
74 const struct acpi_pst_res *status;
77 struct acpi_pst_domain {
78 uint32_t pd_dom;
79 uint32_t pd_coord;
80 uint32_t pd_nproc;
81 LIST_ENTRY(acpi_pst_domain) pd_link;
83 uint32_t pd_flags;
85 int pd_state;
86 int pd_sstart;
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 */
97 struct acpi_pst_softc {
98 device_t pst_dev;
99 struct acpi_cpux_softc *pst_parent;
100 struct acpi_pst_domain *pst_domain;
101 struct acpi_pst_res pst_creg;
102 struct acpi_pst_res pst_sreg;
104 int pst_state;
105 int pst_sstart;
106 int pst_cpuid;
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(device_t, ACPI_OBJECT *);
119 static struct acpi_pst_domain *
120 acpi_pst_domain_find(uint32_t);
121 static struct acpi_pst_domain *
122 acpi_pst_domain_alloc(uint32_t, uint32_t, uint32_t);
123 static int acpi_pst_domain_set_pstate(struct acpi_pst_domain *, int);
125 static int acpi_pst_check_csr(struct acpi_pst_softc *);
126 static int acpi_pst_check_pstates(struct acpi_pst_softc *);
127 static int acpi_pst_init(struct acpi_pst_softc *);
128 static int acpi_pst_set_pstate(struct acpi_pst_softc *,
129 const struct acpi_pstate *);
130 static const struct acpi_pstate *
131 acpi_pst_get_pstate(struct acpi_pst_softc *);
132 static int acpi_pst_alloc_resource(device_t, ACPI_OBJECT *, int,
133 struct acpi_pst_res *);
135 static void acpi_pst_check_csr_handler(struct netmsg *);
136 static void acpi_pst_check_pstates_handler(struct netmsg *);
137 static void acpi_pst_init_handler(struct netmsg *);
138 static void acpi_pst_set_pstate_handler(struct netmsg *);
139 static void acpi_pst_get_pstate_handler(struct netmsg *);
141 static int acpi_pst_sysctl_freqs(SYSCTL_HANDLER_ARGS);
142 static int acpi_pst_sysctl_members(SYSCTL_HANDLER_ARGS);
143 static int acpi_pst_sysctl_select(SYSCTL_HANDLER_ARGS);
144 static int acpi_pst_sysctl_global(SYSCTL_HANDLER_ARGS);
146 static struct acpi_pst_domlist acpi_pst_domains =
147 LIST_HEAD_INITIALIZER(acpi_pst_domains);
149 static int acpi_pst_global_state;
151 static int acpi_npstates;
152 static struct acpi_pstate *acpi_pstates;
154 static const struct acpi_pst_md *acpi_pst_md;
156 static device_method_t acpi_pst_methods[] = {
157 /* Device interface */
158 DEVMETHOD(device_probe, acpi_pst_probe),
159 DEVMETHOD(device_attach, acpi_pst_attach),
160 DEVMETHOD(device_detach, bus_generic_detach),
161 DEVMETHOD(device_shutdown, bus_generic_shutdown),
162 DEVMETHOD(device_suspend, bus_generic_suspend),
163 DEVMETHOD(device_resume, bus_generic_resume),
165 /* Bus interface */
166 DEVMETHOD(bus_add_child, bus_generic_add_child),
167 DEVMETHOD(bus_print_child, bus_generic_print_child),
168 DEVMETHOD(bus_read_ivar, bus_generic_read_ivar),
169 DEVMETHOD(bus_write_ivar, bus_generic_write_ivar),
170 DEVMETHOD(bus_get_resource_list, bus_generic_get_resource_list),
171 DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
172 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
173 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
174 DEVMETHOD(bus_release_resource, bus_generic_release_resource),
175 DEVMETHOD(bus_driver_added, bus_generic_driver_added),
176 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
177 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
178 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
179 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
181 { 0, 0 }
184 static driver_t acpi_pst_driver = {
185 "cpu_pst",
186 acpi_pst_methods,
187 sizeof(struct acpi_pst_softc)
190 static devclass_t acpi_pst_devclass;
191 DRIVER_MODULE(cpu_pst, cpu, acpi_pst_driver, acpi_pst_devclass, 0, 0);
192 MODULE_DEPEND(cpu_pst, acpi, 1, 1, 1);
194 static __inline int
195 acpi_pst_freq2index(int freq)
197 int i;
199 for (i = 0; i < acpi_npstates; ++i) {
200 if (acpi_pstates[i].st_freq == freq)
201 return i;
203 return -1;
206 static int
207 acpi_pst_probe(device_t dev)
209 ACPI_BUFFER buf;
210 ACPI_HANDLE handle;
211 ACPI_STATUS status;
212 ACPI_OBJECT *obj;
214 if (acpi_disabled("cpu_pst") ||
215 acpi_get_type(dev) != ACPI_TYPE_PROCESSOR)
216 return ENXIO;
218 if (acpi_pst_md == NULL)
219 acpi_pst_md = acpi_pst_md_probe();
221 handle = acpi_get_handle(dev);
224 * Check _PCT package
226 buf.Pointer = NULL;
227 buf.Length = ACPI_ALLOCATE_BUFFER;
228 status = AcpiEvaluateObject(handle, "_PCT", NULL, &buf);
229 if (ACPI_FAILURE(status)) {
230 if (bootverbose) {
231 device_printf(dev, "Can't get _PCT package - %s\n",
232 AcpiFormatException(status));
234 return ENXIO;
237 obj = (ACPI_OBJECT *)buf.Pointer;
238 if (!ACPI_PKG_VALID_EQ(obj, 2)) {
239 device_printf(dev, "Invalid _PCT package\n");
240 AcpiOsFree(obj);
241 return ENXIO;
243 AcpiOsFree(obj);
246 * Check _PSS package
248 buf.Pointer = NULL;
249 buf.Length = ACPI_ALLOCATE_BUFFER;
250 status = AcpiEvaluateObject(handle, "_PSS", NULL, &buf);
251 if (ACPI_FAILURE(status)) {
252 device_printf(dev, "Can't get _PSS package - %s\n",
253 AcpiFormatException(status));
254 return ENXIO;
257 obj = (ACPI_OBJECT *)buf.Pointer;
258 if (!ACPI_PKG_VALID(obj, 1)) {
259 device_printf(dev, "Invalid _PSS package\n");
260 AcpiOsFree(obj);
261 return ENXIO;
263 AcpiOsFree(obj);
265 device_set_desc(dev, "ACPI CPU P-State");
266 return 0;
269 static int
270 acpi_pst_attach(device_t dev)
272 struct acpi_pst_softc *sc = device_get_softc(dev), *pst;
273 struct acpi_pst_domain *dom = NULL;
274 ACPI_BUFFER buf;
275 ACPI_STATUS status;
276 ACPI_OBJECT *obj;
277 struct acpi_pstate *pstate, *p;
278 int i, npstate, error;
280 sc->pst_dev = dev;
281 sc->pst_parent = device_get_softc(device_get_parent(dev));
282 sc->pst_handle = acpi_get_handle(dev);
283 sc->pst_cpuid = acpi_get_magic(dev);
286 * If there is a _PSD, then we create procossor domain
287 * accordingly. If there is no _PSD, we just fake a
288 * default processor domain0.
290 buf.Pointer = NULL;
291 buf.Length = ACPI_ALLOCATE_BUFFER;
292 status = AcpiEvaluateObject(sc->pst_handle, "_PSD", NULL, &buf);
293 if (!ACPI_FAILURE(status)) {
294 obj = (ACPI_OBJECT *)buf.Pointer;
295 if (ACPI_PKG_VALID_EQ(obj, 1)) {
296 dom = acpi_pst_domain_create(dev,
297 &obj->Package.Elements[0]);
298 if (dom == NULL) {
299 AcpiOsFree(obj);
300 return ENXIO;
302 } else {
303 device_printf(dev, "Invalid _PSD package\n");
304 AcpiOsFree(obj);
305 return ENXIO;
308 /* Free _PSD */
309 AcpiOsFree(buf.Pointer);
310 } else {
311 /* Create a stub one processor domain */
312 dom = acpi_pst_domain_alloc(0, ACPI_PSD_COORD_SWANY, 1);
313 dom->pd_flags |= ACPI_PSTDOM_FLAG_STUB;
316 /* Make sure that adding us will not overflow our domain */
317 i = 0;
318 LIST_FOREACH(pst, &dom->pd_pstlist, pst_link)
319 ++i;
320 if (i == dom->pd_nproc) {
321 device_printf(dev, "Domain%u already contains %d P-States, "
322 "invalid _PSD package\n",
323 dom->pd_dom, dom->pd_nproc);
324 return ENXIO;
326 KKASSERT(i < dom->pd_nproc);
329 * Get control/status registers from _PCT
331 buf.Pointer = NULL;
332 buf.Length = ACPI_ALLOCATE_BUFFER;
333 status = AcpiEvaluateObject(sc->pst_handle, "_PCT", NULL, &buf);
334 if (ACPI_FAILURE(status)) {
335 device_printf(dev, "Can't get _PCT package - %s\n",
336 AcpiFormatException(status));
337 return ENXIO;
340 obj = (ACPI_OBJECT *)buf.Pointer;
341 if (!ACPI_PKG_VALID_EQ(obj, 2)) {
342 device_printf(dev, "Invalid _PCT package\n");
343 AcpiOsFree(obj);
344 return ENXIO;
347 /* Save and try allocating control register */
348 error = acpi_pst_alloc_resource(dev, obj, 0, &sc->pst_creg);
349 if (error) {
350 AcpiOsFree(obj);
351 return error;
353 if (bootverbose) {
354 device_printf(dev, "control reg %d %llx\n",
355 sc->pst_creg.pr_gas.SpaceId,
356 sc->pst_creg.pr_gas.Address);
359 /* Save and try allocating status register */
360 error = acpi_pst_alloc_resource(dev, obj, 1, &sc->pst_sreg);
361 if (error) {
362 AcpiOsFree(obj);
363 return error;
365 if (bootverbose) {
366 device_printf(dev, "status reg %d %llx\n",
367 sc->pst_sreg.pr_gas.SpaceId,
368 sc->pst_sreg.pr_gas.Address);
371 /* Free _PCT */
372 AcpiOsFree(obj);
375 * Create P-State table according to _PSS
377 buf.Pointer = NULL;
378 buf.Length = ACPI_ALLOCATE_BUFFER;
379 status = AcpiEvaluateObject(sc->pst_handle, "_PSS", NULL, &buf);
380 if (ACPI_FAILURE(status)) {
381 device_printf(dev, "Can't get _PSS package - %s\n",
382 AcpiFormatException(status));
383 return ENXIO;
386 obj = (ACPI_OBJECT *)buf.Pointer;
387 if (!ACPI_PKG_VALID(obj, 1)) {
388 device_printf(dev, "Invalid _PSS package\n");
389 AcpiOsFree(obj);
390 return ENXIO;
393 /* Don't create too many P-States */
394 npstate = obj->Package.Count;
395 if (npstate > ACPI_NPSTATE_MAX) {
396 device_printf(dev, "Too many P-States, %d->%d\n",
397 npstate, ACPI_NPSTATE_MAX);
398 npstate = ACPI_NPSTATE_MAX;
402 * If we have already created P-State table,
403 * we must make sure that number of entries
404 * is consistent.
406 if (acpi_pstates != NULL && acpi_npstates != npstate) {
407 device_printf(dev, "Inconsistent # of P-States "
408 "cross Processor objects\n");
409 AcpiOsFree(obj);
410 return ENXIO;
414 * Create a temporary P-State table
416 pstate = kmalloc(sizeof(*pstate) * npstate, M_TEMP, M_WAITOK);
417 for (i = 0, p = pstate; i < npstate; ++i, ++p) {
418 ACPI_OBJECT *pkg;
419 uint32_t *ptr[ACPI_PSS_PX_NENTRY] = {
420 &p->st_freq, &p->st_power, &p->st_xsit_lat,
421 &p->st_bm_lat, &p->st_cval, &p->st_sval
423 int j;
425 pkg = &obj->Package.Elements[i];
426 if (!ACPI_PKG_VALID(pkg, ACPI_PSS_PX_NENTRY)) {
427 device_printf(dev, "Invalud _PSS P%d\n", i);
428 AcpiOsFree(obj);
429 kfree(pstate, M_TEMP);
430 return ENXIO;
432 for (j = 0; j < ACPI_PSS_PX_NENTRY; ++j) {
433 if (acpi_PkgInt32(pkg, j, ptr[j]) != 0) {
434 device_printf(dev, "Can't extract "
435 "_PSS P%d %dth entry\n", i, j);
436 AcpiOsFree(obj);
437 kfree(pstate, M_TEMP);
438 return ENXIO;
443 /* Free _PSS */
444 AcpiOsFree(obj);
446 if (acpi_pstates == NULL) {
448 * If no P-State table is created yet,
449 * save the temporary one we just created.
451 acpi_pstates = pstate;
452 acpi_npstates = npstate;
453 pstate = NULL;
455 if (bootverbose) {
456 for (i = 0; i < acpi_npstates; ++i) {
457 device_printf(dev,
458 "freq %u, pwr %u, xlat %u, blat %u, "
459 "cv %08x, sv %08x\n",
460 acpi_pstates[i].st_freq,
461 acpi_pstates[i].st_power,
462 acpi_pstates[i].st_xsit_lat,
463 acpi_pstates[i].st_bm_lat,
464 acpi_pstates[i].st_cval,
465 acpi_pstates[i].st_sval);
468 } else {
470 * Make sure that P-State tables are same
471 * for all processors.
473 if (memcmp(pstate, acpi_pstates,
474 sizeof(*pstate) * npstate) != 0) {
475 device_printf(dev, "Inconsistent _PSS "
476 "cross Processor objects\n");
477 kfree(pstate, M_TEMP);
478 return ENXIO;
480 kfree(pstate, M_TEMP);
483 /* By default, we start from P-State table's first entry */
484 sc->pst_sstart = 0;
487 * Adjust the usable first entry of P-State table,
488 * if there is _PPC object.
490 buf.Pointer = NULL;
491 buf.Length = ACPI_ALLOCATE_BUFFER;
492 status = AcpiEvaluateObject(sc->pst_handle, "_PPC", NULL, &buf);
493 if (!ACPI_FAILURE(status)) {
494 obj = (ACPI_OBJECT *)buf.Pointer;
495 if (obj->Type == ACPI_TYPE_INTEGER) {
496 if (obj->Integer.Value >= acpi_npstates) {
497 device_printf(dev, "Invalid _PPC value\n");
498 AcpiOsFree(obj);
499 return ENXIO;
501 sc->pst_sstart = obj->Integer.Value;
502 if (bootverbose)
503 device_printf(dev, "_PPC %d\n", sc->pst_sstart);
505 /* TODO: Install notifiy handler */
506 } else {
507 device_printf(dev, "Invalid _PPC object\n");
508 AcpiOsFree(obj);
509 return ENXIO;
512 /* Free _PPC */
513 AcpiOsFree(obj);
516 sc->pst_state = sc->pst_sstart;
518 /* Link us with the domain */
519 sc->pst_domain = dom;
520 LIST_INSERT_HEAD(&dom->pd_pstlist, sc, pst_link);
522 if (device_get_unit(dev) == 0)
523 AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_pst_postattach, NULL);
525 return 0;
528 static struct acpi_pst_domain *
529 acpi_pst_domain_create(device_t dev, ACPI_OBJECT *obj)
531 struct acpi_pst_domain *dom;
532 uint32_t val, domain, coord, nproc;
534 if (!ACPI_PKG_VALID_EQ(obj, 5)) {
535 device_printf(dev, "Invalid _PSD package\n");
536 return NULL;
539 /* NumberOfEntries */
540 if (acpi_PkgInt32(obj, 0, &val) != 0 || val != 5) {
541 device_printf(dev, "Invalid _PSD NumberOfEntries\n");
542 return NULL;
545 /* Revision */
546 if (acpi_PkgInt32(obj, 1, &val) != 0 || val != 0) {
547 device_printf(dev, "Invalid _PSD Revision\n");
548 return NULL;
551 if (acpi_PkgInt32(obj, 2, &domain) != 0 ||
552 acpi_PkgInt32(obj, 3, &coord) != 0 ||
553 acpi_PkgInt32(obj, 4, &nproc) != 0) {
554 device_printf(dev, "Can't extract _PSD package\n");
555 return NULL;
558 if (!ACPI_PSD_COORD_VALID(coord)) {
559 device_printf(dev, "Invalid _PSD CoordType (%#x)\n", coord);
560 return NULL;
563 if (nproc > MAXCPU) {
565 * If NumProcessors is greater than MAXCPU
566 * and domain's coordination is SWALL, then
567 * we will never be able to start all CPUs
568 * within this domain, and power state
569 * transition will never be completed, so we
570 * just bail out here.
572 if (coord == ACPI_PSD_COORD_SWALL) {
573 device_printf(dev, "Unsupported _PSD NumProcessors "
574 "(%d)\n", nproc);
575 return NULL;
577 } else if (nproc == 0) {
578 device_printf(dev, "_PSD NumProcessors are zero\n");
579 return NULL;
582 dom = acpi_pst_domain_find(domain);
583 if (dom != NULL) {
584 if (dom->pd_coord != coord || dom->pd_nproc != nproc) {
585 device_printf(dev, "Inconsistent _PSD information "
586 "cross Processor objects\n");
587 return NULL;
589 return dom;
592 dom = acpi_pst_domain_alloc(domain, coord, nproc);
593 if (bootverbose)
594 device_printf(dev, "create domain%u\n", dom->pd_dom);
596 return dom;
599 static struct acpi_pst_domain *
600 acpi_pst_domain_find(uint32_t domain)
602 struct acpi_pst_domain *dom;
604 LIST_FOREACH(dom, &acpi_pst_domains, pd_link) {
605 if (dom->pd_flags & ACPI_PSTDOM_FLAG_STUB)
606 continue;
607 if (dom->pd_dom == domain)
608 return dom;
610 return NULL;
613 static struct acpi_pst_domain *
614 acpi_pst_domain_alloc(uint32_t domain, uint32_t coord, uint32_t nproc)
616 struct acpi_pst_domain *dom;
618 dom = kmalloc(sizeof(*dom), M_DEVBUF, M_WAITOK | M_ZERO);
619 dom->pd_dom = domain;
620 dom->pd_coord = coord;
621 dom->pd_nproc = nproc;
622 dom->pd_state = 0; /* XXX */
623 dom->pd_sstart = 0; /* XXX */
624 LIST_INIT(&dom->pd_pstlist);
626 LIST_INSERT_HEAD(&acpi_pst_domains, dom, pd_link);
628 return dom;
631 static int
632 acpi_pst_domain_set_pstate(struct acpi_pst_domain *dom, int i)
634 const struct acpi_pstate *pstate;
635 struct acpi_pst_softc *sc;
636 int done, error;
638 KKASSERT(i >= 0 && i < acpi_npstates);
639 pstate = &acpi_pstates[i];
641 done = 0;
642 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
643 if (!done) {
644 error = acpi_pst_set_pstate(sc, pstate);
645 if (error) {
646 device_printf(sc->pst_dev, "can't set "
647 "freq %d\n", pstate->st_freq);
648 /* XXX error cleanup? */
650 if (dom->pd_coord == ACPI_PSD_COORD_SWANY)
651 done = 1;
653 sc->pst_state = i;
655 dom->pd_state = i;
657 return 0;
660 static void
661 acpi_pst_postattach(void *arg __unused)
663 struct acpi_pst_domain *dom;
664 struct acpi_cpux_softc *cpux;
665 device_t *devices;
666 int i, ndevices, error, has_domain;
668 devices = NULL;
669 ndevices = 0;
670 error = devclass_get_devices(acpi_pst_devclass, &devices, &ndevices);
671 if (error)
672 return;
674 if (ndevices == 0)
675 return;
677 cpux = NULL;
678 for (i = 0; i < ndevices; ++i) {
679 cpux = device_get_softc(device_get_parent(devices[i]));
680 if (cpux->glob_sysctl_tree != NULL)
681 break;
683 kfree(devices, M_TEMP);
684 KKASSERT(cpux != NULL);
686 if (acpi_pst_md == NULL)
687 kprintf("ACPI: no P-State CPU driver\n");
689 has_domain = 0;
690 LIST_FOREACH(dom, &acpi_pst_domains, pd_link) {
691 struct acpi_pst_softc *sc;
692 char buf[32];
695 * Make sure that all processors belonging to this
696 * domain are located.
698 i = 0;
699 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link)
700 ++i;
701 if (i != dom->pd_nproc) {
702 KKASSERT(i < dom->pd_nproc);
704 kprintf("ACPI: domain%u misses processors, "
705 "should be %d, got %d\n", dom->pd_dom,
706 dom->pd_nproc, i);
707 if (dom->pd_coord == ACPI_PSD_COORD_SWALL) {
709 * If this domain's coordination is
710 * SWALL and we don't see all of the
711 * member CPUs of this domain, then
712 * the P-State transition will never
713 * be completed, so just leave this
714 * domain out.
716 dom->pd_flags |= ACPI_PSTDOM_FLAG_DEAD;
717 continue;
719 dom->pd_nproc = i;
723 * Validate P-State configurations for this domain
725 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
726 error = acpi_pst_check_csr(sc);
727 if (error)
728 break;
730 error = acpi_pst_check_pstates(sc);
731 if (error)
732 break;
734 if (sc != NULL) {
735 kprintf("ACPI: domain%u P-State configuration "
736 "check failed\n", dom->pd_dom);
737 dom->pd_flags |= ACPI_PSTDOM_FLAG_DEAD;
738 continue;
742 * Do necssary P-State initialization
744 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
745 error = acpi_pst_init(sc);
746 if (error)
747 break;
749 if (sc != NULL) {
750 kprintf("ACPI: domain%u P-State initialization "
751 "check failed\n", dom->pd_dom);
752 dom->pd_flags |= ACPI_PSTDOM_FLAG_DEAD;
753 continue;
756 has_domain = 1;
758 ksnprintf(buf, sizeof(buf), "px_dom%u", dom->pd_dom);
760 sysctl_ctx_init(&dom->pd_sysctl_ctx);
761 dom->pd_sysctl_tree =
762 SYSCTL_ADD_NODE(&dom->pd_sysctl_ctx,
763 SYSCTL_CHILDREN(cpux->glob_sysctl_tree),
764 OID_AUTO, buf, CTLFLAG_RD, 0,
765 "P-State domain");
766 if (dom->pd_sysctl_tree == NULL) {
767 kprintf("ACPI: Can't create sysctl tree for domain%u",
768 dom->pd_dom);
769 continue;
772 SYSCTL_ADD_PROC(&dom->pd_sysctl_ctx,
773 SYSCTL_CHILDREN(dom->pd_sysctl_tree),
774 OID_AUTO, "available",
775 CTLTYPE_STRING | CTLFLAG_RD,
776 dom, 0, acpi_pst_sysctl_freqs, "A",
777 "available frequencies");
779 SYSCTL_ADD_PROC(&dom->pd_sysctl_ctx,
780 SYSCTL_CHILDREN(dom->pd_sysctl_tree),
781 OID_AUTO, "members",
782 CTLTYPE_STRING | CTLFLAG_RD,
783 dom, 0, acpi_pst_sysctl_members, "A",
784 "member cpus");
786 if (acpi_pst_md != NULL &&
787 acpi_pst_md->pmd_set_pstate != NULL) {
788 SYSCTL_ADD_PROC(&dom->pd_sysctl_ctx,
789 SYSCTL_CHILDREN(dom->pd_sysctl_tree),
790 OID_AUTO, "select",
791 CTLTYPE_UINT | CTLFLAG_RW,
792 dom, 0, acpi_pst_sysctl_select,
793 "IU", "select freq");
797 if (has_domain && acpi_pst_md != NULL &&
798 acpi_pst_md->pmd_set_pstate != NULL) {
799 SYSCTL_ADD_PROC(&cpux->glob_sysctl_ctx,
800 SYSCTL_CHILDREN(cpux->glob_sysctl_tree),
801 OID_AUTO, "px_global",
802 CTLTYPE_UINT | CTLFLAG_RW,
803 NULL, 0, acpi_pst_sysctl_global,
804 "IU", "select freq for all domains");
808 static int
809 acpi_pst_sysctl_freqs(SYSCTL_HANDLER_ARGS)
811 struct acpi_pst_domain *dom = arg1;
812 int i, error;
814 error = 0;
815 for (i = 0; i < acpi_npstates; ++i) {
816 if (error == 0 && i)
817 error = SYSCTL_OUT(req, " ", 1);
818 if (error == 0) {
819 const char *pat;
820 char buf[32];
822 if (i < dom->pd_sstart)
823 pat = "(%u)";
824 else
825 pat = "%u";
827 ksnprintf(buf, sizeof(buf), pat,
828 acpi_pstates[i].st_freq);
829 error = SYSCTL_OUT(req, buf, strlen(buf));
832 return error;
835 static int
836 acpi_pst_sysctl_members(SYSCTL_HANDLER_ARGS)
838 struct acpi_pst_domain *dom = arg1;
839 struct acpi_pst_softc *sc;
840 int loop, error;
842 loop = error = 0;
843 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
844 char buf[32];
846 if (error == 0 && loop)
847 error = SYSCTL_OUT(req, " ", 1);
848 if (error == 0) {
849 ksnprintf(buf, sizeof(buf), "cpu%d", sc->pst_cpuid);
850 error = SYSCTL_OUT(req, buf, strlen(buf));
853 if (error == 0 && acpi_pst_md && acpi_pst_md->pmd_get_pstate) {
854 const struct acpi_pstate *pstate;
855 const char *str;
857 pstate = acpi_pst_get_pstate(sc);
858 if (pstate == NULL) {
859 str = "(*)";
860 } else {
861 ksnprintf(buf, sizeof(buf), "(%d)",
862 pstate->st_freq);
863 str = buf;
865 error = SYSCTL_OUT(req, str, strlen(str));
867 ++loop;
869 return error;
872 static int
873 acpi_pst_sysctl_select(SYSCTL_HANDLER_ARGS)
875 struct acpi_pst_domain *dom = arg1;
876 int error, i, freq;
878 KKASSERT(dom->pd_state >= 0 && dom->pd_state < acpi_npstates);
880 freq = acpi_pstates[dom->pd_state].st_freq;
882 error = sysctl_handle_int(oidp, &freq, 0, req);
883 if (error || req->newptr == NULL)
884 return error;
886 i = acpi_pst_freq2index(freq);
887 if (i < 0)
888 return EINVAL;
890 acpi_pst_domain_set_pstate(dom, i);
891 return 0;
894 static int
895 acpi_pst_sysctl_global(SYSCTL_HANDLER_ARGS)
897 struct acpi_pst_domain *dom;
898 int error, i, freq;
900 KKASSERT(acpi_pst_global_state >= 0 &&
901 acpi_pst_global_state < acpi_npstates);
903 freq = acpi_pstates[acpi_pst_global_state].st_freq;
905 error = sysctl_handle_int(oidp, &freq, 0, req);
906 if (error || req->newptr == NULL)
907 return error;
909 i = acpi_pst_freq2index(freq);
910 if (i < 0)
911 return EINVAL;
913 LIST_FOREACH(dom, &acpi_pst_domains, pd_link) {
914 /* Skip dead domain */
915 if (dom->pd_flags & ACPI_PSTDOM_FLAG_DEAD)
916 continue;
917 acpi_pst_domain_set_pstate(dom, i);
919 acpi_pst_global_state = i;
921 return 0;
924 static void
925 acpi_pst_check_csr_handler(struct netmsg *nmsg)
927 struct netmsg_acpi_pst *msg = (struct netmsg_acpi_pst *)nmsg;
928 int error;
930 error = acpi_pst_md->pmd_check_csr(msg->ctrl, msg->status);
931 lwkt_replymsg(&nmsg->nm_lmsg, error);
934 static int
935 acpi_pst_check_csr(struct acpi_pst_softc *sc)
937 struct netmsg_acpi_pst msg;
939 if (acpi_pst_md == NULL)
940 return 0;
942 netmsg_init(&msg.nmsg, &curthread->td_msgport,
943 MSGF_MPSAFE | MSGF_PRIORITY,
944 acpi_pst_check_csr_handler);
945 msg.ctrl = &sc->pst_creg;
946 msg.status = &sc->pst_sreg;
948 return lwkt_domsg(cpu_portfn(sc->pst_cpuid), &msg.nmsg.nm_lmsg, 0);
951 static void
952 acpi_pst_check_pstates_handler(struct netmsg *nmsg)
954 int error;
956 error = acpi_pst_md->pmd_check_pstates(acpi_pstates, acpi_npstates);
957 lwkt_replymsg(&nmsg->nm_lmsg, error);
960 static int
961 acpi_pst_check_pstates(struct acpi_pst_softc *sc)
963 struct netmsg nmsg;
965 if (acpi_pst_md == NULL)
966 return 0;
968 netmsg_init(&nmsg, &curthread->td_msgport,
969 MSGF_MPSAFE | MSGF_PRIORITY,
970 acpi_pst_check_pstates_handler);
972 return lwkt_domsg(cpu_portfn(sc->pst_cpuid), &nmsg.nm_lmsg, 0);
975 static void
976 acpi_pst_init_handler(struct netmsg *nmsg)
978 struct netmsg_acpi_pst *msg = (struct netmsg_acpi_pst *)nmsg;
979 int error;
981 error = acpi_pst_md->pmd_init(msg->ctrl, msg->status);
982 lwkt_replymsg(&nmsg->nm_lmsg, error);
985 static int
986 acpi_pst_init(struct acpi_pst_softc *sc)
988 struct netmsg_acpi_pst msg;
990 if (acpi_pst_md == NULL)
991 return 0;
993 netmsg_init(&msg.nmsg, &curthread->td_msgport,
994 MSGF_MPSAFE | MSGF_PRIORITY, acpi_pst_init_handler);
995 msg.ctrl = &sc->pst_creg;
996 msg.status = &sc->pst_sreg;
998 return lwkt_domsg(cpu_portfn(sc->pst_cpuid), &msg.nmsg.nm_lmsg, 0);
1001 static void
1002 acpi_pst_set_pstate_handler(struct netmsg *nmsg)
1004 struct netmsg_acpi_pst *msg = (struct netmsg_acpi_pst *)nmsg;
1005 int error;
1007 error = acpi_pst_md->pmd_set_pstate(msg->ctrl, msg->status,
1008 nmsg->nm_lmsg.u.ms_resultp);
1009 lwkt_replymsg(&nmsg->nm_lmsg, error);
1012 static int
1013 acpi_pst_set_pstate(struct acpi_pst_softc *sc, const struct acpi_pstate *pstate)
1015 struct netmsg_acpi_pst msg;
1017 KKASSERT(acpi_pst_md != NULL);
1019 if (bootverbose) {
1020 device_printf(sc->pst_dev, "set pstate, freq %d\n",
1021 pstate->st_freq);
1024 netmsg_init(&msg.nmsg, &curthread->td_msgport,
1025 MSGF_MPSAFE | MSGF_PRIORITY,
1026 acpi_pst_set_pstate_handler);
1027 msg.nmsg.nm_lmsg.u.ms_resultp = __DECONST(void *, pstate);
1028 msg.ctrl = &sc->pst_creg;
1029 msg.status = &sc->pst_sreg;
1031 return lwkt_domsg(cpu_portfn(sc->pst_cpuid), &msg.nmsg.nm_lmsg, 0);
1034 static void
1035 acpi_pst_get_pstate_handler(struct netmsg *nmsg)
1037 struct netmsg_acpi_pst *msg = (struct netmsg_acpi_pst *)nmsg;
1038 const struct acpi_pstate *pstate;
1040 pstate = acpi_pst_md->pmd_get_pstate(msg->status, acpi_pstates,
1041 acpi_npstates);
1042 nmsg->nm_lmsg.u.ms_resultp = __DECONST(void *, pstate);
1043 lwkt_replymsg(&nmsg->nm_lmsg, 0);
1046 static const struct acpi_pstate *
1047 acpi_pst_get_pstate(struct acpi_pst_softc *sc)
1049 struct netmsg_acpi_pst msg;
1051 if (acpi_pst_md == NULL)
1052 return 0;
1054 netmsg_init(&msg.nmsg, &curthread->td_msgport,
1055 MSGF_MPSAFE | MSGF_PRIORITY,
1056 acpi_pst_get_pstate_handler);
1057 msg.status = &sc->pst_sreg;
1059 lwkt_domsg(cpu_portfn(sc->pst_cpuid), &msg.nmsg.nm_lmsg, 0);
1060 return msg.nmsg.nm_lmsg.u.ms_resultp;
1063 static int
1064 acpi_pst_alloc_resource(device_t dev, ACPI_OBJECT *obj, int idx,
1065 struct acpi_pst_res *res)
1067 struct acpi_pst_softc *sc = device_get_softc(dev);
1068 int error, type;
1070 /* Save GAS */
1071 error = acpi_PkgRawGas(obj, idx, &res->pr_gas);
1072 if (error)
1073 return error;
1075 /* Allocate resource, if possible */
1076 res->pr_rid = sc->pst_parent->cpux_next_rid;
1077 acpi_bus_alloc_gas(dev, &type, &res->pr_rid, &res->pr_gas, &res->pr_res, 0);
1078 if (res->pr_res != NULL) {
1079 sc->pst_parent->cpux_next_rid++;
1080 res->pr_bt = rman_get_bustag(res->pr_res);
1081 res->pr_bh = rman_get_bushandle(res->pr_res);
1082 } else {
1083 res->pr_rid = 0;
1085 return 0;