1*0301c379Sjruoho /* $NetBSD: acpi_pdc.c,v 1.2 2011/06/20 15:39:54 jruoho Exp $ */
20fc4e4abSjruoho
30fc4e4abSjruoho /*-
40fc4e4abSjruoho * Copyright (c) 2010, 2011 Jukka Ruohonen <jruohonen@iki.fi>
50fc4e4abSjruoho * All rights reserved.
60fc4e4abSjruoho *
70fc4e4abSjruoho * Redistribution and use in source and binary forms, with or without
80fc4e4abSjruoho * modification, are permitted provided that the following conditions
90fc4e4abSjruoho * are met:
100fc4e4abSjruoho *
110fc4e4abSjruoho * 1. Redistributions of source code must retain the above copyright
120fc4e4abSjruoho * notice, this list of conditions and the following disclaimer.
130fc4e4abSjruoho * 2. Redistributions in binary form must reproduce the above copyright
140fc4e4abSjruoho * notice, this list of conditions and the following disclaimer in the
150fc4e4abSjruoho * documentation and/or other materials provided with the distribution.
160fc4e4abSjruoho *
170fc4e4abSjruoho * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
180fc4e4abSjruoho * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
190fc4e4abSjruoho * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
200fc4e4abSjruoho * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
210fc4e4abSjruoho * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
220fc4e4abSjruoho * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
230fc4e4abSjruoho * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
240fc4e4abSjruoho * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
250fc4e4abSjruoho * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
260fc4e4abSjruoho * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
270fc4e4abSjruoho * SUCH DAMAGE.
280fc4e4abSjruoho */
290fc4e4abSjruoho #include <sys/cdefs.h>
30*0301c379Sjruoho __KERNEL_RCSID(0, "$NetBSD: acpi_pdc.c,v 1.2 2011/06/20 15:39:54 jruoho Exp $");
310fc4e4abSjruoho
320fc4e4abSjruoho #include <sys/param.h>
330fc4e4abSjruoho
340fc4e4abSjruoho #include <x86/cpu.h>
350fc4e4abSjruoho #include <x86/cputypes.h>
360fc4e4abSjruoho #include <x86/cpuvar.h>
370fc4e4abSjruoho
380fc4e4abSjruoho #include <dev/acpi/acpireg.h>
390fc4e4abSjruoho #include <dev/acpi/acpivar.h>
400fc4e4abSjruoho #include <dev/acpi/acpi_cpu.h>
410fc4e4abSjruoho
420fc4e4abSjruoho #include <machine/acpi_machdep.h>
430fc4e4abSjruoho
440fc4e4abSjruoho #define _COMPONENT ACPI_BUS_COMPONENT
450fc4e4abSjruoho ACPI_MODULE_NAME ("acpi_pdc")
460fc4e4abSjruoho
470fc4e4abSjruoho static uint32_t flags = 0;
480fc4e4abSjruoho
490fc4e4abSjruoho static ACPI_STATUS acpi_md_pdc_walk(ACPI_HANDLE, uint32_t,void *,void **);
50*0301c379Sjruoho static void acpi_md_pdc_set(ACPI_HANDLE, uint32_t);
510fc4e4abSjruoho
520fc4e4abSjruoho uint32_t
acpi_md_pdc(void)530fc4e4abSjruoho acpi_md_pdc(void)
540fc4e4abSjruoho {
550fc4e4abSjruoho struct cpu_info *ci = curcpu();
560fc4e4abSjruoho uint32_t regs[4];
570fc4e4abSjruoho
580fc4e4abSjruoho if (flags != 0)
590fc4e4abSjruoho return flags;
600fc4e4abSjruoho
610fc4e4abSjruoho if (cpu_vendor != CPUVENDOR_IDT &&
620fc4e4abSjruoho cpu_vendor != CPUVENDOR_INTEL)
630fc4e4abSjruoho return 0;
640fc4e4abSjruoho
650fc4e4abSjruoho /*
660fc4e4abSjruoho * Basic SMP C-states (required for e.g. _CST).
670fc4e4abSjruoho */
680fc4e4abSjruoho flags |= ACPICPU_PDC_C_C1PT | ACPICPU_PDC_C_C2C3;
690fc4e4abSjruoho
700fc4e4abSjruoho /*
710fc4e4abSjruoho * Claim to support dependency coordination.
720fc4e4abSjruoho */
730fc4e4abSjruoho flags |= ACPICPU_PDC_P_SW | ACPICPU_PDC_C_SW | ACPICPU_PDC_T_SW;
740fc4e4abSjruoho
750fc4e4abSjruoho /*
760fc4e4abSjruoho * If MONITOR/MWAIT is available, announce
770fc4e4abSjruoho * support for native instructions in all C-states.
780fc4e4abSjruoho */
790fc4e4abSjruoho if ((ci->ci_feat_val[1] & CPUID2_MONITOR) != 0)
800fc4e4abSjruoho flags |= ACPICPU_PDC_C_C1_FFH | ACPICPU_PDC_C_C2C3_FFH;
810fc4e4abSjruoho
820fc4e4abSjruoho /*
830fc4e4abSjruoho * Set native P- and T-states, if available.
840fc4e4abSjruoho */
850fc4e4abSjruoho if ((ci->ci_feat_val[1] & CPUID2_EST) != 0)
860fc4e4abSjruoho flags |= ACPICPU_PDC_P_FFH;
870fc4e4abSjruoho
880fc4e4abSjruoho if ((ci->ci_feat_val[0] & CPUID_ACPI) != 0)
890fc4e4abSjruoho flags |= ACPICPU_PDC_T_FFH;
900fc4e4abSjruoho
910fc4e4abSjruoho /*
920fc4e4abSjruoho * Declare support for APERF and MPERF.
930fc4e4abSjruoho */
940fc4e4abSjruoho if (cpuid_level >= 0x06) {
950fc4e4abSjruoho
960fc4e4abSjruoho x86_cpuid(0x00000006, regs);
970fc4e4abSjruoho
980fc4e4abSjruoho if ((regs[2] & CPUID_DSPM_HWF) != 0)
990fc4e4abSjruoho flags |= ACPICPU_PDC_P_HWF;
1000fc4e4abSjruoho }
1010fc4e4abSjruoho
1020fc4e4abSjruoho /*
1030fc4e4abSjruoho * As the _PDC must be evaluated before the internal namespace
1040fc4e4abSjruoho * is built, we have no option but to walk with the interpreter.
1050fc4e4abSjruoho */
106*0301c379Sjruoho (void)AcpiWalkNamespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
1070fc4e4abSjruoho UINT32_MAX, acpi_md_pdc_walk, NULL, NULL, NULL);
1080fc4e4abSjruoho
1090fc4e4abSjruoho return flags;
1100fc4e4abSjruoho }
1110fc4e4abSjruoho
1120fc4e4abSjruoho static ACPI_STATUS
acpi_md_pdc_walk(ACPI_HANDLE hdl,uint32_t level,void * aux,void ** sta)113*0301c379Sjruoho acpi_md_pdc_walk(ACPI_HANDLE hdl, uint32_t level, void *aux, void **sta)
1140fc4e4abSjruoho {
115*0301c379Sjruoho struct cpu_info *ci;
116*0301c379Sjruoho
117*0301c379Sjruoho ci = acpi_match_cpu_handle(hdl);
118*0301c379Sjruoho
119*0301c379Sjruoho if (ci != NULL)
120*0301c379Sjruoho acpi_md_pdc_set(hdl, flags);
121*0301c379Sjruoho
122*0301c379Sjruoho return AE_OK;
1230fc4e4abSjruoho }
1240fc4e4abSjruoho
125*0301c379Sjruoho static void
acpi_md_pdc_set(ACPI_HANDLE hdl,uint32_t val)1260fc4e4abSjruoho acpi_md_pdc_set(ACPI_HANDLE hdl, uint32_t val)
1270fc4e4abSjruoho {
1280fc4e4abSjruoho ACPI_OBJECT_LIST arg;
1290fc4e4abSjruoho ACPI_OBJECT obj;
1300fc4e4abSjruoho uint32_t cap[3];
1310fc4e4abSjruoho
1320fc4e4abSjruoho arg.Count = 1;
1330fc4e4abSjruoho arg.Pointer = &obj;
1340fc4e4abSjruoho
1350fc4e4abSjruoho cap[0] = ACPICPU_PDC_REVID;
1360fc4e4abSjruoho cap[1] = 1;
1370fc4e4abSjruoho cap[2] = val;
1380fc4e4abSjruoho
1390fc4e4abSjruoho obj.Type = ACPI_TYPE_BUFFER;
1400fc4e4abSjruoho obj.Buffer.Length = sizeof(cap);
1410fc4e4abSjruoho obj.Buffer.Pointer = (void *)cap;
1420fc4e4abSjruoho
1430fc4e4abSjruoho (void)AcpiEvaluateObject(hdl, "_PDC", &arg, NULL);
1440fc4e4abSjruoho }
145