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