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/netisr.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
{
73 const struct acpi_pst_res
*ctrl
;
74 const struct acpi_pst_res
*status
;
77 struct acpi_pst_domain
{
81 LIST_ENTRY(acpi_pst_domain
) pd_link
;
87 struct acpi_pst_list pd_pstlist
;
89 struct sysctl_ctx_list pd_sysctl_ctx
;
90 struct sysctl_oid
*pd_sysctl_tree
;
92 LIST_HEAD(acpi_pst_domlist
, acpi_pst_domain
);
94 #define ACPI_PSTDOM_FLAG_STUB 0x1 /* stub domain, no _PSD */
95 #define ACPI_PSTDOM_FLAG_DEAD 0x2 /* domain can't be started */
97 struct acpi_pst_softc
{
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
;
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
),
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
),
184 static driver_t acpi_pst_driver
= {
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);
195 acpi_pst_freq2index(int freq
)
199 for (i
= 0; i
< acpi_npstates
; ++i
) {
200 if (acpi_pstates
[i
].st_freq
== freq
)
207 acpi_pst_probe(device_t dev
)
214 if (acpi_disabled("cpu_pst") ||
215 acpi_get_type(dev
) != ACPI_TYPE_PROCESSOR
)
218 if (acpi_pst_md
== NULL
)
219 acpi_pst_md
= acpi_pst_md_probe();
221 handle
= acpi_get_handle(dev
);
227 buf
.Length
= ACPI_ALLOCATE_BUFFER
;
228 status
= AcpiEvaluateObject(handle
, "_PCT", NULL
, &buf
);
229 if (ACPI_FAILURE(status
)) {
231 device_printf(dev
, "Can't get _PCT package - %s\n",
232 AcpiFormatException(status
));
237 obj
= (ACPI_OBJECT
*)buf
.Pointer
;
238 if (!ACPI_PKG_VALID_EQ(obj
, 2)) {
239 device_printf(dev
, "Invalid _PCT package\n");
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
));
257 obj
= (ACPI_OBJECT
*)buf
.Pointer
;
258 if (!ACPI_PKG_VALID(obj
, 1)) {
259 device_printf(dev
, "Invalid _PSS package\n");
265 device_set_desc(dev
, "ACPI CPU P-State");
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
;
277 struct acpi_pstate
*pstate
, *p
;
278 int i
, npstate
, error
;
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.
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]);
303 device_printf(dev
, "Invalid _PSD package\n");
309 AcpiOsFree(buf
.Pointer
);
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 */
318 LIST_FOREACH(pst
, &dom
->pd_pstlist
, pst_link
)
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
);
326 KKASSERT(i
< dom
->pd_nproc
);
329 * Get control/status registers from _PCT
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
));
340 obj
= (ACPI_OBJECT
*)buf
.Pointer
;
341 if (!ACPI_PKG_VALID_EQ(obj
, 2)) {
342 device_printf(dev
, "Invalid _PCT package\n");
347 /* Save and try allocating control register */
348 error
= acpi_pst_alloc_resource(dev
, obj
, 0, &sc
->pst_creg
);
354 device_printf(dev
, "control reg %jd %jx\n",
355 (intmax_t)sc
->pst_creg
.pr_gas
.SpaceId
,
356 (intmax_t)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
);
366 device_printf(dev
, "status reg %d %llx\n",
367 sc
->pst_sreg
.pr_gas
.SpaceId
,
368 sc
->pst_sreg
.pr_gas
.Address
);
375 * Create P-State table according to _PSS
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
));
386 obj
= (ACPI_OBJECT
*)buf
.Pointer
;
387 if (!ACPI_PKG_VALID(obj
, 1)) {
388 device_printf(dev
, "Invalid _PSS package\n");
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
406 if (acpi_pstates
!= NULL
&& acpi_npstates
!= npstate
) {
407 device_printf(dev
, "Inconsistent # of P-States "
408 "cross Processor objects\n");
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
) {
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
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
);
429 kfree(pstate
, M_TEMP
);
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
);
437 kfree(pstate
, M_TEMP
);
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
;
456 for (i
= 0; i
< acpi_npstates
; ++i
) {
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
);
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
);
480 kfree(pstate
, M_TEMP
);
483 /* By default, we start from P-State table's first entry */
487 * Adjust the usable first entry of P-State table,
488 * if there is _PPC object.
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");
501 sc
->pst_sstart
= obj
->Integer
.Value
;
503 device_printf(dev
, "_PPC %d\n", sc
->pst_sstart
);
505 /* TODO: Install notifiy handler */
507 device_printf(dev
, "Invalid _PPC object\n");
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
);
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");
539 /* NumberOfEntries */
540 if (acpi_PkgInt32(obj
, 0, &val
) != 0 || val
!= 5) {
541 device_printf(dev
, "Invalid _PSD NumberOfEntries\n");
546 if (acpi_PkgInt32(obj
, 1, &val
) != 0 || val
!= 0) {
547 device_printf(dev
, "Invalid _PSD Revision\n");
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");
558 if (!ACPI_PSD_COORD_VALID(coord
)) {
559 device_printf(dev
, "Invalid _PSD CoordType (%#x)\n", coord
);
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 "
577 } else if (nproc
== 0) {
578 device_printf(dev
, "_PSD NumProcessors are zero\n");
582 dom
= acpi_pst_domain_find(domain
);
584 if (dom
->pd_coord
!= coord
|| dom
->pd_nproc
!= nproc
) {
585 device_printf(dev
, "Inconsistent _PSD information "
586 "cross Processor objects\n");
592 dom
= acpi_pst_domain_alloc(domain
, coord
, nproc
);
594 device_printf(dev
, "create domain%u\n", dom
->pd_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
)
607 if (dom
->pd_dom
== domain
)
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
);
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
;
638 KKASSERT(i
>= 0 && i
< acpi_npstates
);
639 pstate
= &acpi_pstates
[i
];
642 LIST_FOREACH(sc
, &dom
->pd_pstlist
, pst_link
) {
644 error
= acpi_pst_set_pstate(sc
, pstate
);
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
)
661 acpi_pst_postattach(void *arg __unused
)
663 struct acpi_pst_domain
*dom
;
664 struct acpi_cpux_softc
*cpux
;
666 int i
, ndevices
, error
, has_domain
;
670 error
= devclass_get_devices(acpi_pst_devclass
, &devices
, &ndevices
);
678 for (i
= 0; i
< ndevices
; ++i
) {
679 cpux
= device_get_softc(device_get_parent(devices
[i
]));
680 if (cpux
->glob_sysctl_tree
!= NULL
)
683 kfree(devices
, M_TEMP
);
684 KKASSERT(cpux
!= NULL
);
686 if (acpi_pst_md
== NULL
)
687 kprintf("ACPI: no P-State CPU driver\n");
690 LIST_FOREACH(dom
, &acpi_pst_domains
, pd_link
) {
691 struct acpi_pst_softc
*sc
;
695 * Make sure that all processors belonging to this
696 * domain are located.
699 LIST_FOREACH(sc
, &dom
->pd_pstlist
, pst_link
)
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
,
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
716 dom
->pd_flags
|= ACPI_PSTDOM_FLAG_DEAD
;
723 * Validate P-State configurations for this domain
725 LIST_FOREACH(sc
, &dom
->pd_pstlist
, pst_link
) {
726 error
= acpi_pst_check_csr(sc
);
730 error
= acpi_pst_check_pstates(sc
);
735 kprintf("ACPI: domain%u P-State configuration "
736 "check failed\n", dom
->pd_dom
);
737 dom
->pd_flags
|= ACPI_PSTDOM_FLAG_DEAD
;
742 * Do necssary P-State initialization
744 LIST_FOREACH(sc
, &dom
->pd_pstlist
, pst_link
) {
745 error
= acpi_pst_init(sc
);
750 kprintf("ACPI: domain%u P-State initialization "
751 "check failed\n", dom
->pd_dom
);
752 dom
->pd_flags
|= ACPI_PSTDOM_FLAG_DEAD
;
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,
766 if (dom
->pd_sysctl_tree
== NULL
) {
767 kprintf("ACPI: Can't create sysctl tree for domain%u",
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
),
782 CTLTYPE_STRING
| CTLFLAG_RD
,
783 dom
, 0, acpi_pst_sysctl_members
, "A",
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
),
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");
809 acpi_pst_sysctl_freqs(SYSCTL_HANDLER_ARGS
)
811 struct acpi_pst_domain
*dom
= arg1
;
815 for (i
= 0; i
< acpi_npstates
; ++i
) {
817 error
= SYSCTL_OUT(req
, " ", 1);
822 if (i
< dom
->pd_sstart
)
827 ksnprintf(buf
, sizeof(buf
), pat
,
828 acpi_pstates
[i
].st_freq
);
829 error
= SYSCTL_OUT(req
, buf
, strlen(buf
));
836 acpi_pst_sysctl_members(SYSCTL_HANDLER_ARGS
)
838 struct acpi_pst_domain
*dom
= arg1
;
839 struct acpi_pst_softc
*sc
;
843 LIST_FOREACH(sc
, &dom
->pd_pstlist
, pst_link
) {
846 if (error
== 0 && loop
)
847 error
= SYSCTL_OUT(req
, " ", 1);
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
;
857 pstate
= acpi_pst_get_pstate(sc
);
858 if (pstate
== NULL
) {
861 ksnprintf(buf
, sizeof(buf
), "(%d)",
865 error
= SYSCTL_OUT(req
, str
, strlen(str
));
873 acpi_pst_sysctl_select(SYSCTL_HANDLER_ARGS
)
875 struct acpi_pst_domain
*dom
= arg1
;
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
)
886 i
= acpi_pst_freq2index(freq
);
890 acpi_pst_domain_set_pstate(dom
, i
);
895 acpi_pst_sysctl_global(SYSCTL_HANDLER_ARGS
)
897 struct acpi_pst_domain
*dom
;
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
)
909 i
= acpi_pst_freq2index(freq
);
913 LIST_FOREACH(dom
, &acpi_pst_domains
, pd_link
) {
914 /* Skip dead domain */
915 if (dom
->pd_flags
& ACPI_PSTDOM_FLAG_DEAD
)
917 acpi_pst_domain_set_pstate(dom
, i
);
919 acpi_pst_global_state
= i
;
925 acpi_pst_check_csr_handler(struct netmsg
*nmsg
)
927 struct netmsg_acpi_pst
*msg
= (struct netmsg_acpi_pst
*)nmsg
;
930 error
= acpi_pst_md
->pmd_check_csr(msg
->ctrl
, msg
->status
);
931 lwkt_replymsg(&nmsg
->nm_lmsg
, error
);
935 acpi_pst_check_csr(struct acpi_pst_softc
*sc
)
937 struct netmsg_acpi_pst msg
;
939 if (acpi_pst_md
== NULL
)
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);
952 acpi_pst_check_pstates_handler(struct netmsg
*nmsg
)
956 error
= acpi_pst_md
->pmd_check_pstates(acpi_pstates
, acpi_npstates
);
957 lwkt_replymsg(&nmsg
->nm_lmsg
, error
);
961 acpi_pst_check_pstates(struct acpi_pst_softc
*sc
)
965 if (acpi_pst_md
== NULL
)
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);
976 acpi_pst_init_handler(struct netmsg
*nmsg
)
978 struct netmsg_acpi_pst
*msg
= (struct netmsg_acpi_pst
*)nmsg
;
981 error
= acpi_pst_md
->pmd_init(msg
->ctrl
, msg
->status
);
982 lwkt_replymsg(&nmsg
->nm_lmsg
, error
);
986 acpi_pst_init(struct acpi_pst_softc
*sc
)
988 struct netmsg_acpi_pst msg
;
990 if (acpi_pst_md
== NULL
)
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);
1002 acpi_pst_set_pstate_handler(struct netmsg
*nmsg
)
1004 struct netmsg_acpi_pst
*msg
= (struct netmsg_acpi_pst
*)nmsg
;
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
);
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
);
1020 device_printf(sc
->pst_dev
, "set pstate, freq %d\n",
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);
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
,
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
)
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
;
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
);
1071 error
= acpi_PkgRawGas(obj
, idx
, &res
->pr_gas
);
1075 /* Allocate resource, if possible */
1076 res
->pr_rid
= sc
->pst_parent
->cpux_next_rid
;
1077 res
->pr_res
= acpi_bus_alloc_gas(dev
, &res
->pr_rid
, &res
->pr_gas
, 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
);