17c478bd9Sstevel@tonic-gate /* 28e56767dSsmall * CDDL HEADER START 38e56767dSsmall * 48e56767dSsmall * The contents of this file are subject to the terms of the 53d50435fSmyers * Common Development and Distribution License (the "License"). 63d50435fSmyers * You may not use this file except in compliance with the License. 78e56767dSsmall * 88e56767dSsmall * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 98e56767dSsmall * or http://www.opensolaris.org/os/licensing. 108e56767dSsmall * See the License for the specific language governing permissions 118e56767dSsmall * and limitations under the License. 128e56767dSsmall * 138e56767dSsmall * When distributing Covered Code, include this CDDL HEADER in each 148e56767dSsmall * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 158e56767dSsmall * If applicable, add the following below this CDDL HEADER, with the 168e56767dSsmall * fields enclosed by brackets "[]" replaced with your own identifying 178e56767dSsmall * information: Portions Copyright [yyyy] [name of copyright owner] 188e56767dSsmall * 198e56767dSsmall * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 220f1b305eSSeth Goldberg * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 258e56767dSsmall /* 268e56767dSsmall * Solaris x86 ACPI CA services 278e56767dSsmall */ 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <sys/file.h> 307c478bd9Sstevel@tonic-gate #include <sys/errno.h> 317c478bd9Sstevel@tonic-gate #include <sys/conf.h> 327c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 337c478bd9Sstevel@tonic-gate #include <sys/open.h> 347c478bd9Sstevel@tonic-gate #include <sys/stat.h> 357c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 367c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 377c478bd9Sstevel@tonic-gate #include <sys/esunddi.h> 382df1fe9cSrandyf #include <sys/kstat.h> 39*b9bfdccdSStuart Maybee #include <sys/x86_archext.h> 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate #include <sys/acpi/acpi.h> 427c478bd9Sstevel@tonic-gate #include <sys/acpica.h> 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate /* 457c478bd9Sstevel@tonic-gate * 467c478bd9Sstevel@tonic-gate */ 477c478bd9Sstevel@tonic-gate static struct modlmisc modlmisc = { 487c478bd9Sstevel@tonic-gate &mod_miscops, 4987bb58d6Smyers "ACPI interpreter", 507c478bd9Sstevel@tonic-gate }; 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 537c478bd9Sstevel@tonic-gate MODREV_1, /* MODREV_1 manual */ 547c478bd9Sstevel@tonic-gate (void *)&modlmisc, /* module linkage */ 557c478bd9Sstevel@tonic-gate NULL, /* list terminator */ 567c478bd9Sstevel@tonic-gate }; 577c478bd9Sstevel@tonic-gate 582df1fe9cSrandyf /* 592df1fe9cSrandyf * Local prototypes 602df1fe9cSrandyf */ 612df1fe9cSrandyf 622df1fe9cSrandyf static void acpica_init_kstats(void); 632df1fe9cSrandyf 647c478bd9Sstevel@tonic-gate /* 657c478bd9Sstevel@tonic-gate * Local data 667c478bd9Sstevel@tonic-gate */ 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate static kmutex_t acpica_module_lock; 692df1fe9cSrandyf static kstat_t *acpica_ksp; 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate /* 727c478bd9Sstevel@tonic-gate * State of acpica subsystem 737c478bd9Sstevel@tonic-gate * After successful initialization, will be ACPICA_INITIALIZED 747c478bd9Sstevel@tonic-gate */ 757c478bd9Sstevel@tonic-gate int acpica_init_state = ACPICA_NOT_INITIALIZED; 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate /* 787c478bd9Sstevel@tonic-gate * Following are set by acpica_process_user_options() 797c478bd9Sstevel@tonic-gate * 807c478bd9Sstevel@tonic-gate * acpica_enable = FALSE prevents initialization of ACPI CA 817c478bd9Sstevel@tonic-gate * completely 827c478bd9Sstevel@tonic-gate * 837c478bd9Sstevel@tonic-gate * acpi_init_level determines level of ACPI CA functionality 847c478bd9Sstevel@tonic-gate * enabled in acpica_init() 857c478bd9Sstevel@tonic-gate */ 867c478bd9Sstevel@tonic-gate int acpica_enable; 877c478bd9Sstevel@tonic-gate UINT32 acpi_init_level; 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate /* 907c478bd9Sstevel@tonic-gate * Non-zero enables lax behavior with respect to some 917c478bd9Sstevel@tonic-gate * common ACPI BIOS issues; see ACPI CA documentation 927c478bd9Sstevel@tonic-gate * Setting this to zero causes ACPI CA to enforce strict 937c478bd9Sstevel@tonic-gate * compliance with ACPI specification 947c478bd9Sstevel@tonic-gate */ 957c478bd9Sstevel@tonic-gate int acpica_enable_interpreter_slack = 1; 967c478bd9Sstevel@tonic-gate 973d50435fSmyers /* 983d50435fSmyers * For non-DEBUG builds, set the ACPI CA debug level to 0 993d50435fSmyers * to quiet chatty BIOS output into /var/adm/messages 1003d50435fSmyers * Field-patchable for diagnostic use. 1013d50435fSmyers */ 1023d50435fSmyers #ifdef DEBUG 1033d50435fSmyers int acpica_muzzle_debug_output = 0; 1043d50435fSmyers #else 1053d50435fSmyers int acpica_muzzle_debug_output = 1; 1063d50435fSmyers #endif 1073d50435fSmyers 1082df1fe9cSrandyf /* 1092df1fe9cSrandyf * ACPI DDI hooks 1102df1fe9cSrandyf */ 1112df1fe9cSrandyf static int acpica_ddi_setwake(dev_info_t *dip, int level); 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate int 1147c478bd9Sstevel@tonic-gate _init(void) 1157c478bd9Sstevel@tonic-gate { 1167c478bd9Sstevel@tonic-gate int error = EBUSY; 1177c478bd9Sstevel@tonic-gate int status; 1182df1fe9cSrandyf extern int (*acpi_fp_setwake)(); 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate mutex_init(&acpica_module_lock, NULL, MUTEX_DRIVER, NULL); 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate if ((error = mod_install(&modlinkage)) != 0) { 1237c478bd9Sstevel@tonic-gate mutex_destroy(&acpica_module_lock); 1242df1fe9cSrandyf goto load_error; 1257c478bd9Sstevel@tonic-gate } 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate AcpiGbl_EnableInterpreterSlack = (acpica_enable_interpreter_slack != 0); 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate if ((status = AcpiInitializeSubsystem()) != AE_OK) { 1307c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "!acpica: error pre-init:1:%d", status); 1317c478bd9Sstevel@tonic-gate } 1327c478bd9Sstevel@tonic-gate 1332df1fe9cSrandyf acpi_fp_setwake = acpica_ddi_setwake; 1342df1fe9cSrandyf 1352df1fe9cSrandyf load_error: 1367c478bd9Sstevel@tonic-gate return (error); 1377c478bd9Sstevel@tonic-gate } 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate int 1407c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 1417c478bd9Sstevel@tonic-gate { 1427c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1437c478bd9Sstevel@tonic-gate } 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate int 1467c478bd9Sstevel@tonic-gate _fini(void) 1477c478bd9Sstevel@tonic-gate { 148186507a7Smyers /* 149186507a7Smyers * acpica module is never unloaded at run-time; there's always 150186507a7Smyers * a PSM depending on it, at the very least 151186507a7Smyers */ 152186507a7Smyers return (EBUSY); 1537c478bd9Sstevel@tonic-gate } 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate /* 1567c478bd9Sstevel@tonic-gate * Install acpica-provided address-space handlers 1577c478bd9Sstevel@tonic-gate */ 1587c478bd9Sstevel@tonic-gate static int 1597c478bd9Sstevel@tonic-gate acpica_install_handlers() 1607c478bd9Sstevel@tonic-gate { 1617c478bd9Sstevel@tonic-gate ACPI_STATUS rv = AE_OK; 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate /* 1647c478bd9Sstevel@tonic-gate * Install ACPI CA default handlers 1657c478bd9Sstevel@tonic-gate */ 1667c478bd9Sstevel@tonic-gate if (AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 1677c478bd9Sstevel@tonic-gate ACPI_ADR_SPACE_SYSTEM_MEMORY, 1687c478bd9Sstevel@tonic-gate ACPI_DEFAULT_HANDLER, NULL, NULL) != AE_OK) { 1697c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "!acpica: no default handler for" 1707c478bd9Sstevel@tonic-gate " system memory"); 1717c478bd9Sstevel@tonic-gate rv = AE_ERROR; 1727c478bd9Sstevel@tonic-gate } 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate if (AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 1757c478bd9Sstevel@tonic-gate ACPI_ADR_SPACE_SYSTEM_IO, 1767c478bd9Sstevel@tonic-gate ACPI_DEFAULT_HANDLER, NULL, NULL) != AE_OK) { 1777c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "!acpica: no default handler for" 1787c478bd9Sstevel@tonic-gate " system I/O"); 1797c478bd9Sstevel@tonic-gate rv = AE_ERROR; 1807c478bd9Sstevel@tonic-gate } 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate if (AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 1837c478bd9Sstevel@tonic-gate ACPI_ADR_SPACE_PCI_CONFIG, 1847c478bd9Sstevel@tonic-gate ACPI_DEFAULT_HANDLER, NULL, NULL) != AE_OK) { 1857c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "!acpica: no default handler for" 1867c478bd9Sstevel@tonic-gate " PCI Config"); 1877c478bd9Sstevel@tonic-gate rv = AE_ERROR; 1887c478bd9Sstevel@tonic-gate } 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate return (rv); 1927c478bd9Sstevel@tonic-gate } 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate /* 1957c478bd9Sstevel@tonic-gate * Find the BIOS date, and return TRUE if supplied 1967c478bd9Sstevel@tonic-gate * date is same or later than the BIOS date, or FALSE 1977c478bd9Sstevel@tonic-gate * if the BIOS date can't be fetched for any reason 1987c478bd9Sstevel@tonic-gate */ 1997c478bd9Sstevel@tonic-gate static int 2007c478bd9Sstevel@tonic-gate acpica_check_bios_date(int yy, int mm, int dd) 2017c478bd9Sstevel@tonic-gate { 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate char *datep; 2047c478bd9Sstevel@tonic-gate int bios_year, bios_month, bios_day; 2057c478bd9Sstevel@tonic-gate 206f2be5148Sszhou /* If firmware has no bios, skip the check */ 207f2be5148Sszhou if (ddi_prop_exists(DDI_DEV_T_ANY, ddi_root_node(), 0, "bios-free")) 208f2be5148Sszhou return (TRUE); 209f2be5148Sszhou 2107c478bd9Sstevel@tonic-gate /* 2117c478bd9Sstevel@tonic-gate * PC BIOSes contain a string in the form of 2127c478bd9Sstevel@tonic-gate * "mm/dd/yy" at absolute address 0xffff5, 2137c478bd9Sstevel@tonic-gate * where mm, dd and yy are all ASCII digits. 2147c478bd9Sstevel@tonic-gate * We map the string, pluck out the values, 2157c478bd9Sstevel@tonic-gate * and accept all BIOSes from 1 Jan 1999 on 2167c478bd9Sstevel@tonic-gate * as valid. 2177c478bd9Sstevel@tonic-gate */ 2187c478bd9Sstevel@tonic-gate 219db2bae30SDana Myers if ((datep = (char *)AcpiOsMapMemory(0xffff5, 8)) == NULL) 2207c478bd9Sstevel@tonic-gate return (FALSE); 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate /* year */ 2237c478bd9Sstevel@tonic-gate bios_year = ((int)(*(datep + 6) - '0') * 10) + (*(datep + 7) - '0'); 2247c478bd9Sstevel@tonic-gate /* month */ 2257c478bd9Sstevel@tonic-gate bios_month = ((int)(*datep - '0') * 10) + (*(datep + 1) - '0'); 2267c478bd9Sstevel@tonic-gate /* day */ 2277c478bd9Sstevel@tonic-gate bios_day = ((int)(*(datep + 3) - '0') * 10) + (*(datep + 4) - '0'); 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate AcpiOsUnmapMemory((void *) datep, 8); 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate if (bios_year < 0 || bios_year > 99 || bios_month < 0 || 2327c478bd9Sstevel@tonic-gate bios_month > 99 || bios_day < 0 || bios_day > 99) { 2337c478bd9Sstevel@tonic-gate /* non-digit chars in BIOS date */ 2347c478bd9Sstevel@tonic-gate return (FALSE); 2357c478bd9Sstevel@tonic-gate } 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate /* 2387c478bd9Sstevel@tonic-gate * Adjust for 2-digit year; note to grand-children: 2397c478bd9Sstevel@tonic-gate * need a new scheme before 2080 rolls around 2407c478bd9Sstevel@tonic-gate */ 2417c478bd9Sstevel@tonic-gate bios_year += (bios_year >= 80 && bios_year <= 99) ? 2427c478bd9Sstevel@tonic-gate 1900 : 2000; 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate if (bios_year < yy) 2457c478bd9Sstevel@tonic-gate return (FALSE); 2467c478bd9Sstevel@tonic-gate else if (bios_year > yy) 2477c478bd9Sstevel@tonic-gate return (TRUE); 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate if (bios_month < mm) 2507c478bd9Sstevel@tonic-gate return (FALSE); 2517c478bd9Sstevel@tonic-gate else if (bios_month > mm) 2527c478bd9Sstevel@tonic-gate return (TRUE); 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate if (bios_day < dd) 2557c478bd9Sstevel@tonic-gate return (FALSE); 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate return (TRUE); 2587c478bd9Sstevel@tonic-gate } 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate /* 2617c478bd9Sstevel@tonic-gate * Check for Metropolis systems with BIOSes older than 10/12/04 2627c478bd9Sstevel@tonic-gate * return TRUE if BIOS requires legacy mode, FALSE otherwise 2637c478bd9Sstevel@tonic-gate */ 2647c478bd9Sstevel@tonic-gate static int 2657c478bd9Sstevel@tonic-gate acpica_metro_old_bios() 2667c478bd9Sstevel@tonic-gate { 2677c478bd9Sstevel@tonic-gate ACPI_TABLE_HEADER *fadt; 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate /* get the FADT */ 270db2bae30SDana Myers if (AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **)&fadt) != 271db2bae30SDana Myers AE_OK) 2727c478bd9Sstevel@tonic-gate return (FALSE); 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate /* compare OEM Table ID to "SUNmetro" - no match, return false */ 2757c478bd9Sstevel@tonic-gate if (strncmp("SUNmetro", fadt->OemTableId, 8)) 2767c478bd9Sstevel@tonic-gate return (FALSE); 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate /* On a Metro - return FALSE if later than 10/12/04 */ 2797c478bd9Sstevel@tonic-gate return (!acpica_check_bios_date(2004, 10, 12)); 2807c478bd9Sstevel@tonic-gate } 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate /* 2847c478bd9Sstevel@tonic-gate * Process acpi-user-options property if present 2857c478bd9Sstevel@tonic-gate */ 2867c478bd9Sstevel@tonic-gate static void 2877c478bd9Sstevel@tonic-gate acpica_process_user_options() 2887c478bd9Sstevel@tonic-gate { 2897c478bd9Sstevel@tonic-gate static int processed = 0; 2907c478bd9Sstevel@tonic-gate int acpi_user_options; 2917c478bd9Sstevel@tonic-gate char *acpi_prop; 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate /* 2947c478bd9Sstevel@tonic-gate * return if acpi-user-options has already been processed 2957c478bd9Sstevel@tonic-gate */ 2967c478bd9Sstevel@tonic-gate if (processed) 2977c478bd9Sstevel@tonic-gate return; 2987c478bd9Sstevel@tonic-gate else 2997c478bd9Sstevel@tonic-gate processed = 1; 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate /* converts acpi-user-options from type string to int, if any */ 3027c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 3037c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "acpi-user-options", &acpi_prop) == 3047c478bd9Sstevel@tonic-gate DDI_PROP_SUCCESS) { 3057c478bd9Sstevel@tonic-gate long data; 3067c478bd9Sstevel@tonic-gate int ret; 3077c478bd9Sstevel@tonic-gate ret = ddi_strtol(acpi_prop, NULL, 0, &data); 3087c478bd9Sstevel@tonic-gate if (ret == 0) { 3097c478bd9Sstevel@tonic-gate e_ddi_prop_remove(DDI_DEV_T_NONE, ddi_root_node(), 3107c478bd9Sstevel@tonic-gate "acpi-user-options"); 311f7534bc1Ssmall e_ddi_prop_update_int(DDI_DEV_T_NONE, ddi_root_node(), 312f7534bc1Ssmall "acpi-user-options", data); 3137c478bd9Sstevel@tonic-gate } 3147c478bd9Sstevel@tonic-gate ddi_prop_free(acpi_prop); 3157c478bd9Sstevel@tonic-gate } 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate /* 3187c478bd9Sstevel@tonic-gate * fetch the optional options property 3197c478bd9Sstevel@tonic-gate */ 3207c478bd9Sstevel@tonic-gate acpi_user_options = ddi_prop_get_int(DDI_DEV_T_ANY, ddi_root_node(), 0, 3217c478bd9Sstevel@tonic-gate "acpi-user-options", 0); 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate /* 3247c478bd9Sstevel@tonic-gate * Note that 'off' has precedence over 'on' 3257c478bd9Sstevel@tonic-gate * Also note - all cases of ACPI_OUSER_MASK 3267c478bd9Sstevel@tonic-gate * provided here, no default: case is present 3277c478bd9Sstevel@tonic-gate */ 3287c478bd9Sstevel@tonic-gate switch (acpi_user_options & ACPI_OUSER_MASK) { 3297c478bd9Sstevel@tonic-gate case ACPI_OUSER_DFLT: 3307c478bd9Sstevel@tonic-gate acpica_enable = acpica_check_bios_date(1999, 1, 1); 3317c478bd9Sstevel@tonic-gate break; 3327c478bd9Sstevel@tonic-gate case ACPI_OUSER_ON: 3337c478bd9Sstevel@tonic-gate acpica_enable = TRUE; 3347c478bd9Sstevel@tonic-gate break; 3357c478bd9Sstevel@tonic-gate case ACPI_OUSER_OFF: 3367c478bd9Sstevel@tonic-gate case ACPI_OUSER_OFF | ACPI_OUSER_ON: 3377c478bd9Sstevel@tonic-gate acpica_enable = FALSE; 3387c478bd9Sstevel@tonic-gate break; 3397c478bd9Sstevel@tonic-gate } 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate acpi_init_level = ACPI_FULL_INITIALIZATION; 3427c478bd9Sstevel@tonic-gate 3437c478bd9Sstevel@tonic-gate /* 3447c478bd9Sstevel@tonic-gate * special test here; may be generalized in the 3457c478bd9Sstevel@tonic-gate * future - test for a machines that are known to 3467c478bd9Sstevel@tonic-gate * work only in legacy mode, and set OUSER_LEGACY if 3477c478bd9Sstevel@tonic-gate * we're on one 3487c478bd9Sstevel@tonic-gate */ 3497c478bd9Sstevel@tonic-gate if (acpica_metro_old_bios()) 3507c478bd9Sstevel@tonic-gate acpi_user_options |= ACPI_OUSER_LEGACY; 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate /* 3537c478bd9Sstevel@tonic-gate * If legacy mode is specified, set initialization 3547c478bd9Sstevel@tonic-gate * options to avoid entering ACPI mode and hooking SCI 3557c478bd9Sstevel@tonic-gate * - basically try to act like legacy acpi_intp 3567c478bd9Sstevel@tonic-gate */ 3577c478bd9Sstevel@tonic-gate if ((acpi_user_options & ACPI_OUSER_LEGACY) != 0) 3587c478bd9Sstevel@tonic-gate acpi_init_level |= (ACPI_NO_ACPI_ENABLE | ACPI_NO_HANDLER_INIT); 3593d50435fSmyers 3603d50435fSmyers /* 3613d50435fSmyers * modify default ACPI CA debug output level for non-DEBUG builds 3623d50435fSmyers * (to avoid BIOS debug chatter in /var/adm/messages) 3633d50435fSmyers */ 3643d50435fSmyers if (acpica_muzzle_debug_output) 3653d50435fSmyers AcpiDbgLevel = 0; 3667c478bd9Sstevel@tonic-gate } 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate /* 3697c478bd9Sstevel@tonic-gate * Initialize the CA subsystem if it hasn't been done already 3707c478bd9Sstevel@tonic-gate */ 3717c478bd9Sstevel@tonic-gate int 3727c478bd9Sstevel@tonic-gate acpica_init() 3737c478bd9Sstevel@tonic-gate { 374*b9bfdccdSStuart Maybee extern void acpica_find_ioapics(void); 3757c478bd9Sstevel@tonic-gate ACPI_STATUS status; 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate /* 3787c478bd9Sstevel@tonic-gate * Make sure user options are processed, 3797c478bd9Sstevel@tonic-gate * then fail to initialize if ACPI CA has been 3807c478bd9Sstevel@tonic-gate * disabled 3817c478bd9Sstevel@tonic-gate */ 3827c478bd9Sstevel@tonic-gate acpica_process_user_options(); 3837c478bd9Sstevel@tonic-gate if (!acpica_enable) 3847c478bd9Sstevel@tonic-gate return (AE_ERROR); 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate mutex_enter(&acpica_module_lock); 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate if (acpica_init_state == ACPICA_NOT_INITIALIZED) { 389db2bae30SDana Myers if (ACPI_FAILURE(status = AcpiInitializeTables(NULL, 0, 0))) 3907c478bd9Sstevel@tonic-gate goto error; 391db2bae30SDana Myers 392db2bae30SDana Myers if (ACPI_FAILURE(status = AcpiLoadTables())) 3937c478bd9Sstevel@tonic-gate goto error; 394db2bae30SDana Myers 395db2bae30SDana Myers if (ACPI_FAILURE(status = acpica_install_handlers())) 3967c478bd9Sstevel@tonic-gate goto error; 397db2bae30SDana Myers 398db2bae30SDana Myers if (ACPI_FAILURE(status = AcpiEnableSubsystem( 399db2bae30SDana Myers acpi_init_level))) 4007c478bd9Sstevel@tonic-gate goto error; 401db2bae30SDana Myers 402db2bae30SDana Myers if (ACPI_FAILURE(status = AcpiInitializeObjects(0))) 403db2bae30SDana Myers goto error; 404db2bae30SDana Myers 4057c478bd9Sstevel@tonic-gate /* 4067c478bd9Sstevel@tonic-gate * Initialize EC 4077c478bd9Sstevel@tonic-gate */ 4087c478bd9Sstevel@tonic-gate acpica_ec_init(); 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate acpica_init_state = ACPICA_INITIALIZED; 411*b9bfdccdSStuart Maybee /* 412*b9bfdccdSStuart Maybee * If we are running on the Xen hypervisor as dom0 we need to 413*b9bfdccdSStuart Maybee * find the ioapics so we can prevent ACPI from trying to 414*b9bfdccdSStuart Maybee * access them. 415*b9bfdccdSStuart Maybee */ 416*b9bfdccdSStuart Maybee if (get_hwenv() == HW_XEN_PV && is_controldom()) 417*b9bfdccdSStuart Maybee acpica_find_ioapics(); 4182df1fe9cSrandyf acpica_init_kstats(); 4197c478bd9Sstevel@tonic-gate error: 4207c478bd9Sstevel@tonic-gate if (acpica_init_state != ACPICA_INITIALIZED) { 4217c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "!failed to initialize" 4227c478bd9Sstevel@tonic-gate " ACPI services"); 4237c478bd9Sstevel@tonic-gate } 4247c478bd9Sstevel@tonic-gate } else 4257c478bd9Sstevel@tonic-gate status = AE_OK; 4267c478bd9Sstevel@tonic-gate 427f7534bc1Ssmall /* 428f7534bc1Ssmall * Set acpi-status to 13 if acpica has been initialized successfully. 429f7534bc1Ssmall * This indicates that acpica is up and running. This variable name 430f7534bc1Ssmall * and value were chosen in order to remain compatible with acpi_intp. 431f7534bc1Ssmall */ 432f7534bc1Ssmall e_ddi_prop_update_int(DDI_DEV_T_NONE, ddi_root_node(), "acpi-status", 43387bb58d6Smyers (status == AE_OK) ? (ACPI_BOOT_INIT | ACPI_BOOT_ENABLE | 43487bb58d6Smyers ACPI_BOOT_BOOTCONF) : 0); 435f7534bc1Ssmall 4367c478bd9Sstevel@tonic-gate mutex_exit(&acpica_module_lock); 4377c478bd9Sstevel@tonic-gate return (status); 4387c478bd9Sstevel@tonic-gate } 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate /* 4417c478bd9Sstevel@tonic-gate * SCI handling 4427c478bd9Sstevel@tonic-gate */ 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate ACPI_STATUS 4457c478bd9Sstevel@tonic-gate acpica_get_sci(int *sci_irq, iflag_t *sci_flags) 4467c478bd9Sstevel@tonic-gate { 447db2bae30SDana Myers ACPI_SUBTABLE_HEADER *ap; 448db2bae30SDana Myers ACPI_TABLE_MADT *mat; 449db2bae30SDana Myers ACPI_MADT_INTERRUPT_OVERRIDE *mio; 450db2bae30SDana Myers ACPI_TABLE_FADT *fadt; 4517c478bd9Sstevel@tonic-gate int madt_seen, madt_size; 4527c478bd9Sstevel@tonic-gate 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate /* 4557c478bd9Sstevel@tonic-gate * Make sure user options are processed, 4567c478bd9Sstevel@tonic-gate * then return error if ACPI CA has been 4577c478bd9Sstevel@tonic-gate * disabled or system is not running in ACPI 4587c478bd9Sstevel@tonic-gate * and won't need/understand SCI 4597c478bd9Sstevel@tonic-gate */ 4607c478bd9Sstevel@tonic-gate acpica_process_user_options(); 4617c478bd9Sstevel@tonic-gate if ((!acpica_enable) || (acpi_init_level & ACPI_NO_ACPI_ENABLE)) 4627c478bd9Sstevel@tonic-gate return (AE_ERROR); 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate /* 4657c478bd9Sstevel@tonic-gate * according to Intel ACPI developers, SCI 4667c478bd9Sstevel@tonic-gate * conforms to PCI bus conventions; level/low 4677c478bd9Sstevel@tonic-gate * unless otherwise directed by overrides. 4687c478bd9Sstevel@tonic-gate */ 4697c478bd9Sstevel@tonic-gate sci_flags->intr_el = INTR_EL_LEVEL; 4707c478bd9Sstevel@tonic-gate sci_flags->intr_po = INTR_PO_ACTIVE_LOW; 4717c478bd9Sstevel@tonic-gate sci_flags->bustype = BUS_PCI; /* we *do* conform to PCI */ 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate /* get the SCI from the FADT */ 474db2bae30SDana Myers if (AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **)&fadt) != 475db2bae30SDana Myers AE_OK) 4767c478bd9Sstevel@tonic-gate return (AE_ERROR); 4777c478bd9Sstevel@tonic-gate 478db2bae30SDana Myers *sci_irq = fadt->SciInterrupt; 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate /* search for ISOs that modify it */ 4817c478bd9Sstevel@tonic-gate /* if we don't find a MADT, that's OK; no ISOs then */ 482db2bae30SDana Myers if (AcpiGetTable(ACPI_SIG_MADT, 1, (ACPI_TABLE_HEADER **) &mat) != 483db2bae30SDana Myers AE_OK) 4847c478bd9Sstevel@tonic-gate return (AE_OK); 4857c478bd9Sstevel@tonic-gate 486db2bae30SDana Myers ap = (ACPI_SUBTABLE_HEADER *) (mat + 1); 487db2bae30SDana Myers madt_size = mat->Header.Length; 4887c478bd9Sstevel@tonic-gate madt_seen = sizeof (*mat); 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate while (madt_seen < madt_size) { 4917c478bd9Sstevel@tonic-gate switch (ap->Type) { 492db2bae30SDana Myers case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE: 493db2bae30SDana Myers mio = (ACPI_MADT_INTERRUPT_OVERRIDE *) ap; 494db2bae30SDana Myers if (mio->SourceIrq == *sci_irq) { 495db2bae30SDana Myers *sci_irq = mio->GlobalIrq; 496db2bae30SDana Myers sci_flags->intr_el = (mio->IntiFlags & 497db2bae30SDana Myers ACPI_MADT_TRIGGER_MASK) >> 2; 498db2bae30SDana Myers sci_flags->intr_po = mio->IntiFlags & 499db2bae30SDana Myers ACPI_MADT_POLARITY_MASK; 5007c478bd9Sstevel@tonic-gate } 5017c478bd9Sstevel@tonic-gate break; 5027c478bd9Sstevel@tonic-gate } 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate /* advance to next entry */ 5057c478bd9Sstevel@tonic-gate madt_seen += ap->Length; 506db2bae30SDana Myers ap = (ACPI_SUBTABLE_HEADER *)(((char *)ap) + ap->Length); 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate /* 5107c478bd9Sstevel@tonic-gate * One more check; if ISO said "conform", revert to default 5117c478bd9Sstevel@tonic-gate */ 5127c478bd9Sstevel@tonic-gate if (sci_flags->intr_el == INTR_EL_CONFORM) 5137c478bd9Sstevel@tonic-gate sci_flags->intr_el = INTR_EL_LEVEL; 5147c478bd9Sstevel@tonic-gate if (sci_flags->intr_po == INTR_PO_CONFORM) 5157c478bd9Sstevel@tonic-gate sci_flags->intr_po = INTR_PO_ACTIVE_LOW; 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate return (AE_OK); 5187c478bd9Sstevel@tonic-gate } 5192df1fe9cSrandyf 5202df1fe9cSrandyf /* 5212df1fe9cSrandyf * Sets ACPI wake state for device referenced by dip. 5222df1fe9cSrandyf * If level is S0 (0), disables wake event; otherwise, 5232df1fe9cSrandyf * enables wake event which will wake system from level. 5242df1fe9cSrandyf */ 5252df1fe9cSrandyf static int 5262df1fe9cSrandyf acpica_ddi_setwake(dev_info_t *dip, int level) 5272df1fe9cSrandyf { 5282df1fe9cSrandyf ACPI_STATUS status; 5292df1fe9cSrandyf ACPI_HANDLE devobj, gpeobj; 5302df1fe9cSrandyf ACPI_OBJECT *prw, *gpe; 5312df1fe9cSrandyf ACPI_BUFFER prw_buf; 5322df1fe9cSrandyf int gpebit, pwr_res_count, prw_level, rv; 5332df1fe9cSrandyf 5342df1fe9cSrandyf /* 5352df1fe9cSrandyf * initialize these early so we can use a common 5362df1fe9cSrandyf * exit point below 5372df1fe9cSrandyf */ 5382df1fe9cSrandyf prw_buf.Pointer = NULL; 5392df1fe9cSrandyf prw_buf.Length = ACPI_ALLOCATE_BUFFER; 5402df1fe9cSrandyf rv = 0; 5412df1fe9cSrandyf 5422df1fe9cSrandyf /* 5432df1fe9cSrandyf * Attempt to get a handle to a corresponding ACPI object. 5442df1fe9cSrandyf * If no object is found, return quietly, since not all 5452df1fe9cSrandyf * devices have corresponding ACPI objects. 5462df1fe9cSrandyf */ 5472df1fe9cSrandyf status = acpica_get_handle(dip, &devobj); 5482df1fe9cSrandyf if (ACPI_FAILURE(status)) { 5492df1fe9cSrandyf char pathbuf[MAXPATHLEN]; 5502df1fe9cSrandyf ddi_pathname(dip, pathbuf); 5512df1fe9cSrandyf #ifdef DEBUG 5522df1fe9cSrandyf cmn_err(CE_NOTE, "!acpica_ddi_setwake: could not get" 5532df1fe9cSrandyf " handle for %s, %s:%d", pathbuf, ddi_driver_name(dip), 5542df1fe9cSrandyf ddi_get_instance(dip)); 5552df1fe9cSrandyf #endif 5562df1fe9cSrandyf goto done; 5572df1fe9cSrandyf } 5582df1fe9cSrandyf 5592df1fe9cSrandyf /* 5602df1fe9cSrandyf * Attempt to evaluate _PRW object. 5612df1fe9cSrandyf * If no valid object is found, return quietly, since not all 5622df1fe9cSrandyf * devices have _PRW objects. 5632df1fe9cSrandyf */ 5642df1fe9cSrandyf status = AcpiEvaluateObject(devobj, "_PRW", NULL, &prw_buf); 5652df1fe9cSrandyf prw = prw_buf.Pointer; 566db2bae30SDana Myers if (ACPI_FAILURE(status) || prw_buf.Length == 0 || prw == NULL || 5672df1fe9cSrandyf prw->Type != ACPI_TYPE_PACKAGE || prw->Package.Count < 2 || 5682df1fe9cSrandyf prw->Package.Elements[1].Type != ACPI_TYPE_INTEGER) { 5692df1fe9cSrandyf cmn_err(CE_NOTE, "acpica_ddi_setwake: could not " 5702df1fe9cSrandyf " evaluate _PRW"); 5712df1fe9cSrandyf goto done; 5722df1fe9cSrandyf } 5732df1fe9cSrandyf 5742df1fe9cSrandyf /* fetch the lowest wake level from the _PRW */ 5752df1fe9cSrandyf prw_level = prw->Package.Elements[1].Integer.Value; 5762df1fe9cSrandyf 5772df1fe9cSrandyf /* 5782df1fe9cSrandyf * process the GPE description 5792df1fe9cSrandyf */ 5802df1fe9cSrandyf switch (prw->Package.Elements[0].Type) { 5812df1fe9cSrandyf case ACPI_TYPE_INTEGER: 5822df1fe9cSrandyf gpeobj = NULL; 5832df1fe9cSrandyf gpebit = prw->Package.Elements[0].Integer.Value; 5842df1fe9cSrandyf break; 5852df1fe9cSrandyf case ACPI_TYPE_PACKAGE: 5862df1fe9cSrandyf gpe = &prw->Package.Elements[0]; 5872df1fe9cSrandyf if (gpe->Package.Count != 2 || 5882df1fe9cSrandyf gpe->Package.Elements[1].Type != ACPI_TYPE_INTEGER) 5892df1fe9cSrandyf goto done; 5902df1fe9cSrandyf gpeobj = gpe->Package.Elements[0].Reference.Handle; 5912df1fe9cSrandyf gpebit = gpe->Package.Elements[1].Integer.Value; 5922df1fe9cSrandyf if (gpeobj == NULL) 5932df1fe9cSrandyf goto done; 5942df1fe9cSrandyf default: 5952df1fe9cSrandyf goto done; 5962df1fe9cSrandyf } 5972df1fe9cSrandyf 5982df1fe9cSrandyf rv = -1; 5992df1fe9cSrandyf if (level == 0) { 6002df1fe9cSrandyf if (ACPI_FAILURE(AcpiDisableGpe(gpeobj, gpebit, ACPI_NOT_ISR))) 6012df1fe9cSrandyf goto done; 6022df1fe9cSrandyf } else if (prw_level <= level) { 6032df1fe9cSrandyf if (ACPI_SUCCESS( 6042df1fe9cSrandyf AcpiSetGpeType(gpeobj, gpebit, ACPI_GPE_TYPE_WAKE))) 6052df1fe9cSrandyf if (ACPI_FAILURE( 6062df1fe9cSrandyf AcpiEnableGpe(gpeobj, gpebit, ACPI_NOT_ISR))) 6072df1fe9cSrandyf goto done; 6082df1fe9cSrandyf } 6092df1fe9cSrandyf rv = 0; 6102df1fe9cSrandyf done: 6112df1fe9cSrandyf if (prw_buf.Pointer != NULL) 6122df1fe9cSrandyf AcpiOsFree(prw_buf.Pointer); 6132df1fe9cSrandyf return (rv); 6142df1fe9cSrandyf } 6152df1fe9cSrandyf 6162df1fe9cSrandyf /* 6172df1fe9cSrandyf * kstat access to a limited set of ACPI propertis 6182df1fe9cSrandyf */ 6192df1fe9cSrandyf static void 6202df1fe9cSrandyf acpica_init_kstats() 6212df1fe9cSrandyf { 6222df1fe9cSrandyf ACPI_HANDLE s3handle; 6232df1fe9cSrandyf ACPI_STATUS status; 624db2bae30SDana Myers ACPI_TABLE_FADT *fadt; 6252df1fe9cSrandyf kstat_named_t *knp; 6262df1fe9cSrandyf 6272df1fe9cSrandyf /* 6282df1fe9cSrandyf * Create a small set of named kstats; just return in the rare 6292df1fe9cSrandyf * case of a failure, * in which case, the kstats won't be present. 6302df1fe9cSrandyf */ 6312df1fe9cSrandyf if ((acpica_ksp = kstat_create("acpi", 0, "acpi", "misc", 6322df1fe9cSrandyf KSTAT_TYPE_NAMED, 2, 0)) == NULL) 6332df1fe9cSrandyf return; 6342df1fe9cSrandyf 6352df1fe9cSrandyf /* 6362df1fe9cSrandyf * initialize kstat 'S3' to reflect the presence of \_S3 in 6372df1fe9cSrandyf * the ACPI namespace (1 = present, 0 = not present) 6382df1fe9cSrandyf */ 6392df1fe9cSrandyf knp = acpica_ksp->ks_data; 6402df1fe9cSrandyf knp->value.l = (AcpiGetHandle(NULL, "\\_S3", &s3handle) == AE_OK); 6412df1fe9cSrandyf kstat_named_init(knp, "S3", KSTAT_DATA_LONG); 6422df1fe9cSrandyf knp++; /* advance to next named kstat */ 6432df1fe9cSrandyf 6442df1fe9cSrandyf /* 6452df1fe9cSrandyf * initialize kstat 'preferred_pm_profile' to the value 6462df1fe9cSrandyf * contained in the (always present) FADT 6472df1fe9cSrandyf */ 648db2bae30SDana Myers status = AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **)&fadt); 649db2bae30SDana Myers knp->value.l = (status == AE_OK) ? fadt->PreferredProfile : -1; 6502df1fe9cSrandyf kstat_named_init(knp, "preferred_pm_profile", KSTAT_DATA_LONG); 6512df1fe9cSrandyf 6522df1fe9cSrandyf /* 6532df1fe9cSrandyf * install the named kstats 6542df1fe9cSrandyf */ 6552df1fe9cSrandyf kstat_install(acpica_ksp); 6562df1fe9cSrandyf } 6572df1fe9cSrandyf 6582df1fe9cSrandyf /* 6592df1fe9cSrandyf * Attempt to save the current ACPI settings (_CRS) for the device 6602df1fe9cSrandyf * which corresponds to the supplied devinfo node. The settings are 6612df1fe9cSrandyf * saved as a property on the dip. If no ACPI object is found to be 6622df1fe9cSrandyf * associated with the devinfo node, no action is taken and no error 6632df1fe9cSrandyf * is reported. 6642df1fe9cSrandyf */ 6652df1fe9cSrandyf void 6662df1fe9cSrandyf acpica_ddi_save_resources(dev_info_t *dip) 6672df1fe9cSrandyf { 6682df1fe9cSrandyf ACPI_HANDLE devobj; 6692df1fe9cSrandyf ACPI_BUFFER resbuf; 6702df1fe9cSrandyf int ret; 6712df1fe9cSrandyf 6722df1fe9cSrandyf resbuf.Length = ACPI_ALLOCATE_BUFFER; 6732df1fe9cSrandyf if (ACPI_FAILURE(acpica_get_handle(dip, &devobj)) || 6742df1fe9cSrandyf ACPI_FAILURE(AcpiGetCurrentResources(devobj, &resbuf))) 6752df1fe9cSrandyf return; 6762df1fe9cSrandyf 6772df1fe9cSrandyf ret = ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 6782df1fe9cSrandyf "acpi-crs", resbuf.Pointer, resbuf.Length); 6792df1fe9cSrandyf 6802df1fe9cSrandyf ASSERT(ret == DDI_PROP_SUCCESS); 6812df1fe9cSrandyf 6822df1fe9cSrandyf AcpiOsFree(resbuf.Pointer); 6832df1fe9cSrandyf } 6842df1fe9cSrandyf 6852df1fe9cSrandyf /* 6862df1fe9cSrandyf * If the supplied devinfo node has an ACPI settings property attached, 6872df1fe9cSrandyf * restore them to the associated ACPI device using _SRS. The property 6882df1fe9cSrandyf * is deleted from the devinfo node afterward. 6892df1fe9cSrandyf */ 6902df1fe9cSrandyf void 6912df1fe9cSrandyf acpica_ddi_restore_resources(dev_info_t *dip) 6922df1fe9cSrandyf { 6932df1fe9cSrandyf ACPI_HANDLE devobj; 6942df1fe9cSrandyf ACPI_BUFFER resbuf; 6952df1fe9cSrandyf uchar_t *propdata; 6962df1fe9cSrandyf uint_t proplen; 6972df1fe9cSrandyf 6982df1fe9cSrandyf if (ACPI_FAILURE(acpica_get_handle(dip, &devobj))) 6992df1fe9cSrandyf return; 7002df1fe9cSrandyf 7012df1fe9cSrandyf if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 7022df1fe9cSrandyf "acpi-crs", &propdata, &proplen) != DDI_PROP_SUCCESS) 7032df1fe9cSrandyf return; 7042df1fe9cSrandyf 7052df1fe9cSrandyf resbuf.Pointer = propdata; 7062df1fe9cSrandyf resbuf.Length = proplen; 7072df1fe9cSrandyf (void) AcpiSetCurrentResources(devobj, &resbuf); 7082df1fe9cSrandyf ddi_prop_free(propdata); 7090f1b305eSSeth Goldberg (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "acpi-crs"); 7102df1fe9cSrandyf } 711