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