19925408fSSepherosa Ziehau /*
29925408fSSepherosa Ziehau * Copyright (c) 2014 The DragonFly Project. All rights reserved.
39925408fSSepherosa Ziehau *
49925408fSSepherosa Ziehau * This code is derived from software contributed to The DragonFly Project
59925408fSSepherosa Ziehau * by Sepherosa Ziehau <sepherosa@gmail.com>
69925408fSSepherosa Ziehau *
79925408fSSepherosa Ziehau * Redistribution and use in source and binary forms, with or without
89925408fSSepherosa Ziehau * modification, are permitted provided that the following conditions
99925408fSSepherosa Ziehau * are met:
109925408fSSepherosa Ziehau *
119925408fSSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright
129925408fSSepherosa Ziehau * notice, this list of conditions and the following disclaimer.
139925408fSSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright
149925408fSSepherosa Ziehau * notice, this list of conditions and the following disclaimer in
159925408fSSepherosa Ziehau * the documentation and/or other materials provided with the
169925408fSSepherosa Ziehau * distribution.
179925408fSSepherosa Ziehau * 3. Neither the name of The DragonFly Project nor the names of its
189925408fSSepherosa Ziehau * contributors may be used to endorse or promote products derived
199925408fSSepherosa Ziehau * from this software without specific, prior written permission.
209925408fSSepherosa Ziehau *
219925408fSSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
229925408fSSepherosa Ziehau * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
239925408fSSepherosa Ziehau * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
249925408fSSepherosa Ziehau * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
259925408fSSepherosa Ziehau * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
269925408fSSepherosa Ziehau * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
279925408fSSepherosa Ziehau * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
289925408fSSepherosa Ziehau * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
299925408fSSepherosa Ziehau * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
309925408fSSepherosa Ziehau * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
319925408fSSepherosa Ziehau * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
329925408fSSepherosa Ziehau * SUCH DAMAGE.
339925408fSSepherosa Ziehau */
349925408fSSepherosa Ziehau
359925408fSSepherosa Ziehau #include <sys/param.h>
369925408fSSepherosa Ziehau #include <sys/kernel.h>
379925408fSSepherosa Ziehau #include <sys/systm.h>
389925408fSSepherosa Ziehau #include <sys/globaldata.h>
399925408fSSepherosa Ziehau
409925408fSSepherosa Ziehau #include <machine/md_var.h>
419925408fSSepherosa Ziehau #include <machine/cpufunc.h>
429925408fSSepherosa Ziehau #include <machine/cpufreq.h>
439925408fSSepherosa Ziehau #include <machine/cputypes.h>
449925408fSSepherosa Ziehau #include <machine/specialreg.h>
459925408fSSepherosa Ziehau
469925408fSSepherosa Ziehau #include "acpi.h"
479925408fSSepherosa Ziehau #include "acpi_cpu_cstate.h"
489925408fSSepherosa Ziehau
495764e125SSepherosa Ziehau /* GAS.BitWidth */
505764e125SSepherosa Ziehau #define ACPI_GAS_INTEL_VENDOR 1
515764e125SSepherosa Ziehau
525764e125SSepherosa Ziehau /* GAS.BitOffset */
535764e125SSepherosa Ziehau #define ACPI_GAS_INTEL_CLASS_C1_IO_HALT 1
545764e125SSepherosa Ziehau #define ACPI_GAS_INTEL_CLASS_CX_NATIVE 2
555764e125SSepherosa Ziehau
565764e125SSepherosa Ziehau /* GAS.AccessWidth */
575764e125SSepherosa Ziehau #define ACPI_GAS_INTEL_ARG1_HWCOORD 0x1
585764e125SSepherosa Ziehau #define ACPI_GAS_INTEL_ARG1_BM_STS 0x2
595764e125SSepherosa Ziehau
605764e125SSepherosa Ziehau /* GAS.Address */
615764e125SSepherosa Ziehau #define ACPI_GAS_INTEL_ARG0_MWAIT_HINTMASK 0xffffffff
625764e125SSepherosa Ziehau
635764e125SSepherosa Ziehau static int acpi_cst_cx_mwait_setup(struct acpi_cst_cx *);
643938d744SSascha Wildner static void acpi_cst_cx_mwait_enter(const struct acpi_cst_cx *);
655764e125SSepherosa Ziehau
669925408fSSepherosa Ziehau int
acpi_cst_md_cx_setup(struct acpi_cst_cx * cx)679925408fSSepherosa Ziehau acpi_cst_md_cx_setup(struct acpi_cst_cx *cx)
689925408fSSepherosa Ziehau {
695764e125SSepherosa Ziehau int error;
705764e125SSepherosa Ziehau
719925408fSSepherosa Ziehau if (cpu_vendor_id != CPU_VENDOR_INTEL) {
729925408fSSepherosa Ziehau /*
739925408fSSepherosa Ziehau * No optimization for non-Intel CPUs so far.
746df05d3dSSepherosa Ziehau *
754019cf69SSepherosa Ziehau * Hardware fixed resource is not supported for
766df05d3dSSepherosa Ziehau * C1+ state yet.
779925408fSSepherosa Ziehau */
786df05d3dSSepherosa Ziehau if (cx->type == ACPI_STATE_C1 &&
796df05d3dSSepherosa Ziehau cx->gas.SpaceId == ACPI_ADR_SPACE_FIXED_HARDWARE)
806df05d3dSSepherosa Ziehau return 0;
819925408fSSepherosa Ziehau if (cx->gas.SpaceId != ACPI_ADR_SPACE_SYSTEM_IO &&
825764e125SSepherosa Ziehau cx->gas.SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) {
835764e125SSepherosa Ziehau kprintf("C%d: invalid SpaceId %d\n", cx->type,
845764e125SSepherosa Ziehau cx->gas.SpaceId);
859925408fSSepherosa Ziehau return EINVAL;
865764e125SSepherosa Ziehau }
879925408fSSepherosa Ziehau return 0;
889925408fSSepherosa Ziehau }
899925408fSSepherosa Ziehau
905764e125SSepherosa Ziehau switch (cx->gas.SpaceId) {
915764e125SSepherosa Ziehau case ACPI_ADR_SPACE_SYSTEM_IO:
925764e125SSepherosa Ziehau case ACPI_ADR_SPACE_SYSTEM_MEMORY:
935764e125SSepherosa Ziehau break;
946df05d3dSSepherosa Ziehau
955764e125SSepherosa Ziehau case ACPI_ADR_SPACE_FIXED_HARDWARE:
965764e125SSepherosa Ziehau error = acpi_cst_cx_mwait_setup(cx);
975764e125SSepherosa Ziehau if (error)
985764e125SSepherosa Ziehau return error;
995764e125SSepherosa Ziehau break;
1005764e125SSepherosa Ziehau
1015764e125SSepherosa Ziehau default:
1025764e125SSepherosa Ziehau kprintf("C%d: invalid SpaceId %d\n", cx->type, cx->gas.SpaceId);
1039925408fSSepherosa Ziehau return EINVAL;
1045764e125SSepherosa Ziehau }
1059925408fSSepherosa Ziehau
1069925408fSSepherosa Ziehau if (cx->type >= ACPI_STATE_C3) {
10790a26aa2SSepherosa Ziehau if ((CPUID_TO_FAMILY(cpu_id) > 0xf ||
1089925408fSSepherosa Ziehau (CPUID_TO_FAMILY(cpu_id) == 0x6 &&
10990a26aa2SSepherosa Ziehau CPUID_TO_MODEL(cpu_id) >= 0xf)) &&
11090a26aa2SSepherosa Ziehau !acpi_cst_force_bmarb) {
1119925408fSSepherosa Ziehau /*
1129925408fSSepherosa Ziehau * Pentium dual-core, Core 2 and beyond do not
1139925408fSSepherosa Ziehau * need any additional activities to enter C3(+).
1149925408fSSepherosa Ziehau */
1159925408fSSepherosa Ziehau cx->preamble = ACPI_CST_CX_PREAMBLE_NONE;
1169925408fSSepherosa Ziehau } else if ((acpi_cst_quirks & ACPI_CST_QUIRK_NO_BM) == 0) {
1179925408fSSepherosa Ziehau /*
1189925408fSSepherosa Ziehau * Intel CPUs support bus master operation for
1199925408fSSepherosa Ziehau * entering C3(+) even on MP system.
1209925408fSSepherosa Ziehau */
1219925408fSSepherosa Ziehau cx->preamble = ACPI_CST_CX_PREAMBLE_BM_ARB;
1229925408fSSepherosa Ziehau }
1239925408fSSepherosa Ziehau }
1249925408fSSepherosa Ziehau return 0;
1259925408fSSepherosa Ziehau }
1265764e125SSepherosa Ziehau
1275764e125SSepherosa Ziehau static int
acpi_cst_cx_mwait_setup(struct acpi_cst_cx * cx)1285764e125SSepherosa Ziehau acpi_cst_cx_mwait_setup(struct acpi_cst_cx *cx)
1295764e125SSepherosa Ziehau {
1305764e125SSepherosa Ziehau uint32_t eax_hint;
131*ca7dfd3cSSepherosa Ziehau int error;
1325764e125SSepherosa Ziehau
1335764e125SSepherosa Ziehau if (bootverbose) {
1345764e125SSepherosa Ziehau kprintf("C%d: BitWidth(vendor) %d, BitOffset(class) %d, "
1355764e125SSepherosa Ziehau "Address(arg0) 0x%jx, AccessWidth(arg1) 0x%x\n", cx->type,
1365764e125SSepherosa Ziehau cx->gas.BitWidth, cx->gas.BitOffset,
1375764e125SSepherosa Ziehau (uintmax_t)cx->gas.Address, cx->gas.AccessWidth);
1385764e125SSepherosa Ziehau }
1395764e125SSepherosa Ziehau
1405764e125SSepherosa Ziehau if (cx->type == ACPI_STATE_C1) {
1415764e125SSepherosa Ziehau /* XXX mwait */
1425764e125SSepherosa Ziehau /* XXX I/O then halt */
1435764e125SSepherosa Ziehau return 0;
1445764e125SSepherosa Ziehau }
1455764e125SSepherosa Ziehau
1465764e125SSepherosa Ziehau if (cx->gas.BitOffset != ACPI_GAS_INTEL_CLASS_CX_NATIVE)
1475764e125SSepherosa Ziehau return EINVAL;
1485764e125SSepherosa Ziehau
1495764e125SSepherosa Ziehau if ((cpu_feature2 & CPUID2_MON) == 0)
1505764e125SSepherosa Ziehau return EOPNOTSUPP;
1515764e125SSepherosa Ziehau if ((cpu_mwait_feature & (CPUID_MWAIT_EXT | CPUID_MWAIT_INTBRK)) !=
1525764e125SSepherosa Ziehau (CPUID_MWAIT_EXT | CPUID_MWAIT_INTBRK))
1535764e125SSepherosa Ziehau return EOPNOTSUPP;
1545764e125SSepherosa Ziehau
1555764e125SSepherosa Ziehau eax_hint = cx->gas.Address & ACPI_GAS_INTEL_ARG0_MWAIT_HINTMASK;
1565764e125SSepherosa Ziehau if (bootverbose) {
1575764e125SSepherosa Ziehau kprintf("C%d -> cpu specific C%d sub state %d\n", cx->type,
1585764e125SSepherosa Ziehau MWAIT_EAX_TO_CX(eax_hint), MWAIT_EAX_TO_CX_SUB(eax_hint));
1595764e125SSepherosa Ziehau }
1605764e125SSepherosa Ziehau
1615764e125SSepherosa Ziehau if (!cpu_mwait_hint_valid(eax_hint)) {
1625764e125SSepherosa Ziehau kprintf("C%d: invalid mwait hint 0x%08x\n", cx->type, eax_hint);
163*ca7dfd3cSSepherosa Ziehau error = EINVAL;
164*ca7dfd3cSSepherosa Ziehau goto done;
1655764e125SSepherosa Ziehau }
1665764e125SSepherosa Ziehau
1675764e125SSepherosa Ziehau cx->md_arg0 = eax_hint;
1685764e125SSepherosa Ziehau cx->enter = acpi_cst_cx_mwait_enter;
169*ca7dfd3cSSepherosa Ziehau error = 0;
1705764e125SSepherosa Ziehau
171*ca7dfd3cSSepherosa Ziehau done:
17290a26aa2SSepherosa Ziehau if ((cx->gas.AccessWidth & ACPI_GAS_INTEL_ARG1_BM_STS) == 0 &&
17390a26aa2SSepherosa Ziehau !acpi_cst_force_bmsts) {
17422d2370fSSepherosa Ziehau cpu_mwait_cx_no_bmsts();
17553937a45SSepherosa Ziehau if (cx->type >= ACPI_STATE_C3)
17653937a45SSepherosa Ziehau cx->flags &= ~ACPI_CST_CX_FLAG_BM_STS;
17722d2370fSSepherosa Ziehau }
1785764e125SSepherosa Ziehau
179e1e344f5SSepherosa Ziehau if (cx->type < ACPI_STATE_C3 && MWAIT_EAX_TO_CX(eax_hint) >= 3) {
180e1e344f5SSepherosa Ziehau /*
181e1e344f5SSepherosa Ziehau * If BIOS maps shallow ACPI C-state (<C3) to deep CPU
182e1e344f5SSepherosa Ziehau * specific C-state (>=C3), it implies no bus mastering
183e1e344f5SSepherosa Ziehau * operations are needed before entering deep CPU specific
184e1e344f5SSepherosa Ziehau * C-states.
185e1e344f5SSepherosa Ziehau */
18690a26aa2SSepherosa Ziehau if (!acpi_cst_force_bmsts)
187e1e344f5SSepherosa Ziehau cpu_mwait_cx_no_bmsts();
18890a26aa2SSepherosa Ziehau if (!acpi_cst_force_bmarb)
189e1e344f5SSepherosa Ziehau cpu_mwait_cx_no_bmarb();
190e1e344f5SSepherosa Ziehau }
191e1e344f5SSepherosa Ziehau
192*ca7dfd3cSSepherosa Ziehau return error;
1935764e125SSepherosa Ziehau }
1945764e125SSepherosa Ziehau
1955764e125SSepherosa Ziehau static void
acpi_cst_cx_mwait_enter(const struct acpi_cst_cx * cx)1963938d744SSascha Wildner acpi_cst_cx_mwait_enter(const struct acpi_cst_cx *cx)
1975764e125SSepherosa Ziehau {
1985764e125SSepherosa Ziehau struct globaldata *gd = mycpu;
1995764e125SSepherosa Ziehau int reqflags;
2005764e125SSepherosa Ziehau
2015764e125SSepherosa Ziehau reqflags = gd->gd_reqflags;
2025764e125SSepherosa Ziehau if ((reqflags & RQF_IDLECHECK_WK_MASK) == 0) {
2035764e125SSepherosa Ziehau cpu_mmw_pause_int(&gd->gd_reqflags, reqflags, cx->md_arg0,
2045764e125SSepherosa Ziehau MWAIT_ECX_INTBRK);
2055764e125SSepherosa Ziehau }
2065764e125SSepherosa Ziehau }
207