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
_init(void)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
_info(struct modinfo * modinfop)152 _info(struct modinfo *modinfop)
153 {
154 return (mod_info(&modlinkage, modinfop));
155 }
156
157 int
_fini(void)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
acpica_install_handlers()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
acpica_check_bios_date(int yy,int mm,int dd)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
acpica_metro_old_bios()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
acpica_process_user_options()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
acpica_init()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
acpica_get_sci(int * sci_irq,iflag_t * sci_flags)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
acpica_ddi_setwake(dev_info_t * dip,int level)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
acpica_init_kstats()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
acpica_ddi_save_resources(dev_info_t * dip)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
acpica_ddi_restore_resources(dev_info_t * dip)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
acpi_reset_system(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