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  * 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,  /* module linkage */
  62         NULL,                   /* list terminator */
  63 };
  64 
  65 /*
  66  * Local prototypes
  67  */
  68 
  69 struct parsed_prw {
  70         ACPI_HANDLE     prw_gpeobj;
  71         int             prw_gpebit;
  72         int             prw_level;
  73 };
  74 
  75 static void     acpica_init_kstats(void);
  76 static ACPI_STATUS      acpica_init_PRW(
  77         ACPI_HANDLE     hdl,
  78         UINT32          lvl,
  79         void            *ctxp,
  80         void            **rvpp);
  81 
  82 static ACPI_STATUS      acpica_parse_PRW(
  83         ACPI_BUFFER     *prw_buf,
  84         struct parsed_prw *prw);
  85 
  86 /*
  87  * Local data
  88  */
  89 
  90 static kmutex_t acpica_module_lock;
  91 static kstat_t  *acpica_ksp;
  92 
  93 /*
  94  * State of acpica subsystem
  95  * After successful initialization, will be ACPICA_INITIALIZED
  96  */
  97 int acpica_init_state = ACPICA_NOT_INITIALIZED;
  98 
  99 /*
 100  * Following are set by acpica_process_user_options()
 101  *
 102  * acpica_enable = FALSE prevents initialization of ACPI CA
 103  * completely
 104  *
 105  * acpi_init_level determines level of ACPI CA functionality
 106  * enabled in acpica_init()
 107  */
 108 int     acpica_enable;
 109 UINT32  acpi_init_level;
 110 
 111 /*
 112  * Non-zero enables lax behavior with respect to some
 113  * common ACPI BIOS issues; see ACPI CA documentation
 114  * Setting this to zero causes ACPI CA to enforce strict
 115  * compliance with ACPI specification
 116  */
 117 int acpica_enable_interpreter_slack = 1;
 118 
 119 /*
 120  * For non-DEBUG builds, set the ACPI CA debug level to 0
 121  * to quiet chatty BIOS output into /var/adm/messages
 122  * Field-patchable for diagnostic use.
 123  */
 124 #ifdef  DEBUG
 125 int acpica_muzzle_debug_output = 0;
 126 #else
 127 int acpica_muzzle_debug_output = 1;
 128 #endif
 129 
 130 /*
 131  * ACPI DDI hooks
 132  */
 133 static int acpica_ddi_setwake(dev_info_t *dip, int level);
 134 
 135 int
 136 _init(void)
 137 {
 138         int error = EBUSY;
 139         int     status;
 140         extern int (*acpi_fp_setwake)();
 141         extern kmutex_t cpu_map_lock;
 142 
 143         mutex_init(&acpica_module_lock, NULL, MUTEX_DRIVER, NULL);
 144         mutex_init(&cpu_map_lock, NULL, MUTEX_SPIN,
 145             (ddi_iblock_cookie_t)ipltospl(DISP_LEVEL));
 146 
 147         if ((error = mod_install(&modlinkage)) != 0) {
 148                 mutex_destroy(&acpica_module_lock);
 149                 goto load_error;
 150         }
 151 
 152         AcpiGbl_EnableInterpreterSlack = (acpica_enable_interpreter_slack != 0);
 153 
 154         /* global ACPI CA initialization */
 155         if (ACPI_FAILURE(status = AcpiInitializeSubsystem()))
 156                 cmn_err(CE_WARN, "!AcpiInitializeSubsystem failed: %d", status);
 157 
 158         /* initialize table manager */
 159         if (ACPI_FAILURE(status = AcpiInitializeTables(NULL, 0, 0)))
 160                 cmn_err(CE_WARN, "!AcpiInitializeTables failed: %d", status);
 161 
 162         acpi_fp_setwake = acpica_ddi_setwake;
 163 
 164 load_error:
 165         return (error);
 166 }
 167 
 168 int
 169 _info(struct modinfo *modinfop)
 170 {
 171         return (mod_info(&modlinkage, modinfop));
 172 }
 173 
 174 int
 175 _fini(void)
 176 {
 177         /*
 178          * acpica module is never unloaded at run-time; there's always
 179          * a PSM depending on it, at the very least
 180          */
 181         return (EBUSY);
 182 }
 183 
 184 /*
 185  * Install acpica-provided (default) address-space handlers
 186  * that may be needed before AcpiEnableSubsystem() runs.
 187  * See the comment in AcpiInstallAddressSpaceHandler().
 188  * Default handlers for remaining address spaces are
 189  * installed later, in AcpiEnableSubsystem.
 190  */
 191 static int
 192 acpica_install_handlers()
 193 {
 194         ACPI_STATUS     rv = AE_OK;
 195 
 196         /*
 197          * Install ACPI CA default handlers
 198          */
 199         if (AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
 200             ACPI_ADR_SPACE_SYSTEM_MEMORY,
 201             ACPI_DEFAULT_HANDLER, NULL, NULL) != AE_OK) {
 202                 cmn_err(CE_WARN, "!acpica: no default handler for"
 203                     " system memory");
 204                 rv = AE_ERROR;
 205         }
 206 
 207         if (AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
 208             ACPI_ADR_SPACE_SYSTEM_IO,
 209             ACPI_DEFAULT_HANDLER, NULL, NULL) != AE_OK) {
 210                 cmn_err(CE_WARN, "!acpica: no default handler for"
 211                     " system I/O");
 212                 rv = AE_ERROR;
 213         }
 214 
 215         if (AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
 216             ACPI_ADR_SPACE_PCI_CONFIG,
 217             ACPI_DEFAULT_HANDLER, NULL, NULL) != AE_OK) {
 218                 cmn_err(CE_WARN, "!acpica: no default handler for"
 219                     " PCI Config");
 220                 rv = AE_ERROR;
 221         }
 222 
 223         if (AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
 224             ACPI_ADR_SPACE_DATA_TABLE,
 225             ACPI_DEFAULT_HANDLER, NULL, NULL) != AE_OK) {
 226                 cmn_err(CE_WARN, "!acpica: no default handler for"
 227                     " Data Table");
 228                 rv = AE_ERROR;
 229         }
 230 
 231         return (rv);
 232 }
 233 
 234 /*
 235  * Find the BIOS date, and return TRUE if supplied
 236  * date is same or later than the BIOS date, or FALSE
 237  * if the BIOS date can't be fetched for any reason
 238  */
 239 static int
 240 acpica_check_bios_date(int yy, int mm, int dd)
 241 {
 242 
 243         char *datep;
 244         int bios_year, bios_month, bios_day;
 245 
 246         /* If firmware has no bios, skip the check */
 247         if (ddi_prop_exists(DDI_DEV_T_ANY, ddi_root_node(), DDI_PROP_DONTPASS,
 248             "bios-free"))
 249                 return (TRUE);
 250 
 251         /*
 252          * PC BIOSes contain a string in the form of
 253          * "mm/dd/yy" at absolute address 0xffff5,
 254          * where mm, dd and yy are all ASCII digits.
 255          * We map the string, pluck out the values,
 256          * and accept all BIOSes from 1 Jan 1999 on
 257          * as valid.
 258          */
 259 
 260         if ((datep = (char *)AcpiOsMapMemory(0xffff5, 8)) == NULL)
 261                 return (FALSE);
 262 
 263         /* year */
 264         bios_year = ((int)(*(datep + 6) - '0') * 10) + (*(datep + 7) - '0');
 265         /* month */
 266         bios_month = ((int)(*datep - '0') * 10) + (*(datep + 1) - '0');
 267         /* day */
 268         bios_day = ((int)(*(datep + 3) - '0') * 10) + (*(datep + 4) - '0');
 269 
 270         AcpiOsUnmapMemory((void *) datep, 8);
 271 
 272         if (bios_year < 0 || bios_year > 99 || bios_month < 0 ||
 273             bios_month > 99 || bios_day < 0 || bios_day > 99) {
 274                 /* non-digit chars in BIOS date */
 275                 return (FALSE);
 276         }
 277 
 278         /*
 279          * Adjust for 2-digit year; note to grand-children:
 280          * need a new scheme before 2080 rolls around
 281          */
 282         bios_year += (bios_year >= 80 && bios_year <= 99) ?
 283             1900 : 2000;
 284 
 285         if (bios_year < yy)
 286                 return (FALSE);
 287         else if (bios_year > yy)
 288                 return (TRUE);
 289 
 290         if (bios_month < mm)
 291                 return (FALSE);
 292         else if (bios_month > mm)
 293                 return (TRUE);
 294 
 295         if (bios_day < dd)
 296                 return (FALSE);
 297 
 298         return (TRUE);
 299 }
 300 
 301 /*
 302  * Check for Metropolis systems with BIOSes older than 10/12/04
 303  * return TRUE if BIOS requires legacy mode, FALSE otherwise
 304  */
 305 static int
 306 acpica_metro_old_bios()
 307 {
 308         ACPI_TABLE_HEADER *fadt;
 309 
 310         /* get the FADT */
 311         if (AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **)&fadt) !=
 312             AE_OK)
 313                 return (FALSE);
 314 
 315         /* compare OEM Table ID to "SUNmetro" - no match, return false */
 316         if (strncmp("SUNmetro", fadt->OemTableId, 8))
 317                 return (FALSE);
 318 
 319         /* On a Metro - return FALSE if later than 10/12/04 */
 320         return (!acpica_check_bios_date(2004, 10, 12));
 321 }
 322 
 323 
 324 /*
 325  * Process acpi-user-options property  if present
 326  */
 327 static void
 328 acpica_process_user_options()
 329 {
 330         static int processed = 0;
 331         int acpi_user_options;
 332         char *acpi_prop;
 333 
 334         /*
 335          * return if acpi-user-options has already been processed
 336          */
 337         if (processed)
 338                 return;
 339         else
 340                 processed = 1;
 341 
 342         /* converts acpi-user-options from type string to int, if any */
 343         if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
 344             DDI_PROP_DONTPASS, "acpi-user-options", &acpi_prop) ==
 345             DDI_PROP_SUCCESS) {
 346                 long data;
 347                 int ret;
 348                 ret = ddi_strtol(acpi_prop, NULL, 0, &data);
 349                 if (ret == 0) {
 350                         e_ddi_prop_remove(DDI_DEV_T_NONE, ddi_root_node(),
 351                             "acpi-user-options");
 352                         e_ddi_prop_update_int(DDI_DEV_T_NONE, ddi_root_node(),
 353                             "acpi-user-options", data);
 354                 }
 355                 ddi_prop_free(acpi_prop);
 356         }
 357 
 358         /*
 359          * fetch the optional options property
 360          */
 361         acpi_user_options = ddi_prop_get_int(DDI_DEV_T_ANY, ddi_root_node(),
 362             DDI_PROP_DONTPASS, "acpi-user-options", 0);
 363 
 364         /*
 365          * Note that 'off' has precedence over 'on'
 366          * Also note - all cases of ACPI_OUSER_MASK
 367          * provided here, no default: case is present
 368          */
 369         switch (acpi_user_options & ACPI_OUSER_MASK) {
 370         case ACPI_OUSER_DFLT:
 371                 acpica_enable = acpica_check_bios_date(1999, 1, 1);
 372                 break;
 373         case ACPI_OUSER_ON:
 374                 acpica_enable = TRUE;
 375                 break;
 376         case ACPI_OUSER_OFF:
 377         case ACPI_OUSER_OFF | ACPI_OUSER_ON:
 378                 acpica_enable = FALSE;
 379                 break;
 380         }
 381 
 382         acpi_init_level = ACPI_FULL_INITIALIZATION;
 383 
 384         /*
 385          * special test here; may be generalized in the
 386          * future - test for a machines that are known to
 387          * work only in legacy mode, and set OUSER_LEGACY if
 388          * we're on one
 389          */
 390         if (acpica_metro_old_bios())
 391                 acpi_user_options |= ACPI_OUSER_LEGACY;
 392 
 393         /*
 394          * If legacy mode is specified, set initialization
 395          * options to avoid entering ACPI mode and hooking SCI
 396          * - basically try to act like legacy acpi_intp
 397          */
 398         if ((acpi_user_options & ACPI_OUSER_LEGACY) != 0)
 399                 acpi_init_level |= (ACPI_NO_ACPI_ENABLE | ACPI_NO_HANDLER_INIT);
 400 
 401         /*
 402          * modify default ACPI CA debug output level for non-DEBUG builds
 403          * (to avoid BIOS debug chatter in /var/adm/messages)
 404          */
 405         if (acpica_muzzle_debug_output)

 406                 AcpiDbgLevel = 0;

 407 }
 408 
 409 /*
 410  * Initialize the CA subsystem if it hasn't been done already
 411  */
 412 int
 413 acpica_init()
 414 {
 415         extern void acpica_find_ioapics(void);
 416         ACPI_STATUS status;
 417 
 418         /*
 419          * Make sure user options are processed,
 420          * then fail to initialize if ACPI CA has been
 421          * disabled
 422          */
 423         acpica_process_user_options();
 424         if (!acpica_enable)
 425                 return (AE_ERROR);
 426 
 427         mutex_enter(&acpica_module_lock);
 428         if (acpica_init_state == ACPICA_INITIALIZED) {
 429                 mutex_exit(&acpica_module_lock);
 430                 return (AE_OK);
 431         }
 432 
 433         if (ACPI_FAILURE(status = AcpiLoadTables()))
 434                 goto error;
 435 
 436         if (ACPI_FAILURE(status = acpica_install_handlers()))
 437                 goto error;
 438 
 439         /*
 440          * Create ACPI-to-devinfo mapping now so _INI and _STA
 441          * methods can access PCI config space when needed
 442          */
 443         scan_d2a_map();
 444 
 445         if (ACPI_FAILURE(status = AcpiEnableSubsystem(acpi_init_level)))
 446                 goto error;
 447 
 448         /* do after AcpiEnableSubsystem() so GPEs are initialized */
 449         acpica_ec_init();       /* initialize EC if present */
 450 
 451         /* This runs all device _STA and _INI methods. */
 452         if (ACPI_FAILURE(status = AcpiInitializeObjects(0)))
 453                 goto error;
 454 
 455         acpica_init_state = ACPICA_INITIALIZED;
 456 
 457         /*
 458          * [ACPI, sec. 4.4.1.1]
 459          * As of ACPICA version 20101217 (December 2010), the _PRW methods
 460          * (Power Resources for Wake) are no longer automatically executed
 461          * as part of the ACPICA initialization.  The OS must do this.
 462          */
 463         (void) AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
 464             UINT32_MAX, acpica_init_PRW, NULL, NULL, NULL);
 465         (void) AcpiUpdateAllGpes();
 466 
 467         /*
 468          * If we are running on the Xen hypervisor as dom0 we need to
 469          * find the ioapics so we can prevent ACPI from trying to
 470          * access them.
 471          */
 472         if (get_hwenv() == HW_XEN_PV && is_controldom())
 473                 acpica_find_ioapics();
 474         acpica_init_kstats();
 475 error:
 476         if (acpica_init_state != ACPICA_INITIALIZED) {
 477                 cmn_err(CE_NOTE, "!failed to initialize ACPI services");
 478         }
 479 
 480         /*
 481          * Set acpi-status to 13 if acpica has been initialized successfully.
 482          * This indicates that acpica is up and running.  This variable name
 483          * and value were chosen in order to remain compatible with acpi_intp.
 484          */
 485         e_ddi_prop_update_int(DDI_DEV_T_NONE, ddi_root_node(), "acpi-status",
 486             (ACPI_SUCCESS(status)) ? (ACPI_BOOT_INIT | ACPI_BOOT_ENABLE |
 487             ACPI_BOOT_BOOTCONF) : 0);
 488 
 489         /* Mark acpica subsystem as fully initialized. */
 490         if (ACPI_SUCCESS(status) &&
 491             acpi_init_level == ACPI_FULL_INITIALIZATION) {
 492                 acpica_set_core_feature(ACPI_FEATURE_FULL_INIT);
 493         }
 494 
 495         mutex_exit(&acpica_module_lock);
 496         return (status);
 497 }
 498 
 499 /*
 500  * SCI handling
 501  */
 502 
 503 ACPI_STATUS
 504 acpica_get_sci(int *sci_irq, iflag_t *sci_flags)
 505 {
 506         ACPI_SUBTABLE_HEADER            *ap;
 507         ACPI_TABLE_MADT                 *mat;
 508         ACPI_MADT_INTERRUPT_OVERRIDE    *mio;
 509         ACPI_TABLE_FADT                 *fadt;
 510         int                     madt_seen, madt_size;
 511 
 512 
 513         /*
 514          * Make sure user options are processed,
 515          * then return error if ACPI CA has been
 516          * disabled or system is not running in ACPI
 517          * and won't need/understand SCI
 518          */
 519         acpica_process_user_options();
 520         if ((!acpica_enable) || (acpi_init_level & ACPI_NO_ACPI_ENABLE))
 521                 return (AE_ERROR);
 522 
 523         /*
 524          * according to Intel ACPI developers, SCI
 525          * conforms to PCI bus conventions; level/low
 526          * unless otherwise directed by overrides.
 527          */
 528         sci_flags->intr_el = INTR_EL_LEVEL;
 529         sci_flags->intr_po = INTR_PO_ACTIVE_LOW;
 530         sci_flags->bustype = BUS_PCI;        /*  we *do* conform to PCI */
 531 
 532         /* get the SCI from the FADT */
 533         if (AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **)&fadt) !=
 534             AE_OK)
 535                 return (AE_ERROR);
 536 
 537         *sci_irq = fadt->SciInterrupt;
 538 
 539         /* search for ISOs that modify it */
 540         /* if we don't find a MADT, that's OK; no ISOs then */
 541         if (AcpiGetTable(ACPI_SIG_MADT, 1, (ACPI_TABLE_HEADER **) &mat) !=
 542             AE_OK)
 543                 return (AE_OK);
 544 
 545         ap = (ACPI_SUBTABLE_HEADER *) (mat + 1);
 546         madt_size = mat->Header.Length;
 547         madt_seen = sizeof (*mat);
 548 
 549         while (madt_seen < madt_size) {
 550                 switch (ap->Type) {
 551                 case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE:
 552                         mio = (ACPI_MADT_INTERRUPT_OVERRIDE *) ap;
 553                         if (mio->SourceIrq == *sci_irq) {
 554                                 *sci_irq = mio->GlobalIrq;
 555                                 sci_flags->intr_el = (mio->IntiFlags &
 556                                     ACPI_MADT_TRIGGER_MASK) >> 2;
 557                                 sci_flags->intr_po = mio->IntiFlags &
 558                                     ACPI_MADT_POLARITY_MASK;
 559                         }
 560                         break;
 561                 }
 562 
 563                 /* advance to next entry */
 564                 madt_seen += ap->Length;
 565                 ap = (ACPI_SUBTABLE_HEADER *)(((char *)ap) + ap->Length);
 566         }
 567 
 568         /*
 569          * One more check; if ISO said "conform", revert to default
 570          */
 571         if (sci_flags->intr_el == INTR_EL_CONFORM)
 572                 sci_flags->intr_el = INTR_EL_LEVEL;
 573         if (sci_flags->intr_po == INTR_PO_CONFORM)
 574                 sci_flags->intr_po = INTR_PO_ACTIVE_LOW;
 575 
 576         return (AE_OK);
 577 }
 578 
 579 /*
 580  * Call-back function used for _PRW initialization.  For every
 581  * device node that has a _PRW method, evaluate, parse, and do
 582  * AcpiSetupGpeForWake().
 583  */
 584 static ACPI_STATUS
 585 acpica_init_PRW(
 586         ACPI_HANDLE     devhdl,
 587         UINT32          depth,
 588         void            *ctxp,
 589         void            **rvpp)
 590 {
 591         ACPI_STATUS     status;
 592         ACPI_BUFFER     prw_buf;
 593         struct parsed_prw prw;
 594 
 595         prw_buf.Pointer = NULL;
 596         prw_buf.Length = ACPI_ALLOCATE_BUFFER;
 597 
 598         /*
 599          * Attempt to evaluate _PRW object.
 600          * If no valid object is found, return quietly, since not all
 601          * devices have _PRW objects.
 602          */
 603         status = AcpiEvaluateObject(devhdl, "_PRW", NULL, &prw_buf);
 604         if (ACPI_FAILURE(status))
 605                 goto done;
 606         status = acpica_parse_PRW(&prw_buf, &prw);
 607         if (ACPI_FAILURE(status))
 608                 goto done;
 609 
 610         (void) AcpiSetupGpeForWake(devhdl,
 611             prw.prw_gpeobj, prw.prw_gpebit);
 612 
 613 done:
 614         if (prw_buf.Pointer != NULL)
 615                 AcpiOsFree(prw_buf.Pointer);
 616 
 617         return (AE_OK);
 618 }
 619 
 620 /*
 621  * Sets ACPI wake state for device referenced by dip.
 622  * If level is S0 (0), disables wake event; otherwise,
 623  * enables wake event which will wake system from level.
 624  */
 625 static int
 626 acpica_ddi_setwake(dev_info_t *dip, int level)
 627 {
 628         ACPI_STATUS     status;
 629         ACPI_HANDLE     devobj;
 630         ACPI_BUFFER     prw_buf;
 631         ACPI_OBJECT_LIST        arglist;
 632         ACPI_OBJECT             args[3];
 633         struct parsed_prw prw;
 634         int             rv;
 635 
 636         /*
 637          * initialize these early so we can use a common
 638          * exit point below
 639          */
 640         prw_buf.Pointer = NULL;
 641         prw_buf.Length = ACPI_ALLOCATE_BUFFER;
 642         rv = 0;
 643 
 644         /*
 645          * Attempt to get a handle to a corresponding ACPI object.
 646          * If no object is found, return quietly, since not all
 647          * devices have corresponding ACPI objects.
 648          */
 649         status = acpica_get_handle(dip, &devobj);
 650         if (ACPI_FAILURE(status)) {
 651                 char pathbuf[MAXPATHLEN];
 652                 ddi_pathname(dip, pathbuf);
 653 #ifdef DEBUG
 654                 cmn_err(CE_NOTE, "!acpica_ddi_setwake: could not get"
 655                     " handle for %s, %s:%d", pathbuf, ddi_driver_name(dip),
 656                     ddi_get_instance(dip));
 657 #endif
 658                 goto done;
 659         }
 660 
 661         /*
 662          * ACPI3.0 7.2.1: only use the _PSW method if OSPM does not support
 663          * _DSW or if the _DSW method is not present.
 664          *
 665          * _DSW arguments:
 666          * args[0] - Enable/Disable
 667          * args[1] - Target system state
 668          * args[2] - Target device state
 669          */
 670 
 671         arglist.Count = 3;
 672         arglist.Pointer = args;
 673         args[0].Type = ACPI_TYPE_INTEGER;
 674         args[0].Integer.Value = level ? 1 : 0;
 675         args[1].Type = ACPI_TYPE_INTEGER;
 676         args[1].Integer.Value = level;
 677         args[2].Type = ACPI_TYPE_INTEGER;
 678         args[2].Integer.Value = level;
 679         if (ACPI_FAILURE(status = AcpiEvaluateObject(devobj, "_DSW",
 680             &arglist, NULL))) {
 681 
 682                 if (status == AE_NOT_FOUND) {
 683                         arglist.Count = 1;
 684                         args[0].Type = ACPI_TYPE_INTEGER;
 685                         args[0].Integer.Value = level ? 1 : 0;
 686 
 687                         if (ACPI_FAILURE(status = AcpiEvaluateObject(devobj,
 688                             "_PSW", &arglist, NULL))) {
 689 
 690                                 if (status != AE_NOT_FOUND) {
 691                                         cmn_err(CE_NOTE,
 692                                             "!_PSW failure %d for device %s",
 693                                             status, ddi_driver_name(dip));
 694                                 }
 695                         }
 696 
 697                 } else {
 698                         cmn_err(CE_NOTE, "!_DSW failure %d for device %s",
 699                             status, ddi_driver_name(dip));
 700                 }
 701         }
 702 
 703         /*
 704          * Attempt to evaluate _PRW object.
 705          * If no valid object is found, return quietly, since not all
 706          * devices have _PRW objects.
 707          */
 708         status = AcpiEvaluateObject(devobj, "_PRW", NULL, &prw_buf);
 709         if (ACPI_FAILURE(status))
 710                 goto done;
 711         status = acpica_parse_PRW(&prw_buf, &prw);
 712         if (ACPI_FAILURE(status))
 713                 goto done;
 714 
 715         rv = -1;
 716         if (level == 0) {
 717                 status = AcpiDisableGpe(prw.prw_gpeobj, prw.prw_gpebit);
 718                 if (ACPI_FAILURE(status))
 719                         goto done;
 720         } else if (prw.prw_level >= level) {
 721                 status = AcpiSetGpeWakeMask(prw.prw_gpeobj, prw.prw_gpebit,
 722                     ACPI_GPE_ENABLE);
 723                 if (ACPI_SUCCESS(status)) {
 724                         status = AcpiEnableGpe(prw.prw_gpeobj, prw.prw_gpebit);
 725                         if (ACPI_FAILURE(status))
 726                                 goto done;
 727                 }
 728         }
 729         rv = 0;
 730 done:
 731         if (prw_buf.Pointer != NULL)
 732                 AcpiOsFree(prw_buf.Pointer);
 733         return (rv);
 734 }
 735 
 736 static ACPI_STATUS
 737 acpica_parse_PRW(
 738         ACPI_BUFFER     *prw_buf,
 739         struct parsed_prw *p_prw)
 740 {
 741         ACPI_HANDLE     gpeobj;
 742         ACPI_OBJECT     *prw, *gpe;
 743         int             gpebit, prw_level;
 744 
 745         if (prw_buf->Length == 0 || prw_buf->Pointer == NULL)
 746                 return (AE_NULL_OBJECT);
 747 
 748         prw = prw_buf->Pointer;
 749         if (prw->Type != ACPI_TYPE_PACKAGE || prw->Package.Count < 2 ||
 750             prw->Package.Elements[1].Type != ACPI_TYPE_INTEGER)
 751                 return (AE_TYPE);
 752 
 753         /* fetch the lowest wake level from the _PRW */
 754         prw_level = prw->Package.Elements[1].Integer.Value;
 755 
 756         /*
 757          * process the GPE description
 758          */
 759         switch (prw->Package.Elements[0].Type) {
 760         case ACPI_TYPE_INTEGER:
 761                 gpeobj = NULL;
 762                 gpebit = prw->Package.Elements[0].Integer.Value;
 763                 break;
 764         case ACPI_TYPE_PACKAGE:
 765                 gpe = &prw->Package.Elements[0];
 766                 if (gpe->Package.Count != 2 ||
 767                     gpe->Package.Elements[1].Type != ACPI_TYPE_INTEGER)
 768                         return (AE_TYPE);
 769                 gpeobj = gpe->Package.Elements[0].Reference.Handle;
 770                 gpebit = gpe->Package.Elements[1].Integer.Value;
 771                 if (gpeobj == NULL)
 772                         return (AE_NULL_OBJECT);
 773                 break;
 774         default:
 775                 return (AE_TYPE);
 776         }
 777 
 778         p_prw->prw_gpeobj = gpeobj;
 779         p_prw->prw_gpebit = gpebit;
 780         p_prw->prw_level  = prw_level;
 781 
 782         return (AE_OK);
 783 }
 784 
 785 /*
 786  * kstat access to a limited set of ACPI propertis
 787  */
 788 static void
 789 acpica_init_kstats()
 790 {
 791         ACPI_HANDLE     s3handle;
 792         ACPI_STATUS     status;
 793         ACPI_TABLE_FADT *fadt;
 794         kstat_named_t *knp;
 795 
 796         /*
 797          * Create a small set of named kstats; just return in the rare
 798          * case of a failure, * in which case, the kstats won't be present.
 799          */
 800         if ((acpica_ksp = kstat_create("acpi", 0, "acpi", "misc",
 801             KSTAT_TYPE_NAMED, 2, 0)) == NULL)
 802                 return;
 803 
 804         /*
 805          * initialize kstat 'S3' to reflect the presence of \_S3 in
 806          * the ACPI namespace (1 = present, 0 = not present)
 807          */
 808         knp = acpica_ksp->ks_data;
 809         knp->value.l = (AcpiGetHandle(NULL, "\\_S3", &s3handle) == AE_OK);
 810         kstat_named_init(knp, "S3", KSTAT_DATA_LONG);
 811         knp++;          /* advance to next named kstat */
 812 
 813         /*
 814          * initialize kstat 'preferred_pm_profile' to the value
 815          * contained in the (always present) FADT
 816          */
 817         status = AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **)&fadt);
 818         knp->value.l = (status == AE_OK) ? fadt->PreferredProfile : -1;
 819         kstat_named_init(knp, "preferred_pm_profile", KSTAT_DATA_LONG);
 820 
 821         /*
 822          * install the named kstats
 823          */
 824         kstat_install(acpica_ksp);
 825 }
 826 
 827 /*
 828  * Attempt to save the current ACPI settings (_CRS) for the device
 829  * which corresponds to the supplied devinfo node.  The settings are
 830  * saved as a property on the dip.  If no ACPI object is found to be
 831  * associated with the devinfo node, no action is taken and no error
 832  * is reported.
 833  */
 834 void
 835 acpica_ddi_save_resources(dev_info_t *dip)
 836 {
 837         ACPI_HANDLE     devobj;
 838         ACPI_BUFFER     resbuf;
 839         int             ret;
 840 
 841         resbuf.Length = ACPI_ALLOCATE_BUFFER;
 842         if (ACPI_FAILURE(acpica_get_handle(dip, &devobj)) ||
 843             ACPI_FAILURE(AcpiGetCurrentResources(devobj, &resbuf)))
 844                 return;
 845 
 846         ret = ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
 847             "acpi-crs", resbuf.Pointer, resbuf.Length);
 848 
 849         ASSERT(ret == DDI_PROP_SUCCESS);
 850 
 851         AcpiOsFree(resbuf.Pointer);
 852 }
 853 
 854 /*
 855  * If the supplied devinfo node has an ACPI settings property attached,
 856  * restore them to the associated ACPI device using _SRS.  The property
 857  * is deleted from the devinfo node afterward.
 858  */
 859 void
 860 acpica_ddi_restore_resources(dev_info_t *dip)
 861 {
 862         ACPI_HANDLE     devobj;
 863         ACPI_BUFFER     resbuf;
 864         uchar_t         *propdata;
 865         uint_t          proplen;
 866 
 867         if (ACPI_FAILURE(acpica_get_handle(dip, &devobj)))
 868                 return;
 869 
 870         if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
 871             "acpi-crs", &propdata, &proplen) != DDI_PROP_SUCCESS)
 872                 return;
 873 
 874         resbuf.Pointer = propdata;
 875         resbuf.Length = proplen;
 876         (void) AcpiSetCurrentResources(devobj, &resbuf);
 877         ddi_prop_free(propdata);
 878         (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "acpi-crs");
 879 }
 880 
 881 void
 882 acpi_reset_system(void)
 883 {
 884         ACPI_STATUS status;
 885         int ten;
 886 
 887         status = AcpiReset();
 888         if (status == AE_OK) {
 889                 /*
 890                  * Wait up to 500 milliseconds for AcpiReset() to make its
 891                  * way.
 892                  */
 893                 ten = 50000;
 894                 while (ten-- > 0)
 895                         tenmicrosec();
 896         }
 897 }
--- EOF ---