2 * Copyright (c) 2014 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Sepherosa Ziehau <sepherosa@gmail.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include <sys/param.h>
36 #include <sys/kernel.h>
37 #include <sys/systm.h>
38 #include <sys/globaldata.h>
40 #include <machine/md_var.h>
41 #include <machine/cpufunc.h>
42 #include <machine/cpufreq.h>
43 #include <machine/cputypes.h>
44 #include <machine/specialreg.h>
47 #include "acpi_cpu_cstate.h"
50 #define ACPI_GAS_INTEL_VENDOR 1
53 #define ACPI_GAS_INTEL_CLASS_C1_IO_HALT 1
54 #define ACPI_GAS_INTEL_CLASS_CX_NATIVE 2
57 #define ACPI_GAS_INTEL_ARG1_HWCOORD 0x1
58 #define ACPI_GAS_INTEL_ARG1_BM_STS 0x2
61 #define ACPI_GAS_INTEL_ARG0_MWAIT_HINTMASK 0xffffffff
63 static int acpi_cst_cx_mwait_setup(struct acpi_cst_cx *);
64 static void acpi_cst_cx_mwait_enter(const struct acpi_cst_cx *);
67 acpi_cst_md_cx_setup(struct acpi_cst_cx *cx)
71 if (cpu_vendor_id != CPU_VENDOR_INTEL) {
73 * No optimization for non-Intel CPUs so far.
75 * Hardware fixed resource is not supported for
78 if (cx->type == ACPI_STATE_C1 &&
79 cx->gas.SpaceId == ACPI_ADR_SPACE_FIXED_HARDWARE)
81 if (cx->gas.SpaceId != ACPI_ADR_SPACE_SYSTEM_IO &&
82 cx->gas.SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) {
83 kprintf("C%d: invalid SpaceId %d\n", cx->type,
90 switch (cx->gas.SpaceId) {
91 case ACPI_ADR_SPACE_SYSTEM_IO:
92 case ACPI_ADR_SPACE_SYSTEM_MEMORY:
95 case ACPI_ADR_SPACE_FIXED_HARDWARE:
96 error = acpi_cst_cx_mwait_setup(cx);
102 kprintf("C%d: invalid SpaceId %d\n", cx->type, cx->gas.SpaceId);
106 if (cx->type >= ACPI_STATE_C3) {
107 if ((CPUID_TO_FAMILY(cpu_id) > 0xf ||
108 (CPUID_TO_FAMILY(cpu_id) == 0x6 &&
109 CPUID_TO_MODEL(cpu_id) >= 0xf)) &&
110 !acpi_cst_force_bmarb) {
112 * Pentium dual-core, Core 2 and beyond do not
113 * need any additional activities to enter C3(+).
115 cx->preamble = ACPI_CST_CX_PREAMBLE_NONE;
116 } else if ((acpi_cst_quirks & ACPI_CST_QUIRK_NO_BM) == 0) {
118 * Intel CPUs support bus master operation for
119 * entering C3(+) even on MP system.
121 cx->preamble = ACPI_CST_CX_PREAMBLE_BM_ARB;
128 acpi_cst_cx_mwait_setup(struct acpi_cst_cx *cx)
133 kprintf("C%d: BitWidth(vendor) %d, BitOffset(class) %d, "
134 "Address(arg0) 0x%jx, AccessWidth(arg1) 0x%x\n", cx->type,
135 cx->gas.BitWidth, cx->gas.BitOffset,
136 (uintmax_t)cx->gas.Address, cx->gas.AccessWidth);
139 if (cx->type == ACPI_STATE_C1) {
141 /* XXX I/O then halt */
145 if (cx->gas.BitOffset != ACPI_GAS_INTEL_CLASS_CX_NATIVE)
148 if ((cpu_feature2 & CPUID2_MON) == 0)
150 if ((cpu_mwait_feature & (CPUID_MWAIT_EXT | CPUID_MWAIT_INTBRK)) !=
151 (CPUID_MWAIT_EXT | CPUID_MWAIT_INTBRK))
154 eax_hint = cx->gas.Address & ACPI_GAS_INTEL_ARG0_MWAIT_HINTMASK;
156 kprintf("C%d -> cpu specific C%d sub state %d\n", cx->type,
157 MWAIT_EAX_TO_CX(eax_hint), MWAIT_EAX_TO_CX_SUB(eax_hint));
160 if (!cpu_mwait_hint_valid(eax_hint)) {
161 kprintf("C%d: invalid mwait hint 0x%08x\n", cx->type, eax_hint);
165 cx->md_arg0 = eax_hint;
166 cx->enter = acpi_cst_cx_mwait_enter;
168 if ((cx->gas.AccessWidth & ACPI_GAS_INTEL_ARG1_BM_STS) == 0 &&
169 !acpi_cst_force_bmsts) {
170 cpu_mwait_cx_no_bmsts();
171 if (cx->type >= ACPI_STATE_C3)
172 cx->flags &= ~ACPI_CST_CX_FLAG_BM_STS;
175 if (cx->type < ACPI_STATE_C3 && MWAIT_EAX_TO_CX(eax_hint) >= 3) {
177 * If BIOS maps shallow ACPI C-state (<C3) to deep CPU
178 * specific C-state (>=C3), it implies no bus mastering
179 * operations are needed before entering deep CPU specific
182 if (!acpi_cst_force_bmsts)
183 cpu_mwait_cx_no_bmsts();
184 if (!acpi_cst_force_bmarb)
185 cpu_mwait_cx_no_bmarb();
192 acpi_cst_cx_mwait_enter(const struct acpi_cst_cx *cx)
194 struct globaldata *gd = mycpu;
197 reqflags = gd->gd_reqflags;
198 if ((reqflags & RQF_IDLECHECK_WK_MASK) == 0) {
199 cpu_mmw_pause_int(&gd->gd_reqflags, reqflags, cx->md_arg0,