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