1 /* $NetBSD: acpi_pdc.c,v 1.2 2011/06/20 15:39:54 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.2 2011/06/20 15:39:54 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 void acpi_md_pdc_set(ACPI_HANDLE, uint32_t); 51 52 uint32_t 53 acpi_md_pdc(void) 54 { 55 struct cpu_info *ci = curcpu(); 56 uint32_t regs[4]; 57 58 if (flags != 0) 59 return flags; 60 61 if (cpu_vendor != CPUVENDOR_IDT && 62 cpu_vendor != CPUVENDOR_INTEL) 63 return 0; 64 65 /* 66 * Basic SMP C-states (required for e.g. _CST). 67 */ 68 flags |= ACPICPU_PDC_C_C1PT | ACPICPU_PDC_C_C2C3; 69 70 /* 71 * Claim to support dependency coordination. 72 */ 73 flags |= ACPICPU_PDC_P_SW | ACPICPU_PDC_C_SW | ACPICPU_PDC_T_SW; 74 75 /* 76 * If MONITOR/MWAIT is available, announce 77 * support for native instructions in all C-states. 78 */ 79 if ((ci->ci_feat_val[1] & CPUID2_MONITOR) != 0) 80 flags |= ACPICPU_PDC_C_C1_FFH | ACPICPU_PDC_C_C2C3_FFH; 81 82 /* 83 * Set native P- and T-states, if available. 84 */ 85 if ((ci->ci_feat_val[1] & CPUID2_EST) != 0) 86 flags |= ACPICPU_PDC_P_FFH; 87 88 if ((ci->ci_feat_val[0] & CPUID_ACPI) != 0) 89 flags |= ACPICPU_PDC_T_FFH; 90 91 /* 92 * Declare support for APERF and MPERF. 93 */ 94 if (cpuid_level >= 0x06) { 95 96 x86_cpuid(0x00000006, regs); 97 98 if ((regs[2] & CPUID_DSPM_HWF) != 0) 99 flags |= ACPICPU_PDC_P_HWF; 100 } 101 102 /* 103 * As the _PDC must be evaluated before the internal namespace 104 * is built, we have no option but to walk with the interpreter. 105 */ 106 (void)AcpiWalkNamespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, 107 UINT32_MAX, acpi_md_pdc_walk, NULL, NULL, NULL); 108 109 return flags; 110 } 111 112 static ACPI_STATUS 113 acpi_md_pdc_walk(ACPI_HANDLE hdl, uint32_t level, void *aux, void **sta) 114 { 115 struct cpu_info *ci; 116 117 ci = acpi_match_cpu_handle(hdl); 118 119 if (ci != NULL) 120 acpi_md_pdc_set(hdl, flags); 121 122 return AE_OK; 123 } 124 125 static void 126 acpi_md_pdc_set(ACPI_HANDLE hdl, uint32_t val) 127 { 128 ACPI_OBJECT_LIST arg; 129 ACPI_OBJECT obj; 130 uint32_t cap[3]; 131 132 arg.Count = 1; 133 arg.Pointer = &obj; 134 135 cap[0] = ACPICPU_PDC_REVID; 136 cap[1] = 1; 137 cap[2] = val; 138 139 obj.Type = ACPI_TYPE_BUFFER; 140 obj.Buffer.Length = sizeof(cap); 141 obj.Buffer.Pointer = (void *)cap; 142 143 (void)AcpiEvaluateObject(hdl, "_PDC", &arg, NULL); 144 } 145