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