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