1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * Copyright (c) 2018, Joyent, Inc. 26 */ 27 /* 28 * Copyright (c) 2009-2010, Intel Corporation. 29 * All rights reserved. 30 */ 31 32 #include <sys/types.h> 33 #include <sys/cmn_err.h> 34 #include <sys/note.h> 35 #include <sys/sysmacros.h> 36 #include <sys/sunddi.h> 37 #include <sys/sunndi.h> 38 #include <sys/acpi/acpi.h> 39 #include <sys/acpica.h> 40 #include <sys/acpidev.h> 41 #include <sys/acpidev_impl.h> 42 #include <util/sscanf.h> 43 44 /* Data structures used to extract the numeric unit address from string _UID. */ 45 static acpidev_pseudo_uid_head_t acpidev_uid_heads[ACPIDEV_CLASS_ID_MAX]; 46 static char *acpidev_uid_formats[] = { 47 "%u", 48 }; 49 50 static char *acpidev_unknown_object_name = "<unknown>"; 51 52 int 53 acpidev_query_device_status(ACPI_HANDLE hdl) 54 { 55 int status; 56 57 ASSERT(hdl != NULL); 58 if (hdl == NULL) { 59 ACPIDEV_DEBUG(CE_WARN, 60 "!acpidev: hdl is NULL in acpidev_query_device_status()."); 61 return (0); 62 } 63 64 if (ACPI_FAILURE(acpica_get_object_status(hdl, &status))) { 65 /* 66 * When the object status is not present, it will generally be 67 * set to the default value as per the ACPI specification (6.3.7 68 * _STA (Status)). However, there are other possible cases of 69 * ACPI failures. As this code is not aware of them and has 70 * always treated all failures like the not-present set. Do the 71 * same for the time being. 72 */ 73 status = 0xF; 74 } 75 76 return (status); 77 } 78 79 boolean_t 80 acpidev_check_device_present(int status) 81 { 82 /* 83 * According to ACPI3.0 Spec, if either the ACPI_STA_DEVICE_PRESENT bit 84 * or the ACPI_STA_DEVICE_FUNCTIONING bit is set, the device exists. 85 */ 86 if (status & (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_FUNCTIONING)) { 87 return (B_TRUE); 88 } 89 90 return (B_FALSE); 91 } 92 93 boolean_t 94 acpidev_check_device_enabled(int stat) 95 { 96 /* 97 * According to ACPI3.0 Spec, if either the ACPI_STA_DEVICE_PRESENT bit 98 * or the ACPI_STA_DEVICE_FUNCTIONING bit is set, the device exists. 99 * Return true if device exists and has been enabled. 100 */ 101 if ((stat & (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_FUNCTIONING)) && 102 (stat & ACPI_STA_DEVICE_ENABLED)) { 103 return (B_TRUE); 104 } 105 106 return (B_FALSE); 107 } 108 109 boolean_t 110 acpidev_match_device_id(ACPI_DEVICE_INFO *infop, char **ids, int count) 111 { 112 int i, j; 113 114 ASSERT(infop != NULL); 115 ASSERT(ids != NULL || count == 0); 116 /* Special case to match all devices if count is 0. */ 117 if (count == 0) { 118 return (B_TRUE); 119 } else if (infop == NULL || ids == NULL) { 120 ACPIDEV_DEBUG(CE_WARN, "!acpidev: invalid parameters in " 121 "acpidev_match_device_id()."); 122 return (B_FALSE); 123 } 124 125 /* Match _HID first. */ 126 if (infop->Valid & ACPI_VALID_HID) { 127 for (i = 0; i < count; i++) { 128 if (strncmp(ids[i], infop->HardwareId.String, 129 infop->HardwareId.Length) == 0) { 130 return (B_TRUE); 131 } 132 } 133 } 134 135 /* Match _CID next. */ 136 if (infop->Valid & ACPI_VALID_CID) { 137 for (i = 0; i < count; i++) { 138 for (j = 0; j < infop->CompatibleIdList.Count; j++) { 139 if (strncmp(ids[i], 140 infop->CompatibleIdList.Ids[j].String, 141 infop->CompatibleIdList.Ids[j].Length) 142 == 0) { 143 return (B_TRUE); 144 } 145 } 146 } 147 } 148 149 return (B_FALSE); 150 } 151 152 struct acpidev_get_device_arg { 153 boolean_t skip_non_exist; 154 int id_count; 155 char **device_ids; 156 void *user_arg; 157 ACPI_WALK_CALLBACK user_func; 158 }; 159 160 static ACPI_STATUS 161 acpidev_get_device_callback(ACPI_HANDLE hdl, UINT32 level, void *arg, 162 void **retval) 163 { 164 ACPI_STATUS rc; 165 ACPI_DEVICE_INFO *infop; 166 struct acpidev_get_device_arg *argp; 167 int status; 168 169 argp = (struct acpidev_get_device_arg *)arg; 170 ASSERT(argp != NULL); 171 ASSERT(hdl != NULL); 172 173 /* Query object information. */ 174 rc = AcpiGetObjectInfo(hdl, &infop); 175 if (ACPI_FAILURE(rc)) { 176 cmn_err(CE_WARN, "!acpidev: failed to get ACPI object info " 177 "in acpidev_get_device_callback()."); 178 return (AE_CTRL_DEPTH); 179 } 180 181 rc = acpica_get_object_status(hdl, &status); 182 183 /* 184 * Skip scanning of children if the device is neither PRESENT nor 185 * FUNCTIONING. 186 * Please refer to ACPI Spec3.0b Sec 6.3.1 and 6.5.1. 187 */ 188 if (argp->skip_non_exist && rc == AE_OK && 189 !acpidev_check_device_present(status)) { 190 rc = AE_CTRL_DEPTH; 191 /* Call user callback if matched. */ 192 } else if (acpidev_match_device_id(infop, argp->device_ids, 193 argp->id_count)) { 194 rc = argp->user_func(hdl, level, argp->user_arg, retval); 195 } else { 196 rc = AE_OK; 197 } 198 199 /* Free ACPI object info buffer. */ 200 AcpiOsFree(infop); 201 202 return (rc); 203 } 204 205 ACPI_STATUS 206 acpidev_get_device_by_id(ACPI_HANDLE hdl, char **ids, int count, 207 int maxdepth, boolean_t skip_non_exist, 208 ACPI_WALK_CALLBACK userfunc, void *userarg, void **retval) 209 { 210 ACPI_STATUS rc; 211 struct acpidev_get_device_arg arg; 212 213 ASSERT(userfunc != NULL); 214 if (hdl == NULL || userfunc == NULL || (ids == NULL && count != 0)) { 215 ACPIDEV_DEBUG(CE_WARN, "!acpidev: invalid parameters " 216 "in acpidev_get_device_by_id()."); 217 return (AE_BAD_PARAMETER); 218 } 219 220 /* Enumerate all descendant objects. */ 221 arg.skip_non_exist = skip_non_exist; 222 arg.device_ids = ids; 223 arg.id_count = count; 224 arg.user_arg = userarg; 225 arg.user_func = userfunc; 226 rc = AcpiWalkNamespace(ACPI_TYPE_DEVICE, hdl, maxdepth, 227 &acpidev_get_device_callback, NULL, &arg, retval); 228 229 return (rc); 230 } 231 232 ACPI_STATUS 233 acpidev_walk_apic(ACPI_BUFFER *bufp, ACPI_HANDLE hdl, char *method, 234 acpidev_apic_walker_t func, void *context) 235 { 236 ACPI_STATUS rc; 237 ssize_t len; 238 ACPI_BUFFER buf; 239 ACPI_OBJECT *obj; 240 ACPI_SUBTABLE_HEADER *ap; 241 ACPI_TABLE_MADT *mp = NULL; 242 243 ASSERT(func != NULL); 244 if (func == NULL) { 245 ACPIDEV_DEBUG(CE_WARN, 246 "!acpidev: invalid parameters for acpidev_walk_apic()."); 247 return (AE_BAD_PARAMETER); 248 } 249 250 buf.Pointer = NULL; 251 buf.Length = ACPI_ALLOCATE_BUFFER; 252 253 /* A walk buffer was passed in if bufp isn't NULL. */ 254 if (bufp != NULL) { 255 ap = (ACPI_SUBTABLE_HEADER *)(bufp->Pointer); 256 len = bufp->Length; 257 } else if (method != NULL) { 258 /* 259 * Otherwise, if we have an evaluate method, we get the walk 260 * buffer from a successful invocation of 261 * AcpiEvaluateObjectTyped(). 262 */ 263 ASSERT(hdl != NULL); 264 rc = AcpiEvaluateObjectTyped(hdl, method, NULL, &buf, 265 ACPI_TYPE_BUFFER); 266 if (ACPI_SUCCESS(rc)) { 267 ASSERT(buf.Length >= sizeof (*obj)); 268 obj = buf.Pointer; 269 ap = (ACPI_SUBTABLE_HEADER *)obj->Buffer.Pointer; 270 len = obj->Buffer.Length; 271 } else { 272 if (rc != AE_NOT_FOUND) 273 cmn_err(CE_WARN, "!acpidev: failed to evaluate " 274 "%s in acpidev_walk_apic().", method); 275 return (rc); 276 } 277 } else { 278 /* As a last resort, walk the MADT table. */ 279 rc = AcpiGetTable(ACPI_SIG_MADT, 1, (ACPI_TABLE_HEADER **)&mp); 280 if (ACPI_FAILURE(rc)) { 281 cmn_err(CE_WARN, "!acpidev: failed to get MADT table " 282 "in acpidev_walk_apic()."); 283 return (rc); 284 } 285 ap = (ACPI_SUBTABLE_HEADER *)(mp + 1); 286 len = mp->Header.Length - sizeof (*mp); 287 } 288 289 ASSERT(len >= 0); 290 for (rc = AE_OK; len > 0 && ACPI_SUCCESS(rc); len -= ap->Length, 291 ap = (ACPI_SUBTABLE_HEADER *)(((char *)ap) + ap->Length)) { 292 ASSERT(len >= sizeof (ACPI_SUBTABLE_HEADER)); 293 if (len <= sizeof (ACPI_SUBTABLE_HEADER) || 294 ap->Length <= sizeof (ACPI_SUBTABLE_HEADER) || 295 len < ap->Length) { 296 cmn_err(CE_WARN, 297 "!acpidev: invalid APIC entry in MADT/_MAT."); 298 break; 299 } 300 rc = (*func)(ap, context); 301 } 302 303 if (buf.Pointer != NULL) { 304 AcpiOsFree(buf.Pointer); 305 } 306 307 return (rc); 308 } 309 310 char * 311 acpidev_get_object_name(ACPI_HANDLE hdl) 312 { 313 ACPI_BUFFER buf; 314 char *objname = acpidev_unknown_object_name; 315 316 buf.Length = ACPI_ALLOCATE_BUFFER; 317 buf.Pointer = NULL; 318 if (ACPI_SUCCESS(AcpiGetName(hdl, ACPI_FULL_PATHNAME, &buf))) { 319 ASSERT(buf.Pointer != NULL); 320 objname = (char *)buf.Pointer; 321 } 322 323 return (objname); 324 } 325 326 void 327 acpidev_free_object_name(char *objname) 328 { 329 if (objname != acpidev_unknown_object_name && objname != NULL) { 330 AcpiOsFree(objname); 331 } 332 } 333 334 acpidev_walk_info_t * 335 acpidev_alloc_walk_info(acpidev_op_type_t op_type, int lvl, ACPI_HANDLE hdl, 336 acpidev_class_list_t **listpp, acpidev_walk_info_t *pinfop) 337 { 338 acpidev_walk_info_t *infop = NULL; 339 acpidev_data_handle_t datap = NULL; 340 341 ASSERT(0 <= lvl && lvl < ACPIDEV_MAX_ENUM_LEVELS); 342 infop = kmem_zalloc(sizeof (*infop), KM_SLEEP); 343 infop->awi_op_type = op_type; 344 infop->awi_level = lvl; 345 infop->awi_parent = pinfop; 346 infop->awi_class_list = listpp; 347 infop->awi_hdl = hdl; 348 infop->awi_name = acpidev_get_object_name(hdl); 349 350 /* Cache ACPI device information. */ 351 if (ACPI_FAILURE(AcpiGetObjectInfo(hdl, &infop->awi_info))) { 352 cmn_err(CE_WARN, "!acpidev: failed to get object info for %s " 353 "in acpidev_alloc_walk_info().", infop->awi_name); 354 acpidev_free_object_name(infop->awi_name); 355 kmem_free(infop, sizeof (*infop)); 356 return (NULL); 357 } 358 359 /* 360 * Get or create an ACPI object data handle, which will be used to 361 * maintain object status information. 362 */ 363 if ((datap = acpidev_data_get_handle(hdl)) != NULL) { 364 ASSERT(datap->aod_hdl == hdl); 365 ASSERT(datap->aod_level == lvl); 366 } else if ((datap = acpidev_data_create_handle(hdl)) != NULL) { 367 datap->aod_level = lvl; 368 datap->aod_hdl = hdl; 369 } else { 370 ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to create object " 371 "handle for %s in acpidev_alloc_walk_info().", 372 infop->awi_name); 373 AcpiOsFree(infop->awi_info); 374 acpidev_free_object_name(infop->awi_name); 375 kmem_free(infop, sizeof (*infop)); 376 return (NULL); 377 } 378 infop->awi_data = datap; 379 /* Sync DEVICE_CREATED flag. */ 380 if (datap->aod_iflag & ACPIDEV_ODF_DEVINFO_CREATED) { 381 ASSERT(datap->aod_dip != NULL); 382 ASSERT(datap->aod_class != NULL); 383 infop->awi_dip = datap->aod_dip; 384 infop->awi_flags |= ACPIDEV_WI_DEVICE_CREATED; 385 } 386 387 return (infop); 388 } 389 390 void 391 acpidev_free_walk_info(acpidev_walk_info_t *infop) 392 { 393 /* 394 * The ACPI object data handle will only be released when the 395 * corresponding object is going to be destroyed. 396 */ 397 if (infop != NULL) { 398 if (infop->awi_info != NULL) { 399 AcpiOsFree(infop->awi_info); 400 } 401 if (infop->awi_name != NULL) { 402 acpidev_free_object_name(infop->awi_name); 403 } 404 kmem_free(infop, sizeof (*infop)); 405 } 406 } 407 408 dev_info_t * 409 acpidev_walk_info_get_pdip(acpidev_walk_info_t *infop) 410 { 411 while (infop != NULL) { 412 if (infop->awi_dip != NULL) { 413 return (infop->awi_dip); 414 } 415 infop = infop->awi_parent; 416 } 417 418 return (NULL); 419 } 420 421 /* 422 * Called to release resources when the corresponding object is going 423 * to be destroyed. 424 */ 425 static void 426 acpidev_free_object_handler(ACPI_HANDLE hdl, void *data) 427 { 428 _NOTE(ARGUNUSED(hdl)); 429 430 acpidev_data_handle_t objhdl = data; 431 432 if (objhdl->aod_class != NULL) { 433 atomic_dec_32(&objhdl->aod_class->adc_refcnt); 434 objhdl->aod_class = NULL; 435 } 436 kmem_free(objhdl, sizeof (acpidev_data_handle_t)); 437 } 438 439 acpidev_data_handle_t 440 acpidev_data_get_handle(ACPI_HANDLE hdl) 441 { 442 void *ptr; 443 acpidev_data_handle_t objhdl = NULL; 444 445 if (ACPI_SUCCESS(AcpiGetData(hdl, acpidev_free_object_handler, &ptr))) { 446 objhdl = (acpidev_data_handle_t)ptr; 447 } 448 449 return (objhdl); 450 } 451 452 acpidev_data_handle_t 453 acpidev_data_create_handle(ACPI_HANDLE hdl) 454 { 455 acpidev_data_handle_t objhdl; 456 457 objhdl = kmem_zalloc(sizeof (*objhdl), KM_SLEEP); 458 objhdl->aod_bdtype = ACPIDEV_INVALID_BOARD; 459 objhdl->aod_bdnum = UINT32_MAX; 460 objhdl->aod_portid = UINT32_MAX; 461 objhdl->aod_class_id = ACPIDEV_CLASS_ID_INVALID; 462 463 if (ACPI_FAILURE(AcpiAttachData(hdl, acpidev_free_object_handler, 464 (void *)objhdl))) { 465 cmn_err(CE_WARN, 466 "!acpidev: failed to attach handle data to object."); 467 kmem_free(objhdl, sizeof (*objhdl)); 468 return (NULL); 469 } 470 471 return (objhdl); 472 } 473 474 void 475 acpidev_data_destroy_handle(ACPI_HANDLE hdl) 476 { 477 void *ptr; 478 acpidev_data_handle_t objhdl = NULL; 479 480 if (ACPI_SUCCESS(AcpiGetData(hdl, acpidev_free_object_handler, &ptr)) && 481 ACPI_SUCCESS(AcpiDetachData(hdl, acpidev_free_object_handler))) { 482 objhdl = ptr; 483 if (objhdl->aod_class != NULL) { 484 atomic_dec_32(&objhdl->aod_class->adc_refcnt); 485 objhdl->aod_class = NULL; 486 } 487 kmem_free(ptr, sizeof (acpidev_data_handle_t)); 488 } 489 } 490 491 ACPI_HANDLE 492 acpidev_data_get_object(acpidev_data_handle_t hdl) 493 { 494 ASSERT(hdl != NULL); 495 return ((hdl != NULL) ? hdl->aod_hdl : NULL); 496 } 497 498 dev_info_t * 499 acpidev_data_get_devinfo(acpidev_data_handle_t hdl) 500 { 501 ASSERT(hdl != NULL); 502 if (hdl == NULL || 503 (hdl->aod_iflag & ACPIDEV_ODF_DEVINFO_CREATED) == 0) { 504 return (NULL); 505 } else { 506 ASSERT(hdl->aod_dip != NULL); 507 return (hdl->aod_dip); 508 } 509 } 510 511 int 512 acpidev_data_get_status(acpidev_data_handle_t hdl) 513 { 514 ASSERT(hdl != NULL); 515 if (hdl == NULL || 516 (hdl->aod_iflag & ACPIDEV_ODF_STATUS_VALID) == 0) { 517 return (0); 518 } else { 519 return (hdl->aod_status); 520 } 521 } 522 523 void 524 acpidev_data_set_flag(acpidev_data_handle_t hdl, uint32_t flag) 525 { 526 ASSERT(hdl != NULL); 527 atomic_or_32(&hdl->aod_eflag, flag); 528 } 529 530 void 531 acpidev_data_clear_flag(acpidev_data_handle_t hdl, uint32_t flag) 532 { 533 ASSERT(hdl != NULL); 534 atomic_and_32(&hdl->aod_eflag, ~flag); 535 } 536 537 uint32_t 538 acpidev_data_get_flag(acpidev_data_handle_t hdl, uint32_t flag) 539 { 540 ASSERT(hdl != NULL); 541 return (hdl->aod_eflag & flag); 542 } 543 544 boolean_t 545 acpidev_data_dr_capable(acpidev_data_handle_t hdl) 546 { 547 ASSERT(hdl != NULL); 548 return (hdl->aod_iflag & ACPIDEV_ODF_HOTPLUG_CAPABLE); 549 } 550 551 boolean_t 552 acpidev_data_dr_ready(acpidev_data_handle_t hdl) 553 { 554 ASSERT(hdl != NULL); 555 return (hdl->aod_iflag & ACPIDEV_ODF_HOTPLUG_READY); 556 } 557 558 boolean_t 559 acpidev_data_dr_failed(acpidev_data_handle_t hdl) 560 { 561 ASSERT(hdl != NULL); 562 return (hdl->aod_iflag & ACPIDEV_ODF_HOTPLUG_FAILED); 563 } 564 565 static char * 566 acpidev_generate_pseudo_unitaddr(char *uid, acpidev_class_id_t cid, 567 char *buf, size_t len) 568 { 569 acpidev_pseudo_uid_t *up, **pp; 570 571 ASSERT(len >= 64); 572 ASSERT(cid >= 0 && cid < ACPIDEV_CLASS_ID_MAX); 573 if (cid < 0 || cid >= ACPIDEV_CLASS_ID_MAX) { 574 return (NULL); 575 } 576 577 mutex_enter(&acpidev_uid_heads[cid].apuh_lock); 578 for (pp = &acpidev_uid_heads[cid].apuh_first; *pp != NULL; 579 pp = &(*pp)->apu_next) { 580 if (strcmp(uid, (*pp)->apu_uid) == 0 && 581 (*pp)->apu_cid == cid) { 582 break; 583 } 584 } 585 /* uid doesn't exist, create one and insert it into the list. */ 586 if (*pp == NULL) { 587 up = kmem_zalloc(sizeof (*up), KM_SLEEP); 588 up->apu_uid = ddi_strdup(uid, KM_SLEEP); 589 up->apu_cid = cid; 590 up->apu_nid = acpidev_uid_heads[cid].apuh_id++; 591 *pp = up; 592 } 593 ASSERT(*pp != NULL); 594 mutex_exit(&acpidev_uid_heads[cid].apuh_lock); 595 596 /* 597 * Generate a special format unit address with three fields to 598 * guarantee uniqueness. Normal unit addresses for ACPI devices have 599 * either one or two fields. 600 */ 601 if (snprintf(buf, len, "%u,%u,0", (*pp)->apu_nid, cid) > len) { 602 return (NULL); 603 } 604 605 return (buf); 606 } 607 608 static char * 609 acpidev_gen_unitaddr(char *uid, char *fmt, char *buf, size_t len) 610 { 611 size_t i, cnt; 612 uint_t id1, id2; 613 614 ASSERT(len >= 64); 615 if (fmt == NULL || strlen(fmt) == 0) { 616 return (NULL); 617 } 618 619 /* 620 * Count '%' in format string to protect sscanf(). 621 * Only support '%u' and '%x', and maximum 2 conversions. 622 */ 623 for (cnt = 0, i = 0; fmt[i] != 0 && cnt <= 2; i++) { 624 if (fmt[i] != '%') { 625 continue; 626 } else if (fmt[i + 1] == 'u' || fmt[i + 1] == 'x') { 627 /* Skip next character. */ 628 i++; 629 cnt++; 630 } else { 631 /* Invalid conversion, stop walking. */ 632 cnt = SIZE_MAX; 633 } 634 } 635 if (cnt != 1 && cnt != 2) { 636 ACPIDEV_DEBUG(CE_WARN, 637 "!acpidev: invalid uid format string '%s'.", fmt); 638 return (NULL); 639 } 640 641 /* Scan uid and generate unitaddr. */ 642 if (sscanf(uid, fmt, &id1, &id2) != cnt) { 643 return (NULL); 644 } 645 /* 646 * Reverse the order of the two IDs to match the requirements of the 647 * hotplug driver. 648 */ 649 if (cnt == 2 && snprintf(buf, len, "%u,%u", id2, id1) >= len) { 650 ACPIDEV_DEBUG(CE_WARN, 651 "!acpidev: generated unitaddr is too long."); 652 return (NULL); 653 } else if (cnt == 1 && snprintf(buf, len, "%u", id1) >= len) { 654 ACPIDEV_DEBUG(CE_WARN, 655 "!acpidev: generated unitaddr is too long."); 656 return (NULL); 657 } 658 659 return (buf); 660 } 661 662 char * 663 acpidev_generate_unitaddr(char *uid, char **fmts, size_t nfmt, 664 char *buf, size_t len) 665 { 666 size_t i; 667 uint_t count = 0; 668 ulong_t val; 669 char **formats = NULL; 670 char *rbuf = NULL; 671 char *endp = NULL; 672 673 ASSERT(len >= 64); 674 675 /* Use _UID as unit address if it's a decimal integer. */ 676 if (ddi_strtoul(uid, &endp, 10, &val) == 0 && 677 (endp == NULL || *endp == 0)) { 678 if (snprintf(buf, len, "%s", uid) >= len) { 679 return (NULL); 680 } else { 681 return (buf); 682 } 683 } 684 685 /* First handle uid format strings from device property. */ 686 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, ddi_root_node(), 687 DDI_PROP_DONTPASS, 688 ACPIDEV_PROP_NAME_UID_FORMAT, &formats, &count) == DDI_SUCCESS) { 689 /* Walk through format strings and try to generate unitaddr. */ 690 for (i = 0; i < count && rbuf == NULL; i++) { 691 rbuf = acpidev_gen_unitaddr(uid, formats[i], buf, len); 692 } 693 ddi_prop_free(formats); 694 } 695 696 /* Then handle embedded uid format strings. */ 697 if (fmts != NULL) { 698 for (i = 0; i < nfmt && rbuf == NULL; i++) { 699 rbuf = acpidev_gen_unitaddr(uid, fmts[i], buf, len); 700 } 701 } 702 703 return (rbuf); 704 } 705 706 /* 707 * The Solaris device "unit-address" property is composed of a comma-delimited 708 * list of hexadecimal values. According to the ACPI spec, the ACPI _UID method 709 * could return an integer or a string. If it returns an integer, it is used 710 * as the unit-address as is. If _UID returns a string, we try to extract some 711 * meaningful integers to compose the unit-address property. If we fail to 712 * extract any integers, a pseudo-sequential number will be generated for the 713 * unit-address. 714 */ 715 ACPI_STATUS 716 acpidev_set_unitaddr(acpidev_walk_info_t *infop, char **fmts, size_t nfmt, 717 char *unitaddr) 718 { 719 char unit[64]; 720 721 ASSERT(infop != NULL); 722 ASSERT(infop->awi_dip != NULL); 723 ASSERT(infop->awi_info != NULL); 724 if (infop == NULL || infop->awi_dip == NULL || 725 infop->awi_info == NULL) { 726 ACPIDEV_DEBUG(CE_WARN, 727 "!acpidev: invalid parameters in acpidev_set_unitaddr()."); 728 return (AE_BAD_PARAMETER); 729 } 730 731 if (infop->awi_info->Valid & ACPI_VALID_UID) { 732 if (ndi_prop_update_string(DDI_DEV_T_NONE, infop->awi_dip, 733 ACPIDEV_PROP_NAME_ACPI_UID, 734 infop->awi_info->UniqueId.String) != NDI_SUCCESS) { 735 cmn_err(CE_WARN, 736 "!acpidev: failed to set UID property for %s.", 737 infop->awi_name); 738 return (AE_ERROR); 739 } 740 } 741 742 if (unitaddr == NULL && (infop->awi_info->Valid & ACPI_VALID_UID)) { 743 /* Try to generate unit address from _UID. */ 744 if (fmts == NULL) { 745 fmts = acpidev_uid_formats; 746 nfmt = sizeof (acpidev_uid_formats) / sizeof (char *); 747 } 748 unitaddr = acpidev_generate_unitaddr( 749 infop->awi_info->UniqueId.String, fmts, nfmt, 750 unit, sizeof (unit)); 751 /* Generate pseudo sequential unit address. */ 752 if (unitaddr == NULL) { 753 unitaddr = acpidev_generate_pseudo_unitaddr( 754 infop->awi_info->UniqueId.String, 755 infop->awi_class_curr->adc_class_id, 756 unit, sizeof (unit)); 757 } 758 if (unitaddr == NULL) { 759 cmn_err(CE_WARN, "!acpidev: failed to generate unit " 760 "address from %s.", 761 infop->awi_info->UniqueId.String); 762 return (AE_ERROR); 763 } 764 } 765 if (unitaddr == NULL) { 766 /* 767 * Some ACPI objects may have no _UID method available, so we 768 * can't generate the "unit-address" property for them. 769 * On the other hand, it's legal to support such a device 770 * without a unit address, so return success here. 771 */ 772 return (AE_OK); 773 } 774 775 if (ndi_prop_update_string(DDI_DEV_T_NONE, infop->awi_dip, 776 ACPIDEV_PROP_NAME_UNIT_ADDR, unitaddr) != NDI_SUCCESS) { 777 cmn_err(CE_WARN, "!acpidev: failed to set unitaddr for %s.", 778 infop->awi_name); 779 return (AE_ERROR); 780 } 781 782 return (AE_OK); 783 } 784 785 ACPI_STATUS 786 acpidev_set_compatible(acpidev_walk_info_t *infop, char **compat, int acount) 787 { 788 int count, i, j; 789 char **compatible = NULL; 790 ACPI_DEVICE_INFO *di; 791 792 /* 793 * Generate compatible list for device based on: 794 * * Device HID if available 795 * * Device CIDs if available 796 * * property array passed in 797 */ 798 ASSERT(infop != NULL); 799 ASSERT(infop->awi_dip != NULL); 800 ASSERT(infop->awi_info != NULL); 801 ASSERT(compat != NULL || acount == 0); 802 if (infop == NULL || infop->awi_dip == NULL || 803 infop->awi_info == NULL || (compat == NULL && acount != 0)) { 804 ACPIDEV_DEBUG(CE_WARN, "!acpidev: invalid parameters " 805 "in acpidev_set_compatible()."); 806 return (AE_BAD_PARAMETER); 807 } 808 809 /* Compute string count. */ 810 count = acount; 811 di = infop->awi_info; 812 if (di->Valid & ACPI_VALID_HID) { 813 count++; 814 } 815 if (di->Valid & ACPI_VALID_CID) { 816 count += di->CompatibleIdList.Count; 817 } 818 compatible = kmem_zalloc(sizeof (char *) * count, KM_SLEEP); 819 820 /* Generate string array. */ 821 i = 0; 822 if (di->Valid & ACPI_VALID_HID) { 823 compatible[i++] = di->HardwareId.String; 824 } 825 if (di->Valid & ACPI_VALID_CID) { 826 for (j = 0; j < di->CompatibleIdList.Count; j++) { 827 compatible[i++] = di->CompatibleIdList.Ids[j].String; 828 } 829 } 830 for (j = 0; j < acount; j++) { 831 compatible[i++] = compat[j]; 832 } 833 ASSERT(i == count); 834 835 /* Set "compatible" property. */ 836 if (ndi_prop_update_string_array(DDI_DEV_T_NONE, infop->awi_dip, 837 OBP_COMPATIBLE, compatible, count) != NDI_SUCCESS) { 838 cmn_err(CE_WARN, "!acpidev: failed to set compatible " 839 "property for %s in acpidev_set_compatible().", 840 infop->awi_name); 841 kmem_free(compatible, count * sizeof (char *)); 842 return (AE_ERROR); 843 } 844 kmem_free(compatible, count * sizeof (char *)); 845 846 return (AE_OK); 847 } 848 849 /* Evaluate _OST method under object, which is used to support hotplug event. */ 850 ACPI_STATUS 851 acpidev_eval_ost(ACPI_HANDLE hdl, uint32_t code, uint32_t status, 852 char *bufp, size_t len) 853 { 854 ACPI_STATUS rc; 855 ACPI_OBJECT args[3]; 856 ACPI_OBJECT_LIST arglist; 857 858 args[0].Type = ACPI_TYPE_INTEGER; 859 args[0].Integer.Value = code; 860 args[1].Type = ACPI_TYPE_INTEGER; 861 args[1].Integer.Value = status; 862 args[2].Type = ACPI_TYPE_BUFFER; 863 args[2].Buffer.Pointer = (UINT8 *)bufp; 864 args[2].Buffer.Length = (UINT32)len; 865 if (bufp == NULL || len == 0) { 866 arglist.Count = 2; 867 } else { 868 arglist.Count = 3; 869 } 870 arglist.Pointer = args; 871 rc = AcpiEvaluateObject(hdl, ACPIDEV_METHOD_NAME_OST, &arglist, NULL); 872 if (rc != AE_OK && rc != AE_NOT_FOUND) { 873 ACPIDEV_DEBUG(CE_WARN, 874 "!acpidev: failed to evaluate _OST method, code 0x%x.", rc); 875 } 876 877 return (rc); 878 } 879 880 ACPI_STATUS 881 acpidev_eval_ej0(ACPI_HANDLE hdl) 882 { 883 ACPI_STATUS rc; 884 ACPI_OBJECT args[1]; 885 ACPI_OBJECT_LIST arglist; 886 887 /* 888 * Quotation from ACPI spec 4.0 section 6.3.3. 889 * Arg0 An Integer containing a device ejection control 890 * 0 Cancel a mark for ejection request (EJ0 will never be called 891 * with this value) 892 * 1 Hot eject or mark for ejection 893 */ 894 args[0].Type = ACPI_TYPE_INTEGER; 895 args[0].Integer.Value = 1; 896 arglist.Count = 1; 897 arglist.Pointer = args; 898 rc = AcpiEvaluateObject(hdl, ACPIDEV_METHOD_NAME_EJ0, &arglist, NULL); 899 if (rc != AE_OK) { 900 ACPIDEV_DEBUG(CE_WARN, 901 "!acpidev: failed to evaluate _EJ0 method, code 0x%x.", rc); 902 } 903 904 return (rc); 905 } 906 907 ACPI_STATUS 908 acpidev_eval_pxm(ACPI_HANDLE hdl, uint32_t *idp) 909 { 910 int pxmid; 911 912 ASSERT(idp != NULL); 913 914 /* 915 * Try to evaluate ACPI _PXM method to get proximity doamin id. 916 * Quotation from ACPI4.0: 917 * If the Local APIC ID / Local SAPIC ID / Local x2APIC ID of a 918 * dynamically added processor is not present in the System Resource 919 * Affinity Table (SRAT), a _PXM object must exist for the processor's 920 * device or one of its ancestors in the ACPI Namespace. 921 */ 922 while (hdl != NULL) { 923 if (ACPI_SUCCESS(acpica_eval_int(hdl, 924 ACPIDEV_METHOD_NAME_PXM, &pxmid))) { 925 *idp = (uint32_t)pxmid; 926 return (AE_OK); 927 } 928 if (ACPI_FAILURE(AcpiGetParent(hdl, &hdl))) { 929 break; 930 } 931 } 932 933 return (AE_NOT_FOUND); 934 } 935