xref: /illumos-gate/usr/src/uts/intel/io/acpica/acpica.c (revision 87bb58d6e153df832c94baf659167ac8744b8f3a)
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