1 /* $NetBSD: acpi_pdc.c,v 1.1 2011/06/12 10:11:52 jruoho Exp $ */ 2 3 /*- 4 * Copyright (c) 2010, 2011 Jukka Ruohonen <jruohonen@iki.fi> 5 * All rights reserved. 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: 10 * 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 the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: acpi_pdc.c,v 1.1 2011/06/12 10:11:52 jruoho Exp $"); 31 32 #include <sys/param.h> 33 34 #include <x86/cpu.h> 35 #include <x86/cputypes.h> 36 #include <x86/cpuvar.h> 37 38 #include <dev/acpi/acpireg.h> 39 #include <dev/acpi/acpivar.h> 40 #include <dev/acpi/acpi_cpu.h> 41 42 #include <machine/acpi_machdep.h> 43 44 #define _COMPONENT ACPI_BUS_COMPONENT 45 ACPI_MODULE_NAME ("acpi_pdc") 46 47 static uint32_t flags = 0; 48 49 static ACPI_STATUS acpi_md_pdc_walk(ACPI_HANDLE, uint32_t,void *,void **); 50 static ACPI_STATUS acpi_md_pdc_set(ACPI_HANDLE, uint32_t); 51 52 uint32_t 53 acpi_md_pdc(void) 54 { 55 char *hid = __UNCONST("ACPI0007"); 56 struct cpu_info *ci = curcpu(); 57 uint32_t regs[4]; 58 59 if (flags != 0) 60 return flags; 61 62 if (cpu_vendor != CPUVENDOR_IDT && 63 cpu_vendor != CPUVENDOR_INTEL) 64 return 0; 65 66 /* 67 * Basic SMP C-states (required for e.g. _CST). 68 */ 69 flags |= ACPICPU_PDC_C_C1PT | ACPICPU_PDC_C_C2C3; 70 71 /* 72 * Claim to support dependency coordination. 73 */ 74 flags |= ACPICPU_PDC_P_SW | ACPICPU_PDC_C_SW | ACPICPU_PDC_T_SW; 75 76 /* 77 * If MONITOR/MWAIT is available, announce 78 * support for native instructions in all C-states. 79 */ 80 if ((ci->ci_feat_val[1] & CPUID2_MONITOR) != 0) 81 flags |= ACPICPU_PDC_C_C1_FFH | ACPICPU_PDC_C_C2C3_FFH; 82 83 /* 84 * Set native P- and T-states, if available. 85 */ 86 if ((ci->ci_feat_val[1] & CPUID2_EST) != 0) 87 flags |= ACPICPU_PDC_P_FFH; 88 89 if ((ci->ci_feat_val[0] & CPUID_ACPI) != 0) 90 flags |= ACPICPU_PDC_T_FFH; 91 92 /* 93 * Declare support for APERF and MPERF. 94 */ 95 if (cpuid_level >= 0x06) { 96 97 x86_cpuid(0x00000006, regs); 98 99 if ((regs[2] & CPUID_DSPM_HWF) != 0) 100 flags |= ACPICPU_PDC_P_HWF; 101 } 102 103 /* 104 * As the _PDC must be evaluated before the internal namespace 105 * is built, we have no option but to walk with the interpreter. 106 */ 107 (void)AcpiGetDevices(hid, acpi_md_pdc_walk, NULL, NULL); 108 109 (void)AcpiWalkNamespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, 110 UINT32_MAX, acpi_md_pdc_walk, NULL, NULL, NULL); 111 112 return flags; 113 } 114 115 static ACPI_STATUS 116 acpi_md_pdc_walk(ACPI_HANDLE hdl, uint32_t level, void *context, void **status) 117 { 118 return acpi_md_pdc_set(hdl, flags); 119 } 120 121 static ACPI_STATUS 122 acpi_md_pdc_set(ACPI_HANDLE hdl, uint32_t val) 123 { 124 ACPI_OBJECT_LIST arg; 125 ACPI_OBJECT obj; 126 uint32_t cap[3]; 127 128 arg.Count = 1; 129 arg.Pointer = &obj; 130 131 cap[0] = ACPICPU_PDC_REVID; 132 cap[1] = 1; 133 cap[2] = val; 134 135 obj.Type = ACPI_TYPE_BUFFER; 136 obj.Buffer.Length = sizeof(cap); 137 obj.Buffer.Pointer = (void *)cap; 138 139 (void)AcpiEvaluateObject(hdl, "_PDC", &arg, NULL); 140 141 return AE_OK; 142 } 143