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