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
;