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 }