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