15db2f26eSSascha Wildner /*
25db2f26eSSascha Wildner  * Copyright (c) 2009 The DragonFly Project.  All rights reserved.
35db2f26eSSascha Wildner  *
45db2f26eSSascha Wildner  * This code is derived from software contributed to The DragonFly Project
55db2f26eSSascha Wildner  * by Sepherosa Ziehau <sepherosa@gmail.com>
65db2f26eSSascha Wildner  *
75db2f26eSSascha Wildner  * Redistribution and use in source and binary forms, with or without
85db2f26eSSascha Wildner  * modification, are permitted provided that the following conditions
95db2f26eSSascha Wildner  * are met:
105db2f26eSSascha Wildner  *
115db2f26eSSascha Wildner  * 1. Redistributions of source code must retain the above copyright
125db2f26eSSascha Wildner  *    notice, this list of conditions and the following disclaimer.
135db2f26eSSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
145db2f26eSSascha Wildner  *    notice, this list of conditions and the following disclaimer in
155db2f26eSSascha Wildner  *    the documentation and/or other materials provided with the
165db2f26eSSascha Wildner  *    distribution.
175db2f26eSSascha Wildner  * 3. Neither the name of The DragonFly Project nor the names of its
185db2f26eSSascha Wildner  *    contributors may be used to endorse or promote products derived
195db2f26eSSascha Wildner  *    from this software without specific, prior written permission.
205db2f26eSSascha Wildner  *
215db2f26eSSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
225db2f26eSSascha Wildner  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
235db2f26eSSascha Wildner  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
245db2f26eSSascha Wildner  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
255db2f26eSSascha Wildner  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
265db2f26eSSascha Wildner  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
275db2f26eSSascha Wildner  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
285db2f26eSSascha Wildner  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
295db2f26eSSascha Wildner  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
305db2f26eSSascha Wildner  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
315db2f26eSSascha Wildner  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
325db2f26eSSascha Wildner  * SUCH DAMAGE.
335db2f26eSSascha Wildner  */
345db2f26eSSascha Wildner 
355db2f26eSSascha Wildner #include <sys/param.h>
365db2f26eSSascha Wildner #include <sys/kernel.h>
375db2f26eSSascha Wildner #include <sys/systm.h>
385db2f26eSSascha Wildner #include <sys/globaldata.h>
395db2f26eSSascha Wildner 
405db2f26eSSascha Wildner #include <machine/md_var.h>
415db2f26eSSascha Wildner #include <machine/cpufunc.h>
425db2f26eSSascha Wildner #include <machine/cpufreq.h>
435db2f26eSSascha Wildner #include <machine/cputypes.h>
445db2f26eSSascha Wildner #include <machine/specialreg.h>
455db2f26eSSascha Wildner 
465db2f26eSSascha Wildner #include "acpi.h"
475db2f26eSSascha Wildner #include "acpi_cpu_pstate.h"
485db2f26eSSascha Wildner 
495db2f26eSSascha Wildner #define AMD_APMI_HWPSTATE		0x80
505db2f26eSSascha Wildner 
515db2f26eSSascha Wildner #define AMD_MSR_PSTATE_CSR_MASK		0x7ULL
525db2f26eSSascha Wildner #define AMD1X_MSR_PSTATE_CTL		0xc0010062
535db2f26eSSascha Wildner #define AMD1X_MSR_PSTATE_ST		0xc0010063
545db2f26eSSascha Wildner 
555db2f26eSSascha Wildner #define AMD_MSR_PSTATE_EN		0x8000000000000000ULL
565db2f26eSSascha Wildner 
57*b4fac0a6SSepherosa Ziehau #define AMD1X_MSR_PSTATE_START		0xc0010064
585db2f26eSSascha Wildner #define AMD10_MSR_PSTATE_COUNT		5
59465a6ec2SSepherosa Ziehau #define AMD11_MSR_PSTATE_COUNT		8	/* starting from 11h */
605db2f26eSSascha Wildner 
615db2f26eSSascha Wildner #define AMD0F_PST_CTL_FID(cval)		(((cval) >> 0)  & 0x3f)
625db2f26eSSascha Wildner #define AMD0F_PST_CTL_VID(cval)		(((cval) >> 6)  & 0x1f)
635db2f26eSSascha Wildner #define AMD0F_PST_CTL_VST(cval)		(((cval) >> 11) & 0x7f)
645db2f26eSSascha Wildner #define AMD0F_PST_CTL_MVS(cval)		(((cval) >> 18) & 0x3)
655db2f26eSSascha Wildner #define AMD0F_PST_CTL_PLLTIME(cval)	(((cval) >> 20) & 0x7f)
665db2f26eSSascha Wildner #define AMD0F_PST_CTL_RVO(cval)		(((cval) >> 28) & 0x3)
675db2f26eSSascha Wildner #define AMD0F_PST_CTL_IRT(cval)		(((cval) >> 30) & 0x3)
685db2f26eSSascha Wildner 
695db2f26eSSascha Wildner #define AMD0F_PST_ST_FID(sval)		(((sval) >> 0) & 0x3f)
705db2f26eSSascha Wildner #define AMD0F_PST_ST_VID(sval)		(((sval) >> 6) & 0x3f)
715db2f26eSSascha Wildner 
725db2f26eSSascha Wildner #define INTEL_MSR_MISC_ENABLE		0x1a0
735db2f26eSSascha Wildner #define INTEL_MSR_MISC_EST_EN		0x10000ULL
745db2f26eSSascha Wildner 
755db2f26eSSascha Wildner #define INTEL_MSR_PERF_STATUS		0x198
765db2f26eSSascha Wildner #define INTEL_MSR_PERF_CTL		0x199
775db2f26eSSascha Wildner #define INTEL_MSR_PERF_MASK		0xffffULL
785db2f26eSSascha Wildner 
795db2f26eSSascha Wildner static const struct acpi_pst_md *
805db2f26eSSascha Wildner 		acpi_pst_amd_probe(void);
815db2f26eSSascha Wildner static int	acpi_pst_amd_check_csr(const struct acpi_pst_res *,
825db2f26eSSascha Wildner 		    const struct acpi_pst_res *);
83*b4fac0a6SSepherosa Ziehau static int	acpi_pst_amd1x_check_pstates1(const struct acpi_pstate *, int,
845db2f26eSSascha Wildner 		    uint32_t, uint32_t);
85*b4fac0a6SSepherosa Ziehau static int	acpi_pst_amd1x_check_pstates(const struct acpi_pstate *, int);
865db2f26eSSascha Wildner static int	acpi_pst_amd0f_check_pstates(const struct acpi_pstate *, int);
875db2f26eSSascha Wildner static int	acpi_pst_amd_init(const struct acpi_pst_res *,
885db2f26eSSascha Wildner 		    const struct acpi_pst_res *);
895db2f26eSSascha Wildner static int	acpi_pst_amd1x_set_pstate(const struct acpi_pst_res *,
905db2f26eSSascha Wildner 		    const struct acpi_pst_res *, const struct acpi_pstate *);
915db2f26eSSascha Wildner static int	acpi_pst_amd0f_set_pstate(const struct acpi_pst_res *,
925db2f26eSSascha Wildner 		    const struct acpi_pst_res *, const struct acpi_pstate *);
935db2f26eSSascha Wildner static const struct acpi_pstate *
945db2f26eSSascha Wildner 		acpi_pst_amd1x_get_pstate(const struct acpi_pst_res *,
955db2f26eSSascha Wildner 		    const struct acpi_pstate *, int);
965db2f26eSSascha Wildner static const struct acpi_pstate *
975db2f26eSSascha Wildner 		acpi_pst_amd0f_get_pstate(const struct acpi_pst_res *,
985db2f26eSSascha Wildner 		    const struct acpi_pstate *, int);
995db2f26eSSascha Wildner 
1005db2f26eSSascha Wildner static const struct acpi_pst_md *
1015db2f26eSSascha Wildner 		acpi_pst_intel_probe(void);
1025db2f26eSSascha Wildner static int	acpi_pst_intel_check_csr(const struct acpi_pst_res *,
1035db2f26eSSascha Wildner 		    const struct acpi_pst_res *);
1045db2f26eSSascha Wildner static int	acpi_pst_intel_check_pstates(const struct acpi_pstate *, int);
1055db2f26eSSascha Wildner static int	acpi_pst_intel_init(const struct acpi_pst_res *,
1065db2f26eSSascha Wildner 		    const struct acpi_pst_res *);
1075db2f26eSSascha Wildner static int	acpi_pst_intel_set_pstate(const struct acpi_pst_res *,
1085db2f26eSSascha Wildner 		    const struct acpi_pst_res *, const struct acpi_pstate *);
1095db2f26eSSascha Wildner static const struct acpi_pstate *
1105db2f26eSSascha Wildner 		acpi_pst_intel_get_pstate(const struct acpi_pst_res *,
1115db2f26eSSascha Wildner 		    const struct acpi_pstate *, int);
1125db2f26eSSascha Wildner 
1135db2f26eSSascha Wildner static int	acpi_pst_md_gas_asz(const ACPI_GENERIC_ADDRESS *);
1145db2f26eSSascha Wildner static int	acpi_pst_md_gas_verify(const ACPI_GENERIC_ADDRESS *);
1155db2f26eSSascha Wildner static uint32_t	acpi_pst_md_res_read(const struct acpi_pst_res *);
1165db2f26eSSascha Wildner static void	acpi_pst_md_res_write(const struct acpi_pst_res *, uint32_t);
1175db2f26eSSascha Wildner 
118*b4fac0a6SSepherosa Ziehau static const struct acpi_pst_md	acpi_pst_amd1x = {
1195db2f26eSSascha Wildner 	.pmd_check_csr		= acpi_pst_amd_check_csr,
120*b4fac0a6SSepherosa Ziehau 	.pmd_check_pstates	= acpi_pst_amd1x_check_pstates,
1215db2f26eSSascha Wildner 	.pmd_init		= acpi_pst_amd_init,
1225db2f26eSSascha Wildner 	.pmd_set_pstate		= acpi_pst_amd1x_set_pstate,
1235db2f26eSSascha Wildner 	.pmd_get_pstate		= acpi_pst_amd1x_get_pstate
1245db2f26eSSascha Wildner };
1255db2f26eSSascha Wildner 
1265db2f26eSSascha Wildner static const struct acpi_pst_md	acpi_pst_amd0f = {
1275db2f26eSSascha Wildner 	.pmd_check_csr		= acpi_pst_amd_check_csr,
1285db2f26eSSascha Wildner 	.pmd_check_pstates	= acpi_pst_amd0f_check_pstates,
1295db2f26eSSascha Wildner 	.pmd_init		= acpi_pst_amd_init,
1305db2f26eSSascha Wildner 	.pmd_set_pstate		= acpi_pst_amd0f_set_pstate,
1315db2f26eSSascha Wildner 	.pmd_get_pstate		= acpi_pst_amd0f_get_pstate
1325db2f26eSSascha Wildner };
1335db2f26eSSascha Wildner 
1345db2f26eSSascha Wildner static const struct acpi_pst_md acpi_pst_intel = {
1355db2f26eSSascha Wildner 	.pmd_check_csr		= acpi_pst_intel_check_csr,
1365db2f26eSSascha Wildner 	.pmd_check_pstates	= acpi_pst_intel_check_pstates,
1375db2f26eSSascha Wildner 	.pmd_init		= acpi_pst_intel_init,
1385db2f26eSSascha Wildner 	.pmd_set_pstate		= acpi_pst_intel_set_pstate,
1395db2f26eSSascha Wildner 	.pmd_get_pstate		= acpi_pst_intel_get_pstate
1405db2f26eSSascha Wildner };
1415db2f26eSSascha Wildner 
1425db2f26eSSascha Wildner static int acpi_pst_stringent_check = 1;
1435db2f26eSSascha Wildner TUNABLE_INT("hw.acpi.cpu.pstate.strigent_check", &acpi_pst_stringent_check);
1445db2f26eSSascha Wildner 
145465a6ec2SSepherosa Ziehau static int acpi_pst_amd1x_msr_pstate_count = AMD10_MSR_PSTATE_COUNT;
146465a6ec2SSepherosa Ziehau 
1475db2f26eSSascha Wildner const struct acpi_pst_md *
acpi_pst_md_probe(void)1485db2f26eSSascha Wildner acpi_pst_md_probe(void)
1495db2f26eSSascha Wildner {
1505db2f26eSSascha Wildner 	if (cpu_vendor_id == CPU_VENDOR_AMD)
1515db2f26eSSascha Wildner 		return acpi_pst_amd_probe();
1525db2f26eSSascha Wildner 	else if (cpu_vendor_id == CPU_VENDOR_INTEL)
1535db2f26eSSascha Wildner 		return acpi_pst_intel_probe();
1545db2f26eSSascha Wildner 	return NULL;
1555db2f26eSSascha Wildner }
1565db2f26eSSascha Wildner 
1575db2f26eSSascha Wildner static const struct acpi_pst_md *
acpi_pst_amd_probe(void)1585db2f26eSSascha Wildner acpi_pst_amd_probe(void)
1595db2f26eSSascha Wildner {
160e876e4b5SSepherosa Ziehau 	uint32_t regs[4];
1615db2f26eSSascha Wildner 
162e876e4b5SSepherosa Ziehau 	/* Only Family >= 0fh has P-State support */
163e876e4b5SSepherosa Ziehau 	if (CPUID_TO_FAMILY(cpu_id) < 0xf)
1645db2f26eSSascha Wildner 		return NULL;
1655db2f26eSSascha Wildner 
1665db2f26eSSascha Wildner 	/* Check whether APMI exists */
167e876e4b5SSepherosa Ziehau 	if (cpu_exthigh < 0x80000007)
1685db2f26eSSascha Wildner 		return NULL;
1695db2f26eSSascha Wildner 
1705db2f26eSSascha Wildner 	/* Fetch APMI */
1715db2f26eSSascha Wildner 	do_cpuid(0x80000007, regs);
1725db2f26eSSascha Wildner 
173e876e4b5SSepherosa Ziehau 	if (CPUID_TO_FAMILY(cpu_id) == 0xf) {		/* Family 0fh */
1745db2f26eSSascha Wildner 		if ((regs[3] & 0x06) == 0x06)
1755db2f26eSSascha Wildner 			return &acpi_pst_amd0f;
176e876e4b5SSepherosa Ziehau 	} else if (CPUID_TO_FAMILY(cpu_id) >= 0x10) {	/* Family >= 10h */
177465a6ec2SSepherosa Ziehau 		if (CPUID_TO_FAMILY(cpu_id) >= 0x11) {
178465a6ec2SSepherosa Ziehau 			acpi_pst_amd1x_msr_pstate_count =
179465a6ec2SSepherosa Ziehau 			    AMD11_MSR_PSTATE_COUNT;
180465a6ec2SSepherosa Ziehau 		}
1815db2f26eSSascha Wildner 		if (regs[3] & 0x80)
182*b4fac0a6SSepherosa Ziehau 			return &acpi_pst_amd1x;
1835db2f26eSSascha Wildner 	}
1845db2f26eSSascha Wildner 	return NULL;
1855db2f26eSSascha Wildner }
1865db2f26eSSascha Wildner 
1875db2f26eSSascha Wildner static int
acpi_pst_amd_check_csr(const struct acpi_pst_res * ctrl,const struct acpi_pst_res * status)1885db2f26eSSascha Wildner acpi_pst_amd_check_csr(const struct acpi_pst_res *ctrl,
1895db2f26eSSascha Wildner 		       const struct acpi_pst_res *status)
1905db2f26eSSascha Wildner {
1915db2f26eSSascha Wildner 	if (ctrl->pr_gas.SpaceId != ACPI_ADR_SPACE_FIXED_HARDWARE) {
1925db2f26eSSascha Wildner 		kprintf("cpu%d: Invalid P-State control register\n", mycpuid);
1935db2f26eSSascha Wildner 		return EINVAL;
1945db2f26eSSascha Wildner 	}
1955db2f26eSSascha Wildner 	if (status->pr_gas.SpaceId != ACPI_ADR_SPACE_FIXED_HARDWARE) {
1965db2f26eSSascha Wildner 		kprintf("cpu%d: Invalid P-State status register\n", mycpuid);
1975db2f26eSSascha Wildner 		return EINVAL;
1985db2f26eSSascha Wildner 	}
1995db2f26eSSascha Wildner 	return 0;
2005db2f26eSSascha Wildner }
2015db2f26eSSascha Wildner 
2025db2f26eSSascha Wildner static int
acpi_pst_amd1x_check_pstates1(const struct acpi_pstate * pstates,int npstates,uint32_t msr_start,uint32_t msr_end)203*b4fac0a6SSepherosa Ziehau acpi_pst_amd1x_check_pstates1(const struct acpi_pstate *pstates, int npstates,
2045db2f26eSSascha Wildner     uint32_t msr_start, uint32_t msr_end)
2055db2f26eSSascha Wildner {
2065db2f26eSSascha Wildner 	int i;
2075db2f26eSSascha Wildner 
2085db2f26eSSascha Wildner 	/*
2095db2f26eSSascha Wildner 	 * Make sure that related MSR P-State registers are enabled.
2105db2f26eSSascha Wildner 	 *
2115db2f26eSSascha Wildner 	 * NOTE:
2125db2f26eSSascha Wildner 	 * We don't check status register value here;
2135db2f26eSSascha Wildner 	 * it will not be used.
2145db2f26eSSascha Wildner 	 */
2155db2f26eSSascha Wildner 	for (i = 0; i < npstates; ++i) {
2165db2f26eSSascha Wildner 		uint64_t pstate;
2175db2f26eSSascha Wildner 		uint32_t msr;
2185db2f26eSSascha Wildner 
2195db2f26eSSascha Wildner 		msr = msr_start +
2205db2f26eSSascha Wildner 		      (pstates[i].st_cval & AMD_MSR_PSTATE_CSR_MASK);
2215db2f26eSSascha Wildner 		if (msr >= msr_end) {
2225db2f26eSSascha Wildner 			kprintf("cpu%d: MSR P-State register %#08x "
2235db2f26eSSascha Wildner 				"does not exist\n", mycpuid, msr);
2245db2f26eSSascha Wildner 			return EINVAL;
2255db2f26eSSascha Wildner 		}
2265db2f26eSSascha Wildner 
2275db2f26eSSascha Wildner 		pstate = rdmsr(msr);
2285db2f26eSSascha Wildner 		if ((pstate & AMD_MSR_PSTATE_EN) == 0) {
2295db2f26eSSascha Wildner 			kprintf("cpu%d: MSR P-State register %#08x "
2305db2f26eSSascha Wildner 				"is not enabled\n", mycpuid, msr);
2315db2f26eSSascha Wildner 			return EINVAL;
2325db2f26eSSascha Wildner 		}
2335db2f26eSSascha Wildner 	}
2345db2f26eSSascha Wildner 	return 0;
2355db2f26eSSascha Wildner }
2365db2f26eSSascha Wildner 
2375db2f26eSSascha Wildner static int
acpi_pst_amd1x_check_pstates(const struct acpi_pstate * pstates,int npstates)238*b4fac0a6SSepherosa Ziehau acpi_pst_amd1x_check_pstates(const struct acpi_pstate *pstates, int npstates)
2395db2f26eSSascha Wildner {
240465a6ec2SSepherosa Ziehau 	if (npstates > acpi_pst_amd1x_msr_pstate_count) {
241465a6ec2SSepherosa Ziehau 		kprintf("cpu%d: only %d P-states are allowed\n", mycpuid,
242465a6ec2SSepherosa Ziehau 		    acpi_pst_amd1x_msr_pstate_count);
2435db2f26eSSascha Wildner 		return EINVAL;
2445db2f26eSSascha Wildner 	}
2455db2f26eSSascha Wildner 
246*b4fac0a6SSepherosa Ziehau 	return acpi_pst_amd1x_check_pstates1(pstates, npstates,
247*b4fac0a6SSepherosa Ziehau 	    AMD1X_MSR_PSTATE_START,
248*b4fac0a6SSepherosa Ziehau 	    AMD1X_MSR_PSTATE_START + acpi_pst_amd1x_msr_pstate_count);
2495db2f26eSSascha Wildner }
2505db2f26eSSascha Wildner 
2515db2f26eSSascha Wildner static int
acpi_pst_amd1x_set_pstate(const struct acpi_pst_res * ctrl __unused,const struct acpi_pst_res * status __unused,const struct acpi_pstate * pstate)2525db2f26eSSascha Wildner acpi_pst_amd1x_set_pstate(const struct acpi_pst_res *ctrl __unused,
2535db2f26eSSascha Wildner 			  const struct acpi_pst_res *status __unused,
2545db2f26eSSascha Wildner 			  const struct acpi_pstate *pstate)
2555db2f26eSSascha Wildner {
2565db2f26eSSascha Wildner 	uint64_t cval;
2575db2f26eSSascha Wildner 
2585db2f26eSSascha Wildner 	cval = pstate->st_cval & AMD_MSR_PSTATE_CSR_MASK;
2595db2f26eSSascha Wildner 	wrmsr(AMD1X_MSR_PSTATE_CTL, cval);
2605db2f26eSSascha Wildner 
2615db2f26eSSascha Wildner 	/*
2625db2f26eSSascha Wildner 	 * Don't check AMD1X_MSR_PSTATE_ST here, since it is
2635db2f26eSSascha Wildner 	 * affected by various P-State limits.
2645db2f26eSSascha Wildner 	 *
2655db2f26eSSascha Wildner 	 * For details:
2665db2f26eSSascha Wildner 	 * AMD Family 10h Processor BKDG Rev 3.20 (#31116)
2675db2f26eSSascha Wildner 	 * 2.4.2.4 P-state Transition Behavior
2685db2f26eSSascha Wildner 	 */
2695db2f26eSSascha Wildner 
2705db2f26eSSascha Wildner 	return 0;
2715db2f26eSSascha Wildner }
2725db2f26eSSascha Wildner 
2735db2f26eSSascha Wildner static const struct acpi_pstate *
acpi_pst_amd1x_get_pstate(const struct acpi_pst_res * status __unused,const struct acpi_pstate * pstates,int npstates)2745db2f26eSSascha Wildner acpi_pst_amd1x_get_pstate(const struct acpi_pst_res *status __unused,
2755db2f26eSSascha Wildner 			  const struct acpi_pstate *pstates, int npstates)
2765db2f26eSSascha Wildner {
2775db2f26eSSascha Wildner 	uint64_t sval;
2785db2f26eSSascha Wildner 	int i;
2795db2f26eSSascha Wildner 
2805db2f26eSSascha Wildner 	sval = rdmsr(AMD1X_MSR_PSTATE_ST) & AMD_MSR_PSTATE_CSR_MASK;
2815db2f26eSSascha Wildner 	for (i = 0; i < npstates; ++i) {
2825db2f26eSSascha Wildner 		if ((pstates[i].st_sval & AMD_MSR_PSTATE_CSR_MASK) == sval)
2835db2f26eSSascha Wildner 			return &pstates[i];
2845db2f26eSSascha Wildner 	}
2855db2f26eSSascha Wildner 	return NULL;
2865db2f26eSSascha Wildner }
2875db2f26eSSascha Wildner 
2885db2f26eSSascha Wildner static int
acpi_pst_amd0f_check_pstates(const struct acpi_pstate * pstates,int npstates)2895db2f26eSSascha Wildner acpi_pst_amd0f_check_pstates(const struct acpi_pstate *pstates, int npstates)
2905db2f26eSSascha Wildner {
2915db2f26eSSascha Wildner 	struct amd0f_fidvid fv_max, fv_min;
2925db2f26eSSascha Wildner 	int i;
2935db2f26eSSascha Wildner 
2945db2f26eSSascha Wildner 	amd0f_fidvid_limit(&fv_min, &fv_max);
2955db2f26eSSascha Wildner 
2965db2f26eSSascha Wildner 	if (fv_min.fid == fv_max.fid && fv_min.vid == fv_max.vid) {
2975db2f26eSSascha Wildner 		kprintf("cpu%d: only one P-State is supported\n", mycpuid);
2985db2f26eSSascha Wildner 		if (acpi_pst_stringent_check)
2995db2f26eSSascha Wildner 			return EOPNOTSUPP;
3005db2f26eSSascha Wildner 	}
3015db2f26eSSascha Wildner 
3025db2f26eSSascha Wildner 	for (i = 0; i < npstates; ++i) {
3035db2f26eSSascha Wildner 		const struct acpi_pstate *p = &pstates[i];
3045db2f26eSSascha Wildner 		uint32_t fid, vid, mvs, rvo;
3055db2f26eSSascha Wildner 		int mvs_mv, rvo_mv;
3065db2f26eSSascha Wildner 
3075db2f26eSSascha Wildner 		fid = AMD0F_PST_CTL_FID(p->st_cval);
3085db2f26eSSascha Wildner 		vid = AMD0F_PST_CTL_VID(p->st_cval);
3095db2f26eSSascha Wildner 
3105db2f26eSSascha Wildner 		if (i == 0) {
3115db2f26eSSascha Wildner 			if (vid != fv_max.vid) {
3125db2f26eSSascha Wildner 				kprintf("cpu%d: max VID mismatch "
3135db2f26eSSascha Wildner 					"real %u, lim %d\n", mycpuid,
3145db2f26eSSascha Wildner 					vid, fv_max.vid);
3155db2f26eSSascha Wildner 			}
3165db2f26eSSascha Wildner 			if (fid != fv_max.fid) {
3175db2f26eSSascha Wildner 				kprintf("cpu%d: max FID mismatch "
3185db2f26eSSascha Wildner 					"real %u, lim %d\n", mycpuid,
3195db2f26eSSascha Wildner 					fid, fv_max.fid);
3205db2f26eSSascha Wildner 			}
3215db2f26eSSascha Wildner 		} else if (i == npstates - 1) {
3225db2f26eSSascha Wildner 			if (vid != fv_min.vid) {
3235db2f26eSSascha Wildner 				kprintf("cpu%d: min VID mismatch "
3245db2f26eSSascha Wildner 					"real %u, lim %d\n", mycpuid,
3255db2f26eSSascha Wildner 					vid, fv_min.vid);
3265db2f26eSSascha Wildner 			}
3275db2f26eSSascha Wildner 			if (fid != fv_min.fid) {
3285db2f26eSSascha Wildner 				kprintf("cpu%d: min FID mismatch "
3295db2f26eSSascha Wildner 					"real %u, lim %d\n", mycpuid,
3305db2f26eSSascha Wildner 					fid, fv_min.fid);
3315db2f26eSSascha Wildner 			}
3325db2f26eSSascha Wildner 		} else {
3335db2f26eSSascha Wildner 			if (fid >= fv_max.fid || fid < (fv_min.fid + 0x8)) {
3345db2f26eSSascha Wildner 				kprintf("cpu%d: Invalid FID %#x, "
3355db2f26eSSascha Wildner 					"out [%#x, %#x]\n", mycpuid, fid,
3365db2f26eSSascha Wildner 					fv_min.fid + 0x8, fv_max.fid);
3375db2f26eSSascha Wildner 				if (acpi_pst_stringent_check)
3385db2f26eSSascha Wildner 					return EINVAL;
3395db2f26eSSascha Wildner 			}
3405db2f26eSSascha Wildner 			if (vid < fv_max.vid || vid > fv_min.vid) {
3415db2f26eSSascha Wildner 				kprintf("cpu%d: Invalid VID %#x, "
3425db2f26eSSascha Wildner 					"in [%#x, %#x]\n", mycpuid, vid,
3435db2f26eSSascha Wildner 					fv_max.vid, fv_min.vid);
3445db2f26eSSascha Wildner 				if (acpi_pst_stringent_check)
3455db2f26eSSascha Wildner 					return EINVAL;
3465db2f26eSSascha Wildner 			}
3475db2f26eSSascha Wildner 		}
3485db2f26eSSascha Wildner 
3495db2f26eSSascha Wildner 		mvs = AMD0F_PST_CTL_MVS(p->st_cval);
3505db2f26eSSascha Wildner 		rvo = AMD0F_PST_CTL_RVO(p->st_cval);
3515db2f26eSSascha Wildner 
3525db2f26eSSascha Wildner 		/* Only 0 is allowed, i.e. 25mV stepping */
3535db2f26eSSascha Wildner 		if (mvs != 0) {
3545db2f26eSSascha Wildner 			kprintf("cpu%d: Invalid MVS %#x\n", mycpuid, mvs);
3555db2f26eSSascha Wildner 			return EINVAL;
3565db2f26eSSascha Wildner 		}
3575db2f26eSSascha Wildner 
3585db2f26eSSascha Wildner 		/* -> mV */
3595db2f26eSSascha Wildner 		mvs_mv = 25 * (1 << mvs);
3605db2f26eSSascha Wildner 		rvo_mv = 25 * rvo;
3615db2f26eSSascha Wildner 		if (rvo_mv % mvs_mv != 0) {
3625db2f26eSSascha Wildner 			kprintf("cpu%d: Invalid MVS/RVO (%#x/%#x)\n",
3635db2f26eSSascha Wildner 				mycpuid, mvs, rvo);
3645db2f26eSSascha Wildner 			return EINVAL;
3655db2f26eSSascha Wildner 		}
3665db2f26eSSascha Wildner 	}
3675db2f26eSSascha Wildner 	return 0;
3685db2f26eSSascha Wildner }
3695db2f26eSSascha Wildner 
3705db2f26eSSascha Wildner static int
acpi_pst_amd0f_set_pstate(const struct acpi_pst_res * ctrl __unused,const struct acpi_pst_res * status __unused,const struct acpi_pstate * pstate)3715db2f26eSSascha Wildner acpi_pst_amd0f_set_pstate(const struct acpi_pst_res *ctrl __unused,
3725db2f26eSSascha Wildner 			  const struct acpi_pst_res *status __unused,
3735db2f26eSSascha Wildner 			  const struct acpi_pstate *pstate)
3745db2f26eSSascha Wildner {
3755db2f26eSSascha Wildner 	struct amd0f_fidvid fv;
3765db2f26eSSascha Wildner 	struct amd0f_xsit xsit;
3775db2f26eSSascha Wildner 
3785db2f26eSSascha Wildner 	fv.fid = AMD0F_PST_CTL_FID(pstate->st_cval);
3795db2f26eSSascha Wildner 	fv.vid = AMD0F_PST_CTL_VID(pstate->st_cval);
3805db2f26eSSascha Wildner 
3815db2f26eSSascha Wildner 	xsit.rvo = AMD0F_PST_CTL_RVO(pstate->st_cval);
3825db2f26eSSascha Wildner 	xsit.mvs = AMD0F_PST_CTL_MVS(pstate->st_cval);
3835db2f26eSSascha Wildner 	xsit.vst = AMD0F_PST_CTL_VST(pstate->st_cval);
3845db2f26eSSascha Wildner 	xsit.pll_time = AMD0F_PST_CTL_PLLTIME(pstate->st_cval);
3855db2f26eSSascha Wildner 	xsit.irt = AMD0F_PST_CTL_IRT(pstate->st_cval);
3865db2f26eSSascha Wildner 
3875db2f26eSSascha Wildner 	return amd0f_set_fidvid(&fv, &xsit);
3885db2f26eSSascha Wildner }
3895db2f26eSSascha Wildner 
3905db2f26eSSascha Wildner static const struct acpi_pstate *
acpi_pst_amd0f_get_pstate(const struct acpi_pst_res * status __unused,const struct acpi_pstate * pstates,int npstates)3915db2f26eSSascha Wildner acpi_pst_amd0f_get_pstate(const struct acpi_pst_res *status __unused,
3925db2f26eSSascha Wildner 			  const struct acpi_pstate *pstates, int npstates)
3935db2f26eSSascha Wildner {
3945db2f26eSSascha Wildner 	struct amd0f_fidvid fv;
3955db2f26eSSascha Wildner 	int error, i;
3965db2f26eSSascha Wildner 
3975db2f26eSSascha Wildner 	error = amd0f_get_fidvid(&fv);
3985db2f26eSSascha Wildner 	if (error)
3995db2f26eSSascha Wildner 		return NULL;
4005db2f26eSSascha Wildner 
4015db2f26eSSascha Wildner 	for (i = 0; i < npstates; ++i) {
4025db2f26eSSascha Wildner 		const struct acpi_pstate *p = &pstates[i];
4035db2f26eSSascha Wildner 
4045db2f26eSSascha Wildner 		if (fv.fid == AMD0F_PST_ST_FID(p->st_sval) &&
4055db2f26eSSascha Wildner 		    fv.vid == AMD0F_PST_ST_VID(p->st_sval))
4065db2f26eSSascha Wildner 			return p;
4075db2f26eSSascha Wildner 	}
4085db2f26eSSascha Wildner 	return NULL;
4095db2f26eSSascha Wildner }
4105db2f26eSSascha Wildner 
4115db2f26eSSascha Wildner static int
acpi_pst_amd_init(const struct acpi_pst_res * ctrl __unused,const struct acpi_pst_res * status __unused)4125db2f26eSSascha Wildner acpi_pst_amd_init(const struct acpi_pst_res *ctrl __unused,
4135db2f26eSSascha Wildner 		  const struct acpi_pst_res *status __unused)
4145db2f26eSSascha Wildner {
4155db2f26eSSascha Wildner 	return 0;
4165db2f26eSSascha Wildner }
4175db2f26eSSascha Wildner 
4185db2f26eSSascha Wildner static const struct acpi_pst_md *
acpi_pst_intel_probe(void)4195db2f26eSSascha Wildner acpi_pst_intel_probe(void)
4205db2f26eSSascha Wildner {
4215db2f26eSSascha Wildner 	if ((cpu_feature2 & CPUID2_EST) == 0)
4225db2f26eSSascha Wildner 		return NULL;
4235db2f26eSSascha Wildner 
4247d338ab4SSepherosa Ziehau 	if (CPUID_TO_FAMILY(cpu_id) >= 0xf || CPUID_TO_FAMILY(cpu_id) == 0x6)
4255db2f26eSSascha Wildner 		return &acpi_pst_intel;
4267d338ab4SSepherosa Ziehau 
4277d338ab4SSepherosa Ziehau 	return NULL;
4285db2f26eSSascha Wildner }
4295db2f26eSSascha Wildner 
4305db2f26eSSascha Wildner static int
acpi_pst_intel_check_csr(const struct acpi_pst_res * ctrl,const struct acpi_pst_res * status)4315db2f26eSSascha Wildner acpi_pst_intel_check_csr(const struct acpi_pst_res *ctrl,
4325db2f26eSSascha Wildner 			 const struct acpi_pst_res *status)
4335db2f26eSSascha Wildner {
4345db2f26eSSascha Wildner 	int error;
4355db2f26eSSascha Wildner 
4365db2f26eSSascha Wildner 	if (ctrl->pr_gas.SpaceId != status->pr_gas.SpaceId) {
4375db2f26eSSascha Wildner 		kprintf("cpu%d: P-State control(%d)/status(%d) registers have "
4385db2f26eSSascha Wildner 			"different SpaceId", mycpuid,
4395db2f26eSSascha Wildner 			ctrl->pr_gas.SpaceId, status->pr_gas.SpaceId);
4405db2f26eSSascha Wildner 		return EINVAL;
4415db2f26eSSascha Wildner 	}
4425db2f26eSSascha Wildner 
4435db2f26eSSascha Wildner 	switch (ctrl->pr_gas.SpaceId) {
4445db2f26eSSascha Wildner 	case ACPI_ADR_SPACE_FIXED_HARDWARE:
4455db2f26eSSascha Wildner 		if (ctrl->pr_res != NULL || status->pr_res != NULL) {
4465db2f26eSSascha Wildner 			/* XXX should panic() */
4475db2f26eSSascha Wildner 			kprintf("cpu%d: Allocated resource for fixed hardware "
4485db2f26eSSascha Wildner 				"registers\n", mycpuid);
4495db2f26eSSascha Wildner 			return EINVAL;
4505db2f26eSSascha Wildner 		}
4515db2f26eSSascha Wildner 		break;
4525db2f26eSSascha Wildner 
4535db2f26eSSascha Wildner 	case ACPI_ADR_SPACE_SYSTEM_IO:
4545db2f26eSSascha Wildner 		if (ctrl->pr_res == NULL) {
4555db2f26eSSascha Wildner 			kprintf("cpu%d: ioport allocation failed for control "
4565db2f26eSSascha Wildner 				"register\n", mycpuid);
4575db2f26eSSascha Wildner 			return ENXIO;
4585db2f26eSSascha Wildner 		}
4595db2f26eSSascha Wildner 		error = acpi_pst_md_gas_verify(&ctrl->pr_gas);
4605db2f26eSSascha Wildner 		if (error) {
4615db2f26eSSascha Wildner 			kprintf("cpu%d: Invalid control register GAS\n",
4625db2f26eSSascha Wildner 				mycpuid);
4635db2f26eSSascha Wildner 			return error;
4645db2f26eSSascha Wildner 		}
4655db2f26eSSascha Wildner 
4665db2f26eSSascha Wildner 		if (status->pr_res == NULL) {
4675db2f26eSSascha Wildner 			kprintf("cpu%d: ioport allocation failed for status "
4685db2f26eSSascha Wildner 				"register\n", mycpuid);
4695db2f26eSSascha Wildner 			return ENXIO;
4705db2f26eSSascha Wildner 		}
4715db2f26eSSascha Wildner 		error = acpi_pst_md_gas_verify(&status->pr_gas);
4725db2f26eSSascha Wildner 		if (error) {
4735db2f26eSSascha Wildner 			kprintf("cpu%d: Invalid status register GAS\n",
4745db2f26eSSascha Wildner 				mycpuid);
4755db2f26eSSascha Wildner 			return error;
4765db2f26eSSascha Wildner 		}
4775db2f26eSSascha Wildner 		break;
4785db2f26eSSascha Wildner 
4795db2f26eSSascha Wildner 	default:
4805db2f26eSSascha Wildner 		kprintf("cpu%d: Invalid P-State control/status register "
4815db2f26eSSascha Wildner 			"SpaceId %d\n", mycpuid, ctrl->pr_gas.SpaceId);
4825db2f26eSSascha Wildner 		return EOPNOTSUPP;
4835db2f26eSSascha Wildner 	}
4845db2f26eSSascha Wildner 	return 0;
4855db2f26eSSascha Wildner }
4865db2f26eSSascha Wildner 
4875db2f26eSSascha Wildner static int
acpi_pst_intel_check_pstates(const struct acpi_pstate * pstates __unused,int npstates __unused)4885db2f26eSSascha Wildner acpi_pst_intel_check_pstates(const struct acpi_pstate *pstates __unused,
4895db2f26eSSascha Wildner 			     int npstates __unused)
4905db2f26eSSascha Wildner {
4915db2f26eSSascha Wildner 	return 0;
4925db2f26eSSascha Wildner }
4935db2f26eSSascha Wildner 
4945db2f26eSSascha Wildner static int
acpi_pst_intel_init(const struct acpi_pst_res * ctrl __unused,const struct acpi_pst_res * status __unused)4955db2f26eSSascha Wildner acpi_pst_intel_init(const struct acpi_pst_res *ctrl __unused,
4965db2f26eSSascha Wildner 		    const struct acpi_pst_res *status __unused)
4975db2f26eSSascha Wildner {
4985db2f26eSSascha Wildner 	uint64_t misc_enable;
4995db2f26eSSascha Wildner 
5007d338ab4SSepherosa Ziehau 	if (CPUID_TO_FAMILY(cpu_id) == 0xf ||
5017d338ab4SSepherosa Ziehau 	    (CPUID_TO_FAMILY(cpu_id) == 0x6 && CPUID_TO_MODEL(cpu_id) < 0xd)) {
5025db2f26eSSascha Wildner 		/* EST enable bit is reserved in INTEL_MSR_MISC_ENABLE */
5035db2f26eSSascha Wildner 		return 0;
5045db2f26eSSascha Wildner 	}
5055db2f26eSSascha Wildner 
5065db2f26eSSascha Wildner 	misc_enable = rdmsr(INTEL_MSR_MISC_ENABLE);
5075db2f26eSSascha Wildner 	if ((misc_enable & INTEL_MSR_MISC_EST_EN) == 0) {
5085db2f26eSSascha Wildner 		misc_enable |= INTEL_MSR_MISC_EST_EN;
5095db2f26eSSascha Wildner 		wrmsr(INTEL_MSR_MISC_ENABLE, misc_enable);
5105db2f26eSSascha Wildner 
5115db2f26eSSascha Wildner 		misc_enable = rdmsr(INTEL_MSR_MISC_ENABLE);
5125db2f26eSSascha Wildner 		if ((misc_enable & INTEL_MSR_MISC_EST_EN) == 0) {
5135db2f26eSSascha Wildner 			kprintf("cpu%d: Can't enable EST\n", mycpuid);
5145db2f26eSSascha Wildner 			return EIO;
5155db2f26eSSascha Wildner 		}
5165db2f26eSSascha Wildner 	}
5175db2f26eSSascha Wildner 	return 0;
5185db2f26eSSascha Wildner }
5195db2f26eSSascha Wildner 
5205db2f26eSSascha Wildner static int
acpi_pst_intel_set_pstate(const struct acpi_pst_res * ctrl,const struct acpi_pst_res * status __unused,const struct acpi_pstate * pstate)5215db2f26eSSascha Wildner acpi_pst_intel_set_pstate(const struct acpi_pst_res *ctrl,
5225db2f26eSSascha Wildner 			  const struct acpi_pst_res *status __unused,
5235db2f26eSSascha Wildner 			  const struct acpi_pstate *pstate)
5245db2f26eSSascha Wildner {
5255db2f26eSSascha Wildner 	if (ctrl->pr_res != NULL) {
5265db2f26eSSascha Wildner 		acpi_pst_md_res_write(ctrl, pstate->st_cval);
5275db2f26eSSascha Wildner 	} else {
5285db2f26eSSascha Wildner 		uint64_t ctl;
5295db2f26eSSascha Wildner 
5305db2f26eSSascha Wildner 		ctl = rdmsr(INTEL_MSR_PERF_CTL);
5315db2f26eSSascha Wildner 		ctl &= ~INTEL_MSR_PERF_MASK;
5325db2f26eSSascha Wildner 		ctl |= (pstate->st_cval & INTEL_MSR_PERF_MASK);
5335db2f26eSSascha Wildner 		wrmsr(INTEL_MSR_PERF_CTL, ctl);
5345db2f26eSSascha Wildner 	}
5355db2f26eSSascha Wildner 	return 0;
5365db2f26eSSascha Wildner }
5375db2f26eSSascha Wildner 
5385db2f26eSSascha Wildner static const struct acpi_pstate *
acpi_pst_intel_get_pstate(const struct acpi_pst_res * status,const struct acpi_pstate * pstates,int npstates)5395db2f26eSSascha Wildner acpi_pst_intel_get_pstate(const struct acpi_pst_res *status,
5405db2f26eSSascha Wildner 			  const struct acpi_pstate *pstates, int npstates)
5415db2f26eSSascha Wildner {
5425db2f26eSSascha Wildner 	int i;
5435db2f26eSSascha Wildner 
5445db2f26eSSascha Wildner 	if (status->pr_res != NULL) {
5455db2f26eSSascha Wildner 		uint32_t st;
5465db2f26eSSascha Wildner 
5475db2f26eSSascha Wildner 		st = acpi_pst_md_res_read(status);
5485db2f26eSSascha Wildner 		for (i = 0; i < npstates; ++i) {
5495db2f26eSSascha Wildner 			if (pstates[i].st_sval == st)
5505db2f26eSSascha Wildner 				return &pstates[i];
5515db2f26eSSascha Wildner 		}
5525db2f26eSSascha Wildner 	} else {
5535db2f26eSSascha Wildner 		uint64_t sval;
5545db2f26eSSascha Wildner 
5555db2f26eSSascha Wildner 		sval = rdmsr(INTEL_MSR_PERF_STATUS) & INTEL_MSR_PERF_MASK;
5565db2f26eSSascha Wildner 		for (i = 0; i < npstates; ++i) {
5575db2f26eSSascha Wildner 			if ((pstates[i].st_sval & INTEL_MSR_PERF_MASK) == sval)
5585db2f26eSSascha Wildner 				return &pstates[i];
5595db2f26eSSascha Wildner 		}
5605db2f26eSSascha Wildner 	}
5615db2f26eSSascha Wildner 	return NULL;
5625db2f26eSSascha Wildner }
5635db2f26eSSascha Wildner 
5645db2f26eSSascha Wildner static int
acpi_pst_md_gas_asz(const ACPI_GENERIC_ADDRESS * gas)5655db2f26eSSascha Wildner acpi_pst_md_gas_asz(const ACPI_GENERIC_ADDRESS *gas)
5665db2f26eSSascha Wildner {
5675db2f26eSSascha Wildner 	int asz;
5685db2f26eSSascha Wildner 
5695db2f26eSSascha Wildner 	if (gas->AccessWidth != 0)
5705db2f26eSSascha Wildner 		asz = gas->AccessWidth;
5715db2f26eSSascha Wildner 	else
5725db2f26eSSascha Wildner 		asz = gas->BitWidth / NBBY;
5735db2f26eSSascha Wildner 	switch (asz) {
5745db2f26eSSascha Wildner 	case 1:
5755db2f26eSSascha Wildner 	case 2:
5765db2f26eSSascha Wildner 	case 4:
5775db2f26eSSascha Wildner 		break;
5785db2f26eSSascha Wildner 	default:
5795db2f26eSSascha Wildner 		asz = 0;
5805db2f26eSSascha Wildner 		break;
5815db2f26eSSascha Wildner 	}
5825db2f26eSSascha Wildner 	return asz;
5835db2f26eSSascha Wildner }
5845db2f26eSSascha Wildner 
5855db2f26eSSascha Wildner static int
acpi_pst_md_gas_verify(const ACPI_GENERIC_ADDRESS * gas)5865db2f26eSSascha Wildner acpi_pst_md_gas_verify(const ACPI_GENERIC_ADDRESS *gas)
5875db2f26eSSascha Wildner {
5885db2f26eSSascha Wildner 	int reg, end, asz;
5895db2f26eSSascha Wildner 
5905db2f26eSSascha Wildner 	if (gas->BitOffset % NBBY != 0)
5915db2f26eSSascha Wildner 		return EINVAL;
5925db2f26eSSascha Wildner 
5935db2f26eSSascha Wildner 	end = gas->BitWidth / NBBY;
5945db2f26eSSascha Wildner 	reg = gas->BitOffset / NBBY;
5955db2f26eSSascha Wildner 
5965db2f26eSSascha Wildner 	if (reg >= end)
5975db2f26eSSascha Wildner 		return EINVAL;
5985db2f26eSSascha Wildner 
5995db2f26eSSascha Wildner 	asz = acpi_pst_md_gas_asz(gas);
6005db2f26eSSascha Wildner 	if (asz == 0)
6015db2f26eSSascha Wildner 		return EINVAL;
6025db2f26eSSascha Wildner 
6035db2f26eSSascha Wildner 	if (reg + asz > end)
6045db2f26eSSascha Wildner 		return EINVAL;
6055db2f26eSSascha Wildner 	return 0;
6065db2f26eSSascha Wildner }
6075db2f26eSSascha Wildner 
6085db2f26eSSascha Wildner static uint32_t
acpi_pst_md_res_read(const struct acpi_pst_res * res)6095db2f26eSSascha Wildner acpi_pst_md_res_read(const struct acpi_pst_res *res)
6105db2f26eSSascha Wildner {
6115db2f26eSSascha Wildner 	int asz, reg;
6125db2f26eSSascha Wildner 
6135db2f26eSSascha Wildner 	KKASSERT(res->pr_res != NULL);
6145db2f26eSSascha Wildner 	asz = acpi_pst_md_gas_asz(&res->pr_gas);
6155db2f26eSSascha Wildner 	reg = res->pr_gas.BitOffset / NBBY;
6165db2f26eSSascha Wildner 
6175db2f26eSSascha Wildner 	switch (asz) {
6185db2f26eSSascha Wildner 	case 1:
6195db2f26eSSascha Wildner 		return bus_space_read_1(res->pr_bt, res->pr_bh, reg);
6205db2f26eSSascha Wildner 	case 2:
6215db2f26eSSascha Wildner 		return bus_space_read_2(res->pr_bt, res->pr_bh, reg);
6225db2f26eSSascha Wildner 	case 4:
6235db2f26eSSascha Wildner 		return bus_space_read_4(res->pr_bt, res->pr_bh, reg);
6245db2f26eSSascha Wildner 	}
6255db2f26eSSascha Wildner 	panic("unsupported access width %d", asz);
6265db2f26eSSascha Wildner 
6275db2f26eSSascha Wildner 	/* NEVER REACHED */
6285db2f26eSSascha Wildner 	return 0;
6295db2f26eSSascha Wildner }
6305db2f26eSSascha Wildner 
6315db2f26eSSascha Wildner static void
acpi_pst_md_res_write(const struct acpi_pst_res * res,uint32_t val)6325db2f26eSSascha Wildner acpi_pst_md_res_write(const struct acpi_pst_res *res, uint32_t val)
6335db2f26eSSascha Wildner {
6345db2f26eSSascha Wildner 	int asz, reg;
6355db2f26eSSascha Wildner 
6365db2f26eSSascha Wildner 	KKASSERT(res->pr_res != NULL);
6375db2f26eSSascha Wildner 	asz = acpi_pst_md_gas_asz(&res->pr_gas);
6385db2f26eSSascha Wildner 	reg = res->pr_gas.BitOffset / NBBY;
6395db2f26eSSascha Wildner 
6405db2f26eSSascha Wildner 	switch (asz) {
6415db2f26eSSascha Wildner 	case 1:
6425db2f26eSSascha Wildner 		bus_space_write_1(res->pr_bt, res->pr_bh, reg, val);
6435db2f26eSSascha Wildner 		break;
6445db2f26eSSascha Wildner 	case 2:
6455db2f26eSSascha Wildner 		bus_space_write_2(res->pr_bt, res->pr_bh, reg, val);
6465db2f26eSSascha Wildner 		break;
6475db2f26eSSascha Wildner 	case 4:
6485db2f26eSSascha Wildner 		bus_space_write_4(res->pr_bt, res->pr_bh, reg, val);
6495db2f26eSSascha Wildner 		break;
6505db2f26eSSascha Wildner 	default:
6515db2f26eSSascha Wildner 		panic("unsupported access width %d", asz);
6525db2f26eSSascha Wildner 	}
6535db2f26eSSascha Wildner }
654