xref: /freebsd/sys/dev/xen/cpu/xen_acpi_cpu.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
1b93f47eaSRoger Pau Monné /*-
2b93f47eaSRoger Pau Monné  * Copyright (c) 2022 Citrix Systems R&D
3b93f47eaSRoger Pau Monné  * Copyright (c) 2003-2005 Nate Lawson (SDG)
4b93f47eaSRoger Pau Monné  * Copyright (c) 2001 Michael Smith
5b93f47eaSRoger Pau Monné  * All rights reserved.
6b93f47eaSRoger Pau Monné  *
7b93f47eaSRoger Pau Monné  * Redistribution and use in source and binary forms, with or without
8b93f47eaSRoger Pau Monné  * modification, are permitted provided that the following conditions
9b93f47eaSRoger Pau Monné  * are met:
10b93f47eaSRoger Pau Monné  * 1. Redistributions of source code must retain the above copyright
11b93f47eaSRoger Pau Monné  *    notice, this list of conditions and the following disclaimer.
12b93f47eaSRoger Pau Monné  * 2. Redistributions in binary form must reproduce the above copyright
13b93f47eaSRoger Pau Monné  *    notice, this list of conditions and the following disclaimer in the
14b93f47eaSRoger Pau Monné  *    documentation and/or other materials provided with the distribution.
15b93f47eaSRoger Pau Monné  *
16b93f47eaSRoger Pau Monné  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17b93f47eaSRoger Pau Monné  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18b93f47eaSRoger Pau Monné  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19b93f47eaSRoger Pau Monné  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20b93f47eaSRoger Pau Monné  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21b93f47eaSRoger Pau Monné  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22b93f47eaSRoger Pau Monné  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23b93f47eaSRoger Pau Monné  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24b93f47eaSRoger Pau Monné  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25b93f47eaSRoger Pau Monné  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26b93f47eaSRoger Pau Monné  * SUCH DAMAGE.
27b93f47eaSRoger Pau Monné  */
28b93f47eaSRoger Pau Monné 
29b93f47eaSRoger Pau Monné #include <sys/cdefs.h>
30b93f47eaSRoger Pau Monné #include "opt_acpi.h"
31b93f47eaSRoger Pau Monné #include <sys/param.h>
32b93f47eaSRoger Pau Monné #include <sys/bus.h>
33b93f47eaSRoger Pau Monné #include <sys/cpu.h>
34b93f47eaSRoger Pau Monné #include <sys/kernel.h>
35b93f47eaSRoger Pau Monné #include <sys/malloc.h>
36b93f47eaSRoger Pau Monné #include <sys/module.h>
37b93f47eaSRoger Pau Monné #include <sys/pcpu.h>
38b93f47eaSRoger Pau Monné #include <sys/power.h>
39b93f47eaSRoger Pau Monné #include <sys/proc.h>
40b93f47eaSRoger Pau Monné #include <sys/sched.h>
41b93f47eaSRoger Pau Monné 
42b93f47eaSRoger Pau Monné #include <machine/_inttypes.h>
43b93f47eaSRoger Pau Monné 
44b93f47eaSRoger Pau Monné #include <contrib/dev/acpica/include/acpi.h>
45b93f47eaSRoger Pau Monné #include <contrib/dev/acpica/include/accommon.h>
46b93f47eaSRoger Pau Monné 
47b93f47eaSRoger Pau Monné #include <dev/acpica/acpivar.h>
48b93f47eaSRoger Pau Monné 
49b93f47eaSRoger Pau Monné #include <xen/xen-os.h>
50b93f47eaSRoger Pau Monné 
51b93f47eaSRoger Pau Monné #define ACPI_DOMAIN_COORD_TYPE_SW_ALL 0xfc
52b93f47eaSRoger Pau Monné #define ACPI_DOMAIN_COORD_TYPE_SW_ANY 0xfd
53b93f47eaSRoger Pau Monné #define ACPI_DOMAIN_COORD_TYPE_HW_ALL 0xfe
54b93f47eaSRoger Pau Monné 
55b93f47eaSRoger Pau Monné #define ACPI_NOTIFY_PERF_STATES 0x80	/* _PSS changed. */
56b93f47eaSRoger Pau Monné #define ACPI_NOTIFY_CX_STATES	0x81	/* _CST changed. */
57b93f47eaSRoger Pau Monné 
58b93f47eaSRoger Pau Monné static MALLOC_DEFINE(M_XENACPI, "xen_acpi", "Xen CPU ACPI forwarder");
59b93f47eaSRoger Pau Monné 
60b93f47eaSRoger Pau Monné /* Hooks for the ACPI CA debugging infrastructure */
61b93f47eaSRoger Pau Monné #define _COMPONENT ACPI_PROCESSOR
62b93f47eaSRoger Pau Monné ACPI_MODULE_NAME("PROCESSOR")
63b93f47eaSRoger Pau Monné 
64b93f47eaSRoger Pau Monné struct xen_acpi_cpu_softc {
65b93f47eaSRoger Pau Monné 	device_t cpu_dev;
66b93f47eaSRoger Pau Monné 	ACPI_HANDLE cpu_handle;
67b93f47eaSRoger Pau Monné 	uint32_t cpu_acpi_id;
68b93f47eaSRoger Pau Monné 	struct xen_processor_cx *cpu_cx_states;
69b93f47eaSRoger Pau Monné 	unsigned int cpu_cx_count;
70b93f47eaSRoger Pau Monné 	struct xen_processor_px *cpu_px_states;
71b93f47eaSRoger Pau Monné 	unsigned int cpu_px_count;
72b93f47eaSRoger Pau Monné 	struct xen_pct_register control_register;
73b93f47eaSRoger Pau Monné 	struct xen_pct_register status_register;
74b93f47eaSRoger Pau Monné 	struct xen_psd_package psd;
75b93f47eaSRoger Pau Monné };
76b93f47eaSRoger Pau Monné 
77b93f47eaSRoger Pau Monné #define	CPUDEV_DEVICE_ID "ACPI0007"
78b93f47eaSRoger Pau Monné 
79b93f47eaSRoger Pau Monné ACPI_SERIAL_DECL(cpu, "ACPI CPU");
80b93f47eaSRoger Pau Monné 
81b93f47eaSRoger Pau Monné #define device_printf(dev,...) \
82b93f47eaSRoger Pau Monné 	if (!device_is_quiet(dev)) \
83b93f47eaSRoger Pau Monné 		device_printf((dev), __VA_ARGS__)
84b93f47eaSRoger Pau Monné 
85b93f47eaSRoger Pau Monné static int
acpi_get_gas(const ACPI_OBJECT * res,unsigned int idx,ACPI_GENERIC_ADDRESS * gas)86b93f47eaSRoger Pau Monné acpi_get_gas(const ACPI_OBJECT *res, unsigned int idx,
87b93f47eaSRoger Pau Monné     ACPI_GENERIC_ADDRESS *gas)
88b93f47eaSRoger Pau Monné {
89b93f47eaSRoger Pau Monné 	const ACPI_OBJECT *obj = &res->Package.Elements[idx];
90b93f47eaSRoger Pau Monné 
91b93f47eaSRoger Pau Monné 	if (obj == NULL || obj->Type != ACPI_TYPE_BUFFER ||
92b93f47eaSRoger Pau Monné 	    obj->Buffer.Length < sizeof(ACPI_GENERIC_ADDRESS) + 3)
93b93f47eaSRoger Pau Monné 		return (EINVAL);
94b93f47eaSRoger Pau Monné 
95b93f47eaSRoger Pau Monné 	memcpy(gas, obj->Buffer.Pointer + 3, sizeof(*gas));
96b93f47eaSRoger Pau Monné 
97b93f47eaSRoger Pau Monné 	return (0);
98b93f47eaSRoger Pau Monné }
99b93f47eaSRoger Pau Monné 
100b93f47eaSRoger Pau Monné static int
acpi_get_pct(const ACPI_OBJECT * res,unsigned int idx,struct xen_pct_register * reg)101b93f47eaSRoger Pau Monné acpi_get_pct(const ACPI_OBJECT *res, unsigned int idx,
102b93f47eaSRoger Pau Monné     struct xen_pct_register *reg)
103b93f47eaSRoger Pau Monné {
104b93f47eaSRoger Pau Monné 	struct {
105b93f47eaSRoger Pau Monné 		uint8_t descriptor;
106b93f47eaSRoger Pau Monné 		uint16_t length;
107b93f47eaSRoger Pau Monné 		ACPI_GENERIC_ADDRESS gas;
108b93f47eaSRoger Pau Monné 	} __packed raw;
109b93f47eaSRoger Pau Monné 	const ACPI_OBJECT *obj = &res->Package.Elements[idx];
110b93f47eaSRoger Pau Monné 
111b93f47eaSRoger Pau Monné 	if (obj == NULL || obj->Type != ACPI_TYPE_BUFFER ||
112b93f47eaSRoger Pau Monné 	    obj->Buffer.Length < sizeof(raw))
113b93f47eaSRoger Pau Monné 		return (EINVAL);
114b93f47eaSRoger Pau Monné 
115b93f47eaSRoger Pau Monné 	memcpy(&raw, obj->Buffer.Pointer, sizeof(raw));
116b93f47eaSRoger Pau Monné 	reg->descriptor = raw.descriptor;
117b93f47eaSRoger Pau Monné 	reg->length = raw.length;
118b93f47eaSRoger Pau Monné 	reg->space_id = raw.gas.SpaceId;
119b93f47eaSRoger Pau Monné 	reg->bit_width = raw.gas.BitWidth;
120b93f47eaSRoger Pau Monné 	reg->bit_offset = raw.gas.BitOffset;
121b93f47eaSRoger Pau Monné 	reg->reserved = raw.gas.AccessWidth;
122b93f47eaSRoger Pau Monné 	reg->address = raw.gas.Address;
123b93f47eaSRoger Pau Monné 
124b93f47eaSRoger Pau Monné 	return (0);
125b93f47eaSRoger Pau Monné }
126b93f47eaSRoger Pau Monné 
127b93f47eaSRoger Pau Monné static int
xen_upload_cx(struct xen_acpi_cpu_softc * sc)128b93f47eaSRoger Pau Monné xen_upload_cx(struct xen_acpi_cpu_softc *sc)
129b93f47eaSRoger Pau Monné {
130b93f47eaSRoger Pau Monné 	struct xen_platform_op op = {
131b93f47eaSRoger Pau Monné 		.cmd			= XENPF_set_processor_pminfo,
132b93f47eaSRoger Pau Monné 		.interface_version	= XENPF_INTERFACE_VERSION,
133b93f47eaSRoger Pau Monné 		.u.set_pminfo.id	= sc->cpu_acpi_id,
134b93f47eaSRoger Pau Monné 		.u.set_pminfo.type	= XEN_PM_CX,
135b93f47eaSRoger Pau Monné 		.u.set_pminfo.u.power.count = sc->cpu_cx_count,
136b93f47eaSRoger Pau Monné 		.u.set_pminfo.u.power.flags.has_cst = 1,
137b93f47eaSRoger Pau Monné 		/* Ignore bm_check and bm_control, Xen will set those. */
138b93f47eaSRoger Pau Monné 	};
139b93f47eaSRoger Pau Monné 	int error;
140b93f47eaSRoger Pau Monné 
141b93f47eaSRoger Pau Monné 	set_xen_guest_handle(op.u.set_pminfo.u.power.states, sc->cpu_cx_states);
142b93f47eaSRoger Pau Monné 
143b93f47eaSRoger Pau Monné 	error = HYPERVISOR_platform_op(&op);
144b93f47eaSRoger Pau Monné 	if (error != 0)
145b93f47eaSRoger Pau Monné 		device_printf(sc->cpu_dev,
146b93f47eaSRoger Pau Monné 		    "ACPI ID %u Cx upload failed: %d\n", sc->cpu_acpi_id,
147b93f47eaSRoger Pau Monné 		    error);
148b93f47eaSRoger Pau Monné 	return (error);
149b93f47eaSRoger Pau Monné }
150b93f47eaSRoger Pau Monné 
151b93f47eaSRoger Pau Monné static int
xen_upload_px(struct xen_acpi_cpu_softc * sc)152b93f47eaSRoger Pau Monné xen_upload_px(struct xen_acpi_cpu_softc *sc)
153b93f47eaSRoger Pau Monné {
154b93f47eaSRoger Pau Monné 	struct xen_platform_op op = {
155b93f47eaSRoger Pau Monné 		.cmd = XENPF_set_processor_pminfo,
156b93f47eaSRoger Pau Monné 		.interface_version = XENPF_INTERFACE_VERSION,
157b93f47eaSRoger Pau Monné 		.u.set_pminfo.id = sc->cpu_acpi_id,
158b93f47eaSRoger Pau Monné 		.u.set_pminfo.type = XEN_PM_PX,
159b93f47eaSRoger Pau Monné 		.u.set_pminfo.u.perf.state_count = sc->cpu_px_count,
160b93f47eaSRoger Pau Monné 		.u.set_pminfo.u.perf.control_register = sc->control_register,
161b93f47eaSRoger Pau Monné 		.u.set_pminfo.u.perf.status_register = sc->status_register,
162b93f47eaSRoger Pau Monné 		.u.set_pminfo.u.perf.domain_info = sc->psd,
163b93f47eaSRoger Pau Monné 		.u.set_pminfo.u.perf.flags = XEN_PX_PPC | XEN_PX_PCT |
164b93f47eaSRoger Pau Monné 		    XEN_PX_PSS | XEN_PX_PSD,
165b93f47eaSRoger Pau Monné 	};
166b93f47eaSRoger Pau Monné 	ACPI_STATUS status;
167b93f47eaSRoger Pau Monné 	int error;
168b93f47eaSRoger Pau Monné 
169b93f47eaSRoger Pau Monné 	status = acpi_GetInteger(sc->cpu_handle, "_PPC",
170b93f47eaSRoger Pau Monné 	    &op.u.set_pminfo.u.perf.platform_limit);
171b93f47eaSRoger Pau Monné 	if (ACPI_FAILURE(status)) {
172b93f47eaSRoger Pau Monné 		device_printf(sc->cpu_dev, "missing _PPC object\n");
173b93f47eaSRoger Pau Monné 		return (ENXIO);
174b93f47eaSRoger Pau Monné 	}
175b93f47eaSRoger Pau Monné 
176b93f47eaSRoger Pau Monné 	set_xen_guest_handle(op.u.set_pminfo.u.perf.states, sc->cpu_px_states);
177b93f47eaSRoger Pau Monné 
178b93f47eaSRoger Pau Monné 	/*
179b93f47eaSRoger Pau Monné 	 * NB: it's unclear the exact purpose of the shared_type field, or why
180b93f47eaSRoger Pau Monné 	 * it can't be calculated by Xen itself. Naively set it here to allow
181b93f47eaSRoger Pau Monné 	 * the upload to succeed.
182b93f47eaSRoger Pau Monné 	 */
183b93f47eaSRoger Pau Monné 	switch (sc->psd.coord_type) {
184b93f47eaSRoger Pau Monné 	case ACPI_DOMAIN_COORD_TYPE_SW_ALL:
185b93f47eaSRoger Pau Monné 		op.u.set_pminfo.u.perf.shared_type =
186b93f47eaSRoger Pau Monné 		    XEN_CPUPERF_SHARED_TYPE_ALL;
187b93f47eaSRoger Pau Monné 		break;
188b93f47eaSRoger Pau Monné 
189b93f47eaSRoger Pau Monné 	case ACPI_DOMAIN_COORD_TYPE_HW_ALL:
190b93f47eaSRoger Pau Monné 		op.u.set_pminfo.u.perf.shared_type =
191b93f47eaSRoger Pau Monné 		    XEN_CPUPERF_SHARED_TYPE_HW;
192b93f47eaSRoger Pau Monné 		break;
193b93f47eaSRoger Pau Monné 
194b93f47eaSRoger Pau Monné 	case ACPI_DOMAIN_COORD_TYPE_SW_ANY:
195b93f47eaSRoger Pau Monné 		op.u.set_pminfo.u.perf.shared_type =
196b93f47eaSRoger Pau Monné 		    XEN_CPUPERF_SHARED_TYPE_ANY;
197b93f47eaSRoger Pau Monné 		break;
198b93f47eaSRoger Pau Monné 	default:
199b93f47eaSRoger Pau Monné 		device_printf(sc->cpu_dev,
200b93f47eaSRoger Pau Monné 		    "unknown coordination type %#" PRIx64 "\n",
201b93f47eaSRoger Pau Monné 		    sc->psd.coord_type);
202b93f47eaSRoger Pau Monné 		return (EINVAL);
203b93f47eaSRoger Pau Monné 	}
204b93f47eaSRoger Pau Monné 
205b93f47eaSRoger Pau Monné 	error = HYPERVISOR_platform_op(&op);
206b93f47eaSRoger Pau Monné 	if (error != 0)
207b93f47eaSRoger Pau Monné 	    device_printf(sc->cpu_dev,
208b93f47eaSRoger Pau Monné 		"ACPI ID %u Px upload failed: %d\n", sc->cpu_acpi_id, error);
209b93f47eaSRoger Pau Monné 	return (error);
210b93f47eaSRoger Pau Monné }
211b93f47eaSRoger Pau Monné 
212b93f47eaSRoger Pau Monné static int
acpi_set_pdc(const struct xen_acpi_cpu_softc * sc)213b93f47eaSRoger Pau Monné acpi_set_pdc(const struct xen_acpi_cpu_softc *sc)
214b93f47eaSRoger Pau Monné {
215b93f47eaSRoger Pau Monné 	struct xen_platform_op op = {
216b93f47eaSRoger Pau Monné 		.cmd			= XENPF_set_processor_pminfo,
217b93f47eaSRoger Pau Monné 		.interface_version	= XENPF_INTERFACE_VERSION,
218b93f47eaSRoger Pau Monné 		.u.set_pminfo.id	= -1,
219b93f47eaSRoger Pau Monné 		.u.set_pminfo.type	= XEN_PM_PDC,
220b93f47eaSRoger Pau Monné 	};
221b93f47eaSRoger Pau Monné 	uint32_t pdc[3] = {1, 1};
222b93f47eaSRoger Pau Monné 	ACPI_OBJECT arg = {
223b93f47eaSRoger Pau Monné 		.Buffer.Type = ACPI_TYPE_BUFFER,
224b93f47eaSRoger Pau Monné 		.Buffer.Length = sizeof(pdc),
225b93f47eaSRoger Pau Monné 		.Buffer.Pointer = (uint8_t *)pdc,
226b93f47eaSRoger Pau Monné 	};
227b93f47eaSRoger Pau Monné 	ACPI_OBJECT_LIST arglist = {
228b93f47eaSRoger Pau Monné 		.Pointer = &arg,
229b93f47eaSRoger Pau Monné 		.Count = 1,
230b93f47eaSRoger Pau Monné 	};
231b93f47eaSRoger Pau Monné 	ACPI_STATUS status;
232b93f47eaSRoger Pau Monné 	int error;
233b93f47eaSRoger Pau Monné 
234b93f47eaSRoger Pau Monné 	set_xen_guest_handle(op.u.set_pminfo.u.pdc, pdc);
235b93f47eaSRoger Pau Monné 	error = HYPERVISOR_platform_op(&op);
236b93f47eaSRoger Pau Monné 	if (error != 0) {
237b93f47eaSRoger Pau Monné 		device_printf(sc->cpu_dev,
238b93f47eaSRoger Pau Monné 		    "unable to get _PDC features from Xen: %d\n", error);
239b93f47eaSRoger Pau Monné 		return (error);
240b93f47eaSRoger Pau Monné 	}
241b93f47eaSRoger Pau Monné 
242b93f47eaSRoger Pau Monné 	status = AcpiEvaluateObject(sc->cpu_handle, "_PDC", &arglist, NULL);
243b93f47eaSRoger Pau Monné 	if (ACPI_FAILURE(status)) {
244b93f47eaSRoger Pau Monné 		device_printf(sc->cpu_dev, "unable to execute _PDC - %s\n",
245b93f47eaSRoger Pau Monné 		    AcpiFormatException(status));
246b93f47eaSRoger Pau Monné 		return (ENXIO);
247b93f47eaSRoger Pau Monné 	}
248b93f47eaSRoger Pau Monné 
249b93f47eaSRoger Pau Monné 	return (0);
250b93f47eaSRoger Pau Monné }
251b93f47eaSRoger Pau Monné 
252b93f47eaSRoger Pau Monné /*
253b93f47eaSRoger Pau Monné  * Parse a _CST package and set up its Cx states.  Since the _CST object
254b93f47eaSRoger Pau Monné  * can change dynamically, our notify handler may call this function
255b93f47eaSRoger Pau Monné  * to clean up and probe the new _CST package.
256b93f47eaSRoger Pau Monné  */
257b93f47eaSRoger Pau Monné static int
acpi_fetch_cx(struct xen_acpi_cpu_softc * sc)258b93f47eaSRoger Pau Monné acpi_fetch_cx(struct xen_acpi_cpu_softc *sc)
259b93f47eaSRoger Pau Monné {
260b93f47eaSRoger Pau Monné 	ACPI_STATUS status;
261b93f47eaSRoger Pau Monné 	ACPI_BUFFER buf = {
262b93f47eaSRoger Pau Monné 		.Length = ACPI_ALLOCATE_BUFFER,
263b93f47eaSRoger Pau Monné 	};
264b93f47eaSRoger Pau Monné 	ACPI_OBJECT *top;
265b93f47eaSRoger Pau Monné 	uint32_t count;
266b93f47eaSRoger Pau Monné 	unsigned int i;
267b93f47eaSRoger Pau Monné 
268b93f47eaSRoger Pau Monné 	status = AcpiEvaluateObject(sc->cpu_handle, "_CST", NULL, &buf);
269b93f47eaSRoger Pau Monné 	if (ACPI_FAILURE(status)) {
270b93f47eaSRoger Pau Monné 		device_printf(sc->cpu_dev, "missing _CST object\n");
271b93f47eaSRoger Pau Monné 		return (ENXIO);
272b93f47eaSRoger Pau Monné 	}
273b93f47eaSRoger Pau Monné 
274b93f47eaSRoger Pau Monné 	/* _CST is a package with a count and at least one Cx package. */
275b93f47eaSRoger Pau Monné 	top = (ACPI_OBJECT *)buf.Pointer;
276b93f47eaSRoger Pau Monné 	if (!ACPI_PKG_VALID(top, 2) || acpi_PkgInt32(top, 0, &count) != 0) {
277b93f47eaSRoger Pau Monné 		device_printf(sc->cpu_dev, "invalid _CST package\n");
278b93f47eaSRoger Pau Monné 		AcpiOsFree(buf.Pointer);
279b93f47eaSRoger Pau Monné 		return (ENXIO);
280b93f47eaSRoger Pau Monné 	}
281b93f47eaSRoger Pau Monné 	if (count != top->Package.Count - 1) {
282b93f47eaSRoger Pau Monné 		device_printf(sc->cpu_dev,
283b93f47eaSRoger Pau Monné 		    "invalid _CST state count (%u != %u)\n",
284b93f47eaSRoger Pau Monné 		    count, top->Package.Count - 1);
285b93f47eaSRoger Pau Monné 		count = top->Package.Count - 1;
286b93f47eaSRoger Pau Monné 	}
287b93f47eaSRoger Pau Monné 
288b93f47eaSRoger Pau Monné 	sc->cpu_cx_states = mallocarray(count, sizeof(struct xen_processor_cx),
289b93f47eaSRoger Pau Monné 	    M_XENACPI, M_WAITOK | M_ZERO);
290b93f47eaSRoger Pau Monné 
291b93f47eaSRoger Pau Monné 	sc->cpu_cx_count = 0;
292b93f47eaSRoger Pau Monné 	for (i = 0; i < count; i++) {
293b93f47eaSRoger Pau Monné 		uint32_t type;
294b93f47eaSRoger Pau Monné 		ACPI_GENERIC_ADDRESS gas;
295b93f47eaSRoger Pau Monné 		ACPI_OBJECT *pkg = &top->Package.Elements[i + 1];
296b93f47eaSRoger Pau Monné 		struct xen_processor_cx *cx_ptr =
297b93f47eaSRoger Pau Monné 		    &sc->cpu_cx_states[sc->cpu_cx_count];
298b93f47eaSRoger Pau Monné 
299b93f47eaSRoger Pau Monné 		if (!ACPI_PKG_VALID(pkg, 4) ||
300b93f47eaSRoger Pau Monné 		    acpi_PkgInt32(pkg, 1, &type) != 0 ||
301b93f47eaSRoger Pau Monné 		    acpi_PkgInt32(pkg, 2, &cx_ptr->latency) != 0 ||
302b93f47eaSRoger Pau Monné 		    acpi_PkgInt32(pkg, 3, &cx_ptr->power) != 0 ||
303b93f47eaSRoger Pau Monné 		    acpi_get_gas(pkg, 0, &gas) != 0) {
304b93f47eaSRoger Pau Monné 			device_printf(sc->cpu_dev,
305b93f47eaSRoger Pau Monné 			    "skipping invalid _CST %u package\n",
306b93f47eaSRoger Pau Monné 			    i + 1);
307b93f47eaSRoger Pau Monné 			continue;
308b93f47eaSRoger Pau Monné 		}
309b93f47eaSRoger Pau Monné 
310b93f47eaSRoger Pau Monné 		cx_ptr->type = type;
311b93f47eaSRoger Pau Monné 		cx_ptr->reg.space_id = gas.SpaceId;
312b93f47eaSRoger Pau Monné 		cx_ptr->reg.bit_width = gas.BitWidth;
313b93f47eaSRoger Pau Monné 		cx_ptr->reg.bit_offset = gas.BitOffset;
314b93f47eaSRoger Pau Monné 		cx_ptr->reg.access_size = gas.AccessWidth;
315b93f47eaSRoger Pau Monné 		cx_ptr->reg.address = gas.Address;
316b93f47eaSRoger Pau Monné 		sc->cpu_cx_count++;
317b93f47eaSRoger Pau Monné 	}
318b93f47eaSRoger Pau Monné 	AcpiOsFree(buf.Pointer);
319b93f47eaSRoger Pau Monné 
320b93f47eaSRoger Pau Monné 	if (sc->cpu_cx_count == 0) {
321b93f47eaSRoger Pau Monné 		device_printf(sc->cpu_dev, "no valid _CST package found\n");
322b93f47eaSRoger Pau Monné 		free(sc->cpu_cx_states, M_XENACPI);
323b93f47eaSRoger Pau Monné 		sc->cpu_cx_states = NULL;
324b93f47eaSRoger Pau Monné 		return (ENXIO);
325b93f47eaSRoger Pau Monné 	}
326b93f47eaSRoger Pau Monné 
327b93f47eaSRoger Pau Monné 	return (0);
328b93f47eaSRoger Pau Monné }
329b93f47eaSRoger Pau Monné 
330b93f47eaSRoger Pau Monné /* Probe and setup any valid performance states (Px). */
331b93f47eaSRoger Pau Monné static int
acpi_fetch_px(struct xen_acpi_cpu_softc * sc)332b93f47eaSRoger Pau Monné acpi_fetch_px(struct xen_acpi_cpu_softc *sc)
333b93f47eaSRoger Pau Monné {
334b93f47eaSRoger Pau Monné 	ACPI_BUFFER buf = {
335b93f47eaSRoger Pau Monné 		.Length = ACPI_ALLOCATE_BUFFER,
336b93f47eaSRoger Pau Monné 	};
337b93f47eaSRoger Pau Monné 	ACPI_OBJECT *pkg, *res;
338b93f47eaSRoger Pau Monné 	ACPI_STATUS status;
339b93f47eaSRoger Pau Monné 	unsigned int count, i;
340b93f47eaSRoger Pau Monné 	int error;
341b93f47eaSRoger Pau Monné 	uint64_t *p;
342b93f47eaSRoger Pau Monné 
343b93f47eaSRoger Pau Monné 	/* _PSS */
344b93f47eaSRoger Pau Monné 	status = AcpiEvaluateObject(sc->cpu_handle, "_PSS", NULL, &buf);
345b93f47eaSRoger Pau Monné 	if (ACPI_FAILURE(status)) {
346b93f47eaSRoger Pau Monné 		device_printf(sc->cpu_dev, "missing _PSS object\n");
347b93f47eaSRoger Pau Monné 		return (ENXIO);
348b93f47eaSRoger Pau Monné 	}
349b93f47eaSRoger Pau Monné 
350b93f47eaSRoger Pau Monné 	pkg = (ACPI_OBJECT *)buf.Pointer;
351b93f47eaSRoger Pau Monné 	if (!ACPI_PKG_VALID(pkg, 1)) {
352b93f47eaSRoger Pau Monné 		device_printf(sc->cpu_dev, "invalid top level _PSS package\n");
353b93f47eaSRoger Pau Monné 		goto error;
354b93f47eaSRoger Pau Monné 	}
355b93f47eaSRoger Pau Monné 	count = pkg->Package.Count;
356b93f47eaSRoger Pau Monné 
357b93f47eaSRoger Pau Monné 	sc->cpu_px_states = mallocarray(count, sizeof(struct xen_processor_px),
358b93f47eaSRoger Pau Monné 	    M_XENACPI, M_WAITOK | M_ZERO);
359b93f47eaSRoger Pau Monné 
360b93f47eaSRoger Pau Monné 	/*
361b93f47eaSRoger Pau Monné 	 * Each state is a package of {CoreFreq, Power, TransitionLatency,
362b93f47eaSRoger Pau Monné 	 * BusMasterLatency, ControlVal, StatusVal}, sorted from highest
363b93f47eaSRoger Pau Monné 	 * performance to lowest.
364b93f47eaSRoger Pau Monné 	 */
365b93f47eaSRoger Pau Monné 	sc->cpu_px_count = 0;
366b93f47eaSRoger Pau Monné 	for (i = 0; i < count; i++) {
367b93f47eaSRoger Pau Monné 		unsigned int j;
368b93f47eaSRoger Pau Monné 
369b93f47eaSRoger Pau Monné 		res = &pkg->Package.Elements[i];
370b93f47eaSRoger Pau Monné 		if (!ACPI_PKG_VALID(res, 6)) {
371b93f47eaSRoger Pau Monné 			device_printf(sc->cpu_dev,
372b93f47eaSRoger Pau Monné 			    "invalid _PSS package idx %u\n", i);
373b93f47eaSRoger Pau Monné 			continue;
374b93f47eaSRoger Pau Monné 		}
375b93f47eaSRoger Pau Monné 
376b93f47eaSRoger Pau Monné 		/* Parse the rest of the package into the struct. */
377b93f47eaSRoger Pau Monné 		p = (uint64_t *)&sc->cpu_px_states[sc->cpu_px_count++];
378b93f47eaSRoger Pau Monné 		for (j = 0; j < 6; j++, p++)
379b93f47eaSRoger Pau Monné 			acpi_PkgInt(res, j, p);
380b93f47eaSRoger Pau Monné 	}
381b93f47eaSRoger Pau Monné 
382b93f47eaSRoger Pau Monné 	/* No valid Px state found so give up. */
383b93f47eaSRoger Pau Monné 	if (sc->cpu_px_count == 0) {
384b93f47eaSRoger Pau Monné 		device_printf(sc->cpu_dev, "no valid _PSS package found\n");
385b93f47eaSRoger Pau Monné 		goto error;
386b93f47eaSRoger Pau Monné 	}
387b93f47eaSRoger Pau Monné 	AcpiOsFree(buf.Pointer);
388b93f47eaSRoger Pau Monné 
389b93f47eaSRoger Pau Monné 	/* _PCT */
390b93f47eaSRoger Pau Monné 	buf.Pointer = NULL;
391b93f47eaSRoger Pau Monné 	buf.Length = ACPI_ALLOCATE_BUFFER;
392b93f47eaSRoger Pau Monné 	status = AcpiEvaluateObject(sc->cpu_handle, "_PCT", NULL, &buf);
393b93f47eaSRoger Pau Monné 	if (ACPI_FAILURE(status)) {
394b93f47eaSRoger Pau Monné 		device_printf(sc->cpu_dev, "missing _PCT object\n");
395b93f47eaSRoger Pau Monné 		goto error;
396b93f47eaSRoger Pau Monné 	}
397b93f47eaSRoger Pau Monné 
398b93f47eaSRoger Pau Monné 	/* Check the package of two registers, each a Buffer in GAS format. */
399b93f47eaSRoger Pau Monné 	pkg = (ACPI_OBJECT *)buf.Pointer;
400b93f47eaSRoger Pau Monné 	if (!ACPI_PKG_VALID(pkg, 2)) {
401b93f47eaSRoger Pau Monné 		device_printf(sc->cpu_dev, "invalid top level _PCT package\n");
402b93f47eaSRoger Pau Monné 		goto error;
403b93f47eaSRoger Pau Monné 	}
404b93f47eaSRoger Pau Monné 
405b93f47eaSRoger Pau Monné 	error = acpi_get_pct(pkg, 0, &sc->control_register);
406b93f47eaSRoger Pau Monné 	if (error != 0) {
407b93f47eaSRoger Pau Monné 		device_printf(sc->cpu_dev,
408b93f47eaSRoger Pau Monné 		    "unable to fetch _PCT control register: %d\n", error);
409b93f47eaSRoger Pau Monné 		goto error;
410b93f47eaSRoger Pau Monné 	}
411b93f47eaSRoger Pau Monné 	error = acpi_get_pct(pkg, 1, &sc->status_register);
412b93f47eaSRoger Pau Monné 	if (error != 0) {
413b93f47eaSRoger Pau Monné 		device_printf(sc->cpu_dev,
414b93f47eaSRoger Pau Monné 		    "unable to fetch _PCT status register: %d\n", error);
415b93f47eaSRoger Pau Monné 		goto error;
416b93f47eaSRoger Pau Monné 	}
417b93f47eaSRoger Pau Monné 	AcpiOsFree(buf.Pointer);
418b93f47eaSRoger Pau Monné 
419b93f47eaSRoger Pau Monné 	/* _PSD */
420b93f47eaSRoger Pau Monné 	buf.Pointer = NULL;
421b93f47eaSRoger Pau Monné 	buf.Length = ACPI_ALLOCATE_BUFFER;
422b93f47eaSRoger Pau Monné 	status = AcpiEvaluateObject(sc->cpu_handle, "_PSD", NULL, &buf);
423b93f47eaSRoger Pau Monné 	if (ACPI_FAILURE(status)) {
424b93f47eaSRoger Pau Monné 		device_printf(sc->cpu_dev, "missing _PSD object\n");
425b93f47eaSRoger Pau Monné 		goto error;
426b93f47eaSRoger Pau Monné 	}
427b93f47eaSRoger Pau Monné 
428b93f47eaSRoger Pau Monné 	pkg = (ACPI_OBJECT *)buf.Pointer;
429b93f47eaSRoger Pau Monné 	if (!ACPI_PKG_VALID(pkg, 1)) {
430b93f47eaSRoger Pau Monné 		device_printf(sc->cpu_dev, "invalid top level _PSD package\n");
431b93f47eaSRoger Pau Monné 		goto error;
432b93f47eaSRoger Pau Monné 	}
433b93f47eaSRoger Pau Monné 
434b93f47eaSRoger Pau Monné 	res = &pkg->Package.Elements[0];
435b93f47eaSRoger Pau Monné 	if (!ACPI_PKG_VALID(res, 5)) {
436b93f47eaSRoger Pau Monné 		printf("invalid _PSD package\n");
437b93f47eaSRoger Pau Monné 		goto error;
438b93f47eaSRoger Pau Monné 	}
439b93f47eaSRoger Pau Monné 
440b93f47eaSRoger Pau Monné 	p = (uint64_t *)&sc->psd;
441b93f47eaSRoger Pau Monné 	for (i = 0; i < 5; i++, p++)
442b93f47eaSRoger Pau Monné 		acpi_PkgInt(res, i, p);
443b93f47eaSRoger Pau Monné 	AcpiOsFree(buf.Pointer);
444b93f47eaSRoger Pau Monné 
445b93f47eaSRoger Pau Monné 	return (0);
446b93f47eaSRoger Pau Monné 
447b93f47eaSRoger Pau Monné error:
448b93f47eaSRoger Pau Monné 	if (buf.Pointer != NULL)
449b93f47eaSRoger Pau Monné 		AcpiOsFree(buf.Pointer);
450b93f47eaSRoger Pau Monné 	if (sc->cpu_px_states != NULL) {
451b93f47eaSRoger Pau Monné 		free(sc->cpu_px_states, M_XENACPI);
452b93f47eaSRoger Pau Monné 		sc->cpu_px_states = NULL;
453b93f47eaSRoger Pau Monné 	}
454b93f47eaSRoger Pau Monné 	return (ENXIO);
455b93f47eaSRoger Pau Monné }
456b93f47eaSRoger Pau Monné 
457b93f47eaSRoger Pau Monné static void
acpi_notify(ACPI_HANDLE h,UINT32 notify,void * context)458b93f47eaSRoger Pau Monné acpi_notify(ACPI_HANDLE h, UINT32 notify, void *context)
459b93f47eaSRoger Pau Monné {
460b93f47eaSRoger Pau Monné 	struct xen_acpi_cpu_softc *sc = context;
461b93f47eaSRoger Pau Monné 
462b93f47eaSRoger Pau Monné 	switch (notify) {
463b93f47eaSRoger Pau Monné 	case ACPI_NOTIFY_PERF_STATES:
464b93f47eaSRoger Pau Monné 		if (acpi_fetch_px(sc) != 0)
465b93f47eaSRoger Pau Monné 			break;
466b93f47eaSRoger Pau Monné 		xen_upload_px(sc);
467b93f47eaSRoger Pau Monné 		free(sc->cpu_px_states, M_XENACPI);
468b93f47eaSRoger Pau Monné 		sc->cpu_px_states = NULL;
469b93f47eaSRoger Pau Monné 		break;
470b93f47eaSRoger Pau Monné 
471b93f47eaSRoger Pau Monné 	case ACPI_NOTIFY_CX_STATES:
472b93f47eaSRoger Pau Monné 		if (acpi_fetch_cx(sc) != 0)
473b93f47eaSRoger Pau Monné 			break;
474b93f47eaSRoger Pau Monné 		xen_upload_cx(sc);
475b93f47eaSRoger Pau Monné 		free(sc->cpu_cx_states, M_XENACPI);
476b93f47eaSRoger Pau Monné 		sc->cpu_cx_states = NULL;
477b93f47eaSRoger Pau Monné 		break;
478b93f47eaSRoger Pau Monné 	}
479b93f47eaSRoger Pau Monné }
480b93f47eaSRoger Pau Monné 
481b93f47eaSRoger Pau Monné static int
xen_acpi_cpu_probe(device_t dev)482b93f47eaSRoger Pau Monné xen_acpi_cpu_probe(device_t dev)
483b93f47eaSRoger Pau Monné {
484b93f47eaSRoger Pau Monné 	static char *cpudev_ids[] = { CPUDEV_DEVICE_ID, NULL };
485b93f47eaSRoger Pau Monné 	ACPI_OBJECT_TYPE type = acpi_get_type(dev);
486b93f47eaSRoger Pau Monné 
487b93f47eaSRoger Pau Monné 	if (!xen_initial_domain())
488b93f47eaSRoger Pau Monné 		return (ENXIO);
489b93f47eaSRoger Pau Monné 	if (type != ACPI_TYPE_PROCESSOR && type != ACPI_TYPE_DEVICE)
490b93f47eaSRoger Pau Monné 		return (ENXIO);
491b93f47eaSRoger Pau Monné 	if (type == ACPI_TYPE_DEVICE &&
492b93f47eaSRoger Pau Monné 	    ACPI_ID_PROBE(device_get_parent(dev), dev, cpudev_ids, NULL) >= 0)
493b93f47eaSRoger Pau Monné 		return (ENXIO);
494b93f47eaSRoger Pau Monné 
495b93f47eaSRoger Pau Monné 	device_set_desc(dev, "XEN ACPI CPU");
496b93f47eaSRoger Pau Monné 	if (!bootverbose)
497b93f47eaSRoger Pau Monné 		device_quiet(dev);
498b93f47eaSRoger Pau Monné 
499b93f47eaSRoger Pau Monné 	/*
500b93f47eaSRoger Pau Monné 	 * Use SPECIFIC because when running as a Xen dom0 the ACPI PROCESSOR
501b93f47eaSRoger Pau Monné 	 * data is the native one, and needs to be forwarded to Xen but not
502b93f47eaSRoger Pau Monné 	 * used by FreeBSD itself.
503b93f47eaSRoger Pau Monné 	 */
504b93f47eaSRoger Pau Monné 	return (BUS_PROBE_SPECIFIC);
505b93f47eaSRoger Pau Monné }
506b93f47eaSRoger Pau Monné 
507*bc9a5b04SRoger Pau Monné static bool
is_processor_online(unsigned int acpi_id)508*bc9a5b04SRoger Pau Monné is_processor_online(unsigned int acpi_id)
509*bc9a5b04SRoger Pau Monné {
510*bc9a5b04SRoger Pau Monné 	unsigned int i, maxid;
511*bc9a5b04SRoger Pau Monné 	struct xen_platform_op op = {
512*bc9a5b04SRoger Pau Monné 		.cmd = XENPF_get_cpuinfo,
513*bc9a5b04SRoger Pau Monné 	};
514*bc9a5b04SRoger Pau Monné 	int ret = HYPERVISOR_platform_op(&op);
515*bc9a5b04SRoger Pau Monné 
516*bc9a5b04SRoger Pau Monné 	if (ret)
517*bc9a5b04SRoger Pau Monné 		return (false);
518*bc9a5b04SRoger Pau Monné 
519*bc9a5b04SRoger Pau Monné 	maxid = op.u.pcpu_info.max_present;
520*bc9a5b04SRoger Pau Monné 	for (i = 0; i <= maxid; i++) {
521*bc9a5b04SRoger Pau Monné 		op.u.pcpu_info.xen_cpuid = i;
522*bc9a5b04SRoger Pau Monné 		ret = HYPERVISOR_platform_op(&op);
523*bc9a5b04SRoger Pau Monné 		if (ret)
524*bc9a5b04SRoger Pau Monné 			continue;
525*bc9a5b04SRoger Pau Monné 		if (op.u.pcpu_info.acpi_id == acpi_id)
526*bc9a5b04SRoger Pau Monné 			return (op.u.pcpu_info.flags & XEN_PCPU_FLAGS_ONLINE);
527*bc9a5b04SRoger Pau Monné 	}
528*bc9a5b04SRoger Pau Monné 
529*bc9a5b04SRoger Pau Monné 	return (false);
530*bc9a5b04SRoger Pau Monné }
531*bc9a5b04SRoger Pau Monné 
532b93f47eaSRoger Pau Monné static int
xen_acpi_cpu_attach(device_t dev)533b93f47eaSRoger Pau Monné xen_acpi_cpu_attach(device_t dev)
534b93f47eaSRoger Pau Monné {
535b93f47eaSRoger Pau Monné 	struct xen_acpi_cpu_softc *sc = device_get_softc(dev);
536b93f47eaSRoger Pau Monné 	ACPI_STATUS status;
537b93f47eaSRoger Pau Monné 	int error;
538b93f47eaSRoger Pau Monné 
539b93f47eaSRoger Pau Monné 	sc->cpu_dev = dev;
540b93f47eaSRoger Pau Monné 	sc->cpu_handle = acpi_get_handle(dev);
541b93f47eaSRoger Pau Monné 
542b93f47eaSRoger Pau Monné 	if (acpi_get_type(dev) == ACPI_TYPE_PROCESSOR) {
543b93f47eaSRoger Pau Monné 		ACPI_BUFFER buf = {
544b93f47eaSRoger Pau Monné 			.Length = ACPI_ALLOCATE_BUFFER,
545b93f47eaSRoger Pau Monné 		};
546b93f47eaSRoger Pau Monné 		ACPI_OBJECT *obj;
547b93f47eaSRoger Pau Monné 
548b93f47eaSRoger Pau Monné 		status = AcpiEvaluateObject(sc->cpu_handle, NULL, NULL, &buf);
549b93f47eaSRoger Pau Monné 		if (ACPI_FAILURE(status)) {
550b93f47eaSRoger Pau Monné 			device_printf(dev,
551b93f47eaSRoger Pau Monné 			    "attach failed to get Processor obj - %s\n",
552b93f47eaSRoger Pau Monné 			    AcpiFormatException(status));
553b93f47eaSRoger Pau Monné 			return (ENXIO);
554b93f47eaSRoger Pau Monné 		}
555b93f47eaSRoger Pau Monné 		obj = (ACPI_OBJECT *)buf.Pointer;
556b93f47eaSRoger Pau Monné 		sc->cpu_acpi_id = obj->Processor.ProcId;
557b93f47eaSRoger Pau Monné 		AcpiOsFree(obj);
558b93f47eaSRoger Pau Monné 	} else {
559b93f47eaSRoger Pau Monné 		KASSERT(acpi_get_type(dev) == ACPI_TYPE_DEVICE,
560b93f47eaSRoger Pau Monné 		    ("Unexpected ACPI object"));
561b93f47eaSRoger Pau Monné 		status = acpi_GetInteger(sc->cpu_handle, "_UID",
562b93f47eaSRoger Pau Monné 		    &sc->cpu_acpi_id);
563b93f47eaSRoger Pau Monné 		if (ACPI_FAILURE(status)) {
564b93f47eaSRoger Pau Monné 			device_printf(dev, "device object has bad value - %s\n",
565b93f47eaSRoger Pau Monné 			    AcpiFormatException(status));
566b93f47eaSRoger Pau Monné 			return (ENXIO);
567b93f47eaSRoger Pau Monné 		}
568b93f47eaSRoger Pau Monné 	}
569b93f47eaSRoger Pau Monné 
570*bc9a5b04SRoger Pau Monné 	if (!is_processor_online(sc->cpu_acpi_id))
571*bc9a5b04SRoger Pau Monné 		/* Processor is not online, attach the driver and ignore it. */
572*bc9a5b04SRoger Pau Monné 		return (0);
573*bc9a5b04SRoger Pau Monné 
574b93f47eaSRoger Pau Monné 	/*
575b93f47eaSRoger Pau Monné 	 * Install the notify handler now: even if we fail to parse or upload
576b93f47eaSRoger Pau Monné 	 * the states it shouldn't prevent us from attempting to parse further
577b93f47eaSRoger Pau Monné 	 * updates.
578b93f47eaSRoger Pau Monné 	 */
579b93f47eaSRoger Pau Monné 	status = AcpiInstallNotifyHandler(sc->cpu_handle, ACPI_DEVICE_NOTIFY,
580b93f47eaSRoger Pau Monné 	    acpi_notify, sc);
581b93f47eaSRoger Pau Monné 	if (ACPI_FAILURE(status))
582b93f47eaSRoger Pau Monné 		device_printf(dev, "failed to register notify handler - %s\n",
583b93f47eaSRoger Pau Monné 		    AcpiFormatException(status));
584b93f47eaSRoger Pau Monné 
585b93f47eaSRoger Pau Monné 	/*
586b93f47eaSRoger Pau Monné 	 * Don't report errors: it's likely there are processor objects
587b93f47eaSRoger Pau Monné 	 * belonging to CPUs that are not online, but the MADT provided to
588b93f47eaSRoger Pau Monné 	 * FreeBSD is crafted to report the number of CPUs available to dom0.
589b93f47eaSRoger Pau Monné 	 *
590b93f47eaSRoger Pau Monné 	 * Parsing or uploading those states could result in errors, just
591b93f47eaSRoger Pau Monné 	 * ignore them in order to avoid pointless noise.
592b93f47eaSRoger Pau Monné 	 */
593b93f47eaSRoger Pau Monné 	error = acpi_set_pdc(sc);
594b93f47eaSRoger Pau Monné 	if (error != 0)
595b93f47eaSRoger Pau Monné 		return (0);
596b93f47eaSRoger Pau Monné 
597b93f47eaSRoger Pau Monné 	error = acpi_fetch_px(sc);
598b93f47eaSRoger Pau Monné 	if (error != 0)
599b93f47eaSRoger Pau Monné 		return (0);
600b93f47eaSRoger Pau Monné 	error = xen_upload_px(sc);
601b93f47eaSRoger Pau Monné 	free(sc->cpu_px_states, M_XENACPI);
602b93f47eaSRoger Pau Monné 	sc->cpu_px_states = NULL;
603b93f47eaSRoger Pau Monné 	if (error != 0)
604b93f47eaSRoger Pau Monné 		return (0);
605b93f47eaSRoger Pau Monné 
606b93f47eaSRoger Pau Monné 	error = acpi_fetch_cx(sc);
607b93f47eaSRoger Pau Monné 	if (error != 0)
608b93f47eaSRoger Pau Monné 		return (0);
609b93f47eaSRoger Pau Monné 	xen_upload_cx(sc);
610b93f47eaSRoger Pau Monné 	free(sc->cpu_cx_states, M_XENACPI);
611b93f47eaSRoger Pau Monné 	sc->cpu_cx_states = NULL;
612b93f47eaSRoger Pau Monné 
613b93f47eaSRoger Pau Monné 	return (0);
614b93f47eaSRoger Pau Monné }
615b93f47eaSRoger Pau Monné 
616b93f47eaSRoger Pau Monné static device_method_t xen_acpi_cpu_methods[] = {
617b93f47eaSRoger Pau Monné     /* Device interface */
618b93f47eaSRoger Pau Monné     DEVMETHOD(device_probe, xen_acpi_cpu_probe),
619b93f47eaSRoger Pau Monné     DEVMETHOD(device_attach, xen_acpi_cpu_attach),
620b93f47eaSRoger Pau Monné 
621b93f47eaSRoger Pau Monné     DEVMETHOD_END
622b93f47eaSRoger Pau Monné };
623b93f47eaSRoger Pau Monné 
624b93f47eaSRoger Pau Monné static driver_t xen_acpi_cpu_driver = {
625b93f47eaSRoger Pau Monné     "xen cpu",
626b93f47eaSRoger Pau Monné     xen_acpi_cpu_methods,
627b93f47eaSRoger Pau Monné     sizeof(struct xen_acpi_cpu_softc),
628b93f47eaSRoger Pau Monné };
629b93f47eaSRoger Pau Monné 
630f929eb1eSJohn Baldwin DRIVER_MODULE(xen_cpu, acpi, xen_acpi_cpu_driver, 0, 0);
631b93f47eaSRoger Pau Monné MODULE_DEPEND(xen_cpu, acpi, 1, 1, 1);
632