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