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