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 /* 22*87bb58d6Smyers * Copyright 2007 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 #pragma ident "%Z%%M% %I% %E% SMI" 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #include <sys/file.h> 337c478bd9Sstevel@tonic-gate #include <sys/errno.h> 347c478bd9Sstevel@tonic-gate #include <sys/conf.h> 357c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 367c478bd9Sstevel@tonic-gate #include <sys/open.h> 377c478bd9Sstevel@tonic-gate #include <sys/stat.h> 387c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 397c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 407c478bd9Sstevel@tonic-gate #include <sys/esunddi.h> 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #include <sys/acpi/acpi.h> 437c478bd9Sstevel@tonic-gate #include <sys/acpica.h> 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate /* 467c478bd9Sstevel@tonic-gate * 477c478bd9Sstevel@tonic-gate */ 487c478bd9Sstevel@tonic-gate static struct modlmisc modlmisc = { 497c478bd9Sstevel@tonic-gate &mod_miscops, 50*87bb58d6Smyers "ACPI interpreter", 517c478bd9Sstevel@tonic-gate }; 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 547c478bd9Sstevel@tonic-gate MODREV_1, /* MODREV_1 manual */ 557c478bd9Sstevel@tonic-gate (void *)&modlmisc, /* module linkage */ 567c478bd9Sstevel@tonic-gate NULL, /* list terminator */ 577c478bd9Sstevel@tonic-gate }; 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate /* 607c478bd9Sstevel@tonic-gate * Local data 617c478bd9Sstevel@tonic-gate */ 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate static kmutex_t acpica_module_lock; 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate /* 667c478bd9Sstevel@tonic-gate * State of acpica subsystem 677c478bd9Sstevel@tonic-gate * After successful initialization, will be ACPICA_INITIALIZED 687c478bd9Sstevel@tonic-gate */ 697c478bd9Sstevel@tonic-gate int acpica_init_state = ACPICA_NOT_INITIALIZED; 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate /* 727c478bd9Sstevel@tonic-gate * Following are set by acpica_process_user_options() 737c478bd9Sstevel@tonic-gate * 747c478bd9Sstevel@tonic-gate * acpica_enable = FALSE prevents initialization of ACPI CA 757c478bd9Sstevel@tonic-gate * completely 767c478bd9Sstevel@tonic-gate * 777c478bd9Sstevel@tonic-gate * acpi_init_level determines level of ACPI CA functionality 787c478bd9Sstevel@tonic-gate * enabled in acpica_init() 797c478bd9Sstevel@tonic-gate */ 807c478bd9Sstevel@tonic-gate int acpica_enable; 817c478bd9Sstevel@tonic-gate UINT32 acpi_init_level; 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate /* 847c478bd9Sstevel@tonic-gate * Non-zero enables lax behavior with respect to some 857c478bd9Sstevel@tonic-gate * common ACPI BIOS issues; see ACPI CA documentation 867c478bd9Sstevel@tonic-gate * Setting this to zero causes ACPI CA to enforce strict 877c478bd9Sstevel@tonic-gate * compliance with ACPI specification 887c478bd9Sstevel@tonic-gate */ 897c478bd9Sstevel@tonic-gate int acpica_enable_interpreter_slack = 1; 907c478bd9Sstevel@tonic-gate 913d50435fSmyers /* 923d50435fSmyers * For non-DEBUG builds, set the ACPI CA debug level to 0 933d50435fSmyers * to quiet chatty BIOS output into /var/adm/messages 943d50435fSmyers * Field-patchable for diagnostic use. 953d50435fSmyers */ 963d50435fSmyers #ifdef DEBUG 973d50435fSmyers int acpica_muzzle_debug_output = 0; 983d50435fSmyers #else 993d50435fSmyers int acpica_muzzle_debug_output = 1; 1003d50435fSmyers #endif 1013d50435fSmyers 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate int 1047c478bd9Sstevel@tonic-gate _init(void) 1057c478bd9Sstevel@tonic-gate { 1067c478bd9Sstevel@tonic-gate int error = EBUSY; 1077c478bd9Sstevel@tonic-gate int status; 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate mutex_init(&acpica_module_lock, NULL, MUTEX_DRIVER, NULL); 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate if ((error = mod_install(&modlinkage)) != 0) { 1127c478bd9Sstevel@tonic-gate mutex_destroy(&acpica_module_lock); 1137c478bd9Sstevel@tonic-gate } 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate AcpiGbl_EnableInterpreterSlack = (acpica_enable_interpreter_slack != 0); 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate if ((status = AcpiInitializeSubsystem()) != AE_OK) { 1187c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "!acpica: error pre-init:1:%d", status); 1197c478bd9Sstevel@tonic-gate } 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate return (error); 1227c478bd9Sstevel@tonic-gate } 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate int 1257c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 1267c478bd9Sstevel@tonic-gate { 1277c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1287c478bd9Sstevel@tonic-gate } 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate int 1317c478bd9Sstevel@tonic-gate _fini(void) 1327c478bd9Sstevel@tonic-gate { 133186507a7Smyers /* 134186507a7Smyers * acpica module is never unloaded at run-time; there's always 135186507a7Smyers * a PSM depending on it, at the very least 136186507a7Smyers */ 137186507a7Smyers return (EBUSY); 1387c478bd9Sstevel@tonic-gate } 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate /* 1417c478bd9Sstevel@tonic-gate * Install acpica-provided address-space handlers 1427c478bd9Sstevel@tonic-gate */ 1437c478bd9Sstevel@tonic-gate static int 1447c478bd9Sstevel@tonic-gate acpica_install_handlers() 1457c478bd9Sstevel@tonic-gate { 1467c478bd9Sstevel@tonic-gate ACPI_STATUS rv = AE_OK; 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate /* 1497c478bd9Sstevel@tonic-gate * Install ACPI CA default handlers 1507c478bd9Sstevel@tonic-gate */ 1517c478bd9Sstevel@tonic-gate if (AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 1527c478bd9Sstevel@tonic-gate ACPI_ADR_SPACE_SYSTEM_MEMORY, 1537c478bd9Sstevel@tonic-gate ACPI_DEFAULT_HANDLER, NULL, NULL) != AE_OK) { 1547c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "!acpica: no default handler for" 1557c478bd9Sstevel@tonic-gate " system memory"); 1567c478bd9Sstevel@tonic-gate rv = AE_ERROR; 1577c478bd9Sstevel@tonic-gate } 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate if (AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 1607c478bd9Sstevel@tonic-gate ACPI_ADR_SPACE_SYSTEM_IO, 1617c478bd9Sstevel@tonic-gate ACPI_DEFAULT_HANDLER, NULL, NULL) != AE_OK) { 1627c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "!acpica: no default handler for" 1637c478bd9Sstevel@tonic-gate " system I/O"); 1647c478bd9Sstevel@tonic-gate rv = AE_ERROR; 1657c478bd9Sstevel@tonic-gate } 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate if (AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 1687c478bd9Sstevel@tonic-gate ACPI_ADR_SPACE_PCI_CONFIG, 1697c478bd9Sstevel@tonic-gate ACPI_DEFAULT_HANDLER, NULL, NULL) != AE_OK) { 1707c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "!acpica: no default handler for" 1717c478bd9Sstevel@tonic-gate " PCI Config"); 1727c478bd9Sstevel@tonic-gate rv = AE_ERROR; 1737c478bd9Sstevel@tonic-gate } 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate return (rv); 1777c478bd9Sstevel@tonic-gate } 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate /* 1807c478bd9Sstevel@tonic-gate * Find the BIOS date, and return TRUE if supplied 1817c478bd9Sstevel@tonic-gate * date is same or later than the BIOS date, or FALSE 1827c478bd9Sstevel@tonic-gate * if the BIOS date can't be fetched for any reason 1837c478bd9Sstevel@tonic-gate */ 1847c478bd9Sstevel@tonic-gate static int 1857c478bd9Sstevel@tonic-gate acpica_check_bios_date(int yy, int mm, int dd) 1867c478bd9Sstevel@tonic-gate { 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate char *datep; 1897c478bd9Sstevel@tonic-gate int bios_year, bios_month, bios_day; 1907c478bd9Sstevel@tonic-gate 191f2be5148Sszhou /* If firmware has no bios, skip the check */ 192f2be5148Sszhou if (ddi_prop_exists(DDI_DEV_T_ANY, ddi_root_node(), 0, "bios-free")) 193f2be5148Sszhou return (TRUE); 194f2be5148Sszhou 1957c478bd9Sstevel@tonic-gate /* 1967c478bd9Sstevel@tonic-gate * PC BIOSes contain a string in the form of 1977c478bd9Sstevel@tonic-gate * "mm/dd/yy" at absolute address 0xffff5, 1987c478bd9Sstevel@tonic-gate * where mm, dd and yy are all ASCII digits. 1997c478bd9Sstevel@tonic-gate * We map the string, pluck out the values, 2007c478bd9Sstevel@tonic-gate * and accept all BIOSes from 1 Jan 1999 on 2017c478bd9Sstevel@tonic-gate * as valid. 2027c478bd9Sstevel@tonic-gate */ 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate if ((int)AcpiOsMapMemory(0xffff5, 8, (void **) &datep) != AE_OK) 2057c478bd9Sstevel@tonic-gate return (FALSE); 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate /* year */ 2087c478bd9Sstevel@tonic-gate bios_year = ((int)(*(datep + 6) - '0') * 10) + (*(datep + 7) - '0'); 2097c478bd9Sstevel@tonic-gate /* month */ 2107c478bd9Sstevel@tonic-gate bios_month = ((int)(*datep - '0') * 10) + (*(datep + 1) - '0'); 2117c478bd9Sstevel@tonic-gate /* day */ 2127c478bd9Sstevel@tonic-gate bios_day = ((int)(*(datep + 3) - '0') * 10) + (*(datep + 4) - '0'); 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate AcpiOsUnmapMemory((void *) datep, 8); 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate if (bios_year < 0 || bios_year > 99 || bios_month < 0 || 2177c478bd9Sstevel@tonic-gate bios_month > 99 || bios_day < 0 || bios_day > 99) { 2187c478bd9Sstevel@tonic-gate /* non-digit chars in BIOS date */ 2197c478bd9Sstevel@tonic-gate return (FALSE); 2207c478bd9Sstevel@tonic-gate } 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate /* 2237c478bd9Sstevel@tonic-gate * Adjust for 2-digit year; note to grand-children: 2247c478bd9Sstevel@tonic-gate * need a new scheme before 2080 rolls around 2257c478bd9Sstevel@tonic-gate */ 2267c478bd9Sstevel@tonic-gate bios_year += (bios_year >= 80 && bios_year <= 99) ? 2277c478bd9Sstevel@tonic-gate 1900 : 2000; 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate if (bios_year < yy) 2307c478bd9Sstevel@tonic-gate return (FALSE); 2317c478bd9Sstevel@tonic-gate else if (bios_year > yy) 2327c478bd9Sstevel@tonic-gate return (TRUE); 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate if (bios_month < mm) 2357c478bd9Sstevel@tonic-gate return (FALSE); 2367c478bd9Sstevel@tonic-gate else if (bios_month > mm) 2377c478bd9Sstevel@tonic-gate return (TRUE); 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate if (bios_day < dd) 2407c478bd9Sstevel@tonic-gate return (FALSE); 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate return (TRUE); 2437c478bd9Sstevel@tonic-gate } 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate /* 2467c478bd9Sstevel@tonic-gate * Check for Metropolis systems with BIOSes older than 10/12/04 2477c478bd9Sstevel@tonic-gate * return TRUE if BIOS requires legacy mode, FALSE otherwise 2487c478bd9Sstevel@tonic-gate */ 2497c478bd9Sstevel@tonic-gate static int 2507c478bd9Sstevel@tonic-gate acpica_metro_old_bios() 2517c478bd9Sstevel@tonic-gate { 2527c478bd9Sstevel@tonic-gate ACPI_TABLE_HEADER *fadt; 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate /* get the FADT */ 2557c478bd9Sstevel@tonic-gate if (AcpiGetFirmwareTable(FADT_SIG, 1, ACPI_LOGICAL_ADDRESSING, 2567c478bd9Sstevel@tonic-gate (ACPI_TABLE_HEADER **)&fadt) != AE_OK) 2577c478bd9Sstevel@tonic-gate return (FALSE); 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate /* compare OEM Table ID to "SUNmetro" - no match, return false */ 2607c478bd9Sstevel@tonic-gate if (strncmp("SUNmetro", fadt->OemTableId, 8)) 2617c478bd9Sstevel@tonic-gate return (FALSE); 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate /* On a Metro - return FALSE if later than 10/12/04 */ 2647c478bd9Sstevel@tonic-gate return (!acpica_check_bios_date(2004, 10, 12)); 2657c478bd9Sstevel@tonic-gate } 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate /* 2697c478bd9Sstevel@tonic-gate * Process acpi-user-options property if present 2707c478bd9Sstevel@tonic-gate */ 2717c478bd9Sstevel@tonic-gate static void 2727c478bd9Sstevel@tonic-gate acpica_process_user_options() 2737c478bd9Sstevel@tonic-gate { 2747c478bd9Sstevel@tonic-gate static int processed = 0; 2757c478bd9Sstevel@tonic-gate int acpi_user_options; 2767c478bd9Sstevel@tonic-gate char *acpi_prop; 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate /* 2797c478bd9Sstevel@tonic-gate * return if acpi-user-options has already been processed 2807c478bd9Sstevel@tonic-gate */ 2817c478bd9Sstevel@tonic-gate if (processed) 2827c478bd9Sstevel@tonic-gate return; 2837c478bd9Sstevel@tonic-gate else 2847c478bd9Sstevel@tonic-gate processed = 1; 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate /* converts acpi-user-options from type string to int, if any */ 2877c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 2887c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "acpi-user-options", &acpi_prop) == 2897c478bd9Sstevel@tonic-gate DDI_PROP_SUCCESS) { 2907c478bd9Sstevel@tonic-gate long data; 2917c478bd9Sstevel@tonic-gate int ret; 2927c478bd9Sstevel@tonic-gate ret = ddi_strtol(acpi_prop, NULL, 0, &data); 2937c478bd9Sstevel@tonic-gate if (ret == 0) { 2947c478bd9Sstevel@tonic-gate e_ddi_prop_remove(DDI_DEV_T_NONE, ddi_root_node(), 2957c478bd9Sstevel@tonic-gate "acpi-user-options"); 296f7534bc1Ssmall e_ddi_prop_update_int(DDI_DEV_T_NONE, ddi_root_node(), 297f7534bc1Ssmall "acpi-user-options", data); 2987c478bd9Sstevel@tonic-gate } 2997c478bd9Sstevel@tonic-gate ddi_prop_free(acpi_prop); 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate /* 3037c478bd9Sstevel@tonic-gate * fetch the optional options property 3047c478bd9Sstevel@tonic-gate */ 3057c478bd9Sstevel@tonic-gate acpi_user_options = ddi_prop_get_int(DDI_DEV_T_ANY, ddi_root_node(), 0, 3067c478bd9Sstevel@tonic-gate "acpi-user-options", 0); 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate /* 3097c478bd9Sstevel@tonic-gate * Note that 'off' has precedence over 'on' 3107c478bd9Sstevel@tonic-gate * Also note - all cases of ACPI_OUSER_MASK 3117c478bd9Sstevel@tonic-gate * provided here, no default: case is present 3127c478bd9Sstevel@tonic-gate */ 3137c478bd9Sstevel@tonic-gate switch (acpi_user_options & ACPI_OUSER_MASK) { 3147c478bd9Sstevel@tonic-gate case ACPI_OUSER_DFLT: 3157c478bd9Sstevel@tonic-gate acpica_enable = acpica_check_bios_date(1999, 1, 1); 3167c478bd9Sstevel@tonic-gate break; 3177c478bd9Sstevel@tonic-gate case ACPI_OUSER_ON: 3187c478bd9Sstevel@tonic-gate acpica_enable = TRUE; 3197c478bd9Sstevel@tonic-gate break; 3207c478bd9Sstevel@tonic-gate case ACPI_OUSER_OFF: 3217c478bd9Sstevel@tonic-gate case ACPI_OUSER_OFF | ACPI_OUSER_ON: 3227c478bd9Sstevel@tonic-gate acpica_enable = FALSE; 3237c478bd9Sstevel@tonic-gate break; 3247c478bd9Sstevel@tonic-gate } 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate acpi_init_level = ACPI_FULL_INITIALIZATION; 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate /* 3297c478bd9Sstevel@tonic-gate * special test here; may be generalized in the 3307c478bd9Sstevel@tonic-gate * future - test for a machines that are known to 3317c478bd9Sstevel@tonic-gate * work only in legacy mode, and set OUSER_LEGACY if 3327c478bd9Sstevel@tonic-gate * we're on one 3337c478bd9Sstevel@tonic-gate */ 3347c478bd9Sstevel@tonic-gate if (acpica_metro_old_bios()) 3357c478bd9Sstevel@tonic-gate acpi_user_options |= ACPI_OUSER_LEGACY; 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate /* 3387c478bd9Sstevel@tonic-gate * If legacy mode is specified, set initialization 3397c478bd9Sstevel@tonic-gate * options to avoid entering ACPI mode and hooking SCI 3407c478bd9Sstevel@tonic-gate * - basically try to act like legacy acpi_intp 3417c478bd9Sstevel@tonic-gate */ 3427c478bd9Sstevel@tonic-gate if ((acpi_user_options & ACPI_OUSER_LEGACY) != 0) 3437c478bd9Sstevel@tonic-gate acpi_init_level |= (ACPI_NO_ACPI_ENABLE | ACPI_NO_HANDLER_INIT); 3443d50435fSmyers 3453d50435fSmyers /* 3463d50435fSmyers * modify default ACPI CA debug output level for non-DEBUG builds 3473d50435fSmyers * (to avoid BIOS debug chatter in /var/adm/messages) 3483d50435fSmyers */ 3493d50435fSmyers if (acpica_muzzle_debug_output) 3503d50435fSmyers AcpiDbgLevel = 0; 3517c478bd9Sstevel@tonic-gate } 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate /* 3547c478bd9Sstevel@tonic-gate * Initialize the CA subsystem if it hasn't been done already 3557c478bd9Sstevel@tonic-gate */ 3567c478bd9Sstevel@tonic-gate int 3577c478bd9Sstevel@tonic-gate acpica_init() 3587c478bd9Sstevel@tonic-gate { 3597c478bd9Sstevel@tonic-gate ACPI_STATUS status; 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate /* 3627c478bd9Sstevel@tonic-gate * Make sure user options are processed, 3637c478bd9Sstevel@tonic-gate * then fail to initialize if ACPI CA has been 3647c478bd9Sstevel@tonic-gate * disabled 3657c478bd9Sstevel@tonic-gate */ 3667c478bd9Sstevel@tonic-gate acpica_process_user_options(); 3677c478bd9Sstevel@tonic-gate if (!acpica_enable) 3687c478bd9Sstevel@tonic-gate return (AE_ERROR); 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate mutex_enter(&acpica_module_lock); 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate if (acpica_init_state == ACPICA_NOT_INITIALIZED) { 3737c478bd9Sstevel@tonic-gate if ((status = AcpiLoadTables()) != AE_OK) { 3747c478bd9Sstevel@tonic-gate goto error; 3757c478bd9Sstevel@tonic-gate } 3767c478bd9Sstevel@tonic-gate if ((status = acpica_install_handlers()) != AE_OK) { 3777c478bd9Sstevel@tonic-gate goto error; 3787c478bd9Sstevel@tonic-gate } 3797c478bd9Sstevel@tonic-gate if ((status = AcpiEnableSubsystem(acpi_init_level)) != AE_OK) { 3807c478bd9Sstevel@tonic-gate goto error; 3817c478bd9Sstevel@tonic-gate } 3827c478bd9Sstevel@tonic-gate if ((status = AcpiInitializeObjects(0)) != AE_OK) { 3837c478bd9Sstevel@tonic-gate goto error; 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate /* 3867c478bd9Sstevel@tonic-gate * Initialize EC 3877c478bd9Sstevel@tonic-gate */ 3887c478bd9Sstevel@tonic-gate acpica_ec_init(); 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate acpica_init_state = ACPICA_INITIALIZED; 3917c478bd9Sstevel@tonic-gate error: 3927c478bd9Sstevel@tonic-gate if (acpica_init_state != ACPICA_INITIALIZED) { 3937c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "!failed to initialize" 3947c478bd9Sstevel@tonic-gate " ACPI services"); 3957c478bd9Sstevel@tonic-gate } 3967c478bd9Sstevel@tonic-gate } else 3977c478bd9Sstevel@tonic-gate status = AE_OK; 3987c478bd9Sstevel@tonic-gate 399f7534bc1Ssmall /* 400f7534bc1Ssmall * Set acpi-status to 13 if acpica has been initialized successfully. 401f7534bc1Ssmall * This indicates that acpica is up and running. This variable name 402f7534bc1Ssmall * and value were chosen in order to remain compatible with acpi_intp. 403f7534bc1Ssmall */ 404f7534bc1Ssmall e_ddi_prop_update_int(DDI_DEV_T_NONE, ddi_root_node(), "acpi-status", 405*87bb58d6Smyers (status == AE_OK) ? (ACPI_BOOT_INIT | ACPI_BOOT_ENABLE | 406*87bb58d6Smyers ACPI_BOOT_BOOTCONF) : 0); 407f7534bc1Ssmall 4087c478bd9Sstevel@tonic-gate mutex_exit(&acpica_module_lock); 4097c478bd9Sstevel@tonic-gate return (status); 4107c478bd9Sstevel@tonic-gate } 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate /* 4137c478bd9Sstevel@tonic-gate * SCI handling 4147c478bd9Sstevel@tonic-gate */ 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate ACPI_STATUS 4177c478bd9Sstevel@tonic-gate acpica_get_sci(int *sci_irq, iflag_t *sci_flags) 4187c478bd9Sstevel@tonic-gate { 4197c478bd9Sstevel@tonic-gate APIC_HEADER *ap; 4207c478bd9Sstevel@tonic-gate MULTIPLE_APIC_TABLE *mat; 4217c478bd9Sstevel@tonic-gate MADT_INTERRUPT_OVERRIDE *mio; 4227c478bd9Sstevel@tonic-gate FADT_DESCRIPTOR *fadt; 4237c478bd9Sstevel@tonic-gate int madt_seen, madt_size; 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate /* 4277c478bd9Sstevel@tonic-gate * Make sure user options are processed, 4287c478bd9Sstevel@tonic-gate * then return error if ACPI CA has been 4297c478bd9Sstevel@tonic-gate * disabled or system is not running in ACPI 4307c478bd9Sstevel@tonic-gate * and won't need/understand SCI 4317c478bd9Sstevel@tonic-gate */ 4327c478bd9Sstevel@tonic-gate acpica_process_user_options(); 4337c478bd9Sstevel@tonic-gate if ((!acpica_enable) || (acpi_init_level & ACPI_NO_ACPI_ENABLE)) 4347c478bd9Sstevel@tonic-gate return (AE_ERROR); 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate /* 4377c478bd9Sstevel@tonic-gate * according to Intel ACPI developers, SCI 4387c478bd9Sstevel@tonic-gate * conforms to PCI bus conventions; level/low 4397c478bd9Sstevel@tonic-gate * unless otherwise directed by overrides. 4407c478bd9Sstevel@tonic-gate */ 4417c478bd9Sstevel@tonic-gate sci_flags->intr_el = INTR_EL_LEVEL; 4427c478bd9Sstevel@tonic-gate sci_flags->intr_po = INTR_PO_ACTIVE_LOW; 4437c478bd9Sstevel@tonic-gate sci_flags->bustype = BUS_PCI; /* we *do* conform to PCI */ 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate /* get the SCI from the FADT */ 4467c478bd9Sstevel@tonic-gate if (AcpiGetFirmwareTable(FADT_SIG, 1, ACPI_LOGICAL_ADDRESSING, 4477c478bd9Sstevel@tonic-gate (ACPI_TABLE_HEADER **)&fadt) != AE_OK) 4487c478bd9Sstevel@tonic-gate return (AE_ERROR); 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate *sci_irq = fadt->SciInt; 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate /* search for ISOs that modify it */ 4537c478bd9Sstevel@tonic-gate /* if we don't find a MADT, that's OK; no ISOs then */ 4547c478bd9Sstevel@tonic-gate if (AcpiGetFirmwareTable(APIC_SIG, 1, ACPI_LOGICAL_ADDRESSING, 455*87bb58d6Smyers (ACPI_TABLE_HEADER **) &mat) != AE_OK) { 4567c478bd9Sstevel@tonic-gate return (AE_OK); 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate ap = (APIC_HEADER *) (mat + 1); 4607c478bd9Sstevel@tonic-gate madt_size = mat->Length; 4617c478bd9Sstevel@tonic-gate madt_seen = sizeof (*mat); 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate while (madt_seen < madt_size) { 4647c478bd9Sstevel@tonic-gate switch (ap->Type) { 4657c478bd9Sstevel@tonic-gate case APIC_XRUPT_OVERRIDE: 4667c478bd9Sstevel@tonic-gate mio = (MADT_INTERRUPT_OVERRIDE *) ap; 4677c478bd9Sstevel@tonic-gate if (mio->Source == *sci_irq) { 4687c478bd9Sstevel@tonic-gate *sci_irq = mio->Interrupt; 4697c478bd9Sstevel@tonic-gate sci_flags->intr_el = mio->TriggerMode; 4707c478bd9Sstevel@tonic-gate sci_flags->intr_po = mio->Polarity; 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate break; 4737c478bd9Sstevel@tonic-gate } 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate /* advance to next entry */ 4767c478bd9Sstevel@tonic-gate madt_seen += ap->Length; 4777c478bd9Sstevel@tonic-gate ap = (APIC_HEADER *)(((char *)ap) + ap->Length); 4787c478bd9Sstevel@tonic-gate } 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate /* 4817c478bd9Sstevel@tonic-gate * One more check; if ISO said "conform", revert to default 4827c478bd9Sstevel@tonic-gate */ 4837c478bd9Sstevel@tonic-gate if (sci_flags->intr_el == INTR_EL_CONFORM) 4847c478bd9Sstevel@tonic-gate sci_flags->intr_el = INTR_EL_LEVEL; 4857c478bd9Sstevel@tonic-gate if (sci_flags->intr_po == INTR_PO_CONFORM) 4867c478bd9Sstevel@tonic-gate sci_flags->intr_po = INTR_PO_ACTIVE_LOW; 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate return (AE_OK); 4897c478bd9Sstevel@tonic-gate } 490