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