17c478bdstevel@tonic-gate/*
28e56767small * CDDL HEADER START
38e56767small *
48e56767small * The contents of this file are subject to the terms of the
53d50435myers * Common Development and Distribution License (the "License").
63d50435myers * You may not use this file except in compliance with the License.
78e56767small *
88e56767small * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98e56767small * or http://www.opensolaris.org/os/licensing.
108e56767small * See the License for the specific language governing permissions
118e56767small * and limitations under the License.
128e56767small *
138e56767small * When distributing Covered Code, include this CDDL HEADER in each
148e56767small * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158e56767small * If applicable, add the following below this CDDL HEADER, with the
168e56767small * fields enclosed by brackets "[]" replaced with your own identifying
178e56767small * information: Portions Copyright [yyyy] [name of copyright owner]
188e56767small *
198e56767small * CDDL HEADER END
207c478bdstevel@tonic-gate */
217c478bdstevel@tonic-gate/*
226f6c7d2Vincent Wang * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
2326f3cdfGordon Ross * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
247b1019aJerry Jelinek * Copyright 2016, Joyent, Inc.
257c478bdstevel@tonic-gate */
268e56767small/*
27fa96bd9Michael Corcoran * Copyright (c) 2009, Intel Corporation.
28fa96bd9Michael Corcoran * All rights reserved.
29fa96bd9Michael Corcoran */
30fa96bd9Michael Corcoran/*
318e56767small * Solaris x86 ACPI CA services
328e56767small */
337c478bdstevel@tonic-gate
347c478bdstevel@tonic-gate#include <sys/file.h>
357c478bdstevel@tonic-gate#include <sys/errno.h>
367c478bdstevel@tonic-gate#include <sys/conf.h>
377c478bdstevel@tonic-gate#include <sys/modctl.h>
387c478bdstevel@tonic-gate#include <sys/open.h>
397c478bdstevel@tonic-gate#include <sys/stat.h>
40a311483Gerry Liu#include <sys/spl.h>
417c478bdstevel@tonic-gate#include <sys/ddi.h>
427c478bdstevel@tonic-gate#include <sys/sunddi.h>
437c478bdstevel@tonic-gate#include <sys/esunddi.h>
442df1fe9randyf#include <sys/kstat.h>
45b9bfdccStuart Maybee#include <sys/x86_archext.h>
467c478bdstevel@tonic-gate
477c478bdstevel@tonic-gate#include <sys/acpi/acpi.h>
487c478bdstevel@tonic-gate#include <sys/acpica.h>
494cf02d4Saurabh Misra#include <sys/archsystm.h>
507c478bdstevel@tonic-gate
517c478bdstevel@tonic-gate/*
527c478bdstevel@tonic-gate *
537c478bdstevel@tonic-gate */
547c478bdstevel@tonic-gatestatic	struct modlmisc modlmisc = {
557c478bdstevel@tonic-gate	&mod_miscops,
5687bb58dmyers	"ACPI interpreter",
577c478bdstevel@tonic-gate};
587c478bdstevel@tonic-gate
597c478bdstevel@tonic-gatestatic	struct modlinkage modlinkage = {
607c478bdstevel@tonic-gate	MODREV_1,		/* MODREV_1 manual */
617c478bdstevel@tonic-gate	(void *)&modlmisc,	/* module linkage */
627c478bdstevel@tonic-gate	NULL,			/* list terminator */
637c478bdstevel@tonic-gate};
647c478bdstevel@tonic-gate
657c478bdstevel@tonic-gate/*
662df1fe9randyf * Local prototypes
672df1fe9randyf */
682df1fe9randyf
6926f3cdfGordon Rossstruct parsed_prw {
7026f3cdfGordon Ross	ACPI_HANDLE	prw_gpeobj;
7126f3cdfGordon Ross	int		prw_gpebit;
7226f3cdfGordon Ross	int		prw_level;
7326f3cdfGordon Ross};
7426f3cdfGordon Ross
752df1fe9randyfstatic void	acpica_init_kstats(void);
7626f3cdfGordon Rossstatic ACPI_STATUS	acpica_init_PRW(
7726f3cdfGordon Ross	ACPI_HANDLE	hdl,
7826f3cdfGordon Ross	UINT32		lvl,
7926f3cdfGordon Ross	void		*ctxp,
8026f3cdfGordon Ross	void		**rvpp);
8126f3cdfGordon Ross
8226f3cdfGordon Rossstatic ACPI_STATUS	acpica_parse_PRW(
8326f3cdfGordon Ross	ACPI_BUFFER	*prw_buf,
8426f3cdfGordon Ross	struct parsed_prw *prw);
852df1fe9randyf
862df1fe9randyf/*
877c478bdstevel@tonic-gate * Local data
887c478bdstevel@tonic-gate */
897c478bdstevel@tonic-gate
907c478bdstevel@tonic-gatestatic kmutex_t	acpica_module_lock;
912df1fe9randyfstatic kstat_t	*acpica_ksp;
927c478bdstevel@tonic-gate
937c478bdstevel@tonic-gate/*
947c478bdstevel@tonic-gate * State of acpica subsystem
957c478bdstevel@tonic-gate * After successful initialization, will be ACPICA_INITIALIZED
967c478bdstevel@tonic-gate */
977c478bdstevel@tonic-gateint acpica_init_state = ACPICA_NOT_INITIALIZED;
987c478bdstevel@tonic-gate
997b1019aJerry Jelinekvoid *AcpiGbl_DbBuffer;
1007b1019aJerry Jelinekuint32_t AcpiGbl_DbConsoleDebugLevel;
1017b1019aJerry Jelinek
1027c478bdstevel@tonic-gate/*
1037c478bdstevel@tonic-gate * Following are set by acpica_process_user_options()
1047c478bdstevel@tonic-gate *
1057c478bdstevel@tonic-gate * acpica_enable = FALSE prevents initialization of ACPI CA
1067c478bdstevel@tonic-gate * completely
1077c478bdstevel@tonic-gate *
1087c478bdstevel@tonic-gate * acpi_init_level determines level of ACPI CA functionality
1097c478bdstevel@tonic-gate * enabled in acpica_init()
1107c478bdstevel@tonic-gate */
1117c478bdstevel@tonic-gateint	acpica_enable;
1127c478bdstevel@tonic-gateUINT32	acpi_init_level;
1137c478bdstevel@tonic-gate
1147c478bdstevel@tonic-gate/*
1157c478bdstevel@tonic-gate * Non-zero enables lax behavior with respect to some
1167c478bdstevel@tonic-gate * common ACPI BIOS issues; see ACPI CA documentation
1177c478bdstevel@tonic-gate * Setting this to zero causes ACPI CA to enforce strict
1187c478bdstevel@tonic-gate * compliance with ACPI specification
1197c478bdstevel@tonic-gate */
1207c478bdstevel@tonic-gateint acpica_enable_interpreter_slack = 1;
1217c478bdstevel@tonic-gate
1223d50435myers/*
1233d50435myers * For non-DEBUG builds, set the ACPI CA debug level to 0
1243d50435myers * to quiet chatty BIOS output into /var/adm/messages
1253d50435myers * Field-patchable for diagnostic use.
1263d50435myers */
1273d50435myers#ifdef  DEBUG
1283d50435myersint acpica_muzzle_debug_output = 0;
1293d50435myers#else
1303d50435myersint acpica_muzzle_debug_output = 1;
1313d50435myers#endif
1323d50435myers
1332df1fe9randyf/*
1342df1fe9randyf * ACPI DDI hooks
1352df1fe9randyf */
1362df1fe9randyfstatic int acpica_ddi_setwake(dev_info_t *dip, int level);
1377c478bdstevel@tonic-gate
1387c478bdstevel@tonic-gateint
1397c478bdstevel@tonic-gate_init(void)
1407c478bdstevel@tonic-gate{
1417c478bdstevel@tonic-gate	int error = EBUSY;
1427c478bdstevel@tonic-gate	int	status;
1432df1fe9randyf	extern int (*acpi_fp_setwake)();
144a311483Gerry Liu	extern kmutex_t cpu_map_lock;
1457c478bdstevel@tonic-gate
1467c478bdstevel@tonic-gate	mutex_init(&acpica_module_lock, NULL, MUTEX_DRIVER, NULL);
147a311483Gerry Liu	mutex_init(&cpu_map_lock, NULL, MUTEX_SPIN,
148a311483Gerry Liu	    (ddi_iblock_cookie_t)ipltospl(DISP_LEVEL));
1497c478bdstevel@tonic-gate
1507c478bdstevel@tonic-gate	if ((error = mod_install(&modlinkage)) != 0) {
1517c478bdstevel@tonic-gate		mutex_destroy(&acpica_module_lock);
1522df1fe9randyf		goto load_error;
1537c478bdstevel@tonic-gate	}
1547c478bdstevel@tonic-gate
1557c478bdstevel@tonic-gate	AcpiGbl_EnableInterpreterSlack = (acpica_enable_interpreter_slack != 0);
1567c478bdstevel@tonic-gate
157c1381f4Dana Myers	/* global ACPI CA initialization */
158c1381f4Dana Myers	if (ACPI_FAILURE(status = AcpiInitializeSubsystem()))
159c1381f4Dana Myers		cmn_err(CE_WARN, "!AcpiInitializeSubsystem failed: %d", status);
160c1381f4Dana Myers
161c1381f4Dana Myers	/* initialize table manager */
162c1381f4Dana Myers	if (ACPI_FAILURE(status = AcpiInitializeTables(NULL, 0, 0)))
163c1381f4Dana Myers		cmn_err(CE_WARN, "!AcpiInitializeTables failed: %d", status);
1647c478bdstevel@tonic-gate
1652df1fe9randyf	acpi_fp_setwake = acpica_ddi_setwake;
1662df1fe9randyf
1672df1fe9randyfload_error:
1687c478bdstevel@tonic-gate	return (error);
1697c478bdstevel@tonic-gate}
1707c478bdstevel@tonic-gate
1717c478bdstevel@tonic-gateint
1727c478bdstevel@tonic-gate_info(struct modinfo *modinfop)
1737c478bdstevel@tonic-gate{
1747c478bdstevel@tonic-gate	return (mod_info(&modlinkage, modinfop));
1757c478bdstevel@tonic-gate}
1767c478bdstevel@tonic-gate
1777c478bdstevel@tonic-gateint
1787c478bdstevel@tonic-gate_fini(void)
1797c478bdstevel@tonic-gate{
180186507amyers	/*
181186507amyers	 * acpica module is never unloaded at run-time; there's always
182186507amyers	 * a PSM depending on it, at the very least
183186507amyers	 */
184186507amyers	return (EBUSY);
1857c478bdstevel@tonic-gate}
1867c478bdstevel@tonic-gate
1877c478bdstevel@tonic-gate/*
18826f3cdfGordon Ross * Install acpica-provided (default) address-space handlers
18926f3cdfGordon Ross * that may be needed before AcpiEnableSubsystem() runs.
19026f3cdfGordon Ross * See the comment in AcpiInstallAddressSpaceHandler().
19126f3cdfGordon Ross * Default handlers for remaining address spaces are
19226f3cdfGordon Ross * installed later, in AcpiEnableSubsystem.
1937c478bdstevel@tonic-gate */
1947c478bdstevel@tonic-gatestatic int
1957c478bdstevel@tonic-gateacpica_install_handlers()
1967c478bdstevel@tonic-gate{
1977c478bdstevel@tonic-gate	ACPI_STATUS	rv = AE_OK;
1987b1019aJerry Jelinek	ACPI_STATUS	res;
1997c478bdstevel@tonic-gate
2007c478bdstevel@tonic-gate	/*
2017c478bdstevel@tonic-gate	 * Install ACPI CA default handlers
2027c478bdstevel@tonic-gate	 */
2037b1019aJerry Jelinek	if ((res = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
2047c478bdstevel@tonic-gate	    ACPI_ADR_SPACE_SYSTEM_MEMORY,
2057b1019aJerry Jelinek	    ACPI_DEFAULT_HANDLER, NULL, NULL)) != AE_OK &&
2067b1019aJerry Jelinek	    res != AE_SAME_HANDLER) {
2077c478bdstevel@tonic-gate		cmn_err(CE_WARN, "!acpica: no default handler for"
2087c478bdstevel@tonic-gate		    " system memory");
2097c478bdstevel@tonic-gate		rv = AE_ERROR;
2107c478bdstevel@tonic-gate	}
2117c478bdstevel@tonic-gate
2127b1019aJerry Jelinek	if ((res = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
2137c478bdstevel@tonic-gate	    ACPI_ADR_SPACE_SYSTEM_IO,
2147b1019aJerry Jelinek	    ACPI_DEFAULT_HANDLER, NULL, NULL)) != AE_OK &&
2157b1019aJerry Jelinek	    res != AE_SAME_HANDLER) {
2167c478bdstevel@tonic-gate		cmn_err(CE_WARN, "!acpica: no default handler for"
2177c478bdstevel@tonic-gate		    " system I/O");
2187c478bdstevel@tonic-gate		rv = AE_ERROR;
2197c478bdstevel@tonic-gate	}
2207c478bdstevel@tonic-gate
2217b1019aJerry Jelinek	if ((res = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
2227c478bdstevel@tonic-gate	    ACPI_ADR_SPACE_PCI_CONFIG,
2237b1019aJerry Jelinek	    ACPI_DEFAULT_HANDLER, NULL, NULL)) != AE_OK &&
2247b1019aJerry Jelinek	    res != AE_SAME_HANDLER) {
2257c478bdstevel@tonic-gate		cmn_err(CE_WARN, "!acpica: no default handler for"
2267c478bdstevel@tonic-gate		    " PCI Config");
2277c478bdstevel@tonic-gate		rv = AE_ERROR;
2287c478bdstevel@tonic-gate	}
2297c478bdstevel@tonic-gate
2307b1019aJerry Jelinek	if ((res = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
23126f3cdfGordon Ross	    ACPI_ADR_SPACE_DATA_TABLE,
2327b1019aJerry Jelinek	    ACPI_DEFAULT_HANDLER, NULL, NULL)) != AE_OK &&
2337b1019aJerry Jelinek	    res != AE_SAME_HANDLER) {
23426f3cdfGordon Ross		cmn_err(CE_WARN, "!acpica: no default handler for"
23526f3cdfGordon Ross		    " Data Table");
23626f3cdfGordon Ross		rv = AE_ERROR;
23726f3cdfGordon Ross	}
2387c478bdstevel@tonic-gate
2397c478bdstevel@tonic-gate	return (rv);
2407c478bdstevel@tonic-gate}
2417c478bdstevel@tonic-gate
2427c478bdstevel@tonic-gate/*
2437c478bdstevel@tonic-gate * Find the BIOS date, and return TRUE if supplied
2447c478bdstevel@tonic-gate * date is same or later than the BIOS date, or FALSE
2457c478bdstevel@tonic-gate * if the BIOS date can't be fetched for any reason
2467c478bdstevel@tonic-gate */
2477c478bdstevel@tonic-gatestatic int
2487c478bdstevel@tonic-gateacpica_check_bios_date(int yy, int mm, int dd)
2497c478bdstevel@tonic-gate{
2507c478bdstevel@tonic-gate
2517c478bdstevel@tonic-gate	char *datep;
2527c478bdstevel@tonic-gate	int bios_year, bios_month, bios_day;
2537c478bdstevel@tonic-gate
254f2be514szhou	/* If firmware has no bios, skip the check */
255fa96bd9Michael Corcoran	if (ddi_prop_exists(DDI_DEV_T_ANY, ddi_root_node(), DDI_PROP_DONTPASS,
256ce1d04bToomas Soome	    "efi-systab"))
257f2be514szhou		return (TRUE);
258f2be514szhou
2597c478bdstevel@tonic-gate	/*
2607c478bdstevel@tonic-gate	 * PC BIOSes contain a string in the form of
2617c478bdstevel@tonic-gate	 * "mm/dd/yy" at absolute address 0xffff5,
2627c478bdstevel@tonic-gate	 * where mm, dd and yy are all ASCII digits.
2637c478bdstevel@tonic-gate	 * We map the string, pluck out the values,
2647c478bdstevel@tonic-gate	 * and accept all BIOSes from 1 Jan 1999 on
2657c478bdstevel@tonic-gate	 * as valid.
2667c478bdstevel@tonic-gate	 */
2677c478bdstevel@tonic-gate
268db2bae3Dana Myers	if ((datep = (char *)AcpiOsMapMemory(0xffff5, 8)) == NULL)
2697c478bdstevel@tonic-gate		return (FALSE);
2707c478bdstevel@tonic-gate
2717c478bdstevel@tonic-gate	/* year */
2727c478bdstevel@tonic-gate	bios_year = ((int)(*(datep + 6) - '0') * 10) + (*(datep + 7) - '0');
2737c478bdstevel@tonic-gate	/* month */
2747c478bdstevel@tonic-gate	bios_month = ((int)(*datep - '0') * 10) + (*(datep + 1) - '0');
2757c478bdstevel@tonic-gate	/* day */
2767c478bdstevel@tonic-gate	bios_day = ((int)(*(datep + 3) - '0') * 10) + (*(datep + 4) - '0');
2777c478bdstevel@tonic-gate
2787c478bdstevel@tonic-gate	AcpiOsUnmapMemory((void *) datep, 8);
2797c478bdstevel@tonic-gate
2807c478bdstevel@tonic-gate	if (bios_year < 0 || bios_year > 99 || bios_month < 0 ||
2817c478bdstevel@tonic-gate	    bios_month > 99 || bios_day < 0 || bios_day > 99) {
2827c478bdstevel@tonic-gate		/* non-digit chars in BIOS date */
2837c478bdstevel@tonic-gate		return (FALSE);
2847c478bdstevel@tonic-gate	}
2857c478bdstevel@tonic-gate
2867c478bdstevel@tonic-gate	/*
2877c478bdstevel@tonic-gate	 * Adjust for 2-digit year; note to grand-children:
2887c478bdstevel@tonic-gate	 * need a new scheme before 2080 rolls around
2897c478bdstevel@tonic-gate	 */
2907c478bdstevel@tonic-gate	bios_year += (bios_year >= 80 && bios_year <= 99) ?
2917c478bdstevel@tonic-gate	    1900 : 2000;
2927c478bdstevel@tonic-gate
2937c478bdstevel@tonic-gate	if (bios_year < yy)
2947c478bdstevel@tonic-gate		return (FALSE);
2957c478bdstevel@tonic-gate	else if (bios_year > yy)
2967c478bdstevel@tonic-gate		return (TRUE);
2977c478bdstevel@tonic-gate
2987c478bdstevel@tonic-gate	if (bios_month < mm)
2997c478bdstevel@tonic-gate		return (FALSE);
3007c478bdstevel@tonic-gate	else if (bios_month > mm)
3017c478bdstevel@tonic-gate		return (TRUE);
3027c478bdstevel@tonic-gate
3037c478bdstevel@tonic-gate	if (bios_day < dd)
3047c478bdstevel@tonic-gate		return (FALSE);
3057c478bdstevel@tonic-gate
3067c478bdstevel@tonic-gate	return (TRUE);
3077c478bdstevel@tonic-gate}
3087c478bdstevel@tonic-gate
3097c478bdstevel@tonic-gate/*
3107c478bdstevel@tonic-gate * Check for Metropolis systems with BIOSes older than 10/12/04
3117c478bdstevel@tonic-gate * return TRUE if BIOS requires legacy mode, FALSE otherwise
3127c478bdstevel@tonic-gate */
3137c478bdstevel@tonic-gatestatic int
3147c478bdstevel@tonic-gateacpica_metro_old_bios()
3157c478bdstevel@tonic-gate{
3167c478bdstevel@tonic-gate	ACPI_TABLE_HEADER *fadt;
3177c478bdstevel@tonic-gate
3187c478bdstevel@tonic-gate	/* get the FADT */
319db2bae3Dana Myers	if (AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **)&fadt) !=
320db2bae3Dana Myers	    AE_OK)
3217c478bdstevel@tonic-gate		return (FALSE);
3227c478bdstevel@tonic-gate
3237c478bdstevel@tonic-gate	/* compare OEM Table ID to "SUNmetro" - no match, return false */
3247c478bdstevel@tonic-gate	if (strncmp("SUNmetro", fadt->OemTableId, 8))
3257c478bdstevel@tonic-gate		return (FALSE);
3267c478bdstevel@tonic-gate
3277c478bdstevel@tonic-gate	/* On a Metro - return FALSE if later than 10/12/04 */
3287c478bdstevel@tonic-gate	return (!acpica_check_bios_date(2004, 10, 12));
3297c478bdstevel@tonic-gate}
3307c478bdstevel@tonic-gate
3317c478bdstevel@tonic-gate
3327c478bdstevel@tonic-gate/*
3337c478bdstevel@tonic-gate * Process acpi-user-options property  if present
3347c478bdstevel@tonic-gate */
3357c478bdstevel@tonic-gatestatic void
3367c478bdstevel@tonic-gateacpica_process_user_options()
3377c478bdstevel@tonic-gate{
3387c478bdstevel@tonic-gate	static int processed = 0;
3397c478bdstevel@tonic-gate	int acpi_user_options;
3407c478bdstevel@tonic-gate	char *acpi_prop;
3417c478bdstevel@tonic-gate
3427c478bdstevel@tonic-gate	/*
3437c478bdstevel@tonic-gate	 * return if acpi-user-options has already been processed
3447c478bdstevel@tonic-gate	 */
3457c478bdstevel@tonic-gate	if (processed)
3467c478bdstevel@tonic-gate		return;
3477c478bdstevel@tonic-gate	else
3487c478bdstevel@tonic-gate		processed = 1;
3497c478bdstevel@tonic-gate
3507c478bdstevel@tonic-gate	/* converts acpi-user-options from type string to int, if any */
3517c478bdstevel@tonic-gate	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
3527c478bdstevel@tonic-gate	    DDI_PROP_DONTPASS, "acpi-user-options", &acpi_prop) ==
3537c478bdstevel@tonic-gate	    DDI_PROP_SUCCESS) {
3547c478bdstevel@tonic-gate		long data;
3557c478bdstevel@tonic-gate		int ret;
3567c478bdstevel@tonic-gate		ret = ddi_strtol(acpi_prop, NULL, 0, &data);
3577c478bdstevel@tonic-gate		if (ret == 0) {
3587c478bdstevel@tonic-gate			e_ddi_prop_remove(DDI_DEV_T_NONE, ddi_root_node(),
3597c478bdstevel@tonic-gate			    "acpi-user-options");
360f7534bcsmall			e_ddi_prop_update_int(DDI_DEV_T_NONE, ddi_root_node(),
361f7534bcsmall			    "acpi-user-options", data);
3627c478bdstevel@tonic-gate		}
3637c478bdstevel@tonic-gate		ddi_prop_free(acpi_prop);
3647c478bdstevel@tonic-gate	}
3657c478bdstevel@tonic-gate
3667c478bdstevel@tonic-gate	/*
3677c478bdstevel@tonic-gate	 * fetch the optional options property
3687c478bdstevel@tonic-gate	 */
369fa96bd9Michael Corcoran	acpi_user_options = ddi_prop_get_int(DDI_DEV_T_ANY, ddi_root_node(),
370fa96bd9Michael Corcoran	    DDI_PROP_DONTPASS, "acpi-user-options", 0);
3717c478bdstevel@tonic-gate
3727c478bdstevel@tonic-gate	/*
3737c478bdstevel@tonic-gate	 * Note that 'off' has precedence over 'on'
3747c478bdstevel@tonic-gate	 * Also note - all cases of ACPI_OUSER_MASK
3757c478bdstevel@tonic-gate	 * provided here, no default: case is present
3767c478bdstevel@tonic-gate	 */
3777c478bdstevel@tonic-gate	switch (acpi_user_options & ACPI_OUSER_MASK) {
3787c478bdstevel@tonic-gate	case ACPI_OUSER_DFLT:
3797c478bdstevel@tonic-gate		acpica_enable = acpica_check_bios_date(1999, 1, 1);
3807c478bdstevel@tonic-gate		break;
3817c478bdstevel@tonic-gate	case ACPI_OUSER_ON:
3827c478bdstevel@tonic-gate		acpica_enable = TRUE;
3837c478bdstevel@tonic-gate		break;
3847c478bdstevel@tonic-gate	case ACPI_OUSER_OFF:
3857c478bdstevel@tonic-gate	case ACPI_OUSER_OFF | ACPI_OUSER_ON:
3867c478bdstevel@tonic-gate		acpica_enable = FALSE;
3877c478bdstevel@tonic-gate		break;
3887c478bdstevel@tonic-gate	}
3897c478bdstevel@tonic-gate
3907c478bdstevel@tonic-gate	acpi_init_level = ACPI_FULL_INITIALIZATION;
3917c478bdstevel@tonic-gate
3927c478bdstevel@tonic-gate	/*
3937c478bdstevel@tonic-gate	 * special test here; may be generalized in the
3947c478bdstevel@tonic-gate	 * future - test for a machines that are known to
3957c478bdstevel@tonic-gate	 * work only in legacy mode, and set OUSER_LEGACY if
3967c478bdstevel@tonic-gate	 * we're on one
3977c478bdstevel@tonic-gate	 */
3987c478bdstevel@tonic-gate	if (acpica_metro_old_bios())
3997c478bdstevel@tonic-gate		acpi_user_options |= ACPI_OUSER_LEGACY;
4007c478bdstevel@tonic-gate
4017c478bdstevel@tonic-gate	/*
4027c478bdstevel@tonic-gate	 * If legacy mode is specified, set initialization
4037c478bdstevel@tonic-gate	 * options to avoid entering ACPI mode and hooking SCI
4047c478bdstevel@tonic-gate	 * - basically try to act like legacy acpi_intp
4057c478bdstevel@tonic-gate	 */
4067c478bdstevel@tonic-gate	if ((acpi_user_options & ACPI_OUSER_LEGACY) != 0)
4077c478bdstevel@tonic-gate		acpi_init_level |= (ACPI_NO_ACPI_ENABLE | ACPI_NO_HANDLER_INIT);
4083d50435myers
4093d50435myers	/*
4103d50435myers	 * modify default ACPI CA debug output level for non-DEBUG builds
4113d50435myers	 * (to avoid BIOS debug chatter in /var/adm/messages)
4123d50435myers	 */
4133d50435myers	if (acpica_muzzle_debug_output)
4143d50435myers		AcpiDbgLevel = 0;
4157c478bdstevel@tonic-gate}
4167c478bdstevel@tonic-gate
4177c478bdstevel@tonic-gate/*
4187c478bdstevel@tonic-gate * Initialize the CA subsystem if it hasn't been done already
4197c478bdstevel@tonic-gate */
4207c478bdstevel@tonic-gateint
4217c478bdstevel@tonic-gateacpica_init()
4227c478bdstevel@tonic-gate{
423b9bfdccStuart Maybee	extern void acpica_find_ioapics(void);
4247c478bdstevel@tonic-gate	ACPI_STATUS status;
4257c478bdstevel@tonic-gate
4267c478bdstevel@tonic-gate	/*
4277c478bdstevel@tonic-gate	 * Make sure user options are processed,
4287c478bdstevel@tonic-gate	 * then fail to initialize if ACPI CA has been
4297c478bdstevel@tonic-gate	 * disabled
4307c478bdstevel@tonic-gate	 */
4317c478bdstevel@tonic-gate	acpica_process_user_options();
4327c478bdstevel@tonic-gate	if (!acpica_enable)
4337c478bdstevel@tonic-gate		return (AE_ERROR);
4347c478bdstevel@tonic-gate
4357c478bdstevel@tonic-gate	mutex_enter(&acpica_module_lock);
436fa96bd9Michael Corcoran	if (acpica_init_state == ACPICA_INITIALIZED) {
437fa96bd9Michael Corcoran		mutex_exit(&acpica_module_lock);
438fa96bd9Michael Corcoran		return (AE_OK);
439fa96bd9Michael Corcoran	}
4407c478bdstevel@tonic-gate
441fa96bd9Michael Corcoran	if (ACPI_FAILURE(status = AcpiLoadTables()))
442fa96bd9Michael Corcoran		goto error;
443db2bae3Dana Myers
444fa96bd9Michael Corcoran	if (ACPI_FAILURE(status = acpica_install_handlers()))
445fa96bd9Michael Corcoran		goto error;
446db2bae3Dana Myers
4475f68fdeDana Myers	/*
4485f68fdeDana Myers	 * Create ACPI-to-devinfo mapping now so _INI and _STA
4495f68fdeDana Myers	 * methods can access PCI config space when needed
4505f68fdeDana Myers	 */
4515f68fdeDana Myers	scan_d2a_map();
4525f68fdeDana Myers
453fa96bd9Michael Corcoran	if (ACPI_FAILURE(status = AcpiEnableSubsystem(acpi_init_level)))
454fa96bd9Michael Corcoran		goto error;
455db2bae3Dana Myers
456fa96bd9Michael Corcoran	/* do after AcpiEnableSubsystem() so GPEs are initialized */
457fa96bd9Michael Corcoran	acpica_ec_init();	/* initialize EC if present */
458c1381f4Dana Myers
45926f3cdfGordon Ross	/* This runs all device _STA and _INI methods. */
460fa96bd9Michael Corcoran	if (ACPI_FAILURE(status = AcpiInitializeObjects(0)))
461fa96bd9Michael Corcoran		goto error;
462db2bae3Dana Myers
463fa96bd9Michael Corcoran	acpica_init_state = ACPICA_INITIALIZED;
464fa96bd9Michael Corcoran
465fa96bd9Michael Corcoran	/*
46626f3cdfGordon Ross	 * [ACPI, sec. 4.4.1.1]
46726f3cdfGordon Ross	 * As of ACPICA version 20101217 (December 2010), the _PRW methods
46826f3cdfGordon Ross	 * (Power Resources for Wake) are no longer automatically executed
46926f3cdfGordon Ross	 * as part of the ACPICA initialization.  The OS must do this.
47026f3cdfGordon Ross	 */
47126f3cdfGordon Ross	(void) AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
47226f3cdfGordon Ross	    UINT32_MAX, acpica_init_PRW, NULL, NULL, NULL);
47326f3cdfGordon Ross	(void) AcpiUpdateAllGpes();
47426f3cdfGordon Ross
47526f3cdfGordon Ross	/*
476fa96bd9Michael Corcoran	 * If we are running on the Xen hypervisor as dom0 we need to
477fa96bd9Michael Corcoran	 * find the ioapics so we can prevent ACPI from trying to
478fa96bd9Michael Corcoran	 * access them.
479fa96bd9Michael Corcoran	 */
480fa96bd9Michael Corcoran	if (get_hwenv() == HW_XEN_PV && is_controldom())
481fa96bd9Michael Corcoran		acpica_find_ioapics();
482fa96bd9Michael Corcoran	acpica_init_kstats();
4837c478bdstevel@tonic-gateerror:
484fa96bd9Michael Corcoran	if (acpica_init_state != ACPICA_INITIALIZED) {
485fa96bd9Michael Corcoran		cmn_err(CE_NOTE, "!failed to initialize ACPI services");
486fa96bd9Michael Corcoran	}
4877c478bdstevel@tonic-gate
488f7534bcsmall	/*
489f7534bcsmall	 * Set acpi-status to 13 if acpica has been initialized successfully.
490f7534bcsmall	 * This indicates that acpica is up and running.  This variable name
491f7534bcsmall	 * and value were chosen in order to remain compatible with acpi_intp.
492f7534bcsmall	 */
493f7534bcsmall	e_ddi_prop_update_int(DDI_DEV_T_NONE, ddi_root_node(), "acpi-status",
494fa96bd9Michael Corcoran	    (ACPI_SUCCESS(status)) ? (ACPI_BOOT_INIT | ACPI_BOOT_ENABLE |
49587bb58dmyers	    ACPI_BOOT_BOOTCONF) : 0);
496f7534bcsmall
497fa96bd9Michael Corcoran	/* Mark acpica subsystem as fully initialized. */
498fa96bd9Michael Corcoran	if (ACPI_SUCCESS(status) &&
499fa96bd9Michael Corcoran	    acpi_init_level == ACPI_FULL_INITIALIZATION) {
500fa96bd9Michael Corcoran		acpica_set_core_feature(ACPI_FEATURE_FULL_INIT);
501fa96bd9Michael Corcoran	}
502fa96bd9Michael Corcoran
5037c478bdstevel@tonic-gate	mutex_exit(&acpica_module_lock);
5047c478bdstevel@tonic-gate	return (status);
5057c478bdstevel@tonic-gate}
5067c478bdstevel@tonic-gate
5077c478bdstevel@tonic-gate/*
5087c478bdstevel@tonic-gate * SCI handling
5097c478bdstevel@tonic-gate */
5107c478bdstevel@tonic-gate
5117c478bdstevel@tonic-gateACPI_STATUS
5127c478bdstevel@tonic-gateacpica_get_sci(int *sci_irq, iflag_t *sci_flags)
5137c478bdstevel@tonic-gate{
514db2bae3Dana Myers	ACPI_SUBTABLE_HEADER		*ap;
515db2bae3Dana Myers	ACPI_TABLE_MADT			*mat;
516db2bae3Dana Myers	ACPI_MADT_INTERRUPT_OVERRIDE	*mio;
517db2bae3Dana Myers	ACPI_TABLE_FADT			*fadt;
5187c478bdstevel@tonic-gate	int			madt_seen, madt_size;
5197c478bdstevel@tonic-gate
5207c478bdstevel@tonic-gate
5217c478bdstevel@tonic-gate	/*
5227c478bdstevel@tonic-gate	 * Make sure user options are processed,
5237c478bdstevel@tonic-gate	 * then return error if ACPI CA has been
5247c478bdstevel@tonic-gate	 * disabled or system is not running in ACPI
5257c478bdstevel@tonic-gate	 * and won't need/understand SCI
5267c478bdstevel@tonic-gate	 */
5277c478bdstevel@tonic-gate	acpica_process_user_options();
5287c478bdstevel@tonic-gate	if ((!acpica_enable) || (acpi_init_level & ACPI_NO_ACPI_ENABLE))
5297c478bdstevel@tonic-gate		return (AE_ERROR);
5307c478bdstevel@tonic-gate
5317c478bdstevel@tonic-gate	/*
5327c478bdstevel@tonic-gate	 * according to Intel ACPI developers, SCI
5337c478bdstevel@tonic-gate	 * conforms to PCI bus conventions; level/low
5347c478bdstevel@tonic-gate	 * unless otherwise directed by overrides.
5357c478bdstevel@tonic-gate	 */
5367c478bdstevel@tonic-gate	sci_flags->intr_el = INTR_EL_LEVEL;
5377c478bdstevel@tonic-gate	sci_flags->intr_po = INTR_PO_ACTIVE_LOW;
5387c478bdstevel@tonic-gate	sci_flags->bustype = BUS_PCI;	/*  we *do* conform to PCI */
5397c478bdstevel@tonic-gate
5407c478bdstevel@tonic-gate	/* get the SCI from the FADT */
541db2bae3Dana Myers	if (AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **)&fadt) !=
542db2bae3Dana Myers	    AE_OK)
5437c478bdstevel@tonic-gate		return (AE_ERROR);
5447c478bdstevel@tonic-gate
545db2bae3Dana Myers	*sci_irq = fadt->SciInterrupt;
5467c478bdstevel@tonic-gate
5477c478bdstevel@tonic-gate	/* search for ISOs that modify it */
5487c478bdstevel@tonic-gate	/* if we don't find a MADT, that's OK; no ISOs then */
549db2bae3Dana Myers	if (AcpiGetTable(ACPI_SIG_MADT, 1, (ACPI_TABLE_HEADER **) &mat) !=
550db2bae3Dana Myers	    AE_OK)
5517c478bdstevel@tonic-gate		return (AE_OK);
5527c478bdstevel@tonic-gate
553db2bae3Dana Myers	ap = (ACPI_SUBTABLE_HEADER *) (mat + 1);
554db2bae3Dana Myers	madt_size = mat->Header.Length;
5557c478bdstevel@tonic-gate	madt_seen = sizeof (*mat);
5567c478bdstevel@tonic-gate
5577c478bdstevel@tonic-gate	while (madt_seen < madt_size) {
5587c478bdstevel@tonic-gate		switch (ap->Type) {
559db2bae3Dana Myers		case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE:
560db2bae3Dana Myers			mio = (ACPI_MADT_INTERRUPT_OVERRIDE *) ap;
561db2bae3Dana Myers			if (mio->SourceIrq == *sci_irq) {
562db2bae3Dana Myers				*sci_irq = mio->GlobalIrq;
563db2bae3Dana Myers				sci_flags->intr_el = (mio->IntiFlags &
564db2bae3Dana Myers				    ACPI_MADT_TRIGGER_MASK) >> 2;
565db2bae3Dana Myers				sci_flags->intr_po = mio->IntiFlags &
566db2bae3Dana Myers				    ACPI_MADT_POLARITY_MASK;
5677c478bdstevel@tonic-gate			}
5687c478bdstevel@tonic-gate			break;
5697c478bdstevel@tonic-gate		}
5707c478bdstevel@tonic-gate
5717c478bdstevel@tonic-gate		/* advance to next entry */
5727c478bdstevel@tonic-gate		madt_seen += ap->Length;
573db2bae3Dana Myers		ap = (ACPI_SUBTABLE_HEADER *)(((char *)ap) + ap->Length);
5747c478bdstevel@tonic-gate	}
5757c478bdstevel@tonic-gate
5767c478bdstevel@tonic-gate	/*
5777c478bdstevel@tonic-gate	 * One more check; if ISO said "conform", revert to default
5787c478bdstevel@tonic-gate	 */
5797c478bdstevel@tonic-gate	if (sci_flags->intr_el == INTR_EL_CONFORM)
5807c478bdstevel@tonic-gate		sci_flags->intr_el = INTR_EL_LEVEL;
5817c478bdstevel@tonic-gate	if (sci_flags->intr_po == INTR_PO_CONFORM)
5827c478bdstevel@tonic-gate		sci_flags->intr_po = INTR_PO_ACTIVE_LOW;
5837c478bdstevel@tonic-gate
5847c478bdstevel@tonic-gate	return (AE_OK);
5857c478bdstevel@tonic-gate}
5862df1fe9randyf
5872df1fe9randyf/*
58826f3cdfGordon Ross * Call-back function used for _PRW initialization.  For every
58926f3cdfGordon Ross * device node that has a _PRW method, evaluate, parse, and do
59026f3cdfGordon Ross * AcpiSetupGpeForWake().
59126f3cdfGordon Ross */
59226f3cdfGordon Rossstatic ACPI_STATUS
59326f3cdfGordon Rossacpica_init_PRW(
59426f3cdfGordon Ross	ACPI_HANDLE	devhdl,
59526f3cdfGordon Ross	UINT32		depth,
59626f3cdfGordon Ross	void		*ctxp,
59726f3cdfGordon Ross	void		**rvpp)
59826f3cdfGordon Ross{
59926f3cdfGordon Ross	ACPI_STATUS	status;
60026f3cdfGordon Ross	ACPI_BUFFER	prw_buf;
60126f3cdfGordon Ross	struct parsed_prw prw;
60226f3cdfGordon Ross
60326f3cdfGordon Ross	prw_buf.Pointer = NULL;
60426f3cdfGordon Ross	prw_buf.Length = ACPI_ALLOCATE_BUFFER;
60526f3cdfGordon Ross
60626f3cdfGordon Ross	/*
60726f3cdfGordon Ross	 * Attempt to evaluate _PRW object.
60826f3cdfGordon Ross	 * If no valid object is found, return quietly, since not all
60926f3cdfGordon Ross	 * devices have _PRW objects.
61026f3cdfGordon Ross	 */
61126f3cdfGordon Ross	status = AcpiEvaluateObject(devhdl, "_PRW", NULL, &prw_buf);
61226f3cdfGordon Ross	if (ACPI_FAILURE(status))
61326f3cdfGordon Ross		goto done;
61426f3cdfGordon Ross	status = acpica_parse_PRW(&prw_buf, &prw);
61526f3cdfGordon Ross	if (ACPI_FAILURE(status))
61626f3cdfGordon Ross		goto done;
61726f3cdfGordon Ross
61826f3cdfGordon Ross	(void) AcpiSetupGpeForWake(devhdl,
61926f3cdfGordon Ross	    prw.prw_gpeobj, prw.prw_gpebit);
62026f3cdfGordon Ross
62126f3cdfGordon Rossdone:
62226f3cdfGordon Ross	if (prw_buf.Pointer != NULL)
62326f3cdfGordon Ross		AcpiOsFree(prw_buf.Pointer);
62426f3cdfGordon Ross
62526f3cdfGordon Ross	return (AE_OK);
62626f3cdfGordon Ross}
62726f3cdfGordon Ross
62826f3cdfGordon Ross/*
6292df1fe9randyf * Sets ACPI wake state for device referenced by dip.
6302df1fe9randyf * If level is S0 (0), disables wake event; otherwise,
6312df1fe9randyf * enables wake event which will wake system from level.
6322df1fe9randyf */
6332df1fe9randyfstatic int
6342df1fe9randyfacpica_ddi_setwake(dev_info_t *dip, int level)
6352df1fe9randyf{
6362df1fe9randyf	ACPI_STATUS	status;
63726f3cdfGordon Ross	ACPI_HANDLE	devobj;
6382df1fe9randyf	ACPI_BUFFER	prw_buf;
6396f6c7d2Vincent Wang	ACPI_OBJECT_LIST	arglist;
6406f6c7d2Vincent Wang	ACPI_OBJECT		args[3];
64126f3cdfGordon Ross	struct parsed_prw prw;
64226f3cdfGordon Ross	int		rv;
6432df1fe9randyf
6442df1fe9randyf	/*
6452df1fe9randyf	 * initialize these early so we can use a common
6462df1fe9randyf	 * exit point below
6472df1fe9randyf	 */
6482df1fe9randyf	prw_buf.Pointer = NULL;
6492df1fe9randyf	prw_buf.Length = ACPI_ALLOCATE_BUFFER;
6502df1fe9randyf	rv = 0;
6512df1fe9randyf
6522df1fe9randyf	/*
6532df1fe9randyf	 * Attempt to get a handle to a corresponding ACPI object.
6542df1fe9randyf	 * If no object is found, return quietly, since not all
6552df1fe9randyf	 * devices have corresponding ACPI objects.
6562df1fe9randyf	 */
6572df1fe9randyf	status = acpica_get_handle(dip, &devobj);
6582df1fe9randyf	if (ACPI_FAILURE(status)) {
6592df1fe9randyf		char pathbuf[MAXPATHLEN];
6602df1fe9randyf		ddi_pathname(dip, pathbuf);
6612df1fe9randyf#ifdef DEBUG
6622df1fe9randyf		cmn_err(CE_NOTE, "!acpica_ddi_setwake: could not get"
6632df1fe9randyf		    " handle for %s, %s:%d", pathbuf, ddi_driver_name(dip),
6642df1fe9randyf		    ddi_get_instance(dip));
6652df1fe9randyf#endif
6662df1fe9randyf		goto done;
6672df1fe9randyf	}
6682df1fe9randyf
6692df1fe9randyf	/*
6706f6c7d2Vincent Wang	 * ACPI3.0 7.2.1: only use the _PSW method if OSPM does not support
6716f6c7d2Vincent Wang	 * _DSW or if the _DSW method is not present.
6726f6c7d2Vincent Wang	 *
6736f6c7d2Vincent Wang	 * _DSW arguments:
6746f6c7d2Vincent Wang	 * args[0] - Enable/Disable
6756f6c7d2Vincent Wang	 * args[1] - Target system state
6766f6c7d2Vincent Wang	 * args[2] - Target device state
6776f6c7d2Vincent Wang	 */
6786f6c7d2Vincent Wang
6796f6c7d2Vincent Wang	arglist.Count = 3;
6806f6c7d2Vincent Wang	arglist.Pointer = args;
6816f6c7d2Vincent Wang	args[0].Type = ACPI_TYPE_INTEGER;
6826f6c7d2Vincent Wang	args[0].Integer.Value = level ? 1 : 0;
6836f6c7d2Vincent Wang	args[1].Type = ACPI_TYPE_INTEGER;
6846f6c7d2Vincent Wang	args[1].Integer.Value = level;
6856f6c7d2Vincent Wang	args[2].Type = ACPI_TYPE_INTEGER;
6866f6c7d2Vincent Wang	args[2].Integer.Value = level;
6876f6c7d2Vincent Wang	if (ACPI_FAILURE(status = AcpiEvaluateObject(devobj, "_DSW",
6886f6c7d2Vincent Wang	    &arglist, NULL))) {
6896f6c7d2Vincent Wang
6906f6c7d2Vincent Wang		if (status == AE_NOT_FOUND) {
6916f6c7d2Vincent Wang			arglist.Count = 1;
6926f6c7d2Vincent Wang			args[0].Type = ACPI_TYPE_INTEGER;
6936f6c7d2Vincent Wang			args[0].Integer.Value = level ? 1 : 0;
6946f6c7d2Vincent Wang
6956f6c7d2Vincent Wang			if (ACPI_FAILURE(status = AcpiEvaluateObject(devobj,
6966f6c7d2Vincent Wang			    "_PSW", &arglist, NULL))) {
6976f6c7d2Vincent Wang
6986f6c7d2Vincent Wang				if (status != AE_NOT_FOUND) {
6996f6c7d2Vincent Wang					cmn_err(CE_NOTE,
7006f6c7d2Vincent Wang					    "!_PSW failure %d for device %s",
7016f6c7d2Vincent Wang					    status, ddi_driver_name(dip));
7026f6c7d2Vincent Wang				}
7036f6c7d2Vincent Wang			}
7046f6c7d2Vincent Wang
7056f6c7d2Vincent Wang		} else {
7066f6c7d2Vincent Wang			cmn_err(CE_NOTE, "!_DSW failure %d for device %s",
7076f6c7d2Vincent Wang			    status, ddi_driver_name(dip));
7086f6c7d2Vincent Wang		}
7096f6c7d2Vincent Wang	}
7106f6c7d2Vincent Wang
7116f6c7d2Vincent Wang	/*
7122df1fe9randyf	 * Attempt to evaluate _PRW object.
7132df1fe9randyf	 * If no valid object is found, return quietly, since not all
7142df1fe9randyf	 * devices have _PRW objects.
7152df1fe9randyf	 */
7162df1fe9randyf	status = AcpiEvaluateObject(devobj, "_PRW", NULL, &prw_buf);
71726f3cdfGordon Ross	if (ACPI_FAILURE(status))
71826f3cdfGordon Ross		goto done;
71926f3cdfGordon Ross	status = acpica_parse_PRW(&prw_buf, &prw);
72026f3cdfGordon Ross	if (ACPI_FAILURE(status))
7212df1fe9randyf		goto done;
72226f3cdfGordon Ross
72326f3cdfGordon Ross	rv = -1;
72426f3cdfGordon Ross	if (level == 0) {
72526f3cdfGordon Ross		status = AcpiDisableGpe(prw.prw_gpeobj, prw.prw_gpebit);
72626f3cdfGordon Ross		if (ACPI_FAILURE(status))
72726f3cdfGordon Ross			goto done;
72826f3cdfGordon Ross	} else if (prw.prw_level >= level) {
72926f3cdfGordon Ross		status = AcpiSetGpeWakeMask(prw.prw_gpeobj, prw.prw_gpebit,
73026f3cdfGordon Ross		    ACPI_GPE_ENABLE);
73126f3cdfGordon Ross		if (ACPI_SUCCESS(status)) {
73226f3cdfGordon Ross			status = AcpiEnableGpe(prw.prw_gpeobj, prw.prw_gpebit);
73326f3cdfGordon Ross			if (ACPI_FAILURE(status))
73426f3cdfGordon Ross				goto done;
73526f3cdfGordon Ross		}
7362df1fe9randyf	}
73726f3cdfGordon Ross	rv = 0;
73826f3cdfGordon Rossdone:
73926f3cdfGordon Ross	if (prw_buf.Pointer != NULL)
74026f3cdfGordon Ross		AcpiOsFree(prw_buf.Pointer);
74126f3cdfGordon Ross	return (rv);
74226f3cdfGordon Ross}
74326f3cdfGordon Ross
74426f3cdfGordon Rossstatic ACPI_STATUS
74526f3cdfGordon Rossacpica_parse_PRW(
74626f3cdfGordon Ross	ACPI_BUFFER	*prw_buf,
74726f3cdfGordon Ross	struct parsed_prw *p_prw)
74826f3cdfGordon Ross{
74926f3cdfGordon Ross	ACPI_HANDLE	gpeobj;
75026f3cdfGordon Ross	ACPI_OBJECT	*prw, *gpe;
75126f3cdfGordon Ross	int		gpebit, prw_level;
75226f3cdfGordon Ross
75326f3cdfGordon Ross	if (prw_buf->Length == 0 || prw_buf->Pointer == NULL)
75426f3cdfGordon Ross		return (AE_NULL_OBJECT);
75526f3cdfGordon Ross
75626f3cdfGordon Ross	prw = prw_buf->Pointer;
75726f3cdfGordon Ross	if (prw->Type != ACPI_TYPE_PACKAGE || prw->Package.Count < 2 ||
75826f3cdfGordon Ross	    prw->Package.Elements[1].Type != ACPI_TYPE_INTEGER)
75926f3cdfGordon Ross		return (AE_TYPE);
7602df1fe9randyf
7612df1fe9randyf	/* fetch the lowest wake level from the _PRW */
7622df1fe9randyf	prw_level = prw->Package.Elements[1].Integer.Value;
7632df1fe9randyf
7642df1fe9randyf	/*
7652df1fe9randyf	 * process the GPE description
7662df1fe9randyf	 */
7672df1fe9randyf	switch (prw->Package.Elements[0].Type) {
7682df1fe9randyf	case ACPI_TYPE_INTEGER:
7692df1fe9randyf		gpeobj = NULL;
7702df1fe9randyf		gpebit = prw->Package.Elements[0].Integer.Value;
7712df1fe9randyf		break;
7722df1fe9randyf	case ACPI_TYPE_PACKAGE:
7732df1fe9randyf		gpe = &prw->Package.Elements[0];
7742df1fe9randyf		if (gpe->Package.Count != 2 ||
7752df1fe9randyf		    gpe->Package.Elements[1].Type != ACPI_TYPE_INTEGER)
77626f3cdfGordon Ross			return (AE_TYPE);
7772df1fe9randyf		gpeobj = gpe->Package.Elements[0].Reference.Handle;
7782df1fe9randyf		gpebit = gpe->Package.Elements[1].Integer.Value;
7792df1fe9randyf		if (gpeobj == NULL)
78026f3cdfGordon Ross			return (AE_NULL_OBJECT);
78126f3cdfGordon Ross		break;
7822df1fe9randyf	default:
78326f3cdfGordon Ross		return (AE_TYPE);
7842df1fe9randyf	}
7852df1fe9randyf
78626f3cdfGordon Ross	p_prw->prw_gpeobj = gpeobj;
78726f3cdfGordon Ross	p_prw->prw_gpebit = gpebit;
78826f3cdfGordon Ross	p_prw->prw_level  = prw_level;
78926f3cdfGordon Ross
79026f3cdfGordon Ross	return (AE_OK);
7912df1fe9randyf}
7922df1fe9randyf
7932df1fe9randyf/*
7942df1fe9randyf * kstat access to a limited set of ACPI propertis
7952df1fe9randyf */
7962df1fe9randyfstatic void
7972df1fe9randyfacpica_init_kstats()
7982df1fe9randyf{
7992df1fe9randyf	ACPI_HANDLE	s3handle;
8002df1fe9randyf	ACPI_STATUS	status;
801db2bae3Dana Myers	ACPI_TABLE_FADT	*fadt;
8022df1fe9randyf	kstat_named_t *knp;
8032df1fe9randyf
8042df1fe9randyf	/*
8052df1fe9randyf	 * Create a small set of named kstats; just return in the rare
8062df1fe9randyf	 * case of a failure, * in which case, the kstats won't be present.
8072df1fe9randyf	 */
8082df1fe9randyf	if ((acpica_ksp = kstat_create("acpi", 0, "acpi", "misc",
8092df1fe9randyf	    KSTAT_TYPE_NAMED, 2, 0)) == NULL)
8102df1fe9randyf		return;
8112df1fe9randyf
8122df1fe9randyf	/*
8132df1fe9randyf	 * initialize kstat 'S3' to reflect the presence of \_S3 in
8142df1fe9randyf	 * the ACPI namespace (1 = present, 0 = not present)
8152df1fe9randyf	 */
8162df1fe9randyf	knp = acpica_ksp->ks_data;
8172df1fe9randyf	knp->value.l = (AcpiGetHandle(NULL, "\\_S3", &s3handle) == AE_OK);
8182df1fe9randyf	kstat_named_init(knp, "S3", KSTAT_DATA_LONG);
8192df1fe9randyf	knp++;		/* advance to next named kstat */
8202df1fe9randyf
8212df1fe9randyf	/*
8222df1fe9randyf	 * initialize kstat 'preferred_pm_profile' to the value
8232df1fe9randyf	 * contained in the (always present) FADT
8242df1fe9randyf	 */
825db2bae3Dana Myers	status = AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **)&fadt);
826db2bae3Dana Myers	knp->value.l = (status == AE_OK) ? fadt->PreferredProfile : -1;
8272df1fe9randyf	kstat_named_init(knp, "preferred_pm_profile", KSTAT_DATA_LONG);
8282df1fe9randyf
8292df1fe9randyf	/*
8302df1fe9randyf	 * install the named kstats
8312df1fe9randyf	 */
8322df1fe9randyf	kstat_install(acpica_ksp);
8332df1fe9randyf}
8342df1fe9randyf
8352df1fe9randyf/*
8362df1fe9randyf * Attempt to save the current ACPI settings (_CRS) for the device
8372df1fe9randyf * which corresponds to the supplied devinfo node.  The settings are
8382df1fe9randyf * saved as a property on the dip.  If no ACPI object is found to be
8392df1fe9randyf * associated with the devinfo node, no action is taken and no error
8402df1fe9randyf * is reported.
8412df1fe9randyf */
8422df1fe9randyfvoid
8432df1fe9randyfacpica_ddi_save_resources(dev_info_t *dip)
8442df1fe9randyf{
8452df1fe9randyf	ACPI_HANDLE	devobj;
8462df1fe9randyf	ACPI_BUFFER	resbuf;
8472df1fe9randyf	int		ret;
8482df1fe9randyf
8492df1fe9randyf	resbuf.Length = ACPI_ALLOCATE_BUFFER;
8502df1fe9randyf	if (ACPI_FAILURE(acpica_get_handle(dip, &devobj)) ||
8512df1fe9randyf	    ACPI_FAILURE(AcpiGetCurrentResources(devobj, &resbuf)))
8522df1fe9randyf		return;
8532df1fe9randyf
8542df1fe9randyf	ret = ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
8552df1fe9randyf	    "acpi-crs", resbuf.Pointer, resbuf.Length);
8562df1fe9randyf
8572df1fe9randyf	ASSERT(ret == DDI_PROP_SUCCESS);
8582df1fe9randyf
8592df1fe9randyf	AcpiOsFree(resbuf.Pointer);
860