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