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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 /* 26 * Copyright (c) 2009, Intel Corporation. 27 * All rights reserved. 28 */ 29 /* 30 * Solaris x86 ACPI CA services 31 */ 32 33 #include <sys/file.h> 34 #include <sys/errno.h> 35 #include <sys/conf.h> 36 #include <sys/modctl.h> 37 #include <sys/open.h> 38 #include <sys/stat.h> 39 #include <sys/ddi.h> 40 #include <sys/sunddi.h> 41 #include <sys/esunddi.h> 42 #include <sys/kstat.h> 43 #include <sys/x86_archext.h> 44 45 #include <sys/acpi/acpi.h> 46 #include <sys/acpica.h> 47 48 /* 49 * 50 */ 51 static struct modlmisc modlmisc = { 52 &mod_miscops, 53 "ACPI interpreter", 54 }; 55 56 static struct modlinkage modlinkage = { 57 MODREV_1, /* MODREV_1 manual */ 58 (void *)&modlmisc, /* module linkage */ 59 NULL, /* list terminator */ 60 }; 61 62 /* 63 * Local prototypes 64 */ 65 66 static void acpica_init_kstats(void); 67 68 /* 69 * Local data 70 */ 71 72 static kmutex_t acpica_module_lock; 73 static kstat_t *acpica_ksp; 74 75 /* 76 * State of acpica subsystem 77 * After successful initialization, will be ACPICA_INITIALIZED 78 */ 79 int acpica_init_state = ACPICA_NOT_INITIALIZED; 80 81 /* 82 * Following are set by acpica_process_user_options() 83 * 84 * acpica_enable = FALSE prevents initialization of ACPI CA 85 * completely 86 * 87 * acpi_init_level determines level of ACPI CA functionality 88 * enabled in acpica_init() 89 */ 90 int acpica_enable; 91 UINT32 acpi_init_level; 92 93 /* 94 * Non-zero enables lax behavior with respect to some 95 * common ACPI BIOS issues; see ACPI CA documentation 96 * Setting this to zero causes ACPI CA to enforce strict 97 * compliance with ACPI specification 98 */ 99 int acpica_enable_interpreter_slack = 1; 100 101 /* 102 * For non-DEBUG builds, set the ACPI CA debug level to 0 103 * to quiet chatty BIOS output into /var/adm/messages 104 * Field-patchable for diagnostic use. 105 */ 106 #ifdef DEBUG 107 int acpica_muzzle_debug_output = 0; 108 #else 109 int acpica_muzzle_debug_output = 1; 110 #endif 111 112 /* 113 * ACPI DDI hooks 114 */ 115 static int acpica_ddi_setwake(dev_info_t *dip, int level); 116 117 int 118 _init(void) 119 { 120 int error = EBUSY; 121 int status; 122 extern int (*acpi_fp_setwake)(); 123 124 mutex_init(&acpica_module_lock, NULL, MUTEX_DRIVER, NULL); 125 126 if ((error = mod_install(&modlinkage)) != 0) { 127 mutex_destroy(&acpica_module_lock); 128 goto load_error; 129 } 130 131 AcpiGbl_EnableInterpreterSlack = (acpica_enable_interpreter_slack != 0); 132 133 /* global ACPI CA initialization */ 134 if (ACPI_FAILURE(status = AcpiInitializeSubsystem())) 135 cmn_err(CE_WARN, "!AcpiInitializeSubsystem failed: %d", status); 136 137 /* initialize table manager */ 138 if (ACPI_FAILURE(status = AcpiInitializeTables(NULL, 0, 0))) 139 cmn_err(CE_WARN, "!AcpiInitializeTables failed: %d", status); 140 141 acpi_fp_setwake = acpica_ddi_setwake; 142 143 load_error: 144 return (error); 145 } 146 147 int 148 _info(struct modinfo *modinfop) 149 { 150 return (mod_info(&modlinkage, modinfop)); 151 } 152 153 int 154 _fini(void) 155 { 156 /* 157 * acpica module is never unloaded at run-time; there's always 158 * a PSM depending on it, at the very least 159 */ 160 return (EBUSY); 161 } 162 163 /* 164 * Install acpica-provided address-space handlers 165 */ 166 static int 167 acpica_install_handlers() 168 { 169 ACPI_STATUS rv = AE_OK; 170 171 /* 172 * Install ACPI CA default handlers 173 */ 174 if (AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 175 ACPI_ADR_SPACE_SYSTEM_MEMORY, 176 ACPI_DEFAULT_HANDLER, NULL, NULL) != AE_OK) { 177 cmn_err(CE_WARN, "!acpica: no default handler for" 178 " system memory"); 179 rv = AE_ERROR; 180 } 181 182 if (AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 183 ACPI_ADR_SPACE_SYSTEM_IO, 184 ACPI_DEFAULT_HANDLER, NULL, NULL) != AE_OK) { 185 cmn_err(CE_WARN, "!acpica: no default handler for" 186 " system I/O"); 187 rv = AE_ERROR; 188 } 189 190 if (AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 191 ACPI_ADR_SPACE_PCI_CONFIG, 192 ACPI_DEFAULT_HANDLER, NULL, NULL) != AE_OK) { 193 cmn_err(CE_WARN, "!acpica: no default handler for" 194 " PCI Config"); 195 rv = AE_ERROR; 196 } 197 198 199 return (rv); 200 } 201 202 /* 203 * Find the BIOS date, and return TRUE if supplied 204 * date is same or later than the BIOS date, or FALSE 205 * if the BIOS date can't be fetched for any reason 206 */ 207 static int 208 acpica_check_bios_date(int yy, int mm, int dd) 209 { 210 211 char *datep; 212 int bios_year, bios_month, bios_day; 213 214 /* If firmware has no bios, skip the check */ 215 if (ddi_prop_exists(DDI_DEV_T_ANY, ddi_root_node(), DDI_PROP_DONTPASS, 216 "bios-free")) 217 return (TRUE); 218 219 /* 220 * PC BIOSes contain a string in the form of 221 * "mm/dd/yy" at absolute address 0xffff5, 222 * where mm, dd and yy are all ASCII digits. 223 * We map the string, pluck out the values, 224 * and accept all BIOSes from 1 Jan 1999 on 225 * as valid. 226 */ 227 228 if ((datep = (char *)AcpiOsMapMemory(0xffff5, 8)) == NULL) 229 return (FALSE); 230 231 /* year */ 232 bios_year = ((int)(*(datep + 6) - '0') * 10) + (*(datep + 7) - '0'); 233 /* month */ 234 bios_month = ((int)(*datep - '0') * 10) + (*(datep + 1) - '0'); 235 /* day */ 236 bios_day = ((int)(*(datep + 3) - '0') * 10) + (*(datep + 4) - '0'); 237 238 AcpiOsUnmapMemory((void *) datep, 8); 239 240 if (bios_year < 0 || bios_year > 99 || bios_month < 0 || 241 bios_month > 99 || bios_day < 0 || bios_day > 99) { 242 /* non-digit chars in BIOS date */ 243 return (FALSE); 244 } 245 246 /* 247 * Adjust for 2-digit year; note to grand-children: 248 * need a new scheme before 2080 rolls around 249 */ 250 bios_year += (bios_year >= 80 && bios_year <= 99) ? 251 1900 : 2000; 252 253 if (bios_year < yy) 254 return (FALSE); 255 else if (bios_year > yy) 256 return (TRUE); 257 258 if (bios_month < mm) 259 return (FALSE); 260 else if (bios_month > mm) 261 return (TRUE); 262 263 if (bios_day < dd) 264 return (FALSE); 265 266 return (TRUE); 267 } 268 269 /* 270 * Check for Metropolis systems with BIOSes older than 10/12/04 271 * return TRUE if BIOS requires legacy mode, FALSE otherwise 272 */ 273 static int 274 acpica_metro_old_bios() 275 { 276 ACPI_TABLE_HEADER *fadt; 277 278 /* get the FADT */ 279 if (AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **)&fadt) != 280 AE_OK) 281 return (FALSE); 282 283 /* compare OEM Table ID to "SUNmetro" - no match, return false */ 284 if (strncmp("SUNmetro", fadt->OemTableId, 8)) 285 return (FALSE); 286 287 /* On a Metro - return FALSE if later than 10/12/04 */ 288 return (!acpica_check_bios_date(2004, 10, 12)); 289 } 290 291 292 /* 293 * Process acpi-user-options property if present 294 */ 295 static void 296 acpica_process_user_options() 297 { 298 static int processed = 0; 299 int acpi_user_options; 300 char *acpi_prop; 301 302 /* 303 * return if acpi-user-options has already been processed 304 */ 305 if (processed) 306 return; 307 else 308 processed = 1; 309 310 /* converts acpi-user-options from type string to int, if any */ 311 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 312 DDI_PROP_DONTPASS, "acpi-user-options", &acpi_prop) == 313 DDI_PROP_SUCCESS) { 314 long data; 315 int ret; 316 ret = ddi_strtol(acpi_prop, NULL, 0, &data); 317 if (ret == 0) { 318 e_ddi_prop_remove(DDI_DEV_T_NONE, ddi_root_node(), 319 "acpi-user-options"); 320 e_ddi_prop_update_int(DDI_DEV_T_NONE, ddi_root_node(), 321 "acpi-user-options", data); 322 } 323 ddi_prop_free(acpi_prop); 324 } 325 326 /* 327 * fetch the optional options property 328 */ 329 acpi_user_options = ddi_prop_get_int(DDI_DEV_T_ANY, ddi_root_node(), 330 DDI_PROP_DONTPASS, "acpi-user-options", 0); 331 332 /* 333 * Note that 'off' has precedence over 'on' 334 * Also note - all cases of ACPI_OUSER_MASK 335 * provided here, no default: case is present 336 */ 337 switch (acpi_user_options & ACPI_OUSER_MASK) { 338 case ACPI_OUSER_DFLT: 339 acpica_enable = acpica_check_bios_date(1999, 1, 1); 340 break; 341 case ACPI_OUSER_ON: 342 acpica_enable = TRUE; 343 break; 344 case ACPI_OUSER_OFF: 345 case ACPI_OUSER_OFF | ACPI_OUSER_ON: 346 acpica_enable = FALSE; 347 break; 348 } 349 350 acpi_init_level = ACPI_FULL_INITIALIZATION; 351 352 /* 353 * special test here; may be generalized in the 354 * future - test for a machines that are known to 355 * work only in legacy mode, and set OUSER_LEGACY if 356 * we're on one 357 */ 358 if (acpica_metro_old_bios()) 359 acpi_user_options |= ACPI_OUSER_LEGACY; 360 361 /* 362 * If legacy mode is specified, set initialization 363 * options to avoid entering ACPI mode and hooking SCI 364 * - basically try to act like legacy acpi_intp 365 */ 366 if ((acpi_user_options & ACPI_OUSER_LEGACY) != 0) 367 acpi_init_level |= (ACPI_NO_ACPI_ENABLE | ACPI_NO_HANDLER_INIT); 368 369 /* 370 * modify default ACPI CA debug output level for non-DEBUG builds 371 * (to avoid BIOS debug chatter in /var/adm/messages) 372 */ 373 if (acpica_muzzle_debug_output) 374 AcpiDbgLevel = 0; 375 } 376 377 /* 378 * Initialize the CA subsystem if it hasn't been done already 379 */ 380 int 381 acpica_init() 382 { 383 extern void acpica_find_ioapics(void); 384 ACPI_STATUS status; 385 386 /* 387 * Make sure user options are processed, 388 * then fail to initialize if ACPI CA has been 389 * disabled 390 */ 391 acpica_process_user_options(); 392 if (!acpica_enable) 393 return (AE_ERROR); 394 395 mutex_enter(&acpica_module_lock); 396 if (acpica_init_state == ACPICA_INITIALIZED) { 397 mutex_exit(&acpica_module_lock); 398 return (AE_OK); 399 } 400 401 if (ACPI_FAILURE(status = AcpiLoadTables())) 402 goto error; 403 404 if (ACPI_FAILURE(status = acpica_install_handlers())) 405 goto error; 406 407 if (ACPI_FAILURE(status = AcpiEnableSubsystem(acpi_init_level))) 408 goto error; 409 410 /* do after AcpiEnableSubsystem() so GPEs are initialized */ 411 acpica_ec_init(); /* initialize EC if present */ 412 413 if (ACPI_FAILURE(status = AcpiInitializeObjects(0))) 414 goto error; 415 416 acpica_init_state = ACPICA_INITIALIZED; 417 418 /* 419 * If we are running on the Xen hypervisor as dom0 we need to 420 * find the ioapics so we can prevent ACPI from trying to 421 * access them. 422 */ 423 if (get_hwenv() == HW_XEN_PV && is_controldom()) 424 acpica_find_ioapics(); 425 acpica_init_kstats(); 426 error: 427 if (acpica_init_state != ACPICA_INITIALIZED) { 428 cmn_err(CE_NOTE, "!failed to initialize ACPI services"); 429 } 430 431 /* 432 * Set acpi-status to 13 if acpica has been initialized successfully. 433 * This indicates that acpica is up and running. This variable name 434 * and value were chosen in order to remain compatible with acpi_intp. 435 */ 436 e_ddi_prop_update_int(DDI_DEV_T_NONE, ddi_root_node(), "acpi-status", 437 (ACPI_SUCCESS(status)) ? (ACPI_BOOT_INIT | ACPI_BOOT_ENABLE | 438 ACPI_BOOT_BOOTCONF) : 0); 439 440 /* Mark acpica subsystem as fully initialized. */ 441 if (ACPI_SUCCESS(status) && 442 acpi_init_level == ACPI_FULL_INITIALIZATION) { 443 acpica_set_core_feature(ACPI_FEATURE_FULL_INIT); 444 } 445 446 mutex_exit(&acpica_module_lock); 447 return (status); 448 } 449 450 /* 451 * SCI handling 452 */ 453 454 ACPI_STATUS 455 acpica_get_sci(int *sci_irq, iflag_t *sci_flags) 456 { 457 ACPI_SUBTABLE_HEADER *ap; 458 ACPI_TABLE_MADT *mat; 459 ACPI_MADT_INTERRUPT_OVERRIDE *mio; 460 ACPI_TABLE_FADT *fadt; 461 int madt_seen, madt_size; 462 463 464 /* 465 * Make sure user options are processed, 466 * then return error if ACPI CA has been 467 * disabled or system is not running in ACPI 468 * and won't need/understand SCI 469 */ 470 acpica_process_user_options(); 471 if ((!acpica_enable) || (acpi_init_level & ACPI_NO_ACPI_ENABLE)) 472 return (AE_ERROR); 473 474 /* 475 * according to Intel ACPI developers, SCI 476 * conforms to PCI bus conventions; level/low 477 * unless otherwise directed by overrides. 478 */ 479 sci_flags->intr_el = INTR_EL_LEVEL; 480 sci_flags->intr_po = INTR_PO_ACTIVE_LOW; 481 sci_flags->bustype = BUS_PCI; /* we *do* conform to PCI */ 482 483 /* get the SCI from the FADT */ 484 if (AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **)&fadt) != 485 AE_OK) 486 return (AE_ERROR); 487 488 *sci_irq = fadt->SciInterrupt; 489 490 /* search for ISOs that modify it */ 491 /* if we don't find a MADT, that's OK; no ISOs then */ 492 if (AcpiGetTable(ACPI_SIG_MADT, 1, (ACPI_TABLE_HEADER **) &mat) != 493 AE_OK) 494 return (AE_OK); 495 496 ap = (ACPI_SUBTABLE_HEADER *) (mat + 1); 497 madt_size = mat->Header.Length; 498 madt_seen = sizeof (*mat); 499 500 while (madt_seen < madt_size) { 501 switch (ap->Type) { 502 case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE: 503 mio = (ACPI_MADT_INTERRUPT_OVERRIDE *) ap; 504 if (mio->SourceIrq == *sci_irq) { 505 *sci_irq = mio->GlobalIrq; 506 sci_flags->intr_el = (mio->IntiFlags & 507 ACPI_MADT_TRIGGER_MASK) >> 2; 508 sci_flags->intr_po = mio->IntiFlags & 509 ACPI_MADT_POLARITY_MASK; 510 } 511 break; 512 } 513 514 /* advance to next entry */ 515 madt_seen += ap->Length; 516 ap = (ACPI_SUBTABLE_HEADER *)(((char *)ap) + ap->Length); 517 } 518 519 /* 520 * One more check; if ISO said "conform", revert to default 521 */ 522 if (sci_flags->intr_el == INTR_EL_CONFORM) 523 sci_flags->intr_el = INTR_EL_LEVEL; 524 if (sci_flags->intr_po == INTR_PO_CONFORM) 525 sci_flags->intr_po = INTR_PO_ACTIVE_LOW; 526 527 return (AE_OK); 528 } 529 530 /* 531 * Sets ACPI wake state for device referenced by dip. 532 * If level is S0 (0), disables wake event; otherwise, 533 * enables wake event which will wake system from level. 534 */ 535 static int 536 acpica_ddi_setwake(dev_info_t *dip, int level) 537 { 538 ACPI_STATUS status; 539 ACPI_HANDLE devobj, gpeobj; 540 ACPI_OBJECT *prw, *gpe; 541 ACPI_BUFFER prw_buf; 542 int gpebit, pwr_res_count, prw_level, rv; 543 544 /* 545 * initialize these early so we can use a common 546 * exit point below 547 */ 548 prw_buf.Pointer = NULL; 549 prw_buf.Length = ACPI_ALLOCATE_BUFFER; 550 rv = 0; 551 552 /* 553 * Attempt to get a handle to a corresponding ACPI object. 554 * If no object is found, return quietly, since not all 555 * devices have corresponding ACPI objects. 556 */ 557 status = acpica_get_handle(dip, &devobj); 558 if (ACPI_FAILURE(status)) { 559 char pathbuf[MAXPATHLEN]; 560 ddi_pathname(dip, pathbuf); 561 #ifdef DEBUG 562 cmn_err(CE_NOTE, "!acpica_ddi_setwake: could not get" 563 " handle for %s, %s:%d", pathbuf, ddi_driver_name(dip), 564 ddi_get_instance(dip)); 565 #endif 566 goto done; 567 } 568 569 /* 570 * Attempt to evaluate _PRW object. 571 * If no valid object is found, return quietly, since not all 572 * devices have _PRW objects. 573 */ 574 status = AcpiEvaluateObject(devobj, "_PRW", NULL, &prw_buf); 575 prw = prw_buf.Pointer; 576 if (ACPI_FAILURE(status) || prw_buf.Length == 0 || prw == NULL || 577 prw->Type != ACPI_TYPE_PACKAGE || prw->Package.Count < 2 || 578 prw->Package.Elements[1].Type != ACPI_TYPE_INTEGER) { 579 cmn_err(CE_NOTE, "acpica_ddi_setwake: could not " 580 " evaluate _PRW"); 581 goto done; 582 } 583 584 /* fetch the lowest wake level from the _PRW */ 585 prw_level = prw->Package.Elements[1].Integer.Value; 586 587 /* 588 * process the GPE description 589 */ 590 switch (prw->Package.Elements[0].Type) { 591 case ACPI_TYPE_INTEGER: 592 gpeobj = NULL; 593 gpebit = prw->Package.Elements[0].Integer.Value; 594 break; 595 case ACPI_TYPE_PACKAGE: 596 gpe = &prw->Package.Elements[0]; 597 if (gpe->Package.Count != 2 || 598 gpe->Package.Elements[1].Type != ACPI_TYPE_INTEGER) 599 goto done; 600 gpeobj = gpe->Package.Elements[0].Reference.Handle; 601 gpebit = gpe->Package.Elements[1].Integer.Value; 602 if (gpeobj == NULL) 603 goto done; 604 default: 605 goto done; 606 } 607 608 rv = -1; 609 if (level == 0) { 610 if (ACPI_FAILURE(AcpiDisableGpe(gpeobj, gpebit, ACPI_NOT_ISR))) 611 goto done; 612 } else if (prw_level <= level) { 613 if (ACPI_SUCCESS( 614 AcpiSetGpeType(gpeobj, gpebit, ACPI_GPE_TYPE_WAKE))) 615 if (ACPI_FAILURE( 616 AcpiEnableGpe(gpeobj, gpebit, ACPI_NOT_ISR))) 617 goto done; 618 } 619 rv = 0; 620 done: 621 if (prw_buf.Pointer != NULL) 622 AcpiOsFree(prw_buf.Pointer); 623 return (rv); 624 } 625 626 /* 627 * kstat access to a limited set of ACPI propertis 628 */ 629 static void 630 acpica_init_kstats() 631 { 632 ACPI_HANDLE s3handle; 633 ACPI_STATUS status; 634 ACPI_TABLE_FADT *fadt; 635 kstat_named_t *knp; 636 637 /* 638 * Create a small set of named kstats; just return in the rare 639 * case of a failure, * in which case, the kstats won't be present. 640 */ 641 if ((acpica_ksp = kstat_create("acpi", 0, "acpi", "misc", 642 KSTAT_TYPE_NAMED, 2, 0)) == NULL) 643 return; 644 645 /* 646 * initialize kstat 'S3' to reflect the presence of \_S3 in 647 * the ACPI namespace (1 = present, 0 = not present) 648 */ 649 knp = acpica_ksp->ks_data; 650 knp->value.l = (AcpiGetHandle(NULL, "\\_S3", &s3handle) == AE_OK); 651 kstat_named_init(knp, "S3", KSTAT_DATA_LONG); 652 knp++; /* advance to next named kstat */ 653 654 /* 655 * initialize kstat 'preferred_pm_profile' to the value 656 * contained in the (always present) FADT 657 */ 658 status = AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **)&fadt); 659 knp->value.l = (status == AE_OK) ? fadt->PreferredProfile : -1; 660 kstat_named_init(knp, "preferred_pm_profile", KSTAT_DATA_LONG); 661 662 /* 663 * install the named kstats 664 */ 665 kstat_install(acpica_ksp); 666 } 667 668 /* 669 * Attempt to save the current ACPI settings (_CRS) for the device 670 * which corresponds to the supplied devinfo node. The settings are 671 * saved as a property on the dip. If no ACPI object is found to be 672 * associated with the devinfo node, no action is taken and no error 673 * is reported. 674 */ 675 void 676 acpica_ddi_save_resources(dev_info_t *dip) 677 { 678 ACPI_HANDLE devobj; 679 ACPI_BUFFER resbuf; 680 int ret; 681 682 resbuf.Length = ACPI_ALLOCATE_BUFFER; 683 if (ACPI_FAILURE(acpica_get_handle(dip, &devobj)) || 684 ACPI_FAILURE(AcpiGetCurrentResources(devobj, &resbuf))) 685 return; 686 687 ret = ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 688 "acpi-crs", resbuf.Pointer, resbuf.Length); 689 690 ASSERT(ret == DDI_PROP_SUCCESS); 691 692 AcpiOsFree(resbuf.Pointer); 693 } 694 695 /* 696 * If the supplied devinfo node has an ACPI settings property attached, 697 * restore them to the associated ACPI device using _SRS. The property 698 * is deleted from the devinfo node afterward. 699 */ 700 void 701 acpica_ddi_restore_resources(dev_info_t *dip) 702 { 703 ACPI_HANDLE devobj; 704 ACPI_BUFFER resbuf; 705 uchar_t *propdata; 706 uint_t proplen; 707 708 if (ACPI_FAILURE(acpica_get_handle(dip, &devobj))) 709 return; 710 711 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 712 "acpi-crs", &propdata, &proplen) != DDI_PROP_SUCCESS) 713 return; 714 715 resbuf.Pointer = propdata; 716 resbuf.Length = proplen; 717 (void) AcpiSetCurrentResources(devobj, &resbuf); 718 ddi_prop_free(propdata); 719 (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "acpi-crs"); 720 } 721