xref: /illumos-gate/usr/src/uts/intel/io/acpica/acpica.c (revision a31148363f598def767ac48c5d82e1572e44b935)
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  */
25fa96bd91SMichael Corcoran /*
26fa96bd91SMichael Corcoran  * Copyright (c) 2009, Intel Corporation.
27fa96bd91SMichael Corcoran  * All rights reserved.
28fa96bd91SMichael Corcoran  */
298e56767dSsmall /*
308e56767dSsmall  * Solaris x86 ACPI CA services
318e56767dSsmall  */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <sys/file.h>
347c478bd9Sstevel@tonic-gate #include <sys/errno.h>
357c478bd9Sstevel@tonic-gate #include <sys/conf.h>
367c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
377c478bd9Sstevel@tonic-gate #include <sys/open.h>
387c478bd9Sstevel@tonic-gate #include <sys/stat.h>
39*a3114836SGerry Liu #include <sys/spl.h>
407c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
417c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
427c478bd9Sstevel@tonic-gate #include <sys/esunddi.h>
432df1fe9cSrandyf #include <sys/kstat.h>
44b9bfdccdSStuart Maybee #include <sys/x86_archext.h>
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #include <sys/acpi/acpi.h>
477c478bd9Sstevel@tonic-gate #include <sys/acpica.h>
484cf02d40SSaurabh Misra #include <sys/archsystm.h>
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate /*
517c478bd9Sstevel@tonic-gate  *
527c478bd9Sstevel@tonic-gate  */
537c478bd9Sstevel@tonic-gate static	struct modlmisc modlmisc = {
547c478bd9Sstevel@tonic-gate 	&mod_miscops,
5587bb58d6Smyers 	"ACPI interpreter",
567c478bd9Sstevel@tonic-gate };
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate static	struct modlinkage modlinkage = {
597c478bd9Sstevel@tonic-gate 	MODREV_1,		/* MODREV_1 manual */
607c478bd9Sstevel@tonic-gate 	(void *)&modlmisc,	/* module linkage */
617c478bd9Sstevel@tonic-gate 	NULL,			/* list terminator */
627c478bd9Sstevel@tonic-gate };
637c478bd9Sstevel@tonic-gate 
642df1fe9cSrandyf /*
652df1fe9cSrandyf  * Local prototypes
662df1fe9cSrandyf  */
672df1fe9cSrandyf 
682df1fe9cSrandyf static void	acpica_init_kstats(void);
692df1fe9cSrandyf 
707c478bd9Sstevel@tonic-gate /*
717c478bd9Sstevel@tonic-gate  * Local data
727c478bd9Sstevel@tonic-gate  */
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate static kmutex_t	acpica_module_lock;
752df1fe9cSrandyf static kstat_t	*acpica_ksp;
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate /*
787c478bd9Sstevel@tonic-gate  * State of acpica subsystem
797c478bd9Sstevel@tonic-gate  * After successful initialization, will be ACPICA_INITIALIZED
807c478bd9Sstevel@tonic-gate  */
817c478bd9Sstevel@tonic-gate int acpica_init_state = ACPICA_NOT_INITIALIZED;
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /*
847c478bd9Sstevel@tonic-gate  * Following are set by acpica_process_user_options()
857c478bd9Sstevel@tonic-gate  *
867c478bd9Sstevel@tonic-gate  * acpica_enable = FALSE prevents initialization of ACPI CA
877c478bd9Sstevel@tonic-gate  * completely
887c478bd9Sstevel@tonic-gate  *
897c478bd9Sstevel@tonic-gate  * acpi_init_level determines level of ACPI CA functionality
907c478bd9Sstevel@tonic-gate  * enabled in acpica_init()
917c478bd9Sstevel@tonic-gate  */
927c478bd9Sstevel@tonic-gate int	acpica_enable;
937c478bd9Sstevel@tonic-gate UINT32	acpi_init_level;
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate /*
967c478bd9Sstevel@tonic-gate  * Non-zero enables lax behavior with respect to some
977c478bd9Sstevel@tonic-gate  * common ACPI BIOS issues; see ACPI CA documentation
987c478bd9Sstevel@tonic-gate  * Setting this to zero causes ACPI CA to enforce strict
997c478bd9Sstevel@tonic-gate  * compliance with ACPI specification
1007c478bd9Sstevel@tonic-gate  */
1017c478bd9Sstevel@tonic-gate int acpica_enable_interpreter_slack = 1;
1027c478bd9Sstevel@tonic-gate 
1033d50435fSmyers /*
1043d50435fSmyers  * For non-DEBUG builds, set the ACPI CA debug level to 0
1053d50435fSmyers  * to quiet chatty BIOS output into /var/adm/messages
1063d50435fSmyers  * Field-patchable for diagnostic use.
1073d50435fSmyers  */
1083d50435fSmyers #ifdef  DEBUG
1093d50435fSmyers int acpica_muzzle_debug_output = 0;
1103d50435fSmyers #else
1113d50435fSmyers int acpica_muzzle_debug_output = 1;
1123d50435fSmyers #endif
1133d50435fSmyers 
1142df1fe9cSrandyf /*
1152df1fe9cSrandyf  * ACPI DDI hooks
1162df1fe9cSrandyf  */
1172df1fe9cSrandyf static int acpica_ddi_setwake(dev_info_t *dip, int level);
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate int
1207c478bd9Sstevel@tonic-gate _init(void)
1217c478bd9Sstevel@tonic-gate {
1227c478bd9Sstevel@tonic-gate 	int error = EBUSY;
1237c478bd9Sstevel@tonic-gate 	int	status;
1242df1fe9cSrandyf 	extern int (*acpi_fp_setwake)();
125*a3114836SGerry Liu 	extern kmutex_t cpu_map_lock;
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	mutex_init(&acpica_module_lock, NULL, MUTEX_DRIVER, NULL);
128*a3114836SGerry Liu 	mutex_init(&cpu_map_lock, NULL, MUTEX_SPIN,
129*a3114836SGerry Liu 	    (ddi_iblock_cookie_t)ipltospl(DISP_LEVEL));
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 	if ((error = mod_install(&modlinkage)) != 0) {
1327c478bd9Sstevel@tonic-gate 		mutex_destroy(&acpica_module_lock);
1332df1fe9cSrandyf 		goto load_error;
1347c478bd9Sstevel@tonic-gate 	}
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	AcpiGbl_EnableInterpreterSlack = (acpica_enable_interpreter_slack != 0);
1377c478bd9Sstevel@tonic-gate 
138c1381f44SDana Myers 	/* global ACPI CA initialization */
139c1381f44SDana Myers 	if (ACPI_FAILURE(status = AcpiInitializeSubsystem()))
140c1381f44SDana Myers 		cmn_err(CE_WARN, "!AcpiInitializeSubsystem failed: %d", status);
141c1381f44SDana Myers 
142c1381f44SDana Myers 	/* initialize table manager */
143c1381f44SDana Myers 	if (ACPI_FAILURE(status = AcpiInitializeTables(NULL, 0, 0)))
144c1381f44SDana Myers 		cmn_err(CE_WARN, "!AcpiInitializeTables failed: %d", status);
1457c478bd9Sstevel@tonic-gate 
1462df1fe9cSrandyf 	acpi_fp_setwake = acpica_ddi_setwake;
1472df1fe9cSrandyf 
1482df1fe9cSrandyf load_error:
1497c478bd9Sstevel@tonic-gate 	return (error);
1507c478bd9Sstevel@tonic-gate }
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate int
1537c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
1547c478bd9Sstevel@tonic-gate {
1557c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate int
1597c478bd9Sstevel@tonic-gate _fini(void)
1607c478bd9Sstevel@tonic-gate {
161186507a7Smyers 	/*
162186507a7Smyers 	 * acpica module is never unloaded at run-time; there's always
163186507a7Smyers 	 * a PSM depending on it, at the very least
164186507a7Smyers 	 */
165186507a7Smyers 	return (EBUSY);
1667c478bd9Sstevel@tonic-gate }
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate /*
1697c478bd9Sstevel@tonic-gate  * Install acpica-provided address-space handlers
1707c478bd9Sstevel@tonic-gate  */
1717c478bd9Sstevel@tonic-gate static int
1727c478bd9Sstevel@tonic-gate acpica_install_handlers()
1737c478bd9Sstevel@tonic-gate {
1747c478bd9Sstevel@tonic-gate 	ACPI_STATUS	rv = AE_OK;
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	/*
1777c478bd9Sstevel@tonic-gate 	 * Install ACPI CA default handlers
1787c478bd9Sstevel@tonic-gate 	 */
1797c478bd9Sstevel@tonic-gate 	if (AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
1807c478bd9Sstevel@tonic-gate 	    ACPI_ADR_SPACE_SYSTEM_MEMORY,
1817c478bd9Sstevel@tonic-gate 	    ACPI_DEFAULT_HANDLER, NULL, NULL) != AE_OK) {
1827c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "!acpica: no default handler for"
1837c478bd9Sstevel@tonic-gate 		    " system memory");
1847c478bd9Sstevel@tonic-gate 		rv = AE_ERROR;
1857c478bd9Sstevel@tonic-gate 	}
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	if (AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
1887c478bd9Sstevel@tonic-gate 	    ACPI_ADR_SPACE_SYSTEM_IO,
1897c478bd9Sstevel@tonic-gate 	    ACPI_DEFAULT_HANDLER, NULL, NULL) != AE_OK) {
1907c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "!acpica: no default handler for"
1917c478bd9Sstevel@tonic-gate 		    " system I/O");
1927c478bd9Sstevel@tonic-gate 		rv = AE_ERROR;
1937c478bd9Sstevel@tonic-gate 	}
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 	if (AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
1967c478bd9Sstevel@tonic-gate 	    ACPI_ADR_SPACE_PCI_CONFIG,
1977c478bd9Sstevel@tonic-gate 	    ACPI_DEFAULT_HANDLER, NULL, NULL) != AE_OK) {
1987c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "!acpica: no default handler for"
1997c478bd9Sstevel@tonic-gate 		    " PCI Config");
2007c478bd9Sstevel@tonic-gate 		rv = AE_ERROR;
2017c478bd9Sstevel@tonic-gate 	}
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	return (rv);
2057c478bd9Sstevel@tonic-gate }
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate /*
2087c478bd9Sstevel@tonic-gate  * Find the BIOS date, and return TRUE if supplied
2097c478bd9Sstevel@tonic-gate  * date is same or later than the BIOS date, or FALSE
2107c478bd9Sstevel@tonic-gate  * if the BIOS date can't be fetched for any reason
2117c478bd9Sstevel@tonic-gate  */
2127c478bd9Sstevel@tonic-gate static int
2137c478bd9Sstevel@tonic-gate acpica_check_bios_date(int yy, int mm, int dd)
2147c478bd9Sstevel@tonic-gate {
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	char *datep;
2177c478bd9Sstevel@tonic-gate 	int bios_year, bios_month, bios_day;
2187c478bd9Sstevel@tonic-gate 
219f2be5148Sszhou 	/* If firmware has no bios, skip the check */
220fa96bd91SMichael Corcoran 	if (ddi_prop_exists(DDI_DEV_T_ANY, ddi_root_node(), DDI_PROP_DONTPASS,
221fa96bd91SMichael Corcoran 	    "bios-free"))
222f2be5148Sszhou 		return (TRUE);
223f2be5148Sszhou 
2247c478bd9Sstevel@tonic-gate 	/*
2257c478bd9Sstevel@tonic-gate 	 * PC BIOSes contain a string in the form of
2267c478bd9Sstevel@tonic-gate 	 * "mm/dd/yy" at absolute address 0xffff5,
2277c478bd9Sstevel@tonic-gate 	 * where mm, dd and yy are all ASCII digits.
2287c478bd9Sstevel@tonic-gate 	 * We map the string, pluck out the values,
2297c478bd9Sstevel@tonic-gate 	 * and accept all BIOSes from 1 Jan 1999 on
2307c478bd9Sstevel@tonic-gate 	 * as valid.
2317c478bd9Sstevel@tonic-gate 	 */
2327c478bd9Sstevel@tonic-gate 
233db2bae30SDana Myers 	if ((datep = (char *)AcpiOsMapMemory(0xffff5, 8)) == NULL)
2347c478bd9Sstevel@tonic-gate 		return (FALSE);
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	/* year */
2377c478bd9Sstevel@tonic-gate 	bios_year = ((int)(*(datep + 6) - '0') * 10) + (*(datep + 7) - '0');
2387c478bd9Sstevel@tonic-gate 	/* month */
2397c478bd9Sstevel@tonic-gate 	bios_month = ((int)(*datep - '0') * 10) + (*(datep + 1) - '0');
2407c478bd9Sstevel@tonic-gate 	/* day */
2417c478bd9Sstevel@tonic-gate 	bios_day = ((int)(*(datep + 3) - '0') * 10) + (*(datep + 4) - '0');
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	AcpiOsUnmapMemory((void *) datep, 8);
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	if (bios_year < 0 || bios_year > 99 || bios_month < 0 ||
2467c478bd9Sstevel@tonic-gate 	    bios_month > 99 || bios_day < 0 || bios_day > 99) {
2477c478bd9Sstevel@tonic-gate 		/* non-digit chars in BIOS date */
2487c478bd9Sstevel@tonic-gate 		return (FALSE);
2497c478bd9Sstevel@tonic-gate 	}
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	/*
2527c478bd9Sstevel@tonic-gate 	 * Adjust for 2-digit year; note to grand-children:
2537c478bd9Sstevel@tonic-gate 	 * need a new scheme before 2080 rolls around
2547c478bd9Sstevel@tonic-gate 	 */
2557c478bd9Sstevel@tonic-gate 	bios_year += (bios_year >= 80 && bios_year <= 99) ?
2567c478bd9Sstevel@tonic-gate 	    1900 : 2000;
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	if (bios_year < yy)
2597c478bd9Sstevel@tonic-gate 		return (FALSE);
2607c478bd9Sstevel@tonic-gate 	else if (bios_year > yy)
2617c478bd9Sstevel@tonic-gate 		return (TRUE);
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	if (bios_month < mm)
2647c478bd9Sstevel@tonic-gate 		return (FALSE);
2657c478bd9Sstevel@tonic-gate 	else if (bios_month > mm)
2667c478bd9Sstevel@tonic-gate 		return (TRUE);
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	if (bios_day < dd)
2697c478bd9Sstevel@tonic-gate 		return (FALSE);
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	return (TRUE);
2727c478bd9Sstevel@tonic-gate }
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate /*
2757c478bd9Sstevel@tonic-gate  * Check for Metropolis systems with BIOSes older than 10/12/04
2767c478bd9Sstevel@tonic-gate  * return TRUE if BIOS requires legacy mode, FALSE otherwise
2777c478bd9Sstevel@tonic-gate  */
2787c478bd9Sstevel@tonic-gate static int
2797c478bd9Sstevel@tonic-gate acpica_metro_old_bios()
2807c478bd9Sstevel@tonic-gate {
2817c478bd9Sstevel@tonic-gate 	ACPI_TABLE_HEADER *fadt;
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	/* get the FADT */
284db2bae30SDana Myers 	if (AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **)&fadt) !=
285db2bae30SDana Myers 	    AE_OK)
2867c478bd9Sstevel@tonic-gate 		return (FALSE);
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	/* compare OEM Table ID to "SUNmetro" - no match, return false */
2897c478bd9Sstevel@tonic-gate 	if (strncmp("SUNmetro", fadt->OemTableId, 8))
2907c478bd9Sstevel@tonic-gate 		return (FALSE);
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	/* On a Metro - return FALSE if later than 10/12/04 */
2937c478bd9Sstevel@tonic-gate 	return (!acpica_check_bios_date(2004, 10, 12));
2947c478bd9Sstevel@tonic-gate }
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate /*
2987c478bd9Sstevel@tonic-gate  * Process acpi-user-options property  if present
2997c478bd9Sstevel@tonic-gate  */
3007c478bd9Sstevel@tonic-gate static void
3017c478bd9Sstevel@tonic-gate acpica_process_user_options()
3027c478bd9Sstevel@tonic-gate {
3037c478bd9Sstevel@tonic-gate 	static int processed = 0;
3047c478bd9Sstevel@tonic-gate 	int acpi_user_options;
3057c478bd9Sstevel@tonic-gate 	char *acpi_prop;
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	/*
3087c478bd9Sstevel@tonic-gate 	 * return if acpi-user-options has already been processed
3097c478bd9Sstevel@tonic-gate 	 */
3107c478bd9Sstevel@tonic-gate 	if (processed)
3117c478bd9Sstevel@tonic-gate 		return;
3127c478bd9Sstevel@tonic-gate 	else
3137c478bd9Sstevel@tonic-gate 		processed = 1;
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	/* converts acpi-user-options from type string to int, if any */
3167c478bd9Sstevel@tonic-gate 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
3177c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "acpi-user-options", &acpi_prop) ==
3187c478bd9Sstevel@tonic-gate 	    DDI_PROP_SUCCESS) {
3197c478bd9Sstevel@tonic-gate 		long data;
3207c478bd9Sstevel@tonic-gate 		int ret;
3217c478bd9Sstevel@tonic-gate 		ret = ddi_strtol(acpi_prop, NULL, 0, &data);
3227c478bd9Sstevel@tonic-gate 		if (ret == 0) {
3237c478bd9Sstevel@tonic-gate 			e_ddi_prop_remove(DDI_DEV_T_NONE, ddi_root_node(),
3247c478bd9Sstevel@tonic-gate 			    "acpi-user-options");
325f7534bc1Ssmall 			e_ddi_prop_update_int(DDI_DEV_T_NONE, ddi_root_node(),
326f7534bc1Ssmall 			    "acpi-user-options", data);
3277c478bd9Sstevel@tonic-gate 		}
3287c478bd9Sstevel@tonic-gate 		ddi_prop_free(acpi_prop);
3297c478bd9Sstevel@tonic-gate 	}
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	/*
3327c478bd9Sstevel@tonic-gate 	 * fetch the optional options property
3337c478bd9Sstevel@tonic-gate 	 */
334fa96bd91SMichael Corcoran 	acpi_user_options = ddi_prop_get_int(DDI_DEV_T_ANY, ddi_root_node(),
335fa96bd91SMichael Corcoran 	    DDI_PROP_DONTPASS, "acpi-user-options", 0);
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	/*
3387c478bd9Sstevel@tonic-gate 	 * Note that 'off' has precedence over 'on'
3397c478bd9Sstevel@tonic-gate 	 * Also note - all cases of ACPI_OUSER_MASK
3407c478bd9Sstevel@tonic-gate 	 * provided here, no default: case is present
3417c478bd9Sstevel@tonic-gate 	 */
3427c478bd9Sstevel@tonic-gate 	switch (acpi_user_options & ACPI_OUSER_MASK) {
3437c478bd9Sstevel@tonic-gate 	case ACPI_OUSER_DFLT:
3447c478bd9Sstevel@tonic-gate 		acpica_enable = acpica_check_bios_date(1999, 1, 1);
3457c478bd9Sstevel@tonic-gate 		break;
3467c478bd9Sstevel@tonic-gate 	case ACPI_OUSER_ON:
3477c478bd9Sstevel@tonic-gate 		acpica_enable = TRUE;
3487c478bd9Sstevel@tonic-gate 		break;
3497c478bd9Sstevel@tonic-gate 	case ACPI_OUSER_OFF:
3507c478bd9Sstevel@tonic-gate 	case ACPI_OUSER_OFF | ACPI_OUSER_ON:
3517c478bd9Sstevel@tonic-gate 		acpica_enable = FALSE;
3527c478bd9Sstevel@tonic-gate 		break;
3537c478bd9Sstevel@tonic-gate 	}
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	acpi_init_level = ACPI_FULL_INITIALIZATION;
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	/*
3587c478bd9Sstevel@tonic-gate 	 * special test here; may be generalized in the
3597c478bd9Sstevel@tonic-gate 	 * future - test for a machines that are known to
3607c478bd9Sstevel@tonic-gate 	 * work only in legacy mode, and set OUSER_LEGACY if
3617c478bd9Sstevel@tonic-gate 	 * we're on one
3627c478bd9Sstevel@tonic-gate 	 */
3637c478bd9Sstevel@tonic-gate 	if (acpica_metro_old_bios())
3647c478bd9Sstevel@tonic-gate 		acpi_user_options |= ACPI_OUSER_LEGACY;
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	/*
3677c478bd9Sstevel@tonic-gate 	 * If legacy mode is specified, set initialization
3687c478bd9Sstevel@tonic-gate 	 * options to avoid entering ACPI mode and hooking SCI
3697c478bd9Sstevel@tonic-gate 	 * - basically try to act like legacy acpi_intp
3707c478bd9Sstevel@tonic-gate 	 */
3717c478bd9Sstevel@tonic-gate 	if ((acpi_user_options & ACPI_OUSER_LEGACY) != 0)
3727c478bd9Sstevel@tonic-gate 		acpi_init_level |= (ACPI_NO_ACPI_ENABLE | ACPI_NO_HANDLER_INIT);
3733d50435fSmyers 
3743d50435fSmyers 	/*
3753d50435fSmyers 	 * modify default ACPI CA debug output level for non-DEBUG builds
3763d50435fSmyers 	 * (to avoid BIOS debug chatter in /var/adm/messages)
3773d50435fSmyers 	 */
3783d50435fSmyers 	if (acpica_muzzle_debug_output)
3793d50435fSmyers 		AcpiDbgLevel = 0;
3807c478bd9Sstevel@tonic-gate }
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate /*
3837c478bd9Sstevel@tonic-gate  * Initialize the CA subsystem if it hasn't been done already
3847c478bd9Sstevel@tonic-gate  */
3857c478bd9Sstevel@tonic-gate int
3867c478bd9Sstevel@tonic-gate acpica_init()
3877c478bd9Sstevel@tonic-gate {
388b9bfdccdSStuart Maybee 	extern void acpica_find_ioapics(void);
3897c478bd9Sstevel@tonic-gate 	ACPI_STATUS status;
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	/*
3927c478bd9Sstevel@tonic-gate 	 * Make sure user options are processed,
3937c478bd9Sstevel@tonic-gate 	 * then fail to initialize if ACPI CA has been
3947c478bd9Sstevel@tonic-gate 	 * disabled
3957c478bd9Sstevel@tonic-gate 	 */
3967c478bd9Sstevel@tonic-gate 	acpica_process_user_options();
3977c478bd9Sstevel@tonic-gate 	if (!acpica_enable)
3987c478bd9Sstevel@tonic-gate 		return (AE_ERROR);
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	mutex_enter(&acpica_module_lock);
401fa96bd91SMichael Corcoran 	if (acpica_init_state == ACPICA_INITIALIZED) {
402fa96bd91SMichael Corcoran 		mutex_exit(&acpica_module_lock);
403fa96bd91SMichael Corcoran 		return (AE_OK);
404fa96bd91SMichael Corcoran 	}
4057c478bd9Sstevel@tonic-gate 
406fa96bd91SMichael Corcoran 	if (ACPI_FAILURE(status = AcpiLoadTables()))
407fa96bd91SMichael Corcoran 		goto error;
408db2bae30SDana Myers 
409fa96bd91SMichael Corcoran 	if (ACPI_FAILURE(status = acpica_install_handlers()))
410fa96bd91SMichael Corcoran 		goto error;
411db2bae30SDana Myers 
4125f68fde5SDana Myers 	/*
4135f68fde5SDana Myers 	 * Create ACPI-to-devinfo mapping now so _INI and _STA
4145f68fde5SDana Myers 	 * methods can access PCI config space when needed
4155f68fde5SDana Myers 	 */
4165f68fde5SDana Myers 	scan_d2a_map();
4175f68fde5SDana Myers 
418fa96bd91SMichael Corcoran 	if (ACPI_FAILURE(status = AcpiEnableSubsystem(acpi_init_level)))
419fa96bd91SMichael Corcoran 		goto error;
420db2bae30SDana Myers 
421fa96bd91SMichael Corcoran 	/* do after AcpiEnableSubsystem() so GPEs are initialized */
422fa96bd91SMichael Corcoran 	acpica_ec_init();	/* initialize EC if present */
423c1381f44SDana Myers 
424fa96bd91SMichael Corcoran 	if (ACPI_FAILURE(status = AcpiInitializeObjects(0)))
425fa96bd91SMichael Corcoran 		goto error;
426db2bae30SDana Myers 
427fa96bd91SMichael Corcoran 	acpica_init_state = ACPICA_INITIALIZED;
428fa96bd91SMichael Corcoran 
429fa96bd91SMichael Corcoran 	/*
430fa96bd91SMichael Corcoran 	 * If we are running on the Xen hypervisor as dom0 we need to
431fa96bd91SMichael Corcoran 	 * find the ioapics so we can prevent ACPI from trying to
432fa96bd91SMichael Corcoran 	 * access them.
433fa96bd91SMichael Corcoran 	 */
434fa96bd91SMichael Corcoran 	if (get_hwenv() == HW_XEN_PV && is_controldom())
435fa96bd91SMichael Corcoran 		acpica_find_ioapics();
436fa96bd91SMichael Corcoran 	acpica_init_kstats();
4377c478bd9Sstevel@tonic-gate error:
438fa96bd91SMichael Corcoran 	if (acpica_init_state != ACPICA_INITIALIZED) {
439fa96bd91SMichael Corcoran 		cmn_err(CE_NOTE, "!failed to initialize ACPI services");
440fa96bd91SMichael Corcoran 	}
4417c478bd9Sstevel@tonic-gate 
442f7534bc1Ssmall 	/*
443f7534bc1Ssmall 	 * Set acpi-status to 13 if acpica has been initialized successfully.
444f7534bc1Ssmall 	 * This indicates that acpica is up and running.  This variable name
445f7534bc1Ssmall 	 * and value were chosen in order to remain compatible with acpi_intp.
446f7534bc1Ssmall 	 */
447f7534bc1Ssmall 	e_ddi_prop_update_int(DDI_DEV_T_NONE, ddi_root_node(), "acpi-status",
448fa96bd91SMichael Corcoran 	    (ACPI_SUCCESS(status)) ? (ACPI_BOOT_INIT | ACPI_BOOT_ENABLE |
44987bb58d6Smyers 	    ACPI_BOOT_BOOTCONF) : 0);
450f7534bc1Ssmall 
451fa96bd91SMichael Corcoran 	/* Mark acpica subsystem as fully initialized. */
452fa96bd91SMichael Corcoran 	if (ACPI_SUCCESS(status) &&
453fa96bd91SMichael Corcoran 	    acpi_init_level == ACPI_FULL_INITIALIZATION) {
454fa96bd91SMichael Corcoran 		acpica_set_core_feature(ACPI_FEATURE_FULL_INIT);
455fa96bd91SMichael Corcoran 	}
456fa96bd91SMichael Corcoran 
4577c478bd9Sstevel@tonic-gate 	mutex_exit(&acpica_module_lock);
4587c478bd9Sstevel@tonic-gate 	return (status);
4597c478bd9Sstevel@tonic-gate }
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate /*
4627c478bd9Sstevel@tonic-gate  * SCI handling
4637c478bd9Sstevel@tonic-gate  */
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate ACPI_STATUS
4667c478bd9Sstevel@tonic-gate acpica_get_sci(int *sci_irq, iflag_t *sci_flags)
4677c478bd9Sstevel@tonic-gate {
468db2bae30SDana Myers 	ACPI_SUBTABLE_HEADER		*ap;
469db2bae30SDana Myers 	ACPI_TABLE_MADT			*mat;
470db2bae30SDana Myers 	ACPI_MADT_INTERRUPT_OVERRIDE	*mio;
471db2bae30SDana Myers 	ACPI_TABLE_FADT			*fadt;
4727c478bd9Sstevel@tonic-gate 	int			madt_seen, madt_size;
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	/*
4767c478bd9Sstevel@tonic-gate 	 * Make sure user options are processed,
4777c478bd9Sstevel@tonic-gate 	 * then return error if ACPI CA has been
4787c478bd9Sstevel@tonic-gate 	 * disabled or system is not running in ACPI
4797c478bd9Sstevel@tonic-gate 	 * and won't need/understand SCI
4807c478bd9Sstevel@tonic-gate 	 */
4817c478bd9Sstevel@tonic-gate 	acpica_process_user_options();
4827c478bd9Sstevel@tonic-gate 	if ((!acpica_enable) || (acpi_init_level & ACPI_NO_ACPI_ENABLE))
4837c478bd9Sstevel@tonic-gate 		return (AE_ERROR);
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	/*
4867c478bd9Sstevel@tonic-gate 	 * according to Intel ACPI developers, SCI
4877c478bd9Sstevel@tonic-gate 	 * conforms to PCI bus conventions; level/low
4887c478bd9Sstevel@tonic-gate 	 * unless otherwise directed by overrides.
4897c478bd9Sstevel@tonic-gate 	 */
4907c478bd9Sstevel@tonic-gate 	sci_flags->intr_el = INTR_EL_LEVEL;
4917c478bd9Sstevel@tonic-gate 	sci_flags->intr_po = INTR_PO_ACTIVE_LOW;
4927c478bd9Sstevel@tonic-gate 	sci_flags->bustype = BUS_PCI;	/*  we *do* conform to PCI */
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 	/* get the SCI from the FADT */
495db2bae30SDana Myers 	if (AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **)&fadt) !=
496db2bae30SDana Myers 	    AE_OK)
4977c478bd9Sstevel@tonic-gate 		return (AE_ERROR);
4987c478bd9Sstevel@tonic-gate 
499db2bae30SDana Myers 	*sci_irq = fadt->SciInterrupt;
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 	/* search for ISOs that modify it */
5027c478bd9Sstevel@tonic-gate 	/* if we don't find a MADT, that's OK; no ISOs then */
503db2bae30SDana Myers 	if (AcpiGetTable(ACPI_SIG_MADT, 1, (ACPI_TABLE_HEADER **) &mat) !=
504db2bae30SDana Myers 	    AE_OK)
5057c478bd9Sstevel@tonic-gate 		return (AE_OK);
5067c478bd9Sstevel@tonic-gate 
507db2bae30SDana Myers 	ap = (ACPI_SUBTABLE_HEADER *) (mat + 1);
508db2bae30SDana Myers 	madt_size = mat->Header.Length;
5097c478bd9Sstevel@tonic-gate 	madt_seen = sizeof (*mat);
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 	while (madt_seen < madt_size) {
5127c478bd9Sstevel@tonic-gate 		switch (ap->Type) {
513db2bae30SDana Myers 		case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE:
514db2bae30SDana Myers 			mio = (ACPI_MADT_INTERRUPT_OVERRIDE *) ap;
515db2bae30SDana Myers 			if (mio->SourceIrq == *sci_irq) {
516db2bae30SDana Myers 				*sci_irq = mio->GlobalIrq;
517db2bae30SDana Myers 				sci_flags->intr_el = (mio->IntiFlags &
518db2bae30SDana Myers 				    ACPI_MADT_TRIGGER_MASK) >> 2;
519db2bae30SDana Myers 				sci_flags->intr_po = mio->IntiFlags &
520db2bae30SDana Myers 				    ACPI_MADT_POLARITY_MASK;
5217c478bd9Sstevel@tonic-gate 			}
5227c478bd9Sstevel@tonic-gate 			break;
5237c478bd9Sstevel@tonic-gate 		}
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 		/* advance to next entry */
5267c478bd9Sstevel@tonic-gate 		madt_seen += ap->Length;
527db2bae30SDana Myers 		ap = (ACPI_SUBTABLE_HEADER *)(((char *)ap) + ap->Length);
5287c478bd9Sstevel@tonic-gate 	}
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 	/*
5317c478bd9Sstevel@tonic-gate 	 * One more check; if ISO said "conform", revert to default
5327c478bd9Sstevel@tonic-gate 	 */
5337c478bd9Sstevel@tonic-gate 	if (sci_flags->intr_el == INTR_EL_CONFORM)
5347c478bd9Sstevel@tonic-gate 		sci_flags->intr_el = INTR_EL_LEVEL;
5357c478bd9Sstevel@tonic-gate 	if (sci_flags->intr_po == INTR_PO_CONFORM)
5367c478bd9Sstevel@tonic-gate 		sci_flags->intr_po = INTR_PO_ACTIVE_LOW;
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 	return (AE_OK);
5397c478bd9Sstevel@tonic-gate }
5402df1fe9cSrandyf 
5412df1fe9cSrandyf /*
5422df1fe9cSrandyf  * Sets ACPI wake state for device referenced by dip.
5432df1fe9cSrandyf  * If level is S0 (0), disables wake event; otherwise,
5442df1fe9cSrandyf  * enables wake event which will wake system from level.
5452df1fe9cSrandyf  */
5462df1fe9cSrandyf static int
5472df1fe9cSrandyf acpica_ddi_setwake(dev_info_t *dip, int level)
5482df1fe9cSrandyf {
5492df1fe9cSrandyf 	ACPI_STATUS	status;
5502df1fe9cSrandyf 	ACPI_HANDLE	devobj, gpeobj;
5512df1fe9cSrandyf 	ACPI_OBJECT	*prw, *gpe;
5522df1fe9cSrandyf 	ACPI_BUFFER	prw_buf;
5532df1fe9cSrandyf 	int		gpebit, pwr_res_count, prw_level, rv;
5542df1fe9cSrandyf 
5552df1fe9cSrandyf 	/*
5562df1fe9cSrandyf 	 * initialize these early so we can use a common
5572df1fe9cSrandyf 	 * exit point below
5582df1fe9cSrandyf 	 */
5592df1fe9cSrandyf 	prw_buf.Pointer = NULL;
5602df1fe9cSrandyf 	prw_buf.Length = ACPI_ALLOCATE_BUFFER;
5612df1fe9cSrandyf 	rv = 0;
5622df1fe9cSrandyf 
5632df1fe9cSrandyf 	/*
5642df1fe9cSrandyf 	 * Attempt to get a handle to a corresponding ACPI object.
5652df1fe9cSrandyf 	 * If no object is found, return quietly, since not all
5662df1fe9cSrandyf 	 * devices have corresponding ACPI objects.
5672df1fe9cSrandyf 	 */
5682df1fe9cSrandyf 	status = acpica_get_handle(dip, &devobj);
5692df1fe9cSrandyf 	if (ACPI_FAILURE(status)) {
5702df1fe9cSrandyf 		char pathbuf[MAXPATHLEN];
5712df1fe9cSrandyf 		ddi_pathname(dip, pathbuf);
5722df1fe9cSrandyf #ifdef DEBUG
5732df1fe9cSrandyf 		cmn_err(CE_NOTE, "!acpica_ddi_setwake: could not get"
5742df1fe9cSrandyf 		    " handle for %s, %s:%d", pathbuf, ddi_driver_name(dip),
5752df1fe9cSrandyf 		    ddi_get_instance(dip));
5762df1fe9cSrandyf #endif
5772df1fe9cSrandyf 		goto done;
5782df1fe9cSrandyf 	}
5792df1fe9cSrandyf 
5802df1fe9cSrandyf 	/*
5812df1fe9cSrandyf 	 * Attempt to evaluate _PRW object.
5822df1fe9cSrandyf 	 * If no valid object is found, return quietly, since not all
5832df1fe9cSrandyf 	 * devices have _PRW objects.
5842df1fe9cSrandyf 	 */
5852df1fe9cSrandyf 	status = AcpiEvaluateObject(devobj, "_PRW", NULL, &prw_buf);
5862df1fe9cSrandyf 	prw = prw_buf.Pointer;
587db2bae30SDana Myers 	if (ACPI_FAILURE(status) || prw_buf.Length == 0 || prw == NULL ||
5882df1fe9cSrandyf 	    prw->Type != ACPI_TYPE_PACKAGE || prw->Package.Count < 2 ||
5892df1fe9cSrandyf 	    prw->Package.Elements[1].Type != ACPI_TYPE_INTEGER) {
5902df1fe9cSrandyf 		cmn_err(CE_NOTE, "acpica_ddi_setwake: could not "
5912df1fe9cSrandyf 		    " evaluate _PRW");
5922df1fe9cSrandyf 		goto done;
5932df1fe9cSrandyf 	}
5942df1fe9cSrandyf 
5952df1fe9cSrandyf 	/* fetch the lowest wake level from the _PRW */
5962df1fe9cSrandyf 	prw_level = prw->Package.Elements[1].Integer.Value;
5972df1fe9cSrandyf 
5982df1fe9cSrandyf 	/*
5992df1fe9cSrandyf 	 * process the GPE description
6002df1fe9cSrandyf 	 */
6012df1fe9cSrandyf 	switch (prw->Package.Elements[0].Type) {
6022df1fe9cSrandyf 	case ACPI_TYPE_INTEGER:
6032df1fe9cSrandyf 		gpeobj = NULL;
6042df1fe9cSrandyf 		gpebit = prw->Package.Elements[0].Integer.Value;
6052df1fe9cSrandyf 		break;
6062df1fe9cSrandyf 	case ACPI_TYPE_PACKAGE:
6072df1fe9cSrandyf 		gpe = &prw->Package.Elements[0];
6082df1fe9cSrandyf 		if (gpe->Package.Count != 2 ||
6092df1fe9cSrandyf 		    gpe->Package.Elements[1].Type != ACPI_TYPE_INTEGER)
6102df1fe9cSrandyf 			goto done;
6112df1fe9cSrandyf 		gpeobj = gpe->Package.Elements[0].Reference.Handle;
6122df1fe9cSrandyf 		gpebit = gpe->Package.Elements[1].Integer.Value;
6132df1fe9cSrandyf 		if (gpeobj == NULL)
6142df1fe9cSrandyf 			goto done;
6152df1fe9cSrandyf 	default:
6162df1fe9cSrandyf 		goto done;
6172df1fe9cSrandyf 	}
6182df1fe9cSrandyf 
6192df1fe9cSrandyf 	rv = -1;
6202df1fe9cSrandyf 	if (level == 0) {
6212df1fe9cSrandyf 		if (ACPI_FAILURE(AcpiDisableGpe(gpeobj, gpebit, ACPI_NOT_ISR)))
6222df1fe9cSrandyf 			goto done;
6232df1fe9cSrandyf 	} else if (prw_level <= level) {
6242df1fe9cSrandyf 		if (ACPI_SUCCESS(
6252df1fe9cSrandyf 		    AcpiSetGpeType(gpeobj, gpebit, ACPI_GPE_TYPE_WAKE)))
6262df1fe9cSrandyf 			if (ACPI_FAILURE(
6272df1fe9cSrandyf 			    AcpiEnableGpe(gpeobj, gpebit, ACPI_NOT_ISR)))
6282df1fe9cSrandyf 				goto done;
6292df1fe9cSrandyf 	}
6302df1fe9cSrandyf 	rv = 0;
6312df1fe9cSrandyf done:
6322df1fe9cSrandyf 	if (prw_buf.Pointer != NULL)
6332df1fe9cSrandyf 		AcpiOsFree(prw_buf.Pointer);
6342df1fe9cSrandyf 	return (rv);
6352df1fe9cSrandyf }
6362df1fe9cSrandyf 
6372df1fe9cSrandyf /*
6382df1fe9cSrandyf  * kstat access to a limited set of ACPI propertis
6392df1fe9cSrandyf  */
6402df1fe9cSrandyf static void
6412df1fe9cSrandyf acpica_init_kstats()
6422df1fe9cSrandyf {
6432df1fe9cSrandyf 	ACPI_HANDLE	s3handle;
6442df1fe9cSrandyf 	ACPI_STATUS	status;
645db2bae30SDana Myers 	ACPI_TABLE_FADT	*fadt;
6462df1fe9cSrandyf 	kstat_named_t *knp;
6472df1fe9cSrandyf 
6482df1fe9cSrandyf 	/*
6492df1fe9cSrandyf 	 * Create a small set of named kstats; just return in the rare
6502df1fe9cSrandyf 	 * case of a failure, * in which case, the kstats won't be present.
6512df1fe9cSrandyf 	 */
6522df1fe9cSrandyf 	if ((acpica_ksp = kstat_create("acpi", 0, "acpi", "misc",
6532df1fe9cSrandyf 	    KSTAT_TYPE_NAMED, 2, 0)) == NULL)
6542df1fe9cSrandyf 		return;
6552df1fe9cSrandyf 
6562df1fe9cSrandyf 	/*
6572df1fe9cSrandyf 	 * initialize kstat 'S3' to reflect the presence of \_S3 in
6582df1fe9cSrandyf 	 * the ACPI namespace (1 = present, 0 = not present)
6592df1fe9cSrandyf 	 */
6602df1fe9cSrandyf 	knp = acpica_ksp->ks_data;
6612df1fe9cSrandyf 	knp->value.l = (AcpiGetHandle(NULL, "\\_S3", &s3handle) == AE_OK);
6622df1fe9cSrandyf 	kstat_named_init(knp, "S3", KSTAT_DATA_LONG);
6632df1fe9cSrandyf 	knp++;		/* advance to next named kstat */
6642df1fe9cSrandyf 
6652df1fe9cSrandyf 	/*
6662df1fe9cSrandyf 	 * initialize kstat 'preferred_pm_profile' to the value
6672df1fe9cSrandyf 	 * contained in the (always present) FADT
6682df1fe9cSrandyf 	 */
669db2bae30SDana Myers 	status = AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **)&fadt);
670db2bae30SDana Myers 	knp->value.l = (status == AE_OK) ? fadt->PreferredProfile : -1;
6712df1fe9cSrandyf 	kstat_named_init(knp, "preferred_pm_profile", KSTAT_DATA_LONG);
6722df1fe9cSrandyf 
6732df1fe9cSrandyf 	/*
6742df1fe9cSrandyf 	 * install the named kstats
6752df1fe9cSrandyf 	 */
6762df1fe9cSrandyf 	kstat_install(acpica_ksp);
6772df1fe9cSrandyf }
6782df1fe9cSrandyf 
6792df1fe9cSrandyf /*
6802df1fe9cSrandyf  * Attempt to save the current ACPI settings (_CRS) for the device
6812df1fe9cSrandyf  * which corresponds to the supplied devinfo node.  The settings are
6822df1fe9cSrandyf  * saved as a property on the dip.  If no ACPI object is found to be
6832df1fe9cSrandyf  * associated with the devinfo node, no action is taken and no error
6842df1fe9cSrandyf  * is reported.
6852df1fe9cSrandyf  */
6862df1fe9cSrandyf void
6872df1fe9cSrandyf acpica_ddi_save_resources(dev_info_t *dip)
6882df1fe9cSrandyf {
6892df1fe9cSrandyf 	ACPI_HANDLE	devobj;
6902df1fe9cSrandyf 	ACPI_BUFFER	resbuf;
6912df1fe9cSrandyf 	int		ret;
6922df1fe9cSrandyf 
6932df1fe9cSrandyf 	resbuf.Length = ACPI_ALLOCATE_BUFFER;
6942df1fe9cSrandyf 	if (ACPI_FAILURE(acpica_get_handle(dip, &devobj)) ||
6952df1fe9cSrandyf 	    ACPI_FAILURE(AcpiGetCurrentResources(devobj, &resbuf)))
6962df1fe9cSrandyf 		return;
6972df1fe9cSrandyf 
6982df1fe9cSrandyf 	ret = ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
6992df1fe9cSrandyf 	    "acpi-crs", resbuf.Pointer, resbuf.Length);
7002df1fe9cSrandyf 
7012df1fe9cSrandyf 	ASSERT(ret == DDI_PROP_SUCCESS);
7022df1fe9cSrandyf 
7032df1fe9cSrandyf 	AcpiOsFree(resbuf.Pointer);
7042df1fe9cSrandyf }
7052df1fe9cSrandyf 
7062df1fe9cSrandyf /*
7072df1fe9cSrandyf  * If the supplied devinfo node has an ACPI settings property attached,
7082df1fe9cSrandyf  * restore them to the associated ACPI device using _SRS.  The property
7092df1fe9cSrandyf  * is deleted from the devinfo node afterward.
7102df1fe9cSrandyf  */
7112df1fe9cSrandyf void
7122df1fe9cSrandyf acpica_ddi_restore_resources(dev_info_t *dip)
7132df1fe9cSrandyf {
7142df1fe9cSrandyf 	ACPI_HANDLE	devobj;
7152df1fe9cSrandyf 	ACPI_BUFFER	resbuf;
7162df1fe9cSrandyf 	uchar_t		*propdata;
7172df1fe9cSrandyf 	uint_t		proplen;
7182df1fe9cSrandyf 
7192df1fe9cSrandyf 	if (ACPI_FAILURE(acpica_get_handle(dip, &devobj)))
7202df1fe9cSrandyf 		return;
7212df1fe9cSrandyf 
7222df1fe9cSrandyf 	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
7232df1fe9cSrandyf 	    "acpi-crs", &propdata, &proplen) != DDI_PROP_SUCCESS)
7242df1fe9cSrandyf 		return;
7252df1fe9cSrandyf 
7262df1fe9cSrandyf 	resbuf.Pointer = propdata;
7272df1fe9cSrandyf 	resbuf.Length = proplen;
7282df1fe9cSrandyf 	(void) AcpiSetCurrentResources(devobj, &resbuf);
7292df1fe9cSrandyf 	ddi_prop_free(propdata);
7300f1b305eSSeth Goldberg 	(void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "acpi-crs");
7312df1fe9cSrandyf }
7324cf02d40SSaurabh Misra 
7334cf02d40SSaurabh Misra void
7344cf02d40SSaurabh Misra acpi_reset_system(void)
7354cf02d40SSaurabh Misra {
7364cf02d40SSaurabh Misra 	ACPI_STATUS status;
7374cf02d40SSaurabh Misra 	int ten;
7384cf02d40SSaurabh Misra 
7394cf02d40SSaurabh Misra 	status = AcpiReset();
7404cf02d40SSaurabh Misra 	if (status == AE_OK) {
7414cf02d40SSaurabh Misra 		/*
7424cf02d40SSaurabh Misra 		 * Wait up to 500 milliseconds for AcpiReset() to make its
7434cf02d40SSaurabh Misra 		 * way.
7444cf02d40SSaurabh Misra 		 */
7454cf02d40SSaurabh Misra 		ten = 50000;
7464cf02d40SSaurabh Misra 		while (ten-- > 0)
7474cf02d40SSaurabh Misra 			tenmicrosec();
7484cf02d40SSaurabh Misra 	}
7494cf02d40SSaurabh Misra }
750