xref: /titanic_44/usr/src/uts/intel/io/acpica/acpica.c (revision cb56572868bfc488bbd3ab847b09db2a25554d44)
1ae115bc7Smrj /*
2ae115bc7Smrj  * CDDL HEADER START
3ae115bc7Smrj  *
4ae115bc7Smrj  * The contents of this file are subject to the terms of the
5ae115bc7Smrj  * Common Development and Distribution License (the "License").
6ae115bc7Smrj  * You may not use this file except in compliance with the License.
7ae115bc7Smrj  *
8ae115bc7Smrj  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9ae115bc7Smrj  * or http://www.opensolaris.org/os/licensing.
10ae115bc7Smrj  * See the License for the specific language governing permissions
11ae115bc7Smrj  * and limitations under the License.
12ae115bc7Smrj  *
13ae115bc7Smrj  * When distributing Covered Code, include this CDDL HEADER in each
14ae115bc7Smrj  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15ae115bc7Smrj  * If applicable, add the following below this CDDL HEADER, with the
16ae115bc7Smrj  * fields enclosed by brackets "[]" replaced with your own identifying
17ae115bc7Smrj  * information: Portions Copyright [yyyy] [name of copyright owner]
18ae115bc7Smrj  *
19ae115bc7Smrj  * CDDL HEADER END
20ae115bc7Smrj  */
21ae115bc7Smrj /*
226f6c7d2bSVincent Wang  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
2326f3cdf0SGordon Ross  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
24*cb565728SJerry Jelinek  * Copyright 2016, Joyent, Inc.
25ae115bc7Smrj  */
26ae115bc7Smrj /*
27fa96bd91SMichael Corcoran  * Copyright (c) 2009, Intel Corporation.
28fa96bd91SMichael Corcoran  * All rights reserved.
29fa96bd91SMichael Corcoran  */
30fa96bd91SMichael Corcoran /*
31ae115bc7Smrj  * Solaris x86 ACPI CA services
32ae115bc7Smrj  */
33ae115bc7Smrj 
34ae115bc7Smrj #include <sys/file.h>
35ae115bc7Smrj #include <sys/errno.h>
36ae115bc7Smrj #include <sys/conf.h>
37ae115bc7Smrj #include <sys/modctl.h>
38ae115bc7Smrj #include <sys/open.h>
39ae115bc7Smrj #include <sys/stat.h>
40a3114836SGerry Liu #include <sys/spl.h>
41ae115bc7Smrj #include <sys/ddi.h>
42ae115bc7Smrj #include <sys/sunddi.h>
43ae115bc7Smrj #include <sys/esunddi.h>
442df1fe9cSrandyf #include <sys/kstat.h>
45b9bfdccdSStuart Maybee #include <sys/x86_archext.h>
46ae115bc7Smrj 
47ae115bc7Smrj #include <sys/acpi/acpi.h>
48ae115bc7Smrj #include <sys/acpica.h>
494cf02d40SSaurabh Misra #include <sys/archsystm.h>
50ae115bc7Smrj 
51ae115bc7Smrj /*
52ae115bc7Smrj  *
53ae115bc7Smrj  */
54ae115bc7Smrj static	struct modlmisc modlmisc = {
55ae115bc7Smrj 	&mod_miscops,
5687bb58d6Smyers 	"ACPI interpreter",
57ae115bc7Smrj };
58ae115bc7Smrj 
59ae115bc7Smrj static	struct modlinkage modlinkage = {
60ae115bc7Smrj 	MODREV_1,		/* MODREV_1 manual */
61ae115bc7Smrj 	(void *)&modlmisc,	/* module linkage */
62ae115bc7Smrj 	NULL,			/* list terminator */
63ae115bc7Smrj };
64ae115bc7Smrj 
65ae115bc7Smrj /*
662df1fe9cSrandyf  * Local prototypes
672df1fe9cSrandyf  */
682df1fe9cSrandyf 
6926f3cdf0SGordon Ross struct parsed_prw {
7026f3cdf0SGordon Ross 	ACPI_HANDLE	prw_gpeobj;
7126f3cdf0SGordon Ross 	int		prw_gpebit;
7226f3cdf0SGordon Ross 	int		prw_level;
7326f3cdf0SGordon Ross };
7426f3cdf0SGordon Ross 
752df1fe9cSrandyf static void	acpica_init_kstats(void);
7626f3cdf0SGordon Ross static ACPI_STATUS	acpica_init_PRW(
7726f3cdf0SGordon Ross 	ACPI_HANDLE	hdl,
7826f3cdf0SGordon Ross 	UINT32		lvl,
7926f3cdf0SGordon Ross 	void		*ctxp,
8026f3cdf0SGordon Ross 	void		**rvpp);
8126f3cdf0SGordon Ross 
8226f3cdf0SGordon Ross static ACPI_STATUS	acpica_parse_PRW(
8326f3cdf0SGordon Ross 	ACPI_BUFFER	*prw_buf,
8426f3cdf0SGordon Ross 	struct parsed_prw *prw);
852df1fe9cSrandyf 
862df1fe9cSrandyf /*
87ae115bc7Smrj  * Local data
88ae115bc7Smrj  */
89ae115bc7Smrj 
90ae115bc7Smrj static kmutex_t	acpica_module_lock;
912df1fe9cSrandyf static kstat_t	*acpica_ksp;
92ae115bc7Smrj 
93ae115bc7Smrj /*
94ae115bc7Smrj  * State of acpica subsystem
95ae115bc7Smrj  * After successful initialization, will be ACPICA_INITIALIZED
96ae115bc7Smrj  */
97ae115bc7Smrj int acpica_init_state = ACPICA_NOT_INITIALIZED;
98ae115bc7Smrj 
99*cb565728SJerry Jelinek void *AcpiGbl_DbBuffer;
100*cb565728SJerry Jelinek uint32_t AcpiGbl_DbConsoleDebugLevel;
101*cb565728SJerry Jelinek 
102ae115bc7Smrj /*
103ae115bc7Smrj  * Following are set by acpica_process_user_options()
104ae115bc7Smrj  *
105ae115bc7Smrj  * acpica_enable = FALSE prevents initialization of ACPI CA
106ae115bc7Smrj  * completely
107ae115bc7Smrj  *
108ae115bc7Smrj  * acpi_init_level determines level of ACPI CA functionality
109ae115bc7Smrj  * enabled in acpica_init()
110ae115bc7Smrj  */
111ae115bc7Smrj int	acpica_enable;
112ae115bc7Smrj UINT32	acpi_init_level;
113ae115bc7Smrj 
114ae115bc7Smrj /*
115ae115bc7Smrj  * Non-zero enables lax behavior with respect to some
116ae115bc7Smrj  * common ACPI BIOS issues; see ACPI CA documentation
117ae115bc7Smrj  * Setting this to zero causes ACPI CA to enforce strict
118ae115bc7Smrj  * compliance with ACPI specification
119ae115bc7Smrj  */
120ae115bc7Smrj int acpica_enable_interpreter_slack = 1;
121ae115bc7Smrj 
122ae115bc7Smrj /*
123ae115bc7Smrj  * For non-DEBUG builds, set the ACPI CA debug level to 0
124ae115bc7Smrj  * to quiet chatty BIOS output into /var/adm/messages
125ae115bc7Smrj  * Field-patchable for diagnostic use.
126ae115bc7Smrj  */
127ae115bc7Smrj #ifdef  DEBUG
128ae115bc7Smrj int acpica_muzzle_debug_output = 0;
129ae115bc7Smrj #else
130ae115bc7Smrj int acpica_muzzle_debug_output = 1;
131ae115bc7Smrj #endif
132ae115bc7Smrj 
1332df1fe9cSrandyf /*
1342df1fe9cSrandyf  * ACPI DDI hooks
1352df1fe9cSrandyf  */
1362df1fe9cSrandyf static int acpica_ddi_setwake(dev_info_t *dip, int level);
137ae115bc7Smrj 
138ae115bc7Smrj int
_init(void)139ae115bc7Smrj _init(void)
140ae115bc7Smrj {
141ae115bc7Smrj 	int error = EBUSY;
142ae115bc7Smrj 	int	status;
1432df1fe9cSrandyf 	extern int (*acpi_fp_setwake)();
144a3114836SGerry Liu 	extern kmutex_t cpu_map_lock;
145ae115bc7Smrj 
146ae115bc7Smrj 	mutex_init(&acpica_module_lock, NULL, MUTEX_DRIVER, NULL);
147a3114836SGerry Liu 	mutex_init(&cpu_map_lock, NULL, MUTEX_SPIN,
148a3114836SGerry Liu 	    (ddi_iblock_cookie_t)ipltospl(DISP_LEVEL));
149ae115bc7Smrj 
150ae115bc7Smrj 	if ((error = mod_install(&modlinkage)) != 0) {
151ae115bc7Smrj 		mutex_destroy(&acpica_module_lock);
1522df1fe9cSrandyf 		goto load_error;
153ae115bc7Smrj 	}
154ae115bc7Smrj 
155ae115bc7Smrj 	AcpiGbl_EnableInterpreterSlack = (acpica_enable_interpreter_slack != 0);
156ae115bc7Smrj 
157c1381f44SDana Myers 	/* global ACPI CA initialization */
158c1381f44SDana Myers 	if (ACPI_FAILURE(status = AcpiInitializeSubsystem()))
159c1381f44SDana Myers 		cmn_err(CE_WARN, "!AcpiInitializeSubsystem failed: %d", status);
160c1381f44SDana Myers 
161c1381f44SDana Myers 	/* initialize table manager */
162c1381f44SDana Myers 	if (ACPI_FAILURE(status = AcpiInitializeTables(NULL, 0, 0)))
163c1381f44SDana Myers 		cmn_err(CE_WARN, "!AcpiInitializeTables failed: %d", status);
164ae115bc7Smrj 
1652df1fe9cSrandyf 	acpi_fp_setwake = acpica_ddi_setwake;
1662df1fe9cSrandyf 
1672df1fe9cSrandyf load_error:
168ae115bc7Smrj 	return (error);
169ae115bc7Smrj }
170ae115bc7Smrj 
171ae115bc7Smrj int
_info(struct modinfo * modinfop)172ae115bc7Smrj _info(struct modinfo *modinfop)
173ae115bc7Smrj {
174ae115bc7Smrj 	return (mod_info(&modlinkage, modinfop));
175ae115bc7Smrj }
176ae115bc7Smrj 
177ae115bc7Smrj int
_fini(void)178ae115bc7Smrj _fini(void)
179ae115bc7Smrj {
180ae115bc7Smrj 	/*
181ae115bc7Smrj 	 * acpica module is never unloaded at run-time; there's always
182ae115bc7Smrj 	 * a PSM depending on it, at the very least
183ae115bc7Smrj 	 */
184ae115bc7Smrj 	return (EBUSY);
185ae115bc7Smrj }
186ae115bc7Smrj 
187ae115bc7Smrj /*
18826f3cdf0SGordon Ross  * Install acpica-provided (default) address-space handlers
18926f3cdf0SGordon Ross  * that may be needed before AcpiEnableSubsystem() runs.
19026f3cdf0SGordon Ross  * See the comment in AcpiInstallAddressSpaceHandler().
19126f3cdf0SGordon Ross  * Default handlers for remaining address spaces are
19226f3cdf0SGordon Ross  * installed later, in AcpiEnableSubsystem.
193ae115bc7Smrj  */
194ae115bc7Smrj static int
acpica_install_handlers()195ae115bc7Smrj acpica_install_handlers()
196ae115bc7Smrj {
197ae115bc7Smrj 	ACPI_STATUS	rv = AE_OK;
198*cb565728SJerry Jelinek 	ACPI_STATUS	res;
199ae115bc7Smrj 
200ae115bc7Smrj 	/*
201ae115bc7Smrj 	 * Install ACPI CA default handlers
202ae115bc7Smrj 	 */
203*cb565728SJerry Jelinek 	if ((res = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
204ae115bc7Smrj 	    ACPI_ADR_SPACE_SYSTEM_MEMORY,
205*cb565728SJerry Jelinek 	    ACPI_DEFAULT_HANDLER, NULL, NULL)) != AE_OK &&
206*cb565728SJerry Jelinek 	    res != AE_SAME_HANDLER) {
207ae115bc7Smrj 		cmn_err(CE_WARN, "!acpica: no default handler for"
208ae115bc7Smrj 		    " system memory");
209ae115bc7Smrj 		rv = AE_ERROR;
210ae115bc7Smrj 	}
211ae115bc7Smrj 
212*cb565728SJerry Jelinek 	if ((res = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
213ae115bc7Smrj 	    ACPI_ADR_SPACE_SYSTEM_IO,
214*cb565728SJerry Jelinek 	    ACPI_DEFAULT_HANDLER, NULL, NULL)) != AE_OK &&
215*cb565728SJerry Jelinek 	    res != AE_SAME_HANDLER) {
216ae115bc7Smrj 		cmn_err(CE_WARN, "!acpica: no default handler for"
217ae115bc7Smrj 		    " system I/O");
218ae115bc7Smrj 		rv = AE_ERROR;
219ae115bc7Smrj 	}
220ae115bc7Smrj 
221*cb565728SJerry Jelinek 	if ((res = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
222ae115bc7Smrj 	    ACPI_ADR_SPACE_PCI_CONFIG,
223*cb565728SJerry Jelinek 	    ACPI_DEFAULT_HANDLER, NULL, NULL)) != AE_OK &&
224*cb565728SJerry Jelinek 	    res != AE_SAME_HANDLER) {
225ae115bc7Smrj 		cmn_err(CE_WARN, "!acpica: no default handler for"
226ae115bc7Smrj 		    " PCI Config");
227ae115bc7Smrj 		rv = AE_ERROR;
228ae115bc7Smrj 	}
229ae115bc7Smrj 
230*cb565728SJerry Jelinek 	if ((res = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
23126f3cdf0SGordon Ross 	    ACPI_ADR_SPACE_DATA_TABLE,
232*cb565728SJerry Jelinek 	    ACPI_DEFAULT_HANDLER, NULL, NULL)) != AE_OK &&
233*cb565728SJerry Jelinek 	    res != AE_SAME_HANDLER) {
23426f3cdf0SGordon Ross 		cmn_err(CE_WARN, "!acpica: no default handler for"
23526f3cdf0SGordon Ross 		    " Data Table");
23626f3cdf0SGordon Ross 		rv = AE_ERROR;
23726f3cdf0SGordon Ross 	}
238ae115bc7Smrj 
239ae115bc7Smrj 	return (rv);
240ae115bc7Smrj }
241ae115bc7Smrj 
242ae115bc7Smrj /*
243ae115bc7Smrj  * Find the BIOS date, and return TRUE if supplied
244ae115bc7Smrj  * date is same or later than the BIOS date, or FALSE
245ae115bc7Smrj  * if the BIOS date can't be fetched for any reason
246ae115bc7Smrj  */
247ae115bc7Smrj static int
acpica_check_bios_date(int yy,int mm,int dd)248ae115bc7Smrj acpica_check_bios_date(int yy, int mm, int dd)
249ae115bc7Smrj {
250ae115bc7Smrj 
251ae115bc7Smrj 	char *datep;
252ae115bc7Smrj 	int bios_year, bios_month, bios_day;
253ae115bc7Smrj 
254ae115bc7Smrj 	/* If firmware has no bios, skip the check */
255fa96bd91SMichael Corcoran 	if (ddi_prop_exists(DDI_DEV_T_ANY, ddi_root_node(), DDI_PROP_DONTPASS,
256fa96bd91SMichael Corcoran 	    "bios-free"))
257ae115bc7Smrj 		return (TRUE);
258ae115bc7Smrj 
259ae115bc7Smrj 	/*
260ae115bc7Smrj 	 * PC BIOSes contain a string in the form of
261ae115bc7Smrj 	 * "mm/dd/yy" at absolute address 0xffff5,
262ae115bc7Smrj 	 * where mm, dd and yy are all ASCII digits.
263ae115bc7Smrj 	 * We map the string, pluck out the values,
264ae115bc7Smrj 	 * and accept all BIOSes from 1 Jan 1999 on
265ae115bc7Smrj 	 * as valid.
266ae115bc7Smrj 	 */
267ae115bc7Smrj 
268db2bae30SDana Myers 	if ((datep = (char *)AcpiOsMapMemory(0xffff5, 8)) == NULL)
269ae115bc7Smrj 		return (FALSE);
270ae115bc7Smrj 
271ae115bc7Smrj 	/* year */
272ae115bc7Smrj 	bios_year = ((int)(*(datep + 6) - '0') * 10) + (*(datep + 7) - '0');
273ae115bc7Smrj 	/* month */
274ae115bc7Smrj 	bios_month = ((int)(*datep - '0') * 10) + (*(datep + 1) - '0');
275ae115bc7Smrj 	/* day */
276ae115bc7Smrj 	bios_day = ((int)(*(datep + 3) - '0') * 10) + (*(datep + 4) - '0');
277ae115bc7Smrj 
278ae115bc7Smrj 	AcpiOsUnmapMemory((void *) datep, 8);
279ae115bc7Smrj 
280ae115bc7Smrj 	if (bios_year < 0 || bios_year > 99 || bios_month < 0 ||
281ae115bc7Smrj 	    bios_month > 99 || bios_day < 0 || bios_day > 99) {
282ae115bc7Smrj 		/* non-digit chars in BIOS date */
283ae115bc7Smrj 		return (FALSE);
284ae115bc7Smrj 	}
285ae115bc7Smrj 
286ae115bc7Smrj 	/*
287ae115bc7Smrj 	 * Adjust for 2-digit year; note to grand-children:
288ae115bc7Smrj 	 * need a new scheme before 2080 rolls around
289ae115bc7Smrj 	 */
290ae115bc7Smrj 	bios_year += (bios_year >= 80 && bios_year <= 99) ?
291ae115bc7Smrj 	    1900 : 2000;
292ae115bc7Smrj 
293ae115bc7Smrj 	if (bios_year < yy)
294ae115bc7Smrj 		return (FALSE);
295ae115bc7Smrj 	else if (bios_year > yy)
296ae115bc7Smrj 		return (TRUE);
297ae115bc7Smrj 
298ae115bc7Smrj 	if (bios_month < mm)
299ae115bc7Smrj 		return (FALSE);
300ae115bc7Smrj 	else if (bios_month > mm)
301ae115bc7Smrj 		return (TRUE);
302ae115bc7Smrj 
303ae115bc7Smrj 	if (bios_day < dd)
304ae115bc7Smrj 		return (FALSE);
305ae115bc7Smrj 
306ae115bc7Smrj 	return (TRUE);
307ae115bc7Smrj }
308ae115bc7Smrj 
309ae115bc7Smrj /*
310ae115bc7Smrj  * Check for Metropolis systems with BIOSes older than 10/12/04
311ae115bc7Smrj  * return TRUE if BIOS requires legacy mode, FALSE otherwise
312ae115bc7Smrj  */
313ae115bc7Smrj static int
acpica_metro_old_bios()314ae115bc7Smrj acpica_metro_old_bios()
315ae115bc7Smrj {
316ae115bc7Smrj 	ACPI_TABLE_HEADER *fadt;
317ae115bc7Smrj 
318ae115bc7Smrj 	/* get the FADT */
319db2bae30SDana Myers 	if (AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **)&fadt) !=
320db2bae30SDana Myers 	    AE_OK)
321ae115bc7Smrj 		return (FALSE);
322ae115bc7Smrj 
323ae115bc7Smrj 	/* compare OEM Table ID to "SUNmetro" - no match, return false */
324ae115bc7Smrj 	if (strncmp("SUNmetro", fadt->OemTableId, 8))
325ae115bc7Smrj 		return (FALSE);
326ae115bc7Smrj 
327ae115bc7Smrj 	/* On a Metro - return FALSE if later than 10/12/04 */
328ae115bc7Smrj 	return (!acpica_check_bios_date(2004, 10, 12));
329ae115bc7Smrj }
330ae115bc7Smrj 
331ae115bc7Smrj 
332ae115bc7Smrj /*
333ae115bc7Smrj  * Process acpi-user-options property  if present
334ae115bc7Smrj  */
335ae115bc7Smrj static void
acpica_process_user_options()336ae115bc7Smrj acpica_process_user_options()
337ae115bc7Smrj {
338ae115bc7Smrj 	static int processed = 0;
339ae115bc7Smrj 	int acpi_user_options;
340ae115bc7Smrj 	char *acpi_prop;
341ae115bc7Smrj 
342ae115bc7Smrj 	/*
343ae115bc7Smrj 	 * return if acpi-user-options has already been processed
344ae115bc7Smrj 	 */
345ae115bc7Smrj 	if (processed)
346ae115bc7Smrj 		return;
347ae115bc7Smrj 	else
348ae115bc7Smrj 		processed = 1;
349ae115bc7Smrj 
350ae115bc7Smrj 	/* converts acpi-user-options from type string to int, if any */
351ae115bc7Smrj 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
352ae115bc7Smrj 	    DDI_PROP_DONTPASS, "acpi-user-options", &acpi_prop) ==
353ae115bc7Smrj 	    DDI_PROP_SUCCESS) {
354ae115bc7Smrj 		long data;
355ae115bc7Smrj 		int ret;
356ae115bc7Smrj 		ret = ddi_strtol(acpi_prop, NULL, 0, &data);
357ae115bc7Smrj 		if (ret == 0) {
358ae115bc7Smrj 			e_ddi_prop_remove(DDI_DEV_T_NONE, ddi_root_node(),
359ae115bc7Smrj 			    "acpi-user-options");
360ae115bc7Smrj 			e_ddi_prop_update_int(DDI_DEV_T_NONE, ddi_root_node(),
361ae115bc7Smrj 			    "acpi-user-options", data);
362ae115bc7Smrj 		}
363ae115bc7Smrj 		ddi_prop_free(acpi_prop);
364ae115bc7Smrj 	}
365ae115bc7Smrj 
366ae115bc7Smrj 	/*
367ae115bc7Smrj 	 * fetch the optional options property
368ae115bc7Smrj 	 */
369fa96bd91SMichael Corcoran 	acpi_user_options = ddi_prop_get_int(DDI_DEV_T_ANY, ddi_root_node(),
370fa96bd91SMichael Corcoran 	    DDI_PROP_DONTPASS, "acpi-user-options", 0);
371ae115bc7Smrj 
372ae115bc7Smrj 	/*
373ae115bc7Smrj 	 * Note that 'off' has precedence over 'on'
374ae115bc7Smrj 	 * Also note - all cases of ACPI_OUSER_MASK
375ae115bc7Smrj 	 * provided here, no default: case is present
376ae115bc7Smrj 	 */
377ae115bc7Smrj 	switch (acpi_user_options & ACPI_OUSER_MASK) {
378ae115bc7Smrj 	case ACPI_OUSER_DFLT:
379ae115bc7Smrj 		acpica_enable = acpica_check_bios_date(1999, 1, 1);
380ae115bc7Smrj 		break;
381ae115bc7Smrj 	case ACPI_OUSER_ON:
382ae115bc7Smrj 		acpica_enable = TRUE;
383ae115bc7Smrj 		break;
384ae115bc7Smrj 	case ACPI_OUSER_OFF:
385ae115bc7Smrj 	case ACPI_OUSER_OFF | ACPI_OUSER_ON:
386ae115bc7Smrj 		acpica_enable = FALSE;
387ae115bc7Smrj 		break;
388ae115bc7Smrj 	}
389ae115bc7Smrj 
390ae115bc7Smrj 	acpi_init_level = ACPI_FULL_INITIALIZATION;
391ae115bc7Smrj 
392ae115bc7Smrj 	/*
393ae115bc7Smrj 	 * special test here; may be generalized in the
394ae115bc7Smrj 	 * future - test for a machines that are known to
395ae115bc7Smrj 	 * work only in legacy mode, and set OUSER_LEGACY if
396ae115bc7Smrj 	 * we're on one
397ae115bc7Smrj 	 */
398ae115bc7Smrj 	if (acpica_metro_old_bios())
399ae115bc7Smrj 		acpi_user_options |= ACPI_OUSER_LEGACY;
400ae115bc7Smrj 
401ae115bc7Smrj 	/*
402ae115bc7Smrj 	 * If legacy mode is specified, set initialization
403ae115bc7Smrj 	 * options to avoid entering ACPI mode and hooking SCI
404ae115bc7Smrj 	 * - basically try to act like legacy acpi_intp
405ae115bc7Smrj 	 */
406ae115bc7Smrj 	if ((acpi_user_options & ACPI_OUSER_LEGACY) != 0)
407ae115bc7Smrj 		acpi_init_level |= (ACPI_NO_ACPI_ENABLE | ACPI_NO_HANDLER_INIT);
408ae115bc7Smrj 
409ae115bc7Smrj 	/*
410ae115bc7Smrj 	 * modify default ACPI CA debug output level for non-DEBUG builds
411ae115bc7Smrj 	 * (to avoid BIOS debug chatter in /var/adm/messages)
412ae115bc7Smrj 	 */
413ae115bc7Smrj 	if (acpica_muzzle_debug_output)
414ae115bc7Smrj 		AcpiDbgLevel = 0;
415ae115bc7Smrj }
416ae115bc7Smrj 
417ae115bc7Smrj /*
418ae115bc7Smrj  * Initialize the CA subsystem if it hasn't been done already
419ae115bc7Smrj  */
420ae115bc7Smrj int
acpica_init()421ae115bc7Smrj acpica_init()
422ae115bc7Smrj {
423b9bfdccdSStuart Maybee 	extern void acpica_find_ioapics(void);
424ae115bc7Smrj 	ACPI_STATUS status;
425ae115bc7Smrj 
426ae115bc7Smrj 	/*
427ae115bc7Smrj 	 * Make sure user options are processed,
428ae115bc7Smrj 	 * then fail to initialize if ACPI CA has been
429ae115bc7Smrj 	 * disabled
430ae115bc7Smrj 	 */
431ae115bc7Smrj 	acpica_process_user_options();
432ae115bc7Smrj 	if (!acpica_enable)
433ae115bc7Smrj 		return (AE_ERROR);
434ae115bc7Smrj 
435ae115bc7Smrj 	mutex_enter(&acpica_module_lock);
436fa96bd91SMichael Corcoran 	if (acpica_init_state == ACPICA_INITIALIZED) {
437fa96bd91SMichael Corcoran 		mutex_exit(&acpica_module_lock);
438fa96bd91SMichael Corcoran 		return (AE_OK);
439fa96bd91SMichael Corcoran 	}
440ae115bc7Smrj 
441db2bae30SDana Myers 	if (ACPI_FAILURE(status = AcpiLoadTables()))
442ae115bc7Smrj 		goto error;
443db2bae30SDana Myers 
444db2bae30SDana Myers 	if (ACPI_FAILURE(status = acpica_install_handlers()))
445ae115bc7Smrj 		goto error;
446db2bae30SDana Myers 
4475f68fde5SDana Myers 	/*
4485f68fde5SDana Myers 	 * Create ACPI-to-devinfo mapping now so _INI and _STA
4495f68fde5SDana Myers 	 * methods can access PCI config space when needed
4505f68fde5SDana Myers 	 */
4515f68fde5SDana Myers 	scan_d2a_map();
4525f68fde5SDana Myers 
453fa96bd91SMichael Corcoran 	if (ACPI_FAILURE(status = AcpiEnableSubsystem(acpi_init_level)))
454ae115bc7Smrj 		goto error;
455db2bae30SDana Myers 
456c1381f44SDana Myers 	/* do after AcpiEnableSubsystem() so GPEs are initialized */
457c1381f44SDana Myers 	acpica_ec_init();	/* initialize EC if present */
458c1381f44SDana Myers 
45926f3cdf0SGordon Ross 	/* This runs all device _STA and _INI methods. */
460db2bae30SDana Myers 	if (ACPI_FAILURE(status = AcpiInitializeObjects(0)))
461db2bae30SDana Myers 		goto error;
462db2bae30SDana Myers 
463ae115bc7Smrj 	acpica_init_state = ACPICA_INITIALIZED;
464fa96bd91SMichael Corcoran 
465b9bfdccdSStuart Maybee 	/*
46626f3cdf0SGordon Ross 	 * [ACPI, sec. 4.4.1.1]
46726f3cdf0SGordon Ross 	 * As of ACPICA version 20101217 (December 2010), the _PRW methods
46826f3cdf0SGordon Ross 	 * (Power Resources for Wake) are no longer automatically executed
46926f3cdf0SGordon Ross 	 * as part of the ACPICA initialization.  The OS must do this.
47026f3cdf0SGordon Ross 	 */
47126f3cdf0SGordon Ross 	(void) AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
47226f3cdf0SGordon Ross 	    UINT32_MAX, acpica_init_PRW, NULL, NULL, NULL);
47326f3cdf0SGordon Ross 	(void) AcpiUpdateAllGpes();
47426f3cdf0SGordon Ross 
47526f3cdf0SGordon Ross 	/*
476b9bfdccdSStuart Maybee 	 * If we are running on the Xen hypervisor as dom0 we need to
477b9bfdccdSStuart Maybee 	 * find the ioapics so we can prevent ACPI from trying to
478b9bfdccdSStuart Maybee 	 * access them.
479b9bfdccdSStuart Maybee 	 */
480b9bfdccdSStuart Maybee 	if (get_hwenv() == HW_XEN_PV && is_controldom())
481b9bfdccdSStuart Maybee 		acpica_find_ioapics();
4822df1fe9cSrandyf 	acpica_init_kstats();
483ae115bc7Smrj error:
484ae115bc7Smrj 	if (acpica_init_state != ACPICA_INITIALIZED) {
485fa96bd91SMichael Corcoran 		cmn_err(CE_NOTE, "!failed to initialize ACPI services");
486ae115bc7Smrj 	}
487ae115bc7Smrj 
488ae115bc7Smrj 	/*
489ae115bc7Smrj 	 * Set acpi-status to 13 if acpica has been initialized successfully.
490ae115bc7Smrj 	 * This indicates that acpica is up and running.  This variable name
491ae115bc7Smrj 	 * and value were chosen in order to remain compatible with acpi_intp.
492ae115bc7Smrj 	 */
493ae115bc7Smrj 	e_ddi_prop_update_int(DDI_DEV_T_NONE, ddi_root_node(), "acpi-status",
494fa96bd91SMichael Corcoran 	    (ACPI_SUCCESS(status)) ? (ACPI_BOOT_INIT | ACPI_BOOT_ENABLE |
495ae115bc7Smrj 	    ACPI_BOOT_BOOTCONF) : 0);
496ae115bc7Smrj 
497fa96bd91SMichael Corcoran 	/* Mark acpica subsystem as fully initialized. */
498fa96bd91SMichael Corcoran 	if (ACPI_SUCCESS(status) &&
499fa96bd91SMichael Corcoran 	    acpi_init_level == ACPI_FULL_INITIALIZATION) {
500fa96bd91SMichael Corcoran 		acpica_set_core_feature(ACPI_FEATURE_FULL_INIT);
501fa96bd91SMichael Corcoran 	}
502fa96bd91SMichael Corcoran 
503ae115bc7Smrj 	mutex_exit(&acpica_module_lock);
504ae115bc7Smrj 	return (status);
505ae115bc7Smrj }
506ae115bc7Smrj 
507ae115bc7Smrj /*
508ae115bc7Smrj  * SCI handling
509ae115bc7Smrj  */
510ae115bc7Smrj 
511ae115bc7Smrj ACPI_STATUS
acpica_get_sci(int * sci_irq,iflag_t * sci_flags)512ae115bc7Smrj acpica_get_sci(int *sci_irq, iflag_t *sci_flags)
513ae115bc7Smrj {
514db2bae30SDana Myers 	ACPI_SUBTABLE_HEADER		*ap;
515db2bae30SDana Myers 	ACPI_TABLE_MADT			*mat;
516db2bae30SDana Myers 	ACPI_MADT_INTERRUPT_OVERRIDE	*mio;
517db2bae30SDana Myers 	ACPI_TABLE_FADT			*fadt;
518ae115bc7Smrj 	int			madt_seen, madt_size;
519ae115bc7Smrj 
520ae115bc7Smrj 
521ae115bc7Smrj 	/*
522ae115bc7Smrj 	 * Make sure user options are processed,
523ae115bc7Smrj 	 * then return error if ACPI CA has been
524ae115bc7Smrj 	 * disabled or system is not running in ACPI
525ae115bc7Smrj 	 * and won't need/understand SCI
526ae115bc7Smrj 	 */
527ae115bc7Smrj 	acpica_process_user_options();
528ae115bc7Smrj 	if ((!acpica_enable) || (acpi_init_level & ACPI_NO_ACPI_ENABLE))
529ae115bc7Smrj 		return (AE_ERROR);
530ae115bc7Smrj 
531ae115bc7Smrj 	/*
532ae115bc7Smrj 	 * according to Intel ACPI developers, SCI
533ae115bc7Smrj 	 * conforms to PCI bus conventions; level/low
534ae115bc7Smrj 	 * unless otherwise directed by overrides.
535ae115bc7Smrj 	 */
536ae115bc7Smrj 	sci_flags->intr_el = INTR_EL_LEVEL;
537ae115bc7Smrj 	sci_flags->intr_po = INTR_PO_ACTIVE_LOW;
538ae115bc7Smrj 	sci_flags->bustype = BUS_PCI;	/*  we *do* conform to PCI */
539ae115bc7Smrj 
540ae115bc7Smrj 	/* get the SCI from the FADT */
541db2bae30SDana Myers 	if (AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **)&fadt) !=
542db2bae30SDana Myers 	    AE_OK)
543ae115bc7Smrj 		return (AE_ERROR);
544ae115bc7Smrj 
545db2bae30SDana Myers 	*sci_irq = fadt->SciInterrupt;
546ae115bc7Smrj 
547ae115bc7Smrj 	/* search for ISOs that modify it */
548ae115bc7Smrj 	/* if we don't find a MADT, that's OK; no ISOs then */
549db2bae30SDana Myers 	if (AcpiGetTable(ACPI_SIG_MADT, 1, (ACPI_TABLE_HEADER **) &mat) !=
550db2bae30SDana Myers 	    AE_OK)
551ae115bc7Smrj 		return (AE_OK);
552ae115bc7Smrj 
553db2bae30SDana Myers 	ap = (ACPI_SUBTABLE_HEADER *) (mat + 1);
554db2bae30SDana Myers 	madt_size = mat->Header.Length;
555ae115bc7Smrj 	madt_seen = sizeof (*mat);
556ae115bc7Smrj 
557ae115bc7Smrj 	while (madt_seen < madt_size) {
558ae115bc7Smrj 		switch (ap->Type) {
559db2bae30SDana Myers 		case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE:
560db2bae30SDana Myers 			mio = (ACPI_MADT_INTERRUPT_OVERRIDE *) ap;
561db2bae30SDana Myers 			if (mio->SourceIrq == *sci_irq) {
562db2bae30SDana Myers 				*sci_irq = mio->GlobalIrq;
563db2bae30SDana Myers 				sci_flags->intr_el = (mio->IntiFlags &
564db2bae30SDana Myers 				    ACPI_MADT_TRIGGER_MASK) >> 2;
565db2bae30SDana Myers 				sci_flags->intr_po = mio->IntiFlags &
566db2bae30SDana Myers 				    ACPI_MADT_POLARITY_MASK;
567ae115bc7Smrj 			}
568ae115bc7Smrj 			break;
569ae115bc7Smrj 		}
570ae115bc7Smrj 
571ae115bc7Smrj 		/* advance to next entry */
572ae115bc7Smrj 		madt_seen += ap->Length;
573db2bae30SDana Myers 		ap = (ACPI_SUBTABLE_HEADER *)(((char *)ap) + ap->Length);
574ae115bc7Smrj 	}
575ae115bc7Smrj 
576ae115bc7Smrj 	/*
577ae115bc7Smrj 	 * One more check; if ISO said "conform", revert to default
578ae115bc7Smrj 	 */
579ae115bc7Smrj 	if (sci_flags->intr_el == INTR_EL_CONFORM)
580ae115bc7Smrj 		sci_flags->intr_el = INTR_EL_LEVEL;
581ae115bc7Smrj 	if (sci_flags->intr_po == INTR_PO_CONFORM)
582ae115bc7Smrj 		sci_flags->intr_po = INTR_PO_ACTIVE_LOW;
583ae115bc7Smrj 
584ae115bc7Smrj 	return (AE_OK);
585ae115bc7Smrj }
5862df1fe9cSrandyf 
5872df1fe9cSrandyf /*
58826f3cdf0SGordon Ross  * Call-back function used for _PRW initialization.  For every
58926f3cdf0SGordon Ross  * device node that has a _PRW method, evaluate, parse, and do
59026f3cdf0SGordon Ross  * AcpiSetupGpeForWake().
59126f3cdf0SGordon Ross  */
59226f3cdf0SGordon Ross static ACPI_STATUS
acpica_init_PRW(ACPI_HANDLE devhdl,UINT32 depth,void * ctxp,void ** rvpp)59326f3cdf0SGordon Ross acpica_init_PRW(
59426f3cdf0SGordon Ross 	ACPI_HANDLE	devhdl,
59526f3cdf0SGordon Ross 	UINT32		depth,
59626f3cdf0SGordon Ross 	void		*ctxp,
59726f3cdf0SGordon Ross 	void		**rvpp)
59826f3cdf0SGordon Ross {
59926f3cdf0SGordon Ross 	ACPI_STATUS	status;
60026f3cdf0SGordon Ross 	ACPI_BUFFER	prw_buf;
60126f3cdf0SGordon Ross 	struct parsed_prw prw;
60226f3cdf0SGordon Ross 
60326f3cdf0SGordon Ross 	prw_buf.Pointer = NULL;
60426f3cdf0SGordon Ross 	prw_buf.Length = ACPI_ALLOCATE_BUFFER;
60526f3cdf0SGordon Ross 
60626f3cdf0SGordon Ross 	/*
60726f3cdf0SGordon Ross 	 * Attempt to evaluate _PRW object.
60826f3cdf0SGordon Ross 	 * If no valid object is found, return quietly, since not all
60926f3cdf0SGordon Ross 	 * devices have _PRW objects.
61026f3cdf0SGordon Ross 	 */
61126f3cdf0SGordon Ross 	status = AcpiEvaluateObject(devhdl, "_PRW", NULL, &prw_buf);
61226f3cdf0SGordon Ross 	if (ACPI_FAILURE(status))
61326f3cdf0SGordon Ross 		goto done;
61426f3cdf0SGordon Ross 	status = acpica_parse_PRW(&prw_buf, &prw);
61526f3cdf0SGordon Ross 	if (ACPI_FAILURE(status))
61626f3cdf0SGordon Ross 		goto done;
61726f3cdf0SGordon Ross 
61826f3cdf0SGordon Ross 	(void) AcpiSetupGpeForWake(devhdl,
61926f3cdf0SGordon Ross 	    prw.prw_gpeobj, prw.prw_gpebit);
62026f3cdf0SGordon Ross 
62126f3cdf0SGordon Ross done:
62226f3cdf0SGordon Ross 	if (prw_buf.Pointer != NULL)
62326f3cdf0SGordon Ross 		AcpiOsFree(prw_buf.Pointer);
62426f3cdf0SGordon Ross 
62526f3cdf0SGordon Ross 	return (AE_OK);
62626f3cdf0SGordon Ross }
62726f3cdf0SGordon Ross 
62826f3cdf0SGordon Ross /*
6292df1fe9cSrandyf  * Sets ACPI wake state for device referenced by dip.
6302df1fe9cSrandyf  * If level is S0 (0), disables wake event; otherwise,
6312df1fe9cSrandyf  * enables wake event which will wake system from level.
6322df1fe9cSrandyf  */
6332df1fe9cSrandyf static int
acpica_ddi_setwake(dev_info_t * dip,int level)6342df1fe9cSrandyf acpica_ddi_setwake(dev_info_t *dip, int level)
6352df1fe9cSrandyf {
6362df1fe9cSrandyf 	ACPI_STATUS	status;
63726f3cdf0SGordon Ross 	ACPI_HANDLE	devobj;
6382df1fe9cSrandyf 	ACPI_BUFFER	prw_buf;
6396f6c7d2bSVincent Wang 	ACPI_OBJECT_LIST	arglist;
6406f6c7d2bSVincent Wang 	ACPI_OBJECT		args[3];
64126f3cdf0SGordon Ross 	struct parsed_prw prw;
64226f3cdf0SGordon Ross 	int		rv;
6432df1fe9cSrandyf 
6442df1fe9cSrandyf 	/*
6452df1fe9cSrandyf 	 * initialize these early so we can use a common
6462df1fe9cSrandyf 	 * exit point below
6472df1fe9cSrandyf 	 */
6482df1fe9cSrandyf 	prw_buf.Pointer = NULL;
6492df1fe9cSrandyf 	prw_buf.Length = ACPI_ALLOCATE_BUFFER;
6502df1fe9cSrandyf 	rv = 0;
6512df1fe9cSrandyf 
6522df1fe9cSrandyf 	/*
6532df1fe9cSrandyf 	 * Attempt to get a handle to a corresponding ACPI object.
6542df1fe9cSrandyf 	 * If no object is found, return quietly, since not all
6552df1fe9cSrandyf 	 * devices have corresponding ACPI objects.
6562df1fe9cSrandyf 	 */
6572df1fe9cSrandyf 	status = acpica_get_handle(dip, &devobj);
6582df1fe9cSrandyf 	if (ACPI_FAILURE(status)) {
6592df1fe9cSrandyf 		char pathbuf[MAXPATHLEN];
6602df1fe9cSrandyf 		ddi_pathname(dip, pathbuf);
6612df1fe9cSrandyf #ifdef DEBUG
6622df1fe9cSrandyf 		cmn_err(CE_NOTE, "!acpica_ddi_setwake: could not get"
6632df1fe9cSrandyf 		    " handle for %s, %s:%d", pathbuf, ddi_driver_name(dip),
6642df1fe9cSrandyf 		    ddi_get_instance(dip));
6652df1fe9cSrandyf #endif
6662df1fe9cSrandyf 		goto done;
6672df1fe9cSrandyf 	}
6682df1fe9cSrandyf 
6692df1fe9cSrandyf 	/*
6706f6c7d2bSVincent Wang 	 * ACPI3.0 7.2.1: only use the _PSW method if OSPM does not support
6716f6c7d2bSVincent Wang 	 * _DSW or if the _DSW method is not present.
6726f6c7d2bSVincent Wang 	 *
6736f6c7d2bSVincent Wang 	 * _DSW arguments:
6746f6c7d2bSVincent Wang 	 * args[0] - Enable/Disable
6756f6c7d2bSVincent Wang 	 * args[1] - Target system state
6766f6c7d2bSVincent Wang 	 * args[2] - Target device state
6776f6c7d2bSVincent Wang 	 */
6786f6c7d2bSVincent Wang 
6796f6c7d2bSVincent Wang 	arglist.Count = 3;
6806f6c7d2bSVincent Wang 	arglist.Pointer = args;
6816f6c7d2bSVincent Wang 	args[0].Type = ACPI_TYPE_INTEGER;
6826f6c7d2bSVincent Wang 	args[0].Integer.Value = level ? 1 : 0;
6836f6c7d2bSVincent Wang 	args[1].Type = ACPI_TYPE_INTEGER;
6846f6c7d2bSVincent Wang 	args[1].Integer.Value = level;
6856f6c7d2bSVincent Wang 	args[2].Type = ACPI_TYPE_INTEGER;
6866f6c7d2bSVincent Wang 	args[2].Integer.Value = level;
6876f6c7d2bSVincent Wang 	if (ACPI_FAILURE(status = AcpiEvaluateObject(devobj, "_DSW",
6886f6c7d2bSVincent Wang 	    &arglist, NULL))) {
6896f6c7d2bSVincent Wang 
6906f6c7d2bSVincent Wang 		if (status == AE_NOT_FOUND) {
6916f6c7d2bSVincent Wang 			arglist.Count = 1;
6926f6c7d2bSVincent Wang 			args[0].Type = ACPI_TYPE_INTEGER;
6936f6c7d2bSVincent Wang 			args[0].Integer.Value = level ? 1 : 0;
6946f6c7d2bSVincent Wang 
6956f6c7d2bSVincent Wang 			if (ACPI_FAILURE(status = AcpiEvaluateObject(devobj,
6966f6c7d2bSVincent Wang 			    "_PSW", &arglist, NULL))) {
6976f6c7d2bSVincent Wang 
6986f6c7d2bSVincent Wang 				if (status != AE_NOT_FOUND) {
6996f6c7d2bSVincent Wang 					cmn_err(CE_NOTE,
7006f6c7d2bSVincent Wang 					    "!_PSW failure %d for device %s",
7016f6c7d2bSVincent Wang 					    status, ddi_driver_name(dip));
7026f6c7d2bSVincent Wang 				}
7036f6c7d2bSVincent Wang 			}
7046f6c7d2bSVincent Wang 
7056f6c7d2bSVincent Wang 		} else {
7066f6c7d2bSVincent Wang 			cmn_err(CE_NOTE, "!_DSW failure %d for device %s",
7076f6c7d2bSVincent Wang 			    status, ddi_driver_name(dip));
7086f6c7d2bSVincent Wang 		}
7096f6c7d2bSVincent Wang 	}
7106f6c7d2bSVincent Wang 
7116f6c7d2bSVincent Wang 	/*
7122df1fe9cSrandyf 	 * Attempt to evaluate _PRW object.
7132df1fe9cSrandyf 	 * If no valid object is found, return quietly, since not all
7142df1fe9cSrandyf 	 * devices have _PRW objects.
7152df1fe9cSrandyf 	 */
7162df1fe9cSrandyf 	status = AcpiEvaluateObject(devobj, "_PRW", NULL, &prw_buf);
71726f3cdf0SGordon Ross 	if (ACPI_FAILURE(status))
71826f3cdf0SGordon Ross 		goto done;
71926f3cdf0SGordon Ross 	status = acpica_parse_PRW(&prw_buf, &prw);
72026f3cdf0SGordon Ross 	if (ACPI_FAILURE(status))
72126f3cdf0SGordon Ross 		goto done;
72226f3cdf0SGordon Ross 
72326f3cdf0SGordon Ross 	rv = -1;
72426f3cdf0SGordon Ross 	if (level == 0) {
72526f3cdf0SGordon Ross 		status = AcpiDisableGpe(prw.prw_gpeobj, prw.prw_gpebit);
72626f3cdf0SGordon Ross 		if (ACPI_FAILURE(status))
72726f3cdf0SGordon Ross 			goto done;
72826f3cdf0SGordon Ross 	} else if (prw.prw_level >= level) {
72926f3cdf0SGordon Ross 		status = AcpiSetGpeWakeMask(prw.prw_gpeobj, prw.prw_gpebit,
73026f3cdf0SGordon Ross 		    ACPI_GPE_ENABLE);
73126f3cdf0SGordon Ross 		if (ACPI_SUCCESS(status)) {
73226f3cdf0SGordon Ross 			status = AcpiEnableGpe(prw.prw_gpeobj, prw.prw_gpebit);
73326f3cdf0SGordon Ross 			if (ACPI_FAILURE(status))
7342df1fe9cSrandyf 				goto done;
7352df1fe9cSrandyf 		}
73626f3cdf0SGordon Ross 	}
73726f3cdf0SGordon Ross 	rv = 0;
73826f3cdf0SGordon Ross done:
73926f3cdf0SGordon Ross 	if (prw_buf.Pointer != NULL)
74026f3cdf0SGordon Ross 		AcpiOsFree(prw_buf.Pointer);
74126f3cdf0SGordon Ross 	return (rv);
74226f3cdf0SGordon Ross }
74326f3cdf0SGordon Ross 
74426f3cdf0SGordon Ross static ACPI_STATUS
acpica_parse_PRW(ACPI_BUFFER * prw_buf,struct parsed_prw * p_prw)74526f3cdf0SGordon Ross acpica_parse_PRW(
74626f3cdf0SGordon Ross 	ACPI_BUFFER	*prw_buf,
74726f3cdf0SGordon Ross 	struct parsed_prw *p_prw)
74826f3cdf0SGordon Ross {
74926f3cdf0SGordon Ross 	ACPI_HANDLE	gpeobj;
75026f3cdf0SGordon Ross 	ACPI_OBJECT	*prw, *gpe;
75126f3cdf0SGordon Ross 	int		gpebit, prw_level;
75226f3cdf0SGordon Ross 
75326f3cdf0SGordon Ross 	if (prw_buf->Length == 0 || prw_buf->Pointer == NULL)
75426f3cdf0SGordon Ross 		return (AE_NULL_OBJECT);
75526f3cdf0SGordon Ross 
75626f3cdf0SGordon Ross 	prw = prw_buf->Pointer;
75726f3cdf0SGordon Ross 	if (prw->Type != ACPI_TYPE_PACKAGE || prw->Package.Count < 2 ||
75826f3cdf0SGordon Ross 	    prw->Package.Elements[1].Type != ACPI_TYPE_INTEGER)
75926f3cdf0SGordon Ross 		return (AE_TYPE);
7602df1fe9cSrandyf 
7612df1fe9cSrandyf 	/* fetch the lowest wake level from the _PRW */
7622df1fe9cSrandyf 	prw_level = prw->Package.Elements[1].Integer.Value;
7632df1fe9cSrandyf 
7642df1fe9cSrandyf 	/*
7652df1fe9cSrandyf 	 * process the GPE description
7662df1fe9cSrandyf 	 */
7672df1fe9cSrandyf 	switch (prw->Package.Elements[0].Type) {
7682df1fe9cSrandyf 	case ACPI_TYPE_INTEGER:
7692df1fe9cSrandyf 		gpeobj = NULL;
7702df1fe9cSrandyf 		gpebit = prw->Package.Elements[0].Integer.Value;
7712df1fe9cSrandyf 		break;
7722df1fe9cSrandyf 	case ACPI_TYPE_PACKAGE:
7732df1fe9cSrandyf 		gpe = &prw->Package.Elements[0];
7742df1fe9cSrandyf 		if (gpe->Package.Count != 2 ||
7752df1fe9cSrandyf 		    gpe->Package.Elements[1].Type != ACPI_TYPE_INTEGER)
77626f3cdf0SGordon Ross 			return (AE_TYPE);
7772df1fe9cSrandyf 		gpeobj = gpe->Package.Elements[0].Reference.Handle;
7782df1fe9cSrandyf 		gpebit = gpe->Package.Elements[1].Integer.Value;
7792df1fe9cSrandyf 		if (gpeobj == NULL)
78026f3cdf0SGordon Ross 			return (AE_NULL_OBJECT);
78126f3cdf0SGordon Ross 		break;
7822df1fe9cSrandyf 	default:
78326f3cdf0SGordon Ross 		return (AE_TYPE);
7842df1fe9cSrandyf 	}
7852df1fe9cSrandyf 
78626f3cdf0SGordon Ross 	p_prw->prw_gpeobj = gpeobj;
78726f3cdf0SGordon Ross 	p_prw->prw_gpebit = gpebit;
78826f3cdf0SGordon Ross 	p_prw->prw_level  = prw_level;
78926f3cdf0SGordon Ross 
79026f3cdf0SGordon Ross 	return (AE_OK);
7912df1fe9cSrandyf }
7922df1fe9cSrandyf 
7932df1fe9cSrandyf /*
7942df1fe9cSrandyf  * kstat access to a limited set of ACPI propertis
7952df1fe9cSrandyf  */
7962df1fe9cSrandyf static void
acpica_init_kstats()7972df1fe9cSrandyf acpica_init_kstats()
7982df1fe9cSrandyf {
7992df1fe9cSrandyf 	ACPI_HANDLE	s3handle;
8002df1fe9cSrandyf 	ACPI_STATUS	status;
801db2bae30SDana Myers 	ACPI_TABLE_FADT	*fadt;
8022df1fe9cSrandyf 	kstat_named_t *knp;
8032df1fe9cSrandyf 
8042df1fe9cSrandyf 	/*
8052df1fe9cSrandyf 	 * Create a small set of named kstats; just return in the rare
8062df1fe9cSrandyf 	 * case of a failure, * in which case, the kstats won't be present.
8072df1fe9cSrandyf 	 */
8082df1fe9cSrandyf 	if ((acpica_ksp = kstat_create("acpi", 0, "acpi", "misc",
8092df1fe9cSrandyf 	    KSTAT_TYPE_NAMED, 2, 0)) == NULL)
8102df1fe9cSrandyf 		return;
8112df1fe9cSrandyf 
8122df1fe9cSrandyf 	/*
8132df1fe9cSrandyf 	 * initialize kstat 'S3' to reflect the presence of \_S3 in
8142df1fe9cSrandyf 	 * the ACPI namespace (1 = present, 0 = not present)
8152df1fe9cSrandyf 	 */
8162df1fe9cSrandyf 	knp = acpica_ksp->ks_data;
8172df1fe9cSrandyf 	knp->value.l = (AcpiGetHandle(NULL, "\\_S3", &s3handle) == AE_OK);
8182df1fe9cSrandyf 	kstat_named_init(knp, "S3", KSTAT_DATA_LONG);
8192df1fe9cSrandyf 	knp++;		/* advance to next named kstat */
8202df1fe9cSrandyf 
8212df1fe9cSrandyf 	/*
8222df1fe9cSrandyf 	 * initialize kstat 'preferred_pm_profile' to the value
8232df1fe9cSrandyf 	 * contained in the (always present) FADT
8242df1fe9cSrandyf 	 */
825db2bae30SDana Myers 	status = AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **)&fadt);
826db2bae30SDana Myers 	knp->value.l = (status == AE_OK) ? fadt->PreferredProfile : -1;
8272df1fe9cSrandyf 	kstat_named_init(knp, "preferred_pm_profile", KSTAT_DATA_LONG);
8282df1fe9cSrandyf 
8292df1fe9cSrandyf 	/*
8302df1fe9cSrandyf 	 * install the named kstats
8312df1fe9cSrandyf 	 */
8322df1fe9cSrandyf 	kstat_install(acpica_ksp);
8332df1fe9cSrandyf }
8342df1fe9cSrandyf 
8352df1fe9cSrandyf /*
8362df1fe9cSrandyf  * Attempt to save the current ACPI settings (_CRS) for the device
8372df1fe9cSrandyf  * which corresponds to the supplied devinfo node.  The settings are
8382df1fe9cSrandyf  * saved as a property on the dip.  If no ACPI object is found to be
8392df1fe9cSrandyf  * associated with the devinfo node, no action is taken and no error
8402df1fe9cSrandyf  * is reported.
8412df1fe9cSrandyf  */
8422df1fe9cSrandyf void
acpica_ddi_save_resources(dev_info_t * dip)8432df1fe9cSrandyf acpica_ddi_save_resources(dev_info_t *dip)
8442df1fe9cSrandyf {
8452df1fe9cSrandyf 	ACPI_HANDLE	devobj;
8462df1fe9cSrandyf 	ACPI_BUFFER	resbuf;
8472df1fe9cSrandyf 	int		ret;
8482df1fe9cSrandyf 
8492df1fe9cSrandyf 	resbuf.Length = ACPI_ALLOCATE_BUFFER;
8502df1fe9cSrandyf 	if (ACPI_FAILURE(acpica_get_handle(dip, &devobj)) ||
8512df1fe9cSrandyf 	    ACPI_FAILURE(AcpiGetCurrentResources(devobj, &resbuf)))
8522df1fe9cSrandyf 		return;
8532df1fe9cSrandyf 
8542df1fe9cSrandyf 	ret = ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
8552df1fe9cSrandyf 	    "acpi-crs", resbuf.Pointer, resbuf.Length);
8562df1fe9cSrandyf 
8572df1fe9cSrandyf 	ASSERT(ret == DDI_PROP_SUCCESS);
8582df1fe9cSrandyf 
8592df1fe9cSrandyf 	AcpiOsFree(resbuf.Pointer);
8602df1fe9cSrandyf }
8612df1fe9cSrandyf 
8622df1fe9cSrandyf /*
8632df1fe9cSrandyf  * If the supplied devinfo node has an ACPI settings property attached,
8642df1fe9cSrandyf  * restore them to the associated ACPI device using _SRS.  The property
8652df1fe9cSrandyf  * is deleted from the devinfo node afterward.
8662df1fe9cSrandyf  */
8672df1fe9cSrandyf void
acpica_ddi_restore_resources(dev_info_t * dip)8682df1fe9cSrandyf acpica_ddi_restore_resources(dev_info_t *dip)
8692df1fe9cSrandyf {
8702df1fe9cSrandyf 	ACPI_HANDLE	devobj;
8712df1fe9cSrandyf 	ACPI_BUFFER	resbuf;
8722df1fe9cSrandyf 	uchar_t		*propdata;
8732df1fe9cSrandyf 	uint_t		proplen;
8742df1fe9cSrandyf 
8752df1fe9cSrandyf 	if (ACPI_FAILURE(acpica_get_handle(dip, &devobj)))
8762df1fe9cSrandyf 		return;
8772df1fe9cSrandyf 
8782df1fe9cSrandyf 	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
8792df1fe9cSrandyf 	    "acpi-crs", &propdata, &proplen) != DDI_PROP_SUCCESS)
8802df1fe9cSrandyf 		return;
8812df1fe9cSrandyf 
8822df1fe9cSrandyf 	resbuf.Pointer = propdata;
8832df1fe9cSrandyf 	resbuf.Length = proplen;
8842df1fe9cSrandyf 	(void) AcpiSetCurrentResources(devobj, &resbuf);
8852df1fe9cSrandyf 	ddi_prop_free(propdata);
8860f1b305eSSeth Goldberg 	(void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "acpi-crs");
8872df1fe9cSrandyf }
8884cf02d40SSaurabh Misra 
8894cf02d40SSaurabh Misra void
acpi_reset_system(void)8904cf02d40SSaurabh Misra acpi_reset_system(void)
8914cf02d40SSaurabh Misra {
8924cf02d40SSaurabh Misra 	ACPI_STATUS status;
8934cf02d40SSaurabh Misra 	int ten;
8944cf02d40SSaurabh Misra 
8954cf02d40SSaurabh Misra 	status = AcpiReset();
8964cf02d40SSaurabh Misra 	if (status == AE_OK) {
8974cf02d40SSaurabh Misra 		/*
8984cf02d40SSaurabh Misra 		 * Wait up to 500 milliseconds for AcpiReset() to make its
8994cf02d40SSaurabh Misra 		 * way.
9004cf02d40SSaurabh Misra 		 */
9014cf02d40SSaurabh Misra 		ten = 50000;
9024cf02d40SSaurabh Misra 		while (ten-- > 0)
9034cf02d40SSaurabh Misra 			tenmicrosec();
9044cf02d40SSaurabh Misra 	}
9054cf02d40SSaurabh Misra }
906