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