1*a93f58a9Sjmcneill /* $NetBSD: acpi.c,v 1.302 2024/12/30 11:44:16 jmcneill Exp $ */ 28dc2532aSmycroft 38dc2532aSmycroft /*- 41d4a085aSad * Copyright (c) 2003, 2007 The NetBSD Foundation, Inc. 58dc2532aSmycroft * All rights reserved. 68dc2532aSmycroft * 78dc2532aSmycroft * This code is derived from software contributed to The NetBSD Foundation 88dc2532aSmycroft * by Charles M. Hannum of By Noon Software, Inc. 98dc2532aSmycroft * 108dc2532aSmycroft * Redistribution and use in source and binary forms, with or without 118dc2532aSmycroft * modification, are permitted provided that the following conditions 128dc2532aSmycroft * are met: 138dc2532aSmycroft * 1. Redistributions of source code must retain the above copyright 148dc2532aSmycroft * notice, this list of conditions and the following disclaimer. 158dc2532aSmycroft * 2. Redistributions in binary form must reproduce the above copyright 168dc2532aSmycroft * notice, this list of conditions and the following disclaimer in the 178dc2532aSmycroft * documentation and/or other materials provided with the distribution. 188dc2532aSmycroft * 198dc2532aSmycroft * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 208dc2532aSmycroft * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 218dc2532aSmycroft * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 228dc2532aSmycroft * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 238dc2532aSmycroft * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 248dc2532aSmycroft * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 258dc2532aSmycroft * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 268dc2532aSmycroft * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 278dc2532aSmycroft * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 288dc2532aSmycroft * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 298dc2532aSmycroft * POSSIBILITY OF SUCH DAMAGE. 308dc2532aSmycroft */ 3169f30a11Sthorpej 3269f30a11Sthorpej /* 336e6e0264Sjruoho * Copyright (c) 2003 Wasabi Systems, Inc. 346e6e0264Sjruoho * All rights reserved. 356e6e0264Sjruoho * 366e6e0264Sjruoho * Written by Frank van der Linden for Wasabi Systems, Inc. 376e6e0264Sjruoho * 386e6e0264Sjruoho * Redistribution and use in source and binary forms, with or without 396e6e0264Sjruoho * modification, are permitted provided that the following conditions 406e6e0264Sjruoho * are met: 416e6e0264Sjruoho * 1. Redistributions of source code must retain the above copyright 426e6e0264Sjruoho * notice, this list of conditions and the following disclaimer. 436e6e0264Sjruoho * 2. Redistributions in binary form must reproduce the above copyright 446e6e0264Sjruoho * notice, this list of conditions and the following disclaimer in the 456e6e0264Sjruoho * documentation and/or other materials provided with the distribution. 466e6e0264Sjruoho * 3. All advertising materials mentioning features or use of this software 476e6e0264Sjruoho * must display the following acknowledgement: 486e6e0264Sjruoho * This product includes software developed for the NetBSD Project by 496e6e0264Sjruoho * Wasabi Systems, Inc. 506e6e0264Sjruoho * 4. The name of Wasabi Systems, Inc. may not be used to endorse 516e6e0264Sjruoho * or promote products derived from this software without specific prior 526e6e0264Sjruoho * written permission. 536e6e0264Sjruoho * 546e6e0264Sjruoho * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 556e6e0264Sjruoho * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 566e6e0264Sjruoho * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 576e6e0264Sjruoho * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 586e6e0264Sjruoho * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 596e6e0264Sjruoho * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 606e6e0264Sjruoho * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 616e6e0264Sjruoho * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 626e6e0264Sjruoho * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 636e6e0264Sjruoho * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 646e6e0264Sjruoho * POSSIBILITY OF SUCH DAMAGE. 656e6e0264Sjruoho */ 666e6e0264Sjruoho 676e6e0264Sjruoho /* 6859ea64b6Sthorpej * Copyright 2001, 2003 Wasabi Systems, Inc. 6969f30a11Sthorpej * All rights reserved. 7069f30a11Sthorpej * 7169f30a11Sthorpej * Written by Jason R. Thorpe for Wasabi Systems, Inc. 7269f30a11Sthorpej * 7369f30a11Sthorpej * Redistribution and use in source and binary forms, with or without 7469f30a11Sthorpej * modification, are permitted provided that the following conditions 7569f30a11Sthorpej * are met: 7669f30a11Sthorpej * 1. Redistributions of source code must retain the above copyright 7769f30a11Sthorpej * notice, this list of conditions and the following disclaimer. 7869f30a11Sthorpej * 2. Redistributions in binary form must reproduce the above copyright 7969f30a11Sthorpej * notice, this list of conditions and the following disclaimer in the 8069f30a11Sthorpej * documentation and/or other materials provided with the distribution. 8169f30a11Sthorpej * 3. All advertising materials mentioning features or use of this software 8269f30a11Sthorpej * must display the following acknowledgement: 8369f30a11Sthorpej * This product includes software developed for the NetBSD Project by 8469f30a11Sthorpej * Wasabi Systems, Inc. 8569f30a11Sthorpej * 4. The name of Wasabi Systems, Inc. may not be used to endorse 8669f30a11Sthorpej * or promote products derived from this software without specific prior 8769f30a11Sthorpej * written permission. 8869f30a11Sthorpej * 8969f30a11Sthorpej * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 9069f30a11Sthorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 9169f30a11Sthorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 9269f30a11Sthorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 9369f30a11Sthorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 9469f30a11Sthorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 9569f30a11Sthorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 9669f30a11Sthorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 9769f30a11Sthorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 9869f30a11Sthorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 9969f30a11Sthorpej * POSSIBILITY OF SUCH DAMAGE. 10069f30a11Sthorpej */ 10169f30a11Sthorpej 10213ac4302Slukem #include <sys/cdefs.h> 103*a93f58a9Sjmcneill __KERNEL_RCSID(0, "$NetBSD: acpi.c,v 1.302 2024/12/30 11:44:16 jmcneill Exp $"); 104c601b235Schristos 1058802859cSmaya #include "pci.h" 106c601b235Schristos #include "opt_acpi.h" 1070919f4d2Ssekiya #include "opt_pcifixup.h" 10813ac4302Slukem 10969f30a11Sthorpej #include <sys/param.h> 110cf234944Sriastradh #include <sys/atomic.h> 11169f30a11Sthorpej #include <sys/device.h> 1125a425210Sjruoho #include <sys/kernel.h> 1136f104f56Sjruoho #include <sys/kmem.h> 11469f30a11Sthorpej #include <sys/malloc.h> 1156c40070dSpgoyette #include <sys/module.h> 116039f493eSxtraeme #include <sys/mutex.h> 1173de4cab6Scube #include <sys/sysctl.h> 1185a425210Sjruoho #include <sys/systm.h> 119bd772854Sjruoho #include <sys/timetc.h> 12069f30a11Sthorpej 12169f30a11Sthorpej #include <dev/acpi/acpireg.h> 12269f30a11Sthorpej #include <dev/acpi/acpivar.h> 123605f564fSmsaitoh #include <dev/acpi/acpi_mcfg.h> 12469f30a11Sthorpej #include <dev/acpi/acpi_osd.h> 1255a425210Sjruoho #include <dev/acpi/acpi_pci.h> 1269ddf2c51Sjruoho #include <dev/acpi/acpi_power.h> 127c14d23acSdrochner #include <dev/acpi/acpi_timer.h> 128f5e82b65Sjmcneill #include <dev/acpi/acpi_wakedev.h> 1295a425210Sjruoho 1306f104f56Sjruoho #include <machine/acpi_machdep.h> 1316f104f56Sjruoho 13282b8cabaSriastradh #include "ioconf.h" 13382b8cabaSriastradh 134fb74e5b5Sjruoho #define _COMPONENT ACPI_BUS_COMPONENT 13523ab96a3Smlelstv ACPI_MODULE_NAME ("acpi") 13623ab96a3Smlelstv 13769f30a11Sthorpej /* 1383dd22c3cSjruoho * The acpi_active variable is set when the ACPI subsystem is active. 1393dd22c3cSjruoho * Machine-dependent code may wish to skip other steps (such as attaching 14069f30a11Sthorpej * subsystems that ACPI supercedes) when ACPI is active. 14169f30a11Sthorpej */ 1423dd22c3cSjruoho int acpi_active = 0; 1430cc9fff2Sjmcneill int acpi_suspended = 0; 1443dd22c3cSjruoho int acpi_force_load = 0; 145e1035e2bSjruoho int acpi_verbose_loaded = 0; 14669f30a11Sthorpej 147762d68ffSjruoho struct acpi_softc *acpi_softc = NULL; 148fb74e5b5Sjruoho static uint64_t acpi_root_pointer; 1491d4a085aSad extern kmutex_t acpi_interrupt_list_mtx; 1502203417fSjruoho static ACPI_HANDLE acpi_scopes[4]; 15140f2c5cbSjruoho ACPI_TABLE_HEADER *madt_header; 1521b71b828Sjmcneill ACPI_TABLE_HEADER *gtdt_header; 153e077f7a7Stshiozak 1549af38538Scube /* 1550c6bf9beSjruoho * This structure provides a context for the ACPI 1560c6bf9beSjruoho * namespace walk performed in acpi_build_tree(). 1570c6bf9beSjruoho */ 1580c6bf9beSjruoho struct acpi_walkcontext { 1590c6bf9beSjruoho struct acpi_softc *aw_sc; 1600c6bf9beSjruoho struct acpi_devnode *aw_parent; 1610c6bf9beSjruoho }; 1620c6bf9beSjruoho 1630c6bf9beSjruoho /* 164f4cdb667Sjruoho * Ignored HIDs. 16586acf021Sjmcneill */ 16686acf021Sjmcneill static const char * const acpi_ignored_ids[] = { 16786acf021Sjmcneill #if defined(i386) || defined(x86_64) 168494badebSjruoho "ACPI0007", /* ACPI CPUs do not attach to acpi(4) */ 16986acf021Sjmcneill "PNP0000", /* AT interrupt controller is handled internally */ 17001c4bf16Sjmcneill "PNP0001", /* EISA interrupt controller is handled internally */ 17186acf021Sjmcneill "PNP0200", /* AT DMA controller is handled internally */ 17282b81a0cScegger "PNP0A??", /* PCI Busses are handled internally */ 17386acf021Sjmcneill "PNP0B00", /* AT RTC is handled internally */ 17401c4bf16Sjmcneill "PNP0C02", /* PnP motherboard resources */ 17586acf021Sjmcneill "PNP0C0F", /* ACPI PCI link devices are handled internally */ 17686acf021Sjmcneill #endif 17786acf021Sjmcneill #if defined(x86_64) 17886acf021Sjmcneill "PNP0C04", /* FPU is handled internally */ 17986acf021Sjmcneill #endif 1802e237d44Sjmcneill #if defined(__aarch64__) 181bd974014Sjmcneill "ACPI0004", /* ACPI module devices are handled internally */ 18289e5088dSjmcneill "PNP0C0F", /* ACPI PCI link devices are handled internally */ 1832e237d44Sjmcneill #endif 18486acf021Sjmcneill NULL 18586acf021Sjmcneill }; 18686acf021Sjmcneill 187740a9e0cSjruoho /* 188740a9e0cSjruoho * Devices that should be attached early. 189740a9e0cSjruoho */ 190740a9e0cSjruoho static const char * const acpi_early_ids[] = { 191740a9e0cSjruoho "PNP0C09", /* acpiec(4) */ 192740a9e0cSjruoho NULL 193740a9e0cSjruoho }; 194740a9e0cSjruoho 1950c88d0e4Sjruoho static int acpi_match(device_t, cfdata_t, void *); 1960c88d0e4Sjruoho static int acpi_submatch(device_t, cfdata_t, const int *, void *); 1970c88d0e4Sjruoho static void acpi_attach(device_t, device_t, void *); 1980c88d0e4Sjruoho static int acpi_detach(device_t, int); 1990c88d0e4Sjruoho static void acpi_childdet(device_t, device_t); 2000c88d0e4Sjruoho static bool acpi_suspend(device_t, const pmf_qual_t *); 2010c88d0e4Sjruoho static bool acpi_resume(device_t, const pmf_qual_t *); 2020c88d0e4Sjruoho 203beb4a7feSkochi static void acpi_build_tree(struct acpi_softc *); 204dbbb0499Sjmcneill static void acpi_find_deps(struct acpi_softc *); 205323db750Schs static void acpi_config_tree(struct acpi_softc *); 206439fe919Sjmcneill static void acpi_config_dma(struct acpi_softc *); 20778670726Sjruoho static ACPI_STATUS acpi_make_devnode(ACPI_HANDLE, uint32_t, 20878670726Sjruoho void *, void **); 2090c6bf9beSjruoho static ACPI_STATUS acpi_make_devnode_post(ACPI_HANDLE, uint32_t, 2100c6bf9beSjruoho void *, void **); 2110af1ebd4Sjruoho static void acpi_make_name(struct acpi_devnode *, uint32_t); 21269f30a11Sthorpej 2130c88d0e4Sjruoho static int acpi_rescan(device_t, const char *, const int *); 214740a9e0cSjruoho static void acpi_rescan_early(struct acpi_softc *); 2150c88d0e4Sjruoho static void acpi_rescan_nodes(struct acpi_softc *); 216e008cf16Sjruoho static void acpi_rescan_capabilities(device_t); 2170c88d0e4Sjruoho static int acpi_print(void *aux, const char *); 2180c88d0e4Sjruoho 21955052ecaSjruoho static void acpi_notify_handler(ACPI_HANDLE, uint32_t, void *); 22055052ecaSjruoho 221426356f9Sjruoho static void acpi_register_fixed_button(struct acpi_softc *, int); 222426356f9Sjruoho static void acpi_deregister_fixed_button(struct acpi_softc *, int); 223426356f9Sjruoho static uint32_t acpi_fixed_button_handler(void *); 224426356f9Sjruoho static void acpi_fixed_button_pressed(void *); 225426356f9Sjruoho 226fb74e5b5Sjruoho static void acpi_sleep_init(struct acpi_softc *); 22769f30a11Sthorpej 2282a35c4cfSjruoho static int sysctl_hw_acpi_fixedstats(SYSCTLFN_PROTO); 2292a35c4cfSjruoho static int sysctl_hw_acpi_sleepstate(SYSCTLFN_PROTO); 2302a35c4cfSjruoho static int sysctl_hw_acpi_sleepstates(SYSCTLFN_PROTO); 2310c88d0e4Sjruoho 2322203417fSjruoho static bool acpi_is_scope(struct acpi_devnode *); 233a73b7786Sjmcneill static ACPI_TABLE_HEADER *acpi_map_rsdt(void); 234a73b7786Sjmcneill static void acpi_unmap_rsdt(ACPI_TABLE_HEADER *); 235a73b7786Sjmcneill 236e1035e2bSjruoho void acpi_print_verbose_stub(struct acpi_softc *); 2379f0fa4d2Spgoyette void acpi_print_dev_stub(const char *); 2389f0fa4d2Spgoyette 2391bb3132dSjruoho static void acpi_activate_device(ACPI_HANDLE, ACPI_DEVICE_INFO **); 2401bb3132dSjruoho ACPI_STATUS acpi_allocate_resources(ACPI_HANDLE); 2411bb3132dSjruoho 242e1035e2bSjruoho void (*acpi_print_verbose)(struct acpi_softc *) = acpi_print_verbose_stub; 2439f0fa4d2Spgoyette void (*acpi_print_dev)(const char *) = acpi_print_dev_stub; 2446c40070dSpgoyette 2453d25b0deSjmcneill bus_dma_tag_t acpi_default_dma_tag(struct acpi_softc *, struct acpi_devnode *); 2463d25b0deSjmcneill bus_dma_tag_t acpi_default_dma64_tag(struct acpi_softc *, struct acpi_devnode *); 2476f25f864Sjmcneill pci_chipset_tag_t acpi_default_pci_chipset_tag(struct acpi_softc *, int, int); 2483d25b0deSjmcneill 2490c88d0e4Sjruoho CFATTACH_DECL2_NEW(acpi, sizeof(struct acpi_softc), 2500c88d0e4Sjruoho acpi_match, acpi_attach, acpi_detach, NULL, acpi_rescan, acpi_childdet); 2512aba9513Sjruoho 25269f30a11Sthorpej /* 2530c88d0e4Sjruoho * Probe for ACPI support. 25469f30a11Sthorpej * 2550c88d0e4Sjruoho * This is called by the machine-dependent ACPI front-end. 2560c88d0e4Sjruoho * Note: this is not an autoconfiguration interface function. 25769f30a11Sthorpej */ 25869f30a11Sthorpej int 25969f30a11Sthorpej acpi_probe(void) 26069f30a11Sthorpej { 261a73b7786Sjmcneill ACPI_TABLE_HEADER *rsdt; 26206a5faf4Sjruoho ACPI_STATUS rv; 263762d68ffSjruoho int quirks; 26469f30a11Sthorpej 265762d68ffSjruoho if (acpi_softc != NULL) 2660c88d0e4Sjruoho panic("%s: already probed", __func__); 2670c88d0e4Sjruoho 268598ab03aSad mutex_init(&acpi_interrupt_list_mtx, MUTEX_DEFAULT, IPL_NONE); 269e077f7a7Stshiozak 27069f30a11Sthorpej /* 27169f30a11Sthorpej * Start up ACPICA. 27269f30a11Sthorpej */ 27306a5faf4Sjruoho AcpiGbl_EnableInterpreterSlack = true; 2744c1d81b2Sjmcneill 27569f30a11Sthorpej rv = AcpiInitializeSubsystem(); 27606a5faf4Sjruoho 277762d68ffSjruoho if (ACPI_FAILURE(rv)) { 278762d68ffSjruoho aprint_error("%s: failed to initialize subsystem\n", __func__); 279762d68ffSjruoho return 0; 28069f30a11Sthorpej } 28169f30a11Sthorpej 282b9961a4eSjruoho /* 283b9961a4eSjruoho * Allocate space for RSDT/XSDT and DSDT, 284b9961a4eSjruoho * but allow resizing if more tables exist. 285b9961a4eSjruoho */ 286b9961a4eSjruoho rv = AcpiInitializeTables(NULL, 2, true); 28706a5faf4Sjruoho 2884c1d81b2Sjmcneill if (ACPI_FAILURE(rv)) { 289762d68ffSjruoho aprint_error("%s: failed to initialize tables\n", __func__); 29006a5faf4Sjruoho goto fail; 2914c1d81b2Sjmcneill } 2924c1d81b2Sjmcneill 29369f30a11Sthorpej rv = AcpiLoadTables(); 29406a5faf4Sjruoho 2954ac0e3e5Smycroft if (ACPI_FAILURE(rv)) { 296762d68ffSjruoho aprint_error("%s: failed to load tables\n", __func__); 29706a5faf4Sjruoho goto fail; 29869f30a11Sthorpej } 29969f30a11Sthorpej 300a73b7786Sjmcneill rsdt = acpi_map_rsdt(); 30106a5faf4Sjruoho 302a73b7786Sjmcneill if (rsdt == NULL) { 303762d68ffSjruoho aprint_error("%s: failed to map RSDT\n", __func__); 30406a5faf4Sjruoho goto fail; 305a73b7786Sjmcneill } 306d72049ddSjmcneill 307762d68ffSjruoho quirks = acpi_find_quirks(); 308762d68ffSjruoho 309762d68ffSjruoho if (acpi_force_load == 0 && (quirks & ACPI_QUIRK_BROKEN) != 0) { 310762d68ffSjruoho 31106a5faf4Sjruoho aprint_normal("ACPI: BIOS is listed as broken:\n"); 31206a5faf4Sjruoho aprint_normal("ACPI: X/RSDT: OemId <%6.6s,%8.8s,%08x>, " 313762d68ffSjruoho "AslId <%4.4s,%08x>\n", rsdt->OemId, rsdt->OemTableId, 314762d68ffSjruoho rsdt->OemRevision, rsdt->AslCompilerId, 315a73b7786Sjmcneill rsdt->AslCompilerRevision); 31606a5faf4Sjruoho aprint_normal("ACPI: Not used. Set acpi_force_load to use.\n"); 317762d68ffSjruoho 318a73b7786Sjmcneill acpi_unmap_rsdt(rsdt); 319762d68ffSjruoho goto fail; 32001158ea8Schristos } 321762d68ffSjruoho 322762d68ffSjruoho if (acpi_force_load == 0 && (quirks & ACPI_QUIRK_OLDBIOS) != 0) { 323762d68ffSjruoho 324762d68ffSjruoho aprint_normal("ACPI: BIOS is too old (%s). " 325762d68ffSjruoho "Set acpi_force_load to use.\n", 326bd2d899cSjmcneill pmf_get_platform("bios-date")); 327762d68ffSjruoho 328eb0e82d8Sjmcneill acpi_unmap_rsdt(rsdt); 329762d68ffSjruoho goto fail; 330eb0e82d8Sjmcneill } 33101158ea8Schristos 332a73b7786Sjmcneill acpi_unmap_rsdt(rsdt); 333a73b7786Sjmcneill 3344c1d81b2Sjmcneill rv = AcpiEnableSubsystem(~(ACPI_NO_HARDWARE_INIT|ACPI_NO_ACPI_ENABLE)); 33506a5faf4Sjruoho 3364c1d81b2Sjmcneill if (ACPI_FAILURE(rv)) { 337762d68ffSjruoho aprint_error("%s: failed to enable subsystem\n", __func__); 33806a5faf4Sjruoho goto fail; 3394c1d81b2Sjmcneill } 3404c1d81b2Sjmcneill 3410c88d0e4Sjruoho return 1; 34206a5faf4Sjruoho 34306a5faf4Sjruoho fail: 34406a5faf4Sjruoho (void)AcpiTerminate(); 34506a5faf4Sjruoho 34606a5faf4Sjruoho return 0; 3470c88d0e4Sjruoho } 34869f30a11Sthorpej 3496745d5beSjruoho void 3506745d5beSjruoho acpi_disable(void) 3516745d5beSjruoho { 3526745d5beSjruoho 353c99562cbSjruoho if (acpi_softc == NULL) 354c99562cbSjruoho return; 355c99562cbSjruoho 356c99562cbSjruoho KASSERT(acpi_active != 0); 357c99562cbSjruoho 3586745d5beSjruoho if (AcpiGbl_FADT.SmiCommand != 0) 3596745d5beSjruoho AcpiDisable(); 3606745d5beSjruoho } 3616745d5beSjruoho 3620c88d0e4Sjruoho int 3630c88d0e4Sjruoho acpi_check(device_t parent, const char *ifattr) 3640c88d0e4Sjruoho { 3652685996bSthorpej return config_search(parent, NULL, 366c7fb772bSthorpej CFARGS(.submatch = acpi_submatch, 367c7fb772bSthorpej .iattr = ifattr)) != NULL; 3680c88d0e4Sjruoho } 3690c88d0e4Sjruoho 370048f3118Sjmcneill int 371048f3118Sjmcneill acpi_reset(void) 372048f3118Sjmcneill { 373048f3118Sjmcneill struct acpi_softc *sc = acpi_softc; 374048f3118Sjmcneill ACPI_GENERIC_ADDRESS *ResetReg; 375048f3118Sjmcneill ACPI_PCI_ID PciId; 376048f3118Sjmcneill ACPI_STATUS status; 377048f3118Sjmcneill 378048f3118Sjmcneill if (sc == NULL) 379048f3118Sjmcneill return ENXIO; 380048f3118Sjmcneill 381048f3118Sjmcneill ResetReg = &AcpiGbl_FADT.ResetRegister; 382048f3118Sjmcneill 383048f3118Sjmcneill /* Check if the reset register is supported */ 384048f3118Sjmcneill if (!(AcpiGbl_FADT.Flags & ACPI_FADT_RESET_REGISTER) || 385048f3118Sjmcneill !ResetReg->Address) { 386048f3118Sjmcneill return ENOENT; 387048f3118Sjmcneill } 388048f3118Sjmcneill 389048f3118Sjmcneill switch (ResetReg->SpaceId) { 390048f3118Sjmcneill case ACPI_ADR_SPACE_PCI_CONFIG: 391048f3118Sjmcneill PciId.Segment = PciId.Bus = 0; 392048f3118Sjmcneill PciId.Device = ACPI_GAS_PCI_DEV(ResetReg->Address); 393048f3118Sjmcneill PciId.Function = ACPI_GAS_PCI_FUNC(ResetReg->Address); 394048f3118Sjmcneill status = AcpiOsWritePciConfiguration(&PciId, 395048f3118Sjmcneill ACPI_GAS_PCI_REGOFF(ResetReg->Address), 396048f3118Sjmcneill AcpiGbl_FADT.ResetValue, ResetReg->BitWidth); 397048f3118Sjmcneill break; 398048f3118Sjmcneill case ACPI_ADR_SPACE_SYSTEM_IO: 399048f3118Sjmcneill case ACPI_ADR_SPACE_SYSTEM_MEMORY: 400048f3118Sjmcneill status = AcpiReset(); 401048f3118Sjmcneill break; 402048f3118Sjmcneill default: 403048f3118Sjmcneill status = AE_TYPE; 404048f3118Sjmcneill break; 405048f3118Sjmcneill } 406048f3118Sjmcneill 407048f3118Sjmcneill return ACPI_FAILURE(status) ? EIO : 0; 408048f3118Sjmcneill } 409048f3118Sjmcneill 410d6afaa44Sjruoho /* 411d6afaa44Sjruoho * Autoconfiguration. 412d6afaa44Sjruoho */ 4130c88d0e4Sjruoho static int 4140c88d0e4Sjruoho acpi_match(device_t parent, cfdata_t match, void *aux) 4150c88d0e4Sjruoho { 4160c88d0e4Sjruoho /* 4170c88d0e4Sjruoho * XXX: Nada; MD code has called acpi_probe(). 4180c88d0e4Sjruoho */ 4192bde9b60Skochi return 1; 42069f30a11Sthorpej } 42169f30a11Sthorpej 42235d885e5Scube static int 42335d885e5Scube acpi_submatch(device_t parent, cfdata_t cf, const int *locs, void *aux) 42435d885e5Scube { 42535d885e5Scube struct cfattach *ca; 42635d885e5Scube 42735d885e5Scube ca = config_cfattach_lookup(cf->cf_name, cf->cf_atname); 4280c88d0e4Sjruoho 42935d885e5Scube return (ca == &acpi_ca); 43035d885e5Scube } 43135d885e5Scube 432beb4a7feSkochi static void 43373e95cafSdyoung acpi_attach(device_t parent, device_t self, void *aux) 43469f30a11Sthorpej { 43573e95cafSdyoung struct acpi_softc *sc = device_private(self); 43669f30a11Sthorpej struct acpibus_attach_args *aa = aux; 437da7b6279Sjmcneill ACPI_TABLE_HEADER *rsdt, *hdr; 438fb74e5b5Sjruoho ACPI_STATUS rv; 439da7b6279Sjmcneill int i; 44069f30a11Sthorpej 44186acf021Sjmcneill aprint_naive("\n"); 44286acf021Sjmcneill aprint_normal(": Intel ACPICA %08x\n", ACPI_CA_VERSION); 44369f30a11Sthorpej 44469f30a11Sthorpej if (acpi_softc != NULL) 44506a5faf4Sjruoho panic("%s: already attached", __func__); 4465a20f4beSthorpej 447a73b7786Sjmcneill rsdt = acpi_map_rsdt(); 44806a5faf4Sjruoho 44906a5faf4Sjruoho if (rsdt == NULL) 45006a5faf4Sjruoho aprint_error_dev(self, "X/RSDT: Not found\n"); 45106a5faf4Sjruoho else { 45206a5faf4Sjruoho aprint_verbose_dev(self, 45373e95cafSdyoung "X/RSDT: OemId <%6.6s,%8.8s,%08x>, AslId <%4.4s,%08x>\n", 454a73b7786Sjmcneill rsdt->OemId, rsdt->OemTableId, 455a73b7786Sjmcneill rsdt->OemRevision, 456a73b7786Sjmcneill rsdt->AslCompilerId, rsdt->AslCompilerRevision); 45706a5faf4Sjruoho } 458320e1e3fSjruoho 459a73b7786Sjmcneill acpi_unmap_rsdt(rsdt); 4609f4eb04cSfvdl 461fcb7a451Sjmcneill sc->sc_dev = self; 4620c6bf9beSjruoho sc->sc_root = NULL; 4630c6bf9beSjruoho 464fb74e5b5Sjruoho sc->sc_sleepstate = ACPI_STATE_S0; 4650c6bf9beSjruoho sc->sc_quirks = acpi_find_quirks(); 466c0b69866Sfvdl 46706a5faf4Sjruoho sysmon_power_settype("acpi"); 46806a5faf4Sjruoho 46969f30a11Sthorpej sc->sc_iot = aa->aa_iot; 47069f30a11Sthorpej sc->sc_memt = aa->aa_memt; 47169f30a11Sthorpej sc->sc_pciflags = aa->aa_pciflags; 472c8111254Sjmcneill sc->sc_ic = aa->aa_ic; 4736af4cd33Snonaka sc->sc_dmat = aa->aa_dmat; 4746af4cd33Snonaka sc->sc_dmat64 = aa->aa_dmat64; 47569f30a11Sthorpej 476de6a49e8Sskrll SIMPLEQ_INIT(&sc->sc_head); 477320e1e3fSjruoho 47869f30a11Sthorpej acpi_softc = sc; 47969f30a11Sthorpej 48006a5faf4Sjruoho if (pmf_device_register(self, acpi_suspend, acpi_resume) != true) 4814c1d81b2Sjmcneill aprint_error_dev(self, "couldn't establish power handler\n"); 4824c1d81b2Sjmcneill 4834c1d81b2Sjmcneill /* 484762d68ffSjruoho * Bring ACPICA on-line. 48569f30a11Sthorpej */ 4864c1d81b2Sjmcneill 487323db750Schs rv = AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION); 48806a5faf4Sjruoho 48906a5faf4Sjruoho if (ACPI_FAILURE(rv)) 49006a5faf4Sjruoho goto fail; 491bd130abaSkochi 492d6afaa44Sjruoho /* 4930fc4e4abSjruoho * Early initialization of acpiec(4) via ECDT. 4940fc4e4abSjruoho */ 4952685996bSthorpej config_found(self, aa, NULL, 496c7fb772bSthorpej CFARGS(.iattr = "acpiecdtbus")); 497bd130abaSkochi 4984c1d81b2Sjmcneill rv = AcpiInitializeObjects(ACPI_FULL_INITIALIZATION); 49906a5faf4Sjruoho 50006a5faf4Sjruoho if (ACPI_FAILURE(rv)) 50106a5faf4Sjruoho goto fail; 50206a5faf4Sjruoho 50355052ecaSjruoho /* 504323db750Schs * Scan the namespace and build our device tree. 505323db750Schs */ 506323db750Schs acpi_build_tree(sc); 507323db750Schs 508fe7c8ea3Sscole #if NPCI > 0 509605f564fSmsaitoh /* 510605f564fSmsaitoh * Probe MCFG table 511605f564fSmsaitoh */ 512605f564fSmsaitoh acpimcfg_probe(sc); 5135eb49c4eSmaya #endif 514605f564fSmsaitoh 515323db750Schs acpi_md_callback(sc); 516323db750Schs 517323db750Schs /* 5185fcd9d30Sjruoho * Early initialization of the _PDC control method 5195fcd9d30Sjruoho * that may load additional SSDT tables dynamically. 5205fcd9d30Sjruoho */ 5215fcd9d30Sjruoho (void)acpi_md_pdc(); 5225fcd9d30Sjruoho 5235fcd9d30Sjruoho /* 52455052ecaSjruoho * Install global notify handlers. 52555052ecaSjruoho */ 52655052ecaSjruoho rv = AcpiInstallNotifyHandler(ACPI_ROOT_OBJECT, 52755052ecaSjruoho ACPI_SYSTEM_NOTIFY, acpi_notify_handler, NULL); 52855052ecaSjruoho 52955052ecaSjruoho if (ACPI_FAILURE(rv)) 53055052ecaSjruoho goto fail; 53155052ecaSjruoho 53255052ecaSjruoho rv = AcpiInstallNotifyHandler(ACPI_ROOT_OBJECT, 53355052ecaSjruoho ACPI_DEVICE_NOTIFY, acpi_notify_handler, NULL); 53455052ecaSjruoho 53555052ecaSjruoho if (ACPI_FAILURE(rv)) 53655052ecaSjruoho goto fail; 53755052ecaSjruoho 53869f30a11Sthorpej acpi_active = 1; 53969f30a11Sthorpej 54088992e2eSjmcneill if (!AcpiGbl_ReducedHardware) { 54123508069Skanaoka /* Show SCI interrupt. */ 5424fcde464Sjruoho aprint_verbose_dev(self, "SCI interrupting at int %u\n", 54373e95cafSdyoung AcpiGbl_FADT.SciInterrupt); 5444c1d81b2Sjmcneill 54569f30a11Sthorpej /* 546426356f9Sjruoho * Install fixed-event handlers. 54769f30a11Sthorpej */ 548426356f9Sjruoho acpi_register_fixed_button(sc, ACPI_EVENT_POWER_BUTTON); 549426356f9Sjruoho acpi_register_fixed_button(sc, ACPI_EVENT_SLEEP_BUTTON); 55088992e2eSjmcneill } 551426356f9Sjruoho 552da7b6279Sjmcneill /* 553da7b6279Sjmcneill * Load drivers that operate on System Description Tables. 554da7b6279Sjmcneill */ 555da7b6279Sjmcneill for (i = 0; i < AcpiGbl_RootTableList.CurrentTableCount; ++i) { 556da7b6279Sjmcneill rv = AcpiGetTableByIndex(i, &hdr); 557da7b6279Sjmcneill if (ACPI_FAILURE(rv)) { 558da7b6279Sjmcneill continue; 559da7b6279Sjmcneill } 5602685996bSthorpej config_found(sc->sc_dev, hdr, NULL, 561c7fb772bSthorpej CFARGS(.iattr = "acpisdtbus")); 562da7b6279Sjmcneill AcpiPutTable(hdr); 563da7b6279Sjmcneill } 564da7b6279Sjmcneill 565bd772854Sjruoho acpitimer_init(sc); 566323db750Schs acpi_config_tree(sc); 567fb74e5b5Sjruoho acpi_sleep_init(sc); 5683de4cab6Scube 5694cd0ccf8Sjruoho #ifdef ACPI_DEBUG 5704cd0ccf8Sjruoho acpi_debug_init(); 5714cd0ccf8Sjruoho #endif 57206a5faf4Sjruoho 573e1035e2bSjruoho /* 574e1035e2bSjruoho * Print debug information. 575e1035e2bSjruoho */ 576e1035e2bSjruoho acpi_print_verbose(sc); 577e1035e2bSjruoho 57806a5faf4Sjruoho return; 57906a5faf4Sjruoho 58006a5faf4Sjruoho fail: 58106a5faf4Sjruoho aprint_error("%s: failed to initialize ACPI: %s\n", 58206a5faf4Sjruoho __func__, AcpiFormatException(rv)); 58369f30a11Sthorpej } 58469f30a11Sthorpej 5858a96e477Sjruoho /* 5868a96e477Sjruoho * XXX: This is incomplete. 5878a96e477Sjruoho */ 588222f7adfSdyoung static int 589222f7adfSdyoung acpi_detach(device_t self, int flags) 590222f7adfSdyoung { 591426356f9Sjruoho struct acpi_softc *sc = device_private(self); 59255052ecaSjruoho ACPI_STATUS rv; 593222f7adfSdyoung int rc; 594222f7adfSdyoung 59555052ecaSjruoho rv = AcpiRemoveNotifyHandler(ACPI_ROOT_OBJECT, 59655052ecaSjruoho ACPI_SYSTEM_NOTIFY, acpi_notify_handler); 59755052ecaSjruoho 59855052ecaSjruoho if (ACPI_FAILURE(rv)) 59955052ecaSjruoho return EBUSY; 60055052ecaSjruoho 60155052ecaSjruoho rv = AcpiRemoveNotifyHandler(ACPI_ROOT_OBJECT, 60255052ecaSjruoho ACPI_DEVICE_NOTIFY, acpi_notify_handler); 60355052ecaSjruoho 60455052ecaSjruoho if (ACPI_FAILURE(rv)) 60555052ecaSjruoho return EBUSY; 60655052ecaSjruoho 607222f7adfSdyoung if ((rc = config_detach_children(self, flags)) != 0) 608222f7adfSdyoung return rc; 609222f7adfSdyoung 610222f7adfSdyoung if ((rc = acpitimer_detach()) != 0) 611222f7adfSdyoung return rc; 612222f7adfSdyoung 61388992e2eSjmcneill if (!AcpiGbl_ReducedHardware) { 614426356f9Sjruoho acpi_deregister_fixed_button(sc, ACPI_EVENT_POWER_BUTTON); 615426356f9Sjruoho acpi_deregister_fixed_button(sc, ACPI_EVENT_SLEEP_BUTTON); 61688992e2eSjmcneill } 617426356f9Sjruoho 618222f7adfSdyoung pmf_device_deregister(self); 619222f7adfSdyoung 620222f7adfSdyoung acpi_softc = NULL; 621222f7adfSdyoung 622222f7adfSdyoung return 0; 623222f7adfSdyoung } 624222f7adfSdyoung 6250c88d0e4Sjruoho static void 6260c88d0e4Sjruoho acpi_childdet(device_t self, device_t child) 6270c88d0e4Sjruoho { 6280c88d0e4Sjruoho struct acpi_softc *sc = device_private(self); 6290c88d0e4Sjruoho struct acpi_devnode *ad; 6300c88d0e4Sjruoho 6310c88d0e4Sjruoho if (sc->sc_apmbus == child) 6320c88d0e4Sjruoho sc->sc_apmbus = NULL; 6336f104f56Sjruoho 6346e72689aSjruoho if (sc->sc_hpet == child) 6356e72689aSjruoho sc->sc_hpet = NULL; 6366e72689aSjruoho 63727686d11Sjmcneill if (sc->sc_wdrt == child) 63827686d11Sjmcneill sc->sc_wdrt = NULL; 6390c88d0e4Sjruoho 640062c0d7eSriastradh if (sc->sc_apei == child) 641062c0d7eSriastradh sc->sc_apei = NULL; 642062c0d7eSriastradh 643de6a49e8Sskrll SIMPLEQ_FOREACH(ad, &sc->sc_head, ad_list) { 6440c88d0e4Sjruoho 6450c88d0e4Sjruoho if (ad->ad_device == child) 6460c88d0e4Sjruoho ad->ad_device = NULL; 6470c88d0e4Sjruoho } 6480c88d0e4Sjruoho } 6490c88d0e4Sjruoho 6500cc9fff2Sjmcneill static bool 651c1b390d4Sdyoung acpi_suspend(device_t dv, const pmf_qual_t *qual) 6520cc9fff2Sjmcneill { 6530c88d0e4Sjruoho 6540cc9fff2Sjmcneill acpi_suspended = 1; 6550c88d0e4Sjruoho 6560cc9fff2Sjmcneill return true; 6570cc9fff2Sjmcneill } 6580cc9fff2Sjmcneill 6590cc9fff2Sjmcneill static bool 660c1b390d4Sdyoung acpi_resume(device_t dv, const pmf_qual_t *qual) 6610cc9fff2Sjmcneill { 6620c88d0e4Sjruoho 6630cc9fff2Sjmcneill acpi_suspended = 0; 6640c88d0e4Sjruoho 6650cc9fff2Sjmcneill return true; 6660cc9fff2Sjmcneill } 6670cc9fff2Sjmcneill 66869f30a11Sthorpej /* 6690c88d0e4Sjruoho * Namespace scan. 67069f30a11Sthorpej */ 671beb4a7feSkochi static void 67269f30a11Sthorpej acpi_build_tree(struct acpi_softc *sc) 67369f30a11Sthorpej { 6740c6bf9beSjruoho struct acpi_walkcontext awc; 675320e1e3fSjruoho 6762203417fSjruoho /* 6772203417fSjruoho * Get the root scope handles. 6782203417fSjruoho */ 6792203417fSjruoho KASSERT(__arraycount(acpi_scopes) == 4); 6802203417fSjruoho 6812203417fSjruoho (void)AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_PR_", &acpi_scopes[0]); 6822e3ac7f8Sjruoho (void)AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &acpi_scopes[1]); 6832e3ac7f8Sjruoho (void)AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SI_", &acpi_scopes[2]); 6842203417fSjruoho (void)AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_TZ_", &acpi_scopes[3]); 6852203417fSjruoho 6862203417fSjruoho /* 6872203417fSjruoho * Make the root node. 6882203417fSjruoho */ 6890c6bf9beSjruoho awc.aw_sc = sc; 6900c6bf9beSjruoho awc.aw_parent = NULL; 6910c6bf9beSjruoho 6920c6bf9beSjruoho (void)acpi_make_devnode(ACPI_ROOT_OBJECT, 0, &awc, NULL); 6930c6bf9beSjruoho 6940c6bf9beSjruoho KASSERT(sc->sc_root == NULL); 6950c6bf9beSjruoho KASSERT(awc.aw_parent != NULL); 6960c6bf9beSjruoho 6970c6bf9beSjruoho sc->sc_root = awc.aw_parent; 6980c6bf9beSjruoho 6992203417fSjruoho /* 7002203417fSjruoho * Build the internal namespace. 7012203417fSjruoho */ 7020c6bf9beSjruoho (void)AcpiWalkNamespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, UINT32_MAX, 7030c6bf9beSjruoho acpi_make_devnode, acpi_make_devnode_post, &awc, NULL); 7040c6bf9beSjruoho 705dbbb0499Sjmcneill /* 706dbbb0499Sjmcneill * Find device dependencies. 707dbbb0499Sjmcneill */ 708dbbb0499Sjmcneill acpi_find_deps(sc); 709dbbb0499Sjmcneill 710ef019da3Smrg #if NPCI > 0 7112203417fSjruoho /* 7122203417fSjruoho * Scan the internal namespace. 7132203417fSjruoho */ 714e28e04ceSgsutre (void)acpi_pcidev_scan(sc->sc_root); 715ef019da3Smrg #endif 716323db750Schs } 717323db750Schs 718323db750Schs static void 719dbbb0499Sjmcneill acpi_add_dep(struct acpi_devnode *ad, struct acpi_devnode *depad) 720dbbb0499Sjmcneill { 721dbbb0499Sjmcneill struct acpi_devnodedep *dd; 722dbbb0499Sjmcneill 723dbbb0499Sjmcneill dd = kmem_alloc(sizeof(*dd), KM_SLEEP); 724dbbb0499Sjmcneill dd->dd_node = depad; 725dbbb0499Sjmcneill SIMPLEQ_INSERT_TAIL(&ad->ad_deps, dd, dd_list); 726dbbb0499Sjmcneill } 727dbbb0499Sjmcneill 728dbbb0499Sjmcneill static void 729dbbb0499Sjmcneill acpi_find_deps(struct acpi_softc *sc) 730dbbb0499Sjmcneill { 731dbbb0499Sjmcneill struct acpi_devnode *ad; 732dbbb0499Sjmcneill 733dbbb0499Sjmcneill SIMPLEQ_FOREACH(ad, &sc->sc_head, ad_list) { 734dbbb0499Sjmcneill struct acpi_devnode *depad; 735dbbb0499Sjmcneill ACPI_OBJECT *obj; 736dbbb0499Sjmcneill ACPI_HANDLE _dep; 737dbbb0499Sjmcneill ACPI_BUFFER buf; 738dbbb0499Sjmcneill ACPI_STATUS rv; 739dbbb0499Sjmcneill u_int ref; 740dbbb0499Sjmcneill 741dbbb0499Sjmcneill if (acpi_is_scope(ad) || 742dbbb0499Sjmcneill ad->ad_parent == NULL || 743dbbb0499Sjmcneill ad->ad_devinfo->Type != ACPI_TYPE_DEVICE) { 744dbbb0499Sjmcneill continue; 745dbbb0499Sjmcneill } 746dbbb0499Sjmcneill 747dbbb0499Sjmcneill /* Add an implicit dependency on parent devices. */ 748dbbb0499Sjmcneill if (!acpi_is_scope(ad->ad_parent) && 749dbbb0499Sjmcneill ad->ad_parent->ad_devinfo->Type == ACPI_TYPE_DEVICE) { 750dbbb0499Sjmcneill acpi_add_dep(ad, ad->ad_parent); 751dbbb0499Sjmcneill } 752dbbb0499Sjmcneill 753dbbb0499Sjmcneill rv = AcpiGetHandle(ad->ad_handle, "_DEP", &_dep); 754dbbb0499Sjmcneill if (ACPI_FAILURE(rv)) { 755dbbb0499Sjmcneill goto logit; 756dbbb0499Sjmcneill } 757dbbb0499Sjmcneill 758dbbb0499Sjmcneill buf.Pointer = NULL; 759dbbb0499Sjmcneill buf.Length = ACPI_ALLOCATE_BUFFER; 760dbbb0499Sjmcneill rv = AcpiEvaluateObjectTyped(_dep, NULL, NULL, &buf, 761dbbb0499Sjmcneill ACPI_TYPE_PACKAGE); 762dbbb0499Sjmcneill if (ACPI_FAILURE(rv)) { 763dbbb0499Sjmcneill goto logit; 764dbbb0499Sjmcneill } 765dbbb0499Sjmcneill obj = buf.Pointer; 766dbbb0499Sjmcneill 767dbbb0499Sjmcneill for (ref = 0; ref < obj->Package.Count; ref++) { 768dbbb0499Sjmcneill ACPI_OBJECT *robj = &obj->Package.Elements[ref]; 769dbbb0499Sjmcneill ACPI_HANDLE rhdl; 770dbbb0499Sjmcneill 771dbbb0499Sjmcneill rv = acpi_eval_reference_handle(robj, &rhdl); 772dbbb0499Sjmcneill if (ACPI_FAILURE(rv)) { 773dbbb0499Sjmcneill continue; 774dbbb0499Sjmcneill } 775dbbb0499Sjmcneill 776dbbb0499Sjmcneill depad = acpi_match_node(rhdl); 777dbbb0499Sjmcneill if (depad != NULL) { 778dbbb0499Sjmcneill acpi_add_dep(ad, depad); 779dbbb0499Sjmcneill } 780dbbb0499Sjmcneill } 781dbbb0499Sjmcneill 782dbbb0499Sjmcneill ACPI_FREE(buf.Pointer); 783dbbb0499Sjmcneill 784dbbb0499Sjmcneill logit: 785dbbb0499Sjmcneill if (!SIMPLEQ_EMPTY(&ad->ad_deps)) { 786dbbb0499Sjmcneill struct acpi_devnodedep *dd; 787dbbb0499Sjmcneill 788dbbb0499Sjmcneill aprint_debug_dev(sc->sc_dev, "%s dependencies:", 789dbbb0499Sjmcneill ad->ad_name); 790dbbb0499Sjmcneill SIMPLEQ_FOREACH(dd, &ad->ad_deps, dd_list) { 791dbbb0499Sjmcneill aprint_debug(" %s", dd->dd_node->ad_name); 792dbbb0499Sjmcneill } 793dbbb0499Sjmcneill aprint_debug("\n"); 794dbbb0499Sjmcneill } 795dbbb0499Sjmcneill } 796dbbb0499Sjmcneill } 797dbbb0499Sjmcneill 798dbbb0499Sjmcneill static void 799323db750Schs acpi_config_tree(struct acpi_softc *sc) 800323db750Schs { 801439fe919Sjmcneill /* 802439fe919Sjmcneill * Assign bus_dma resources 803439fe919Sjmcneill */ 804439fe919Sjmcneill acpi_config_dma(sc); 805323db750Schs 806323db750Schs /* 807323db750Schs * Configure all everything found "at acpi?". 808323db750Schs */ 80962a3a065Sjruoho (void)acpi_rescan(sc->sc_dev, NULL, NULL); 81062a3a065Sjruoho 811e008cf16Sjruoho /* 81280a2b045Sjruoho * Update GPE information. 81380a2b045Sjruoho * 81480a2b045Sjruoho * Note that this must be called after 81580a2b045Sjruoho * all GPE handlers have been installed. 81680a2b045Sjruoho */ 81780a2b045Sjruoho (void)AcpiUpdateAllGpes(); 81880a2b045Sjruoho 81980a2b045Sjruoho /* 820e008cf16Sjruoho * Defer rest of the configuration. 821e008cf16Sjruoho */ 822e008cf16Sjruoho (void)config_defer(sc->sc_dev, acpi_rescan_capabilities); 823222f7adfSdyoung } 824222f7adfSdyoung 825de6a49e8Sskrll // XXXNH? 826439fe919Sjmcneill static void 827439fe919Sjmcneill acpi_config_dma(struct acpi_softc *sc) 828439fe919Sjmcneill { 829439fe919Sjmcneill struct acpi_devnode *ad; 830439fe919Sjmcneill 831de6a49e8Sskrll SIMPLEQ_FOREACH(ad, &sc->sc_head, ad_list) { 832439fe919Sjmcneill 833439fe919Sjmcneill if (ad->ad_device != NULL) 834439fe919Sjmcneill continue; 835439fe919Sjmcneill 836439fe919Sjmcneill if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE) 837439fe919Sjmcneill continue; 838439fe919Sjmcneill 839439fe919Sjmcneill ad->ad_dmat = acpi_get_dma_tag(sc, ad); 840439fe919Sjmcneill ad->ad_dmat64 = acpi_get_dma64_tag(sc, ad); 841439fe919Sjmcneill } 842439fe919Sjmcneill } 843439fe919Sjmcneill 844beb4a7feSkochi static ACPI_STATUS 84578670726Sjruoho acpi_make_devnode(ACPI_HANDLE handle, uint32_t level, 84678670726Sjruoho void *context, void **status) 84769f30a11Sthorpej { 8480c6bf9beSjruoho struct acpi_walkcontext *awc = context; 8490c6bf9beSjruoho struct acpi_softc *sc = awc->aw_sc; 85069f30a11Sthorpej struct acpi_devnode *ad; 85184795bd3Skochi ACPI_DEVICE_INFO *devinfo; 85278670726Sjruoho ACPI_OBJECT_TYPE type; 85378670726Sjruoho ACPI_STATUS rv; 85469f30a11Sthorpej 855b32f00afSjruoho rv = AcpiGetObjectInfo(handle, &devinfo); 85678670726Sjruoho 85778670726Sjruoho if (ACPI_FAILURE(rv)) 85878670726Sjruoho return AE_OK; /* Do not terminate the walk. */ 85978670726Sjruoho 860b32f00afSjruoho type = devinfo->Type; 8619ae405a1Saugustss 86269f30a11Sthorpej switch (type) { 86378670726Sjruoho 86469f30a11Sthorpej case ACPI_TYPE_DEVICE: 8659ae405a1Saugustss acpi_activate_device(handle, &devinfo); 86696228e02Sjmcneill /* FALLTHROUGH */ 86796228e02Sjmcneill 86869f30a11Sthorpej case ACPI_TYPE_PROCESSOR: 86969f30a11Sthorpej case ACPI_TYPE_THERMAL: 87069f30a11Sthorpej case ACPI_TYPE_POWER: 87178670726Sjruoho 872ce0335d4Sjruoho ad = kmem_zalloc(sizeof(*ad), KM_SLEEP); 87378670726Sjruoho 87455052ecaSjruoho ad->ad_device = NULL; 8750c6bf9beSjruoho ad->ad_notify = NULL; 876b3ff23fbSjruoho ad->ad_pciinfo = NULL; 87780a2b045Sjruoho ad->ad_wakedev = NULL; 87855052ecaSjruoho 87969f30a11Sthorpej ad->ad_type = type; 88055052ecaSjruoho ad->ad_handle = handle; 88155052ecaSjruoho ad->ad_devinfo = devinfo; 88269f30a11Sthorpej 8830c6bf9beSjruoho ad->ad_root = sc->sc_dev; 8840c6bf9beSjruoho ad->ad_parent = awc->aw_parent; 8850c6bf9beSjruoho 886a9db528eSjruoho acpi_match_node_init(ad); 8870af1ebd4Sjruoho acpi_make_name(ad, devinfo->Name); 8888b3327feScube 88980a2b045Sjruoho /* 89080a2b045Sjruoho * Identify wake GPEs from the _PRW. Note that 89180a2b045Sjruoho * AcpiUpdateAllGpes() must be called afterwards. 89280a2b045Sjruoho */ 89380a2b045Sjruoho if (ad->ad_devinfo->Type == ACPI_TYPE_DEVICE) 89480a2b045Sjruoho acpi_wakedev_init(ad); 89580a2b045Sjruoho 8960c6bf9beSjruoho SIMPLEQ_INIT(&ad->ad_child_head); 897de6a49e8Sskrll SIMPLEQ_INSERT_TAIL(&sc->sc_head, ad, ad_list); 898dbbb0499Sjmcneill SIMPLEQ_INIT(&ad->ad_deps); 8990c6bf9beSjruoho 9000c6bf9beSjruoho if (ad->ad_parent != NULL) { 9010c6bf9beSjruoho 9020c6bf9beSjruoho SIMPLEQ_INSERT_TAIL(&ad->ad_parent->ad_child_head, 9030c6bf9beSjruoho ad, ad_child_list); 9040c6bf9beSjruoho } 9050c6bf9beSjruoho 9060c6bf9beSjruoho awc->aw_parent = ad; 9077ca8eb7dSmaxv break; 9087ca8eb7dSmaxv 9097ca8eb7dSmaxv default: 9107ca8eb7dSmaxv ACPI_FREE(devinfo); 9117ca8eb7dSmaxv break; 91269f30a11Sthorpej } 91378670726Sjruoho 9142bde9b60Skochi return AE_OK; 91569f30a11Sthorpej } 91669f30a11Sthorpej 9170c6bf9beSjruoho static ACPI_STATUS 9180c6bf9beSjruoho acpi_make_devnode_post(ACPI_HANDLE handle, uint32_t level, 9190c6bf9beSjruoho void *context, void **status) 9200c6bf9beSjruoho { 9210c6bf9beSjruoho struct acpi_walkcontext *awc = context; 9220c6bf9beSjruoho 9230c6bf9beSjruoho KASSERT(awc != NULL); 9240c6bf9beSjruoho KASSERT(awc->aw_parent != NULL); 9250c6bf9beSjruoho 9260c6bf9beSjruoho if (handle == awc->aw_parent->ad_handle) 9270c6bf9beSjruoho awc->aw_parent = awc->aw_parent->ad_parent; 9280c6bf9beSjruoho 9290c6bf9beSjruoho return AE_OK; 9300c6bf9beSjruoho } 9310c6bf9beSjruoho 9320af1ebd4Sjruoho static void 9330af1ebd4Sjruoho acpi_make_name(struct acpi_devnode *ad, uint32_t name) 9340af1ebd4Sjruoho { 9350af1ebd4Sjruoho ACPI_NAME_UNION *anu; 9360af1ebd4Sjruoho int clear, i; 9370af1ebd4Sjruoho 9380af1ebd4Sjruoho anu = (ACPI_NAME_UNION *)&name; 9390af1ebd4Sjruoho ad->ad_name[4] = '\0'; 9400af1ebd4Sjruoho 9410af1ebd4Sjruoho for (i = 3, clear = 0; i >= 0; i--) { 9420af1ebd4Sjruoho 9430af1ebd4Sjruoho if (clear == 0 && anu->Ascii[i] == '_') 9440af1ebd4Sjruoho ad->ad_name[i] = '\0'; 9450af1ebd4Sjruoho else { 9460af1ebd4Sjruoho ad->ad_name[i] = anu->Ascii[i]; 9470af1ebd4Sjruoho clear = 1; 9480af1ebd4Sjruoho } 9490af1ebd4Sjruoho } 9500af1ebd4Sjruoho 9510af1ebd4Sjruoho if (ad->ad_name[0] == '\0') 9520af1ebd4Sjruoho ad->ad_name[0] = '_'; 9530af1ebd4Sjruoho } 9540af1ebd4Sjruoho 9553d25b0deSjmcneill bus_dma_tag_t 9563d25b0deSjmcneill acpi_default_dma_tag(struct acpi_softc *sc, struct acpi_devnode *ad) 9573d25b0deSjmcneill { 9583d25b0deSjmcneill return sc->sc_dmat; 9593d25b0deSjmcneill } 9603d25b0deSjmcneill __weak_alias(acpi_get_dma_tag,acpi_default_dma_tag); 9613d25b0deSjmcneill 9623d25b0deSjmcneill bus_dma_tag_t 9633d25b0deSjmcneill acpi_default_dma64_tag(struct acpi_softc *sc, struct acpi_devnode *ad) 9643d25b0deSjmcneill { 9653d25b0deSjmcneill return sc->sc_dmat64; 9663d25b0deSjmcneill } 9673d25b0deSjmcneill __weak_alias(acpi_get_dma64_tag,acpi_default_dma64_tag); 9683d25b0deSjmcneill 9696f25f864Sjmcneill pci_chipset_tag_t 9706f25f864Sjmcneill acpi_default_pci_chipset_tag(struct acpi_softc *sc, int seg, int bbn) 9716f25f864Sjmcneill { 9726f25f864Sjmcneill return NULL; 9736f25f864Sjmcneill } 9746f25f864Sjmcneill __weak_alias(acpi_get_pci_chipset_tag,acpi_default_pci_chipset_tag); 9756f25f864Sjmcneill 9760c88d0e4Sjruoho /* 9770c88d0e4Sjruoho * Device attachment. 9780c88d0e4Sjruoho */ 9790c88d0e4Sjruoho static int 9800c88d0e4Sjruoho acpi_rescan(device_t self, const char *ifattr, const int *locators) 9810c88d0e4Sjruoho { 9820c88d0e4Sjruoho struct acpi_softc *sc = device_private(self); 9836e72689aSjruoho struct acpi_attach_args aa; 9846e72689aSjruoho 9856e72689aSjruoho /* 9866e72689aSjruoho * Try to attach hpet(4) first via a specific table. 9876e72689aSjruoho */ 9886e72689aSjruoho aa.aa_memt = sc->sc_memt; 9896e72689aSjruoho 9902685996bSthorpej if (ifattr_match(ifattr, "acpihpetbus") && sc->sc_hpet == NULL) { 9912685996bSthorpej sc->sc_hpet = config_found(sc->sc_dev, &aa, NULL, 992c7fb772bSthorpej CFARGS(.iattr = "acpihpetbus")); 9932685996bSthorpej } 9940c88d0e4Sjruoho 995740a9e0cSjruoho /* 996740a9e0cSjruoho * A two-pass scan for acpinodebus. 997740a9e0cSjruoho */ 998740a9e0cSjruoho if (ifattr_match(ifattr, "acpinodebus")) { 999740a9e0cSjruoho acpi_rescan_early(sc); 10000c88d0e4Sjruoho acpi_rescan_nodes(sc); 1001740a9e0cSjruoho } 10020c88d0e4Sjruoho 10036e72689aSjruoho /* 10046e72689aSjruoho * Attach APM emulation and acpiwdrt(4). 10056e72689aSjruoho */ 10062685996bSthorpej if (ifattr_match(ifattr, "acpiapmbus") && sc->sc_apmbus == NULL) { 10072685996bSthorpej sc->sc_apmbus = config_found(sc->sc_dev, NULL, NULL, 1008c7fb772bSthorpej CFARGS(.iattr = "acpiapmbus")); 10092685996bSthorpej } 101062a3a065Sjruoho 10112685996bSthorpej if (ifattr_match(ifattr, "acpiwdrtbus") && sc->sc_wdrt == NULL) { 10122685996bSthorpej sc->sc_wdrt = config_found(sc->sc_dev, NULL, NULL, 1013c7fb772bSthorpej CFARGS(.iattr = "acpiwdrtbus")); 10142685996bSthorpej } 101527686d11Sjmcneill 1016062c0d7eSriastradh if (ifattr_match(ifattr, "apeibus") && sc->sc_apei == NULL) { 1017062c0d7eSriastradh sc->sc_apei = config_found(sc->sc_dev, NULL, NULL, 1018062c0d7eSriastradh CFARGS(.iattr = "apeibus")); 1019062c0d7eSriastradh } 1020062c0d7eSriastradh 102162a3a065Sjruoho return 0; 10220c88d0e4Sjruoho } 10230c88d0e4Sjruoho 10240c88d0e4Sjruoho static void 1025dbbb0499Sjmcneill acpi_rescan_node(struct acpi_softc *sc, struct acpi_devnode *ad) 1026dbbb0499Sjmcneill { 1027dbbb0499Sjmcneill const char * const hpet_ids[] = { "PNP0103", NULL }; 1028dbbb0499Sjmcneill struct acpi_attach_args aa; 1029dbbb0499Sjmcneill struct acpi_devnodedep *dd; 1030dbbb0499Sjmcneill ACPI_DEVICE_INFO *di = ad->ad_devinfo; 1031dbbb0499Sjmcneill 1032dbbb0499Sjmcneill if (ad->ad_scanned || ad->ad_device != NULL) { 1033dbbb0499Sjmcneill return; 1034dbbb0499Sjmcneill } 1035dbbb0499Sjmcneill 1036dbbb0499Sjmcneill /* 1037dbbb0499Sjmcneill * Mark as scanned before checking dependencies to 1038dbbb0499Sjmcneill * break out of dependency cycles. 1039dbbb0499Sjmcneill */ 1040dbbb0499Sjmcneill ad->ad_scanned = true; 1041dbbb0499Sjmcneill 1042dbbb0499Sjmcneill if (!acpi_device_present(ad->ad_handle)) { 1043dbbb0499Sjmcneill return; 1044dbbb0499Sjmcneill } 1045dbbb0499Sjmcneill 1046dbbb0499Sjmcneill if (acpi_match_hid(di, acpi_ignored_ids) != 0) { 1047dbbb0499Sjmcneill return; 1048dbbb0499Sjmcneill } 1049dbbb0499Sjmcneill 1050dbbb0499Sjmcneill if (acpi_match_hid(di, hpet_ids) != 0 && sc->sc_hpet != NULL) { 1051dbbb0499Sjmcneill return; 1052dbbb0499Sjmcneill } 1053dbbb0499Sjmcneill 1054dbbb0499Sjmcneill /* Rescan dependencies first. */ 1055dbbb0499Sjmcneill SIMPLEQ_FOREACH(dd, &ad->ad_deps, dd_list) { 1056dbbb0499Sjmcneill if (!dd->dd_node->ad_scanned) { 1057dbbb0499Sjmcneill acpi_rescan_node(sc, dd->dd_node); 1058dbbb0499Sjmcneill } 1059dbbb0499Sjmcneill } 1060dbbb0499Sjmcneill 1061*a93f58a9Sjmcneill /* Dependency scanning may have claimed this device. */ 1062*a93f58a9Sjmcneill if (ad->ad_device != NULL) { 1063*a93f58a9Sjmcneill return; 1064*a93f58a9Sjmcneill } 1065*a93f58a9Sjmcneill 1066dbbb0499Sjmcneill aa.aa_node = ad; 1067dbbb0499Sjmcneill aa.aa_iot = sc->sc_iot; 1068dbbb0499Sjmcneill aa.aa_memt = sc->sc_memt; 1069dbbb0499Sjmcneill if (ad->ad_pciinfo != NULL) { 1070dbbb0499Sjmcneill aa.aa_pc = ad->ad_pciinfo->ap_pc; 1071dbbb0499Sjmcneill aa.aa_pciflags = sc->sc_pciflags; 1072dbbb0499Sjmcneill } 1073dbbb0499Sjmcneill aa.aa_ic = sc->sc_ic; 1074dbbb0499Sjmcneill aa.aa_dmat = ad->ad_dmat; 1075dbbb0499Sjmcneill aa.aa_dmat64 = ad->ad_dmat64; 1076dbbb0499Sjmcneill 1077dbbb0499Sjmcneill ad->ad_device = config_found(sc->sc_dev, &aa, acpi_print, 1078dbbb0499Sjmcneill CFARGS(.iattr = "acpinodebus", 1079dbbb0499Sjmcneill .devhandle = devhandle_from_acpi(devhandle_invalid(), 1080dbbb0499Sjmcneill ad->ad_handle))); 1081dbbb0499Sjmcneill } 1082dbbb0499Sjmcneill 1083dbbb0499Sjmcneill static void 1084740a9e0cSjruoho acpi_rescan_early(struct acpi_softc *sc) 1085740a9e0cSjruoho { 1086740a9e0cSjruoho struct acpi_devnode *ad; 1087740a9e0cSjruoho 1088740a9e0cSjruoho /* 1089740a9e0cSjruoho * First scan for devices such as acpiec(4) that 1090740a9e0cSjruoho * should be always attached before anything else. 1091740a9e0cSjruoho * We want these devices to attach regardless of 1092740a9e0cSjruoho * the device status and other restrictions. 1093740a9e0cSjruoho */ 1094de6a49e8Sskrll SIMPLEQ_FOREACH(ad, &sc->sc_head, ad_list) { 1095740a9e0cSjruoho 1096740a9e0cSjruoho if (ad->ad_device != NULL) 1097740a9e0cSjruoho continue; 1098740a9e0cSjruoho 1099740a9e0cSjruoho if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE) 1100740a9e0cSjruoho continue; 1101740a9e0cSjruoho 1102740a9e0cSjruoho if (acpi_match_hid(ad->ad_devinfo, acpi_early_ids) == 0) 1103740a9e0cSjruoho continue; 1104740a9e0cSjruoho 11052685996bSthorpej KASSERT(ad->ad_handle != NULL); 11062685996bSthorpej 1107dbbb0499Sjmcneill acpi_rescan_node(sc, ad); 1108740a9e0cSjruoho } 1109740a9e0cSjruoho } 1110740a9e0cSjruoho 1111740a9e0cSjruoho static void 11120c88d0e4Sjruoho acpi_rescan_nodes(struct acpi_softc *sc) 11130c88d0e4Sjruoho { 11140c88d0e4Sjruoho struct acpi_devnode *ad; 1115d5124a18Sjruoho ACPI_DEVICE_INFO *di; 11160c88d0e4Sjruoho 1117dbbb0499Sjmcneill /* Reset scan state. */ 1118dbbb0499Sjmcneill SIMPLEQ_FOREACH(ad, &sc->sc_head, ad_list) { 1119dbbb0499Sjmcneill ad->ad_scanned = false; 1120dbbb0499Sjmcneill } 1121dbbb0499Sjmcneill 1122de6a49e8Sskrll SIMPLEQ_FOREACH(ad, &sc->sc_head, ad_list) { 11230c88d0e4Sjruoho 11240c88d0e4Sjruoho if (ad->ad_device != NULL) 11250c88d0e4Sjruoho continue; 11260c88d0e4Sjruoho 11272203417fSjruoho /* 11282203417fSjruoho * There is a bug in ACPICA: it defines the type 11292203417fSjruoho * of the scopes incorrectly for its own reasons. 11302203417fSjruoho */ 11312203417fSjruoho if (acpi_is_scope(ad) != false) 11322203417fSjruoho continue; 11330c88d0e4Sjruoho 1134d5124a18Sjruoho di = ad->ad_devinfo; 1135d5124a18Sjruoho 1136a2cf80f2Schristos /* 1137a2cf80f2Schristos * We only attach devices which are present, enabled, and 1138a2cf80f2Schristos * functioning properly. However, if a device is enabled, 1139a2cf80f2Schristos * it is decoding resources and we should claim these, 1140a2cf80f2Schristos * if possible. This requires changes to bus_space(9). 1141a2cf80f2Schristos */ 1142a2cf80f2Schristos if (di->Type == ACPI_TYPE_DEVICE && 1143a2cf80f2Schristos !acpi_device_present(ad->ad_handle)) { 1144a2cf80f2Schristos continue; 1145a2cf80f2Schristos } 1146a2cf80f2Schristos 11474d861e5bSjruoho if (di->Type == ACPI_TYPE_POWER) 11480c88d0e4Sjruoho continue; 11490c88d0e4Sjruoho 1150494badebSjruoho if (di->Type == ACPI_TYPE_PROCESSOR) 11513dd22c3cSjruoho continue; 11523dd22c3cSjruoho 1153d982261bSjruoho if (acpi_match_hid(di, acpi_early_ids) != 0) 1154d982261bSjruoho continue; 1155d982261bSjruoho 11562685996bSthorpej KASSERT(ad->ad_handle != NULL); 11572685996bSthorpej 1158dbbb0499Sjmcneill acpi_rescan_node(sc, ad); 11590c88d0e4Sjruoho } 11600c88d0e4Sjruoho } 11610c88d0e4Sjruoho 11620c88d0e4Sjruoho static void 1163e008cf16Sjruoho acpi_rescan_capabilities(device_t self) 11640c88d0e4Sjruoho { 1165e008cf16Sjruoho struct acpi_softc *sc = device_private(self); 11660c88d0e4Sjruoho struct acpi_devnode *ad; 11670c88d0e4Sjruoho ACPI_HANDLE tmp; 11680c88d0e4Sjruoho ACPI_STATUS rv; 11690c88d0e4Sjruoho 1170de6a49e8Sskrll SIMPLEQ_FOREACH(ad, &sc->sc_head, ad_list) { 11710c88d0e4Sjruoho 1172881c3c1eSjruoho if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE) 11730c88d0e4Sjruoho continue; 11740c88d0e4Sjruoho 11750c88d0e4Sjruoho /* 11760c88d0e4Sjruoho * Scan power resource capabilities. 11779ddf2c51Sjruoho * 11789ddf2c51Sjruoho * If any power states are supported, 11799ddf2c51Sjruoho * at least _PR0 and _PR3 must be present. 11800c88d0e4Sjruoho */ 11810c88d0e4Sjruoho rv = AcpiGetHandle(ad->ad_handle, "_PR0", &tmp); 11820c88d0e4Sjruoho 11839ddf2c51Sjruoho if (ACPI_SUCCESS(rv)) { 11840c88d0e4Sjruoho ad->ad_flags |= ACPI_DEVICE_POWER; 118516bdc3ffSjruoho acpi_power_add(ad); 11869ddf2c51Sjruoho } 11870c88d0e4Sjruoho 11880c88d0e4Sjruoho /* 11890c88d0e4Sjruoho * Scan wake-up capabilities. 11900c88d0e4Sjruoho */ 119180a2b045Sjruoho if (ad->ad_wakedev != NULL) { 11920c88d0e4Sjruoho ad->ad_flags |= ACPI_DEVICE_WAKEUP; 11930c88d0e4Sjruoho acpi_wakedev_add(ad); 11940c88d0e4Sjruoho } 11956a3b9e2cSjruoho 11966a3b9e2cSjruoho /* 1197710112e7Sjruoho * Scan docking stations. 1198710112e7Sjruoho */ 1199710112e7Sjruoho rv = AcpiGetHandle(ad->ad_handle, "_DCK", &tmp); 1200710112e7Sjruoho 1201710112e7Sjruoho if (ACPI_SUCCESS(rv)) 1202710112e7Sjruoho ad->ad_flags |= ACPI_DEVICE_DOCK; 1203710112e7Sjruoho 1204710112e7Sjruoho /* 12056a3b9e2cSjruoho * Scan devices that are ejectable. 12066a3b9e2cSjruoho */ 12076a3b9e2cSjruoho rv = AcpiGetHandle(ad->ad_handle, "_EJ0", &tmp); 12086a3b9e2cSjruoho 12096a3b9e2cSjruoho if (ACPI_SUCCESS(rv)) 12106a3b9e2cSjruoho ad->ad_flags |= ACPI_DEVICE_EJECT; 12110c88d0e4Sjruoho } 12120c88d0e4Sjruoho } 12130c88d0e4Sjruoho 1214beb4a7feSkochi static int 121569f30a11Sthorpej acpi_print(void *aux, const char *pnp) 121669f30a11Sthorpej { 121769f30a11Sthorpej struct acpi_attach_args *aa = aux; 1218f861d1bcSjruoho struct acpi_devnode *ad; 1219f861d1bcSjruoho const char *hid, *uid; 1220f861d1bcSjruoho ACPI_DEVICE_INFO *di; 122169f30a11Sthorpej 1222f861d1bcSjruoho ad = aa->aa_node; 1223f861d1bcSjruoho di = ad->ad_devinfo; 1224c601b235Schristos 1225f861d1bcSjruoho hid = di->HardwareId.String; 1226f861d1bcSjruoho uid = di->UniqueId.String; 12271f5b658bSmlelstv 1228f861d1bcSjruoho if (pnp != NULL) { 1229f861d1bcSjruoho 1230f861d1bcSjruoho if (di->Type != ACPI_TYPE_DEVICE) { 1231f861d1bcSjruoho 1232f861d1bcSjruoho aprint_normal("%s (ACPI Object Type '%s') at %s", 1233f861d1bcSjruoho ad->ad_name, AcpiUtGetTypeName(ad->ad_type), pnp); 1234f861d1bcSjruoho 1235f861d1bcSjruoho return UNCONF; 12361f5b658bSmlelstv } 1237c601b235Schristos 1238f861d1bcSjruoho if ((di->Valid & ACPI_VALID_HID) == 0 || hid == NULL) 12394c1d81b2Sjmcneill return 0; 1240c601b235Schristos 1241f861d1bcSjruoho aprint_normal("%s (%s) ", ad->ad_name, hid); 1242f861d1bcSjruoho acpi_print_dev(hid); 1243f861d1bcSjruoho aprint_normal("at %s", pnp); 1244f861d1bcSjruoho 1245f861d1bcSjruoho return UNCONF; 1246f861d1bcSjruoho } 1247f861d1bcSjruoho 1248f861d1bcSjruoho aprint_normal(" (%s", ad->ad_name); 1249f861d1bcSjruoho 1250f861d1bcSjruoho if ((di->Valid & ACPI_VALID_HID) != 0 && hid != NULL) { 1251f861d1bcSjruoho 1252f861d1bcSjruoho aprint_normal(", %s", hid); 1253f861d1bcSjruoho 1254f861d1bcSjruoho if ((di->Valid & ACPI_VALID_UID) != 0 && uid != NULL) { 1255f861d1bcSjruoho 1256fec4c11fSmycroft if (uid[0] == '\0') 12573893537dSjmcneill uid = "<null>"; 1258f861d1bcSjruoho 125972a7af27Sthorpej aprint_normal("-%s", uid); 12603893537dSjmcneill } 1261fa591d48Sthorpej } 1262f861d1bcSjruoho 12638b3327feScube aprint_normal(")"); 126469f30a11Sthorpej 12652bde9b60Skochi return UNCONF; 126669f30a11Sthorpej } 126769f30a11Sthorpej 126869f30a11Sthorpej /* 126955052ecaSjruoho * Notify. 127055052ecaSjruoho */ 127155052ecaSjruoho static void 127255052ecaSjruoho acpi_notify_handler(ACPI_HANDLE handle, uint32_t event, void *aux) 127355052ecaSjruoho { 127455052ecaSjruoho struct acpi_softc *sc = acpi_softc; 127555052ecaSjruoho struct acpi_devnode *ad; 1276cf234944Sriastradh ACPI_NOTIFY_HANDLER notify; 127755052ecaSjruoho 127855052ecaSjruoho KASSERT(sc != NULL); 127955052ecaSjruoho KASSERT(aux == NULL); 128055052ecaSjruoho KASSERT(acpi_active != 0); 128155052ecaSjruoho 128255052ecaSjruoho if (acpi_suspended != 0) 128355052ecaSjruoho return; 128455052ecaSjruoho 128555052ecaSjruoho /* 128655052ecaSjruoho * System: 0x00 - 0x7F. 128755052ecaSjruoho * Device: 0x80 - 0xFF. 128855052ecaSjruoho */ 128955052ecaSjruoho switch (event) { 129055052ecaSjruoho 129155052ecaSjruoho case ACPI_NOTIFY_BUS_CHECK: 129255052ecaSjruoho case ACPI_NOTIFY_DEVICE_CHECK: 129355052ecaSjruoho case ACPI_NOTIFY_DEVICE_WAKE: 129455052ecaSjruoho case ACPI_NOTIFY_EJECT_REQUEST: 129555052ecaSjruoho case ACPI_NOTIFY_DEVICE_CHECK_LIGHT: 129655052ecaSjruoho case ACPI_NOTIFY_FREQUENCY_MISMATCH: 129755052ecaSjruoho case ACPI_NOTIFY_BUS_MODE_MISMATCH: 129855052ecaSjruoho case ACPI_NOTIFY_POWER_FAULT: 129955052ecaSjruoho case ACPI_NOTIFY_CAPABILITIES_CHECK: 130055052ecaSjruoho case ACPI_NOTIFY_DEVICE_PLD_CHECK: 130155052ecaSjruoho case ACPI_NOTIFY_RESERVED: 130255052ecaSjruoho case ACPI_NOTIFY_LOCALITY_UPDATE: 130355052ecaSjruoho break; 130455052ecaSjruoho } 130555052ecaSjruoho 130655052ecaSjruoho ACPI_DEBUG_PRINT((ACPI_DB_INFO, "notification 0x%02X for " 130755052ecaSjruoho "%s (%p)\n", event, acpi_name(handle), handle)); 130855052ecaSjruoho 130955052ecaSjruoho /* 131055052ecaSjruoho * We deliver notifications only to drivers 1311041ea587Sjakllsch * that have been successfully attached and 131255052ecaSjruoho * that have registered a handler with us. 131355052ecaSjruoho * The opaque pointer is always the device_t. 131455052ecaSjruoho */ 1315de6a49e8Sskrll SIMPLEQ_FOREACH(ad, &sc->sc_head, ad_list) { 131655052ecaSjruoho 131755052ecaSjruoho if (ad->ad_device == NULL) 131855052ecaSjruoho continue; 131955052ecaSjruoho 1320cf234944Sriastradh if ((notify = atomic_load_acquire(&ad->ad_notify)) == NULL) 132155052ecaSjruoho continue; 132255052ecaSjruoho 132355052ecaSjruoho if (ad->ad_handle != handle) 132455052ecaSjruoho continue; 132555052ecaSjruoho 1326cf234944Sriastradh (*notify)(ad->ad_handle, event, ad->ad_device); 132755052ecaSjruoho 132855052ecaSjruoho return; 132955052ecaSjruoho } 133055052ecaSjruoho 133155052ecaSjruoho aprint_debug_dev(sc->sc_dev, "unhandled notify 0x%02X " 133255052ecaSjruoho "for %s (%p)\n", event, acpi_name(handle), handle); 133355052ecaSjruoho } 133455052ecaSjruoho 133555052ecaSjruoho bool 133655052ecaSjruoho acpi_register_notify(struct acpi_devnode *ad, ACPI_NOTIFY_HANDLER notify) 133755052ecaSjruoho { 133855052ecaSjruoho struct acpi_softc *sc = acpi_softc; 133955052ecaSjruoho 134055052ecaSjruoho KASSERT(sc != NULL); 134155052ecaSjruoho KASSERT(acpi_active != 0); 134255052ecaSjruoho 134355052ecaSjruoho if (acpi_suspended != 0) 134455052ecaSjruoho goto fail; 134555052ecaSjruoho 134655052ecaSjruoho if (ad == NULL || notify == NULL) 134755052ecaSjruoho goto fail; 134855052ecaSjruoho 13493c8f7268Sriastradh KASSERTMSG(ad->ad_notify == NULL, 13503c8f7268Sriastradh "%s: ACPI node %s already has notify handler: %p", 13513c8f7268Sriastradh ad->ad_device ? device_xname(ad->ad_device) : "(unknown)", 13523c8f7268Sriastradh ad->ad_name, 13533c8f7268Sriastradh ad->ad_notify); 1354cf234944Sriastradh atomic_store_release(&ad->ad_notify, notify); 135555052ecaSjruoho 135655052ecaSjruoho return true; 135755052ecaSjruoho 135855052ecaSjruoho fail: 135955052ecaSjruoho aprint_error_dev(sc->sc_dev, "failed to register notify " 136055052ecaSjruoho "handler for %s (%p)\n", ad->ad_name, ad->ad_handle); 136155052ecaSjruoho 136255052ecaSjruoho return false; 136355052ecaSjruoho } 136455052ecaSjruoho 136555052ecaSjruoho void 136655052ecaSjruoho acpi_deregister_notify(struct acpi_devnode *ad) 136755052ecaSjruoho { 136855052ecaSjruoho 1369cf234944Sriastradh atomic_store_relaxed(&ad->ad_notify, NULL); 1370cf234944Sriastradh 1371cf234944Sriastradh /* Wait for any in-flight calls to the notifier to complete. */ 1372cf234944Sriastradh AcpiOsWaitEventsComplete(); 137355052ecaSjruoho } 137455052ecaSjruoho 137555052ecaSjruoho /* 1376426356f9Sjruoho * Fixed buttons. 137769f30a11Sthorpej */ 1378beb4a7feSkochi static void 1379426356f9Sjruoho acpi_register_fixed_button(struct acpi_softc *sc, int event) 138069f30a11Sthorpej { 1381426356f9Sjruoho struct sysmon_pswitch *smpsw; 1382426356f9Sjruoho ACPI_STATUS rv; 1383426356f9Sjruoho int type; 1384426356f9Sjruoho 1385426356f9Sjruoho switch (event) { 1386426356f9Sjruoho 1387426356f9Sjruoho case ACPI_EVENT_POWER_BUTTON: 1388426356f9Sjruoho 1389426356f9Sjruoho if ((AcpiGbl_FADT.Flags & ACPI_FADT_POWER_BUTTON) != 0) 1390426356f9Sjruoho return; 1391426356f9Sjruoho 1392426356f9Sjruoho type = PSWITCH_TYPE_POWER; 1393426356f9Sjruoho smpsw = &sc->sc_smpsw_power; 1394426356f9Sjruoho break; 1395426356f9Sjruoho 1396426356f9Sjruoho case ACPI_EVENT_SLEEP_BUTTON: 1397426356f9Sjruoho 1398426356f9Sjruoho if ((AcpiGbl_FADT.Flags & ACPI_FADT_SLEEP_BUTTON) != 0) 1399426356f9Sjruoho return; 1400426356f9Sjruoho 1401426356f9Sjruoho type = PSWITCH_TYPE_SLEEP; 1402426356f9Sjruoho smpsw = &sc->sc_smpsw_sleep; 1403426356f9Sjruoho break; 1404426356f9Sjruoho 1405426356f9Sjruoho default: 1406426356f9Sjruoho rv = AE_TYPE; 1407426356f9Sjruoho goto fail; 1408426356f9Sjruoho } 1409426356f9Sjruoho 1410426356f9Sjruoho smpsw->smpsw_type = type; 1411426356f9Sjruoho smpsw->smpsw_name = device_xname(sc->sc_dev); 1412426356f9Sjruoho 1413426356f9Sjruoho if (sysmon_pswitch_register(smpsw) != 0) { 1414426356f9Sjruoho rv = AE_ERROR; 1415426356f9Sjruoho goto fail; 1416426356f9Sjruoho } 1417426356f9Sjruoho 1418704e16c1Sjakllsch AcpiClearEvent(event); 1419704e16c1Sjakllsch 1420426356f9Sjruoho rv = AcpiInstallFixedEventHandler(event, 1421426356f9Sjruoho acpi_fixed_button_handler, smpsw); 1422426356f9Sjruoho 142303fcc342Sjruoho if (ACPI_FAILURE(rv)) { 142403fcc342Sjruoho sysmon_pswitch_unregister(smpsw); 1425426356f9Sjruoho goto fail; 142603fcc342Sjruoho } 1427426356f9Sjruoho 1428fb3dc779Sryoon aprint_normal_dev(sc->sc_dev, "fixed %s button present\n", 1429abc4d7caSjmcneill (type != PSWITCH_TYPE_SLEEP) ? "power" : "sleep"); 1430426356f9Sjruoho 1431426356f9Sjruoho return; 1432426356f9Sjruoho 1433426356f9Sjruoho fail: 1434426356f9Sjruoho aprint_error_dev(sc->sc_dev, "failed to register " 1435aff0a6a0Sjakllsch "fixed event %d: %s\n", event, AcpiFormatException(rv)); 1436426356f9Sjruoho } 1437426356f9Sjruoho 1438426356f9Sjruoho static void 1439426356f9Sjruoho acpi_deregister_fixed_button(struct acpi_softc *sc, int event) 1440426356f9Sjruoho { 1441426356f9Sjruoho struct sysmon_pswitch *smpsw; 144269f30a11Sthorpej ACPI_STATUS rv; 144369f30a11Sthorpej 1444426356f9Sjruoho switch (event) { 144559ea64b6Sthorpej 1446426356f9Sjruoho case ACPI_EVENT_POWER_BUTTON: 1447426356f9Sjruoho smpsw = &sc->sc_smpsw_power; 1448426356f9Sjruoho 1449426356f9Sjruoho if ((AcpiGbl_FADT.Flags & ACPI_FADT_POWER_BUTTON) != 0) { 1450426356f9Sjruoho KASSERT(smpsw->smpsw_type != PSWITCH_TYPE_POWER); 1451426356f9Sjruoho return; 145269f30a11Sthorpej } 145369f30a11Sthorpej 1454426356f9Sjruoho break; 1455426356f9Sjruoho 1456426356f9Sjruoho case ACPI_EVENT_SLEEP_BUTTON: 1457426356f9Sjruoho smpsw = &sc->sc_smpsw_sleep; 1458426356f9Sjruoho 1459426356f9Sjruoho if ((AcpiGbl_FADT.Flags & ACPI_FADT_SLEEP_BUTTON) != 0) { 1460426356f9Sjruoho KASSERT(smpsw->smpsw_type != PSWITCH_TYPE_SLEEP); 1461426356f9Sjruoho return; 146259ea64b6Sthorpej } 146359ea64b6Sthorpej 1464426356f9Sjruoho break; 1465426356f9Sjruoho 1466426356f9Sjruoho default: 1467426356f9Sjruoho rv = AE_TYPE; 1468426356f9Sjruoho goto fail; 1469426356f9Sjruoho } 1470426356f9Sjruoho 1471426356f9Sjruoho rv = AcpiRemoveFixedEventHandler(event, acpi_fixed_button_handler); 1472426356f9Sjruoho 1473426356f9Sjruoho if (ACPI_SUCCESS(rv)) { 1474426356f9Sjruoho sysmon_pswitch_unregister(smpsw); 1475426356f9Sjruoho return; 1476426356f9Sjruoho } 1477426356f9Sjruoho 1478426356f9Sjruoho fail: 1479426356f9Sjruoho aprint_error_dev(sc->sc_dev, "failed to deregister " 1480426356f9Sjruoho "fixed event: %s\n", AcpiFormatException(rv)); 1481426356f9Sjruoho } 1482426356f9Sjruoho 1483426356f9Sjruoho static uint32_t 148459ea64b6Sthorpej acpi_fixed_button_handler(void *context) 148559ea64b6Sthorpej { 14866957e121Sjruoho static const int handler = OSL_NOTIFY_HANDLER; 148759ea64b6Sthorpej struct sysmon_pswitch *smpsw = context; 148859ea64b6Sthorpej 14896957e121Sjruoho (void)AcpiOsExecute(handler, acpi_fixed_button_pressed, smpsw); 149069f30a11Sthorpej 14912bde9b60Skochi return ACPI_INTERRUPT_HANDLED; 149269f30a11Sthorpej } 149369f30a11Sthorpej 1494beb4a7feSkochi static void 149559ea64b6Sthorpej acpi_fixed_button_pressed(void *context) 149669f30a11Sthorpej { 149759ea64b6Sthorpej struct sysmon_pswitch *smpsw = context; 149869f30a11Sthorpej 149903fcc342Sjruoho ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s fixed button pressed\n", 150003fcc342Sjruoho (smpsw->smpsw_type != ACPI_EVENT_SLEEP_BUTTON) ? 150103fcc342Sjruoho "power" : "sleep")); 150269f30a11Sthorpej 15035a20f4beSthorpej sysmon_pswitch_event(smpsw, PSWITCH_EVENT_PRESSED); 150469f30a11Sthorpej } 150569f30a11Sthorpej 15066179b9baSthorpej /* 15070c88d0e4Sjruoho * Sleep. 1508fb74e5b5Sjruoho */ 1509fb74e5b5Sjruoho static void 1510fb74e5b5Sjruoho acpi_sleep_init(struct acpi_softc *sc) 151136809088Stshiozak { 1512fb74e5b5Sjruoho uint8_t a, b, i; 1513fb74e5b5Sjruoho ACPI_STATUS rv; 151436809088Stshiozak 1515fb74e5b5Sjruoho CTASSERT(ACPI_STATE_S0 == 0 && ACPI_STATE_S1 == 1); 1516fb74e5b5Sjruoho CTASSERT(ACPI_STATE_S2 == 2 && ACPI_STATE_S3 == 3); 1517fb74e5b5Sjruoho CTASSERT(ACPI_STATE_S4 == 4 && ACPI_STATE_S5 == 5); 1518fb74e5b5Sjruoho 15190c88d0e4Sjruoho /* 15200c88d0e4Sjruoho * Evaluate supported sleep states. 15210c88d0e4Sjruoho */ 1522fb74e5b5Sjruoho for (i = ACPI_STATE_S0; i <= ACPI_STATE_S5; i++) { 1523fb74e5b5Sjruoho 1524fb74e5b5Sjruoho rv = AcpiGetSleepTypeData(i, &a, &b); 1525fb74e5b5Sjruoho 1526fb74e5b5Sjruoho if (ACPI_SUCCESS(rv)) 1527fb74e5b5Sjruoho sc->sc_sleepstates |= __BIT(i); 1528fb74e5b5Sjruoho } 152936809088Stshiozak } 153036809088Stshiozak 1531c2df94f2Sjruoho /* 1532c2df94f2Sjruoho * Must be called with interrupts enabled. 1533c2df94f2Sjruoho */ 1534cd892425Sjruoho void 1535c99562cbSjruoho acpi_enter_sleep_state(int state) 153636809088Stshiozak { 1537c99562cbSjruoho struct acpi_softc *sc = acpi_softc; 1538cd892425Sjruoho ACPI_STATUS rv; 153936809088Stshiozak 1540c99562cbSjruoho if (acpi_softc == NULL) 1541c99562cbSjruoho return; 1542c99562cbSjruoho 1543fb74e5b5Sjruoho if (state == sc->sc_sleepstate) 1544cd892425Sjruoho return; 154546e62b97Schristos 1546c99562cbSjruoho if (state < ACPI_STATE_S0 || state > ACPI_STATE_S5) 1547c99562cbSjruoho return; 1548c99562cbSjruoho 1549fb74e5b5Sjruoho aprint_normal_dev(sc->sc_dev, "entering state S%d\n", state); 155046e62b97Schristos 155136809088Stshiozak switch (state) { 1552fb74e5b5Sjruoho 155336809088Stshiozak case ACPI_STATE_S0: 1554cd892425Sjruoho sc->sc_sleepstate = ACPI_STATE_S0; 1555cd892425Sjruoho return; 1556fb74e5b5Sjruoho 155736809088Stshiozak case ACPI_STATE_S1: 155836809088Stshiozak case ACPI_STATE_S2: 155936809088Stshiozak case ACPI_STATE_S3: 156036809088Stshiozak case ACPI_STATE_S4: 1561fb74e5b5Sjruoho 1562fb74e5b5Sjruoho if ((sc->sc_sleepstates & __BIT(state)) == 0) { 1563fb74e5b5Sjruoho aprint_error_dev(sc->sc_dev, "sleep state " 1564fb74e5b5Sjruoho "S%d is not available\n", state); 1565cd892425Sjruoho return; 156636809088Stshiozak } 15674c1d81b2Sjmcneill 15680c1ea6e2Sjruoho /* 1569902b3840Sjruoho * Evaluate the _TTS method. This should be done before 1570902b3840Sjruoho * pmf_system_suspend(9) and the evaluation of _PTS. 1571902b3840Sjruoho * We should also re-evaluate this once we return to 1572902b3840Sjruoho * S0 or if we abort the sleep state transition in the 1573902b3840Sjruoho * middle (see ACPI 3.0, section 7.3.6). In reality, 1574902b3840Sjruoho * however, the _TTS method is seldom seen in the field. 157561a52d76Sjruoho */ 157661a52d76Sjruoho rv = acpi_eval_set_integer(NULL, "\\_TTS", state); 157761a52d76Sjruoho 157861a52d76Sjruoho if (ACPI_SUCCESS(rv)) 157961a52d76Sjruoho aprint_debug_dev(sc->sc_dev, "evaluated _TTS\n"); 158061a52d76Sjruoho 1581902b3840Sjruoho if (state != ACPI_STATE_S1 && 1582902b3840Sjruoho pmf_system_suspend(PMF_Q_NONE) != true) { 1583902b3840Sjruoho aprint_error_dev(sc->sc_dev, "aborting suspend\n"); 1584902b3840Sjruoho break; 1585902b3840Sjruoho } 1586902b3840Sjruoho 158761a52d76Sjruoho /* 15880c1ea6e2Sjruoho * This will evaluate the _PTS and _SST methods, 15890c1ea6e2Sjruoho * but unlike the documentation claims, not _GTS, 15900c1ea6e2Sjruoho * which is evaluated in AcpiEnterSleepState(). 15910c1ea6e2Sjruoho * This must be called with interrupts enabled. 15920c1ea6e2Sjruoho */ 1593fb74e5b5Sjruoho rv = AcpiEnterSleepStatePrep(state); 1594fb74e5b5Sjruoho 1595fb74e5b5Sjruoho if (ACPI_FAILURE(rv)) { 1596fb74e5b5Sjruoho aprint_error_dev(sc->sc_dev, "failed to prepare " 1597fb74e5b5Sjruoho "S%d: %s\n", state, AcpiFormatException(rv)); 159836809088Stshiozak break; 159936809088Stshiozak } 16004c1d81b2Sjmcneill 16014dc5d3caSjruoho /* 16024dc5d3caSjruoho * After the _PTS method has been evaluated, we can 16034dc5d3caSjruoho * enable wake and evaluate _PSW (ACPI 4.0, p. 284). 16044dc5d3caSjruoho */ 16054dc5d3caSjruoho acpi_wakedev_commit(sc, state); 16064dc5d3caSjruoho 1607fb74e5b5Sjruoho sc->sc_sleepstate = state; 1608fb74e5b5Sjruoho 160936809088Stshiozak if (state == ACPI_STATE_S1) { 1610fb74e5b5Sjruoho 161167a63399Sjruoho /* 1612224e9f93Sjruoho * Before the transition to S1, CPU caches 1613224e9f93Sjruoho * must be flushed (see ACPI 4.0, 7.3.4.2). 1614224e9f93Sjruoho * 1615224e9f93Sjruoho * Note that interrupts must be off before 1616224e9f93Sjruoho * calling AcpiEnterSleepState(). Conversely, 1617224e9f93Sjruoho * AcpiLeaveSleepState() should always be 1618224e9f93Sjruoho * called with interrupts enabled. 161967a63399Sjruoho */ 162069c89290Skanaoka acpi_md_OsDisableInterrupt(); 1621224e9f93Sjruoho 1622224e9f93Sjruoho ACPI_FLUSH_CPU_CACHE(); 1623fb74e5b5Sjruoho rv = AcpiEnterSleepState(state); 1624fb74e5b5Sjruoho 1625fb74e5b5Sjruoho if (ACPI_FAILURE(rv)) 1626fb74e5b5Sjruoho aprint_error_dev(sc->sc_dev, "failed to " 1627fb74e5b5Sjruoho "enter S1: %s\n", AcpiFormatException(rv)); 1628fb74e5b5Sjruoho 162911e87ad5Sjmcneill /* 163011e87ad5Sjmcneill * Clear fixed events and disable all GPEs before 163111e87ad5Sjmcneill * interrupts are enabled. 163211e87ad5Sjmcneill */ 163311e87ad5Sjmcneill AcpiClearEvent(ACPI_EVENT_PMTIMER); 163411e87ad5Sjmcneill AcpiClearEvent(ACPI_EVENT_GLOBAL); 163511e87ad5Sjmcneill AcpiClearEvent(ACPI_EVENT_POWER_BUTTON); 163611e87ad5Sjmcneill AcpiClearEvent(ACPI_EVENT_SLEEP_BUTTON); 163711e87ad5Sjmcneill AcpiClearEvent(ACPI_EVENT_RTC); 1638cbdb37a1Sjmcneill #if (!ACPI_REDUCED_HARDWARE) 163911e87ad5Sjmcneill AcpiHwDisableAllGpes(); 1640bc5cf562Sjmcneill #endif 164111e87ad5Sjmcneill 164267a63399Sjruoho acpi_md_OsEnableInterrupt(); 164367a63399Sjruoho rv = AcpiLeaveSleepState(state); 1644fb74e5b5Sjruoho 164536809088Stshiozak } else { 1646fb74e5b5Sjruoho 16475d72dee0Schristos (void)acpi_md_sleep(state); 1648fb74e5b5Sjruoho 164936809088Stshiozak if (state == ACPI_STATE_S4) 165036809088Stshiozak AcpiEnable(); 1651fb74e5b5Sjruoho 16522e742e4aSjruoho (void)pmf_system_bus_resume(PMF_Q_NONE); 1653fb74e5b5Sjruoho (void)AcpiLeaveSleepState(state); 1654f8d654daSchristos (void)AcpiSetFirmwareWakingVector(0, 0); 16552e742e4aSjruoho (void)pmf_system_resume(PMF_Q_NONE); 16564c1d81b2Sjmcneill } 16574c1d81b2Sjmcneill 165867a63399Sjruoho /* 165967a63399Sjruoho * No wake GPEs should be enabled at runtime. 166067a63399Sjruoho */ 16613af8b2cbSjruoho acpi_wakedev_commit(sc, ACPI_STATE_S0); 166236809088Stshiozak break; 166361a52d76Sjruoho 166436809088Stshiozak case ACPI_STATE_S5: 1665fb74e5b5Sjruoho 1666902b3840Sjruoho (void)acpi_eval_set_integer(NULL, "\\_TTS", ACPI_STATE_S5); 166761a52d76Sjruoho 1668fb74e5b5Sjruoho rv = AcpiEnterSleepStatePrep(ACPI_STATE_S5); 1669fb74e5b5Sjruoho 1670fb74e5b5Sjruoho if (ACPI_FAILURE(rv)) { 1671fb74e5b5Sjruoho aprint_error_dev(sc->sc_dev, "failed to prepare " 1672fb74e5b5Sjruoho "S%d: %s\n", state, AcpiFormatException(rv)); 167336809088Stshiozak break; 167436809088Stshiozak } 167536809088Stshiozak 1676c2df94f2Sjruoho (void)AcpiDisableAllGpes(); 1677c2df94f2Sjruoho 1678fb74e5b5Sjruoho DELAY(1000000); 1679fb74e5b5Sjruoho 1680fb74e5b5Sjruoho sc->sc_sleepstate = state; 1681fb74e5b5Sjruoho acpi_md_OsDisableInterrupt(); 1682fb74e5b5Sjruoho 1683fb74e5b5Sjruoho (void)AcpiEnterSleepState(ACPI_STATE_S5); 1684fb74e5b5Sjruoho 1685fb74e5b5Sjruoho aprint_error_dev(sc->sc_dev, "WARNING: powerdown failed!\n"); 168661a52d76Sjruoho 1687fb74e5b5Sjruoho break; 1688fb74e5b5Sjruoho } 1689fb74e5b5Sjruoho 1690fb74e5b5Sjruoho sc->sc_sleepstate = ACPI_STATE_S0; 1691fb74e5b5Sjruoho 169261a52d76Sjruoho (void)acpi_eval_set_integer(NULL, "\\_TTS", ACPI_STATE_S0); 169336809088Stshiozak } 1694290fa82cSaugustss 16952aba9513Sjruoho /* 16960c88d0e4Sjruoho * Sysctl. 16972aba9513Sjruoho */ 16989af38538Scube SYSCTL_SETUP(sysctl_acpi_setup, "sysctl hw.acpi subtree setup") 16999af38538Scube { 17000addcacfSjruoho const struct sysctlnode *rnode, *snode; 170142105e9fSjruoho int err; 17029af38538Scube 170342105e9fSjruoho err = sysctl_createv(clog, 0, NULL, &rnode, 170442105e9fSjruoho CTLFLAG_PERMANENT, CTLTYPE_NODE, 170542105e9fSjruoho "acpi", SYSCTL_DESCR("ACPI subsystem parameters"), 17069af38538Scube NULL, 0, NULL, 0, 17074f6fb3bfSpooka CTL_HW, CTL_CREATE, CTL_EOL); 170842105e9fSjruoho 170942105e9fSjruoho if (err != 0) 17109af38538Scube return; 17119af38538Scube 171242105e9fSjruoho (void)sysctl_createv(NULL, 0, &rnode, NULL, 171342105e9fSjruoho CTLFLAG_PERMANENT | CTLFLAG_READONLY, CTLTYPE_QUAD, 171442105e9fSjruoho "root", SYSCTL_DESCR("ACPI root pointer"), 171595fc3f26Sjmcneill NULL, 0, &acpi_root_pointer, sizeof(acpi_root_pointer), 171642105e9fSjruoho CTL_CREATE, CTL_EOL); 171766bdce45Sjmcneill 1718b99cdd8eSjruoho err = sysctl_createv(clog, 0, &rnode, &snode, 1719b99cdd8eSjruoho CTLFLAG_PERMANENT, CTLTYPE_NODE, 1720b99cdd8eSjruoho "sleep", SYSCTL_DESCR("ACPI sleep"), 1721b99cdd8eSjruoho NULL, 0, NULL, 0, 1722b99cdd8eSjruoho CTL_CREATE, CTL_EOL); 1723b99cdd8eSjruoho 1724b99cdd8eSjruoho if (err != 0) 1725b99cdd8eSjruoho return; 1726b99cdd8eSjruoho 1727b99cdd8eSjruoho (void)sysctl_createv(NULL, 0, &snode, NULL, 1728b99cdd8eSjruoho CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, 1729b99cdd8eSjruoho "state", SYSCTL_DESCR("System sleep state"), 1730b99cdd8eSjruoho sysctl_hw_acpi_sleepstate, 0, NULL, 0, 1731b99cdd8eSjruoho CTL_CREATE, CTL_EOL); 1732b99cdd8eSjruoho 1733b99cdd8eSjruoho (void)sysctl_createv(NULL, 0, &snode, NULL, 173442105e9fSjruoho CTLFLAG_PERMANENT | CTLFLAG_READONLY, CTLTYPE_STRING, 1735b99cdd8eSjruoho "states", SYSCTL_DESCR("Supported sleep states"), 1736fb74e5b5Sjruoho sysctl_hw_acpi_sleepstates, 0, NULL, 0, 173742105e9fSjruoho CTL_CREATE, CTL_EOL); 173842105e9fSjruoho 173942105e9fSjruoho err = sysctl_createv(clog, 0, &rnode, &rnode, 174042105e9fSjruoho CTLFLAG_PERMANENT, CTLTYPE_NODE, 174142105e9fSjruoho "stat", SYSCTL_DESCR("ACPI statistics"), 174242105e9fSjruoho NULL, 0, NULL, 0, 174342105e9fSjruoho CTL_CREATE, CTL_EOL); 174442105e9fSjruoho 174542105e9fSjruoho if (err != 0) 174666bdce45Sjmcneill return; 174742105e9fSjruoho 174842105e9fSjruoho (void)sysctl_createv(clog, 0, &rnode, NULL, 174942105e9fSjruoho CTLFLAG_PERMANENT | CTLFLAG_READONLY, CTLTYPE_QUAD, 175042105e9fSjruoho "gpe", SYSCTL_DESCR("Number of dispatched GPEs"), 175142105e9fSjruoho NULL, 0, &AcpiGpeCount, sizeof(AcpiGpeCount), 175242105e9fSjruoho CTL_CREATE, CTL_EOL); 175342105e9fSjruoho 175442105e9fSjruoho (void)sysctl_createv(clog, 0, &rnode, NULL, 175542105e9fSjruoho CTLFLAG_PERMANENT | CTLFLAG_READONLY, CTLTYPE_QUAD, 175642105e9fSjruoho "sci", SYSCTL_DESCR("Number of SCI interrupts"), 175742105e9fSjruoho NULL, 0, &AcpiSciCount, sizeof(AcpiSciCount), 175842105e9fSjruoho CTL_CREATE, CTL_EOL); 175942105e9fSjruoho 176042105e9fSjruoho (void)sysctl_createv(clog, 0, &rnode, NULL, 176142105e9fSjruoho CTLFLAG_PERMANENT | CTLFLAG_READONLY, CTLTYPE_QUAD, 176242105e9fSjruoho "fixed", SYSCTL_DESCR("Number of fixed events"), 176342105e9fSjruoho sysctl_hw_acpi_fixedstats, 0, NULL, 0, 176442105e9fSjruoho CTL_CREATE, CTL_EOL); 176542105e9fSjruoho 176642105e9fSjruoho (void)sysctl_createv(clog, 0, &rnode, NULL, 176742105e9fSjruoho CTLFLAG_PERMANENT | CTLFLAG_READONLY, CTLTYPE_QUAD, 176842105e9fSjruoho "method", SYSCTL_DESCR("Number of methods executed"), 176942105e9fSjruoho NULL, 0, &AcpiMethodCount, sizeof(AcpiMethodCount), 177042105e9fSjruoho CTL_CREATE, CTL_EOL); 177142105e9fSjruoho 177242105e9fSjruoho CTASSERT(sizeof(AcpiGpeCount) == sizeof(uint64_t)); 177342105e9fSjruoho CTASSERT(sizeof(AcpiSciCount) == sizeof(uint64_t)); 177442105e9fSjruoho } 177542105e9fSjruoho 177642105e9fSjruoho static int 177742105e9fSjruoho sysctl_hw_acpi_fixedstats(SYSCTLFN_ARGS) 177842105e9fSjruoho { 177942105e9fSjruoho struct sysctlnode node; 178042105e9fSjruoho uint64_t t; 178142105e9fSjruoho int err, i; 178242105e9fSjruoho 178342105e9fSjruoho for (i = t = 0; i < __arraycount(AcpiFixedEventCount); i++) 178442105e9fSjruoho t += AcpiFixedEventCount[i]; 178542105e9fSjruoho 178642105e9fSjruoho node = *rnode; 178742105e9fSjruoho node.sysctl_data = &t; 178842105e9fSjruoho 178942105e9fSjruoho err = sysctl_lookup(SYSCTLFN_CALL(&node)); 179042105e9fSjruoho 179142105e9fSjruoho if (err || newp == NULL) 179242105e9fSjruoho return err; 179342105e9fSjruoho 179442105e9fSjruoho return 0; 179566bdce45Sjmcneill } 179666bdce45Sjmcneill 179766bdce45Sjmcneill static int 179866bdce45Sjmcneill sysctl_hw_acpi_sleepstate(SYSCTLFN_ARGS) 179966bdce45Sjmcneill { 1800fb74e5b5Sjruoho struct acpi_softc *sc = acpi_softc; 180166bdce45Sjmcneill struct sysctlnode node; 180242105e9fSjruoho int err, t; 180366bdce45Sjmcneill 1804fb74e5b5Sjruoho if (acpi_softc == NULL) 1805fb74e5b5Sjruoho return ENOSYS; 1806fb74e5b5Sjruoho 180766bdce45Sjmcneill node = *rnode; 1808fb74e5b5Sjruoho t = sc->sc_sleepstate; 180966bdce45Sjmcneill node.sysctl_data = &t; 181042105e9fSjruoho 181142105e9fSjruoho err = sysctl_lookup(SYSCTLFN_CALL(&node)); 181242105e9fSjruoho 181342105e9fSjruoho if (err || newp == NULL) 181442105e9fSjruoho return err; 181566bdce45Sjmcneill 181642105e9fSjruoho if (t < ACPI_STATE_S0 || t > ACPI_STATE_S5) 181742105e9fSjruoho return EINVAL; 181842105e9fSjruoho 1819c99562cbSjruoho acpi_enter_sleep_state(t); 1820fb74e5b5Sjruoho 1821fb74e5b5Sjruoho return 0; 1822fb74e5b5Sjruoho } 1823fb74e5b5Sjruoho 1824fb74e5b5Sjruoho static int 1825fb74e5b5Sjruoho sysctl_hw_acpi_sleepstates(SYSCTLFN_ARGS) 1826fb74e5b5Sjruoho { 1827fb74e5b5Sjruoho struct acpi_softc *sc = acpi_softc; 1828fb74e5b5Sjruoho struct sysctlnode node; 1829fb74e5b5Sjruoho char t[3 * 6 + 1]; 1830fb74e5b5Sjruoho int err; 1831fb74e5b5Sjruoho 1832fb74e5b5Sjruoho if (acpi_softc == NULL) 1833fb74e5b5Sjruoho return ENOSYS; 1834fb74e5b5Sjruoho 1835fb74e5b5Sjruoho (void)memset(t, '\0', sizeof(t)); 1836fb74e5b5Sjruoho 1837fb74e5b5Sjruoho (void)snprintf(t, sizeof(t), "%s%s%s%s%s%s", 1838fb74e5b5Sjruoho ((sc->sc_sleepstates & __BIT(0)) != 0) ? "S0 " : "", 1839fb74e5b5Sjruoho ((sc->sc_sleepstates & __BIT(1)) != 0) ? "S1 " : "", 1840fb74e5b5Sjruoho ((sc->sc_sleepstates & __BIT(2)) != 0) ? "S2 " : "", 1841fb74e5b5Sjruoho ((sc->sc_sleepstates & __BIT(3)) != 0) ? "S3 " : "", 1842fb74e5b5Sjruoho ((sc->sc_sleepstates & __BIT(4)) != 0) ? "S4 " : "", 1843fb74e5b5Sjruoho ((sc->sc_sleepstates & __BIT(5)) != 0) ? "S5 " : ""); 1844fb74e5b5Sjruoho 1845fb74e5b5Sjruoho node = *rnode; 1846fb74e5b5Sjruoho node.sysctl_data = &t; 1847fb74e5b5Sjruoho 1848fb74e5b5Sjruoho err = sysctl_lookup(SYSCTLFN_CALL(&node)); 1849fb74e5b5Sjruoho 1850fb74e5b5Sjruoho if (err || newp == NULL) 1851fb74e5b5Sjruoho return err; 185266bdce45Sjmcneill 185366bdce45Sjmcneill return 0; 18549af38538Scube } 1855a73b7786Sjmcneill 18560c88d0e4Sjruoho /* 18576e6e0264Sjruoho * Tables. 18580c88d0e4Sjruoho */ 18590c88d0e4Sjruoho ACPI_PHYSICAL_ADDRESS 18600c88d0e4Sjruoho acpi_OsGetRootPointer(void) 18610c88d0e4Sjruoho { 18620c88d0e4Sjruoho ACPI_PHYSICAL_ADDRESS PhysicalAddress; 18630c88d0e4Sjruoho 18640c88d0e4Sjruoho /* 186506a5faf4Sjruoho * We let MD code handle this since there are multiple ways to do it: 186606a5faf4Sjruoho * 18670c88d0e4Sjruoho * IA-32: Use AcpiFindRootPointer() to locate the RSDP. 18680c88d0e4Sjruoho * 18690c88d0e4Sjruoho * IA-64: Use the EFI. 18700c88d0e4Sjruoho */ 18710c88d0e4Sjruoho PhysicalAddress = acpi_md_OsGetRootPointer(); 18720c88d0e4Sjruoho 18730c88d0e4Sjruoho if (acpi_root_pointer == 0) 18740c88d0e4Sjruoho acpi_root_pointer = PhysicalAddress; 18750c88d0e4Sjruoho 18760c88d0e4Sjruoho return PhysicalAddress; 18770c88d0e4Sjruoho } 18780c88d0e4Sjruoho 1879a73b7786Sjmcneill static ACPI_TABLE_HEADER * 1880a73b7786Sjmcneill acpi_map_rsdt(void) 1881a73b7786Sjmcneill { 1882a73b7786Sjmcneill ACPI_PHYSICAL_ADDRESS paddr; 1883a73b7786Sjmcneill ACPI_TABLE_RSDP *rsdp; 1884a73b7786Sjmcneill 1885a73b7786Sjmcneill paddr = AcpiOsGetRootPointer(); 188606a5faf4Sjruoho 188706a5faf4Sjruoho if (paddr == 0) 1888a73b7786Sjmcneill return NULL; 188906a5faf4Sjruoho 1890a73b7786Sjmcneill rsdp = AcpiOsMapMemory(paddr, sizeof(ACPI_TABLE_RSDP)); 189106a5faf4Sjruoho 189206a5faf4Sjruoho if (rsdp == NULL) 1893a73b7786Sjmcneill return NULL; 189406a5faf4Sjruoho 1895a73b7786Sjmcneill if (rsdp->Revision > 1 && rsdp->XsdtPhysicalAddress) 189606a5faf4Sjruoho paddr = rsdp->XsdtPhysicalAddress; 1897a73b7786Sjmcneill else 189806a5faf4Sjruoho paddr = rsdp->RsdtPhysicalAddress; 189906a5faf4Sjruoho 1900a73b7786Sjmcneill AcpiOsUnmapMemory(rsdp, sizeof(ACPI_TABLE_RSDP)); 1901a73b7786Sjmcneill 1902a73b7786Sjmcneill return AcpiOsMapMemory(paddr, sizeof(ACPI_TABLE_HEADER)); 1903a73b7786Sjmcneill } 1904a73b7786Sjmcneill 1905762d68ffSjruoho /* 1906762d68ffSjruoho * XXX: Refactor to be a generic function that unmaps tables. 1907762d68ffSjruoho */ 1908a73b7786Sjmcneill static void 1909a73b7786Sjmcneill acpi_unmap_rsdt(ACPI_TABLE_HEADER *rsdt) 1910a73b7786Sjmcneill { 191106a5faf4Sjruoho 1912a73b7786Sjmcneill if (rsdt == NULL) 1913a73b7786Sjmcneill return; 1914a73b7786Sjmcneill 1915a73b7786Sjmcneill AcpiOsUnmapMemory(rsdt, sizeof(ACPI_TABLE_HEADER)); 1916a73b7786Sjmcneill } 1917e1035e2bSjruoho 1918e1035e2bSjruoho /* 19196e6e0264Sjruoho * XXX: Refactor to be a generic function that maps tables. 19206e6e0264Sjruoho */ 19216e6e0264Sjruoho ACPI_STATUS 19226e6e0264Sjruoho acpi_madt_map(void) 19236e6e0264Sjruoho { 19246e6e0264Sjruoho ACPI_STATUS rv; 19256e6e0264Sjruoho 19266e6e0264Sjruoho if (madt_header != NULL) 19276e6e0264Sjruoho return AE_ALREADY_EXISTS; 19286e6e0264Sjruoho 19296e6e0264Sjruoho rv = AcpiGetTable(ACPI_SIG_MADT, 1, &madt_header); 19306e6e0264Sjruoho 19316e6e0264Sjruoho if (ACPI_FAILURE(rv)) 19326e6e0264Sjruoho return rv; 19336e6e0264Sjruoho 19346e6e0264Sjruoho return AE_OK; 19356e6e0264Sjruoho } 19366e6e0264Sjruoho 19376e6e0264Sjruoho void 19386e6e0264Sjruoho acpi_madt_unmap(void) 19396e6e0264Sjruoho { 19406e6e0264Sjruoho madt_header = NULL; 19416e6e0264Sjruoho } 19426e6e0264Sjruoho 19431b71b828Sjmcneill ACPI_STATUS 19441b71b828Sjmcneill acpi_gtdt_map(void) 19451b71b828Sjmcneill { 19461b71b828Sjmcneill ACPI_STATUS rv; 19471b71b828Sjmcneill 19481b71b828Sjmcneill if (gtdt_header != NULL) 19491b71b828Sjmcneill return AE_ALREADY_EXISTS; 19501b71b828Sjmcneill 19511b71b828Sjmcneill rv = AcpiGetTable(ACPI_SIG_GTDT, 1, >dt_header); 19521b71b828Sjmcneill 19531b71b828Sjmcneill if (ACPI_FAILURE(rv)) 19541b71b828Sjmcneill return rv; 19551b71b828Sjmcneill 19561b71b828Sjmcneill return AE_OK; 19571b71b828Sjmcneill } 19581b71b828Sjmcneill 19591b71b828Sjmcneill void 19601b71b828Sjmcneill acpi_gtdt_unmap(void) 19611b71b828Sjmcneill { 19621b71b828Sjmcneill gtdt_header = NULL; 19631b71b828Sjmcneill } 19641b71b828Sjmcneill 19656e6e0264Sjruoho /* 19666e6e0264Sjruoho * XXX: Refactor to be a generic function that walks tables. 19676e6e0264Sjruoho */ 19686e6e0264Sjruoho void 19696e6e0264Sjruoho acpi_madt_walk(ACPI_STATUS (*func)(ACPI_SUBTABLE_HEADER *, void *), void *aux) 19706e6e0264Sjruoho { 19716e6e0264Sjruoho ACPI_SUBTABLE_HEADER *hdrp; 19726e6e0264Sjruoho char *madtend, *where; 19736e6e0264Sjruoho 19746e6e0264Sjruoho madtend = (char *)madt_header + madt_header->Length; 19756e6e0264Sjruoho where = (char *)madt_header + sizeof (ACPI_TABLE_MADT); 19766e6e0264Sjruoho 19776e6e0264Sjruoho while (where < madtend) { 19786e6e0264Sjruoho 19796e6e0264Sjruoho hdrp = (ACPI_SUBTABLE_HEADER *)where; 19806e6e0264Sjruoho 1981d462fb8dSjmcneill if (hdrp->Length == 0 || ACPI_FAILURE(func(hdrp, aux))) 19826e6e0264Sjruoho break; 19836e6e0264Sjruoho 19846e6e0264Sjruoho where += hdrp->Length; 19856e6e0264Sjruoho } 19866e6e0264Sjruoho } 19876e6e0264Sjruoho 19881b71b828Sjmcneill void 19891b71b828Sjmcneill acpi_gtdt_walk(ACPI_STATUS (*func)(ACPI_GTDT_HEADER *, void *), void *aux) 19901b71b828Sjmcneill { 19911b71b828Sjmcneill ACPI_GTDT_HEADER *hdrp; 19921b71b828Sjmcneill char *gtdtend, *where; 19931b71b828Sjmcneill 19941b71b828Sjmcneill gtdtend = (char *)gtdt_header + gtdt_header->Length; 19951b71b828Sjmcneill where = (char *)gtdt_header + sizeof (ACPI_TABLE_GTDT); 19961b71b828Sjmcneill 19971b71b828Sjmcneill while (where < gtdtend) { 19981b71b828Sjmcneill 19991b71b828Sjmcneill hdrp = (ACPI_GTDT_HEADER *)where; 20001b71b828Sjmcneill 2001d462fb8dSjmcneill if (hdrp->Length == 0 || ACPI_FAILURE(func(hdrp, aux))) 20021b71b828Sjmcneill break; 20031b71b828Sjmcneill 20041b71b828Sjmcneill where += hdrp->Length; 20051b71b828Sjmcneill } 20061b71b828Sjmcneill } 20071b71b828Sjmcneill 20086e6e0264Sjruoho /* 20096e6e0264Sjruoho * Miscellaneous. 20106e6e0264Sjruoho */ 20116e6e0264Sjruoho static bool 20126e6e0264Sjruoho acpi_is_scope(struct acpi_devnode *ad) 20136e6e0264Sjruoho { 20146e6e0264Sjruoho int i; 20156e6e0264Sjruoho 20166e6e0264Sjruoho /* 20176e6e0264Sjruoho * Return true if the node is a root scope. 20186e6e0264Sjruoho */ 20196e6e0264Sjruoho if (ad->ad_parent == NULL) 20206e6e0264Sjruoho return false; 20216e6e0264Sjruoho 20226e6e0264Sjruoho if (ad->ad_parent->ad_handle != ACPI_ROOT_OBJECT) 20236e6e0264Sjruoho return false; 20246e6e0264Sjruoho 20256e6e0264Sjruoho for (i = 0; i < __arraycount(acpi_scopes); i++) { 20266e6e0264Sjruoho 20276e6e0264Sjruoho if (acpi_scopes[i] == NULL) 20286e6e0264Sjruoho continue; 20296e6e0264Sjruoho 20306e6e0264Sjruoho if (ad->ad_handle == acpi_scopes[i]) 20316e6e0264Sjruoho return true; 20326e6e0264Sjruoho } 20336e6e0264Sjruoho 20346e6e0264Sjruoho return false; 20356e6e0264Sjruoho } 20366e6e0264Sjruoho 2037a2cf80f2Schristos bool 2038a2cf80f2Schristos acpi_device_present(ACPI_HANDLE handle) 2039a2cf80f2Schristos { 2040a2cf80f2Schristos ACPI_STATUS rv; 2041a2cf80f2Schristos ACPI_INTEGER sta; 2042a2cf80f2Schristos 2043a2cf80f2Schristos rv = acpi_eval_integer(handle, "_STA", &sta); 2044a2cf80f2Schristos 2045a2cf80f2Schristos if (ACPI_FAILURE(rv)) { 2046a2cf80f2Schristos /* No _STA method -> must be there */ 2047a2cf80f2Schristos return rv == AE_NOT_FOUND; 2048a2cf80f2Schristos } 2049a2cf80f2Schristos 2050a2cf80f2Schristos return (sta & ACPI_STA_OK) == ACPI_STA_OK; 2051a2cf80f2Schristos } 2052a2cf80f2Schristos 20536e6e0264Sjruoho /* 2054e1035e2bSjruoho * ACPIVERBOSE. 2055e1035e2bSjruoho */ 2056e1035e2bSjruoho void 2057e1035e2bSjruoho acpi_load_verbose(void) 2058e1035e2bSjruoho { 2059e1035e2bSjruoho 2060f05cff10Spgoyette if (acpi_verbose_loaded == 0) 2061e1035e2bSjruoho module_autoload("acpiverbose", MODULE_CLASS_MISC); 2062e1035e2bSjruoho } 2063e1035e2bSjruoho 2064e1035e2bSjruoho void 2065e1035e2bSjruoho acpi_print_verbose_stub(struct acpi_softc *sc) 2066e1035e2bSjruoho { 2067e1035e2bSjruoho 2068e1035e2bSjruoho acpi_load_verbose(); 2069e1035e2bSjruoho 2070e1035e2bSjruoho if (acpi_verbose_loaded != 0) 2071e1035e2bSjruoho acpi_print_verbose(sc); 2072e1035e2bSjruoho } 2073e1035e2bSjruoho 2074e1035e2bSjruoho void 2075e1035e2bSjruoho acpi_print_dev_stub(const char *pnpstr) 2076e1035e2bSjruoho { 2077e1035e2bSjruoho 2078e1035e2bSjruoho acpi_load_verbose(); 2079e1035e2bSjruoho 2080e1035e2bSjruoho if (acpi_verbose_loaded != 0) 2081e1035e2bSjruoho acpi_print_dev(pnpstr); 2082e1035e2bSjruoho } 20831bb3132dSjruoho 20846f104f56Sjruoho MALLOC_DECLARE(M_ACPI); /* XXX: ACPI_ACTIVATE_DEV should use kmem(9). */ 20856f104f56Sjruoho 20861bb3132dSjruoho /* 20871bb3132dSjruoho * ACPI_ACTIVATE_DEV. 20881bb3132dSjruoho */ 20891bb3132dSjruoho static void 20901bb3132dSjruoho acpi_activate_device(ACPI_HANDLE handle, ACPI_DEVICE_INFO **di) 20911bb3132dSjruoho { 20921bb3132dSjruoho 20931bb3132dSjruoho #ifndef ACPI_ACTIVATE_DEV 20941bb3132dSjruoho return; 20951bb3132dSjruoho } 20961bb3132dSjruoho #else 2097f45f09e8Schristos static const int valid = ACPI_VALID_HID; 20981bb3132dSjruoho ACPI_DEVICE_INFO *newdi; 20991bb3132dSjruoho ACPI_STATUS rv; 21001bb3132dSjruoho 2101a2cf80f2Schristos 21021bb3132dSjruoho /* 21031bb3132dSjruoho * If the device is valid and present, 21041bb3132dSjruoho * but not enabled, try to activate it. 21051bb3132dSjruoho */ 21061bb3132dSjruoho if (((*di)->Valid & valid) != valid) 21071bb3132dSjruoho return; 21081bb3132dSjruoho 2109a2cf80f2Schristos if (!acpi_device_present(handle)) 2110a2cf80f2Schristos return; 2111a2cf80f2Schristos 21121bb3132dSjruoho rv = acpi_allocate_resources(handle); 21131bb3132dSjruoho 21141bb3132dSjruoho if (ACPI_FAILURE(rv)) 21151bb3132dSjruoho goto fail; 21161bb3132dSjruoho 21171bb3132dSjruoho rv = AcpiGetObjectInfo(handle, &newdi); 21181bb3132dSjruoho 21191bb3132dSjruoho if (ACPI_FAILURE(rv)) 21201bb3132dSjruoho goto fail; 21211bb3132dSjruoho 21221bb3132dSjruoho ACPI_FREE(*di); 21231bb3132dSjruoho *di = newdi; 21241bb3132dSjruoho 21251bb3132dSjruoho aprint_verbose_dev(acpi_softc->sc_dev, 2126f45f09e8Schristos "%s activated\n", (*di)->HardwareId.String); 21271bb3132dSjruoho 21281bb3132dSjruoho return; 21291bb3132dSjruoho 21301bb3132dSjruoho fail: 21311bb3132dSjruoho aprint_error_dev(acpi_softc->sc_dev, "failed to " 21321bb3132dSjruoho "activate %s\n", (*di)->HardwareId.String); 21331bb3132dSjruoho } 21341bb3132dSjruoho 21351bb3132dSjruoho /* 21361bb3132dSjruoho * XXX: This very incomplete. 21371bb3132dSjruoho */ 21381bb3132dSjruoho ACPI_STATUS 21391bb3132dSjruoho acpi_allocate_resources(ACPI_HANDLE handle) 21401bb3132dSjruoho { 21411bb3132dSjruoho ACPI_BUFFER bufp, bufc, bufn; 21421bb3132dSjruoho ACPI_RESOURCE *resp, *resc, *resn; 21431bb3132dSjruoho ACPI_RESOURCE_IRQ *irq; 2144f5fe8e85Schristos #if 0 21451bb3132dSjruoho ACPI_RESOURCE_EXTENDED_IRQ *xirq; 2146f5fe8e85Schristos #endif 21471bb3132dSjruoho ACPI_STATUS rv; 21481bb3132dSjruoho uint delta; 21491bb3132dSjruoho 21501bb3132dSjruoho rv = acpi_get(handle, &bufp, AcpiGetPossibleResources); 21511bb3132dSjruoho if (ACPI_FAILURE(rv)) 21521bb3132dSjruoho goto out; 21531bb3132dSjruoho rv = acpi_get(handle, &bufc, AcpiGetCurrentResources); 21541bb3132dSjruoho if (ACPI_FAILURE(rv)) { 21551bb3132dSjruoho goto out1; 21561bb3132dSjruoho } 21571bb3132dSjruoho 21581bb3132dSjruoho bufn.Length = 1000; 21591bb3132dSjruoho bufn.Pointer = resn = malloc(bufn.Length, M_ACPI, M_WAITOK); 21601bb3132dSjruoho resp = bufp.Pointer; 21611bb3132dSjruoho resc = bufc.Pointer; 21621bb3132dSjruoho while (resc->Type != ACPI_RESOURCE_TYPE_END_TAG && 21631bb3132dSjruoho resp->Type != ACPI_RESOURCE_TYPE_END_TAG) { 21641bb3132dSjruoho while (resc->Type != resp->Type && resp->Type != ACPI_RESOURCE_TYPE_END_TAG) 21651bb3132dSjruoho resp = ACPI_NEXT_RESOURCE(resp); 21661bb3132dSjruoho if (resp->Type == ACPI_RESOURCE_TYPE_END_TAG) 21671bb3132dSjruoho break; 21681bb3132dSjruoho /* Found identical Id */ 21691bb3132dSjruoho resn->Type = resc->Type; 21701bb3132dSjruoho switch (resc->Type) { 21711bb3132dSjruoho case ACPI_RESOURCE_TYPE_IRQ: 21721bb3132dSjruoho memcpy(&resn->Data, &resp->Data, 21731bb3132dSjruoho sizeof(ACPI_RESOURCE_IRQ)); 21741bb3132dSjruoho irq = (ACPI_RESOURCE_IRQ *)&resn->Data; 21751bb3132dSjruoho irq->Interrupts[0] = 21761bb3132dSjruoho ((ACPI_RESOURCE_IRQ *)&resp->Data)-> 21771bb3132dSjruoho Interrupts[irq->InterruptCount-1]; 21781bb3132dSjruoho irq->InterruptCount = 1; 21791bb3132dSjruoho resn->Length = ACPI_RS_SIZE(ACPI_RESOURCE_IRQ); 21801bb3132dSjruoho break; 21811bb3132dSjruoho case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 21821bb3132dSjruoho memcpy(&resn->Data, &resp->Data, 21831bb3132dSjruoho sizeof(ACPI_RESOURCE_EXTENDED_IRQ)); 21841bb3132dSjruoho #if 0 2185f5fe8e85Schristos xirq = (ACPI_RESOURCE_EXTENDED_IRQ *)&resn->Data; 21861bb3132dSjruoho /* 21871bb3132dSjruoho * XXX: Not duplicating the interrupt logic above 21881bb3132dSjruoho * because its not clear what it accomplishes. 21891bb3132dSjruoho */ 21901bb3132dSjruoho xirq->Interrupts[0] = 21911bb3132dSjruoho ((ACPI_RESOURCE_EXT_IRQ *)&resp->Data)-> 21921bb3132dSjruoho Interrupts[irq->NumberOfInterrupts-1]; 21931bb3132dSjruoho xirq->NumberOfInterrupts = 1; 21941bb3132dSjruoho #endif 21951bb3132dSjruoho resn->Length = ACPI_RS_SIZE(ACPI_RESOURCE_EXTENDED_IRQ); 21961bb3132dSjruoho break; 21971bb3132dSjruoho case ACPI_RESOURCE_TYPE_IO: 21981bb3132dSjruoho memcpy(&resn->Data, &resp->Data, 21991bb3132dSjruoho sizeof(ACPI_RESOURCE_IO)); 22001bb3132dSjruoho resn->Length = resp->Length; 22011bb3132dSjruoho break; 22021bb3132dSjruoho default: 22031bb3132dSjruoho aprint_error_dev(acpi_softc->sc_dev, 22041bb3132dSjruoho "%s: invalid type %u\n", __func__, resc->Type); 22051bb3132dSjruoho rv = AE_BAD_DATA; 22061bb3132dSjruoho goto out2; 22071bb3132dSjruoho } 22081bb3132dSjruoho resc = ACPI_NEXT_RESOURCE(resc); 22091bb3132dSjruoho resn = ACPI_NEXT_RESOURCE(resn); 22101bb3132dSjruoho resp = ACPI_NEXT_RESOURCE(resp); 22111bb3132dSjruoho delta = (uint8_t *)resn - (uint8_t *)bufn.Pointer; 22121bb3132dSjruoho if (delta >= 22131bb3132dSjruoho bufn.Length-ACPI_RS_SIZE(ACPI_RESOURCE_DATA)) { 22141bb3132dSjruoho bufn.Length *= 2; 22151bb3132dSjruoho bufn.Pointer = realloc(bufn.Pointer, bufn.Length, 22161bb3132dSjruoho M_ACPI, M_WAITOK); 22171bb3132dSjruoho resn = (ACPI_RESOURCE *)((uint8_t *)bufn.Pointer + 22181bb3132dSjruoho delta); 22191bb3132dSjruoho } 22201bb3132dSjruoho } 22211bb3132dSjruoho 22221bb3132dSjruoho if (resc->Type != ACPI_RESOURCE_TYPE_END_TAG) { 22231bb3132dSjruoho aprint_error_dev(acpi_softc->sc_dev, 22241bb3132dSjruoho "%s: resc not exhausted\n", __func__); 22251bb3132dSjruoho rv = AE_BAD_DATA; 22261bb3132dSjruoho goto out3; 22271bb3132dSjruoho } 22281bb3132dSjruoho 22291bb3132dSjruoho resn->Type = ACPI_RESOURCE_TYPE_END_TAG; 22301bb3132dSjruoho rv = AcpiSetCurrentResources(handle, &bufn); 22311bb3132dSjruoho 22321bb3132dSjruoho if (ACPI_FAILURE(rv)) 22331bb3132dSjruoho aprint_error_dev(acpi_softc->sc_dev, "%s: failed to set " 22341bb3132dSjruoho "resources: %s\n", __func__, AcpiFormatException(rv)); 22351bb3132dSjruoho 22361bb3132dSjruoho out3: 22371bb3132dSjruoho free(bufn.Pointer, M_ACPI); 22381bb3132dSjruoho out2: 22391bb3132dSjruoho ACPI_FREE(bufc.Pointer); 22401bb3132dSjruoho out1: 22411bb3132dSjruoho ACPI_FREE(bufp.Pointer); 22421bb3132dSjruoho out: 22431bb3132dSjruoho return rv; 22441bb3132dSjruoho } 22451bb3132dSjruoho 22461bb3132dSjruoho #endif /* ACPI_ACTIVATE_DEV */ 2247