1ae115bc7Smrj /* 2ae115bc7Smrj * CDDL HEADER START 3ae115bc7Smrj * 4ae115bc7Smrj * The contents of this file are subject to the terms of the 5ae115bc7Smrj * Common Development and Distribution License (the "License"). 6ae115bc7Smrj * You may not use this file except in compliance with the License. 7ae115bc7Smrj * 8ae115bc7Smrj * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9ae115bc7Smrj * or http://www.opensolaris.org/os/licensing. 10ae115bc7Smrj * See the License for the specific language governing permissions 11ae115bc7Smrj * and limitations under the License. 12ae115bc7Smrj * 13ae115bc7Smrj * When distributing Covered Code, include this CDDL HEADER in each 14ae115bc7Smrj * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15ae115bc7Smrj * If applicable, add the following below this CDDL HEADER, with the 16ae115bc7Smrj * fields enclosed by brackets "[]" replaced with your own identifying 17ae115bc7Smrj * information: Portions Copyright [yyyy] [name of copyright owner] 18ae115bc7Smrj * 19ae115bc7Smrj * CDDL HEADER END 20ae115bc7Smrj */ 21ae115bc7Smrj /* 226f6c7d2bSVincent Wang * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 2326f3cdf0SGordon Ross * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 24*385cc6b4SJerry Jelinek * Copyright 2016, Joyent, Inc. 25ae115bc7Smrj */ 26ae115bc7Smrj /* 27fa96bd91SMichael Corcoran * Copyright (c) 2009, Intel Corporation. 28fa96bd91SMichael Corcoran * All rights reserved. 29fa96bd91SMichael Corcoran */ 30fa96bd91SMichael Corcoran /* 31ae115bc7Smrj * Solaris x86 ACPI CA services 32ae115bc7Smrj */ 33ae115bc7Smrj 34ae115bc7Smrj #include <sys/file.h> 35ae115bc7Smrj #include <sys/errno.h> 36ae115bc7Smrj #include <sys/conf.h> 37ae115bc7Smrj #include <sys/modctl.h> 38ae115bc7Smrj #include <sys/open.h> 39ae115bc7Smrj #include <sys/stat.h> 40a3114836SGerry Liu #include <sys/spl.h> 41ae115bc7Smrj #include <sys/ddi.h> 42ae115bc7Smrj #include <sys/sunddi.h> 43ae115bc7Smrj #include <sys/esunddi.h> 442df1fe9cSrandyf #include <sys/kstat.h> 45b9bfdccdSStuart Maybee #include <sys/x86_archext.h> 46ae115bc7Smrj 47ae115bc7Smrj #include <sys/acpi/acpi.h> 48ae115bc7Smrj #include <sys/acpica.h> 494cf02d40SSaurabh Misra #include <sys/archsystm.h> 50ae115bc7Smrj 51ae115bc7Smrj /* 52ae115bc7Smrj * 53ae115bc7Smrj */ 54ae115bc7Smrj static struct modlmisc modlmisc = { 55ae115bc7Smrj &mod_miscops, 5687bb58d6Smyers "ACPI interpreter", 57ae115bc7Smrj }; 58ae115bc7Smrj 59ae115bc7Smrj static struct modlinkage modlinkage = { 60ae115bc7Smrj MODREV_1, /* MODREV_1 manual */ 61ae115bc7Smrj (void *)&modlmisc, /* module linkage */ 62ae115bc7Smrj NULL, /* list terminator */ 63ae115bc7Smrj }; 64ae115bc7Smrj 65ae115bc7Smrj /* 662df1fe9cSrandyf * Local prototypes 672df1fe9cSrandyf */ 682df1fe9cSrandyf 6926f3cdf0SGordon Ross struct parsed_prw { 7026f3cdf0SGordon Ross ACPI_HANDLE prw_gpeobj; 7126f3cdf0SGordon Ross int prw_gpebit; 7226f3cdf0SGordon Ross int prw_level; 7326f3cdf0SGordon Ross }; 7426f3cdf0SGordon Ross 752df1fe9cSrandyf static void acpica_init_kstats(void); 7626f3cdf0SGordon Ross static ACPI_STATUS acpica_init_PRW( 7726f3cdf0SGordon Ross ACPI_HANDLE hdl, 7826f3cdf0SGordon Ross UINT32 lvl, 7926f3cdf0SGordon Ross void *ctxp, 8026f3cdf0SGordon Ross void **rvpp); 8126f3cdf0SGordon Ross 8226f3cdf0SGordon Ross static ACPI_STATUS acpica_parse_PRW( 8326f3cdf0SGordon Ross ACPI_BUFFER *prw_buf, 8426f3cdf0SGordon Ross struct parsed_prw *prw); 852df1fe9cSrandyf 862df1fe9cSrandyf /* 87ae115bc7Smrj * Local data 88ae115bc7Smrj */ 89ae115bc7Smrj 90ae115bc7Smrj static kmutex_t acpica_module_lock; 912df1fe9cSrandyf static kstat_t *acpica_ksp; 92ae115bc7Smrj 93ae115bc7Smrj /* 94ae115bc7Smrj * State of acpica subsystem 95ae115bc7Smrj * After successful initialization, will be ACPICA_INITIALIZED 96ae115bc7Smrj */ 97ae115bc7Smrj int acpica_init_state = ACPICA_NOT_INITIALIZED; 98ae115bc7Smrj 99*385cc6b4SJerry Jelinek void *AcpiGbl_DbBuffer; 100*385cc6b4SJerry Jelinek uint32_t AcpiGbl_DbConsoleDebugLevel; 101*385cc6b4SJerry Jelinek 102ae115bc7Smrj /* 103ae115bc7Smrj * Following are set by acpica_process_user_options() 104ae115bc7Smrj * 105ae115bc7Smrj * acpica_enable = FALSE prevents initialization of ACPI CA 106ae115bc7Smrj * completely 107ae115bc7Smrj * 108ae115bc7Smrj * acpi_init_level determines level of ACPI CA functionality 109ae115bc7Smrj * enabled in acpica_init() 110ae115bc7Smrj */ 111ae115bc7Smrj int acpica_enable; 112ae115bc7Smrj UINT32 acpi_init_level; 113ae115bc7Smrj 114ae115bc7Smrj /* 115ae115bc7Smrj * Non-zero enables lax behavior with respect to some 116ae115bc7Smrj * common ACPI BIOS issues; see ACPI CA documentation 117ae115bc7Smrj * Setting this to zero causes ACPI CA to enforce strict 118ae115bc7Smrj * compliance with ACPI specification 119ae115bc7Smrj */ 120ae115bc7Smrj int acpica_enable_interpreter_slack = 1; 121ae115bc7Smrj 122ae115bc7Smrj /* 123ae115bc7Smrj * For non-DEBUG builds, set the ACPI CA debug level to 0 124ae115bc7Smrj * to quiet chatty BIOS output into /var/adm/messages 125ae115bc7Smrj * Field-patchable for diagnostic use. 126ae115bc7Smrj */ 127ae115bc7Smrj #ifdef DEBUG 128ae115bc7Smrj int acpica_muzzle_debug_output = 0; 129ae115bc7Smrj #else 130ae115bc7Smrj int acpica_muzzle_debug_output = 1; 131ae115bc7Smrj #endif 132ae115bc7Smrj 1332df1fe9cSrandyf /* 1342df1fe9cSrandyf * ACPI DDI hooks 1352df1fe9cSrandyf */ 1362df1fe9cSrandyf static int acpica_ddi_setwake(dev_info_t *dip, int level); 137ae115bc7Smrj 138ae115bc7Smrj int 139ae115bc7Smrj _init(void) 140ae115bc7Smrj { 141ae115bc7Smrj int error = EBUSY; 142ae115bc7Smrj int status; 1432df1fe9cSrandyf extern int (*acpi_fp_setwake)(); 144a3114836SGerry Liu extern kmutex_t cpu_map_lock; 145ae115bc7Smrj 146ae115bc7Smrj mutex_init(&acpica_module_lock, NULL, MUTEX_DRIVER, NULL); 147a3114836SGerry Liu mutex_init(&cpu_map_lock, NULL, MUTEX_SPIN, 148a3114836SGerry Liu (ddi_iblock_cookie_t)ipltospl(DISP_LEVEL)); 149ae115bc7Smrj 150ae115bc7Smrj if ((error = mod_install(&modlinkage)) != 0) { 151ae115bc7Smrj mutex_destroy(&acpica_module_lock); 1522df1fe9cSrandyf goto load_error; 153ae115bc7Smrj } 154ae115bc7Smrj 155ae115bc7Smrj AcpiGbl_EnableInterpreterSlack = (acpica_enable_interpreter_slack != 0); 156ae115bc7Smrj 157c1381f44SDana Myers /* global ACPI CA initialization */ 158c1381f44SDana Myers if (ACPI_FAILURE(status = AcpiInitializeSubsystem())) 159c1381f44SDana Myers cmn_err(CE_WARN, "!AcpiInitializeSubsystem failed: %d", status); 160c1381f44SDana Myers 161c1381f44SDana Myers /* initialize table manager */ 162c1381f44SDana Myers if (ACPI_FAILURE(status = AcpiInitializeTables(NULL, 0, 0))) 163c1381f44SDana Myers cmn_err(CE_WARN, "!AcpiInitializeTables failed: %d", status); 164ae115bc7Smrj 1652df1fe9cSrandyf acpi_fp_setwake = acpica_ddi_setwake; 1662df1fe9cSrandyf 1672df1fe9cSrandyf load_error: 168ae115bc7Smrj return (error); 169ae115bc7Smrj } 170ae115bc7Smrj 171ae115bc7Smrj int 172ae115bc7Smrj _info(struct modinfo *modinfop) 173ae115bc7Smrj { 174ae115bc7Smrj return (mod_info(&modlinkage, modinfop)); 175ae115bc7Smrj } 176ae115bc7Smrj 177ae115bc7Smrj int 178ae115bc7Smrj _fini(void) 179ae115bc7Smrj { 180ae115bc7Smrj /* 181ae115bc7Smrj * acpica module is never unloaded at run-time; there's always 182ae115bc7Smrj * a PSM depending on it, at the very least 183ae115bc7Smrj */ 184ae115bc7Smrj return (EBUSY); 185ae115bc7Smrj } 186ae115bc7Smrj 187ae115bc7Smrj /* 18826f3cdf0SGordon Ross * Install acpica-provided (default) address-space handlers 18926f3cdf0SGordon Ross * that may be needed before AcpiEnableSubsystem() runs. 19026f3cdf0SGordon Ross * See the comment in AcpiInstallAddressSpaceHandler(). 19126f3cdf0SGordon Ross * Default handlers for remaining address spaces are 19226f3cdf0SGordon Ross * installed later, in AcpiEnableSubsystem. 193ae115bc7Smrj */ 194ae115bc7Smrj static int 195ae115bc7Smrj acpica_install_handlers() 196ae115bc7Smrj { 197ae115bc7Smrj ACPI_STATUS rv = AE_OK; 198*385cc6b4SJerry Jelinek ACPI_STATUS res; 199ae115bc7Smrj 200ae115bc7Smrj /* 201ae115bc7Smrj * Install ACPI CA default handlers 202ae115bc7Smrj */ 203*385cc6b4SJerry Jelinek if ((res = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 204ae115bc7Smrj ACPI_ADR_SPACE_SYSTEM_MEMORY, 205*385cc6b4SJerry Jelinek ACPI_DEFAULT_HANDLER, NULL, NULL)) != AE_OK && 206*385cc6b4SJerry Jelinek res != AE_SAME_HANDLER) { 207ae115bc7Smrj cmn_err(CE_WARN, "!acpica: no default handler for" 208ae115bc7Smrj " system memory"); 209ae115bc7Smrj rv = AE_ERROR; 210ae115bc7Smrj } 211ae115bc7Smrj 212*385cc6b4SJerry Jelinek if ((res = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 213ae115bc7Smrj ACPI_ADR_SPACE_SYSTEM_IO, 214*385cc6b4SJerry Jelinek ACPI_DEFAULT_HANDLER, NULL, NULL)) != AE_OK && 215*385cc6b4SJerry Jelinek res != AE_SAME_HANDLER) { 216ae115bc7Smrj cmn_err(CE_WARN, "!acpica: no default handler for" 217ae115bc7Smrj " system I/O"); 218ae115bc7Smrj rv = AE_ERROR; 219ae115bc7Smrj } 220ae115bc7Smrj 221*385cc6b4SJerry Jelinek if ((res = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 222ae115bc7Smrj ACPI_ADR_SPACE_PCI_CONFIG, 223*385cc6b4SJerry Jelinek ACPI_DEFAULT_HANDLER, NULL, NULL)) != AE_OK && 224*385cc6b4SJerry Jelinek res != AE_SAME_HANDLER) { 225ae115bc7Smrj cmn_err(CE_WARN, "!acpica: no default handler for" 226ae115bc7Smrj " PCI Config"); 227ae115bc7Smrj rv = AE_ERROR; 228ae115bc7Smrj } 229ae115bc7Smrj 230*385cc6b4SJerry Jelinek if ((res = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 23126f3cdf0SGordon Ross ACPI_ADR_SPACE_DATA_TABLE, 232*385cc6b4SJerry Jelinek ACPI_DEFAULT_HANDLER, NULL, NULL)) != AE_OK && 233*385cc6b4SJerry Jelinek res != AE_SAME_HANDLER) { 23426f3cdf0SGordon Ross cmn_err(CE_WARN, "!acpica: no default handler for" 23526f3cdf0SGordon Ross " Data Table"); 23626f3cdf0SGordon Ross rv = AE_ERROR; 23726f3cdf0SGordon Ross } 238ae115bc7Smrj 239ae115bc7Smrj return (rv); 240ae115bc7Smrj } 241ae115bc7Smrj 242ae115bc7Smrj /* 243ae115bc7Smrj * Find the BIOS date, and return TRUE if supplied 244ae115bc7Smrj * date is same or later than the BIOS date, or FALSE 245ae115bc7Smrj * if the BIOS date can't be fetched for any reason 246ae115bc7Smrj */ 247ae115bc7Smrj static int 248ae115bc7Smrj acpica_check_bios_date(int yy, int mm, int dd) 249ae115bc7Smrj { 250ae115bc7Smrj 251ae115bc7Smrj char *datep; 252ae115bc7Smrj int bios_year, bios_month, bios_day; 253ae115bc7Smrj 254ae115bc7Smrj /* If firmware has no bios, skip the check */ 255fa96bd91SMichael Corcoran if (ddi_prop_exists(DDI_DEV_T_ANY, ddi_root_node(), DDI_PROP_DONTPASS, 256fa96bd91SMichael Corcoran "bios-free")) 257ae115bc7Smrj return (TRUE); 258ae115bc7Smrj 259ae115bc7Smrj /* 260ae115bc7Smrj * PC BIOSes contain a string in the form of 261ae115bc7Smrj * "mm/dd/yy" at absolute address 0xffff5, 262ae115bc7Smrj * where mm, dd and yy are all ASCII digits. 263ae115bc7Smrj * We map the string, pluck out the values, 264ae115bc7Smrj * and accept all BIOSes from 1 Jan 1999 on 265ae115bc7Smrj * as valid. 266ae115bc7Smrj */ 267ae115bc7Smrj 268db2bae30SDana Myers if ((datep = (char *)AcpiOsMapMemory(0xffff5, 8)) == NULL) 269ae115bc7Smrj return (FALSE); 270ae115bc7Smrj 271ae115bc7Smrj /* year */ 272ae115bc7Smrj bios_year = ((int)(*(datep + 6) - '0') * 10) + (*(datep + 7) - '0'); 273ae115bc7Smrj /* month */ 274ae115bc7Smrj bios_month = ((int)(*datep - '0') * 10) + (*(datep + 1) - '0'); 275ae115bc7Smrj /* day */ 276ae115bc7Smrj bios_day = ((int)(*(datep + 3) - '0') * 10) + (*(datep + 4) - '0'); 277ae115bc7Smrj 278ae115bc7Smrj AcpiOsUnmapMemory((void *) datep, 8); 279ae115bc7Smrj 280ae115bc7Smrj if (bios_year < 0 || bios_year > 99 || bios_month < 0 || 281ae115bc7Smrj bios_month > 99 || bios_day < 0 || bios_day > 99) { 282ae115bc7Smrj /* non-digit chars in BIOS date */ 283ae115bc7Smrj return (FALSE); 284ae115bc7Smrj } 285ae115bc7Smrj 286ae115bc7Smrj /* 287ae115bc7Smrj * Adjust for 2-digit year; note to grand-children: 288ae115bc7Smrj * need a new scheme before 2080 rolls around 289ae115bc7Smrj */ 290ae115bc7Smrj bios_year += (bios_year >= 80 && bios_year <= 99) ? 291ae115bc7Smrj 1900 : 2000; 292ae115bc7Smrj 293ae115bc7Smrj if (bios_year < yy) 294ae115bc7Smrj return (FALSE); 295ae115bc7Smrj else if (bios_year > yy) 296ae115bc7Smrj return (TRUE); 297ae115bc7Smrj 298ae115bc7Smrj if (bios_month < mm) 299ae115bc7Smrj return (FALSE); 300ae115bc7Smrj else if (bios_month > mm) 301ae115bc7Smrj return (TRUE); 302ae115bc7Smrj 303ae115bc7Smrj if (bios_day < dd) 304ae115bc7Smrj return (FALSE); 305ae115bc7Smrj 306ae115bc7Smrj return (TRUE); 307ae115bc7Smrj } 308ae115bc7Smrj 309ae115bc7Smrj /* 310ae115bc7Smrj * Check for Metropolis systems with BIOSes older than 10/12/04 311ae115bc7Smrj * return TRUE if BIOS requires legacy mode, FALSE otherwise 312ae115bc7Smrj */ 313ae115bc7Smrj static int 314ae115bc7Smrj acpica_metro_old_bios() 315ae115bc7Smrj { 316ae115bc7Smrj ACPI_TABLE_HEADER *fadt; 317ae115bc7Smrj 318ae115bc7Smrj /* get the FADT */ 319db2bae30SDana Myers if (AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **)&fadt) != 320db2bae30SDana Myers AE_OK) 321ae115bc7Smrj return (FALSE); 322ae115bc7Smrj 323ae115bc7Smrj /* compare OEM Table ID to "SUNmetro" - no match, return false */ 324ae115bc7Smrj if (strncmp("SUNmetro", fadt->OemTableId, 8)) 325ae115bc7Smrj return (FALSE); 326ae115bc7Smrj 327ae115bc7Smrj /* On a Metro - return FALSE if later than 10/12/04 */ 328ae115bc7Smrj return (!acpica_check_bios_date(2004, 10, 12)); 329ae115bc7Smrj } 330ae115bc7Smrj 331ae115bc7Smrj 332ae115bc7Smrj /* 333ae115bc7Smrj * Process acpi-user-options property if present 334ae115bc7Smrj */ 335ae115bc7Smrj static void 336ae115bc7Smrj acpica_process_user_options() 337ae115bc7Smrj { 338ae115bc7Smrj static int processed = 0; 339ae115bc7Smrj int acpi_user_options; 340ae115bc7Smrj char *acpi_prop; 341ae115bc7Smrj 342ae115bc7Smrj /* 343ae115bc7Smrj * return if acpi-user-options has already been processed 344ae115bc7Smrj */ 345ae115bc7Smrj if (processed) 346ae115bc7Smrj return; 347ae115bc7Smrj else 348ae115bc7Smrj processed = 1; 349ae115bc7Smrj 350ae115bc7Smrj /* converts acpi-user-options from type string to int, if any */ 351ae115bc7Smrj if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 352ae115bc7Smrj DDI_PROP_DONTPASS, "acpi-user-options", &acpi_prop) == 353ae115bc7Smrj DDI_PROP_SUCCESS) { 354ae115bc7Smrj long data; 355ae115bc7Smrj int ret; 356ae115bc7Smrj ret = ddi_strtol(acpi_prop, NULL, 0, &data); 357ae115bc7Smrj if (ret == 0) { 358ae115bc7Smrj e_ddi_prop_remove(DDI_DEV_T_NONE, ddi_root_node(), 359ae115bc7Smrj "acpi-user-options"); 360ae115bc7Smrj e_ddi_prop_update_int(DDI_DEV_T_NONE, ddi_root_node(), 361ae115bc7Smrj "acpi-user-options", data); 362ae115bc7Smrj } 363ae115bc7Smrj ddi_prop_free(acpi_prop); 364ae115bc7Smrj } 365ae115bc7Smrj 366ae115bc7Smrj /* 367ae115bc7Smrj * fetch the optional options property 368ae115bc7Smrj */ 369fa96bd91SMichael Corcoran acpi_user_options = ddi_prop_get_int(DDI_DEV_T_ANY, ddi_root_node(), 370fa96bd91SMichael Corcoran DDI_PROP_DONTPASS, "acpi-user-options", 0); 371ae115bc7Smrj 372ae115bc7Smrj /* 373ae115bc7Smrj * Note that 'off' has precedence over 'on' 374ae115bc7Smrj * Also note - all cases of ACPI_OUSER_MASK 375ae115bc7Smrj * provided here, no default: case is present 376ae115bc7Smrj */ 377ae115bc7Smrj switch (acpi_user_options & ACPI_OUSER_MASK) { 378ae115bc7Smrj case ACPI_OUSER_DFLT: 379ae115bc7Smrj acpica_enable = acpica_check_bios_date(1999, 1, 1); 380ae115bc7Smrj break; 381ae115bc7Smrj case ACPI_OUSER_ON: 382ae115bc7Smrj acpica_enable = TRUE; 383ae115bc7Smrj break; 384ae115bc7Smrj case ACPI_OUSER_OFF: 385ae115bc7Smrj case ACPI_OUSER_OFF | ACPI_OUSER_ON: 386ae115bc7Smrj acpica_enable = FALSE; 387ae115bc7Smrj break; 388ae115bc7Smrj } 389ae115bc7Smrj 390ae115bc7Smrj acpi_init_level = ACPI_FULL_INITIALIZATION; 391ae115bc7Smrj 392ae115bc7Smrj /* 393ae115bc7Smrj * special test here; may be generalized in the 394ae115bc7Smrj * future - test for a machines that are known to 395ae115bc7Smrj * work only in legacy mode, and set OUSER_LEGACY if 396ae115bc7Smrj * we're on one 397ae115bc7Smrj */ 398ae115bc7Smrj if (acpica_metro_old_bios()) 399ae115bc7Smrj acpi_user_options |= ACPI_OUSER_LEGACY; 400ae115bc7Smrj 401ae115bc7Smrj /* 402ae115bc7Smrj * If legacy mode is specified, set initialization 403ae115bc7Smrj * options to avoid entering ACPI mode and hooking SCI 404ae115bc7Smrj * - basically try to act like legacy acpi_intp 405ae115bc7Smrj */ 406ae115bc7Smrj if ((acpi_user_options & ACPI_OUSER_LEGACY) != 0) 407ae115bc7Smrj acpi_init_level |= (ACPI_NO_ACPI_ENABLE | ACPI_NO_HANDLER_INIT); 408ae115bc7Smrj 409ae115bc7Smrj /* 410ae115bc7Smrj * modify default ACPI CA debug output level for non-DEBUG builds 411ae115bc7Smrj * (to avoid BIOS debug chatter in /var/adm/messages) 412ae115bc7Smrj */ 413ae115bc7Smrj if (acpica_muzzle_debug_output) 414ae115bc7Smrj AcpiDbgLevel = 0; 415ae115bc7Smrj } 416ae115bc7Smrj 417ae115bc7Smrj /* 418ae115bc7Smrj * Initialize the CA subsystem if it hasn't been done already 419ae115bc7Smrj */ 420ae115bc7Smrj int 421ae115bc7Smrj acpica_init() 422ae115bc7Smrj { 423b9bfdccdSStuart Maybee extern void acpica_find_ioapics(void); 424ae115bc7Smrj ACPI_STATUS status; 425ae115bc7Smrj 426ae115bc7Smrj /* 427ae115bc7Smrj * Make sure user options are processed, 428ae115bc7Smrj * then fail to initialize if ACPI CA has been 429ae115bc7Smrj * disabled 430ae115bc7Smrj */ 431ae115bc7Smrj acpica_process_user_options(); 432ae115bc7Smrj if (!acpica_enable) 433ae115bc7Smrj return (AE_ERROR); 434ae115bc7Smrj 435ae115bc7Smrj mutex_enter(&acpica_module_lock); 436fa96bd91SMichael Corcoran if (acpica_init_state == ACPICA_INITIALIZED) { 437fa96bd91SMichael Corcoran mutex_exit(&acpica_module_lock); 438fa96bd91SMichael Corcoran return (AE_OK); 439fa96bd91SMichael Corcoran } 440ae115bc7Smrj 441db2bae30SDana Myers if (ACPI_FAILURE(status = AcpiLoadTables())) 442ae115bc7Smrj goto error; 443db2bae30SDana Myers 444db2bae30SDana Myers if (ACPI_FAILURE(status = acpica_install_handlers())) 445ae115bc7Smrj goto error; 446db2bae30SDana Myers 4475f68fde5SDana Myers /* 4485f68fde5SDana Myers * Create ACPI-to-devinfo mapping now so _INI and _STA 4495f68fde5SDana Myers * methods can access PCI config space when needed 4505f68fde5SDana Myers */ 4515f68fde5SDana Myers scan_d2a_map(); 4525f68fde5SDana Myers 453fa96bd91SMichael Corcoran if (ACPI_FAILURE(status = AcpiEnableSubsystem(acpi_init_level))) 454ae115bc7Smrj goto error; 455db2bae30SDana Myers 456c1381f44SDana Myers /* do after AcpiEnableSubsystem() so GPEs are initialized */ 457c1381f44SDana Myers acpica_ec_init(); /* initialize EC if present */ 458c1381f44SDana Myers 45926f3cdf0SGordon Ross /* This runs all device _STA and _INI methods. */ 460db2bae30SDana Myers if (ACPI_FAILURE(status = AcpiInitializeObjects(0))) 461db2bae30SDana Myers goto error; 462db2bae30SDana Myers 463ae115bc7Smrj acpica_init_state = ACPICA_INITIALIZED; 464fa96bd91SMichael Corcoran 465b9bfdccdSStuart Maybee /* 46626f3cdf0SGordon Ross * [ACPI, sec. 4.4.1.1] 46726f3cdf0SGordon Ross * As of ACPICA version 20101217 (December 2010), the _PRW methods 46826f3cdf0SGordon Ross * (Power Resources for Wake) are no longer automatically executed 46926f3cdf0SGordon Ross * as part of the ACPICA initialization. The OS must do this. 47026f3cdf0SGordon Ross */ 47126f3cdf0SGordon Ross (void) AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 47226f3cdf0SGordon Ross UINT32_MAX, acpica_init_PRW, NULL, NULL, NULL); 47326f3cdf0SGordon Ross (void) AcpiUpdateAllGpes(); 47426f3cdf0SGordon Ross 47526f3cdf0SGordon Ross /* 476b9bfdccdSStuart Maybee * If we are running on the Xen hypervisor as dom0 we need to 477b9bfdccdSStuart Maybee * find the ioapics so we can prevent ACPI from trying to 478b9bfdccdSStuart Maybee * access them. 479b9bfdccdSStuart Maybee */ 480b9bfdccdSStuart Maybee if (get_hwenv() == HW_XEN_PV && is_controldom()) 481b9bfdccdSStuart Maybee acpica_find_ioapics(); 4822df1fe9cSrandyf acpica_init_kstats(); 483ae115bc7Smrj error: 484ae115bc7Smrj if (acpica_init_state != ACPICA_INITIALIZED) { 485fa96bd91SMichael Corcoran cmn_err(CE_NOTE, "!failed to initialize ACPI services"); 486ae115bc7Smrj } 487ae115bc7Smrj 488ae115bc7Smrj /* 489ae115bc7Smrj * Set acpi-status to 13 if acpica has been initialized successfully. 490ae115bc7Smrj * This indicates that acpica is up and running. This variable name 491ae115bc7Smrj * and value were chosen in order to remain compatible with acpi_intp. 492ae115bc7Smrj */ 493ae115bc7Smrj e_ddi_prop_update_int(DDI_DEV_T_NONE, ddi_root_node(), "acpi-status", 494fa96bd91SMichael Corcoran (ACPI_SUCCESS(status)) ? (ACPI_BOOT_INIT | ACPI_BOOT_ENABLE | 495ae115bc7Smrj ACPI_BOOT_BOOTCONF) : 0); 496ae115bc7Smrj 497fa96bd91SMichael Corcoran /* Mark acpica subsystem as fully initialized. */ 498fa96bd91SMichael Corcoran if (ACPI_SUCCESS(status) && 499fa96bd91SMichael Corcoran acpi_init_level == ACPI_FULL_INITIALIZATION) { 500fa96bd91SMichael Corcoran acpica_set_core_feature(ACPI_FEATURE_FULL_INIT); 501fa96bd91SMichael Corcoran } 502fa96bd91SMichael Corcoran 503ae115bc7Smrj mutex_exit(&acpica_module_lock); 504ae115bc7Smrj return (status); 505ae115bc7Smrj } 506ae115bc7Smrj 507ae115bc7Smrj /* 508ae115bc7Smrj * SCI handling 509ae115bc7Smrj */ 510ae115bc7Smrj 511ae115bc7Smrj ACPI_STATUS 512ae115bc7Smrj acpica_get_sci(int *sci_irq, iflag_t *sci_flags) 513ae115bc7Smrj { 514db2bae30SDana Myers ACPI_SUBTABLE_HEADER *ap; 515db2bae30SDana Myers ACPI_TABLE_MADT *mat; 516db2bae30SDana Myers ACPI_MADT_INTERRUPT_OVERRIDE *mio; 517db2bae30SDana Myers ACPI_TABLE_FADT *fadt; 518ae115bc7Smrj int madt_seen, madt_size; 519ae115bc7Smrj 520ae115bc7Smrj 521ae115bc7Smrj /* 522ae115bc7Smrj * Make sure user options are processed, 523ae115bc7Smrj * then return error if ACPI CA has been 524ae115bc7Smrj * disabled or system is not running in ACPI 525ae115bc7Smrj * and won't need/understand SCI 526ae115bc7Smrj */ 527ae115bc7Smrj acpica_process_user_options(); 528ae115bc7Smrj if ((!acpica_enable) || (acpi_init_level & ACPI_NO_ACPI_ENABLE)) 529ae115bc7Smrj return (AE_ERROR); 530ae115bc7Smrj 531ae115bc7Smrj /* 532ae115bc7Smrj * according to Intel ACPI developers, SCI 533ae115bc7Smrj * conforms to PCI bus conventions; level/low 534ae115bc7Smrj * unless otherwise directed by overrides. 535ae115bc7Smrj */ 536ae115bc7Smrj sci_flags->intr_el = INTR_EL_LEVEL; 537ae115bc7Smrj sci_flags->intr_po = INTR_PO_ACTIVE_LOW; 538ae115bc7Smrj sci_flags->bustype = BUS_PCI; /* we *do* conform to PCI */ 539ae115bc7Smrj 540ae115bc7Smrj /* get the SCI from the FADT */ 541db2bae30SDana Myers if (AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **)&fadt) != 542db2bae30SDana Myers AE_OK) 543ae115bc7Smrj return (AE_ERROR); 544ae115bc7Smrj 545db2bae30SDana Myers *sci_irq = fadt->SciInterrupt; 546ae115bc7Smrj 547ae115bc7Smrj /* search for ISOs that modify it */ 548ae115bc7Smrj /* if we don't find a MADT, that's OK; no ISOs then */ 549db2bae30SDana Myers if (AcpiGetTable(ACPI_SIG_MADT, 1, (ACPI_TABLE_HEADER **) &mat) != 550db2bae30SDana Myers AE_OK) 551ae115bc7Smrj return (AE_OK); 552ae115bc7Smrj 553db2bae30SDana Myers ap = (ACPI_SUBTABLE_HEADER *) (mat + 1); 554db2bae30SDana Myers madt_size = mat->Header.Length; 555ae115bc7Smrj madt_seen = sizeof (*mat); 556ae115bc7Smrj 557ae115bc7Smrj while (madt_seen < madt_size) { 558ae115bc7Smrj switch (ap->Type) { 559db2bae30SDana Myers case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE: 560db2bae30SDana Myers mio = (ACPI_MADT_INTERRUPT_OVERRIDE *) ap; 561db2bae30SDana Myers if (mio->SourceIrq == *sci_irq) { 562db2bae30SDana Myers *sci_irq = mio->GlobalIrq; 563db2bae30SDana Myers sci_flags->intr_el = (mio->IntiFlags & 564db2bae30SDana Myers ACPI_MADT_TRIGGER_MASK) >> 2; 565db2bae30SDana Myers sci_flags->intr_po = mio->IntiFlags & 566db2bae30SDana Myers ACPI_MADT_POLARITY_MASK; 567ae115bc7Smrj } 568ae115bc7Smrj break; 569ae115bc7Smrj } 570ae115bc7Smrj 571ae115bc7Smrj /* advance to next entry */ 572ae115bc7Smrj madt_seen += ap->Length; 573db2bae30SDana Myers ap = (ACPI_SUBTABLE_HEADER *)(((char *)ap) + ap->Length); 574ae115bc7Smrj } 575ae115bc7Smrj 576ae115bc7Smrj /* 577ae115bc7Smrj * One more check; if ISO said "conform", revert to default 578ae115bc7Smrj */ 579ae115bc7Smrj if (sci_flags->intr_el == INTR_EL_CONFORM) 580ae115bc7Smrj sci_flags->intr_el = INTR_EL_LEVEL; 581ae115bc7Smrj if (sci_flags->intr_po == INTR_PO_CONFORM) 582ae115bc7Smrj sci_flags->intr_po = INTR_PO_ACTIVE_LOW; 583ae115bc7Smrj 584ae115bc7Smrj return (AE_OK); 585ae115bc7Smrj } 5862df1fe9cSrandyf 5872df1fe9cSrandyf /* 58826f3cdf0SGordon Ross * Call-back function used for _PRW initialization. For every 58926f3cdf0SGordon Ross * device node that has a _PRW method, evaluate, parse, and do 59026f3cdf0SGordon Ross * AcpiSetupGpeForWake(). 59126f3cdf0SGordon Ross */ 59226f3cdf0SGordon Ross static ACPI_STATUS 59326f3cdf0SGordon Ross acpica_init_PRW( 59426f3cdf0SGordon Ross ACPI_HANDLE devhdl, 59526f3cdf0SGordon Ross UINT32 depth, 59626f3cdf0SGordon Ross void *ctxp, 59726f3cdf0SGordon Ross void **rvpp) 59826f3cdf0SGordon Ross { 59926f3cdf0SGordon Ross ACPI_STATUS status; 60026f3cdf0SGordon Ross ACPI_BUFFER prw_buf; 60126f3cdf0SGordon Ross struct parsed_prw prw; 60226f3cdf0SGordon Ross 60326f3cdf0SGordon Ross prw_buf.Pointer = NULL; 60426f3cdf0SGordon Ross prw_buf.Length = ACPI_ALLOCATE_BUFFER; 60526f3cdf0SGordon Ross 60626f3cdf0SGordon Ross /* 60726f3cdf0SGordon Ross * Attempt to evaluate _PRW object. 60826f3cdf0SGordon Ross * If no valid object is found, return quietly, since not all 60926f3cdf0SGordon Ross * devices have _PRW objects. 61026f3cdf0SGordon Ross */ 61126f3cdf0SGordon Ross status = AcpiEvaluateObject(devhdl, "_PRW", NULL, &prw_buf); 61226f3cdf0SGordon Ross if (ACPI_FAILURE(status)) 61326f3cdf0SGordon Ross goto done; 61426f3cdf0SGordon Ross status = acpica_parse_PRW(&prw_buf, &prw); 61526f3cdf0SGordon Ross if (ACPI_FAILURE(status)) 61626f3cdf0SGordon Ross goto done; 61726f3cdf0SGordon Ross 61826f3cdf0SGordon Ross (void) AcpiSetupGpeForWake(devhdl, 61926f3cdf0SGordon Ross prw.prw_gpeobj, prw.prw_gpebit); 62026f3cdf0SGordon Ross 62126f3cdf0SGordon Ross done: 62226f3cdf0SGordon Ross if (prw_buf.Pointer != NULL) 62326f3cdf0SGordon Ross AcpiOsFree(prw_buf.Pointer); 62426f3cdf0SGordon Ross 62526f3cdf0SGordon Ross return (AE_OK); 62626f3cdf0SGordon Ross } 62726f3cdf0SGordon Ross 62826f3cdf0SGordon Ross /* 6292df1fe9cSrandyf * Sets ACPI wake state for device referenced by dip. 6302df1fe9cSrandyf * If level is S0 (0), disables wake event; otherwise, 6312df1fe9cSrandyf * enables wake event which will wake system from level. 6322df1fe9cSrandyf */ 6332df1fe9cSrandyf static int 6342df1fe9cSrandyf acpica_ddi_setwake(dev_info_t *dip, int level) 6352df1fe9cSrandyf { 6362df1fe9cSrandyf ACPI_STATUS status; 63726f3cdf0SGordon Ross ACPI_HANDLE devobj; 6382df1fe9cSrandyf ACPI_BUFFER prw_buf; 6396f6c7d2bSVincent Wang ACPI_OBJECT_LIST arglist; 6406f6c7d2bSVincent Wang ACPI_OBJECT args[3]; 64126f3cdf0SGordon Ross struct parsed_prw prw; 64226f3cdf0SGordon Ross int rv; 6432df1fe9cSrandyf 6442df1fe9cSrandyf /* 6452df1fe9cSrandyf * initialize these early so we can use a common 6462df1fe9cSrandyf * exit point below 6472df1fe9cSrandyf */ 6482df1fe9cSrandyf prw_buf.Pointer = NULL; 6492df1fe9cSrandyf prw_buf.Length = ACPI_ALLOCATE_BUFFER; 6502df1fe9cSrandyf rv = 0; 6512df1fe9cSrandyf 6522df1fe9cSrandyf /* 6532df1fe9cSrandyf * Attempt to get a handle to a corresponding ACPI object. 6542df1fe9cSrandyf * If no object is found, return quietly, since not all 6552df1fe9cSrandyf * devices have corresponding ACPI objects. 6562df1fe9cSrandyf */ 6572df1fe9cSrandyf status = acpica_get_handle(dip, &devobj); 6582df1fe9cSrandyf if (ACPI_FAILURE(status)) { 6592df1fe9cSrandyf char pathbuf[MAXPATHLEN]; 6602df1fe9cSrandyf ddi_pathname(dip, pathbuf); 6612df1fe9cSrandyf #ifdef DEBUG 6622df1fe9cSrandyf cmn_err(CE_NOTE, "!acpica_ddi_setwake: could not get" 6632df1fe9cSrandyf " handle for %s, %s:%d", pathbuf, ddi_driver_name(dip), 6642df1fe9cSrandyf ddi_get_instance(dip)); 6652df1fe9cSrandyf #endif 6662df1fe9cSrandyf goto done; 6672df1fe9cSrandyf } 6682df1fe9cSrandyf 6692df1fe9cSrandyf /* 6706f6c7d2bSVincent Wang * ACPI3.0 7.2.1: only use the _PSW method if OSPM does not support 6716f6c7d2bSVincent Wang * _DSW or if the _DSW method is not present. 6726f6c7d2bSVincent Wang * 6736f6c7d2bSVincent Wang * _DSW arguments: 6746f6c7d2bSVincent Wang * args[0] - Enable/Disable 6756f6c7d2bSVincent Wang * args[1] - Target system state 6766f6c7d2bSVincent Wang * args[2] - Target device state 6776f6c7d2bSVincent Wang */ 6786f6c7d2bSVincent Wang 6796f6c7d2bSVincent Wang arglist.Count = 3; 6806f6c7d2bSVincent Wang arglist.Pointer = args; 6816f6c7d2bSVincent Wang args[0].Type = ACPI_TYPE_INTEGER; 6826f6c7d2bSVincent Wang args[0].Integer.Value = level ? 1 : 0; 6836f6c7d2bSVincent Wang args[1].Type = ACPI_TYPE_INTEGER; 6846f6c7d2bSVincent Wang args[1].Integer.Value = level; 6856f6c7d2bSVincent Wang args[2].Type = ACPI_TYPE_INTEGER; 6866f6c7d2bSVincent Wang args[2].Integer.Value = level; 6876f6c7d2bSVincent Wang if (ACPI_FAILURE(status = AcpiEvaluateObject(devobj, "_DSW", 6886f6c7d2bSVincent Wang &arglist, NULL))) { 6896f6c7d2bSVincent Wang 6906f6c7d2bSVincent Wang if (status == AE_NOT_FOUND) { 6916f6c7d2bSVincent Wang arglist.Count = 1; 6926f6c7d2bSVincent Wang args[0].Type = ACPI_TYPE_INTEGER; 6936f6c7d2bSVincent Wang args[0].Integer.Value = level ? 1 : 0; 6946f6c7d2bSVincent Wang 6956f6c7d2bSVincent Wang if (ACPI_FAILURE(status = AcpiEvaluateObject(devobj, 6966f6c7d2bSVincent Wang "_PSW", &arglist, NULL))) { 6976f6c7d2bSVincent Wang 6986f6c7d2bSVincent Wang if (status != AE_NOT_FOUND) { 6996f6c7d2bSVincent Wang cmn_err(CE_NOTE, 7006f6c7d2bSVincent Wang "!_PSW failure %d for device %s", 7016f6c7d2bSVincent Wang status, ddi_driver_name(dip)); 7026f6c7d2bSVincent Wang } 7036f6c7d2bSVincent Wang } 7046f6c7d2bSVincent Wang 7056f6c7d2bSVincent Wang } else { 7066f6c7d2bSVincent Wang cmn_err(CE_NOTE, "!_DSW failure %d for device %s", 7076f6c7d2bSVincent Wang status, ddi_driver_name(dip)); 7086f6c7d2bSVincent Wang } 7096f6c7d2bSVincent Wang } 7106f6c7d2bSVincent Wang 7116f6c7d2bSVincent Wang /* 7122df1fe9cSrandyf * Attempt to evaluate _PRW object. 7132df1fe9cSrandyf * If no valid object is found, return quietly, since not all 7142df1fe9cSrandyf * devices have _PRW objects. 7152df1fe9cSrandyf */ 7162df1fe9cSrandyf status = AcpiEvaluateObject(devobj, "_PRW", NULL, &prw_buf); 71726f3cdf0SGordon Ross if (ACPI_FAILURE(status)) 71826f3cdf0SGordon Ross goto done; 71926f3cdf0SGordon Ross status = acpica_parse_PRW(&prw_buf, &prw); 72026f3cdf0SGordon Ross if (ACPI_FAILURE(status)) 72126f3cdf0SGordon Ross goto done; 72226f3cdf0SGordon Ross 72326f3cdf0SGordon Ross rv = -1; 72426f3cdf0SGordon Ross if (level == 0) { 72526f3cdf0SGordon Ross status = AcpiDisableGpe(prw.prw_gpeobj, prw.prw_gpebit); 72626f3cdf0SGordon Ross if (ACPI_FAILURE(status)) 72726f3cdf0SGordon Ross goto done; 72826f3cdf0SGordon Ross } else if (prw.prw_level >= level) { 72926f3cdf0SGordon Ross status = AcpiSetGpeWakeMask(prw.prw_gpeobj, prw.prw_gpebit, 73026f3cdf0SGordon Ross ACPI_GPE_ENABLE); 73126f3cdf0SGordon Ross if (ACPI_SUCCESS(status)) { 73226f3cdf0SGordon Ross status = AcpiEnableGpe(prw.prw_gpeobj, prw.prw_gpebit); 73326f3cdf0SGordon Ross if (ACPI_FAILURE(status)) 7342df1fe9cSrandyf goto done; 7352df1fe9cSrandyf } 73626f3cdf0SGordon Ross } 73726f3cdf0SGordon Ross rv = 0; 73826f3cdf0SGordon Ross done: 73926f3cdf0SGordon Ross if (prw_buf.Pointer != NULL) 74026f3cdf0SGordon Ross AcpiOsFree(prw_buf.Pointer); 74126f3cdf0SGordon Ross return (rv); 74226f3cdf0SGordon Ross } 74326f3cdf0SGordon Ross 74426f3cdf0SGordon Ross static ACPI_STATUS 74526f3cdf0SGordon Ross acpica_parse_PRW( 74626f3cdf0SGordon Ross ACPI_BUFFER *prw_buf, 74726f3cdf0SGordon Ross struct parsed_prw *p_prw) 74826f3cdf0SGordon Ross { 74926f3cdf0SGordon Ross ACPI_HANDLE gpeobj; 75026f3cdf0SGordon Ross ACPI_OBJECT *prw, *gpe; 75126f3cdf0SGordon Ross int gpebit, prw_level; 75226f3cdf0SGordon Ross 75326f3cdf0SGordon Ross if (prw_buf->Length == 0 || prw_buf->Pointer == NULL) 75426f3cdf0SGordon Ross return (AE_NULL_OBJECT); 75526f3cdf0SGordon Ross 75626f3cdf0SGordon Ross prw = prw_buf->Pointer; 75726f3cdf0SGordon Ross if (prw->Type != ACPI_TYPE_PACKAGE || prw->Package.Count < 2 || 75826f3cdf0SGordon Ross prw->Package.Elements[1].Type != ACPI_TYPE_INTEGER) 75926f3cdf0SGordon Ross return (AE_TYPE); 7602df1fe9cSrandyf 7612df1fe9cSrandyf /* fetch the lowest wake level from the _PRW */ 7622df1fe9cSrandyf prw_level = prw->Package.Elements[1].Integer.Value; 7632df1fe9cSrandyf 7642df1fe9cSrandyf /* 7652df1fe9cSrandyf * process the GPE description 7662df1fe9cSrandyf */ 7672df1fe9cSrandyf switch (prw->Package.Elements[0].Type) { 7682df1fe9cSrandyf case ACPI_TYPE_INTEGER: 7692df1fe9cSrandyf gpeobj = NULL; 7702df1fe9cSrandyf gpebit = prw->Package.Elements[0].Integer.Value; 7712df1fe9cSrandyf break; 7722df1fe9cSrandyf case ACPI_TYPE_PACKAGE: 7732df1fe9cSrandyf gpe = &prw->Package.Elements[0]; 7742df1fe9cSrandyf if (gpe->Package.Count != 2 || 7752df1fe9cSrandyf gpe->Package.Elements[1].Type != ACPI_TYPE_INTEGER) 77626f3cdf0SGordon Ross return (AE_TYPE); 7772df1fe9cSrandyf gpeobj = gpe->Package.Elements[0].Reference.Handle; 7782df1fe9cSrandyf gpebit = gpe->Package.Elements[1].Integer.Value; 7792df1fe9cSrandyf if (gpeobj == NULL) 78026f3cdf0SGordon Ross return (AE_NULL_OBJECT); 78126f3cdf0SGordon Ross break; 7822df1fe9cSrandyf default: 78326f3cdf0SGordon Ross return (AE_TYPE); 7842df1fe9cSrandyf } 7852df1fe9cSrandyf 78626f3cdf0SGordon Ross p_prw->prw_gpeobj = gpeobj; 78726f3cdf0SGordon Ross p_prw->prw_gpebit = gpebit; 78826f3cdf0SGordon Ross p_prw->prw_level = prw_level; 78926f3cdf0SGordon Ross 79026f3cdf0SGordon Ross return (AE_OK); 7912df1fe9cSrandyf } 7922df1fe9cSrandyf 7932df1fe9cSrandyf /* 7942df1fe9cSrandyf * kstat access to a limited set of ACPI propertis 7952df1fe9cSrandyf */ 7962df1fe9cSrandyf static void 7972df1fe9cSrandyf acpica_init_kstats() 7982df1fe9cSrandyf { 7992df1fe9cSrandyf ACPI_HANDLE s3handle; 8002df1fe9cSrandyf ACPI_STATUS status; 801db2bae30SDana Myers ACPI_TABLE_FADT *fadt; 8022df1fe9cSrandyf kstat_named_t *knp; 8032df1fe9cSrandyf 8042df1fe9cSrandyf /* 8052df1fe9cSrandyf * Create a small set of named kstats; just return in the rare 8062df1fe9cSrandyf * case of a failure, * in which case, the kstats won't be present. 8072df1fe9cSrandyf */ 8082df1fe9cSrandyf if ((acpica_ksp = kstat_create("acpi", 0, "acpi", "misc", 8092df1fe9cSrandyf KSTAT_TYPE_NAMED, 2, 0)) == NULL) 8102df1fe9cSrandyf return; 8112df1fe9cSrandyf 8122df1fe9cSrandyf /* 8132df1fe9cSrandyf * initialize kstat 'S3' to reflect the presence of \_S3 in 8142df1fe9cSrandyf * the ACPI namespace (1 = present, 0 = not present) 8152df1fe9cSrandyf */ 8162df1fe9cSrandyf knp = acpica_ksp->ks_data; 8172df1fe9cSrandyf knp->value.l = (AcpiGetHandle(NULL, "\\_S3", &s3handle) == AE_OK); 8182df1fe9cSrandyf kstat_named_init(knp, "S3", KSTAT_DATA_LONG); 8192df1fe9cSrandyf knp++; /* advance to next named kstat */ 8202df1fe9cSrandyf 8212df1fe9cSrandyf /* 8222df1fe9cSrandyf * initialize kstat 'preferred_pm_profile' to the value 8232df1fe9cSrandyf * contained in the (always present) FADT 8242df1fe9cSrandyf */ 825db2bae30SDana Myers status = AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **)&fadt); 826db2bae30SDana Myers knp->value.l = (status == AE_OK) ? fadt->PreferredProfile : -1; 8272df1fe9cSrandyf kstat_named_init(knp, "preferred_pm_profile", KSTAT_DATA_LONG); 8282df1fe9cSrandyf 8292df1fe9cSrandyf /* 8302df1fe9cSrandyf * install the named kstats 8312df1fe9cSrandyf */ 8322df1fe9cSrandyf kstat_install(acpica_ksp); 8332df1fe9cSrandyf } 8342df1fe9cSrandyf 8352df1fe9cSrandyf /* 8362df1fe9cSrandyf * Attempt to save the current ACPI settings (_CRS) for the device 8372df1fe9cSrandyf * which corresponds to the supplied devinfo node. The settings are 8382df1fe9cSrandyf * saved as a property on the dip. If no ACPI object is found to be 8392df1fe9cSrandyf * associated with the devinfo node, no action is taken and no error 8402df1fe9cSrandyf * is reported. 8412df1fe9cSrandyf */ 8422df1fe9cSrandyf void 8432df1fe9cSrandyf acpica_ddi_save_resources(dev_info_t *dip) 8442df1fe9cSrandyf { 8452df1fe9cSrandyf ACPI_HANDLE devobj; 8462df1fe9cSrandyf ACPI_BUFFER resbuf; 8472df1fe9cSrandyf int ret; 8482df1fe9cSrandyf 8492df1fe9cSrandyf resbuf.Length = ACPI_ALLOCATE_BUFFER; 8502df1fe9cSrandyf if (ACPI_FAILURE(acpica_get_handle(dip, &devobj)) || 8512df1fe9cSrandyf ACPI_FAILURE(AcpiGetCurrentResources(devobj, &resbuf))) 8522df1fe9cSrandyf return; 8532df1fe9cSrandyf 8542df1fe9cSrandyf ret = ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 8552df1fe9cSrandyf "acpi-crs", resbuf.Pointer, resbuf.Length); 8562df1fe9cSrandyf 8572df1fe9cSrandyf ASSERT(ret == DDI_PROP_SUCCESS); 8582df1fe9cSrandyf 8592df1fe9cSrandyf AcpiOsFree(resbuf.Pointer); 8602df1fe9cSrandyf } 8612df1fe9cSrandyf 8622df1fe9cSrandyf /* 8632df1fe9cSrandyf * If the supplied devinfo node has an ACPI settings property attached, 8642df1fe9cSrandyf * restore them to the associated ACPI device using _SRS. The property 8652df1fe9cSrandyf * is deleted from the devinfo node afterward. 8662df1fe9cSrandyf */ 8672df1fe9cSrandyf void 8682df1fe9cSrandyf acpica_ddi_restore_resources(dev_info_t *dip) 8692df1fe9cSrandyf { 8702df1fe9cSrandyf ACPI_HANDLE devobj; 8712df1fe9cSrandyf ACPI_BUFFER resbuf; 8722df1fe9cSrandyf uchar_t *propdata; 8732df1fe9cSrandyf uint_t proplen; 8742df1fe9cSrandyf 8752df1fe9cSrandyf if (ACPI_FAILURE(acpica_get_handle(dip, &devobj))) 8762df1fe9cSrandyf return; 8772df1fe9cSrandyf 8782df1fe9cSrandyf if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 8792df1fe9cSrandyf "acpi-crs", &propdata, &proplen) != DDI_PROP_SUCCESS) 8802df1fe9cSrandyf return; 8812df1fe9cSrandyf 8822df1fe9cSrandyf resbuf.Pointer = propdata; 8832df1fe9cSrandyf resbuf.Length = proplen; 8842df1fe9cSrandyf (void) AcpiSetCurrentResources(devobj, &resbuf); 8852df1fe9cSrandyf ddi_prop_free(propdata); 8860f1b305eSSeth Goldberg (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "acpi-crs"); 8872df1fe9cSrandyf } 8884cf02d40SSaurabh Misra 8894cf02d40SSaurabh Misra void 8904cf02d40SSaurabh Misra acpi_reset_system(void) 8914cf02d40SSaurabh Misra { 8924cf02d40SSaurabh Misra ACPI_STATUS status; 8934cf02d40SSaurabh Misra int ten; 8944cf02d40SSaurabh Misra 8954cf02d40SSaurabh Misra status = AcpiReset(); 8964cf02d40SSaurabh Misra if (status == AE_OK) { 8974cf02d40SSaurabh Misra /* 8984cf02d40SSaurabh Misra * Wait up to 500 milliseconds for AcpiReset() to make its 8994cf02d40SSaurabh Misra * way. 9004cf02d40SSaurabh Misra */ 9014cf02d40SSaurabh Misra ten = 50000; 9024cf02d40SSaurabh Misra while (ten-- > 0) 9034cf02d40SSaurabh Misra tenmicrosec(); 9044cf02d40SSaurabh Misra } 9054cf02d40SSaurabh Misra } 906