xref: /netbsd-src/sys/dev/acpi/acpi_cpu.c (revision 30d28f20005de11b20499fed000071fb0a455337)
1*30d28f20Sjmcneill /* $NetBSD: acpi_cpu.c,v 1.53 2020/12/07 10:57:41 jmcneill Exp $ */
24d861e5bSjruoho 
34d861e5bSjruoho /*-
4eb43e911Sjruoho  * Copyright (c) 2010, 2011 Jukka Ruohonen <jruohonen@iki.fi>
54d861e5bSjruoho  * All rights reserved.
64d861e5bSjruoho  *
74d861e5bSjruoho  * Redistribution and use in source and binary forms, with or without
84d861e5bSjruoho  * modification, are permitted provided that the following conditions
94d861e5bSjruoho  * are met:
104d861e5bSjruoho  *
114d861e5bSjruoho  * 1. Redistributions of source code must retain the above copyright
124d861e5bSjruoho  *    notice, this list of conditions and the following disclaimer.
134d861e5bSjruoho  * 2. Redistributions in binary form must reproduce the above copyright
144d861e5bSjruoho  *    notice, this list of conditions and the following disclaimer in the
154d861e5bSjruoho  *    documentation and/or other materials provided with the distribution.
164d861e5bSjruoho  *
174d861e5bSjruoho  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
184d861e5bSjruoho  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
194d861e5bSjruoho  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
204d861e5bSjruoho  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
214d861e5bSjruoho  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
224d861e5bSjruoho  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
234d861e5bSjruoho  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
244d861e5bSjruoho  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
254d861e5bSjruoho  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
264d861e5bSjruoho  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
274d861e5bSjruoho  * SUCH DAMAGE.
284d861e5bSjruoho  */
294d861e5bSjruoho #include <sys/cdefs.h>
30*30d28f20Sjmcneill __KERNEL_RCSID(0, "$NetBSD: acpi_cpu.c,v 1.53 2020/12/07 10:57:41 jmcneill Exp $");
314d861e5bSjruoho 
324d861e5bSjruoho #include <sys/param.h>
334d861e5bSjruoho #include <sys/cpu.h>
34e98440f2Sjruoho #include <sys/evcnt.h>
354d861e5bSjruoho #include <sys/kernel.h>
364d861e5bSjruoho #include <sys/kmem.h>
374d861e5bSjruoho #include <sys/module.h>
3887a3551cSjruoho #include <sys/mutex.h>
39a5a73b2aSjruoho #include <sys/sysctl.h>
40804fdee3Sjruoho #include <sys/cpufreq.h>
414d861e5bSjruoho 
424d861e5bSjruoho #include <dev/acpi/acpireg.h>
434d861e5bSjruoho #include <dev/acpi/acpivar.h>
444d861e5bSjruoho #include <dev/acpi/acpi_cpu.h>
454d861e5bSjruoho 
464d861e5bSjruoho #include <machine/acpi_machdep.h>
47*30d28f20Sjmcneill 
48*30d28f20Sjmcneill #if defined(__i386__) || defined(__x86_64__)
49494badebSjruoho #include <machine/cpuvar.h>
50*30d28f20Sjmcneill #endif
514d861e5bSjruoho 
524d861e5bSjruoho #define _COMPONENT	  ACPI_BUS_COMPONENT
534d861e5bSjruoho ACPI_MODULE_NAME	  ("acpi_cpu")
544d861e5bSjruoho 
554d861e5bSjruoho static int		  acpicpu_match(device_t, cfdata_t, void *);
564d861e5bSjruoho static void		  acpicpu_attach(device_t, device_t, void *);
574d861e5bSjruoho static int		  acpicpu_detach(device_t, int);
584d861e5bSjruoho static int		  acpicpu_once_attach(void);
594d861e5bSjruoho static int		  acpicpu_once_detach(void);
602510a0e2Sjruoho static void		  acpicpu_start(device_t);
614d861e5bSjruoho 
62494badebSjruoho static ACPI_STATUS	  acpicpu_object(ACPI_HANDLE, struct acpicpu_object *);
634d861e5bSjruoho static uint32_t		  acpicpu_cap(struct acpicpu_softc *);
649d3272e7Sjruoho static ACPI_STATUS	  acpicpu_cap_osc(struct acpicpu_softc *,
659d3272e7Sjruoho 					  uint32_t, uint32_t *);
664d861e5bSjruoho static void		  acpicpu_notify(ACPI_HANDLE, uint32_t, void *);
674d861e5bSjruoho static bool		  acpicpu_suspend(device_t, const pmf_qual_t *);
684d861e5bSjruoho static bool		  acpicpu_resume(device_t, const pmf_qual_t *);
69e98440f2Sjruoho static void		  acpicpu_evcnt_attach(device_t);
70e98440f2Sjruoho static void		  acpicpu_evcnt_detach(device_t);
71e98440f2Sjruoho static void		  acpicpu_debug_print(device_t);
72804fdee3Sjruoho static const char	 *acpicpu_debug_print_method_c(uint8_t);
73804fdee3Sjruoho static const char	 *acpicpu_debug_print_method_pt(uint8_t);
74e98440f2Sjruoho static const char	 *acpicpu_debug_print_dep(uint32_t);
754d861e5bSjruoho 
76494badebSjruoho static uint32_t		  acpicpu_count = 0;
774d861e5bSjruoho struct acpicpu_softc	**acpicpu_sc = NULL;
78a5a73b2aSjruoho static bool		  acpicpu_dynamic = true;
79a5a73b2aSjruoho static bool		  acpicpu_passive = true;
804d861e5bSjruoho 
8180dcd7f7Sjruoho static const struct {
8280dcd7f7Sjruoho 	const char	 *manu;
8380dcd7f7Sjruoho 	const char	 *prod;
8480dcd7f7Sjruoho 	const char	 *vers;
8580dcd7f7Sjruoho } acpicpu_quirks[] = {
8680dcd7f7Sjruoho 	{ "Supermicro", "PDSMi-LN4", "0123456789" },
8778d78ed5Sjruoho 	{ "ASUSTeK Computer INC.", "M2A-MX", "Rev 1.xx" },
8880dcd7f7Sjruoho };
8980dcd7f7Sjruoho 
904d861e5bSjruoho CFATTACH_DECL_NEW(acpicpu, sizeof(struct acpicpu_softc),
914d861e5bSjruoho     acpicpu_match, acpicpu_attach, acpicpu_detach, NULL);
924d861e5bSjruoho 
934d861e5bSjruoho static int
acpicpu_match(device_t parent,cfdata_t match,void * aux)944d861e5bSjruoho acpicpu_match(device_t parent, cfdata_t match, void *aux)
954d861e5bSjruoho {
9680dcd7f7Sjruoho 	const char *manu, *prod, *vers;
97cd966b24Sjruoho 	struct cpu_info *ci;
9880dcd7f7Sjruoho 	size_t i;
994d861e5bSjruoho 
100494badebSjruoho 	if (acpi_softc == NULL)
1014d861e5bSjruoho 		return 0;
1024d861e5bSjruoho 
10378d78ed5Sjruoho 	manu = pmf_get_platform("board-vendor");
10478d78ed5Sjruoho 	prod = pmf_get_platform("board-product");
10578d78ed5Sjruoho 	vers = pmf_get_platform("board-version");
10680dcd7f7Sjruoho 
10780dcd7f7Sjruoho 	if (manu != NULL && prod != NULL && vers != NULL) {
10880dcd7f7Sjruoho 
10980dcd7f7Sjruoho 		for (i = 0; i < __arraycount(acpicpu_quirks); i++) {
11080dcd7f7Sjruoho 
11180dcd7f7Sjruoho 			if (strcasecmp(acpicpu_quirks[i].manu, manu) == 0 &&
11280dcd7f7Sjruoho 			    strcasecmp(acpicpu_quirks[i].prod, prod) == 0 &&
11380dcd7f7Sjruoho 			    strcasecmp(acpicpu_quirks[i].vers, vers) == 0)
11480dcd7f7Sjruoho 				return 0;
11580dcd7f7Sjruoho 		}
11680dcd7f7Sjruoho 	}
11780dcd7f7Sjruoho 
118cd966b24Sjruoho 	ci = acpicpu_md_match(parent, match, aux);
119cd966b24Sjruoho 
120cd966b24Sjruoho 	if (ci == NULL)
121515e411dSchristos 		return 0;
12244091f01Sjruoho 
123d7b285b0Sjruoho 	if (acpi_match_cpu_info(ci) == NULL)
124d7b285b0Sjruoho 		return 0;
125d7b285b0Sjruoho 
126d7b285b0Sjruoho 	return 10;
1274d861e5bSjruoho }
1284d861e5bSjruoho 
1294d861e5bSjruoho static void
acpicpu_attach(device_t parent,device_t self,void * aux)1304d861e5bSjruoho acpicpu_attach(device_t parent, device_t self, void *aux)
1314d861e5bSjruoho {
1324d861e5bSjruoho 	struct acpicpu_softc *sc = device_private(self);
133cd966b24Sjruoho 	struct cpu_info *ci;
134d7b285b0Sjruoho 	ACPI_HANDLE hdl;
13586bc152dSjruoho 	cpuid_t id;
1364d861e5bSjruoho 	int rv;
1374d861e5bSjruoho 
138cd966b24Sjruoho 	ci = acpicpu_md_attach(parent, self, aux);
139cd966b24Sjruoho 
140cd966b24Sjruoho 	if (ci == NULL)
141cd966b24Sjruoho 		return;
142cd966b24Sjruoho 
143494badebSjruoho 	sc->sc_ci = ci;
1444d861e5bSjruoho 	sc->sc_dev = self;
1452510a0e2Sjruoho 	sc->sc_cold = true;
1464d861e5bSjruoho 
147d7b285b0Sjruoho 	hdl = acpi_match_cpu_info(ci);
14886bc152dSjruoho 
149d7b285b0Sjruoho 	if (hdl == NULL) {
150494badebSjruoho 		aprint_normal(": failed to match processor\n");
1514d861e5bSjruoho 		return;
1524d861e5bSjruoho 	}
1534d861e5bSjruoho 
154a9db528eSjruoho 	sc->sc_node = acpi_match_node(hdl);
155d7b285b0Sjruoho 
156494badebSjruoho 	if (acpicpu_once_attach() != 0) {
157494badebSjruoho 		aprint_normal(": failed to initialize\n");
158494badebSjruoho 		return;
159494badebSjruoho 	}
160494badebSjruoho 
161494badebSjruoho 	KASSERT(acpi_softc != NULL);
162494badebSjruoho 	KASSERT(acpicpu_sc != NULL);
163494badebSjruoho 	KASSERT(sc->sc_node != NULL);
164494badebSjruoho 
16586bc152dSjruoho 	id = sc->sc_ci->ci_acpiid;
16686bc152dSjruoho 
16786bc152dSjruoho 	if (acpicpu_sc[id] != NULL) {
168494badebSjruoho 		aprint_normal(": already attached\n");
1694d861e5bSjruoho 		return;
1704d861e5bSjruoho 	}
1714d861e5bSjruoho 
1729d3272e7Sjruoho 	aprint_naive("\n");
1739d3272e7Sjruoho 	aprint_normal(": ACPI CPU\n");
1749d3272e7Sjruoho 
175494badebSjruoho 	rv = acpicpu_object(sc->sc_node->ad_handle, &sc->sc_object);
176494badebSjruoho 
177*30d28f20Sjmcneill 	if (ACPI_FAILURE(rv) && rv != AE_TYPE)
178494badebSjruoho 		aprint_verbose_dev(self, "failed to obtain CPU object\n");
179494badebSjruoho 
180494badebSjruoho 	acpicpu_count++;
18186bc152dSjruoho 	acpicpu_sc[id] = sc;
1824d861e5bSjruoho 
1834d861e5bSjruoho 	sc->sc_cap = acpicpu_cap(sc);
184a080ec14Sjruoho 	sc->sc_ncpus = acpi_md_ncpus();
185494badebSjruoho 	sc->sc_flags = acpicpu_md_flags();
1864d861e5bSjruoho 
187494badebSjruoho 	KASSERT(acpicpu_count <= sc->sc_ncpus);
188494badebSjruoho 	KASSERT(sc->sc_node->ad_device == NULL);
189494badebSjruoho 
190494badebSjruoho 	sc->sc_node->ad_device = self;
19187a3551cSjruoho 	mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_NONE);
19287a3551cSjruoho 
193*30d28f20Sjmcneill #if defined(__i386__) || defined(__x86_64__)
1944d861e5bSjruoho 	acpicpu_cstate_attach(self);
195*30d28f20Sjmcneill #endif
19653e8f6c9Sjruoho 	acpicpu_pstate_attach(self);
1976b9ff107Sjruoho 	acpicpu_tstate_attach(self);
19853e8f6c9Sjruoho 
199494badebSjruoho 	acpicpu_debug_print(self);
200e98440f2Sjruoho 	acpicpu_evcnt_attach(self);
201494badebSjruoho 
202494badebSjruoho 	(void)config_interrupts(self, acpicpu_start);
2034d861e5bSjruoho 	(void)acpi_register_notify(sc->sc_node, acpicpu_notify);
2044d861e5bSjruoho 	(void)pmf_device_register(self, acpicpu_suspend, acpicpu_resume);
2054d861e5bSjruoho }
2064d861e5bSjruoho 
2074d861e5bSjruoho static int
acpicpu_detach(device_t self,int flags)2084d861e5bSjruoho acpicpu_detach(device_t self, int flags)
2094d861e5bSjruoho {
2104d861e5bSjruoho 	struct acpicpu_softc *sc = device_private(self);
2114d861e5bSjruoho 
2127a639613Sjruoho 	sc->sc_cold = true;
2135b407ea2Sjruoho 
2145b407ea2Sjruoho 	acpicpu_evcnt_detach(self);
2154d861e5bSjruoho 	acpi_deregister_notify(sc->sc_node);
2164d861e5bSjruoho 
2174fb79b4eSjruoho 	acpicpu_cstate_detach(self);
2184fb79b4eSjruoho 	acpicpu_pstate_detach(self);
2194fb79b4eSjruoho 	acpicpu_tstate_detach(self);
2206b9ff107Sjruoho 
22187a3551cSjruoho 	mutex_destroy(&sc->sc_mtx);
222494badebSjruoho 	sc->sc_node->ad_device = NULL;
223494badebSjruoho 
224494badebSjruoho 	acpicpu_count--;
225494badebSjruoho 	acpicpu_once_detach();
22687a3551cSjruoho 
2274d861e5bSjruoho 	return 0;
2284d861e5bSjruoho }
2294d861e5bSjruoho 
2304d861e5bSjruoho static int
acpicpu_once_attach(void)2314d861e5bSjruoho acpicpu_once_attach(void)
2324d861e5bSjruoho {
2334d861e5bSjruoho 	struct acpicpu_softc *sc;
2344d861e5bSjruoho 	unsigned int i;
2354d861e5bSjruoho 
236494badebSjruoho 	if (acpicpu_count != 0)
237494badebSjruoho 		return 0;
238494badebSjruoho 
239494badebSjruoho 	KASSERT(acpicpu_sc == NULL);
240494badebSjruoho 
2414d861e5bSjruoho 	acpicpu_sc = kmem_zalloc(maxcpus * sizeof(*sc), KM_SLEEP);
2424d861e5bSjruoho 
2434d861e5bSjruoho 	for (i = 0; i < maxcpus; i++)
2444d861e5bSjruoho 		acpicpu_sc[i] = NULL;
2454d861e5bSjruoho 
2464d861e5bSjruoho 	return 0;
2474d861e5bSjruoho }
2484d861e5bSjruoho 
2494d861e5bSjruoho static int
acpicpu_once_detach(void)2504d861e5bSjruoho acpicpu_once_detach(void)
2514d861e5bSjruoho {
2524d861e5bSjruoho 	struct acpicpu_softc *sc;
2534d861e5bSjruoho 
254494badebSjruoho 	if (acpicpu_count != 0)
255494badebSjruoho 		return EDEADLK;
2564d861e5bSjruoho 
25777e84d0eSjruoho 	cpufreq_deregister();
25877e84d0eSjruoho 
25977e84d0eSjruoho 	if (acpicpu_sc != NULL)
260494badebSjruoho 		kmem_free(acpicpu_sc, maxcpus * sizeof(*sc));
261494badebSjruoho 
2624d861e5bSjruoho 	return 0;
2634d861e5bSjruoho }
2644d861e5bSjruoho 
2652510a0e2Sjruoho static void
acpicpu_start(device_t self)2665ecdb7f3Sjruoho acpicpu_start(device_t self)
2675ecdb7f3Sjruoho {
2685ecdb7f3Sjruoho 	struct acpicpu_softc *sc = device_private(self);
269494badebSjruoho 	static uint32_t count = 0;
270804fdee3Sjruoho 	struct cpufreq cf;
271804fdee3Sjruoho 	uint32_t i;
2725ecdb7f3Sjruoho 
2732510a0e2Sjruoho 	/*
274494badebSjruoho 	 * Run the state-specific initialization routines. These
275494badebSjruoho 	 * must run only once, after interrupts have been enabled,
276494badebSjruoho 	 * all CPUs are running, and all ACPI CPUs have attached.
277494badebSjruoho 	 */
278494badebSjruoho 	if (++count != acpicpu_count || acpicpu_count != sc->sc_ncpus) {
279494badebSjruoho 		sc->sc_cold = false;
280494badebSjruoho 		return;
281494badebSjruoho 	}
282494badebSjruoho 
283494badebSjruoho 	/*
284494badebSjruoho 	 * Set the last ACPI CPU as non-cold
285494badebSjruoho 	 * only after C-states are enabled.
2862510a0e2Sjruoho 	 */
2872510a0e2Sjruoho 	if ((sc->sc_flags & ACPICPU_FLAG_C) != 0)
2882510a0e2Sjruoho 		acpicpu_cstate_start(self);
2892510a0e2Sjruoho 
290494badebSjruoho 	sc->sc_cold = false;
291494badebSjruoho 
2922510a0e2Sjruoho 	if ((sc->sc_flags & ACPICPU_FLAG_P) != 0)
2932510a0e2Sjruoho 		acpicpu_pstate_start(self);
2942510a0e2Sjruoho 
2952510a0e2Sjruoho 	if ((sc->sc_flags & ACPICPU_FLAG_T) != 0)
2962510a0e2Sjruoho 		acpicpu_tstate_start(self);
2972510a0e2Sjruoho 
298494badebSjruoho 	aprint_debug_dev(self, "ACPI CPUs started\n");
299804fdee3Sjruoho 
300804fdee3Sjruoho 	/*
301804fdee3Sjruoho 	 * Register with cpufreq(9).
302804fdee3Sjruoho 	 */
303804fdee3Sjruoho 	if ((sc->sc_flags & ACPICPU_FLAG_P) != 0) {
304804fdee3Sjruoho 
305804fdee3Sjruoho 		(void)memset(&cf, 0, sizeof(struct cpufreq));
306804fdee3Sjruoho 
307804fdee3Sjruoho 		cf.cf_mp = false;
308804fdee3Sjruoho 		cf.cf_cookie = NULL;
309804fdee3Sjruoho 		cf.cf_get_freq = acpicpu_pstate_get;
310804fdee3Sjruoho 		cf.cf_set_freq = acpicpu_pstate_set;
311804fdee3Sjruoho 		cf.cf_state_count = sc->sc_pstate_count;
312804fdee3Sjruoho 
313804fdee3Sjruoho 		(void)strlcpy(cf.cf_name, "acpicpu", sizeof(cf.cf_name));
314804fdee3Sjruoho 
315804fdee3Sjruoho 		for (i = 0; i < sc->sc_pstate_count; i++) {
316804fdee3Sjruoho 
317804fdee3Sjruoho 			if (sc->sc_pstate[i].ps_freq == 0)
318804fdee3Sjruoho 				continue;
319804fdee3Sjruoho 
320804fdee3Sjruoho 			cf.cf_state[i].cfs_freq = sc->sc_pstate[i].ps_freq;
321804fdee3Sjruoho 			cf.cf_state[i].cfs_power = sc->sc_pstate[i].ps_power;
322804fdee3Sjruoho 		}
323804fdee3Sjruoho 
324804fdee3Sjruoho 		if (cpufreq_register(&cf) != 0)
325804fdee3Sjruoho 			aprint_error_dev(self, "failed to register cpufreq\n");
326804fdee3Sjruoho 	}
3272510a0e2Sjruoho }
3282510a0e2Sjruoho 
3299120d451Spgoyette SYSCTL_SETUP(acpicpu_sysctl, "acpi_cpu sysctls")
330a5a73b2aSjruoho {
331a5a73b2aSjruoho 	const struct sysctlnode *node;
332a5a73b2aSjruoho 	int err;
333a5a73b2aSjruoho 
3349120d451Spgoyette 	err = sysctl_createv(clog, 0, NULL, &node,
335a5a73b2aSjruoho 	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "acpi", NULL,
3364f6fb3bfSpooka 	    NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL);
337a5a73b2aSjruoho 
338a5a73b2aSjruoho 	if (err != 0)
339a5a73b2aSjruoho 		goto fail;
340a5a73b2aSjruoho 
3419120d451Spgoyette 	err = sysctl_createv(clog, 0, &node, &node,
342a5a73b2aSjruoho 	    0, CTLTYPE_NODE, "cpu", SYSCTL_DESCR("ACPI CPU"),
343a5a73b2aSjruoho 	    NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
344a5a73b2aSjruoho 
345a5a73b2aSjruoho 	if (err != 0)
346a5a73b2aSjruoho 		goto fail;
347a5a73b2aSjruoho 
3489120d451Spgoyette 	err = sysctl_createv(clog, 0, &node, NULL,
349a5a73b2aSjruoho 	    CTLFLAG_READWRITE, CTLTYPE_BOOL, "dynamic",
350a5a73b2aSjruoho 	    SYSCTL_DESCR("Dynamic states"), NULL, 0,
351a5a73b2aSjruoho 	    &acpicpu_dynamic, 0, CTL_CREATE, CTL_EOL);
352a5a73b2aSjruoho 
353a5a73b2aSjruoho 	if (err != 0)
354a5a73b2aSjruoho 		goto fail;
355a5a73b2aSjruoho 
3569120d451Spgoyette 	err = sysctl_createv(clog, 0, &node, NULL,
357a5a73b2aSjruoho 	    CTLFLAG_READWRITE, CTLTYPE_BOOL, "passive",
358a5a73b2aSjruoho 	    SYSCTL_DESCR("Passive cooling"), NULL, 0,
359a5a73b2aSjruoho 	    &acpicpu_passive, 0, CTL_CREATE, CTL_EOL);
360a5a73b2aSjruoho 
361a5a73b2aSjruoho 	if (err != 0)
362a5a73b2aSjruoho 		goto fail;
363a5a73b2aSjruoho 
364a5a73b2aSjruoho 	return;
365a5a73b2aSjruoho 
366a5a73b2aSjruoho fail:
3679120d451Spgoyette 	aprint_error("%s: failed to init sysctl (err %d)\n", __func__, err);
368a5a73b2aSjruoho }
369a5a73b2aSjruoho 
370494badebSjruoho static ACPI_STATUS
acpicpu_object(ACPI_HANDLE hdl,struct acpicpu_object * ao)3714d861e5bSjruoho acpicpu_object(ACPI_HANDLE hdl, struct acpicpu_object *ao)
3724d861e5bSjruoho {
373*30d28f20Sjmcneill 	ACPI_OBJECT_TYPE typ;
3744d861e5bSjruoho 	ACPI_OBJECT *obj;
3754d861e5bSjruoho 	ACPI_BUFFER buf;
3764d861e5bSjruoho 	ACPI_STATUS rv;
3774d861e5bSjruoho 
378*30d28f20Sjmcneill 	rv = AcpiGetType(hdl, &typ);
379*30d28f20Sjmcneill 	if (typ != ACPI_TYPE_PROCESSOR) {
380*30d28f20Sjmcneill 		return AE_TYPE;
381*30d28f20Sjmcneill 	}
382*30d28f20Sjmcneill 
3834d861e5bSjruoho 	rv = acpi_eval_struct(hdl, NULL, &buf);
3844d861e5bSjruoho 
3854d861e5bSjruoho 	if (ACPI_FAILURE(rv))
386494badebSjruoho 		goto out;
3874d861e5bSjruoho 
3884d861e5bSjruoho 	obj = buf.Pointer;
3894d861e5bSjruoho 
3904d861e5bSjruoho 	if (obj->Type != ACPI_TYPE_PROCESSOR) {
3914d861e5bSjruoho 		rv = AE_TYPE;
3924d861e5bSjruoho 		goto out;
3934d861e5bSjruoho 	}
3944d861e5bSjruoho 
3954d861e5bSjruoho 	if (obj->Processor.ProcId > (uint32_t)maxcpus) {
3964d861e5bSjruoho 		rv = AE_LIMIT;
3974d861e5bSjruoho 		goto out;
3984d861e5bSjruoho 	}
3994d861e5bSjruoho 
4004d861e5bSjruoho 	KDASSERT((uint64_t)obj->Processor.PblkAddress < UINT32_MAX);
4014d861e5bSjruoho 
4024d861e5bSjruoho 	if (ao != NULL) {
4034d861e5bSjruoho 		ao->ao_procid = obj->Processor.ProcId;
4044d861e5bSjruoho 		ao->ao_pblklen = obj->Processor.PblkLength;
4054d861e5bSjruoho 		ao->ao_pblkaddr = obj->Processor.PblkAddress;
4064d861e5bSjruoho 	}
4074d861e5bSjruoho 
4084d861e5bSjruoho out:
4094d861e5bSjruoho 	if (buf.Pointer != NULL)
4104d861e5bSjruoho 		ACPI_FREE(buf.Pointer);
4114d861e5bSjruoho 
412494badebSjruoho 	return rv;
4134d861e5bSjruoho }
4144d861e5bSjruoho 
4154d861e5bSjruoho static uint32_t
acpicpu_cap(struct acpicpu_softc * sc)4164d861e5bSjruoho acpicpu_cap(struct acpicpu_softc *sc)
4174d861e5bSjruoho {
4189d3272e7Sjruoho 	uint32_t flags, cap = 0;
4194d861e5bSjruoho 	ACPI_STATUS rv;
4204d861e5bSjruoho 
4214d861e5bSjruoho 	/*
4229d3272e7Sjruoho 	 * Query and set machine-dependent capabilities.
4230fc4e4abSjruoho 	 * Note that the Intel-specific _PDC method has
4240fc4e4abSjruoho 	 * already been evaluated. It was furthermore
4259d3272e7Sjruoho 	 * deprecated in the ACPI 3.0 in favor of _OSC.
4264d861e5bSjruoho 	 */
4270fc4e4abSjruoho 	flags = acpi_md_pdc();
4289d3272e7Sjruoho 	rv = acpicpu_cap_osc(sc, flags, &cap);
4294d861e5bSjruoho 
4309d3272e7Sjruoho 	if (ACPI_FAILURE(rv) && rv != AE_NOT_FOUND) {
4314d861e5bSjruoho 
4329d3272e7Sjruoho 		aprint_error_dev(sc->sc_dev, "failed to evaluate "
4330fc4e4abSjruoho 		    "_OSC: %s\n", AcpiFormatException(rv));
4349d3272e7Sjruoho 	}
4359d3272e7Sjruoho 
4360fc4e4abSjruoho 	return (cap != 0) ? cap : flags;
4374d861e5bSjruoho }
4384d861e5bSjruoho 
4394d861e5bSjruoho static ACPI_STATUS
acpicpu_cap_osc(struct acpicpu_softc * sc,uint32_t flags,uint32_t * val)4409d3272e7Sjruoho acpicpu_cap_osc(struct acpicpu_softc *sc, uint32_t flags, uint32_t *val)
4414d861e5bSjruoho {
4429d3272e7Sjruoho 	ACPI_OBJECT_LIST arg;
4439d3272e7Sjruoho 	ACPI_OBJECT obj[4];
4449d3272e7Sjruoho 	ACPI_OBJECT *osc;
4454d861e5bSjruoho 	ACPI_BUFFER buf;
4464d861e5bSjruoho 	ACPI_STATUS rv;
4479d3272e7Sjruoho 	uint32_t cap[2];
4489d3272e7Sjruoho 	uint32_t *ptr;
4499d3272e7Sjruoho 	int i = 5;
4504d861e5bSjruoho 
4519d3272e7Sjruoho 	static uint8_t intel_uuid[16] = {
4524d861e5bSjruoho 		0x16, 0xA6, 0x77, 0x40, 0x0C, 0x29, 0xBE, 0x47,
4534d861e5bSjruoho 		0x9E, 0xBD, 0xD8, 0x70, 0x58, 0x71, 0x39, 0x53
4544d861e5bSjruoho 	};
4554d861e5bSjruoho 
4569d3272e7Sjruoho 	cap[0] = ACPI_OSC_QUERY;
4579d3272e7Sjruoho 	cap[1] = flags;
4584d861e5bSjruoho 
4599d3272e7Sjruoho again:
4609d3272e7Sjruoho 	arg.Count = 4;
4619d3272e7Sjruoho 	arg.Pointer = obj;
4624d861e5bSjruoho 
4639d3272e7Sjruoho 	obj[0].Type = ACPI_TYPE_BUFFER;
4649d3272e7Sjruoho 	obj[0].Buffer.Length = sizeof(intel_uuid);
4659d3272e7Sjruoho 	obj[0].Buffer.Pointer = intel_uuid;
4664d861e5bSjruoho 
4679d3272e7Sjruoho 	obj[1].Type = ACPI_TYPE_INTEGER;
4689d3272e7Sjruoho 	obj[1].Integer.Value = ACPICPU_PDC_REVID;
4694d861e5bSjruoho 
4709d3272e7Sjruoho 	obj[2].Type = ACPI_TYPE_INTEGER;
4719d3272e7Sjruoho 	obj[2].Integer.Value = __arraycount(cap);
4724d861e5bSjruoho 
4739d3272e7Sjruoho 	obj[3].Type = ACPI_TYPE_BUFFER;
4749d3272e7Sjruoho 	obj[3].Buffer.Length = sizeof(cap);
4759d3272e7Sjruoho 	obj[3].Buffer.Pointer = (void *)cap;
4764d861e5bSjruoho 
4774d861e5bSjruoho 	buf.Pointer = NULL;
4784d861e5bSjruoho 	buf.Length = ACPI_ALLOCATE_LOCAL_BUFFER;
4794d861e5bSjruoho 
4809d3272e7Sjruoho 	rv = AcpiEvaluateObject(sc->sc_node->ad_handle, "_OSC", &arg, &buf);
4814d861e5bSjruoho 
4824d861e5bSjruoho 	if (ACPI_FAILURE(rv))
4839d3272e7Sjruoho 		goto out;
4844d861e5bSjruoho 
4859d3272e7Sjruoho 	osc = buf.Pointer;
4864d861e5bSjruoho 
4879d3272e7Sjruoho 	if (osc->Type != ACPI_TYPE_BUFFER) {
4884d861e5bSjruoho 		rv = AE_TYPE;
4894d861e5bSjruoho 		goto out;
4904d861e5bSjruoho 	}
4914d861e5bSjruoho 
4929d3272e7Sjruoho 	if (osc->Buffer.Length != sizeof(cap)) {
4934d861e5bSjruoho 		rv = AE_BUFFER_OVERFLOW;
4944d861e5bSjruoho 		goto out;
4954d861e5bSjruoho 	}
4964d861e5bSjruoho 
4979d3272e7Sjruoho 	ptr = (uint32_t *)osc->Buffer.Pointer;
4989d3272e7Sjruoho 
4999d3272e7Sjruoho 	if ((ptr[0] & ACPI_OSC_ERROR) != 0) {
5009d3272e7Sjruoho 		rv = AE_ERROR;
5019d3272e7Sjruoho 		goto out;
5029d3272e7Sjruoho 	}
5039d3272e7Sjruoho 
5049d3272e7Sjruoho 	if ((ptr[0] & (ACPI_OSC_ERROR_REV | ACPI_OSC_ERROR_UUID)) != 0) {
5059d3272e7Sjruoho 		rv = AE_BAD_PARAMETER;
5069d3272e7Sjruoho 		goto out;
5079d3272e7Sjruoho 	}
5089d3272e7Sjruoho 
5099d3272e7Sjruoho 	/*
5109d3272e7Sjruoho 	 * "It is strongly recommended that the OS evaluate
5119d3272e7Sjruoho 	 *  _OSC with the Query Support Flag set until _OSC
5129d3272e7Sjruoho 	 *  returns the Capabilities Masked bit clear, to
5139d3272e7Sjruoho 	 *  negotiate the set of features to be granted to
5149d3272e7Sjruoho 	 *  the OS for native support (ACPI 4.0, 6.2.10)."
5159d3272e7Sjruoho 	 */
5169d3272e7Sjruoho 	if ((ptr[0] & ACPI_OSC_ERROR_MASKED) != 0 && i >= 0) {
5179d3272e7Sjruoho 
5189d3272e7Sjruoho 		ACPI_FREE(buf.Pointer);
5199d3272e7Sjruoho 		i--;
5209d3272e7Sjruoho 
5219d3272e7Sjruoho 		goto again;
5229d3272e7Sjruoho 	}
5239d3272e7Sjruoho 
5249d3272e7Sjruoho 	if ((cap[0] & ACPI_OSC_QUERY) != 0) {
5259d3272e7Sjruoho 
5269d3272e7Sjruoho 		ACPI_FREE(buf.Pointer);
5279d3272e7Sjruoho 		cap[0] &= ~ACPI_OSC_QUERY;
5289d3272e7Sjruoho 
5299d3272e7Sjruoho 		goto again;
5309d3272e7Sjruoho 	}
5319d3272e7Sjruoho 
5329d3272e7Sjruoho 	/*
5339d3272e7Sjruoho 	 * It is permitted for _OSC to return all
5349d3272e7Sjruoho 	 * bits cleared, but this is specified to
5359d3272e7Sjruoho 	 * vary on per-device basis. Assume that
5369d3272e7Sjruoho 	 * everything rather than nothing will be
537fcd28418Sjruoho 	 * supported in this case; we do not need
5389d3272e7Sjruoho 	 * the firmware to know the CPU features.
5399d3272e7Sjruoho 	 */
5409d3272e7Sjruoho 	*val = (ptr[1] != 0) ? ptr[1] : cap[1];
5414d861e5bSjruoho 
5424d861e5bSjruoho out:
5434d861e5bSjruoho 	if (buf.Pointer != NULL)
5444d861e5bSjruoho 		ACPI_FREE(buf.Pointer);
5454d861e5bSjruoho 
5464d861e5bSjruoho 	return rv;
5474d861e5bSjruoho }
5484d861e5bSjruoho 
5494d861e5bSjruoho static void
acpicpu_notify(ACPI_HANDLE hdl,uint32_t evt,void * aux)5504d861e5bSjruoho acpicpu_notify(ACPI_HANDLE hdl, uint32_t evt, void *aux)
5514d861e5bSjruoho {
5524d861e5bSjruoho 	ACPI_OSD_EXEC_CALLBACK func;
5534d861e5bSjruoho 	struct acpicpu_softc *sc;
5544d861e5bSjruoho 	device_t self = aux;
5554d861e5bSjruoho 
5564d861e5bSjruoho 	sc = device_private(self);
5574d861e5bSjruoho 
558e9a3c2e5Sjruoho 	if (sc->sc_cold != false)
559e9a3c2e5Sjruoho 		return;
560e9a3c2e5Sjruoho 
561a5a73b2aSjruoho 	if (acpicpu_dynamic != true)
562a5a73b2aSjruoho 		return;
563a5a73b2aSjruoho 
5644d861e5bSjruoho 	switch (evt) {
5654d861e5bSjruoho 
5664d861e5bSjruoho 	case ACPICPU_C_NOTIFY:
5674d861e5bSjruoho 
5684d861e5bSjruoho 		if ((sc->sc_flags & ACPICPU_FLAG_C) == 0)
5694d861e5bSjruoho 			return;
5704d861e5bSjruoho 
5714d861e5bSjruoho 		func = acpicpu_cstate_callback;
5724d861e5bSjruoho 		break;
5734d861e5bSjruoho 
5744d861e5bSjruoho 	case ACPICPU_P_NOTIFY:
5754d861e5bSjruoho 
5764d861e5bSjruoho 		if ((sc->sc_flags & ACPICPU_FLAG_P) == 0)
5774d861e5bSjruoho 			return;
5784d861e5bSjruoho 
57953e8f6c9Sjruoho 		func = acpicpu_pstate_callback;
5804d861e5bSjruoho 		break;
5814d861e5bSjruoho 
5824d861e5bSjruoho 	case ACPICPU_T_NOTIFY:
5834d861e5bSjruoho 
5844d861e5bSjruoho 		if ((sc->sc_flags & ACPICPU_FLAG_T) == 0)
5854d861e5bSjruoho 			return;
5864d861e5bSjruoho 
5876b9ff107Sjruoho 		func = acpicpu_tstate_callback;
5884d861e5bSjruoho 		break;
5894d861e5bSjruoho 
5904d861e5bSjruoho 	default:
5914d861e5bSjruoho 		aprint_error_dev(sc->sc_dev,  "unknown notify: 0x%02X\n", evt);
5924d861e5bSjruoho 		return;
5934d861e5bSjruoho 	}
5944d861e5bSjruoho 
5954d861e5bSjruoho 	(void)AcpiOsExecute(OSL_NOTIFY_HANDLER, func, sc->sc_dev);
5964d861e5bSjruoho }
5974d861e5bSjruoho 
5984d861e5bSjruoho static bool
acpicpu_suspend(device_t self,const pmf_qual_t * qual)5994d861e5bSjruoho acpicpu_suspend(device_t self, const pmf_qual_t *qual)
6004d861e5bSjruoho {
6014d861e5bSjruoho 	struct acpicpu_softc *sc = device_private(self);
6024d861e5bSjruoho 
6034d861e5bSjruoho 	if ((sc->sc_flags & ACPICPU_FLAG_C) != 0)
6044d861e5bSjruoho 		(void)acpicpu_cstate_suspend(self);
6054d861e5bSjruoho 
60653e8f6c9Sjruoho 	if ((sc->sc_flags & ACPICPU_FLAG_P) != 0)
60753e8f6c9Sjruoho 		(void)acpicpu_pstate_suspend(self);
60853e8f6c9Sjruoho 
6096b9ff107Sjruoho 	if ((sc->sc_flags & ACPICPU_FLAG_T) != 0)
6106b9ff107Sjruoho 		(void)acpicpu_tstate_suspend(self);
6116b9ff107Sjruoho 
612c1f0324cSjruoho 	sc->sc_cold = true;
613c1f0324cSjruoho 
6144d861e5bSjruoho 	return true;
6154d861e5bSjruoho }
6164d861e5bSjruoho 
6174d861e5bSjruoho static bool
acpicpu_resume(device_t self,const pmf_qual_t * qual)6184d861e5bSjruoho acpicpu_resume(device_t self, const pmf_qual_t *qual)
6194d861e5bSjruoho {
6204d861e5bSjruoho 	struct acpicpu_softc *sc = device_private(self);
6218e61d414Sjruoho 	static const int handler = OSL_NOTIFY_HANDLER;
6224d861e5bSjruoho 
623c1f0324cSjruoho 	sc->sc_cold = false;
624c1f0324cSjruoho 
6254d861e5bSjruoho 	if ((sc->sc_flags & ACPICPU_FLAG_C) != 0)
6268e61d414Sjruoho 		(void)AcpiOsExecute(handler, acpicpu_cstate_resume, self);
6274d861e5bSjruoho 
62853e8f6c9Sjruoho 	if ((sc->sc_flags & ACPICPU_FLAG_P) != 0)
6298e61d414Sjruoho 		(void)AcpiOsExecute(handler, acpicpu_pstate_resume, self);
63053e8f6c9Sjruoho 
6316b9ff107Sjruoho 	if ((sc->sc_flags & ACPICPU_FLAG_T) != 0)
6328e61d414Sjruoho 		(void)AcpiOsExecute(handler, acpicpu_tstate_resume, self);
6336b9ff107Sjruoho 
6344d861e5bSjruoho 	return true;
6354d861e5bSjruoho }
6364d861e5bSjruoho 
637a080ec14Sjruoho static void
acpicpu_evcnt_attach(device_t self)638e98440f2Sjruoho acpicpu_evcnt_attach(device_t self)
639e98440f2Sjruoho {
640e98440f2Sjruoho 	struct acpicpu_softc *sc = device_private(self);
641e98440f2Sjruoho 	struct acpicpu_cstate *cs;
642e98440f2Sjruoho 	struct acpicpu_pstate *ps;
643e98440f2Sjruoho 	struct acpicpu_tstate *ts;
644e98440f2Sjruoho 	const char *str;
645e98440f2Sjruoho 	uint32_t i;
646e98440f2Sjruoho 
647e98440f2Sjruoho 	for (i = 0; i < __arraycount(sc->sc_cstate); i++) {
648e98440f2Sjruoho 
649e98440f2Sjruoho 		cs = &sc->sc_cstate[i];
650e98440f2Sjruoho 
651e98440f2Sjruoho 		if (cs->cs_method == 0)
652e98440f2Sjruoho 			continue;
653e98440f2Sjruoho 
654e98440f2Sjruoho 		str = "HALT";
655e98440f2Sjruoho 
656e98440f2Sjruoho 		if (cs->cs_method == ACPICPU_C_STATE_FFH)
657e98440f2Sjruoho 			str = "MWAIT";
658e98440f2Sjruoho 
659e98440f2Sjruoho 		if (cs->cs_method == ACPICPU_C_STATE_SYSIO)
660e98440f2Sjruoho 			str = "I/O";
661e98440f2Sjruoho 
662e98440f2Sjruoho 		(void)snprintf(cs->cs_name, sizeof(cs->cs_name),
663e98440f2Sjruoho 		    "C%d (%s)", i, str);
664e98440f2Sjruoho 
665e98440f2Sjruoho 		evcnt_attach_dynamic(&cs->cs_evcnt, EVCNT_TYPE_MISC,
666e98440f2Sjruoho 		    NULL, device_xname(sc->sc_dev), cs->cs_name);
667e98440f2Sjruoho 	}
668e98440f2Sjruoho 
669e98440f2Sjruoho 	for (i = 0; i < sc->sc_pstate_count; i++) {
670e98440f2Sjruoho 
671e98440f2Sjruoho 		ps = &sc->sc_pstate[i];
672e98440f2Sjruoho 
673e98440f2Sjruoho 		if (ps->ps_freq == 0)
674e98440f2Sjruoho 			continue;
675e98440f2Sjruoho 
676e98440f2Sjruoho 		(void)snprintf(ps->ps_name, sizeof(ps->ps_name),
677e98440f2Sjruoho 		    "P%u (%u MHz)", i, ps->ps_freq);
678e98440f2Sjruoho 
679e98440f2Sjruoho 		evcnt_attach_dynamic(&ps->ps_evcnt, EVCNT_TYPE_MISC,
680e98440f2Sjruoho 		    NULL, device_xname(sc->sc_dev), ps->ps_name);
681e98440f2Sjruoho 	}
682e98440f2Sjruoho 
683e98440f2Sjruoho 	for (i = 0; i < sc->sc_tstate_count; i++) {
684e98440f2Sjruoho 
685e98440f2Sjruoho 		ts = &sc->sc_tstate[i];
686e98440f2Sjruoho 
687e98440f2Sjruoho 		if (ts->ts_percent == 0)
688e98440f2Sjruoho 			continue;
689e98440f2Sjruoho 
690e98440f2Sjruoho 		(void)snprintf(ts->ts_name, sizeof(ts->ts_name),
691e98440f2Sjruoho 		    "T%u (%u %%)", i, ts->ts_percent);
692e98440f2Sjruoho 
693e98440f2Sjruoho 		evcnt_attach_dynamic(&ts->ts_evcnt, EVCNT_TYPE_MISC,
694e98440f2Sjruoho 		    NULL, device_xname(sc->sc_dev), ts->ts_name);
695e98440f2Sjruoho 	}
696e98440f2Sjruoho }
697e98440f2Sjruoho 
698e98440f2Sjruoho static void
acpicpu_evcnt_detach(device_t self)699e98440f2Sjruoho acpicpu_evcnt_detach(device_t self)
700e98440f2Sjruoho {
701e98440f2Sjruoho 	struct acpicpu_softc *sc = device_private(self);
702e98440f2Sjruoho 	struct acpicpu_cstate *cs;
703e98440f2Sjruoho 	struct acpicpu_pstate *ps;
704e98440f2Sjruoho 	struct acpicpu_tstate *ts;
705e98440f2Sjruoho 	uint32_t i;
706e98440f2Sjruoho 
707e98440f2Sjruoho 	for (i = 0; i < __arraycount(sc->sc_cstate); i++) {
708e98440f2Sjruoho 
709e98440f2Sjruoho 		cs = &sc->sc_cstate[i];
710e98440f2Sjruoho 
711e98440f2Sjruoho 		if (cs->cs_method != 0)
712e98440f2Sjruoho 			evcnt_detach(&cs->cs_evcnt);
713e98440f2Sjruoho 	}
714e98440f2Sjruoho 
715e98440f2Sjruoho 	for (i = 0; i < sc->sc_pstate_count; i++) {
716e98440f2Sjruoho 
717e98440f2Sjruoho 		ps = &sc->sc_pstate[i];
718e98440f2Sjruoho 
719e98440f2Sjruoho 		if (ps->ps_freq != 0)
720e98440f2Sjruoho 			evcnt_detach(&ps->ps_evcnt);
721e98440f2Sjruoho 	}
722e98440f2Sjruoho 
723e98440f2Sjruoho 	for (i = 0; i < sc->sc_tstate_count; i++) {
724e98440f2Sjruoho 
725e98440f2Sjruoho 		ts = &sc->sc_tstate[i];
726e98440f2Sjruoho 
727e98440f2Sjruoho 		if (ts->ts_percent != 0)
728e98440f2Sjruoho 			evcnt_detach(&ts->ts_evcnt);
729e98440f2Sjruoho 	}
730e98440f2Sjruoho }
731e98440f2Sjruoho 
732e98440f2Sjruoho static void
acpicpu_debug_print(device_t self)733494badebSjruoho acpicpu_debug_print(device_t self)
734a080ec14Sjruoho {
735494badebSjruoho 	struct acpicpu_softc *sc = device_private(self);
736494badebSjruoho 	struct cpu_info *ci = sc->sc_ci;
737b9f7a5acSjruoho 	struct acpicpu_cstate *cs;
738b9f7a5acSjruoho 	struct acpicpu_pstate *ps;
739b9f7a5acSjruoho 	struct acpicpu_tstate *ts;
740b9f7a5acSjruoho 	static bool once = false;
741a080ec14Sjruoho 	struct acpicpu_dep *dep;
742b9f7a5acSjruoho 	uint32_t i, method;
743b9f7a5acSjruoho 
744b9f7a5acSjruoho 	if (once != true) {
745b9f7a5acSjruoho 
746b9f7a5acSjruoho 		for (i = 0; i < __arraycount(sc->sc_cstate); i++) {
747b9f7a5acSjruoho 
748b9f7a5acSjruoho 			cs = &sc->sc_cstate[i];
749b9f7a5acSjruoho 
750b9f7a5acSjruoho 			if (cs->cs_method == 0)
751b9f7a5acSjruoho 				continue;
752b9f7a5acSjruoho 
753b9f7a5acSjruoho 			aprint_verbose_dev(sc->sc_dev, "C%d: %3s, "
7545bfb3adeSjruoho 			    "lat %3u us, pow %5u mW%s\n", i,
755804fdee3Sjruoho 			    acpicpu_debug_print_method_c(cs->cs_method),
756b9f7a5acSjruoho 			    cs->cs_latency, cs->cs_power,
7575bfb3adeSjruoho 			    (cs->cs_flags != 0) ? ", bus master check" : "");
758b9f7a5acSjruoho 		}
759b9f7a5acSjruoho 
760b9f7a5acSjruoho 		method = sc->sc_pstate_control.reg_spaceid;
761b9f7a5acSjruoho 
762b9f7a5acSjruoho 		for (i = 0; i < sc->sc_pstate_count; i++) {
763b9f7a5acSjruoho 
764b9f7a5acSjruoho 			ps = &sc->sc_pstate[i];
765b9f7a5acSjruoho 
766b9f7a5acSjruoho 			if (ps->ps_freq == 0)
767b9f7a5acSjruoho 				continue;
768b9f7a5acSjruoho 
769b9f7a5acSjruoho 			aprint_verbose_dev(sc->sc_dev, "P%d: %3s, "
7705bfb3adeSjruoho 			    "lat %3u us, pow %5u mW, %4u MHz%s\n", i,
771804fdee3Sjruoho 			    acpicpu_debug_print_method_pt(method),
7725bfb3adeSjruoho 			    ps->ps_latency, ps->ps_power, ps->ps_freq,
7735bfb3adeSjruoho 			    (ps->ps_flags & ACPICPU_FLAG_P_TURBO) != 0 ?
7745bfb3adeSjruoho 			    ", turbo boost" : "");
775b9f7a5acSjruoho 		}
776b9f7a5acSjruoho 
777b9f7a5acSjruoho 		method = sc->sc_tstate_control.reg_spaceid;
778b9f7a5acSjruoho 
779b9f7a5acSjruoho 		for (i = 0; i < sc->sc_tstate_count; i++) {
780b9f7a5acSjruoho 
781b9f7a5acSjruoho 			ts = &sc->sc_tstate[i];
782b9f7a5acSjruoho 
783b9f7a5acSjruoho 			if (ts->ts_percent == 0)
784b9f7a5acSjruoho 				continue;
785b9f7a5acSjruoho 
786b9f7a5acSjruoho 			aprint_verbose_dev(sc->sc_dev, "T%u: %3s, "
787b9f7a5acSjruoho 			    "lat %3u us, pow %5u mW, %3u %%\n", i,
788804fdee3Sjruoho 			    acpicpu_debug_print_method_pt(method),
789b9f7a5acSjruoho 			    ts->ts_latency, ts->ts_power, ts->ts_percent);
790b9f7a5acSjruoho 		}
791b9f7a5acSjruoho 
792b9f7a5acSjruoho 		once = true;
793b9f7a5acSjruoho 	}
794a080ec14Sjruoho 
795494badebSjruoho 	aprint_debug_dev(sc->sc_dev, "id %u, lapic id %u, "
796494badebSjruoho 	    "cap 0x%04x, flags 0x%08x\n", ci->ci_acpiid,
797494badebSjruoho 	    (uint32_t)ci->ci_cpuid, sc->sc_cap, sc->sc_flags);
798494badebSjruoho 
799a080ec14Sjruoho 	if ((sc->sc_flags & ACPICPU_FLAG_C_DEP) != 0) {
800a080ec14Sjruoho 
801a080ec14Sjruoho 		dep = &sc->sc_cstate_dep;
802a080ec14Sjruoho 
803a080ec14Sjruoho 		aprint_debug_dev(sc->sc_dev, "C-state coordination: "
804a080ec14Sjruoho 		    "%u CPUs, domain %u, type %s\n", dep->dep_ncpus,
805a080ec14Sjruoho 		    dep->dep_domain, acpicpu_debug_print_dep(dep->dep_type));
806a080ec14Sjruoho 	}
807a080ec14Sjruoho 
808a080ec14Sjruoho 	if ((sc->sc_flags & ACPICPU_FLAG_P_DEP) != 0) {
809a080ec14Sjruoho 
810a080ec14Sjruoho 		dep = &sc->sc_pstate_dep;
811a080ec14Sjruoho 
812a080ec14Sjruoho 		aprint_debug_dev(sc->sc_dev, "P-state coordination: "
813a080ec14Sjruoho 		    "%u CPUs, domain %u, type %s\n", dep->dep_ncpus,
814a080ec14Sjruoho 		    dep->dep_domain, acpicpu_debug_print_dep(dep->dep_type));
815a080ec14Sjruoho 	}
816a080ec14Sjruoho 
817a080ec14Sjruoho 	if ((sc->sc_flags & ACPICPU_FLAG_T_DEP) != 0) {
818a080ec14Sjruoho 
819a080ec14Sjruoho 		dep = &sc->sc_tstate_dep;
820a080ec14Sjruoho 
821a080ec14Sjruoho 		aprint_debug_dev(sc->sc_dev, "T-state coordination: "
822a080ec14Sjruoho 		    "%u CPUs, domain %u, type %s\n", dep->dep_ncpus,
823a080ec14Sjruoho 		    dep->dep_domain, acpicpu_debug_print_dep(dep->dep_type));
824a080ec14Sjruoho 	}
825a080ec14Sjruoho }
826a080ec14Sjruoho 
827a080ec14Sjruoho static const char *
acpicpu_debug_print_method_c(uint8_t val)828804fdee3Sjruoho acpicpu_debug_print_method_c(uint8_t val)
829b9f7a5acSjruoho {
830b9f7a5acSjruoho 
831cc543157Sjruoho 	if (val == ACPICPU_C_STATE_FFH)
832b9f7a5acSjruoho 		return "FFH";
833b9f7a5acSjruoho 
834cc543157Sjruoho 	if (val == ACPICPU_C_STATE_HALT)
835cc543157Sjruoho 		return "HLT";
836cc543157Sjruoho 
837cc543157Sjruoho 	if (val == ACPICPU_C_STATE_SYSIO)
838b9f7a5acSjruoho 		return "I/O";
839b9f7a5acSjruoho 
840804fdee3Sjruoho 	return "???";
841804fdee3Sjruoho }
842804fdee3Sjruoho 
843804fdee3Sjruoho static const char *
acpicpu_debug_print_method_pt(uint8_t val)844804fdee3Sjruoho acpicpu_debug_print_method_pt(uint8_t val)
845804fdee3Sjruoho {
846*30d28f20Sjmcneill 	if (val == ACPI_ADR_SPACE_SYSTEM_MEMORY)
847*30d28f20Sjmcneill 		return "MMIO";
848804fdee3Sjruoho 
849cc543157Sjruoho 	if (val == ACPI_ADR_SPACE_SYSTEM_IO)
850cc543157Sjruoho 		return "I/O";
851cc543157Sjruoho 
852cc543157Sjruoho 	if (val == ACPI_ADR_SPACE_FIXED_HARDWARE)
853cc543157Sjruoho 		return "FFH";
854cc543157Sjruoho 
855b9f7a5acSjruoho 	return "???";
856b9f7a5acSjruoho }
857b9f7a5acSjruoho 
858b9f7a5acSjruoho static const char *
acpicpu_debug_print_dep(uint32_t val)859a080ec14Sjruoho acpicpu_debug_print_dep(uint32_t val)
860a080ec14Sjruoho {
861a080ec14Sjruoho 
862a080ec14Sjruoho 	switch (val) {
863a080ec14Sjruoho 
864a080ec14Sjruoho 	case ACPICPU_DEP_SW_ALL:
865a080ec14Sjruoho 		return "SW_ALL";
866a080ec14Sjruoho 
867a080ec14Sjruoho 	case ACPICPU_DEP_SW_ANY:
868a080ec14Sjruoho 		return "SW_ANY";
869a080ec14Sjruoho 
870a080ec14Sjruoho 	case ACPICPU_DEP_HW_ALL:
871a080ec14Sjruoho 		return "HW_ALL";
872a080ec14Sjruoho 
873a080ec14Sjruoho 	default:
874a080ec14Sjruoho 		return "unknown";
875a080ec14Sjruoho 	}
876a080ec14Sjruoho }
877a080ec14Sjruoho 
8784d861e5bSjruoho MODULE(MODULE_CLASS_DRIVER, acpicpu, NULL);
8794d861e5bSjruoho 
8802b0b13f2Sjruoho #ifdef _MODULE
8812b0b13f2Sjruoho #include "ioconf.c"
8822b0b13f2Sjruoho #endif
8834d861e5bSjruoho 
8844d861e5bSjruoho static int
acpicpu_modcmd(modcmd_t cmd,void * aux)8852b0b13f2Sjruoho acpicpu_modcmd(modcmd_t cmd, void *aux)
8864d861e5bSjruoho {
8872b0b13f2Sjruoho 	int rv = 0;
8884d861e5bSjruoho 
8894d861e5bSjruoho 	switch (cmd) {
8904d861e5bSjruoho 
8914d861e5bSjruoho 	case MODULE_CMD_INIT:
8924d861e5bSjruoho 
8932b0b13f2Sjruoho #ifdef _MODULE
8942b0b13f2Sjruoho 		rv = config_init_component(cfdriver_ioconf_acpicpu,
8952b0b13f2Sjruoho 		    cfattach_ioconf_acpicpu, cfdata_ioconf_acpicpu);
8962b0b13f2Sjruoho #endif
8972b0b13f2Sjruoho 		break;
8984d861e5bSjruoho 
8994d861e5bSjruoho 	case MODULE_CMD_FINI:
9004d861e5bSjruoho 
9012b0b13f2Sjruoho #ifdef _MODULE
9022b0b13f2Sjruoho 		rv = config_fini_component(cfdriver_ioconf_acpicpu,
9032b0b13f2Sjruoho 		    cfattach_ioconf_acpicpu, cfdata_ioconf_acpicpu);
9042b0b13f2Sjruoho #endif
9052b0b13f2Sjruoho 		break;
9064d861e5bSjruoho 
9074d861e5bSjruoho 	default:
9082b0b13f2Sjruoho 		rv = ENOTTY;
9094d861e5bSjruoho 	}
9104d861e5bSjruoho 
9112b0b13f2Sjruoho 	return rv;
9122b0b13f2Sjruoho }
913