acpi.c revision 1.53
1/* $NetBSD: acpi.c,v 1.53 2003/11/01 20:58:33 mycroft Exp $ */ 2 3/*- 4 * Copyright (c) 2003 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Charles M. Hannum of By Noon Software, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39/* 40 * Copyright 2001, 2003 Wasabi Systems, Inc. 41 * All rights reserved. 42 * 43 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 44 * 45 * Redistribution and use in source and binary forms, with or without 46 * modification, are permitted provided that the following conditions 47 * are met: 48 * 1. Redistributions of source code must retain the above copyright 49 * notice, this list of conditions and the following disclaimer. 50 * 2. Redistributions in binary form must reproduce the above copyright 51 * notice, this list of conditions and the following disclaimer in the 52 * documentation and/or other materials provided with the distribution. 53 * 3. All advertising materials mentioning features or use of this software 54 * must display the following acknowledgement: 55 * This product includes software developed for the NetBSD Project by 56 * Wasabi Systems, Inc. 57 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 58 * or promote products derived from this software without specific prior 59 * written permission. 60 * 61 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 62 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 63 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 64 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 65 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 66 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 67 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 68 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 69 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 70 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 71 * POSSIBILITY OF SUCH DAMAGE. 72 */ 73 74/* 75 * Autoconfiguration support for the Intel ACPI Component Architecture 76 * ACPI reference implementation. 77 */ 78 79#include <sys/cdefs.h> 80__KERNEL_RCSID(0, "$NetBSD: acpi.c,v 1.53 2003/11/01 20:58:33 mycroft Exp $"); 81 82#include "opt_acpi.h" 83 84#include <sys/param.h> 85#include <sys/systm.h> 86#include <sys/device.h> 87#include <sys/malloc.h> 88#include <sys/kernel.h> 89#include <sys/proc.h> 90 91#include <dev/acpi/acpica.h> 92#include <dev/acpi/acpireg.h> 93#include <dev/acpi/acpivar.h> 94#include <dev/acpi/acpi_osd.h> 95#ifdef ACPIVERBOSE 96#include <dev/acpi/acpidevs_data.h> 97#endif 98 99#ifdef ACPI_PCI_FIXUP 100#include <dev/acpi/acpica/Subsystem/acnamesp.h> /* AcpiNsGetNodeByPath() */ 101#include <dev/pci/pcidevs.h> 102#endif 103 104MALLOC_DECLARE(M_ACPI); 105 106#include <machine/acpi_machdep.h> 107 108#ifdef ACPI_DEBUGGER 109#define ACPI_DBGR_INIT 0x01 110#define ACPI_DBGR_TABLES 0x02 111#define ACPI_DBGR_ENABLE 0x04 112#define ACPI_DBGR_PROBE 0x08 113#define ACPI_DBGR_RUNNING 0x10 114 115int acpi_dbgr = 0x00; 116#endif 117 118int acpi_match(struct device *, struct cfdata *, void *); 119void acpi_attach(struct device *, struct device *, void *); 120 121int acpi_print(void *aux, const char *); 122 123extern struct cfdriver acpi_cd; 124 125CFATTACH_DECL(acpi, sizeof(struct acpi_softc), 126 acpi_match, acpi_attach, NULL, NULL); 127 128/* 129 * This is a flag we set when the ACPI subsystem is active. Machine 130 * dependent code may wish to skip other steps (such as attaching 131 * subsystems that ACPI supercedes) when ACPI is active. 132 */ 133int acpi_active; 134 135/* 136 * Pointer to the ACPI subsystem's state. There can be only 137 * one ACPI instance. 138 */ 139struct acpi_softc *acpi_softc; 140 141/* 142 * Locking stuff. 143 */ 144static struct simplelock acpi_slock; 145static int acpi_locked; 146 147/* 148 * Prototypes. 149 */ 150void acpi_shutdown(void *); 151ACPI_STATUS acpi_disable(struct acpi_softc *sc); 152void acpi_build_tree(struct acpi_softc *); 153ACPI_STATUS acpi_make_devnode(ACPI_HANDLE, UINT32, void *, void **); 154 155void acpi_enable_fixed_events(struct acpi_softc *); 156#ifdef ACPI_PCI_FIXUP 157void acpi_pci_fixup(struct acpi_softc *); 158#endif 159#if defined(ACPI_PCI_FIXUP) || defined(ACPI_ACTIVATE_DEV) 160ACPI_STATUS acpi_allocate_resources(ACPI_HANDLE handle); 161#endif 162 163/* 164 * acpi_probe: 165 * 166 * Probe for ACPI support. This is called by the 167 * machine-dependent ACPI front-end. All of the 168 * actual work is done by ACPICA. 169 * 170 * NOTE: This is not an autoconfiguration interface function. 171 */ 172int 173acpi_probe(void) 174{ 175 static int beenhere; 176 ACPI_STATUS rv; 177 178 if (beenhere != 0) 179 panic("acpi_probe: ACPI has already been probed"); 180 beenhere = 1; 181 182 simple_lock_init(&acpi_slock); 183 acpi_locked = 0; 184 185 /* 186 * Start up ACPICA. 187 */ 188#ifdef ACPI_DEBUGGER 189 if (acpi_dbgr & ACPI_DBGR_INIT) 190 acpi_osd_debugger(); 191#endif 192 193 rv = AcpiInitializeSubsystem(); 194 if (rv != AE_OK) { 195 printf("ACPI: unable to initialize ACPICA: %d\n", rv); 196 return (0); 197 } 198 199#ifdef ACPI_DEBUGGER 200 if (acpi_dbgr & ACPI_DBGR_TABLES) 201 acpi_osd_debugger(); 202#endif 203 204 rv = AcpiLoadTables(); 205 if (rv != AE_OK) { 206 printf("ACPI: unable to load tables: %d\n", rv); 207 return (0); 208 } 209 210 /* 211 * Looks like we have ACPI! 212 */ 213 214 return (1); 215} 216 217/* 218 * acpi_match: 219 * 220 * Autoconfiguration `match' routine. 221 */ 222int 223acpi_match(struct device *parent, struct cfdata *match, void *aux) 224{ 225 struct acpibus_attach_args *aa = aux; 226 227 if (strcmp(aa->aa_busname, acpi_cd.cd_name) != 0) 228 return (0); 229 230 /* 231 * XXX Check other locators? Hard to know -- machine 232 * dependent code has already checked for the presence 233 * of ACPI by calling acpi_probe(), so I suppose we 234 * don't really have to do anything else. 235 */ 236 return (1); 237} 238 239/* 240 * acpi_attach: 241 * 242 * Autoconfiguration `attach' routine. Finish initializing 243 * ACPICA (some initialization was done in acpi_probe(), 244 * which was required to check for the presence of ACPI), 245 * and enable the ACPI subsystem. 246 */ 247void 248acpi_attach(struct device *parent, struct device *self, void *aux) 249{ 250 struct acpi_softc *sc = (void *) self; 251 struct acpibus_attach_args *aa = aux; 252 ACPI_STATUS rv; 253 254 printf("\n"); 255 256 if (acpi_softc != NULL) 257 panic("acpi_attach: ACPI has already been attached"); 258 259 sysmon_power_settype("acpi"); 260 261 printf("%s: using Intel ACPI CA subsystem version %08x\n", 262 sc->sc_dev.dv_xname, ACPI_CA_VERSION); 263 264 printf("%s: X/RSDT: OemId <%6.6s,%8.8s,%08x>, AslId <%4.4s,%08x>\n", 265 sc->sc_dev.dv_xname, 266 AcpiGbl_XSDT->OemId, AcpiGbl_XSDT->OemTableId, 267 AcpiGbl_XSDT->OemRevision, 268 AcpiGbl_XSDT->AslCompilerId, AcpiGbl_XSDT->AslCompilerRevision); 269 270 sc->sc_quirks = acpi_find_quirks(); 271 272 sc->sc_iot = aa->aa_iot; 273 sc->sc_memt = aa->aa_memt; 274 sc->sc_pc = aa->aa_pc; 275 sc->sc_pciflags = aa->aa_pciflags; 276 sc->sc_ic = aa->aa_ic; 277 278 acpi_softc = sc; 279 280 /* 281 * Bring ACPI on-line. 282 */ 283#ifdef ACPI_DEBUGGER 284 if (acpi_dbgr & ACPI_DBGR_ENABLE) 285 acpi_osd_debugger(); 286#endif 287 288 rv = AcpiEnableSubsystem(0); 289 if (rv != AE_OK) { 290 printf("%s: unable to enable ACPI: %d\n", 291 sc->sc_dev.dv_xname, rv); 292 return; 293 } 294 rv = AcpiInitializeObjects(0); 295 if (rv != AE_OK) { 296 printf("%s: unable to initialize ACPI objects: %d\n", 297 sc->sc_dev.dv_xname, rv); 298 return; 299 } 300 acpi_active = 1; 301 302 /* Our current state is "awake". */ 303 sc->sc_sleepstate = ACPI_STATE_S0; 304 305 /* Show SCI interrupt. */ 306 if (AcpiGbl_FADT != NULL) 307 printf("%s: SCI interrupting at int %d\n", 308 sc->sc_dev.dv_xname, AcpiGbl_FADT->SciInt); 309 /* 310 * Check for fixed-hardware features. 311 */ 312 acpi_enable_fixed_events(sc); 313 314 /* 315 * Fix up PCI devices. 316 */ 317#ifdef ACPI_PCI_FIXUP 318 if ((sc->sc_quirks & (ACPI_QUIRK_BADPCI | ACPI_QUIRK_BADIRQ)) == 0) 319 acpi_pci_fixup(sc); 320#endif 321 322 /* 323 * Scan the namespace and build our device tree. 324 */ 325#ifdef ACPI_DEBUGGER 326 if (acpi_dbgr & ACPI_DBGR_PROBE) 327 acpi_osd_debugger(); 328#endif 329 acpi_md_callback((struct device *)sc); 330 acpi_build_tree(sc); 331 332 /* 333 * Register a shutdown hook that disables certain ACPI 334 * events that might happen and confuse us while we're 335 * trying to shut down. 336 */ 337 sc->sc_sdhook = shutdownhook_establish(acpi_shutdown, sc); 338 if (sc->sc_sdhook == NULL) 339 printf("%s: WARNING: unable to register shutdown hook\n", 340 sc->sc_dev.dv_xname); 341 342#ifdef ACPI_DEBUGGER 343 if (acpi_dbgr & ACPI_DBGR_RUNNING) 344 acpi_osd_debugger(); 345#endif 346} 347 348/* 349 * acpi_shutdown: 350 * 351 * Shutdown hook for ACPI -- disable some events that 352 * might confuse us. 353 */ 354void 355acpi_shutdown(void *arg) 356{ 357 struct acpi_softc *sc = arg; 358 359 if (acpi_disable(sc) != AE_OK) 360 printf("%s: WARNING: unable to disable ACPI\n", 361 sc->sc_dev.dv_xname); 362} 363 364/* 365 * acpi_disable: 366 * 367 * Disable ACPI. 368 */ 369ACPI_STATUS 370acpi_disable(struct acpi_softc *sc) 371{ 372 ACPI_STATUS rv = AE_OK; 373 374 if (acpi_active) { 375 rv = AcpiDisable(); 376 if (rv == AE_OK) 377 acpi_active = 0; 378 } 379 return (rv); 380} 381 382struct acpi_make_devnode_state { 383 struct acpi_softc *softc; 384 struct acpi_scope *scope; 385}; 386 387/* 388 * acpi_build_tree: 389 * 390 * Scan relevant portions of the ACPI namespace and attach 391 * child devices. 392 */ 393void 394acpi_build_tree(struct acpi_softc *sc) 395{ 396 static const char *scopes[] = { 397 "\\_PR_", /* ACPI 1.0 processor namespace */ 398 "\\_SB_", /* system bus namespace */ 399 "\\_SI_", /* system idicator namespace */ 400 "\\_TZ_", /* ACPI 1.0 thermal zone namespace */ 401 NULL, 402 }; 403 struct acpi_attach_args aa; 404 struct acpi_make_devnode_state state; 405 struct acpi_scope *as; 406 struct acpi_devnode *ad; 407 ACPI_HANDLE parent; 408 int i; 409 410 TAILQ_INIT(&sc->sc_scopes); 411 412 state.softc = sc; 413 414 /* 415 * Scan the namespace and build our tree. 416 */ 417 for (i = 0; scopes[i] != NULL; i++) { 418 as = malloc(sizeof(*as), M_ACPI, M_WAITOK); 419 as->as_name = scopes[i]; 420 TAILQ_INIT(&as->as_devnodes); 421 422 TAILQ_INSERT_TAIL(&sc->sc_scopes, as, as_list); 423 424 state.scope = as; 425 426 if (AcpiGetHandle(ACPI_ROOT_OBJECT, (char *) scopes[i], 427 &parent) == AE_OK) { 428 AcpiWalkNamespace(ACPI_TYPE_ANY, parent, 100, 429 acpi_make_devnode, &state, NULL); 430 } 431 432 /* Now, for this namespace, try and attach the devices. */ 433 TAILQ_FOREACH(ad, &as->as_devnodes, ad_list) { 434 aa.aa_node = ad; 435 aa.aa_iot = sc->sc_iot; 436 aa.aa_memt = sc->sc_memt; 437 aa.aa_pc = sc->sc_pc; 438 aa.aa_pciflags = sc->sc_pciflags; 439 aa.aa_ic = sc->sc_ic; 440 441 if (ad->ad_devinfo.Type == ACPI_TYPE_DEVICE) { 442 /* 443 * XXX We only attach devices which are: 444 * 445 * - present 446 * - enabled 447 * - functioning properly 448 * 449 * However, if enabled, it's decoding resources, 450 * so we should claim them, if possible. 451 * Requires changes to bus_space(9). 452 */ 453 if ((ad->ad_devinfo.Valid & ACPI_VALID_STA) == 454 ACPI_VALID_STA && 455 (ad->ad_devinfo.CurrentStatus & 456 (ACPI_STA_DEV_PRESENT|ACPI_STA_DEV_ENABLED| 457 ACPI_STA_DEV_OK)) != 458 (ACPI_STA_DEV_PRESENT|ACPI_STA_DEV_ENABLED| 459 ACPI_STA_DEV_OK)) 460 continue; 461 462 /* 463 * XXX Same problem as above... 464 */ 465 if ((ad->ad_devinfo.Valid & ACPI_VALID_HID) 466 == 0) 467 continue; 468 } 469 470 ad->ad_device = config_found(&sc->sc_dev, 471 &aa, acpi_print); 472 } 473 } 474} 475 476#ifdef ACPI_ACTIVATE_DEV 477static void 478acpi_activate_device(ACPI_HANDLE handle, ACPI_DEVICE_INFO *di) 479{ 480 ACPI_STATUS rv; 481 482#ifdef ACPI_DEBUG 483 ACPI_BUFFER buf; 484 485 printf("acpi_activate_device: %s, old status=%x\n", 486 di->HardwareId.Value, di->CurrentStatus); 487#endif 488 489 rv = acpi_allocate_resources(handle); 490 if (ACPI_FAILURE(rv)) { 491 printf("acpi: activate failed for %s\n", di->HardwareId.Value); 492 } else { 493 printf("acpi: activated %s\n", di->HardwareId.Value); 494 } 495 496#ifdef ACPI_DEBUG 497 buf.Pointer = di; 498 buf.Length = sizeof(*di); 499 (void)AcpiGetObjectInfo(handle, &buf); 500 printf("acpi_activate_device: %s, new status=%x\n", 501 di->HardwareId.Value, di->CurrentStatus); 502#endif 503} 504#endif /* ACPI_ACTIVATE_DEV */ 505 506/* 507 * acpi_make_devnode: 508 * 509 * Make an ACPI devnode. 510 */ 511ACPI_STATUS 512acpi_make_devnode(ACPI_HANDLE handle, UINT32 level, void *context, 513 void **status) 514{ 515 struct acpi_make_devnode_state *state = context; 516#if defined(ACPI_DEBUG) || defined(ACPI_EXTRA_DEBUG) 517 struct acpi_softc *sc = state->softc; 518#endif 519 struct acpi_scope *as = state->scope; 520 struct acpi_devnode *ad; 521 ACPI_OBJECT_TYPE type; 522 ACPI_BUFFER buf; 523 ACPI_DEVICE_INFO devinfo; 524 ACPI_STATUS rv; 525 526 if (AcpiGetType(handle, &type) == AE_OK) { 527 buf.Pointer = &devinfo; 528 buf.Length = sizeof(devinfo); 529 rv = AcpiGetObjectInfo(handle, &buf); 530 if (rv != AE_OK) { 531#ifdef ACPI_DEBUG 532 printf("%s: AcpiGetObjectInfo failed\n", 533 sc->sc_dev.dv_xname); 534#endif 535 goto out; /* XXX why return OK */ 536 } 537 538 switch (type) { 539 case ACPI_TYPE_DEVICE: 540#ifdef ACPI_ACTIVATE_DEV 541 if ((devinfo.Valid & (ACPI_VALID_STA|ACPI_VALID_HID)) == 542 (ACPI_VALID_STA|ACPI_VALID_HID) && 543 (devinfo.CurrentStatus & 544 (ACPI_STA_DEV_PRESENT|ACPI_STA_DEV_ENABLED)) == 545 ACPI_STA_DEV_PRESENT) { 546 acpi_activate_device(handle, &devinfo); 547 548 /* Update devinfo. */ 549 buf.Pointer = &devinfo; 550 buf.Length = sizeof(devinfo); 551 rv = AcpiGetObjectInfo(handle, &buf); 552 if (rv != AE_OK) 553 goto out; 554 } 555 556 /* FALLTHROUGH */ 557#endif 558 559 case ACPI_TYPE_PROCESSOR: 560 case ACPI_TYPE_THERMAL: 561 case ACPI_TYPE_POWER: 562 ad = malloc(sizeof(*ad), M_ACPI, M_NOWAIT|M_ZERO); 563 if (ad == NULL) 564 return (AE_NO_MEMORY); 565 566 ad->ad_devinfo = devinfo; 567 ad->ad_handle = handle; 568 ad->ad_level = level; 569 ad->ad_scope = as; 570 ad->ad_type = type; 571 572 TAILQ_INSERT_TAIL(&as->as_devnodes, ad, ad_list); 573 574 if ((ad->ad_devinfo.Valid & ACPI_VALID_HID) == 0) 575 goto out; 576 577#ifdef ACPI_EXTRA_DEBUG 578 printf("%s: HID %s found in scope %s level %d\n", 579 sc->sc_dev.dv_xname, ad->ad_devinfo.HardwareId.Value, 580 as->as_name, ad->ad_level); 581 if (ad->ad_devinfo.Valid & ACPI_VALID_UID) 582 printf(" UID %s\n", 583 ad->ad_devinfo.UniqueId.Value); 584 if (ad->ad_devinfo.Valid & ACPI_VALID_ADR) 585 printf(" ADR 0x%016qx\n", 586 ad->ad_devinfo.Address); 587 if (ad->ad_devinfo.Valid & ACPI_VALID_STA) 588 printf(" STA 0x%08x\n", 589 ad->ad_devinfo.CurrentStatus); 590#endif 591 } 592 } 593 out: 594 return (AE_OK); 595} 596 597/* 598 * acpi_print: 599 * 600 * Autoconfiguration print routine. 601 */ 602int 603acpi_print(void *aux, const char *pnp) 604{ 605 struct acpi_attach_args *aa = aux; 606 607 if (pnp) { 608 if (aa->aa_node->ad_devinfo.Valid & ACPI_VALID_HID) { 609 char *pnpstr = aa->aa_node->ad_devinfo.HardwareId.Value; 610 char *str; 611 612 aprint_normal("%s ", pnpstr); 613 if (acpi_eval_string(aa->aa_node->ad_handle, 614 "_STR", &str) == AE_OK) { 615 aprint_normal("[%s] ", str); 616 AcpiOsFree(str); 617 } 618#ifdef ACPIVERBOSE 619 else { 620 int i; 621 622 for (i = 0; i < sizeof(acpi_knowndevs) / 623 sizeof(acpi_knowndevs[0]); i++) { 624 if (strcmp(acpi_knowndevs[i].pnp, 625 pnpstr) == 0) { 626 printf("[%s] ", 627 acpi_knowndevs[i].str); 628 } 629 } 630 } 631 632#endif 633 } else { 634 aprint_normal("ACPI Object Type '%s' (0x%02x) ", 635 AcpiUtGetTypeName(aa->aa_node->ad_devinfo.Type), 636 aa->aa_node->ad_devinfo.Type); 637 } 638 aprint_normal("at %s", pnp); 639 } else { 640 if (aa->aa_node->ad_devinfo.Valid & ACPI_VALID_HID) { 641 aprint_normal(" (%s", aa->aa_node->ad_devinfo.HardwareId.Value); 642 if (aa->aa_node->ad_devinfo.Valid & ACPI_VALID_UID) { 643 char *uid; 644 645 uid = aa->aa_node->ad_devinfo.UniqueId.Value; 646 if (uid[0] == '\0') 647 uid = "<null>"; 648 aprint_normal("-%s", uid); 649 } 650 aprint_normal(")"); 651 } 652 } 653 654 return (UNCONF); 655} 656 657/***************************************************************************** 658 * ACPI fixed-hardware feature handlers 659 *****************************************************************************/ 660 661UINT32 acpi_fixed_button_handler(void *); 662void acpi_fixed_button_pressed(void *); 663 664/* 665 * acpi_enable_fixed_events: 666 * 667 * Enable any fixed-hardware feature handlers. 668 */ 669void 670acpi_enable_fixed_events(struct acpi_softc *sc) 671{ 672 static int beenhere; 673 ACPI_STATUS rv; 674 675 KASSERT(beenhere == 0); 676 beenhere = 1; 677 678 /* 679 * Check for fixed-hardware buttons. 680 */ 681 682 if (AcpiGbl_FADT != NULL && AcpiGbl_FADT->PwrButton == 0) { 683 printf("%s: fixed-feature power button present\n", 684 sc->sc_dev.dv_xname); 685 sc->sc_smpsw_power.smpsw_name = sc->sc_dev.dv_xname; 686 sc->sc_smpsw_power.smpsw_type = PSWITCH_TYPE_POWER; 687 if (sysmon_pswitch_register(&sc->sc_smpsw_power) != 0) { 688 printf("%s: unable to register fixed power button " 689 "with sysmon\n", sc->sc_dev.dv_xname); 690 } else { 691 rv = AcpiInstallFixedEventHandler( 692 ACPI_EVENT_POWER_BUTTON, 693 acpi_fixed_button_handler, &sc->sc_smpsw_power); 694 if (rv != AE_OK) { 695 printf("%s: unable to install handler for " 696 "fixed power button: %d\n", 697 sc->sc_dev.dv_xname, rv); 698 } 699 } 700 } 701 702 if (AcpiGbl_FADT != NULL && AcpiGbl_FADT->SleepButton == 0) { 703 printf("%s: fixed-feature sleep button present\n", 704 sc->sc_dev.dv_xname); 705 sc->sc_smpsw_sleep.smpsw_name = sc->sc_dev.dv_xname; 706 sc->sc_smpsw_sleep.smpsw_type = PSWITCH_TYPE_SLEEP; 707 if (sysmon_pswitch_register(&sc->sc_smpsw_power) != 0) { 708 printf("%s: unable to register fixed sleep button " 709 "with sysmon\n", sc->sc_dev.dv_xname); 710 } else { 711 rv = AcpiInstallFixedEventHandler( 712 ACPI_EVENT_SLEEP_BUTTON, 713 acpi_fixed_button_handler, &sc->sc_smpsw_sleep); 714 if (rv != AE_OK) { 715 printf("%s: unable to install handler for " 716 "fixed sleep button: %d\n", 717 sc->sc_dev.dv_xname, rv); 718 } 719 } 720 } 721} 722 723/* 724 * acpi_fixed_button_handler: 725 * 726 * Event handler for the fixed buttons. 727 */ 728UINT32 729acpi_fixed_button_handler(void *context) 730{ 731 struct sysmon_pswitch *smpsw = context; 732 int rv; 733 734#ifdef ACPI_BUT_DEBUG 735 printf("%s: fixed button handler\n", smpsw->smpsw_name); 736#endif 737 738 rv = AcpiOsQueueForExecution(OSD_PRIORITY_LO, 739 acpi_fixed_button_pressed, smpsw); 740 if (rv != AE_OK) 741 printf("%s: WARNING: unable to queue fixed button pressed " 742 "callback: %d\n", smpsw->smpsw_name, rv); 743 744 return (ACPI_INTERRUPT_HANDLED); 745} 746 747/* 748 * acpi_fixed_button_pressed: 749 * 750 * Deal with a fixed button being pressed. 751 */ 752void 753acpi_fixed_button_pressed(void *context) 754{ 755 struct sysmon_pswitch *smpsw = context; 756 757#ifdef ACPI_BUT_DEBUG 758 printf("%s: fixed button pressed, calling sysmon\n", 759 smpsw->smpsw_name); 760#endif 761 762 sysmon_pswitch_event(smpsw, PSWITCH_EVENT_PRESSED); 763} 764 765/***************************************************************************** 766 * ACPI utility routines. 767 *****************************************************************************/ 768 769/* 770 * acpi_eval_integer: 771 * 772 * Evaluate an integer object. 773 */ 774ACPI_STATUS 775acpi_eval_integer(ACPI_HANDLE handle, char *path, int *valp) 776{ 777 ACPI_STATUS rv; 778 ACPI_BUFFER buf; 779 ACPI_OBJECT param; 780 781 if (handle == NULL) 782 handle = ACPI_ROOT_OBJECT; 783 784 buf.Pointer = ¶m; 785 buf.Length = sizeof(param); 786 787 rv = AcpiEvaluateObjectTyped(handle, path, NULL, &buf, ACPI_TYPE_INTEGER); 788 if (rv == AE_OK) 789 *valp = param.Integer.Value; 790 791 return (rv); 792} 793 794/* 795 * acpi_eval_string: 796 * 797 * Evaluate a (Unicode) string object. 798 */ 799ACPI_STATUS 800acpi_eval_string(ACPI_HANDLE handle, char *path, char **stringp) 801{ 802 ACPI_STATUS rv; 803 ACPI_BUFFER buf; 804 805 if (handle == NULL) 806 handle = ACPI_ROOT_OBJECT; 807 808 buf.Pointer = NULL; 809 buf.Length = ACPI_ALLOCATE_BUFFER; 810 811 rv = AcpiEvaluateObjectTyped(handle, path, NULL, &buf, ACPI_TYPE_STRING); 812 if (rv == AE_OK) { 813 ACPI_OBJECT *param = buf.Pointer; 814 char *ptr = param->String.Pointer; 815 size_t len = param->String.Length; 816 if ((*stringp = AcpiOsAllocate(len)) == NULL) 817 rv = AE_NO_MEMORY; 818 else 819 (void)memcpy(*stringp, ptr, len); 820 AcpiOsFree(param); 821 } 822 823 return (rv); 824} 825 826 827/* 828 * acpi_eval_struct: 829 * 830 * Evaluate a more complex structure. 831 * Caller must free buf.Pointer by AcpiOsFree(). 832 */ 833ACPI_STATUS 834acpi_eval_struct(ACPI_HANDLE handle, char *path, ACPI_BUFFER *bufp) 835{ 836 ACPI_STATUS rv; 837 838 if (handle == NULL) 839 handle = ACPI_ROOT_OBJECT; 840 841 bufp->Pointer = NULL; 842 bufp->Length = ACPI_ALLOCATE_BUFFER; 843 844 rv = AcpiEvaluateObject(handle, path, NULL, bufp); 845 846 return (rv); 847} 848 849/* 850 * acpi_get: 851 * 852 * Fetch data info the specified (empty) ACPI buffer. 853 * Caller must free buf.Pointer by AcpiOsFree(). 854 */ 855ACPI_STATUS 856acpi_get(ACPI_HANDLE handle, ACPI_BUFFER *buf, 857 ACPI_STATUS (*getit)(ACPI_HANDLE, ACPI_BUFFER *)) 858{ 859 buf->Pointer = NULL; 860 buf->Length = ACPI_ALLOCATE_BUFFER; 861 862 return ((*getit)(handle, buf)); 863} 864 865 866/***************************************************************************** 867 * ACPI sleep support. 868 *****************************************************************************/ 869 870static int 871is_available_state(struct acpi_softc *sc, int state) 872{ 873 UINT8 type_a, type_b; 874 875 return (ACPI_SUCCESS(AcpiGetSleepTypeData((UINT8)state, 876 &type_a, &type_b))); 877} 878 879/* 880 * acpi_enter_sleep_state: 881 * 882 * enter to the specified sleep state. 883 */ 884 885ACPI_STATUS 886acpi_enter_sleep_state(struct acpi_softc *sc, int state) 887{ 888 int s; 889 ACPI_STATUS ret = AE_OK; 890 891 switch (state) { 892 case ACPI_STATE_S0: 893 break; 894 case ACPI_STATE_S1: 895 case ACPI_STATE_S2: 896 case ACPI_STATE_S3: 897 case ACPI_STATE_S4: 898 if (!is_available_state(sc, state)) { 899 printf("acpi: cannot enter the sleep state (%d).\n", 900 state); 901 break; 902 } 903 ret = AcpiEnterSleepStatePrep(state); 904 if (ACPI_FAILURE(ret)) { 905 printf("acpi: failed preparing to sleep (%s)\n", 906 AcpiFormatException(ret)); 907 break; 908 } 909 if (state==ACPI_STATE_S1) { 910 /* just enter the state */ 911 acpi_md_OsDisableInterrupt(); 912 AcpiEnterSleepState((UINT8)state); 913 AcpiUtReleaseMutex(ACPI_MTX_HARDWARE); 914 } else { 915 /* XXX: powerhooks(9) framework is too poor to 916 * support ACPI sleep state... 917 */ 918 dopowerhooks(PWR_SOFTSUSPEND); 919 s = splhigh(); 920 dopowerhooks(PWR_SUSPEND); 921 acpi_md_sleep(state); 922 dopowerhooks(PWR_RESUME); 923 splx(s); 924 dopowerhooks(PWR_SOFTRESUME); 925 if (state==ACPI_STATE_S4) 926 AcpiEnable(); 927 } 928 AcpiLeaveSleepState((UINT8)state); 929 break; 930 case ACPI_STATE_S5: 931 ret = AcpiEnterSleepStatePrep(ACPI_STATE_S5); 932 if (ACPI_FAILURE(ret)) { 933 printf("acpi: failed preparing to sleep (%s)\n", 934 AcpiFormatException(ret)); 935 break; 936 } 937 acpi_md_OsDisableInterrupt(); 938 AcpiEnterSleepState(ACPI_STATE_S5); 939 printf("WARNING: powerdown failed!\n"); 940 break; 941 } 942 943 return (ret); 944} 945 946#ifdef ACPI_PCI_FIXUP 947ACPI_STATUS acpi_pci_fixup_bus(ACPI_HANDLE, UINT32, void *, void **); 948/* 949 * acpi_pci_fixup: 950 * 951 * Set up PCI devices that BIOS didn't handle right. 952 * Iterate through all devices and try to get the _PTR 953 * (PCI Routing Table). If it exists then make sure all 954 * interrupt links that it uses are working. 955 */ 956void 957acpi_pci_fixup(struct acpi_softc *sc) 958{ 959 ACPI_HANDLE parent; 960 961#ifdef ACPI_DEBUG 962 printf("acpi_pci_fixup starts:\n"); 963#endif 964 if (AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &parent) != AE_OK) 965 return; 966 sc->sc_pci_bus = 0; 967 AcpiWalkNamespace(ACPI_TYPE_DEVICE, parent, 100, 968 acpi_pci_fixup_bus, sc, NULL); 969} 970 971static ACPI_HANDLE 972acpi_get_node(char *name) 973{ 974 ACPI_NAMESPACE_NODE *ObjDesc; 975 ACPI_STATUS Status; 976 977 Status = AcpiNsGetNodeByPath(name, NULL, 0, &ObjDesc); 978 if (ACPI_FAILURE (Status)) { 979 printf("acpi_get_node: could not find: %s\n", 980 AcpiFormatException (Status)); 981 return NULL; 982 } 983 return ObjDesc; 984} 985 986static uint 987acpi_get_intr(ACPI_HANDLE handle) 988{ 989 ACPI_BUFFER ret; 990 ACPI_STATUS rv; 991 ACPI_RESOURCE *res; 992 ACPI_RESOURCE_IRQ *irq; 993 uint intr; 994 995 intr = -1; 996 rv = acpi_get(handle, &ret, AcpiGetCurrentResources); 997 if (ACPI_FAILURE(rv)) 998 return (intr); 999 for (res = ret.Pointer; res->Id != ACPI_RSTYPE_END_TAG; 1000 res = ACPI_NEXT_RESOURCE(res)) { 1001 if (res->Id == ACPI_RSTYPE_IRQ) { 1002 irq = (ACPI_RESOURCE_IRQ *)&res->Data; 1003 if (irq->NumberOfInterrupts == 1) 1004 intr = irq->Interrupts[0]; 1005 break; 1006 } 1007 } 1008 AcpiOsFree(ret.Pointer); 1009 return (intr); 1010} 1011 1012static void 1013acpi_pci_set_line(int bus, int dev, int pin, int line) 1014{ 1015 ACPI_STATUS err; 1016 ACPI_PCI_ID pid; 1017 UINT32 intr, id, bhlc; 1018 int func, nfunc; 1019 1020 pid.Bus = bus; 1021 pid.Device = dev; 1022 pid.Function = 0; 1023 1024 err = AcpiOsReadPciConfiguration(&pid, PCI_BHLC_REG, &bhlc, 32); 1025 if (err) 1026 return; 1027 if (PCI_HDRTYPE_MULTIFN(bhlc)) 1028 nfunc = 8; 1029 else 1030 nfunc = 1; 1031 1032 for (func = 0; func < nfunc; func++) { 1033 pid.Function = func; 1034 1035 err = AcpiOsReadPciConfiguration(&pid, PCI_ID_REG, &id, 32); 1036 if (err || PCI_VENDOR(id) == PCI_VENDOR_INVALID || 1037 PCI_VENDOR(id) == 0) 1038 continue; 1039 1040 err = AcpiOsReadPciConfiguration(&pid, PCI_INTERRUPT_REG, 1041 &intr, 32); 1042 if (err) { 1043 printf("AcpiOsReadPciConfiguration failed %d\n", err); 1044 return; 1045 } 1046 if (pin == PCI_INTERRUPT_PIN(intr) && 1047 line != PCI_INTERRUPT_LINE(intr)) { 1048#ifdef ACPI_DEBUG 1049 printf("acpi fixup pci intr: %d:%d:%d %c: %d -> %d\n", 1050 bus, dev, func, 1051 pin + '@', PCI_INTERRUPT_LINE(intr), 1052 line); 1053#endif 1054 intr &= ~(PCI_INTERRUPT_LINE_MASK << 1055 PCI_INTERRUPT_LINE_SHIFT); 1056 intr |= line << PCI_INTERRUPT_LINE_SHIFT; 1057 err = AcpiOsWritePciConfiguration(&pid, 1058 PCI_INTERRUPT_REG, intr, 32); 1059 if (err) { 1060 printf("AcpiOsWritePciConfiguration failed" 1061 " %d\n", err); 1062 return; 1063 } 1064 } 1065 } 1066} 1067 1068ACPI_STATUS 1069acpi_pci_fixup_bus(ACPI_HANDLE handle, UINT32 level, void *context, 1070 void **status) 1071{ 1072 struct acpi_softc *sc = context; 1073 ACPI_STATUS rv; 1074 ACPI_BUFFER buf; 1075 UINT8 *Buffer; 1076 ACPI_PCI_ROUTING_TABLE *PrtElement; 1077 ACPI_HANDLE link; 1078 uint line; 1079 ACPI_NAMESPACE_NODE *node; 1080 ACPI_INTEGER val; 1081 1082 rv = acpi_get(handle, &buf, AcpiGetIrqRoutingTable); 1083 if (ACPI_FAILURE(rv)) 1084 return (AE_OK); 1085 1086 /* 1087 * If at level 1, this is a PCI root bus. Try the _BBN method 1088 * to get the right PCI bus numbering for the following 1089 * busses (this is a depth-first walk). It may fail, 1090 * for example if there's only one root bus, but that 1091 * case should be ok, so we'll ignore that. 1092 */ 1093 if (level == 1) { 1094 node = AcpiNsMapHandleToNode(handle); 1095 rv = AcpiUtEvaluateNumericObject(METHOD_NAME__BBN, node, &val); 1096 if (!ACPI_FAILURE(rv)) { 1097#ifdef ACPI_DEBUG 1098 printf("%s: fixup: _BBN success, bus # was %d now %d\n", 1099 sc->sc_dev.dv_xname, sc->sc_pci_bus, 1100 ACPI_LOWORD(val)); 1101#endif 1102 sc->sc_pci_bus = ACPI_LOWORD(val); 1103 } 1104 } 1105 1106 1107#ifdef ACPI_DEBUG 1108 printf("%s: fixing up PCI bus %d at level %u\n", sc->sc_dev.dv_xname, 1109 sc->sc_pci_bus, level); 1110#endif 1111 1112 for (Buffer = buf.Pointer; ; Buffer += PrtElement->Length) { 1113 PrtElement = (ACPI_PCI_ROUTING_TABLE *)Buffer; 1114 if (PrtElement->Length == 0) 1115 break; 1116 if (PrtElement->Source[0] == 0) 1117 continue; 1118 1119 link = acpi_get_node(PrtElement->Source); 1120 if (link == NULL) 1121 continue; 1122 line = acpi_get_intr(link); 1123 if (line == -1) { 1124#ifdef ACPI_DEBUG 1125 printf("%s: fixing up intr link %s\n", 1126 sc->sc_dev.dv_xname, PrtElement->Source); 1127#endif 1128 rv = acpi_allocate_resources(link); 1129 if (ACPI_FAILURE(rv)) { 1130 printf("%s: interrupt allocation failed %s\n", 1131 sc->sc_dev.dv_xname, PrtElement->Source); 1132 continue; 1133 } 1134 line = acpi_get_intr(link); 1135 if (line == -1) { 1136 printf("%s: get intr failed %s\n", 1137 sc->sc_dev.dv_xname, PrtElement->Source); 1138 continue; 1139 } 1140 } 1141 1142 acpi_pci_set_line(sc->sc_pci_bus, PrtElement->Address >> 16, 1143 PrtElement->Pin + 1, line); 1144 } 1145 1146 sc->sc_pci_bus++; 1147 1148 AcpiOsFree(buf.Pointer); 1149 return (AE_OK); 1150} 1151#endif /* ACPI_PCI_FIXUP */ 1152 1153#if defined(ACPI_PCI_FIXUP) || defined(ACPI_ACTIVATE_DEV) 1154/* XXX This very incomplete */ 1155ACPI_STATUS 1156acpi_allocate_resources(ACPI_HANDLE handle) 1157{ 1158 ACPI_BUFFER bufp, bufc, bufn; 1159 ACPI_RESOURCE *resp, *resc, *resn; 1160 ACPI_RESOURCE_IRQ *irq; 1161 ACPI_STATUS rv; 1162 uint delta; 1163 1164 rv = acpi_get(handle, &bufp, AcpiGetPossibleResources); 1165 if (ACPI_FAILURE(rv)) 1166 goto out; 1167 rv = acpi_get(handle, &bufc, AcpiGetCurrentResources); 1168 if (ACPI_FAILURE(rv)) { 1169 goto out1; 1170 } 1171 1172 bufn.Length = 1000; 1173 bufn.Pointer = resn = malloc(bufn.Length, M_ACPI, M_WAITOK); 1174 resp = bufp.Pointer; 1175 resc = bufc.Pointer; 1176 while (resc->Id != ACPI_RSTYPE_END_TAG && 1177 resp->Id != ACPI_RSTYPE_END_TAG) { 1178 while (resc->Id != resp->Id && resp->Id != ACPI_RSTYPE_END_TAG) 1179 resp = ACPI_NEXT_RESOURCE(resp); 1180 if (resp->Id == ACPI_RSTYPE_END_TAG) 1181 break; 1182 /* Found identical Id */ 1183 resn->Id = resc->Id; 1184 switch (resc->Id) { 1185 case ACPI_RSTYPE_IRQ: 1186 memcpy(&resn->Data, &resp->Data, 1187 sizeof(ACPI_RESOURCE_IRQ)); 1188 irq = (ACPI_RESOURCE_IRQ *)&resn->Data; 1189 irq->Interrupts[0] = 1190 ((ACPI_RESOURCE_IRQ *)&resp->Data)-> 1191 Interrupts[irq->NumberOfInterrupts-1]; 1192 irq->NumberOfInterrupts = 1; 1193 resn->Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_IRQ); 1194 break; 1195 case ACPI_RSTYPE_IO: 1196 memcpy(&resn->Data, &resp->Data, 1197 sizeof(ACPI_RESOURCE_IO)); 1198 resn->Length = resp->Length; 1199 break; 1200 default: 1201 printf("acpi_allocate_resources: res=%d\n", resc->Id); 1202 rv = AE_BAD_DATA; 1203 goto out2; 1204 } 1205 resc = ACPI_NEXT_RESOURCE(resc); 1206 resn = ACPI_NEXT_RESOURCE(resn); 1207 delta = (UINT8 *)resn - (UINT8 *)bufn.Pointer; 1208 if (delta >= 1209 bufn.Length-ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_DATA)) { 1210 bufn.Length *= 2; 1211 bufn.Pointer = realloc(bufn.Pointer, bufn.Length, 1212 M_ACPI, M_WAITOK); 1213 resn = (ACPI_RESOURCE *)((UINT8 *)bufn.Pointer + delta); 1214 } 1215 } 1216 if (resc->Id != ACPI_RSTYPE_END_TAG) { 1217 printf("acpi_allocate_resources: resc not exhausted\n"); 1218 rv = AE_BAD_DATA; 1219 goto out3; 1220 } 1221 1222 resn->Id = ACPI_RSTYPE_END_TAG; 1223 rv = AcpiSetCurrentResources(handle, &bufn); 1224 if (ACPI_FAILURE(rv)) { 1225 printf("acpi_allocate_resources: AcpiSetCurrentResources %s\n", 1226 AcpiFormatException(rv)); 1227 } 1228 1229out3: 1230 free(bufn.Pointer, M_ACPI); 1231out2: 1232 AcpiOsFree(bufc.Pointer); 1233out1: 1234 AcpiOsFree(bufp.Pointer); 1235out: 1236 return rv; 1237} 1238#endif /* ACPI_PCI_FIXUP || ACPI_ACTIVATE_DEV */ 1239