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