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
acpi_get_gas(const ACPI_OBJECT * res,unsigned int idx,ACPI_GENERIC_ADDRESS * gas)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
acpi_get_pct(const ACPI_OBJECT * res,unsigned int idx,struct xen_pct_register * reg)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
xen_upload_cx(struct xen_acpi_cpu_softc * sc)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
xen_upload_px(struct xen_acpi_cpu_softc * sc)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
acpi_set_pdc(const struct xen_acpi_cpu_softc * sc)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
acpi_fetch_cx(struct xen_acpi_cpu_softc * sc)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
acpi_fetch_px(struct xen_acpi_cpu_softc * sc)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
acpi_notify(ACPI_HANDLE h,UINT32 notify,void * context)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
xen_acpi_cpu_probe(device_t dev)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
is_processor_online(unsigned int acpi_id)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
xen_acpi_cpu_attach(device_t dev)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