xref: /netbsd-src/sys/dev/acpi/acpi.c (revision a93f58a934a2e19c46b0d361605c35f4f839c6bf)
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, &gtdt_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