acpi_pdc.c revision 1.2
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
45ACPI_MODULE_NAME	("acpi_pdc")
46
47static uint32_t		flags = 0;
48
49static ACPI_STATUS	acpi_md_pdc_walk(ACPI_HANDLE, uint32_t,void *,void **);
50static void		acpi_md_pdc_set(ACPI_HANDLE, uint32_t);
51
52uint32_t
53acpi_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
112static ACPI_STATUS
113acpi_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
125static void
126acpi_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