1 /* $NetBSD: acpi_util.c,v 1.32 2022/01/22 11:49:17 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 2003, 2007, 2021 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Charles M. Hannum of By Noon Software, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright 2001, 2003 Wasabi Systems, Inc. 34 * All rights reserved. 35 * 36 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 37 * 38 * Redistribution and use in source and binary forms, with or without 39 * modification, are permitted provided that the following conditions 40 * are met: 41 * 1. Redistributions of source code must retain the above copyright 42 * notice, this list of conditions and the following disclaimer. 43 * 2. Redistributions in binary form must reproduce the above copyright 44 * notice, this list of conditions and the following disclaimer in the 45 * documentation and/or other materials provided with the distribution. 46 * 3. All advertising materials mentioning features or use of this software 47 * must display the following acknowledgement: 48 * This product includes software developed for the NetBSD Project by 49 * Wasabi Systems, Inc. 50 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 51 * or promote products derived from this software without specific prior 52 * written permission. 53 * 54 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 56 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 57 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 58 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 59 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 60 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 61 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 62 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 63 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 64 * POSSIBILITY OF SUCH DAMAGE. 65 */ 66 67 #include <sys/cdefs.h> 68 __KERNEL_RCSID(0, "$NetBSD: acpi_util.c,v 1.32 2022/01/22 11:49:17 thorpej Exp $"); 69 70 #include <sys/param.h> 71 #include <sys/kmem.h> 72 #include <sys/cpu.h> 73 74 #include <dev/acpi/acpireg.h> 75 #include <dev/acpi/acpivar.h> 76 #include <dev/acpi/acpi_intr.h> 77 78 #include <sys/device_calls.h> 79 80 #include <machine/acpi_machdep.h> 81 82 #define _COMPONENT ACPI_BUS_COMPONENT 83 ACPI_MODULE_NAME ("acpi_util") 84 85 static void acpi_clean_node(ACPI_HANDLE, void *); 86 static ACPI_STATUS acpi_dsd_property(ACPI_HANDLE, const char *, 87 ACPI_BUFFER *, ACPI_OBJECT_TYPE, ACPI_OBJECT **); 88 89 static const char * const acpicpu_ids[] = { 90 "ACPI0007", 91 NULL 92 }; 93 94 static const struct device_compatible_entry dtlink_compat_data[] = { 95 { .compat = "PRP0001" }, 96 DEVICE_COMPAT_EOL 97 }; 98 99 /* 100 * ACPI device handle support. 101 */ 102 103 static device_call_t 104 acpi_devhandle_lookup_device_call(devhandle_t handle, const char *name, 105 devhandle_t *call_handlep) 106 { 107 __link_set_decl(acpi_device_calls, struct device_call_descriptor); 108 struct device_call_descriptor * const *desc; 109 110 __link_set_foreach(desc, acpi_device_calls) { 111 if (strcmp((*desc)->name, name) == 0) { 112 return (*desc)->call; 113 } 114 } 115 return NULL; 116 } 117 118 static const struct devhandle_impl acpi_devhandle_impl = { 119 .type = DEVHANDLE_TYPE_ACPI, 120 .lookup_device_call = acpi_devhandle_lookup_device_call, 121 }; 122 123 devhandle_t 124 devhandle_from_acpi(devhandle_t super_handle, ACPI_HANDLE const hdl) 125 { 126 devhandle_type_t super_type = devhandle_type(super_handle); 127 devhandle_t handle = { 0 }; 128 129 if (super_type == DEVHANDLE_TYPE_ACPI) { 130 handle.impl = super_handle.impl; 131 } else { 132 KASSERT(super_type == DEVHANDLE_TYPE_INVALID); 133 handle.impl = &acpi_devhandle_impl; 134 } 135 handle.pointer = hdl; 136 137 return handle; 138 } 139 140 ACPI_HANDLE 141 devhandle_to_acpi(devhandle_t const handle) 142 { 143 KASSERT(devhandle_type(handle) == DEVHANDLE_TYPE_ACPI); 144 145 return handle.pointer; 146 } 147 148 static int 149 acpi_device_enumerate_children(device_t dev, devhandle_t call_handle, void *v) 150 { 151 struct device_enumerate_children_args *args = v; 152 ACPI_HANDLE hdl = devhandle_to_acpi(call_handle); 153 struct acpi_devnode *devnode, *ad; 154 155 devnode = acpi_match_node(hdl); 156 KASSERT(devnode != NULL); 157 158 SIMPLEQ_FOREACH(ad, &devnode->ad_child_head, ad_child_list) { 159 if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE || 160 !acpi_device_present(ad->ad_handle)) { 161 continue; 162 } 163 if (!args->callback(dev, devhandle_from_acpi(call_handle, 164 ad->ad_handle), 165 args->callback_arg)) { 166 break; 167 } 168 } 169 170 return 0; 171 } 172 ACPI_DEVICE_CALL_REGISTER(DEVICE_ENUMERATE_CHILDREN_STR, 173 acpi_device_enumerate_children) 174 175 /* 176 * Evaluate an integer object. 177 */ 178 ACPI_STATUS 179 acpi_eval_integer(ACPI_HANDLE handle, const char *path, ACPI_INTEGER *valp) 180 { 181 ACPI_OBJECT obj; 182 ACPI_BUFFER buf; 183 ACPI_STATUS rv; 184 185 if (handle == NULL) 186 handle = ACPI_ROOT_OBJECT; 187 188 (void)memset(&obj, 0, sizeof(obj)); 189 buf.Pointer = &obj; 190 buf.Length = sizeof(obj); 191 192 rv = AcpiEvaluateObject(handle, path, NULL, &buf); 193 194 if (ACPI_FAILURE(rv)) 195 return rv; 196 197 /* Check that evaluation produced a return value. */ 198 if (buf.Length == 0) 199 return AE_NULL_OBJECT; 200 201 if (obj.Type != ACPI_TYPE_INTEGER) 202 return AE_TYPE; 203 204 if (valp != NULL) 205 *valp = obj.Integer.Value; 206 207 return AE_OK; 208 } 209 210 /* 211 * Evaluate an integer object with a single integer input parameter. 212 */ 213 ACPI_STATUS 214 acpi_eval_set_integer(ACPI_HANDLE handle, const char *path, ACPI_INTEGER val) 215 { 216 ACPI_OBJECT_LIST arg; 217 ACPI_OBJECT obj; 218 219 if (handle == NULL) 220 handle = ACPI_ROOT_OBJECT; 221 222 obj.Type = ACPI_TYPE_INTEGER; 223 obj.Integer.Value = val; 224 225 arg.Count = 1; 226 arg.Pointer = &obj; 227 228 return AcpiEvaluateObject(handle, path, &arg, NULL); 229 } 230 231 /* 232 * Evaluate a (Unicode) string object. 233 */ 234 ACPI_STATUS 235 acpi_eval_string(ACPI_HANDLE handle, const char *path, char **stringp) 236 { 237 ACPI_OBJECT *obj; 238 ACPI_BUFFER buf; 239 ACPI_STATUS rv; 240 241 rv = acpi_eval_struct(handle, path, &buf); 242 243 if (ACPI_FAILURE(rv)) 244 return rv; 245 246 obj = buf.Pointer; 247 248 if (obj->Type != ACPI_TYPE_STRING) { 249 rv = AE_TYPE; 250 goto out; 251 } 252 253 if (obj->String.Length == 0) { 254 rv = AE_BAD_DATA; 255 goto out; 256 } 257 258 *stringp = ACPI_ALLOCATE(obj->String.Length + 1); 259 260 if (*stringp == NULL) { 261 rv = AE_NO_MEMORY; 262 goto out; 263 } 264 265 (void)memcpy(*stringp, obj->String.Pointer, obj->String.Length); 266 267 (*stringp)[obj->String.Length] = '\0'; 268 269 out: 270 ACPI_FREE(buf.Pointer); 271 272 return rv; 273 } 274 275 /* 276 * Evaluate a structure. Caller must free buf.Pointer by ACPI_FREE(). 277 */ 278 ACPI_STATUS 279 acpi_eval_struct(ACPI_HANDLE handle, const char *path, ACPI_BUFFER *buf) 280 { 281 282 if (handle == NULL) 283 handle = ACPI_ROOT_OBJECT; 284 285 buf->Pointer = NULL; 286 buf->Length = ACPI_ALLOCATE_LOCAL_BUFFER; 287 288 return AcpiEvaluateObject(handle, path, NULL, buf); 289 } 290 291 /* 292 * Evaluate a reference handle from an element in a package. 293 */ 294 ACPI_STATUS 295 acpi_eval_reference_handle(ACPI_OBJECT *elm, ACPI_HANDLE *handle) 296 { 297 298 if (elm == NULL || handle == NULL) 299 return AE_BAD_PARAMETER; 300 301 switch (elm->Type) { 302 303 case ACPI_TYPE_ANY: 304 case ACPI_TYPE_LOCAL_REFERENCE: 305 306 if (elm->Reference.Handle == NULL) 307 return AE_NULL_ENTRY; 308 309 *handle = elm->Reference.Handle; 310 311 return AE_OK; 312 313 case ACPI_TYPE_STRING: 314 return AcpiGetHandle(NULL, elm->String.Pointer, handle); 315 316 default: 317 return AE_TYPE; 318 } 319 } 320 321 /* 322 * Iterate over all objects in a package, and pass them all 323 * to a function. If the called function returns non-AE_OK, 324 * the iteration is stopped and that value is returned. 325 */ 326 ACPI_STATUS 327 acpi_foreach_package_object(ACPI_OBJECT *pkg, 328 ACPI_STATUS (*func)(ACPI_OBJECT *, void *), void *arg) 329 { 330 ACPI_STATUS rv = AE_OK; 331 uint32_t i; 332 333 if (pkg == NULL) 334 return AE_BAD_PARAMETER; 335 336 if (pkg->Type != ACPI_TYPE_PACKAGE) 337 return AE_TYPE; 338 339 for (i = 0; i < pkg->Package.Count; i++) { 340 341 rv = (*func)(&pkg->Package.Elements[i], arg); 342 343 if (ACPI_FAILURE(rv)) 344 break; 345 } 346 347 return rv; 348 } 349 350 /* 351 * Fetch data info the specified (empty) ACPI buffer. 352 * Caller must free buf.Pointer by ACPI_FREE(). 353 */ 354 ACPI_STATUS 355 acpi_get(ACPI_HANDLE handle, ACPI_BUFFER *buf, 356 ACPI_STATUS (*getit)(ACPI_HANDLE, ACPI_BUFFER *)) 357 { 358 359 buf->Pointer = NULL; 360 buf->Length = ACPI_ALLOCATE_LOCAL_BUFFER; 361 362 return (*getit)(handle, buf); 363 } 364 365 /* 366 * Return a complete pathname from a handle. 367 * 368 * Note that the function uses static data storage; 369 * if the data is needed for future use, it should be 370 * copied before any subsequent calls overwrite it. 371 */ 372 const char * 373 acpi_name(ACPI_HANDLE handle) 374 { 375 static char name[80]; 376 ACPI_BUFFER buf; 377 ACPI_STATUS rv; 378 379 if (handle == NULL) 380 handle = ACPI_ROOT_OBJECT; 381 382 buf.Pointer = name; 383 buf.Length = sizeof(name); 384 385 rv = AcpiGetName(handle, ACPI_FULL_PATHNAME, &buf); 386 387 if (ACPI_FAILURE(rv)) 388 return "UNKNOWN"; 389 390 return name; 391 } 392 393 /* 394 * Pack _HID and _CID ID strings into an OpenFirmware-style 395 * string list. 396 */ 397 char * 398 acpi_pack_compat_list(ACPI_DEVICE_INFO *ad, size_t *sizep) 399 { 400 KASSERT(sizep != NULL); 401 402 char *sl = NULL; 403 size_t slsize = 0; 404 uint32_t i; 405 406 if ((ad->Valid & ACPI_VALID_HID) != 0) { 407 strlist_append(&sl, &slsize, ad->HardwareId.String); 408 } 409 410 if ((ad->Valid & ACPI_VALID_CID) != 0) { 411 for (i = 0; i < ad->CompatibleIdList.Count; i++) { 412 strlist_append(&sl, &slsize, 413 ad->CompatibleIdList.Ids[i].String); 414 } 415 } 416 417 *sizep = slsize; 418 return sl; 419 } 420 421 /* 422 * The ACPI_PNP_DEVICE_ID type is somewhat inconvenient for us to 423 * use. We'll need some temporary space to pack it into an array 424 * of C strings. Room for 8 should be plenty, but we can allocate 425 * more if necessary. 426 */ 427 #define ACPI_COMPATSTR_MAX 8 428 429 static const char ** 430 acpi_compatible_alloc_strarray(ACPI_PNP_DEVICE_ID *ids, 431 unsigned int count, const char **buf) 432 { 433 unsigned int i; 434 435 buf = kmem_tmpbuf_alloc(count * sizeof(const char *), 436 buf, ACPI_COMPATSTR_MAX * sizeof(const char *), KM_SLEEP); 437 for (i = 0; i < count; i++) { 438 buf[i] = ids[i].String; 439 } 440 return buf; 441 } 442 443 static void 444 acpi_compatible_free_strarray(const char **cpp, unsigned int count, 445 const char **buf) 446 { 447 kmem_tmpbuf_free(cpp, count * sizeof(const char *), buf); 448 } 449 450 static int 451 acpi_compatible_match_dtlink(const struct acpi_attach_args * const aa, 452 const struct device_compatible_entry * const dce) 453 { 454 const char *strings[ACPI_COMPATSTR_MAX * sizeof(const char *)]; 455 ACPI_HANDLE handle = aa->aa_node->ad_handle; 456 ACPI_BUFFER buf; 457 char *compatible; 458 ACPI_STATUS ret; 459 ACPI_OBJECT *obj; 460 int rv = 0, n; 461 462 buf.Pointer = NULL; 463 buf.Length = ACPI_ALLOCATE_BUFFER; 464 465 /* Match a single string _DSD value */ 466 ret = acpi_dsd_string(handle, "compatible", &compatible); 467 if (ACPI_SUCCESS(ret)) { 468 strings[0] = compatible; 469 rv = device_compatible_pmatch(strings, 1, dce); 470 kmem_strfree(compatible); 471 goto done; 472 } 473 474 /* Match from a list of strings in a _DSD value */ 475 ret = acpi_dsd_property(handle, "compatible", &buf, 476 ACPI_TYPE_PACKAGE, &obj); 477 if (ACPI_FAILURE(ret)) { 478 goto done; 479 } 480 if (obj->Package.Count == 0) { 481 goto done; 482 } 483 for (n = 0; n < imin(obj->Package.Count, ACPI_COMPATSTR_MAX); n++) { 484 if (obj->Package.Elements[n].Type != ACPI_TYPE_STRING) { 485 goto done; 486 } 487 strings[n] = obj->Package.Elements[n].String.Pointer; 488 } 489 rv = device_compatible_pmatch(strings, n, dce); 490 491 done: 492 if (buf.Pointer != NULL) { 493 ACPI_FREE(buf.Pointer); 494 } 495 if (rv) { 496 rv = (rv - 1) + ACPI_MATCHSCORE_CID; 497 return imin(rv, ACPI_MATCHSCORE_CID_MAX); 498 } 499 return 0; 500 } 501 502 /* 503 * acpi_compatible_match -- 504 * 505 * Returns a weighted match value, comparing the _HID and _CID 506 * IDs against a driver's compatibility data. 507 */ 508 int 509 acpi_compatible_match(const struct acpi_attach_args * const aa, 510 const struct device_compatible_entry * const dce) 511 { 512 const char *strings[ACPI_COMPATSTR_MAX * sizeof(const char *)]; 513 const char **cpp; 514 bool dtlink = false; 515 int rv; 516 517 if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) { 518 return 0; 519 } 520 521 ACPI_DEVICE_INFO *ad = aa->aa_node->ad_devinfo; 522 523 if ((ad->Valid & ACPI_VALID_HID) != 0) { 524 strings[0] = ad->HardwareId.String; 525 526 /* Matching _HID wins big. */ 527 if (device_compatible_pmatch(strings, 1, dce) != 0) { 528 return ACPI_MATCHSCORE_HID; 529 } 530 531 if (device_compatible_pmatch(strings, 1, 532 dtlink_compat_data) != 0) { 533 dtlink = true; 534 } 535 } 536 537 if ((ad->Valid & ACPI_VALID_CID) != 0) { 538 cpp = acpi_compatible_alloc_strarray(ad->CompatibleIdList.Ids, 539 ad->CompatibleIdList.Count, strings); 540 541 rv = device_compatible_pmatch(cpp, 542 ad->CompatibleIdList.Count, dce); 543 if (!dtlink && 544 device_compatible_pmatch(cpp, ad->CompatibleIdList.Count, 545 dtlink_compat_data) != 0) { 546 dtlink = true; 547 } 548 acpi_compatible_free_strarray(cpp, ad->CompatibleIdList.Count, 549 strings); 550 if (rv) { 551 rv = (rv - 1) + ACPI_MATCHSCORE_CID; 552 return imin(rv, ACPI_MATCHSCORE_CID_MAX); 553 } 554 } 555 556 if (dtlink) { 557 return acpi_compatible_match_dtlink(aa, dce); 558 } 559 560 return 0; 561 } 562 563 /* 564 * acpi_compatible_lookup -- 565 * 566 * Returns the device_compatible_entry that matches the _HID 567 * or _CID ID. 568 */ 569 const struct device_compatible_entry * 570 acpi_compatible_lookup(const struct acpi_attach_args * const aa, 571 const struct device_compatible_entry * const dce) 572 { 573 const struct device_compatible_entry *rv = NULL; 574 const char *strings[ACPI_COMPATSTR_MAX]; 575 const char **cpp; 576 577 if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) { 578 return NULL; 579 } 580 581 ACPI_DEVICE_INFO *ad = aa->aa_node->ad_devinfo; 582 583 if ((ad->Valid & ACPI_VALID_HID) != 0) { 584 strings[0] = ad->HardwareId.String; 585 586 rv = device_compatible_plookup(strings, 1, dce); 587 if (rv != NULL) 588 return rv; 589 } 590 591 if ((ad->Valid & ACPI_VALID_CID) != 0) { 592 cpp = acpi_compatible_alloc_strarray(ad->CompatibleIdList.Ids, 593 ad->CompatibleIdList.Count, strings); 594 595 rv = device_compatible_plookup(cpp, 596 ad->CompatibleIdList.Count, dce); 597 acpi_compatible_free_strarray(cpp, ad->CompatibleIdList.Count, 598 strings); 599 } 600 601 return rv; 602 } 603 604 /* 605 * Match given IDs against _HID and _CIDs. 606 */ 607 int 608 acpi_match_hid(ACPI_DEVICE_INFO *ad, const char * const *ids) 609 { 610 uint32_t i, n; 611 char *id; 612 613 while (*ids) { 614 615 if ((ad->Valid & ACPI_VALID_HID) != 0) { 616 617 if (pmatch(ad->HardwareId.String, *ids, NULL) == 2) 618 return 1; 619 } 620 621 if ((ad->Valid & ACPI_VALID_CID) != 0) { 622 623 n = ad->CompatibleIdList.Count; 624 625 for (i = 0; i < n; i++) { 626 627 id = ad->CompatibleIdList.Ids[i].String; 628 629 if (pmatch(id, *ids, NULL) == 2) 630 return 1; 631 } 632 } 633 634 ids++; 635 } 636 637 return 0; 638 } 639 640 /* 641 * Match a PCI-defined bass-class, sub-class, and programming interface 642 * against a handle's _CLS object. 643 */ 644 int 645 acpi_match_class(ACPI_HANDLE handle, uint8_t pci_class, uint8_t pci_subclass, 646 uint8_t pci_interface) 647 { 648 ACPI_BUFFER buf; 649 ACPI_OBJECT *obj; 650 ACPI_STATUS rv; 651 int match = 0; 652 653 rv = acpi_eval_struct(handle, "_CLS", &buf); 654 if (ACPI_FAILURE(rv)) 655 goto done; 656 657 obj = buf.Pointer; 658 if (obj->Type != ACPI_TYPE_PACKAGE) 659 goto done; 660 if (obj->Package.Count != 3) 661 goto done; 662 if (obj->Package.Elements[0].Type != ACPI_TYPE_INTEGER || 663 obj->Package.Elements[1].Type != ACPI_TYPE_INTEGER || 664 obj->Package.Elements[2].Type != ACPI_TYPE_INTEGER) 665 goto done; 666 667 match = obj->Package.Elements[0].Integer.Value == pci_class && 668 obj->Package.Elements[1].Integer.Value == pci_subclass && 669 obj->Package.Elements[2].Integer.Value == pci_interface; 670 671 done: 672 if (buf.Pointer) 673 ACPI_FREE(buf.Pointer); 674 return match ? ACPI_MATCHSCORE_CLS : 0; 675 } 676 677 /* 678 * Match a device node from a handle. 679 */ 680 struct acpi_devnode * 681 acpi_match_node(ACPI_HANDLE handle) 682 { 683 struct acpi_devnode *ad; 684 ACPI_STATUS rv; 685 686 if (handle == NULL) 687 return NULL; 688 689 rv = AcpiGetData(handle, acpi_clean_node, (void **)&ad); 690 691 if (ACPI_FAILURE(rv)) 692 return NULL; 693 694 return ad; 695 } 696 697 /* 698 * Permanently associate a device node with a handle. 699 */ 700 void 701 acpi_match_node_init(struct acpi_devnode *ad) 702 { 703 (void)AcpiAttachData(ad->ad_handle, acpi_clean_node, ad); 704 } 705 706 static void 707 acpi_clean_node(ACPI_HANDLE handle, void *aux) 708 { 709 /* Nothing. */ 710 } 711 712 /* 713 * Match a handle from a cpu_info. Returns NULL on failure. 714 * 715 * Note that acpi_match_node() can be used if the device node 716 * is also required. 717 */ 718 ACPI_HANDLE 719 acpi_match_cpu_info(struct cpu_info *ci) 720 { 721 struct acpi_softc *sc = acpi_softc; 722 struct acpi_devnode *ad; 723 ACPI_INTEGER val; 724 ACPI_OBJECT *obj; 725 ACPI_BUFFER buf; 726 ACPI_HANDLE hdl; 727 ACPI_STATUS rv; 728 729 if (sc == NULL || acpi_active == 0) 730 return NULL; 731 732 /* 733 * CPUs are declared in the ACPI namespace 734 * either as a Processor() or as a Device(). 735 * In both cases the MADT entries are used 736 * for the match (see ACPI 4.0, section 8.4). 737 */ 738 SIMPLEQ_FOREACH(ad, &sc->sc_head, ad_list) { 739 740 hdl = ad->ad_handle; 741 742 switch (ad->ad_type) { 743 744 case ACPI_TYPE_DEVICE: 745 746 if (acpi_match_hid(ad->ad_devinfo, acpicpu_ids) == 0) 747 break; 748 749 rv = acpi_eval_integer(hdl, "_UID", &val); 750 751 if (ACPI_SUCCESS(rv) && val == ci->ci_acpiid) 752 return hdl; 753 754 break; 755 756 case ACPI_TYPE_PROCESSOR: 757 758 rv = acpi_eval_struct(hdl, NULL, &buf); 759 760 if (ACPI_FAILURE(rv)) 761 break; 762 763 obj = buf.Pointer; 764 765 if (obj->Processor.ProcId == ci->ci_acpiid) { 766 ACPI_FREE(buf.Pointer); 767 return hdl; 768 } 769 770 ACPI_FREE(buf.Pointer); 771 break; 772 } 773 } 774 775 return NULL; 776 } 777 778 /* 779 * Match a CPU from a handle. Returns NULL on failure. 780 */ 781 struct cpu_info * 782 acpi_match_cpu_handle(ACPI_HANDLE hdl) 783 { 784 struct cpu_info *ci; 785 ACPI_DEVICE_INFO *di; 786 CPU_INFO_ITERATOR cii; 787 ACPI_INTEGER val; 788 ACPI_OBJECT *obj; 789 ACPI_BUFFER buf; 790 ACPI_STATUS rv; 791 792 ci = NULL; 793 di = NULL; 794 buf.Pointer = NULL; 795 796 rv = AcpiGetObjectInfo(hdl, &di); 797 798 if (ACPI_FAILURE(rv)) 799 return NULL; 800 801 switch (di->Type) { 802 803 case ACPI_TYPE_DEVICE: 804 805 if (acpi_match_hid(di, acpicpu_ids) == 0) 806 goto out; 807 808 rv = acpi_eval_integer(hdl, "_UID", &val); 809 810 if (ACPI_FAILURE(rv)) 811 goto out; 812 813 break; 814 815 case ACPI_TYPE_PROCESSOR: 816 817 rv = acpi_eval_struct(hdl, NULL, &buf); 818 819 if (ACPI_FAILURE(rv)) 820 goto out; 821 822 obj = buf.Pointer; 823 val = obj->Processor.ProcId; 824 break; 825 826 default: 827 goto out; 828 } 829 830 for (CPU_INFO_FOREACH(cii, ci)) { 831 832 if (ci->ci_acpiid == val) 833 goto out; 834 } 835 836 ci = NULL; 837 838 out: 839 if (di != NULL) 840 ACPI_FREE(di); 841 842 if (buf.Pointer != NULL) 843 ACPI_FREE(buf.Pointer); 844 845 return ci; 846 } 847 848 struct acpi_irq_handler { 849 uint32_t aih_irq; 850 void *aih_ih; 851 }; 852 853 void * 854 acpi_intr_establish(device_t dev, uint64_t c, int ipl, bool mpsafe, 855 int (*intr)(void *), void *iarg, const char *xname) 856 { 857 ACPI_STATUS rv; 858 ACPI_HANDLE hdl = (void *)(uintptr_t)c; 859 struct acpi_resources res; 860 struct acpi_irq *irq; 861 void *aih = NULL; 862 863 rv = acpi_resource_parse(dev, hdl, "_CRS", &res, 864 &acpi_resource_parse_ops_quiet); 865 if (ACPI_FAILURE(rv)) 866 return NULL; 867 868 irq = acpi_res_irq(&res, 0); 869 if (irq == NULL) 870 goto end; 871 872 aih = acpi_intr_establish_irq(dev, irq, ipl, mpsafe, 873 intr, iarg, xname); 874 875 end: 876 acpi_resource_cleanup(&res); 877 878 return aih; 879 } 880 881 void * 882 acpi_intr_establish_irq(device_t dev, struct acpi_irq *irq, int ipl, 883 bool mpsafe, int (*intr)(void *), void *iarg, const char *xname) 884 { 885 struct acpi_irq_handler *aih; 886 void *ih; 887 888 const int type = (irq->ar_type == ACPI_EDGE_SENSITIVE) ? IST_EDGE : IST_LEVEL; 889 ih = acpi_md_intr_establish(irq->ar_irq, ipl, type, intr, iarg, mpsafe, xname); 890 if (ih == NULL) 891 return NULL; 892 893 aih = kmem_alloc(sizeof(struct acpi_irq_handler), KM_SLEEP); 894 aih->aih_irq = irq->ar_irq; 895 aih->aih_ih = ih; 896 897 return aih; 898 } 899 900 void 901 acpi_intr_mask(void *c) 902 { 903 struct acpi_irq_handler * const aih = c; 904 905 acpi_md_intr_mask(aih->aih_ih); 906 } 907 908 void 909 acpi_intr_unmask(void *c) 910 { 911 struct acpi_irq_handler * const aih = c; 912 913 acpi_md_intr_unmask(aih->aih_ih); 914 } 915 916 void 917 acpi_intr_disestablish(void *c) 918 { 919 struct acpi_irq_handler *aih = c; 920 921 acpi_md_intr_disestablish(aih->aih_ih); 922 kmem_free(aih, sizeof(struct acpi_irq_handler)); 923 } 924 925 const char * 926 acpi_intr_string(void *c, char *buf, size_t size) 927 { 928 struct acpi_irq_handler *aih = c; 929 intr_handle_t ih = aih->aih_irq; 930 931 return intr_string(ih, buf, size); 932 } 933 934 /* 935 * Device-Specific Data (_DSD) support 936 */ 937 938 static UINT8 acpi_dsd_uuid[ACPI_UUID_LENGTH] = { 939 0x14, 0xd8, 0xff, 0xda, 0xba, 0x6e, 0x8c, 0x4d, 940 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01 941 }; 942 943 static ACPI_STATUS 944 acpi_dsd_property(ACPI_HANDLE handle, const char *prop, ACPI_BUFFER *pbuf, ACPI_OBJECT_TYPE type, ACPI_OBJECT **ret) 945 { 946 ACPI_OBJECT *obj, *uuid, *props, *pobj, *propkey, *propval; 947 ACPI_STATUS rv; 948 int n; 949 950 rv = AcpiEvaluateObjectTyped(handle, "_DSD", NULL, pbuf, ACPI_TYPE_PACKAGE); 951 if (ACPI_FAILURE(rv)) 952 return rv; 953 954 props = NULL; 955 obj = (ACPI_OBJECT *)pbuf->Pointer; 956 for (n = 0; (n + 1) < obj->Package.Count; n += 2) { 957 uuid = &obj->Package.Elements[n]; 958 if (uuid->Buffer.Length == ACPI_UUID_LENGTH && 959 memcmp(uuid->Buffer.Pointer, acpi_dsd_uuid, ACPI_UUID_LENGTH) == 0) { 960 props = &obj->Package.Elements[n + 1]; 961 break; 962 } 963 } 964 if (props == NULL) 965 return AE_NOT_FOUND; 966 967 for (n = 0; n < props->Package.Count; n++) { 968 pobj = &props->Package.Elements[n]; 969 if (pobj->Type != ACPI_TYPE_PACKAGE || pobj->Package.Count != 2) 970 continue; 971 propkey = (ACPI_OBJECT *)&pobj->Package.Elements[0]; 972 propval = (ACPI_OBJECT *)&pobj->Package.Elements[1]; 973 if (propkey->Type != ACPI_TYPE_STRING) 974 continue; 975 if (strcmp(propkey->String.Pointer, prop) != 0) 976 continue; 977 978 if (propval->Type != type) { 979 return AE_TYPE; 980 } else { 981 *ret = propval; 982 return AE_OK; 983 } 984 break; 985 } 986 987 return AE_NOT_FOUND; 988 } 989 990 ACPI_STATUS 991 acpi_dsd_integer(ACPI_HANDLE handle, const char *prop, ACPI_INTEGER *val) 992 { 993 ACPI_OBJECT *propval; 994 ACPI_STATUS rv; 995 ACPI_BUFFER buf; 996 997 buf.Pointer = NULL; 998 buf.Length = ACPI_ALLOCATE_BUFFER; 999 1000 rv = acpi_dsd_property(handle, prop, &buf, ACPI_TYPE_INTEGER, &propval); 1001 if (ACPI_SUCCESS(rv)) 1002 *val = propval->Integer.Value; 1003 1004 if (buf.Pointer != NULL) 1005 ACPI_FREE(buf.Pointer); 1006 return rv; 1007 } 1008 1009 ACPI_STATUS 1010 acpi_dsd_string(ACPI_HANDLE handle, const char *prop, char **val) 1011 { 1012 ACPI_OBJECT *propval; 1013 ACPI_STATUS rv; 1014 ACPI_BUFFER buf; 1015 1016 buf.Pointer = NULL; 1017 buf.Length = ACPI_ALLOCATE_BUFFER; 1018 1019 rv = acpi_dsd_property(handle, prop, &buf, ACPI_TYPE_STRING, &propval); 1020 if (ACPI_SUCCESS(rv)) 1021 *val = kmem_strdup(propval->String.Pointer, KM_SLEEP); 1022 1023 if (buf.Pointer != NULL) 1024 ACPI_FREE(buf.Pointer); 1025 return rv; 1026 } 1027 1028 ACPI_STATUS 1029 acpi_dsd_bool(ACPI_HANDLE handle, const char *prop, bool *val) 1030 { 1031 ACPI_STATUS rv; 1032 ACPI_INTEGER ival; 1033 1034 rv = acpi_dsd_integer(handle, prop, &ival); 1035 if (ACPI_SUCCESS(rv)) { 1036 *val = ival != 0; 1037 } 1038 1039 return rv; 1040 } 1041 1042 1043 /* 1044 * Device Specific Method (_DSM) support 1045 */ 1046 1047 ACPI_STATUS 1048 acpi_dsm_typed(ACPI_HANDLE handle, uint8_t *uuid, ACPI_INTEGER rev, 1049 ACPI_INTEGER func, const ACPI_OBJECT *arg3, ACPI_OBJECT_TYPE return_type, 1050 ACPI_OBJECT **return_obj) 1051 { 1052 ACPI_OBJECT_LIST arg; 1053 ACPI_OBJECT obj[4]; 1054 ACPI_BUFFER buf; 1055 ACPI_STATUS status; 1056 1057 arg.Count = 4; 1058 arg.Pointer = obj; 1059 1060 obj[0].Type = ACPI_TYPE_BUFFER; 1061 obj[0].Buffer.Length = ACPI_UUID_LENGTH; 1062 obj[0].Buffer.Pointer = uuid; 1063 1064 obj[1].Type = ACPI_TYPE_INTEGER; 1065 obj[1].Integer.Value = rev; 1066 1067 obj[2].Type = ACPI_TYPE_INTEGER; 1068 obj[2].Integer.Value = func; 1069 1070 if (arg3 != NULL) { 1071 obj[3] = *arg3; 1072 } else { 1073 obj[3].Type = ACPI_TYPE_PACKAGE; 1074 obj[3].Package.Count = 0; 1075 obj[3].Package.Elements = NULL; 1076 } 1077 1078 buf.Pointer = NULL; 1079 buf.Length = ACPI_ALLOCATE_BUFFER; 1080 1081 if (return_obj == NULL && return_type == ACPI_TYPE_ANY) { 1082 status = AcpiEvaluateObject(handle, "_DSM", &arg, NULL); 1083 } else { 1084 *return_obj = NULL; 1085 status = AcpiEvaluateObjectTyped(handle, "_DSM", &arg, &buf, 1086 return_type); 1087 } 1088 if (ACPI_FAILURE(status)) { 1089 return status; 1090 } 1091 if (return_obj != NULL) { 1092 *return_obj = buf.Pointer; 1093 } else if (buf.Pointer != NULL) { 1094 ACPI_FREE(buf.Pointer); 1095 } 1096 return AE_OK; 1097 } 1098 1099 ACPI_STATUS 1100 acpi_dsm_integer(ACPI_HANDLE handle, uint8_t *uuid, ACPI_INTEGER rev, 1101 ACPI_INTEGER func, const ACPI_OBJECT *arg3, ACPI_INTEGER *ret) 1102 { 1103 ACPI_OBJECT *obj; 1104 ACPI_STATUS status; 1105 1106 status = acpi_dsm_typed(handle, uuid, rev, func, arg3, 1107 ACPI_TYPE_INTEGER, &obj); 1108 if (ACPI_FAILURE(status)) { 1109 return status; 1110 } 1111 1112 *ret = obj->Integer.Value; 1113 ACPI_FREE(obj); 1114 1115 return AE_OK; 1116 } 1117 1118 ACPI_STATUS 1119 acpi_dsm(ACPI_HANDLE handle, uint8_t *uuid, ACPI_INTEGER rev, 1120 ACPI_INTEGER func, const ACPI_OBJECT *arg3, ACPI_OBJECT **return_obj) 1121 { 1122 return acpi_dsm_typed(handle, uuid, rev, func, arg3, ACPI_TYPE_ANY, 1123 return_obj); 1124 } 1125 1126 ACPI_STATUS 1127 acpi_dsm_query(ACPI_HANDLE handle, uint8_t *uuid, ACPI_INTEGER rev, 1128 ACPI_INTEGER *ret) 1129 { 1130 ACPI_OBJECT *obj; 1131 ACPI_STATUS status; 1132 uint8_t *data; 1133 u_int n; 1134 1135 status = acpi_dsm(handle, uuid, rev, 0, NULL, &obj); 1136 if (ACPI_FAILURE(status)) { 1137 return status; 1138 } 1139 1140 if (obj->Type == ACPI_TYPE_INTEGER) { 1141 *ret = obj->Integer.Value; 1142 } else if (obj->Type == ACPI_TYPE_BUFFER && 1143 obj->Buffer.Length <= 8) { 1144 *ret = 0; 1145 data = (uint8_t *)obj->Buffer.Pointer; 1146 for (n = 0; n < obj->Buffer.Length; n++) { 1147 *ret |= (uint64_t)data[n] << (n * 8); 1148 } 1149 } else { 1150 status = AE_TYPE; 1151 } 1152 1153 ACPI_FREE(obj); 1154 1155 return status; 1156 } 1157 1158 ACPI_STATUS 1159 acpi_claim_childdevs(device_t dev, struct acpi_devnode *devnode) 1160 { 1161 struct acpi_devnode *ad; 1162 1163 SIMPLEQ_FOREACH(ad, &devnode->ad_child_head, ad_child_list) { 1164 if (ad->ad_device != NULL) 1165 continue; 1166 aprint_debug_dev(dev, "claiming %s\n", 1167 acpi_name(ad->ad_handle)); 1168 ad->ad_device = dev; 1169 acpi_claim_childdevs(dev, ad); 1170 } 1171 1172 return AE_OK; 1173 } 1174