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