1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
24 * Copyright 2016, Joyent, Inc.
25 */
26/*
27 * Copyright (c) 2009, Intel Corporation.
28 * All rights reserved.
29 */
30/*
31 * Solaris x86 ACPI CA services
32 */
33
34#include <sys/file.h>
35#include <sys/errno.h>
36#include <sys/conf.h>
37#include <sys/modctl.h>
38#include <sys/open.h>
39#include <sys/stat.h>
40#include <sys/spl.h>
41#include <sys/ddi.h>
42#include <sys/sunddi.h>
43#include <sys/esunddi.h>
44#include <sys/kstat.h>
45#include <sys/x86_archext.h>
46
47#include <sys/acpi/acpi.h>
48#include <sys/acpica.h>
49#include <sys/archsystm.h>
50
51/*
52 *
53 */
54static	struct modlmisc modlmisc = {
55	&mod_miscops,
56	"ACPI interpreter",
57};
58
59static	struct modlinkage modlinkage = {
60	MODREV_1,		/* MODREV_1 manual */
61	(void *)&modlmisc,	/* module linkage */
62	NULL,			/* list terminator */
63};
64
65/*
66 * Local prototypes
67 */
68
69struct parsed_prw {
70	ACPI_HANDLE	prw_gpeobj;
71	int		prw_gpebit;
72	int		prw_level;
73};
74
75static void	acpica_init_kstats(void);
76static ACPI_STATUS	acpica_init_PRW(
77	ACPI_HANDLE	hdl,
78	UINT32		lvl,
79	void		*ctxp,
80	void		**rvpp);
81
82static ACPI_STATUS	acpica_parse_PRW(
83	ACPI_BUFFER	*prw_buf,
84	struct parsed_prw *prw);
85
86/*
87 * Local data
88 */
89
90static kmutex_t	acpica_module_lock;
91static kstat_t	*acpica_ksp;
92
93/*
94 * State of acpica subsystem
95 * After successful initialization, will be ACPICA_INITIALIZED
96 */
97int acpica_init_state = ACPICA_NOT_INITIALIZED;
98
99void *AcpiGbl_DbBuffer;
100uint32_t AcpiGbl_DbConsoleDebugLevel;
101
102/*
103 * Following are set by acpica_process_user_options()
104 *
105 * acpica_enable = FALSE prevents initialization of ACPI CA
106 * completely
107 *
108 * acpi_init_level determines level of ACPI CA functionality
109 * enabled in acpica_init()
110 */
111int	acpica_enable;
112UINT32	acpi_init_level;
113
114/*
115 * Non-zero enables lax behavior with respect to some
116 * common ACPI BIOS issues; see ACPI CA documentation
117 * Setting this to zero causes ACPI CA to enforce strict
118 * compliance with ACPI specification
119 */
120int acpica_enable_interpreter_slack = 1;
121
122/*
123 * For non-DEBUG builds, set the ACPI CA debug level to 0
124 * to quiet chatty BIOS output into /var/adm/messages
125 * Field-patchable for diagnostic use.
126 */
127#ifdef  DEBUG
128int acpica_muzzle_debug_output = 0;
129#else
130int acpica_muzzle_debug_output = 1;
131#endif
132
133/*
134 * ACPI DDI hooks
135 */
136static int acpica_ddi_setwake(dev_info_t *dip, int level);
137
138int
139_init(void)
140{
141	int error = EBUSY;
142	int	status;
143	extern int (*acpi_fp_setwake)();
144	extern kmutex_t cpu_map_lock;
145
146	mutex_init(&acpica_module_lock, NULL, MUTEX_DRIVER, NULL);
147	mutex_init(&cpu_map_lock, NULL, MUTEX_SPIN,
148	    (ddi_iblock_cookie_t)ipltospl(DISP_LEVEL));
149
150	if ((error = mod_install(&modlinkage)) != 0) {
151		mutex_destroy(&acpica_module_lock);
152		goto load_error;
153	}
154
155	AcpiGbl_EnableInterpreterSlack = (acpica_enable_interpreter_slack != 0);
156
157	/* global ACPI CA initialization */
158	if (ACPI_FAILURE(status = AcpiInitializeSubsystem()))
159		cmn_err(CE_WARN, "!AcpiInitializeSubsystem failed: %d", status);
160
161	/* initialize table manager */
162	if (ACPI_FAILURE(status = AcpiInitializeTables(NULL, 0, 0)))
163		cmn_err(CE_WARN, "!AcpiInitializeTables failed: %d", status);
164
165	acpi_fp_setwake = acpica_ddi_setwake;
166
167load_error:
168	return (error);
169}
170
171int
172_info(struct modinfo *modinfop)
173{
174	return (mod_info(&modlinkage, modinfop));
175}
176
177int
178_fini(void)
179{
180	/*
181	 * acpica module is never unloaded at run-time; there's always
182	 * a PSM depending on it, at the very least
183	 */
184	return (EBUSY);
185}
186
187/*
188 * Install acpica-provided (default) address-space handlers
189 * that may be needed before AcpiEnableSubsystem() runs.
190 * See the comment in AcpiInstallAddressSpaceHandler().
191 * Default handlers for remaining address spaces are
192 * installed later, in AcpiEnableSubsystem.
193 */
194static int
195acpica_install_handlers()
196{
197	ACPI_STATUS	rv = AE_OK;
198	ACPI_STATUS	res;
199
200	/*
201	 * Install ACPI CA default handlers
202	 */
203	if ((res = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
204	    ACPI_ADR_SPACE_SYSTEM_MEMORY,
205	    ACPI_DEFAULT_HANDLER, NULL, NULL)) != AE_OK &&
206	    res != AE_SAME_HANDLER) {
207		cmn_err(CE_WARN, "!acpica: no default handler for"
208		    " system memory");
209		rv = AE_ERROR;
210	}
211
212	if ((res = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
213	    ACPI_ADR_SPACE_SYSTEM_IO,
214	    ACPI_DEFAULT_HANDLER, NULL, NULL)) != AE_OK &&
215	    res != AE_SAME_HANDLER) {
216		cmn_err(CE_WARN, "!acpica: no default handler for"
217		    " system I/O");
218		rv = AE_ERROR;
219	}
220
221	if ((res = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
222	    ACPI_ADR_SPACE_PCI_CONFIG,
223	    ACPI_DEFAULT_HANDLER, NULL, NULL)) != AE_OK &&
224	    res != AE_SAME_HANDLER) {
225		cmn_err(CE_WARN, "!acpica: no default handler for"
226		    " PCI Config");
227		rv = AE_ERROR;
228	}
229
230	if ((res = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
231	    ACPI_ADR_SPACE_DATA_TABLE,
232	    ACPI_DEFAULT_HANDLER, NULL, NULL)) != AE_OK &&
233	    res != AE_SAME_HANDLER) {
234		cmn_err(CE_WARN, "!acpica: no default handler for"
235		    " Data Table");
236		rv = AE_ERROR;
237	}
238
239	return (rv);
240}
241
242/*
243 * Find the BIOS date, and return TRUE if supplied
244 * date is same or later than the BIOS date, or FALSE
245 * if the BIOS date can't be fetched for any reason
246 */
247static int
248acpica_check_bios_date(int yy, int mm, int dd)
249{
250
251	char *datep;
252	int bios_year, bios_month, bios_day;
253
254	/* If firmware has no bios, skip the check */
255	if (ddi_prop_exists(DDI_DEV_T_ANY, ddi_root_node(), DDI_PROP_DONTPASS,
256	    "efi-systab"))
257		return (TRUE);
258
259	/*
260	 * PC BIOSes contain a string in the form of
261	 * "mm/dd/yy" at absolute address 0xffff5,
262	 * where mm, dd and yy are all ASCII digits.
263	 * We map the string, pluck out the values,
264	 * and accept all BIOSes from 1 Jan 1999 on
265	 * as valid.
266	 */
267
268	if ((datep = (char *)AcpiOsMapMemory(0xffff5, 8)) == NULL)
269		return (FALSE);
270
271	/* year */
272	bios_year = ((int)(*(datep + 6) - '0') * 10) + (*(datep + 7) - '0');
273	/* month */
274	bios_month = ((int)(*datep - '0') * 10) + (*(datep + 1) - '0');
275	/* day */
276	bios_day = ((int)(*(datep + 3) - '0') * 10) + (*(datep + 4) - '0');
277
278	AcpiOsUnmapMemory((void *) datep, 8);
279
280	if (bios_year < 0 || bios_year > 99 || bios_month < 0 ||
281	    bios_month > 99 || bios_day < 0 || bios_day > 99) {
282		/* non-digit chars in BIOS date */
283		return (FALSE);
284	}
285
286	/*
287	 * Adjust for 2-digit year; note to grand-children:
288	 * need a new scheme before 2080 rolls around
289	 */
290	bios_year += (bios_year >= 80 && bios_year <= 99) ?
291	    1900 : 2000;
292
293	if (bios_year < yy)
294		return (FALSE);
295	else if (bios_year > yy)
296		return (TRUE);
297
298	if (bios_month < mm)
299		return (FALSE);
300	else if (bios_month > mm)
301		return (TRUE);
302
303	if (bios_day < dd)
304		return (FALSE);
305
306	return (TRUE);
307}
308
309/*
310 * Check for Metropolis systems with BIOSes older than 10/12/04
311 * return TRUE if BIOS requires legacy mode, FALSE otherwise
312 */
313static int
314acpica_metro_old_bios()
315{
316	ACPI_TABLE_HEADER *fadt;
317
318	/* get the FADT */
319	if (AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **)&fadt) !=
320	    AE_OK)
321		return (FALSE);
322
323	/* compare OEM Table ID to "SUNmetro" - no match, return false */
324	if (strncmp("SUNmetro", fadt->OemTableId, 8))
325		return (FALSE);
326
327	/* On a Metro - return FALSE if later than 10/12/04 */
328	return (!acpica_check_bios_date(2004, 10, 12));
329}
330
331
332/*
333 * Process acpi-user-options property  if present
334 */
335static void
336acpica_process_user_options()
337{
338	static int processed = 0;
339	int acpi_user_options;
340	char *acpi_prop;
341
342	/*
343	 * return if acpi-user-options has already been processed
344	 */
345	if (processed)
346		return;
347	else
348		processed = 1;
349
350	/* converts acpi-user-options from type string to int, if any */
351	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
352	    DDI_PROP_DONTPASS, "acpi-user-options", &acpi_prop) ==
353	    DDI_PROP_SUCCESS) {
354		long data;
355		int ret;
356		ret = ddi_strtol(acpi_prop, NULL, 0, &data);
357		if (ret == 0) {
358			e_ddi_prop_remove(DDI_DEV_T_NONE, ddi_root_node(),
359			    "acpi-user-options");
360			e_ddi_prop_update_int(DDI_DEV_T_NONE, ddi_root_node(),
361			    "acpi-user-options", data);
362		}
363		ddi_prop_free(acpi_prop);
364	}
365
366	/*
367	 * fetch the optional options property
368	 */
369	acpi_user_options = ddi_prop_get_int(DDI_DEV_T_ANY, ddi_root_node(),
370	    DDI_PROP_DONTPASS, "acpi-user-options", 0);
371
372	/*
373	 * Note that 'off' has precedence over 'on'
374	 * Also note - all cases of ACPI_OUSER_MASK
375	 * provided here, no default: case is present
376	 */
377	switch (acpi_user_options & ACPI_OUSER_MASK) {
378	case ACPI_OUSER_DFLT:
379		acpica_enable = acpica_check_bios_date(1999, 1, 1);
380		break;
381	case ACPI_OUSER_ON:
382		acpica_enable = TRUE;
383		break;
384	case ACPI_OUSER_OFF:
385	case ACPI_OUSER_OFF | ACPI_OUSER_ON:
386		acpica_enable = FALSE;
387		break;
388	}
389
390	acpi_init_level = ACPI_FULL_INITIALIZATION;
391
392	/*
393	 * special test here; may be generalized in the
394	 * future - test for a machines that are known to
395	 * work only in legacy mode, and set OUSER_LEGACY if
396	 * we're on one
397	 */
398	if (acpica_metro_old_bios())
399		acpi_user_options |= ACPI_OUSER_LEGACY;
400
401	/*
402	 * If legacy mode is specified, set initialization
403	 * options to avoid entering ACPI mode and hooking SCI
404	 * - basically try to act like legacy acpi_intp
405	 */
406	if ((acpi_user_options & ACPI_OUSER_LEGACY) != 0)
407		acpi_init_level |= (ACPI_NO_ACPI_ENABLE | ACPI_NO_HANDLER_INIT);
408
409	/*
410	 * modify default ACPI CA debug output level for non-DEBUG builds
411	 * (to avoid BIOS debug chatter in /var/adm/messages)
412	 */
413	if (acpica_muzzle_debug_output)
414		AcpiDbgLevel = 0;
415}
416
417/*
418 * Initialize the CA subsystem if it hasn't been done already
419 */
420int
421acpica_init()
422{
423	extern void acpica_find_ioapics(void);
424	ACPI_STATUS status;
425
426	/*
427	 * Make sure user options are processed,
428	 * then fail to initialize if ACPI CA has been
429	 * disabled
430	 */
431	acpica_process_user_options();
432	if (!acpica_enable)
433		return (AE_ERROR);
434
435	mutex_enter(&acpica_module_lock);
436	if (acpica_init_state == ACPICA_INITIALIZED) {
437		mutex_exit(&acpica_module_lock);
438		return (AE_OK);
439	}
440
441	if (ACPI_FAILURE(status = AcpiLoadTables()))
442		goto error;
443
444	if (ACPI_FAILURE(status = acpica_install_handlers()))
445		goto error;
446
447	/*
448	 * Create ACPI-to-devinfo mapping now so _INI and _STA
449	 * methods can access PCI config space when needed
450	 */
451	scan_d2a_map();
452
453	if (ACPI_FAILURE(status = AcpiEnableSubsystem(acpi_init_level)))
454		goto error;
455
456	/* do after AcpiEnableSubsystem() so GPEs are initialized */
457	acpica_ec_init();	/* initialize EC if present */
458
459	/* This runs all device _STA and _INI methods. */
460	if (ACPI_FAILURE(status = AcpiInitializeObjects(0)))
461		goto error;
462
463	acpica_init_state = ACPICA_INITIALIZED;
464
465	/*
466	 * [ACPI, sec. 4.4.1.1]
467	 * As of ACPICA version 20101217 (December 2010), the _PRW methods
468	 * (Power Resources for Wake) are no longer automatically executed
469	 * as part of the ACPICA initialization.  The OS must do this.
470	 */
471	(void) AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
472	    UINT32_MAX, acpica_init_PRW, NULL, NULL, NULL);
473	(void) AcpiUpdateAllGpes();
474
475	/*
476	 * If we are running on the Xen hypervisor as dom0 we need to
477	 * find the ioapics so we can prevent ACPI from trying to
478	 * access them.
479	 */
480	if (get_hwenv() == HW_XEN_PV && is_controldom())
481		acpica_find_ioapics();
482	acpica_init_kstats();
483error:
484	if (acpica_init_state != ACPICA_INITIALIZED) {
485		cmn_err(CE_NOTE, "!failed to initialize ACPI services");
486	}
487
488	/*
489	 * Set acpi-status to 13 if acpica has been initialized successfully.
490	 * This indicates that acpica is up and running.  This variable name
491	 * and value were chosen in order to remain compatible with acpi_intp.
492	 */
493	e_ddi_prop_update_int(DDI_DEV_T_NONE, ddi_root_node(), "acpi-status",
494	    (ACPI_SUCCESS(status)) ? (ACPI_BOOT_INIT | ACPI_BOOT_ENABLE |
495	    ACPI_BOOT_BOOTCONF) : 0);
496
497	/* Mark acpica subsystem as fully initialized. */
498	if (ACPI_SUCCESS(status) &&
499	    acpi_init_level == ACPI_FULL_INITIALIZATION) {
500		acpica_set_core_feature(ACPI_FEATURE_FULL_INIT);
501	}
502
503	mutex_exit(&acpica_module_lock);
504	return (status);
505}
506
507/*
508 * SCI handling
509 */
510
511ACPI_STATUS
512acpica_get_sci(int *sci_irq, iflag_t *sci_flags)
513{
514	ACPI_SUBTABLE_HEADER		*ap;
515	ACPI_TABLE_MADT			*mat;
516	ACPI_MADT_INTERRUPT_OVERRIDE	*mio;
517	ACPI_TABLE_FADT			*fadt;
518	int			madt_seen, madt_size;
519
520
521	/*
522	 * Make sure user options are processed,
523	 * then return error if ACPI CA has been
524	 * disabled or system is not running in ACPI
525	 * and won't need/understand SCI
526	 */
527	acpica_process_user_options();
528	if ((!acpica_enable) || (acpi_init_level & ACPI_NO_ACPI_ENABLE))
529		return (AE_ERROR);
530
531	/*
532	 * according to Intel ACPI developers, SCI
533	 * conforms to PCI bus conventions; level/low
534	 * unless otherwise directed by overrides.
535	 */
536	sci_flags->intr_el = INTR_EL_LEVEL;
537	sci_flags->intr_po = INTR_PO_ACTIVE_LOW;
538	sci_flags->bustype = BUS_PCI;	/*  we *do* conform to PCI */
539
540	/* get the SCI from the FADT */
541	if (AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **)&fadt) !=
542	    AE_OK)
543		return (AE_ERROR);
544
545	*sci_irq = fadt->SciInterrupt;
546
547	/* search for ISOs that modify it */
548	/* if we don't find a MADT, that's OK; no ISOs then */
549	if (AcpiGetTable(ACPI_SIG_MADT, 1, (ACPI_TABLE_HEADER **) &mat) !=
550	    AE_OK)
551		return (AE_OK);
552
553	ap = (ACPI_SUBTABLE_HEADER *) (mat + 1);
554	madt_size = mat->Header.Length;
555	madt_seen = sizeof (*mat);
556
557	while (madt_seen < madt_size) {
558		switch (ap->Type) {
559		case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE:
560			mio = (ACPI_MADT_INTERRUPT_OVERRIDE *) ap;
561			if (mio->SourceIrq == *sci_irq) {
562				*sci_irq = mio->GlobalIrq;
563				sci_flags->intr_el = (mio->IntiFlags &
564				    ACPI_MADT_TRIGGER_MASK) >> 2;
565				sci_flags->intr_po = mio->IntiFlags &
566				    ACPI_MADT_POLARITY_MASK;
567			}
568			break;
569		}
570
571		/* advance to next entry */
572		madt_seen += ap->Length;
573		ap = (ACPI_SUBTABLE_HEADER *)(((char *)ap) + ap->Length);
574	}
575
576	/*
577	 * One more check; if ISO said "conform", revert to default
578	 */
579	if (sci_flags->intr_el == INTR_EL_CONFORM)
580		sci_flags->intr_el = INTR_EL_LEVEL;
581	if (sci_flags->intr_po == INTR_PO_CONFORM)
582		sci_flags->intr_po = INTR_PO_ACTIVE_LOW;
583
584	return (AE_OK);
585}
586
587/*
588 * Call-back function used for _PRW initialization.  For every
589 * device node that has a _PRW method, evaluate, parse, and do
590 * AcpiSetupGpeForWake().
591 */
592static ACPI_STATUS
593acpica_init_PRW(
594	ACPI_HANDLE	devhdl,
595	UINT32		depth,
596	void		*ctxp,
597	void		**rvpp)
598{
599	ACPI_STATUS	status;
600	ACPI_BUFFER	prw_buf;
601	struct parsed_prw prw;
602
603	prw_buf.Pointer = NULL;
604	prw_buf.Length = ACPI_ALLOCATE_BUFFER;
605
606	/*
607	 * Attempt to evaluate _PRW object.
608	 * If no valid object is found, return quietly, since not all
609	 * devices have _PRW objects.
610	 */
611	status = AcpiEvaluateObject(devhdl, "_PRW", NULL, &prw_buf);
612	if (ACPI_FAILURE(status))
613		goto done;
614	status = acpica_parse_PRW(&prw_buf, &prw);
615	if (ACPI_FAILURE(status))
616		goto done;
617
618	(void) AcpiSetupGpeForWake(devhdl,
619	    prw.prw_gpeobj, prw.prw_gpebit);
620
621done:
622	if (prw_buf.Pointer != NULL)
623		AcpiOsFree(prw_buf.Pointer);
624
625	return (AE_OK);
626}
627
628/*
629 * Sets ACPI wake state for device referenced by dip.
630 * If level is S0 (0), disables wake event; otherwise,
631 * enables wake event which will wake system from level.
632 */
633static int
634acpica_ddi_setwake(dev_info_t *dip, int level)
635{
636	ACPI_STATUS	status;
637	ACPI_HANDLE	devobj;
638	ACPI_BUFFER	prw_buf;
639	ACPI_OBJECT_LIST	arglist;
640	ACPI_OBJECT		args[3];
641	struct parsed_prw prw;
642	int		rv;
643
644	/*
645	 * initialize these early so we can use a common
646	 * exit point below
647	 */
648	prw_buf.Pointer = NULL;
649	prw_buf.Length = ACPI_ALLOCATE_BUFFER;
650	rv = 0;
651
652	/*
653	 * Attempt to get a handle to a corresponding ACPI object.
654	 * If no object is found, return quietly, since not all
655	 * devices have corresponding ACPI objects.
656	 */
657	status = acpica_get_handle(dip, &devobj);
658	if (ACPI_FAILURE(status)) {
659		char pathbuf[MAXPATHLEN];
660		ddi_pathname(dip, pathbuf);
661#ifdef DEBUG
662		cmn_err(CE_NOTE, "!acpica_ddi_setwake: could not get"
663		    " handle for %s, %s:%d", pathbuf, ddi_driver_name(dip),
664		    ddi_get_instance(dip));
665#endif
666		goto done;
667	}
668
669	/*
670	 * ACPI3.0 7.2.1: only use the _PSW method if OSPM does not support
671	 * _DSW or if the _DSW method is not present.
672	 *
673	 * _DSW arguments:
674	 * args[0] - Enable/Disable
675	 * args[1] - Target system state
676	 * args[2] - Target device state
677	 */
678
679	arglist.Count = 3;
680	arglist.Pointer = args;
681	args[0].Type = ACPI_TYPE_INTEGER;
682	args[0].Integer.Value = level ? 1 : 0;
683	args[1].Type = ACPI_TYPE_INTEGER;
684	args[1].Integer.Value = level;
685	args[2].Type = ACPI_TYPE_INTEGER;
686	args[2].Integer.Value = level;
687	if (ACPI_FAILURE(status = AcpiEvaluateObject(devobj, "_DSW",
688	    &arglist, NULL))) {
689
690		if (status == AE_NOT_FOUND) {
691			arglist.Count = 1;
692			args[0].Type = ACPI_TYPE_INTEGER;
693			args[0].Integer.Value = level ? 1 : 0;
694
695			if (ACPI_FAILURE(status = AcpiEvaluateObject(devobj,
696			    "_PSW", &arglist, NULL))) {
697
698				if (status != AE_NOT_FOUND) {
699					cmn_err(CE_NOTE,
700					    "!_PSW failure %d for device %s",
701					    status, ddi_driver_name(dip));
702				}
703			}
704
705		} else {
706			cmn_err(CE_NOTE, "!_DSW failure %d for device %s",
707			    status, ddi_driver_name(dip));
708		}
709	}
710
711	/*
712	 * Attempt to evaluate _PRW object.
713	 * If no valid object is found, return quietly, since not all
714	 * devices have _PRW objects.
715	 */
716	status = AcpiEvaluateObject(devobj, "_PRW", NULL, &prw_buf);
717	if (ACPI_FAILURE(status))
718		goto done;
719	status = acpica_parse_PRW(&prw_buf, &prw);
720	if (ACPI_FAILURE(status))
721		goto done;
722
723	rv = -1;
724	if (level == 0) {
725		status = AcpiDisableGpe(prw.prw_gpeobj, prw.prw_gpebit);
726		if (ACPI_FAILURE(status))
727			goto done;
728	} else if (prw.prw_level >= level) {
729		status = AcpiSetGpeWakeMask(prw.prw_gpeobj, prw.prw_gpebit,
730		    ACPI_GPE_ENABLE);
731		if (ACPI_SUCCESS(status)) {
732			status = AcpiEnableGpe(prw.prw_gpeobj, prw.prw_gpebit);
733			if (ACPI_FAILURE(status))
734				goto done;
735		}
736	}
737	rv = 0;
738done:
739	if (prw_buf.Pointer != NULL)
740		AcpiOsFree(prw_buf.Pointer);
741	return (rv);
742}
743
744static ACPI_STATUS
745acpica_parse_PRW(
746	ACPI_BUFFER	*prw_buf,
747	struct parsed_prw *p_prw)
748{
749	ACPI_HANDLE	gpeobj;
750	ACPI_OBJECT	*prw, *gpe;
751	int		gpebit, prw_level;
752
753	if (prw_buf->Length == 0 || prw_buf->Pointer == NULL)
754		return (AE_NULL_OBJECT);
755
756	prw = prw_buf->Pointer;
757	if (prw->Type != ACPI_TYPE_PACKAGE || prw->Package.Count < 2 ||
758	    prw->Package.Elements[1].Type != ACPI_TYPE_INTEGER)
759		return (AE_TYPE);
760
761	/* fetch the lowest wake level from the _PRW */
762	prw_level = prw->Package.Elements[1].Integer.Value;
763
764	/*
765	 * process the GPE description
766	 */
767	switch (prw->Package.Elements[0].Type) {
768	case ACPI_TYPE_INTEGER:
769		gpeobj = NULL;
770		gpebit = prw->Package.Elements[0].Integer.Value;
771		break;
772	case ACPI_TYPE_PACKAGE:
773		gpe = &prw->Package.Elements[0];
774		if (gpe->Package.Count != 2 ||
775		    gpe->Package.Elements[1].Type != ACPI_TYPE_INTEGER)
776			return (AE_TYPE);
777		gpeobj = gpe->Package.Elements[0].Reference.Handle;
778		gpebit = gpe->Package.Elements[1].Integer.Value;
779		if (gpeobj == NULL)
780			return (AE_NULL_OBJECT);
781		break;
782	default:
783		return (AE_TYPE);
784	}
785
786	p_prw->prw_gpeobj = gpeobj;
787	p_prw->prw_gpebit = gpebit;
788	p_prw->prw_level  = prw_level;
789
790	return (AE_OK);
791}
792
793/*
794 * kstat access to a limited set of ACPI propertis
795 */
796static void
797acpica_init_kstats()
798{
799	ACPI_HANDLE	s3handle;
800	ACPI_STATUS	status;
801	ACPI_TABLE_FADT	*fadt;
802	kstat_named_t *knp;
803
804	/*
805	 * Create a small set of named kstats; just return in the rare
806	 * case of a failure, * in which case, the kstats won't be present.
807	 */
808	if ((acpica_ksp = kstat_create("acpi", 0, "acpi", "misc",
809	    KSTAT_TYPE_NAMED, 2, 0)) == NULL)
810		return;
811
812	/*
813	 * initialize kstat 'S3' to reflect the presence of \_S3 in
814	 * the ACPI namespace (1 = present, 0 = not present)
815	 */
816	knp = acpica_ksp->ks_data;
817	knp->value.l = (AcpiGetHandle(NULL, "\\_S3", &s3handle) == AE_OK);
818	kstat_named_init(knp, "S3", KSTAT_DATA_LONG);
819	knp++;		/* advance to next named kstat */
820
821	/*
822	 * initialize kstat 'preferred_pm_profile' to the value
823	 * contained in the (always present) FADT
824	 */
825	status = AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **)&fadt);
826	knp->value.l = (status == AE_OK) ? fadt->PreferredProfile : -1;
827	kstat_named_init(knp, "preferred_pm_profile", KSTAT_DATA_LONG);
828
829	/*
830	 * install the named kstats
831	 */
832	kstat_install(acpica_ksp);
833}
834
835/*
836 * Attempt to save the current ACPI settings (_CRS) for the device
837 * which corresponds to the supplied devinfo node.  The settings are
838 * saved as a property on the dip.  If no ACPI object is found to be
839 * associated with the devinfo node, no action is taken and no error
840 * is reported.
841 */
842void
843acpica_ddi_save_resources(dev_info_t *dip)
844{
845	ACPI_HANDLE	devobj;
846	ACPI_BUFFER	resbuf;
847	int		ret;
848
849	resbuf.Length = ACPI_ALLOCATE_BUFFER;
850	if (ACPI_FAILURE(acpica_get_handle(dip, &devobj)) ||
851	    ACPI_FAILURE(AcpiGetCurrentResources(devobj, &resbuf)))
852		return;
853
854	ret = ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
855	    "acpi-crs", resbuf.Pointer, resbuf.Length);
856
857	ASSERT(ret == DDI_PROP_SUCCESS);
858
859	AcpiOsFree(resbuf.Pointer);
860}
861
862/*
863 * If the supplied devinfo node has an ACPI settings property attached,
864 * restore them to the associated ACPI device using _SRS.  The property
865 * is deleted from the devinfo node afterward.
866 */
867void
868acpica_ddi_restore_resources(dev_info_t *dip)
869{
870	ACPI_HANDLE	devobj;
871	ACPI_BUFFER	resbuf;
872	uchar_t		*propdata;
873	uint_t		proplen;
874
875	if (ACPI_FAILURE(acpica_get_handle(dip, &devobj)))
876		return;
877
878	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
879	    "acpi-crs", &propdata, &proplen) != DDI_PROP_SUCCESS)
880		return;
881
882	resbuf.Pointer = propdata;
883	resbuf.Length = proplen;
884	(void) AcpiSetCurrentResources(devobj, &resbuf);
885	ddi_prop_free(propdata);
886	(void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "acpi-crs");
887}
888
889void
890acpi_reset_system(void)
891{
892	ACPI_STATUS status;
893	int ten;
894
895	status = AcpiReset();
896	if (status == AE_OK) {
897		/*
898		 * Wait up to 500 milliseconds for AcpiReset() to make its
899		 * way.
900		 */
901		ten = 50000;
902		while (ten-- > 0)
903			tenmicrosec();
904	}
905}
906