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 int 510 xen_acpi_cpu_attach(device_t dev) 511 { 512 struct xen_acpi_cpu_softc *sc = device_get_softc(dev); 513 ACPI_STATUS status; 514 int error; 515 516 sc->cpu_dev = dev; 517 sc->cpu_handle = acpi_get_handle(dev); 518 519 if (acpi_get_type(dev) == ACPI_TYPE_PROCESSOR) { 520 ACPI_BUFFER buf = { 521 .Length = ACPI_ALLOCATE_BUFFER, 522 }; 523 ACPI_OBJECT *obj; 524 525 status = AcpiEvaluateObject(sc->cpu_handle, NULL, NULL, &buf); 526 if (ACPI_FAILURE(status)) { 527 device_printf(dev, 528 "attach failed to get Processor obj - %s\n", 529 AcpiFormatException(status)); 530 return (ENXIO); 531 } 532 obj = (ACPI_OBJECT *)buf.Pointer; 533 sc->cpu_acpi_id = obj->Processor.ProcId; 534 AcpiOsFree(obj); 535 } else { 536 KASSERT(acpi_get_type(dev) == ACPI_TYPE_DEVICE, 537 ("Unexpected ACPI object")); 538 status = acpi_GetInteger(sc->cpu_handle, "_UID", 539 &sc->cpu_acpi_id); 540 if (ACPI_FAILURE(status)) { 541 device_printf(dev, "device object has bad value - %s\n", 542 AcpiFormatException(status)); 543 return (ENXIO); 544 } 545 } 546 547 /* 548 * Install the notify handler now: even if we fail to parse or upload 549 * the states it shouldn't prevent us from attempting to parse further 550 * updates. 551 */ 552 status = AcpiInstallNotifyHandler(sc->cpu_handle, ACPI_DEVICE_NOTIFY, 553 acpi_notify, sc); 554 if (ACPI_FAILURE(status)) 555 device_printf(dev, "failed to register notify handler - %s\n", 556 AcpiFormatException(status)); 557 558 /* 559 * Don't report errors: it's likely there are processor objects 560 * belonging to CPUs that are not online, but the MADT provided to 561 * FreeBSD is crafted to report the number of CPUs available to dom0. 562 * 563 * Parsing or uploading those states could result in errors, just 564 * ignore them in order to avoid pointless noise. 565 */ 566 error = acpi_set_pdc(sc); 567 if (error != 0) 568 return (0); 569 570 error = acpi_fetch_px(sc); 571 if (error != 0) 572 return (0); 573 error = xen_upload_px(sc); 574 free(sc->cpu_px_states, M_XENACPI); 575 sc->cpu_px_states = NULL; 576 if (error != 0) 577 return (0); 578 579 error = acpi_fetch_cx(sc); 580 if (error != 0) 581 return (0); 582 xen_upload_cx(sc); 583 free(sc->cpu_cx_states, M_XENACPI); 584 sc->cpu_cx_states = NULL; 585 586 return (0); 587 } 588 589 static device_method_t xen_acpi_cpu_methods[] = { 590 /* Device interface */ 591 DEVMETHOD(device_probe, xen_acpi_cpu_probe), 592 DEVMETHOD(device_attach, xen_acpi_cpu_attach), 593 594 DEVMETHOD_END 595 }; 596 597 static driver_t xen_acpi_cpu_driver = { 598 "xen cpu", 599 xen_acpi_cpu_methods, 600 sizeof(struct xen_acpi_cpu_softc), 601 }; 602 603 DRIVER_MODULE(xen_cpu, acpi, xen_acpi_cpu_driver, 0, 0); 604 MODULE_DEPEND(xen_cpu, acpi, 1, 1, 1); 605