4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
28 #include <sys/cpu_acpi.h>
30 #define CPU_ACPI_PSTATES_SIZE(cnt) (cnt * sizeof (cpu_acpi_pstate_t))
31 #define CPU_ACPI_PSS_SIZE (sizeof (cpu_acpi_pstate_t) / sizeof (uint32_t))
34 * Map the dip to an ACPI handle for the device.
37 cpu_acpi_init(dev_info_t
*dip
)
39 cpu_acpi_handle_t handle
;
41 handle
= kmem_zalloc(sizeof (cpu_acpi_state_t
), KM_SLEEP
);
43 if (ACPI_FAILURE(acpica_get_handle(dip
, &handle
->cs_handle
))) {
44 kmem_free(handle
, sizeof (cpu_acpi_state_t
));
55 cpu_acpi_fini(cpu_acpi_handle_t handle
)
57 if (handle
->cs_pstates
!= NULL
) {
58 if (CPU_ACPI_PSTATES(handle
) != NULL
)
59 kmem_free(CPU_ACPI_PSTATES(handle
),
60 CPU_ACPI_PSTATES_SIZE(
61 CPU_ACPI_PSTATES_COUNT(handle
)));
62 kmem_free(handle
->cs_pstates
, sizeof (cpu_acpi_pstates_t
));
64 kmem_free(handle
, sizeof (cpu_acpi_state_t
));
68 * Cache the ACPI _PCT data. The _PCT data defines the interface to use
69 * when making power level transitions (i.e., system IO ports, fixed
70 * hardware port, etc).
73 cpu_acpi_cache_pct(cpu_acpi_handle_t handle
)
77 AML_RESOURCE_GENERIC_REGISTER
*greg
;
83 * Fetch the _PCT (if present) for the CPU node. Since the PCT is
84 * optional, non-existence is not a failure (we just consider
85 * it a fixed hardware case).
87 CPU_ACPI_OBJ_IS_NOT_CACHED(handle
, CPU_ACPI_PCT_CACHED
);
88 abuf
.Length
= ACPI_ALLOCATE_BUFFER
;
90 if (ACPI_FAILURE(AcpiEvaluateObjectTyped(handle
->cs_handle
, "_PCT",
91 NULL
, &abuf
, ACPI_TYPE_PACKAGE
))) {
92 CPU_ACPI_PCT(handle
)[0].pc_addrspace_id
=
93 ACPI_ADR_SPACE_FIXED_HARDWARE
;
94 CPU_ACPI_PCT(handle
)[1].pc_addrspace_id
=
95 ACPI_ADR_SPACE_FIXED_HARDWARE
;
100 if (obj
->Package
.Count
!= 2) {
101 cmn_err(CE_NOTE
, "!cpu_acpi: _PCT package bad count %d.",
107 * Does the package look coherent?
109 for (i
= 0; i
< obj
->Package
.Count
; i
++) {
110 if (obj
->Package
.Elements
[i
].Type
!= ACPI_TYPE_BUFFER
) {
111 cmn_err(CE_NOTE
, "!cpu_acpi: "
112 "Unexpected data in _PCT package.");
116 greg
= (AML_RESOURCE_GENERIC_REGISTER
*)
117 obj
->Package
.Elements
[i
].Buffer
.Pointer
;
118 if (greg
->DescriptorType
!=
119 ACPI_RESOURCE_NAME_GENERIC_REGISTER
) {
120 cmn_err(CE_NOTE
, "!cpu_acpi: "
121 "_PCT package has format error.");
124 if (greg
->ResourceLength
!=
125 ACPI_AML_SIZE_LARGE(AML_RESOURCE_GENERIC_REGISTER
)) {
126 cmn_err(CE_NOTE
, "!cpu_acpi: "
127 "_PCT package not right size.");
130 if (greg
->AddressSpaceId
!= ACPI_ADR_SPACE_FIXED_HARDWARE
&&
131 greg
->AddressSpaceId
!= ACPI_ADR_SPACE_SYSTEM_IO
) {
132 cmn_err(CE_NOTE
, "!cpu_apci: _PCT contains unsupported "
133 "address space type %x", greg
->AddressSpaceId
);
141 for (i
= 0; i
< obj
->Package
.Count
; i
++) {
142 greg
= (AML_RESOURCE_GENERIC_REGISTER
*)
143 obj
->Package
.Elements
[i
].Buffer
.Pointer
;
144 pct
= &CPU_ACPI_PCT(handle
)[i
];
145 pct
->pc_addrspace_id
= greg
->AddressSpaceId
;
146 pct
->pc_width
= greg
->BitWidth
;
147 pct
->pc_offset
= greg
->BitOffset
;
148 pct
->pc_asize
= greg
->AccessSize
;
149 pct
->pc_address
= greg
->Address
;
151 CPU_ACPI_OBJ_IS_CACHED(handle
, CPU_ACPI_PCT_CACHED
);
154 AcpiOsFree(abuf
.Pointer
);
159 * Cache the ACPI _PSD data. The _PSD data defines CPU dependencies
160 * (think CPU domains).
163 cpu_acpi_cache_psd(cpu_acpi_handle_t handle
)
166 ACPI_OBJECT
*pkg
, *elements
;
171 * Fetch the _PSD (if present) for the CPU node. Since the PSD is
172 * optional, non-existence is not a failure (it's up to the caller
173 * to determine how to handle non-existence).
175 CPU_ACPI_OBJ_IS_NOT_CACHED(handle
, CPU_ACPI_PSD_CACHED
);
176 abuf
.Length
= ACPI_ALLOCATE_BUFFER
;
178 if (ACPI_FAILURE(AcpiEvaluateObjectTyped(handle
->cs_handle
, "_PSD",
179 NULL
, &abuf
, ACPI_TYPE_PACKAGE
))) {
184 if (pkg
->Package
.Count
!= 1) {
185 cmn_err(CE_NOTE
, "!cpu_acpi: _PSD unsupported package "
186 "count %d.", pkg
->Package
.Count
);
190 if (pkg
->Package
.Elements
[0].Type
!= ACPI_TYPE_PACKAGE
||
191 pkg
->Package
.Elements
[0].Package
.Count
!= 5) {
192 cmn_err(CE_NOTE
, "!cpu_acpi: Unexpected data in _PSD package.");
195 elements
= pkg
->Package
.Elements
[0].Package
.Elements
;
196 if (elements
[0].Integer
.Value
!= 5 || elements
[1].Integer
.Value
!= 0) {
197 cmn_err(CE_NOTE
, "!cpu_acpi: Unexpected _PSD revision.");
200 psd
= &CPU_ACPI_PSD(handle
);
202 psd
->pd_entries
= elements
[0].Integer
.Value
;
203 psd
->pd_revision
= elements
[1].Integer
.Value
;
204 psd
->pd_domain
= elements
[2].Integer
.Value
;
205 psd
->pd_type
= elements
[3].Integer
.Value
;
206 psd
->pd_num
= elements
[4].Integer
.Value
;
207 CPU_ACPI_OBJ_IS_CACHED(handle
, CPU_ACPI_PSD_CACHED
);
210 AcpiOsFree(abuf
.Pointer
);
215 * Cache the _PSS data. The _PSS data defines the different power levels
216 * supported by the CPU and the attributes associated with each power level
217 * (i.e., frequency, voltage, etc.). The power levels are number from
218 * highest to lowest. That is, the highest power level is _PSS entry 0
219 * and the lowest power level is the last _PSS entry.
222 cpu_acpi_cache_pstates(cpu_acpi_handle_t handle
)
225 ACPI_OBJECT
*obj
, *q
, *l
;
226 cpu_acpi_pstate_t
*pstate
;
227 boolean_t eot
= B_FALSE
;
233 * Fetch the _PSS (if present) for the CPU node. If there isn't
234 * one, then CPU power management will not be possible.
236 CPU_ACPI_OBJ_IS_NOT_CACHED(handle
, CPU_ACPI_PSS_CACHED
);
237 abuf
.Length
= ACPI_ALLOCATE_BUFFER
;
239 if (ACPI_FAILURE(AcpiEvaluateObjectTyped(handle
->cs_handle
, "_PSS",
240 NULL
, &abuf
, ACPI_TYPE_PACKAGE
))) {
241 cmn_err(CE_NOTE
, "!cpu_acpi: _PSS package not found.");
245 if (obj
->Package
.Count
< 2) {
246 cmn_err(CE_NOTE
, "!cpu_acpi: _PSS package bad count %d.",
252 * Does the package look coherent?
255 for (i
= 0, l
= NULL
; i
< obj
->Package
.Count
; i
++, l
= q
) {
256 if (obj
->Package
.Elements
[i
].Type
!= ACPI_TYPE_PACKAGE
||
257 obj
->Package
.Elements
[i
].Package
.Count
!=
259 cmn_err(CE_NOTE
, "!cpu_acpi: "
260 "Unexpected data in _PSS package.");
264 q
= obj
->Package
.Elements
[i
].Package
.Elements
;
265 for (j
= 0; j
< CPU_ACPI_PSS_SIZE
; j
++) {
266 if (q
[j
].Type
!= ACPI_TYPE_INTEGER
) {
267 cmn_err(CE_NOTE
, "!cpu_acpi: "
268 "_PSS element invalid (type)");
274 * Ignore duplicate entries.
276 if (l
!= NULL
&& l
[0].Integer
.Value
== q
[0].Integer
.Value
)
280 * Some _PSS tables are larger than required
281 * and unused elements are filled with patterns
282 * of 0xff. Simply check here for frequency = 0xffff
283 * and stop counting if found.
285 if (q
[0].Integer
.Value
== 0xffff) {
291 * We should never find a valid entry after we've hit
292 * an end-of-table entry.
295 cmn_err(CE_NOTE
, "!cpu_acpi: "
296 "Unexpected data in _PSS package after eot.");
301 * pstates must be defined in order from highest to lowest.
303 if (l
!= NULL
&& l
[0].Integer
.Value
< q
[0].Integer
.Value
) {
304 cmn_err(CE_NOTE
, "!cpu_acpi: "
305 "_PSS package pstate definitions out of order.");
318 * Yes, fill in pstate structure.
320 handle
->cs_pstates
= kmem_zalloc(sizeof (cpu_acpi_pstates_t
), KM_SLEEP
);
321 CPU_ACPI_PSTATES_COUNT(handle
) = cnt
;
322 CPU_ACPI_PSTATES(handle
) = kmem_zalloc(CPU_ACPI_PSTATES_SIZE(cnt
),
324 pstate
= CPU_ACPI_PSTATES(handle
);
325 for (i
= 0, l
= NULL
; i
< obj
->Package
.Count
&& cnt
> 0; i
++, l
= q
) {
328 q
= obj
->Package
.Elements
[i
].Package
.Elements
;
331 * Skip duplicate entries.
333 if (l
!= NULL
&& l
[0].Integer
.Value
== q
[0].Integer
.Value
)
336 up
= (uint32_t *)pstate
;
337 for (j
= 0; j
< CPU_ACPI_PSS_SIZE
; j
++)
338 up
[j
] = q
[j
].Integer
.Value
;
342 CPU_ACPI_OBJ_IS_CACHED(handle
, CPU_ACPI_PSS_CACHED
);
345 AcpiOsFree(abuf
.Pointer
);
350 * Cache the _PPC data. The _PPC simply contains an integer value which
351 * represents the highest power level that a CPU should transition to.
352 * That is, it's an index into the array of _PSS entries and will be
353 * greater than or equal to zero.
356 cpu_acpi_cache_ppc(cpu_acpi_handle_t handle
)
362 * Fetch the _PPC (if present) for the CPU node. Since the PPC is
363 * optional (I think), non-existence is not a failure.
365 CPU_ACPI_OBJ_IS_NOT_CACHED(handle
, CPU_ACPI_PPC_CACHED
);
366 abuf
.Length
= ACPI_ALLOCATE_BUFFER
;
368 if (ACPI_FAILURE(AcpiEvaluateObject(handle
->cs_handle
, "_PPC",
370 CPU_ACPI_PPC(handle
) = 0;
374 obj
= (ACPI_OBJECT
*)abuf
.Pointer
;
375 CPU_ACPI_PPC(handle
) = obj
->Integer
.Value
;
376 CPU_ACPI_OBJ_IS_CACHED(handle
, CPU_ACPI_PPC_CACHED
);
377 AcpiOsFree(abuf
.Pointer
);
381 * Cache the _PCT, _PSS, _PSD and _PPC data.
384 cpu_acpi_cache_data(cpu_acpi_handle_t handle
)
386 if (cpu_acpi_cache_pct(handle
) < 0) {
387 cmn_err(CE_WARN
, "!cpu_acpi: error parsing _PCT for "
388 "CPU instance %d", ddi_get_instance(handle
->cs_dip
));
392 if (cpu_acpi_cache_pstates(handle
) != 0) {
393 cmn_err(CE_WARN
, "!cpu_acpi: error parsing _PSS for "
394 "CPU instance %d", ddi_get_instance(handle
->cs_dip
));
398 if (cpu_acpi_cache_psd(handle
) < 0) {
399 cmn_err(CE_WARN
, "!cpu_acpi: error parsing _PSD for "
400 "CPU instance %d", ddi_get_instance(handle
->cs_dip
));
404 cpu_acpi_cache_ppc(handle
);
410 * Register a handler for _PPC change notifications. The _PPC
411 * change notification is the means by which _P
414 cpu_acpi_install_ppc_handler(cpu_acpi_handle_t handle
,
415 ACPI_NOTIFY_HANDLER handler
, dev_info_t
*dip
)
417 char path
[MAXNAMELEN
];
418 if (ACPI_FAILURE(AcpiInstallNotifyHandler(handle
->cs_handle
,
419 ACPI_DEVICE_NOTIFY
, handler
, dip
)))
420 cmn_err(CE_NOTE
, "!cpu_acpi: Unable to register _PPC "
421 "notify handler for %s", ddi_pathname(dip
, path
));
428 cpu_acpi_write_pdc(cpu_acpi_handle_t handle
, uint32_t revision
, uint32_t count
,
429 uint32_t *capabilities
)
432 ACPI_OBJECT_LIST list
= { 1, &obj
};
438 bufsize
= (count
+ 2) * sizeof (uint32_t);
439 buffer
= kmem_zalloc(bufsize
, KM_SLEEP
);
440 buffer
[0] = revision
;
443 for (i
= 0; i
< count
; i
++)
444 *bufptr
++ = *capabilities
++;
446 obj
.Type
= ACPI_TYPE_BUFFER
;
447 obj
.Buffer
.Length
= bufsize
;
448 obj
.Buffer
.Pointer
= (void *)buffer
;
451 * _PDC is optional, so don't log failure.
453 if (ACPI_FAILURE(AcpiEvaluateObject(handle
->cs_handle
, "_PDC",
455 kmem_free(buffer
, bufsize
);
459 kmem_free(buffer
, bufsize
);
464 * Write to system IO port.
467 cpu_acpi_write_port(ACPI_IO_ADDRESS address
, uint32_t value
, uint32_t width
)
469 if (ACPI_FAILURE(AcpiOsWritePort(address
, value
, width
))) {
470 cmn_err(CE_NOTE
, "cpu_acpi: error writing system IO port "
471 "%lx.", (long)address
);
478 * Read from a system IO port.
481 cpu_acpi_read_port(ACPI_IO_ADDRESS address
, uint32_t *value
, uint32_t width
)
483 if (ACPI_FAILURE(AcpiOsReadPort(address
, value
, width
))) {
484 cmn_err(CE_NOTE
, "cpu_acpi: error reading system IO port "
485 "%lx.", (long)address
);
492 * Return supported frequencies.
495 cpu_acpi_get_speeds(cpu_acpi_handle_t handle
, int **speeds
)
497 cpu_acpi_pstate_t
*pstate
;
502 nspeeds
= CPU_ACPI_PSTATES_COUNT(handle
);
503 hspeeds
= kmem_zalloc(nspeeds
* sizeof (int), KM_SLEEP
);
504 for (i
= 0; i
< nspeeds
; i
++) {
505 pstate
= CPU_ACPI_PSTATE(handle
, i
);
506 hspeeds
[i
] = CPU_ACPI_FREQ(pstate
);
513 * Free resources allocated by cpu_acpi_get_speeds().
516 cpu_acpi_free_speeds(int *speeds
, uint_t nspeeds
)
518 kmem_free(speeds
, nspeeds
* sizeof (int));