167761Smsmith/*- 267761Smsmith * Copyright (c) 2000 Takanori Watanabe <takawata@jp.freebsd.org> 367761Smsmith * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@jp.freebsd.org> 478991Smsmith * Copyright (c) 2000, 2001 Michael Smith 567761Smsmith * Copyright (c) 2000 BSDi 667761Smsmith * All rights reserved. 767761Smsmith * 867761Smsmith * Redistribution and use in source and binary forms, with or without 967761Smsmith * modification, are permitted provided that the following conditions 1067761Smsmith * are met: 1167761Smsmith * 1. Redistributions of source code must retain the above copyright 1267761Smsmith * notice, this list of conditions and the following disclaimer. 1367761Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1467761Smsmith * notice, this list of conditions and the following disclaimer in the 1567761Smsmith * documentation and/or other materials provided with the distribution. 1667761Smsmith * 1767761Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1867761Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1967761Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2067761Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2167761Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2267761Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2367761Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2467761Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2567761Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2667761Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2767761Smsmith * SUCH DAMAGE. 2867761Smsmith */ 2967761Smsmith 30143002Sobrien#include <sys/cdefs.h> 31143002Sobrien__FBSDID("$FreeBSD: stable/10/sys/dev/acpica/acpi.c 306536 2016-09-30 22:40:58Z jkim $"); 32143002Sobrien 3367761Smsmith#include "opt_acpi.h" 3467761Smsmith#include <sys/param.h> 3567761Smsmith#include <sys/kernel.h> 3676166Smarkm#include <sys/proc.h> 37110894Stakawata#include <sys/fcntl.h> 3867761Smsmith#include <sys/malloc.h> 39129879Sphk#include <sys/module.h> 4067761Smsmith#include <sys/bus.h> 4167761Smsmith#include <sys/conf.h> 4267761Smsmith#include <sys/ioccom.h> 4367761Smsmith#include <sys/reboot.h> 4467761Smsmith#include <sys/sysctl.h> 4567761Smsmith#include <sys/ctype.h> 4686133Siwasaki#include <sys/linker.h> 4785835Siwasaki#include <sys/power.h> 48123337Snjl#include <sys/sbuf.h> 49189903Sjkim#include <sys/sched.h> 50127193Snjl#include <sys/smp.h> 51189903Sjkim#include <sys/timetc.h> 5267761Smsmith 53181987Sjhb#if defined(__i386__) || defined(__amd64__) 54181987Sjhb#include <machine/pci_cfgreg.h> 55181987Sjhb#endif 5667761Smsmith#include <machine/resource.h> 57122764Snjl#include <machine/bus.h> 58122764Snjl#include <sys/rman.h> 5982537Smsmith#include <isa/isavar.h> 60131258Snjl#include <isa/pnpvar.h> 6182537Smsmith 62193530Sjkim#include <contrib/dev/acpica/include/acpi.h> 63193530Sjkim#include <contrib/dev/acpica/include/accommon.h> 64193530Sjkim#include <contrib/dev/acpica/include/acnamesp.h> 65193530Sjkim 6667761Smsmith#include <dev/acpica/acpivar.h> 6767761Smsmith#include <dev/acpica/acpiio.h> 6867761Smsmith 69167814Sjkim#include <vm/vm_param.h> 70167814Sjkim 71227293Sedstatic MALLOC_DEFINE(M_ACPIDEV, "acpidev", "ACPI devices"); 7267761Smsmith 73119529Snjl/* Hooks for the ACPI CA debugging infrastructure */ 7478991Smsmith#define _COMPONENT ACPI_BUS 7591120SmsmithACPI_MODULE_NAME("ACPI") 7669744Smsmith 7767761Smsmithstatic d_open_t acpiopen; 7867761Smsmithstatic d_close_t acpiclose; 7967761Smsmithstatic d_ioctl_t acpiioctl; 8067761Smsmith 8167761Smsmithstatic struct cdevsw acpi_cdevsw = { 82126080Sphk .d_version = D_VERSION, 83111815Sphk .d_open = acpiopen, 84111815Sphk .d_close = acpiclose, 85111815Sphk .d_ioctl = acpiioctl, 86111815Sphk .d_name = "acpi", 8767761Smsmith}; 8867761Smsmith 89214390Sjkimstruct acpi_interface { 90214390Sjkim ACPI_STRING *data; 91214390Sjkim int num; 92214390Sjkim}; 93214390Sjkim 94131336Snjl/* Global mutex for locking access to the ACPI subsystem. */ 9578991Smsmithstruct mtx acpi_mutex; 9678991Smsmith 97131315Snjl/* Bitmap of device quirks. */ 98131336Snjlint acpi_quirks; 99131315Snjl 100191695Sjkim/* Supported sleep states. */ 101191695Sjkimstatic BOOLEAN acpi_sleep_states[ACPI_S_STATE_COUNT]; 102191695Sjkim 103295131Sjhbstatic void acpi_lookup(void *arg, const char *name, device_t *dev); 10480604Smsmithstatic int acpi_modevent(struct module *mod, int event, void *junk); 10567761Smsmithstatic int acpi_probe(device_t dev); 10667761Smsmithstatic int acpi_attach(device_t dev); 107138306Snjlstatic int acpi_suspend(device_t dev); 108138306Snjlstatic int acpi_resume(device_t dev); 109130114Snjlstatic int acpi_shutdown(device_t dev); 110212413Savgstatic device_t acpi_add_child(device_t bus, u_int order, const char *name, 111119529Snjl int unit); 11267761Smsmithstatic int acpi_print_child(device_t bus, device_t child); 113138306Snjlstatic void acpi_probe_nomatch(device_t bus, device_t child); 114138306Snjlstatic void acpi_driver_added(device_t dev, driver_t *driver); 115119529Snjlstatic int acpi_read_ivar(device_t dev, device_t child, int index, 116119529Snjl uintptr_t *result); 117119529Snjlstatic int acpi_write_ivar(device_t dev, device_t child, int index, 118119529Snjl uintptr_t value); 119130439Snjlstatic struct resource_list *acpi_get_rlist(device_t dev, device_t child); 120216674Sjhbstatic void acpi_reserve_resources(device_t dev); 121134217Snjlstatic int acpi_sysres_alloc(device_t dev); 122216674Sjhbstatic int acpi_set_resource(device_t dev, device_t child, int type, 123216674Sjhb int rid, u_long start, u_long count); 124119529Snjlstatic struct resource *acpi_alloc_resource(device_t bus, device_t child, 125119529Snjl int type, int *rid, u_long start, u_long end, 126119529Snjl u_long count, u_int flags); 127222929Sjhbstatic int acpi_adjust_resource(device_t bus, device_t child, int type, 128222929Sjhb struct resource *r, u_long start, u_long end); 129119529Snjlstatic int acpi_release_resource(device_t bus, device_t child, int type, 130119529Snjl int rid, struct resource *r); 131143997Snjlstatic void acpi_delete_resource(device_t bus, device_t child, int type, 132143997Snjl int rid); 133123619Snjlstatic uint32_t acpi_isa_get_logicalid(device_t dev); 134123619Snjlstatic int acpi_isa_get_compatid(device_t dev, uint32_t *cids, int count); 135131281Snjlstatic char *acpi_device_id_probe(device_t bus, device_t dev, char **ids); 136131281Snjlstatic ACPI_STATUS acpi_device_eval_obj(device_t bus, device_t dev, 137131281Snjl ACPI_STRING pathname, ACPI_OBJECT_LIST *parameters, 138131281Snjl ACPI_BUFFER *ret); 139132212Snjlstatic ACPI_STATUS acpi_device_scan_cb(ACPI_HANDLE h, UINT32 level, 140132212Snjl void *context, void **retval); 141132212Snjlstatic ACPI_STATUS acpi_device_scan_children(device_t bus, device_t dev, 142132212Snjl int max_depth, acpi_scan_cb_t user_fn, void *arg); 143214072Sjkimstatic int acpi_set_powerstate(device_t child, int state); 144119529Snjlstatic int acpi_isa_pnp_probe(device_t bus, device_t child, 145132212Snjl struct isa_pnp_id *ids); 14667761Smsmithstatic void acpi_probe_children(device_t bus); 147177985Sjhbstatic void acpi_probe_order(ACPI_HANDLE handle, int *order); 148119529Snjlstatic ACPI_STATUS acpi_probe_child(ACPI_HANDLE handle, UINT32 level, 149132212Snjl void *context, void **status); 150191695Sjkimstatic void acpi_sleep_enable(void *arg); 151191695Sjkimstatic ACPI_STATUS acpi_sleep_disable(struct acpi_softc *sc); 152170976Snjlstatic ACPI_STATUS acpi_EnterSleepState(struct acpi_softc *sc, int state); 15367761Smsmithstatic void acpi_shutdown_final(void *arg, int howto); 15470897Siwasakistatic void acpi_enable_fixed_events(struct acpi_softc *sc); 155223207Sjhbstatic BOOLEAN acpi_has_hid(ACPI_HANDLE handle); 156231227Sjkimstatic void acpi_resync_clock(struct acpi_softc *sc); 157131341Snjlstatic int acpi_wake_sleep_prep(ACPI_HANDLE handle, int sstate); 158131341Snjlstatic int acpi_wake_run_prep(ACPI_HANDLE handle, int sstate); 159131341Snjlstatic int acpi_wake_prep_walk(int sstate); 160129802Snjlstatic int acpi_wake_sysctl_walk(device_t dev); 161129802Snjlstatic int acpi_wake_set_sysctl(SYSCTL_HANDLER_ARGS); 16267761Smsmithstatic void acpi_system_eventhandler_sleep(void *arg, int state); 16367761Smsmithstatic void acpi_system_eventhandler_wakeup(void *arg, int state); 164191695Sjkimstatic int acpi_sname2sstate(const char *sname); 165191697Sjkimstatic const char *acpi_sstate2sname(int sstate); 166113366Siwasakistatic int acpi_supported_sleep_state_sysctl(SYSCTL_HANDLER_ARGS); 16771001Sjhbstatic int acpi_sleep_state_sysctl(SYSCTL_HANDLER_ARGS); 168204916Sjkimstatic int acpi_debug_objects_sysctl(SYSCTL_HANDLER_ARGS); 16985835Siwasakistatic int acpi_pm_func(u_long cmd, void *arg, ...); 170127488Stakawatastatic int acpi_child_location_str_method(device_t acdev, device_t child, 171127488Stakawata char *buf, size_t buflen); 172127488Stakawatastatic int acpi_child_pnpinfo_str_method(device_t acdev, device_t child, 173127488Stakawata char *buf, size_t buflen); 174181987Sjhb#if defined(__i386__) || defined(__amd64__) 175181987Sjhbstatic void acpi_enable_pcie(void); 176181987Sjhb#endif 177185059Sjhbstatic void acpi_hint_device_unit(device_t acdev, device_t child, 178185059Sjhb const char *name, int *unitp); 179214390Sjkimstatic void acpi_reset_interfaces(device_t dev); 18085835Siwasaki 18167761Smsmithstatic device_method_t acpi_methods[] = { 18267761Smsmith /* Device interface */ 18367761Smsmith DEVMETHOD(device_probe, acpi_probe), 18467761Smsmith DEVMETHOD(device_attach, acpi_attach), 185130114Snjl DEVMETHOD(device_shutdown, acpi_shutdown), 186122904Snjl DEVMETHOD(device_detach, bus_generic_detach), 187138306Snjl DEVMETHOD(device_suspend, acpi_suspend), 188138306Snjl DEVMETHOD(device_resume, acpi_resume), 18967761Smsmith 19067761Smsmith /* Bus interface */ 19167761Smsmith DEVMETHOD(bus_add_child, acpi_add_child), 19267761Smsmith DEVMETHOD(bus_print_child, acpi_print_child), 193138306Snjl DEVMETHOD(bus_probe_nomatch, acpi_probe_nomatch), 194138306Snjl DEVMETHOD(bus_driver_added, acpi_driver_added), 19567761Smsmith DEVMETHOD(bus_read_ivar, acpi_read_ivar), 19667761Smsmith DEVMETHOD(bus_write_ivar, acpi_write_ivar), 197130439Snjl DEVMETHOD(bus_get_resource_list, acpi_get_rlist), 198216674Sjhb DEVMETHOD(bus_set_resource, acpi_set_resource), 199130439Snjl DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 20067761Smsmith DEVMETHOD(bus_alloc_resource, acpi_alloc_resource), 201222929Sjhb DEVMETHOD(bus_adjust_resource, acpi_adjust_resource), 20267761Smsmith DEVMETHOD(bus_release_resource, acpi_release_resource), 203143997Snjl DEVMETHOD(bus_delete_resource, acpi_delete_resource), 204127681Snjl DEVMETHOD(bus_child_pnpinfo_str, acpi_child_pnpinfo_str_method), 205127681Snjl DEVMETHOD(bus_child_location_str, acpi_child_location_str_method), 20667761Smsmith DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 20767761Smsmith DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 20867761Smsmith DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 20967761Smsmith DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 210185059Sjhb DEVMETHOD(bus_hint_device_unit, acpi_hint_device_unit), 211279904Sscottl DEVMETHOD(bus_get_domain, acpi_get_domain), 21267761Smsmith 213131281Snjl /* ACPI bus */ 214131281Snjl DEVMETHOD(acpi_id_probe, acpi_device_id_probe), 215131281Snjl DEVMETHOD(acpi_evaluate_object, acpi_device_eval_obj), 216138306Snjl DEVMETHOD(acpi_pwr_for_sleep, acpi_device_pwr_for_sleep), 217132212Snjl DEVMETHOD(acpi_scan_children, acpi_device_scan_children), 218131281Snjl 21982537Smsmith /* ISA emulation */ 22082537Smsmith DEVMETHOD(isa_pnp_probe, acpi_isa_pnp_probe), 22182537Smsmith 222246128Ssbz DEVMETHOD_END 22367761Smsmith}; 22467761Smsmith 22567761Smsmithstatic driver_t acpi_driver = { 22667761Smsmith "acpi", 22767761Smsmith acpi_methods, 22867761Smsmith sizeof(struct acpi_softc), 22967761Smsmith}; 23067761Smsmith 23189054Smsmithstatic devclass_t acpi_devclass; 23280604SmsmithDRIVER_MODULE(acpi, nexus, acpi_driver, acpi_devclass, acpi_modevent, 0); 233128036SnjlMODULE_VERSION(acpi, 1); 23467761Smsmith 235133612SnjlACPI_SERIAL_DECL(acpi, "ACPI root bus"); 236133612Snjl 237134217Snjl/* Local pools for managing system resources for ACPI child devices. */ 238134217Snjlstatic struct rman acpi_rman_io, acpi_rman_mem; 239134217Snjl 240133051Snjl#define ACPI_MINIMUM_AWAKETIME 5 241133051Snjl 242177157Sjhb/* Holds the description of the acpi0 device. */ 243177157Sjhbstatic char acpi_desc[ACPI_OEM_ID_SIZE + ACPI_OEM_TABLE_ID_SIZE + 2]; 244177157Sjhb 245159476SnjlSYSCTL_NODE(_debug, OID_AUTO, acpi, CTLFLAG_RD, NULL, "ACPI debugging"); 246120494Snjlstatic char acpi_ca_version[12]; 247120494SnjlSYSCTL_STRING(_debug_acpi, OID_AUTO, acpi_ca_version, CTLFLAG_RD, 248120494Snjl acpi_ca_version, 0, "Version of Intel ACPI-CA"); 24967761Smsmith 25067761Smsmith/* 251214390Sjkim * Allow overriding _OSI methods. 252214390Sjkim */ 253214390Sjkimstatic char acpi_install_interface[256]; 254214390SjkimTUNABLE_STR("hw.acpi.install_interface", acpi_install_interface, 255214390Sjkim sizeof(acpi_install_interface)); 256214390Sjkimstatic char acpi_remove_interface[256]; 257214390SjkimTUNABLE_STR("hw.acpi.remove_interface", acpi_remove_interface, 258214390Sjkim sizeof(acpi_remove_interface)); 259214390Sjkim 260204916Sjkim/* Allow users to dump Debug objects without ACPI debugger. */ 261204916Sjkimstatic int acpi_debug_objects; 262204916SjkimTUNABLE_INT("debug.acpi.enable_debug_objects", &acpi_debug_objects); 263204916SjkimSYSCTL_PROC(_debug_acpi, OID_AUTO, enable_debug_objects, 264204916Sjkim CTLFLAG_RW | CTLTYPE_INT, NULL, 0, acpi_debug_objects_sysctl, "I", 265204916Sjkim "Enable Debug objects"); 266204916Sjkim 267204916Sjkim/* Allow the interpreter to ignore common mistakes in BIOS. */ 268204916Sjkimstatic int acpi_interpreter_slack = 1; 269204916SjkimTUNABLE_INT("debug.acpi.interpreter_slack", &acpi_interpreter_slack); 270204916SjkimSYSCTL_INT(_debug_acpi, OID_AUTO, interpreter_slack, CTLFLAG_RDTUN, 271204916Sjkim &acpi_interpreter_slack, 1, "Turn on interpreter slack mode."); 272204916Sjkim 273281075Sdim/* Ignore register widths set by FADT and use default widths instead. */ 274281075Sdimstatic int acpi_ignore_reg_width = 1; 275281075SdimTUNABLE_INT("debug.acpi.default_register_width", &acpi_ignore_reg_width); 276281075SdimSYSCTL_INT(_debug_acpi, OID_AUTO, default_register_width, CTLFLAG_RDTUN, 277281075Sdim &acpi_ignore_reg_width, 1, "Ignore register widths set by FADT"); 278281075Sdim 279246252Savg#ifdef __amd64__ 280190340Sjkim/* Reset system clock while resuming. XXX Remove once tested. */ 281190340Sjkimstatic int acpi_reset_clock = 1; 282190340SjkimTUNABLE_INT("debug.acpi.reset_clock", &acpi_reset_clock); 283190340SjkimSYSCTL_INT(_debug_acpi, OID_AUTO, reset_clock, CTLFLAG_RW, 284190340Sjkim &acpi_reset_clock, 1, "Reset system clock while resuming."); 285231227Sjkim#endif 286190340Sjkim 287141830Snjl/* Allow users to override quirks. */ 288141830SnjlTUNABLE_INT("debug.acpi.quirks", &acpi_quirks); 289141830Snjl 290169973Snjlstatic int acpi_susp_bounce; 291169973SnjlSYSCTL_INT(_debug_acpi, OID_AUTO, suspend_bounce, CTLFLAG_RW, 292169973Snjl &acpi_susp_bounce, 0, "Don't actually suspend, just test devices."); 293169973Snjl 294127609Snjl/* 29580604Smsmith * ACPI can only be loaded as a module by the loader; activating it after 29680604Smsmith * system bootstrap time is not useful, and can be fatal to the system. 297181299Sjhb * It also cannot be unloaded, since the entire system bus hierarchy hangs 298119529Snjl * off it. 29980604Smsmith */ 30080604Smsmithstatic int 30180604Smsmithacpi_modevent(struct module *mod, int event, void *junk) 30280604Smsmith{ 303131281Snjl switch (event) { 30480604Smsmith case MOD_LOAD: 305107199Siwasaki if (!cold) { 306107199Siwasaki printf("The ACPI driver cannot be loaded after boot.\n"); 307119529Snjl return (EPERM); 308107199Siwasaki } 30980604Smsmith break; 31080604Smsmith case MOD_UNLOAD: 31185835Siwasaki if (!cold && power_pm_get_type() == POWER_PM_TYPE_ACPI) 312119529Snjl return (EBUSY); 31385835Siwasaki break; 31480604Smsmith default: 31580604Smsmith break; 31680604Smsmith } 317119529Snjl return (0); 31880604Smsmith} 31980604Smsmith 32080604Smsmith/* 321125047Sjhb * Perform early initialization. 32267761Smsmith */ 323125047SjhbACPI_STATUS 324125047Sjhbacpi_Startup(void) 32567761Smsmith{ 326131315Snjl static int started = 0; 327167814Sjkim ACPI_STATUS status; 328167814Sjkim int val; 32967761Smsmith 330125135Sroam ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 331125135Sroam 332133051Snjl /* Only run the startup code once. The MADT driver also calls this. */ 333125047Sjhb if (started) 334167814Sjkim return_VALUE (AE_OK); 335125047Sjhb started = 1; 33669744Smsmith 337127184Snjl /* 338167814Sjkim * Pre-allocate space for RSDT/XSDT and DSDT tables and allow resizing 339167814Sjkim * if more tables exist. 340127184Snjl */ 341167814Sjkim if (ACPI_FAILURE(status = AcpiInitializeTables(NULL, 2, TRUE))) { 342167814Sjkim printf("ACPI: Table initialisation failed: %s\n", 343167814Sjkim AcpiFormatException(status)); 344167814Sjkim return_VALUE (status); 34567761Smsmith } 34686133Siwasaki 347131315Snjl /* Set up any quirks we have for this system. */ 348167814Sjkim if (acpi_quirks == ACPI_Q_OK) 349141830Snjl acpi_table_quirks(&acpi_quirks); 350131315Snjl 351141830Snjl /* If the user manually set the disabled hint to 0, force-enable ACPI. */ 352131315Snjl if (resource_int_value("acpi", 0, "disabled", &val) == 0 && val == 0) 353131315Snjl acpi_quirks &= ~ACPI_Q_BROKEN; 354131315Snjl if (acpi_quirks & ACPI_Q_BROKEN) { 355131315Snjl printf("ACPI disabled by blacklist. Contact your BIOS vendor.\n"); 356167814Sjkim status = AE_SUPPORT; 357131315Snjl } 358126517Snjl 359167814Sjkim return_VALUE (status); 360125047Sjhb} 361125047Sjhb 362125047Sjhb/* 363177157Sjhb * Detect ACPI and perform early initialisation. 364125047Sjhb */ 365177157Sjhbint 366177157Sjhbacpi_identify(void) 367125047Sjhb{ 368177157Sjhb ACPI_TABLE_RSDP *rsdp; 369177157Sjhb ACPI_TABLE_HEADER *rsdt; 370177157Sjhb ACPI_PHYSICAL_ADDRESS paddr; 371177157Sjhb struct sbuf sb; 372125047Sjhb 373125047Sjhb ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 374125047Sjhb 375125047Sjhb if (!cold) 376177157Sjhb return (ENXIO); 377125047Sjhb 378241885Seadler /* Check that we haven't been disabled with a hint. */ 379241885Seadler if (resource_disabled("acpi", 0)) 380241885Seadler return (ENXIO); 381241885Seadler 382177157Sjhb /* Check for other PM systems. */ 383177157Sjhb if (power_pm_get_type() != POWER_PM_TYPE_NONE && 384177157Sjhb power_pm_get_type() != POWER_PM_TYPE_ACPI) { 385177157Sjhb printf("ACPI identify failed, other PM system enabled.\n"); 386177157Sjhb return (ENXIO); 387177157Sjhb } 388125047Sjhb 389167814Sjkim /* Initialize root tables. */ 390167814Sjkim if (ACPI_FAILURE(acpi_Startup())) { 391167814Sjkim printf("ACPI: Try disabling either ACPI or apic support.\n"); 392177157Sjhb return (ENXIO); 393167814Sjkim } 394125047Sjhb 395167814Sjkim if ((paddr = AcpiOsGetRootPointer()) == 0 || 396167814Sjkim (rsdp = AcpiOsMapMemory(paddr, sizeof(ACPI_TABLE_RSDP))) == NULL) 397177157Sjhb return (ENXIO); 398167814Sjkim if (rsdp->Revision > 1 && rsdp->XsdtPhysicalAddress != 0) 399167814Sjkim paddr = (ACPI_PHYSICAL_ADDRESS)rsdp->XsdtPhysicalAddress; 400167814Sjkim else 401167814Sjkim paddr = (ACPI_PHYSICAL_ADDRESS)rsdp->RsdtPhysicalAddress; 402167814Sjkim AcpiOsUnmapMemory(rsdp, sizeof(ACPI_TABLE_RSDP)); 403133051Snjl 404167814Sjkim if ((rsdt = AcpiOsMapMemory(paddr, sizeof(ACPI_TABLE_HEADER))) == NULL) 405177157Sjhb return (ENXIO); 406177157Sjhb sbuf_new(&sb, acpi_desc, sizeof(acpi_desc), SBUF_FIXEDLEN); 407167814Sjkim sbuf_bcat(&sb, rsdt->OemId, ACPI_OEM_ID_SIZE); 408167814Sjkim sbuf_trim(&sb); 409167814Sjkim sbuf_putc(&sb, ' '); 410167814Sjkim sbuf_bcat(&sb, rsdt->OemTableId, ACPI_OEM_TABLE_ID_SIZE); 411167814Sjkim sbuf_trim(&sb); 412167814Sjkim sbuf_finish(&sb); 413167814Sjkim sbuf_delete(&sb); 414167814Sjkim AcpiOsUnmapMemory(rsdt, sizeof(ACPI_TABLE_HEADER)); 415167814Sjkim 416177157Sjhb snprintf(acpi_ca_version, sizeof(acpi_ca_version), "%x", ACPI_CA_VERSION); 417177157Sjhb 418177157Sjhb return (0); 419177157Sjhb} 420177157Sjhb 421177157Sjhb/* 422177157Sjhb * Fetch some descriptive data from ACPI to put in our attach message. 423177157Sjhb */ 424177157Sjhbstatic int 425177157Sjhbacpi_probe(device_t dev) 426177157Sjhb{ 427177157Sjhb 428177157Sjhb ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 429177157Sjhb 430177157Sjhb device_set_desc(dev, acpi_desc); 431177157Sjhb 432265999Sian return_VALUE (BUS_PROBE_NOWILDCARD); 43367761Smsmith} 43467761Smsmith 43567761Smsmithstatic int 43667761Smsmithacpi_attach(device_t dev) 43767761Smsmith{ 43867761Smsmith struct acpi_softc *sc; 43978991Smsmith ACPI_STATUS status; 440128993Snjl int error, state; 44183180Smsmith UINT32 flags; 442128993Snjl UINT8 TypeA, TypeB; 443106261Siwasaki char *env; 44467761Smsmith 44596926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 446133051Snjl 44767761Smsmith sc = device_get_softc(dev); 44867761Smsmith sc->acpi_dev = dev; 449170976Snjl callout_init(&sc->susp_force_to, TRUE); 45067761Smsmith 451167814Sjkim error = ENXIO; 452167814Sjkim 453130439Snjl /* Initialize resource manager. */ 454130439Snjl acpi_rman_io.rm_type = RMAN_ARRAY; 455130439Snjl acpi_rman_io.rm_start = 0; 456130439Snjl acpi_rman_io.rm_end = 0xffff; 457162225Sjhb acpi_rman_io.rm_descr = "ACPI I/O ports"; 458130439Snjl if (rman_init(&acpi_rman_io) != 0) 459130439Snjl panic("acpi rman_init IO ports failed"); 460130439Snjl acpi_rman_mem.rm_type = RMAN_ARRAY; 461130439Snjl acpi_rman_mem.rm_start = 0; 462130439Snjl acpi_rman_mem.rm_end = ~0ul; 463162225Sjhb acpi_rman_mem.rm_descr = "ACPI I/O memory addresses"; 464130439Snjl if (rman_init(&acpi_rman_mem) != 0) 465130439Snjl panic("acpi rman_init memory failed"); 466130439Snjl 467167814Sjkim /* Initialise the ACPI mutex */ 468167814Sjkim mtx_init(&acpi_mutex, "ACPI global lock", NULL, MTX_DEF); 469167814Sjkim 470167814Sjkim /* 471167814Sjkim * Set the globals from our tunables. This is needed because ACPI-CA 472167814Sjkim * uses UINT8 for some values and we have no tunable_byte. 473167814Sjkim */ 474204916Sjkim AcpiGbl_EnableInterpreterSlack = acpi_interpreter_slack ? TRUE : FALSE; 475204916Sjkim AcpiGbl_EnableAmlDebugObject = acpi_debug_objects ? TRUE : FALSE; 476281075Sdim AcpiGbl_UseDefaultRegisterWidths = acpi_ignore_reg_width ? TRUE : FALSE; 477167814Sjkim 478204916Sjkim#ifndef ACPI_DEBUG 479204916Sjkim /* 480204916Sjkim * Disable all debugging layers and levels. 481204916Sjkim */ 482204916Sjkim AcpiDbgLayer = 0; 483204916Sjkim AcpiDbgLevel = 0; 484204916Sjkim#endif 485204916Sjkim 486167814Sjkim /* Start up the ACPI CA subsystem. */ 487167814Sjkim status = AcpiInitializeSubsystem(); 488167814Sjkim if (ACPI_FAILURE(status)) { 489167814Sjkim device_printf(dev, "Could not initialize Subsystem: %s\n", 490167814Sjkim AcpiFormatException(status)); 491167814Sjkim goto out; 492167814Sjkim } 493167814Sjkim 494214390Sjkim /* Override OS interfaces if the user requested. */ 495214390Sjkim acpi_reset_interfaces(dev); 496214390Sjkim 497167814Sjkim /* Load ACPI name space. */ 498167814Sjkim status = AcpiLoadTables(); 499167814Sjkim if (ACPI_FAILURE(status)) { 500167814Sjkim device_printf(dev, "Could not load Namespace: %s\n", 501167814Sjkim AcpiFormatException(status)); 502167814Sjkim goto out; 503167814Sjkim } 504167814Sjkim 505181987Sjhb#if defined(__i386__) || defined(__amd64__) 506181987Sjhb /* Handle MCFG table if present. */ 507181987Sjhb acpi_enable_pcie(); 508181987Sjhb#endif 509181987Sjhb 51067761Smsmith /* 511119529Snjl * Note that some systems (specifically, those with namespace evaluation 512119529Snjl * issues that require the avoidance of parts of the namespace) must 513119529Snjl * avoid running _INI and _STA on everything, as well as dodging the final 514119529Snjl * object init pass. 51567761Smsmith * 51683180Smsmith * For these devices, we set ACPI_NO_DEVICE_INIT and ACPI_NO_OBJECT_INIT). 51783180Smsmith * 518119529Snjl * XXX We should arrange for the object init pass after we have attached 519119529Snjl * all our child devices, but on many systems it works here. 52067761Smsmith */ 52183180Smsmith flags = 0; 52294936Smux if (testenv("debug.acpi.avoid")) 52383180Smsmith flags = ACPI_NO_DEVICE_INIT | ACPI_NO_OBJECT_INIT; 524133051Snjl 525133051Snjl /* Bring the hardware and basic handlers online. */ 52691120Smsmith if (ACPI_FAILURE(status = AcpiEnableSubsystem(flags))) { 527119529Snjl device_printf(dev, "Could not enable ACPI: %s\n", 528119529Snjl AcpiFormatException(status)); 52978991Smsmith goto out; 53067761Smsmith } 53167761Smsmith 532117795Snjl /* 533117795Snjl * Call the ECDT probe function to provide EC functionality before 534117795Snjl * the namespace has been evaluated. 535158346Snjl * 536158346Snjl * XXX This happens before the sysresource devices have been probed and 537158346Snjl * attached so its resources come from nexus0. In practice, this isn't 538158346Snjl * a problem but should be addressed eventually. 539117795Snjl */ 540117795Snjl acpi_ec_ecdt_probe(dev); 541117795Snjl 542133051Snjl /* Bring device objects and regions online. */ 543100969Siwasaki if (ACPI_FAILURE(status = AcpiInitializeObjects(flags))) { 544119529Snjl device_printf(dev, "Could not initialize ACPI objects: %s\n", 545119529Snjl AcpiFormatException(status)); 546100969Siwasaki goto out; 547100969Siwasaki } 548100969Siwasaki 54967761Smsmith /* 55071001Sjhb * Setup our sysctl tree. 55171001Sjhb * 55271001Sjhb * XXX: This doesn't check to make sure that none of these fail. 55371001Sjhb */ 55471001Sjhb sysctl_ctx_init(&sc->acpi_sysctl_ctx); 55571001Sjhb sc->acpi_sysctl_tree = SYSCTL_ADD_NODE(&sc->acpi_sysctl_ctx, 55671001Sjhb SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, 55771001Sjhb device_get_name(dev), CTLFLAG_RD, 0, ""); 55871001Sjhb SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), 559113366Siwasaki OID_AUTO, "supported_sleep_state", CTLTYPE_STRING | CTLFLAG_RD, 560113366Siwasaki 0, 0, acpi_supported_sleep_state_sysctl, "A", ""); 561113366Siwasaki SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), 56271001Sjhb OID_AUTO, "power_button_state", CTLTYPE_STRING | CTLFLAG_RW, 56371001Sjhb &sc->acpi_power_button_sx, 0, acpi_sleep_state_sysctl, "A", ""); 56471001Sjhb SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), 56571001Sjhb OID_AUTO, "sleep_button_state", CTLTYPE_STRING | CTLFLAG_RW, 56671001Sjhb &sc->acpi_sleep_button_sx, 0, acpi_sleep_state_sysctl, "A", ""); 56771001Sjhb SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), 56871001Sjhb OID_AUTO, "lid_switch_state", CTLTYPE_STRING | CTLFLAG_RW, 56971001Sjhb &sc->acpi_lid_switch_sx, 0, acpi_sleep_state_sysctl, "A", ""); 57085556Siwasaki SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), 57185556Siwasaki OID_AUTO, "standby_state", CTLTYPE_STRING | CTLFLAG_RW, 57285556Siwasaki &sc->acpi_standby_sx, 0, acpi_sleep_state_sysctl, "A", ""); 57385556Siwasaki SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), 57485556Siwasaki OID_AUTO, "suspend_state", CTLTYPE_STRING | CTLFLAG_RW, 57585556Siwasaki &sc->acpi_suspend_sx, 0, acpi_sleep_state_sysctl, "A", ""); 57685699Siwasaki SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), 577159476Snjl OID_AUTO, "sleep_delay", CTLFLAG_RW, &sc->acpi_sleep_delay, 0, 578225533Sbrueffer "sleep delay in seconds"); 579102402Siwasaki SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), 580159476Snjl OID_AUTO, "s4bios", CTLFLAG_RW, &sc->acpi_s4bios, 0, "S4BIOS mode"); 58186133Siwasaki SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), 582159476Snjl OID_AUTO, "verbose", CTLFLAG_RW, &sc->acpi_verbose, 0, "verbose mode"); 583159524Snjl SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), 584159524Snjl OID_AUTO, "disable_on_reboot", CTLFLAG_RW, 585159524Snjl &sc->acpi_do_disable, 0, "Disable ACPI when rebooting/halting system"); 586160824Snjl SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), 587160824Snjl OID_AUTO, "handle_reboot", CTLFLAG_RW, 588160824Snjl &sc->acpi_handle_reboot, 0, "Use ACPI Reset Register to reboot"); 589118642Snjl 590118642Snjl /* 591129831Snjl * Default to 1 second before sleeping to give some machines time to 592118642Snjl * stabilize. 593118642Snjl */ 594129831Snjl sc->acpi_sleep_delay = 1; 59585699Siwasaki if (bootverbose) 59685699Siwasaki sc->acpi_verbose = 1; 597144414Snjl if ((env = getenv("hw.acpi.verbose")) != NULL) { 598144414Snjl if (strcmp(env, "0") != 0) 599144414Snjl sc->acpi_verbose = 1; 600106261Siwasaki freeenv(env); 601106261Siwasaki } 602106261Siwasaki 603213755Sjkim /* Only enable reboot by default if the FADT says it is available. */ 604213755Sjkim if (AcpiGbl_FADT.Flags & ACPI_FADT_RESET_REGISTER) 605213755Sjkim sc->acpi_handle_reboot = 1; 606213755Sjkim 607120087Snjl /* Only enable S4BIOS by default if the FACS says it is available. */ 608193530Sjkim if (AcpiGbl_FACS->Flags & ACPI_FACS_S4_BIOS_PRESENT) 609131315Snjl sc->acpi_s4bios = 1; 610120087Snjl 611191695Sjkim /* Probe all supported sleep states. */ 612191695Sjkim acpi_sleep_states[ACPI_STATE_S0] = TRUE; 613191695Sjkim for (state = ACPI_STATE_S1; state < ACPI_S_STATE_COUNT; state++) 614245582Sjkim if (ACPI_SUCCESS(AcpiEvaluateObject(ACPI_ROOT_OBJECT, 615245582Sjkim __DECONST(char *, AcpiGbl_SleepStateNames[state]), NULL, NULL)) && 616245582Sjkim ACPI_SUCCESS(AcpiGetSleepTypeData(state, &TypeA, &TypeB))) 617191695Sjkim acpi_sleep_states[state] = TRUE; 618191695Sjkim 61971001Sjhb /* 620128993Snjl * Dispatch the default sleep state to devices. The lid switch is set 621191695Sjkim * to UNKNOWN by default to avoid surprising users. 62267761Smsmith */ 623191695Sjkim sc->acpi_power_button_sx = acpi_sleep_states[ACPI_STATE_S5] ? 624191695Sjkim ACPI_STATE_S5 : ACPI_STATE_UNKNOWN; 625191695Sjkim sc->acpi_lid_switch_sx = ACPI_STATE_UNKNOWN; 626191695Sjkim sc->acpi_standby_sx = acpi_sleep_states[ACPI_STATE_S1] ? 627191695Sjkim ACPI_STATE_S1 : ACPI_STATE_UNKNOWN; 628191695Sjkim sc->acpi_suspend_sx = acpi_sleep_states[ACPI_STATE_S3] ? 629191695Sjkim ACPI_STATE_S3 : ACPI_STATE_UNKNOWN; 63067761Smsmith 631128993Snjl /* Pick the first valid sleep state for the sleep button default. */ 632191695Sjkim sc->acpi_sleep_button_sx = ACPI_STATE_UNKNOWN; 633170976Snjl for (state = ACPI_STATE_S1; state <= ACPI_STATE_S4; state++) 634191695Sjkim if (acpi_sleep_states[state]) { 635128993Snjl sc->acpi_sleep_button_sx = state; 636128993Snjl break; 637128993Snjl } 638128993Snjl 63970897Siwasaki acpi_enable_fixed_events(sc); 64067761Smsmith 64167761Smsmith /* 64267761Smsmith * Scan the namespace and attach/initialise children. 64367761Smsmith */ 64467761Smsmith 645130451Snjl /* Register our shutdown handler. */ 646119529Snjl EVENTHANDLER_REGISTER(shutdown_final, acpi_shutdown_final, sc, 647119529Snjl SHUTDOWN_PRI_LAST); 64867761Smsmith 64967761Smsmith /* 65067761Smsmith * Register our acpi event handlers. 65167761Smsmith * XXX should be configurable eg. via userland policy manager. 65267761Smsmith */ 653119529Snjl EVENTHANDLER_REGISTER(acpi_sleep_event, acpi_system_eventhandler_sleep, 654119529Snjl sc, ACPI_EVENT_PRI_LAST); 655119529Snjl EVENTHANDLER_REGISTER(acpi_wakeup_event, acpi_system_eventhandler_wakeup, 656119529Snjl sc, ACPI_EVENT_PRI_LAST); 65767761Smsmith 658119529Snjl /* Flag our initial states. */ 659191695Sjkim sc->acpi_enabled = TRUE; 66067761Smsmith sc->acpi_sstate = ACPI_STATE_S0; 661191695Sjkim sc->acpi_sleep_disabled = TRUE; 66267761Smsmith 663119529Snjl /* Create the control device */ 664110894Stakawata sc->acpi_dev_t = make_dev(&acpi_cdevsw, 0, UID_ROOT, GID_WHEEL, 0644, 665119529Snjl "acpi"); 66667761Smsmith sc->acpi_dev_t->si_drv1 = sc; 66767761Smsmith 668119529Snjl if ((error = acpi_machdep_init(dev))) 66985556Siwasaki goto out; 67085556Siwasaki 67185835Siwasaki /* Register ACPI again to pass the correct argument of pm_func. */ 67285835Siwasaki power_pm_register(POWER_PM_TYPE_ACPI, acpi_pm_func, sc); 67385835Siwasaki 674295131Sjhb if (!acpi_disabled("bus")) { 675295131Sjhb EVENTHANDLER_REGISTER(dev_lookup, acpi_lookup, NULL, 1000); 676103022Sjhb acpi_probe_children(dev); 677295131Sjhb } 678103022Sjhb 679216471Sjkim /* Update all GPEs and enable runtime GPEs. */ 680216471Sjkim status = AcpiUpdateAllGpes(); 681216471Sjkim if (ACPI_FAILURE(status)) 682216471Sjkim device_printf(dev, "Could not update all GPEs: %s\n", 683216471Sjkim AcpiFormatException(status)); 684216471Sjkim 685191695Sjkim /* Allow sleep request after a while. */ 686191695Sjkim timeout(acpi_sleep_enable, sc, hz * ACPI_MINIMUM_AWAKETIME); 687191695Sjkim 68878991Smsmith error = 0; 68978991Smsmith 69078991Smsmith out: 691119529Snjl return_VALUE (error); 69267761Smsmith} 69367761Smsmith 694214072Sjkimstatic void 695214072Sjkimacpi_set_power_children(device_t dev, int state) 696214072Sjkim{ 697214072Sjkim device_t child, parent; 698214072Sjkim device_t *devlist; 699214072Sjkim struct pci_devinfo *dinfo; 700214072Sjkim int dstate, i, numdevs; 701214072Sjkim 702214072Sjkim if (device_get_children(dev, &devlist, &numdevs) != 0) 703214072Sjkim return; 704214072Sjkim 705214072Sjkim /* 706214072Sjkim * Retrieve and set D-state for the sleep state if _SxD is present. 707214072Sjkim * Skip children who aren't attached since they are handled separately. 708214072Sjkim */ 709214072Sjkim parent = device_get_parent(dev); 710214072Sjkim for (i = 0; i < numdevs; i++) { 711214072Sjkim child = devlist[i]; 712214072Sjkim dinfo = device_get_ivars(child); 713214072Sjkim dstate = state; 714214072Sjkim if (device_is_attached(child) && 715214072Sjkim acpi_device_pwr_for_sleep(parent, dev, &dstate) == 0) 716214072Sjkim acpi_set_powerstate(child, dstate); 717214072Sjkim } 718214072Sjkim free(devlist, M_TEMP); 719214072Sjkim} 720214072Sjkim 721130114Snjlstatic int 722138306Snjlacpi_suspend(device_t dev) 723138306Snjl{ 724214072Sjkim int error; 725138306Snjl 726196403Sjhb GIANT_REQUIRED; 727196403Sjhb 728138306Snjl error = bus_generic_suspend(dev); 729214072Sjkim if (error == 0) 730214072Sjkim acpi_set_power_children(dev, ACPI_STATE_D3); 731138306Snjl 732138306Snjl return (error); 733138306Snjl} 734138306Snjl 735138306Snjlstatic int 736138306Snjlacpi_resume(device_t dev) 737138306Snjl{ 738138306Snjl 739196403Sjhb GIANT_REQUIRED; 740196403Sjhb 741214072Sjkim acpi_set_power_children(dev, ACPI_STATE_D0); 742138306Snjl 743138306Snjl return (bus_generic_resume(dev)); 744138306Snjl} 745138306Snjl 746138306Snjlstatic int 747130114Snjlacpi_shutdown(device_t dev) 748130114Snjl{ 749130114Snjl 750196403Sjhb GIANT_REQUIRED; 751196403Sjhb 752130119Snjl /* Allow children to shutdown first. */ 753130119Snjl bus_generic_shutdown(dev); 754130119Snjl 755133051Snjl /* 756133051Snjl * Enable any GPEs that are able to power-on the system (i.e., RTC). 757133051Snjl * Also, disable any that are not valid for this state (most). 758133051Snjl */ 759131341Snjl acpi_wake_prep_walk(ACPI_STATE_S5); 760131341Snjl 761130114Snjl return (0); 762130114Snjl} 763130114Snjl 76467761Smsmith/* 76567761Smsmith * Handle a new device being added 76667761Smsmith */ 76767761Smsmithstatic device_t 768212413Savgacpi_add_child(device_t bus, u_int order, const char *name, int unit) 76967761Smsmith{ 77067761Smsmith struct acpi_device *ad; 77167761Smsmith device_t child; 77267761Smsmith 773119529Snjl if ((ad = malloc(sizeof(*ad), M_ACPIDEV, M_NOWAIT | M_ZERO)) == NULL) 774119529Snjl return (NULL); 77567761Smsmith 77667761Smsmith resource_list_init(&ad->ad_rl); 777129783Snjl 77867761Smsmith child = device_add_child_ordered(bus, order, name, unit); 77967761Smsmith if (child != NULL) 78067761Smsmith device_set_ivars(child, ad); 781144170Snjl else 782144170Snjl free(ad, M_ACPIDEV); 783119529Snjl return (child); 78467761Smsmith} 78567761Smsmith 78667761Smsmithstatic int 78767761Smsmithacpi_print_child(device_t bus, device_t child) 78867761Smsmith{ 789119529Snjl struct acpi_device *adev = device_get_ivars(child); 790119529Snjl struct resource_list *rl = &adev->ad_rl; 79167761Smsmith int retval = 0; 79267761Smsmith 79367761Smsmith retval += bus_print_child_header(bus, child); 794102918Sjhb retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx"); 795102918Sjhb retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#lx"); 796102918Sjhb retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); 797102918Sjhb retval += resource_list_print_type(rl, "drq", SYS_RES_DRQ, "%ld"); 798136475Snjl if (device_get_flags(child)) 799136475Snjl retval += printf(" flags %#x", device_get_flags(child)); 800279904Sscottl retval += bus_print_child_domain(bus, child); 801136476Snjl retval += bus_print_child_footer(bus, child); 80267761Smsmith 803119529Snjl return (retval); 80467761Smsmith} 80567761Smsmith 806138306Snjl/* 807138306Snjl * If this device is an ACPI child but no one claimed it, attempt 808138306Snjl * to power it off. We'll power it back up when a driver is added. 809138306Snjl * 810138306Snjl * XXX Disabled for now since many necessary devices (like fdc and 811138306Snjl * ATA) don't claim the devices we created for them but still expect 812138306Snjl * them to be powered up. 813138306Snjl */ 814138306Snjlstatic void 815138306Snjlacpi_probe_nomatch(device_t bus, device_t child) 816138306Snjl{ 817184563Simp#ifdef ACPI_ENABLE_POWERDOWN_NODRIVER 818214072Sjkim acpi_set_powerstate(child, ACPI_STATE_D3); 819184563Simp#endif 820138306Snjl} 821138306Snjl 822138306Snjl/* 823138306Snjl * If a new driver has a chance to probe a child, first power it up. 824138306Snjl * 825138306Snjl * XXX Disabled for now (see acpi_probe_nomatch for details). 826138306Snjl */ 827138306Snjlstatic void 828138306Snjlacpi_driver_added(device_t dev, driver_t *driver) 829138306Snjl{ 830138306Snjl device_t child, *devlist; 831138306Snjl int i, numdevs; 832138306Snjl 833138306Snjl DEVICE_IDENTIFY(driver, dev); 834182071Simp if (device_get_children(dev, &devlist, &numdevs)) 835182071Simp return; 836138306Snjl for (i = 0; i < numdevs; i++) { 837138306Snjl child = devlist[i]; 838138306Snjl if (device_get_state(child) == DS_NOTPRESENT) { 839184563Simp#ifdef ACPI_ENABLE_POWERDOWN_NODRIVER 840214072Sjkim acpi_set_powerstate(child, ACPI_STATE_D0); 841138306Snjl if (device_probe_and_attach(child) != 0) 842214072Sjkim acpi_set_powerstate(child, ACPI_STATE_D3); 843184563Simp#else 844184563Simp device_probe_and_attach(child); 845184563Simp#endif 846138306Snjl } 847138306Snjl } 848138306Snjl free(devlist, M_TEMP); 849138306Snjl} 850138306Snjl 851127681Snjl/* Location hint for devctl(8) */ 852127681Snjlstatic int 853127678Stakawataacpi_child_location_str_method(device_t cbdev, device_t child, char *buf, 854127678Stakawata size_t buflen) 855127678Stakawata{ 856127678Stakawata struct acpi_device *dinfo = device_get_ivars(child); 857279904Sscottl char buf2[32]; 858279904Sscottl int pxm; 859133933Snjl 860279904Sscottl if (dinfo->ad_handle) { 861279904Sscottl snprintf(buf, buflen, "handle=%s", acpi_name(dinfo->ad_handle)); 862279904Sscottl if (ACPI_SUCCESS(acpi_GetInteger(dinfo->ad_handle, "_PXM", &pxm))) { 863279904Sscottl snprintf(buf2, 32, " _PXM=%d", pxm); 864279904Sscottl strlcat(buf, buf2, buflen); 865279904Sscottl } 866279904Sscottl } else { 867279904Sscottl snprintf(buf, buflen, "unknown"); 868279904Sscottl } 869127678Stakawata return (0); 870127678Stakawata} 871127678Stakawata 872127681Snjl/* PnP information for devctl(8) */ 873127681Snjlstatic int 874127678Stakawataacpi_child_pnpinfo_str_method(device_t cbdev, device_t child, char *buf, 875127678Stakawata size_t buflen) 876127678Stakawata{ 877197105Sjkim struct acpi_device *dinfo = device_get_ivars(child); 878127681Snjl ACPI_DEVICE_INFO *adinfo; 879127678Stakawata 880197105Sjkim if (ACPI_FAILURE(AcpiGetObjectInfo(dinfo->ad_handle, &adinfo))) { 881132115Snjl snprintf(buf, buflen, "unknown"); 882197105Sjkim return (0); 883197105Sjkim } 884127678Stakawata 885197105Sjkim snprintf(buf, buflen, "_HID=%s _UID=%lu", 886197105Sjkim (adinfo->Valid & ACPI_VALID_HID) ? 887197105Sjkim adinfo->HardwareId.String : "none", 888197105Sjkim (adinfo->Valid & ACPI_VALID_UID) ? 889197105Sjkim strtoul(adinfo->UniqueId.String, NULL, 10) : 0UL); 890197105Sjkim AcpiOsFree(adinfo); 891197105Sjkim 892127678Stakawata return (0); 893127678Stakawata} 894127678Stakawata 895127678Stakawata/* 89667761Smsmith * Handle per-device ivars 89767761Smsmith */ 89867761Smsmithstatic int 89967761Smsmithacpi_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) 90067761Smsmith{ 90167761Smsmith struct acpi_device *ad; 90267761Smsmith 90367761Smsmith if ((ad = device_get_ivars(child)) == NULL) { 904191696Sjkim device_printf(child, "device has no ivars\n"); 905119529Snjl return (ENOENT); 90667761Smsmith } 90767761Smsmith 908119529Snjl /* ACPI and ISA compatibility ivars */ 90967761Smsmith switch(index) { 91067761Smsmith case ACPI_IVAR_HANDLE: 91167761Smsmith *(ACPI_HANDLE *)result = ad->ad_handle; 91267761Smsmith break; 91367761Smsmith case ACPI_IVAR_PRIVATE: 91467761Smsmith *(void **)result = ad->ad_private; 91567761Smsmith break; 916131341Snjl case ACPI_IVAR_FLAGS: 917131341Snjl *(int *)result = ad->ad_flags; 918131341Snjl break; 91983180Smsmith case ISA_IVAR_VENDORID: 92083180Smsmith case ISA_IVAR_SERIAL: 92183180Smsmith case ISA_IVAR_COMPATID: 92283180Smsmith *(int *)result = -1; 92383180Smsmith break; 92483180Smsmith case ISA_IVAR_LOGICALID: 92583180Smsmith *(int *)result = acpi_isa_get_logicalid(child); 92683180Smsmith break; 92767761Smsmith default: 928119529Snjl return (ENOENT); 92967761Smsmith } 930119529Snjl 931119529Snjl return (0); 93267761Smsmith} 93367761Smsmith 93467761Smsmithstatic int 93567761Smsmithacpi_write_ivar(device_t dev, device_t child, int index, uintptr_t value) 93667761Smsmith{ 93767761Smsmith struct acpi_device *ad; 93867761Smsmith 93967761Smsmith if ((ad = device_get_ivars(child)) == NULL) { 940191696Sjkim device_printf(child, "device has no ivars\n"); 941119529Snjl return (ENOENT); 94267761Smsmith } 94367761Smsmith 94467761Smsmith switch(index) { 94567761Smsmith case ACPI_IVAR_HANDLE: 94667761Smsmith ad->ad_handle = (ACPI_HANDLE)value; 94767761Smsmith break; 94867761Smsmith case ACPI_IVAR_PRIVATE: 94967761Smsmith ad->ad_private = (void *)value; 95067761Smsmith break; 951131341Snjl case ACPI_IVAR_FLAGS: 952131341Snjl ad->ad_flags = (int)value; 953131341Snjl break; 95467761Smsmith default: 955101763Simp panic("bad ivar write request (%d)", index); 956119529Snjl return (ENOENT); 95767761Smsmith } 958119529Snjl 959119529Snjl return (0); 96067761Smsmith} 96167761Smsmith 96267761Smsmith/* 96367761Smsmith * Handle child resource allocation/removal 96467761Smsmith */ 965130439Snjlstatic struct resource_list * 966130439Snjlacpi_get_rlist(device_t dev, device_t child) 96767761Smsmith{ 968130439Snjl struct acpi_device *ad; 96967761Smsmith 970130439Snjl ad = device_get_ivars(child); 971130439Snjl return (&ad->ad_rl); 97267761Smsmith} 97367761Smsmith 974185059Sjhbstatic int 975185059Sjhbacpi_match_resource_hint(device_t dev, int type, long value) 976185059Sjhb{ 977185059Sjhb struct acpi_device *ad = device_get_ivars(dev); 978185059Sjhb struct resource_list *rl = &ad->ad_rl; 979185059Sjhb struct resource_list_entry *rle; 980185059Sjhb 981185059Sjhb STAILQ_FOREACH(rle, rl, link) { 982185059Sjhb if (rle->type != type) 983185059Sjhb continue; 984185059Sjhb if (rle->start <= value && rle->end >= value) 985185059Sjhb return (1); 986185059Sjhb } 987185059Sjhb return (0); 988185059Sjhb} 989185059Sjhb 990134217Snjl/* 991185059Sjhb * Wire device unit numbers based on resource matches in hints. 992185059Sjhb */ 993185059Sjhbstatic void 994185059Sjhbacpi_hint_device_unit(device_t acdev, device_t child, const char *name, 995185059Sjhb int *unitp) 996185059Sjhb{ 997185059Sjhb const char *s; 998185059Sjhb long value; 999185059Sjhb int line, matches, unit; 1000185059Sjhb 1001185059Sjhb /* 1002185059Sjhb * Iterate over all the hints for the devices with the specified 1003185059Sjhb * name to see if one's resources are a subset of this device. 1004185059Sjhb */ 1005185059Sjhb line = 0; 1006185059Sjhb for (;;) { 1007185059Sjhb if (resource_find_dev(&line, name, &unit, "at", NULL) != 0) 1008185059Sjhb break; 1009185059Sjhb 1010185059Sjhb /* Must have an "at" for acpi or isa. */ 1011185059Sjhb resource_string_value(name, unit, "at", &s); 1012185059Sjhb if (!(strcmp(s, "acpi0") == 0 || strcmp(s, "acpi") == 0 || 1013185059Sjhb strcmp(s, "isa0") == 0 || strcmp(s, "isa") == 0)) 1014185059Sjhb continue; 1015185059Sjhb 1016185059Sjhb /* 1017196520Sjhb * Check for matching resources. We must have at least one match. 1018196520Sjhb * Since I/O and memory resources cannot be shared, if we get a 1019196520Sjhb * match on either of those, ignore any mismatches in IRQs or DRQs. 1020185059Sjhb * 1021185059Sjhb * XXX: We may want to revisit this to be more lenient and wire 1022185059Sjhb * as long as it gets one match. 1023185059Sjhb */ 1024185059Sjhb matches = 0; 1025185059Sjhb if (resource_long_value(name, unit, "port", &value) == 0) { 1026196520Sjhb /* 1027196520Sjhb * Floppy drive controllers are notorious for having a 1028196520Sjhb * wide variety of resources not all of which include the 1029196520Sjhb * first port that is specified by the hint (typically 1030196520Sjhb * 0x3f0) (see the comment above fdc_isa_alloc_resources() 1031196520Sjhb * in fdc_isa.c). However, they do all seem to include 1032196520Sjhb * port + 2 (e.g. 0x3f2) so for a floppy device, look for 1033196520Sjhb * 'value + 2' in the port resources instead of the hint 1034196520Sjhb * value. 1035196520Sjhb */ 1036196520Sjhb if (strcmp(name, "fdc") == 0) 1037196520Sjhb value += 2; 1038185059Sjhb if (acpi_match_resource_hint(child, SYS_RES_IOPORT, value)) 1039185059Sjhb matches++; 1040185059Sjhb else 1041185059Sjhb continue; 1042185059Sjhb } 1043185059Sjhb if (resource_long_value(name, unit, "maddr", &value) == 0) { 1044185059Sjhb if (acpi_match_resource_hint(child, SYS_RES_MEMORY, value)) 1045185059Sjhb matches++; 1046185059Sjhb else 1047185059Sjhb continue; 1048185059Sjhb } 1049196520Sjhb if (matches > 0) 1050196520Sjhb goto matched; 1051185059Sjhb if (resource_long_value(name, unit, "irq", &value) == 0) { 1052185059Sjhb if (acpi_match_resource_hint(child, SYS_RES_IRQ, value)) 1053185059Sjhb matches++; 1054185059Sjhb else 1055185059Sjhb continue; 1056185059Sjhb } 1057185059Sjhb if (resource_long_value(name, unit, "drq", &value) == 0) { 1058185059Sjhb if (acpi_match_resource_hint(child, SYS_RES_DRQ, value)) 1059185059Sjhb matches++; 1060185059Sjhb else 1061185059Sjhb continue; 1062185059Sjhb } 1063185059Sjhb 1064196520Sjhb matched: 1065185059Sjhb if (matches > 0) { 1066185059Sjhb /* We have a winner! */ 1067185059Sjhb *unitp = unit; 1068185059Sjhb break; 1069185059Sjhb } 1070185059Sjhb } 1071185059Sjhb} 1072185059Sjhb 1073185059Sjhb/* 1074279904Sscottl * Fech the NUMA domain for the given device. 1075279904Sscottl * 1076279904Sscottl * If a device has a _PXM method, map that to a NUMA domain. 1077279904Sscottl * 1078279904Sscottl * If none is found, then it'll call the parent method. 1079279904Sscottl * If there's no domain, return ENOENT. 1080279904Sscottl */ 1081279904Sscottlint 1082279904Sscottlacpi_get_domain(device_t dev, device_t child, int *domain) 1083279904Sscottl{ 1084279904Sscottl#if MAXMEMDOM > 1 1085279904Sscottl ACPI_HANDLE h; 1086279904Sscottl int d, pxm; 1087279904Sscottl 1088279904Sscottl h = acpi_get_handle(child); 1089279904Sscottl if ((h != NULL) && 1090279904Sscottl ACPI_SUCCESS(acpi_GetInteger(h, "_PXM", &pxm))) { 1091279904Sscottl d = acpi_map_pxm_to_vm_domainid(pxm); 1092279904Sscottl if (d < 0) 1093279904Sscottl return (ENOENT); 1094279904Sscottl *domain = d; 1095279904Sscottl return (0); 1096279904Sscottl } 1097279904Sscottl#endif 1098279904Sscottl /* No _PXM node; go up a level */ 1099279904Sscottl return (bus_generic_get_domain(dev, child, domain)); 1100279904Sscottl} 1101279904Sscottl 1102279904Sscottl/* 1103134217Snjl * Pre-allocate/manage all memory and IO resources. Since rman can't handle 1104134217Snjl * duplicates, we merge any in the sysresource attach routine. 1105134217Snjl */ 1106134217Snjlstatic int 1107134217Snjlacpi_sysres_alloc(device_t dev) 1108134217Snjl{ 1109134217Snjl struct resource *res; 1110134217Snjl struct resource_list *rl; 1111134217Snjl struct resource_list_entry *rle; 1112134217Snjl struct rman *rm; 1113158346Snjl char *sysres_ids[] = { "PNP0C01", "PNP0C02", NULL }; 1114158346Snjl device_t *children; 1115158346Snjl int child_count, i; 1116134217Snjl 1117158346Snjl /* 1118158346Snjl * Probe/attach any sysresource devices. This would be unnecessary if we 1119158346Snjl * had multi-pass probe/attach. 1120158346Snjl */ 1121158346Snjl if (device_get_children(dev, &children, &child_count) != 0) 1122158346Snjl return (ENXIO); 1123158346Snjl for (i = 0; i < child_count; i++) { 1124158346Snjl if (ACPI_ID_PROBE(dev, children[i], sysres_ids) != NULL) 1125158346Snjl device_probe_and_attach(children[i]); 1126158346Snjl } 1127158346Snjl free(children, M_TEMP); 1128158346Snjl 1129134217Snjl rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev); 1130143801Sphk STAILQ_FOREACH(rle, rl, link) { 1131134217Snjl if (rle->res != NULL) { 1132134217Snjl device_printf(dev, "duplicate resource for %lx\n", rle->start); 1133134217Snjl continue; 1134134217Snjl } 1135134217Snjl 1136134217Snjl /* Only memory and IO resources are valid here. */ 1137134217Snjl switch (rle->type) { 1138134217Snjl case SYS_RES_IOPORT: 1139134217Snjl rm = &acpi_rman_io; 1140134217Snjl break; 1141134217Snjl case SYS_RES_MEMORY: 1142134217Snjl rm = &acpi_rman_mem; 1143134217Snjl break; 1144134217Snjl default: 1145134217Snjl continue; 1146134217Snjl } 1147134217Snjl 1148134217Snjl /* Pre-allocate resource and add to our rman pool. */ 1149134217Snjl res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, rle->type, 1150134217Snjl &rle->rid, rle->start, rle->start + rle->count - 1, rle->count, 0); 1151134217Snjl if (res != NULL) { 1152134217Snjl rman_manage_region(rm, rman_get_start(res), rman_get_end(res)); 1153134217Snjl rle->res = res; 1154281910Sjhb } else if (bootverbose) 1155134217Snjl device_printf(dev, "reservation of %lx, %lx (%d) failed\n", 1156134217Snjl rle->start, rle->count, rle->type); 1157134217Snjl } 1158134217Snjl return (0); 1159134217Snjl} 1160134217Snjl 1161216674Sjhbstatic char *pcilink_ids[] = { "PNP0C0F", NULL }; 1162216674Sjhbstatic char *sysres_ids[] = { "PNP0C01", "PNP0C02", NULL }; 1163216674Sjhb 1164216674Sjhb/* 1165216674Sjhb * Reserve declared resources for devices found during attach once system 1166216674Sjhb * resources have been allocated. 1167216674Sjhb */ 1168216674Sjhbstatic void 1169216674Sjhbacpi_reserve_resources(device_t dev) 117067761Smsmith{ 1171130439Snjl struct resource_list_entry *rle; 1172216674Sjhb struct resource_list *rl; 1173216674Sjhb struct acpi_device *ad; 1174216674Sjhb struct acpi_softc *sc; 1175216674Sjhb device_t *children; 1176216674Sjhb int child_count, i; 117767761Smsmith 1178216674Sjhb sc = device_get_softc(dev); 1179216674Sjhb if (device_get_children(dev, &children, &child_count) != 0) 1180216674Sjhb return; 1181216674Sjhb for (i = 0; i < child_count; i++) { 1182216674Sjhb ad = device_get_ivars(children[i]); 1183216674Sjhb rl = &ad->ad_rl; 1184167768Sjhb 1185216674Sjhb /* Don't reserve system resources. */ 1186216674Sjhb if (ACPI_ID_PROBE(dev, children[i], sysres_ids) != NULL) 1187216674Sjhb continue; 1188216674Sjhb 1189216674Sjhb STAILQ_FOREACH(rle, rl, link) { 1190216674Sjhb /* 1191216674Sjhb * Don't reserve IRQ resources. There are many sticky things 1192216674Sjhb * to get right otherwise (e.g. IRQs for psm, atkbd, and HPET 1193216674Sjhb * when using legacy routing). 1194216674Sjhb */ 1195216674Sjhb if (rle->type == SYS_RES_IRQ) 1196216674Sjhb continue; 1197216674Sjhb 1198216674Sjhb /* 1199216680Sjhb * Don't reserve the resource if it is already allocated. 1200216680Sjhb * The acpi_ec(4) driver can allocate its resources early 1201216680Sjhb * if ECDT is present. 1202216680Sjhb */ 1203216680Sjhb if (rle->res != NULL) 1204216680Sjhb continue; 1205216680Sjhb 1206216680Sjhb /* 1207216674Sjhb * Try to reserve the resource from our parent. If this 1208216674Sjhb * fails because the resource is a system resource, just 1209216674Sjhb * let it be. The resource range is already reserved so 1210216674Sjhb * that other devices will not use it. If the driver 1211216674Sjhb * needs to allocate the resource, then 1212216674Sjhb * acpi_alloc_resource() will sub-alloc from the system 1213216674Sjhb * resource. 1214216674Sjhb */ 1215216674Sjhb resource_list_reserve(rl, dev, children[i], rle->type, &rle->rid, 1216216674Sjhb rle->start, rle->end, rle->count, 0); 1217216674Sjhb } 1218167768Sjhb } 1219216674Sjhb free(children, M_TEMP); 1220216674Sjhb sc->acpi_resources_reserved = 1; 1221216674Sjhb} 1222133612Snjl 1223216674Sjhbstatic int 1224216674Sjhbacpi_set_resource(device_t dev, device_t child, int type, int rid, 1225216674Sjhb u_long start, u_long count) 1226216674Sjhb{ 1227216674Sjhb struct acpi_softc *sc = device_get_softc(dev); 1228216674Sjhb struct acpi_device *ad = device_get_ivars(child); 1229216674Sjhb struct resource_list *rl = &ad->ad_rl; 1230263022Sjhb ACPI_DEVICE_INFO *devinfo; 1231216674Sjhb u_long end; 1232216674Sjhb 1233216674Sjhb /* Ignore IRQ resources for PCI link devices. */ 1234216674Sjhb if (type == SYS_RES_IRQ && ACPI_ID_PROBE(dev, child, pcilink_ids) != NULL) 1235216674Sjhb return (0); 1236216674Sjhb 1237263022Sjhb /* 1238269038Sjhb * Ignore most resources for PCI root bridges. Some BIOSes 1239263022Sjhb * incorrectly enumerate the memory ranges they decode as plain 1240269038Sjhb * memory resources instead of as ResourceProducer ranges. Other 1241269038Sjhb * BIOSes incorrectly list system resource entries for I/O ranges 1242269038Sjhb * under the PCI bridge. Do allow the one known-correct case on 1243269038Sjhb * x86 of a PCI bridge claiming the I/O ports used for PCI config 1244269038Sjhb * access. 1245263022Sjhb */ 1246269038Sjhb if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) { 1247263022Sjhb if (ACPI_SUCCESS(AcpiGetObjectInfo(ad->ad_handle, &devinfo))) { 1248263022Sjhb if ((devinfo->Flags & ACPI_PCI_ROOT_BRIDGE) != 0) { 1249269038Sjhb#if defined(__i386__) || defined(__amd64__) 1250269038Sjhb if (!(type == SYS_RES_IOPORT && start == CONF1_ADDR_PORT)) 1251269038Sjhb#endif 1252269038Sjhb { 1253269038Sjhb AcpiOsFree(devinfo); 1254269038Sjhb return (0); 1255269038Sjhb } 1256263022Sjhb } 1257263022Sjhb AcpiOsFree(devinfo); 1258263022Sjhb } 1259263022Sjhb } 1260263022Sjhb 1261216674Sjhb /* If the resource is already allocated, fail. */ 1262216674Sjhb if (resource_list_busy(rl, type, rid)) 1263216674Sjhb return (EBUSY); 1264216674Sjhb 1265216674Sjhb /* If the resource is already reserved, release it. */ 1266216674Sjhb if (resource_list_reserved(rl, type, rid)) 1267216674Sjhb resource_list_unreserve(rl, dev, child, type, rid); 1268216674Sjhb 1269216674Sjhb /* Add the resource. */ 1270216674Sjhb end = (start + count - 1); 1271216674Sjhb resource_list_add(rl, type, rid, start, end, count); 1272216674Sjhb 1273216674Sjhb /* Don't reserve resources until the system resources are allocated. */ 1274216674Sjhb if (!sc->acpi_resources_reserved) 1275216674Sjhb return (0); 1276216674Sjhb 1277216674Sjhb /* Don't reserve system resources. */ 1278216674Sjhb if (ACPI_ID_PROBE(dev, child, sysres_ids) != NULL) 1279216674Sjhb return (0); 1280216674Sjhb 1281130439Snjl /* 1282216674Sjhb * Don't reserve IRQ resources. There are many sticky things to 1283216674Sjhb * get right otherwise (e.g. IRQs for psm, atkbd, and HPET when 1284216674Sjhb * using legacy routing). 1285130439Snjl */ 1286216674Sjhb if (type == SYS_RES_IRQ) 1287216674Sjhb return (0); 1288130439Snjl 1289167768Sjhb /* 1290216674Sjhb * Reserve the resource. 1291216674Sjhb * 1292216674Sjhb * XXX: Ignores failure for now. Failure here is probably a 1293216674Sjhb * BIOS/firmware bug? 1294167768Sjhb */ 1295216674Sjhb resource_list_reserve(rl, dev, child, type, &rid, start, end, count, 0); 1296216674Sjhb return (0); 1297216674Sjhb} 1298130439Snjl 1299216674Sjhbstatic struct resource * 1300216674Sjhbacpi_alloc_resource(device_t bus, device_t child, int type, int *rid, 1301216674Sjhb u_long start, u_long end, u_long count, u_int flags) 1302216674Sjhb{ 1303216674Sjhb ACPI_RESOURCE ares; 1304216674Sjhb struct acpi_device *ad; 1305216674Sjhb struct resource_list_entry *rle; 1306216674Sjhb struct resource_list *rl; 1307216674Sjhb struct resource *res; 1308216674Sjhb int isdefault = (start == 0UL && end == ~0UL); 1309130981Sjhb 1310216674Sjhb /* 1311216674Sjhb * First attempt at allocating the resource. For direct children, 1312216674Sjhb * use resource_list_alloc() to handle reserved resources. For 1313223502Sjhb * other devices, pass the request up to our parent. 1314216674Sjhb */ 1315216674Sjhb if (bus == device_get_parent(child)) { 1316216674Sjhb ad = device_get_ivars(child); 1317216674Sjhb rl = &ad->ad_rl; 1318216674Sjhb 1319216674Sjhb /* 1320216674Sjhb * Simulate the behavior of the ISA bus for direct children 1321216674Sjhb * devices. That is, if a non-default range is specified for 1322216674Sjhb * a resource that doesn't exist, use bus_set_resource() to 1323216674Sjhb * add the resource before allocating it. Note that these 1324216674Sjhb * resources will not be reserved. 1325216674Sjhb */ 1326216674Sjhb if (!isdefault && resource_list_find(rl, type, *rid) == NULL) 1327216674Sjhb resource_list_add(rl, type, *rid, start, end, count); 1328216674Sjhb res = resource_list_alloc(rl, bus, child, type, rid, start, end, count, 1329216674Sjhb flags); 1330216674Sjhb if (res != NULL && type == SYS_RES_IRQ) { 1331130981Sjhb /* 1332130981Sjhb * Since bus_config_intr() takes immediate effect, we cannot 1333130981Sjhb * configure the interrupt associated with a device when we 1334130981Sjhb * parse the resources but have to defer it until a driver 1335130981Sjhb * actually allocates the interrupt via bus_alloc_resource(). 1336130981Sjhb * 1337130981Sjhb * XXX: Should we handle the lookup failing? 1338130981Sjhb */ 1339130981Sjhb if (ACPI_SUCCESS(acpi_lookup_irq_resource(child, *rid, res, &ares))) 1340130981Sjhb acpi_config_intr(child, &ares); 1341130439Snjl } 1342133612Snjl 1343216674Sjhb /* 1344216674Sjhb * If this is an allocation of the "default" range for a given 1345216674Sjhb * RID, fetch the exact bounds for this resource from the 1346216674Sjhb * resource list entry to try to allocate the range from the 1347216674Sjhb * system resource regions. 1348216674Sjhb */ 1349216674Sjhb if (res == NULL && isdefault) { 1350216674Sjhb rle = resource_list_find(rl, type, *rid); 1351216674Sjhb if (rle != NULL) { 1352216674Sjhb start = rle->start; 1353216674Sjhb end = rle->end; 1354216674Sjhb count = rle->count; 1355216674Sjhb } 1356216674Sjhb } 1357216674Sjhb } else 1358216674Sjhb res = BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type, rid, 1359216674Sjhb start, end, count, flags); 1360216674Sjhb 1361216674Sjhb /* 1362216674Sjhb * If the first attempt failed and this is an allocation of a 1363216674Sjhb * specific range, try to satisfy the request via a suballocation 1364226302Sjhb * from our system resource regions. 1365216674Sjhb */ 1366226302Sjhb if (res == NULL && start + count - 1 == end) 1367226302Sjhb res = acpi_alloc_sysres(child, type, rid, start, end, count, flags); 1368226302Sjhb return (res); 1369226302Sjhb} 1370226302Sjhb 1371226302Sjhb/* 1372226302Sjhb * Attempt to allocate a specific resource range from the system 1373226302Sjhb * resource ranges. Note that we only handle memory and I/O port 1374226302Sjhb * system resources. 1375226302Sjhb */ 1376226302Sjhbstruct resource * 1377226302Sjhbacpi_alloc_sysres(device_t child, int type, int *rid, u_long start, u_long end, 1378226302Sjhb u_long count, u_int flags) 1379226302Sjhb{ 1380226302Sjhb struct rman *rm; 1381226302Sjhb struct resource *res; 1382226302Sjhb 1383216674Sjhb switch (type) { 1384216674Sjhb case SYS_RES_IOPORT: 1385216674Sjhb rm = &acpi_rman_io; 1386216674Sjhb break; 1387216674Sjhb case SYS_RES_MEMORY: 1388216674Sjhb rm = &acpi_rman_mem; 1389216674Sjhb break; 1390216674Sjhb default: 1391216674Sjhb return (NULL); 1392216674Sjhb } 1393216674Sjhb 1394226302Sjhb KASSERT(start + count - 1 == end, ("wildcard resource range")); 1395216674Sjhb res = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE, 1396216674Sjhb child); 1397216674Sjhb if (res == NULL) 1398216674Sjhb return (NULL); 1399216674Sjhb 1400216674Sjhb rman_set_rid(res, *rid); 1401216674Sjhb 1402216674Sjhb /* If requested, activate the resource using the parent's method. */ 1403216674Sjhb if (flags & RF_ACTIVE) 1404216674Sjhb if (bus_activate_resource(child, type, *rid, res) != 0) { 1405216674Sjhb rman_release_resource(res); 1406216674Sjhb return (NULL); 1407216674Sjhb } 1408216674Sjhb 1409130439Snjl return (res); 141067761Smsmith} 141167761Smsmith 141267761Smsmithstatic int 1413222929Sjhbacpi_is_resource_managed(int type, struct resource *r) 141467761Smsmith{ 141567761Smsmith 1416167768Sjhb /* We only handle memory and IO resources through rman. */ 1417167768Sjhb switch (type) { 1418167768Sjhb case SYS_RES_IOPORT: 1419222929Sjhb return (rman_is_region_manager(r, &acpi_rman_io)); 1420167768Sjhb case SYS_RES_MEMORY: 1421222929Sjhb return (rman_is_region_manager(r, &acpi_rman_mem)); 1422167768Sjhb } 1423222929Sjhb return (0); 1424222929Sjhb} 1425167768Sjhb 1426222929Sjhbstatic int 1427222929Sjhbacpi_adjust_resource(device_t bus, device_t child, int type, struct resource *r, 1428222929Sjhb u_long start, u_long end) 1429222929Sjhb{ 1430222929Sjhb 1431222929Sjhb if (acpi_is_resource_managed(type, r)) 1432222929Sjhb return (rman_adjust_resource(r, start, end)); 1433222929Sjhb return (bus_generic_adjust_resource(bus, child, type, r, start, end)); 1434222929Sjhb} 1435222929Sjhb 1436222929Sjhbstatic int 1437222929Sjhbacpi_release_resource(device_t bus, device_t child, int type, int rid, 1438222929Sjhb struct resource *r) 1439222929Sjhb{ 1440222929Sjhb int ret; 1441222929Sjhb 1442130439Snjl /* 1443167768Sjhb * If this resource belongs to one of our internal managers, 1444216674Sjhb * deactivate it and release it to the local pool. 1445130439Snjl */ 1446222929Sjhb if (acpi_is_resource_managed(type, r)) { 1447130439Snjl if (rman_get_flags(r) & RF_ACTIVE) { 1448130439Snjl ret = bus_deactivate_resource(child, type, rid, r); 1449130439Snjl if (ret != 0) 1450216674Sjhb return (ret); 1451130439Snjl } 1452216674Sjhb return (rman_release_resource(r)); 1453216674Sjhb } 1454130439Snjl 1455216674Sjhb return (bus_generic_rl_release_resource(bus, child, type, rid, r)); 145667761Smsmith} 145767761Smsmith 1458143997Snjlstatic void 1459143997Snjlacpi_delete_resource(device_t bus, device_t child, int type, int rid) 1460143997Snjl{ 1461143997Snjl struct resource_list *rl; 1462143997Snjl 1463143997Snjl rl = acpi_get_rlist(bus, child); 1464216674Sjhb if (resource_list_busy(rl, type, rid)) { 1465216674Sjhb device_printf(bus, "delete_resource: Resource still owned by child" 1466216674Sjhb " (type=%d, rid=%d)\n", type, rid); 1467216674Sjhb return; 1468216674Sjhb } 1469216674Sjhb resource_list_unreserve(rl, bus, child, type, rid); 1470143997Snjl resource_list_delete(rl, type, rid); 1471143997Snjl} 1472143997Snjl 1473122764Snjl/* Allocate an IO port or memory resource, given its GAS. */ 1474141371Snjlint 1475141371Snjlacpi_bus_alloc_gas(device_t dev, int *type, int *rid, ACPI_GENERIC_ADDRESS *gas, 1476165875Snjl struct resource **res, u_int flags) 1477122764Snjl{ 1478141371Snjl int error, res_type; 1479122764Snjl 1480141371Snjl error = ENOMEM; 1481142024Snjl if (type == NULL || rid == NULL || gas == NULL || res == NULL) 1482141371Snjl return (EINVAL); 1483122764Snjl 1484142024Snjl /* We only support memory and IO spaces. */ 1485167814Sjkim switch (gas->SpaceId) { 1486122764Snjl case ACPI_ADR_SPACE_SYSTEM_MEMORY: 1487141371Snjl res_type = SYS_RES_MEMORY; 1488122764Snjl break; 1489122764Snjl case ACPI_ADR_SPACE_SYSTEM_IO: 1490141371Snjl res_type = SYS_RES_IOPORT; 1491122764Snjl break; 1492122764Snjl default: 1493141371Snjl return (EOPNOTSUPP); 1494122764Snjl } 1495122764Snjl 1496142278Snjl /* 1497142480Snjl * If the register width is less than 8, assume the BIOS author means 1498142480Snjl * it is a bit field and just allocate a byte. 1499142278Snjl */ 1500167814Sjkim if (gas->BitWidth && gas->BitWidth < 8) 1501167814Sjkim gas->BitWidth = 8; 1502142278Snjl 1503142024Snjl /* Validate the address after we're sure we support the space. */ 1504167814Sjkim if (gas->Address == 0 || gas->BitWidth == 0) 1505142024Snjl return (EINVAL); 1506142024Snjl 1507141371Snjl bus_set_resource(dev, res_type, *rid, gas->Address, 1508167814Sjkim gas->BitWidth / 8); 1509165875Snjl *res = bus_alloc_resource_any(dev, res_type, rid, RF_ACTIVE | flags); 1510141371Snjl if (*res != NULL) { 1511141371Snjl *type = res_type; 1512141371Snjl error = 0; 1513144197Snjl } else 1514144197Snjl bus_delete_resource(dev, res_type, *rid); 1515144197Snjl 1516141371Snjl return (error); 1517122764Snjl} 1518122764Snjl 1519131258Snjl/* Probe _HID and _CID for compatible ISA PNP ids. */ 1520123619Snjlstatic uint32_t 152183180Smsmithacpi_isa_get_logicalid(device_t dev) 152282537Smsmith{ 1523123619Snjl ACPI_DEVICE_INFO *devinfo; 152482537Smsmith ACPI_HANDLE h; 1525197105Sjkim uint32_t pnpid; 152683180Smsmith 152796926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 152883180Smsmith 1529117530Snjl /* Fetch and validate the HID. */ 1530197105Sjkim if ((h = acpi_get_handle(dev)) == NULL || 1531197105Sjkim ACPI_FAILURE(AcpiGetObjectInfo(h, &devinfo))) 1532197105Sjkim return_VALUE (0); 153383180Smsmith 1534197105Sjkim pnpid = (devinfo->Valid & ACPI_VALID_HID) != 0 && 1535197105Sjkim devinfo->HardwareId.Length >= ACPI_EISAID_STRING_SIZE ? 1536197105Sjkim PNP_EISAID(devinfo->HardwareId.String) : 0; 1537197105Sjkim AcpiOsFree(devinfo); 1538119529Snjl 1539119529Snjl return_VALUE (pnpid); 154083180Smsmith} 154183180Smsmith 1542123619Snjlstatic int 1543123619Snjlacpi_isa_get_compatid(device_t dev, uint32_t *cids, int count) 1544111948Stakawata{ 1545123619Snjl ACPI_DEVICE_INFO *devinfo; 1546241973Sjkim ACPI_PNP_DEVICE_ID *ids; 1547111948Stakawata ACPI_HANDLE h; 1548123619Snjl uint32_t *pnpid; 1549197105Sjkim int i, valid; 1550111948Stakawata 1551111948Stakawata ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 1552111948Stakawata 1553123619Snjl pnpid = cids; 1554123781Snjl 1555123619Snjl /* Fetch and validate the CID */ 1556197105Sjkim if ((h = acpi_get_handle(dev)) == NULL || 1557197105Sjkim ACPI_FAILURE(AcpiGetObjectInfo(h, &devinfo))) 1558197105Sjkim return_VALUE (0); 1559111948Stakawata 1560197105Sjkim if ((devinfo->Valid & ACPI_VALID_CID) == 0) { 1561197105Sjkim AcpiOsFree(devinfo); 1562197105Sjkim return_VALUE (0); 1563123619Snjl } 1564123619Snjl 1565197105Sjkim if (devinfo->CompatibleIdList.Count < count) 1566197105Sjkim count = devinfo->CompatibleIdList.Count; 1567197105Sjkim ids = devinfo->CompatibleIdList.Ids; 1568197105Sjkim for (i = 0, valid = 0; i < count; i++) 1569197105Sjkim if (ids[i].Length >= ACPI_EISAID_STRING_SIZE && 1570197105Sjkim strncmp(ids[i].String, "PNP", 3) == 0) { 1571197105Sjkim *pnpid++ = PNP_EISAID(ids[i].String); 1572197105Sjkim valid++; 1573197105Sjkim } 1574197105Sjkim AcpiOsFree(devinfo); 1575197105Sjkim 1576123619Snjl return_VALUE (valid); 1577111948Stakawata} 1578111948Stakawata 1579131281Snjlstatic char * 1580131281Snjlacpi_device_id_probe(device_t bus, device_t dev, char **ids) 1581131281Snjl{ 1582131281Snjl ACPI_HANDLE h; 1583197105Sjkim ACPI_OBJECT_TYPE t; 1584131281Snjl int i; 1585131281Snjl 1586131281Snjl h = acpi_get_handle(dev); 1587197105Sjkim if (ids == NULL || h == NULL) 1588131281Snjl return (NULL); 1589197105Sjkim t = acpi_get_type(dev); 1590197105Sjkim if (t != ACPI_TYPE_DEVICE && t != ACPI_TYPE_PROCESSOR) 1591197105Sjkim return (NULL); 1592131281Snjl 1593131281Snjl /* Try to match one of the array of IDs with a HID or CID. */ 1594131281Snjl for (i = 0; ids[i] != NULL; i++) { 1595131281Snjl if (acpi_MatchHid(h, ids[i])) 1596131281Snjl return (ids[i]); 1597131281Snjl } 1598131281Snjl return (NULL); 1599131281Snjl} 1600131281Snjl 1601131281Snjlstatic ACPI_STATUS 1602131281Snjlacpi_device_eval_obj(device_t bus, device_t dev, ACPI_STRING pathname, 1603131281Snjl ACPI_OBJECT_LIST *parameters, ACPI_BUFFER *ret) 1604131281Snjl{ 1605131281Snjl ACPI_HANDLE h; 1606131281Snjl 1607132212Snjl if (dev == NULL) 1608132212Snjl h = ACPI_ROOT_OBJECT; 1609132212Snjl else if ((h = acpi_get_handle(dev)) == NULL) 1610131281Snjl return (AE_BAD_PARAMETER); 1611131281Snjl return (AcpiEvaluateObject(h, pathname, parameters, ret)); 1612131281Snjl} 1613131281Snjl 1614211430Sjhbint 1615138306Snjlacpi_device_pwr_for_sleep(device_t bus, device_t dev, int *dstate) 1616138306Snjl{ 1617138306Snjl struct acpi_softc *sc; 1618138306Snjl ACPI_HANDLE handle; 1619138306Snjl ACPI_STATUS status; 1620138306Snjl char sxd[8]; 1621138306Snjl 1622138306Snjl handle = acpi_get_handle(dev); 1623138306Snjl 1624138306Snjl /* 1625138306Snjl * XXX If we find these devices, don't try to power them down. 1626138306Snjl * The serial and IRDA ports on my T23 hang the system when 1627138306Snjl * set to D3 and it appears that such legacy devices may 1628138306Snjl * need special handling in their drivers. 1629138306Snjl */ 1630214072Sjkim if (dstate == NULL || handle == NULL || 1631138306Snjl acpi_MatchHid(handle, "PNP0500") || 1632138306Snjl acpi_MatchHid(handle, "PNP0501") || 1633138306Snjl acpi_MatchHid(handle, "PNP0502") || 1634138306Snjl acpi_MatchHid(handle, "PNP0510") || 1635138306Snjl acpi_MatchHid(handle, "PNP0511")) 1636138306Snjl return (ENXIO); 1637138306Snjl 1638138306Snjl /* 1639214072Sjkim * Override next state with the value from _SxD, if present. 1640214072Sjkim * Note illegal _S0D is evaluated because some systems expect this. 1641138306Snjl */ 1642214072Sjkim sc = device_get_softc(bus); 1643138306Snjl snprintf(sxd, sizeof(sxd), "_S%dD", sc->acpi_sstate); 1644214072Sjkim status = acpi_GetInteger(handle, sxd, dstate); 1645214072Sjkim if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { 1646214072Sjkim device_printf(dev, "failed to get %s on %s: %s\n", sxd, 1647214072Sjkim acpi_name(handle), AcpiFormatException(status)); 1648214072Sjkim return (ENXIO); 1649138306Snjl } 1650138306Snjl 1651214072Sjkim return (0); 1652138306Snjl} 1653138306Snjl 1654132212Snjl/* Callback arg for our implementation of walking the namespace. */ 1655132212Snjlstruct acpi_device_scan_ctx { 1656132212Snjl acpi_scan_cb_t user_fn; 1657132212Snjl void *arg; 1658132212Snjl ACPI_HANDLE parent; 1659132212Snjl}; 1660132212Snjl 1661131281Snjlstatic ACPI_STATUS 1662132212Snjlacpi_device_scan_cb(ACPI_HANDLE h, UINT32 level, void *arg, void **retval) 1663131281Snjl{ 1664132212Snjl struct acpi_device_scan_ctx *ctx; 1665132212Snjl device_t dev, old_dev; 1666132212Snjl ACPI_STATUS status; 1667132212Snjl ACPI_OBJECT_TYPE type; 1668132212Snjl 1669132212Snjl /* 1670132212Snjl * Skip this device if we think we'll have trouble with it or it is 1671132212Snjl * the parent where the scan began. 1672132212Snjl */ 1673132212Snjl ctx = (struct acpi_device_scan_ctx *)arg; 1674132212Snjl if (acpi_avoid(h) || h == ctx->parent) 1675132212Snjl return (AE_OK); 1676132212Snjl 1677132212Snjl /* If this is not a valid device type (e.g., a method), skip it. */ 1678132212Snjl if (ACPI_FAILURE(AcpiGetType(h, &type))) 1679132212Snjl return (AE_OK); 1680132212Snjl if (type != ACPI_TYPE_DEVICE && type != ACPI_TYPE_PROCESSOR && 1681132212Snjl type != ACPI_TYPE_THERMAL && type != ACPI_TYPE_POWER) 1682132212Snjl return (AE_OK); 1683132212Snjl 1684132212Snjl /* 1685132212Snjl * Call the user function with the current device. If it is unchanged 1686132212Snjl * afterwards, return. Otherwise, we update the handle to the new dev. 1687132212Snjl */ 1688132212Snjl old_dev = acpi_get_device(h); 1689132212Snjl dev = old_dev; 1690132212Snjl status = ctx->user_fn(h, &dev, level, ctx->arg); 1691132212Snjl if (ACPI_FAILURE(status) || old_dev == dev) 1692132212Snjl return (status); 1693132212Snjl 1694132212Snjl /* Remove the old child and its connection to the handle. */ 1695132212Snjl if (old_dev != NULL) { 1696132212Snjl device_delete_child(device_get_parent(old_dev), old_dev); 1697132212Snjl AcpiDetachData(h, acpi_fake_objhandler); 1698132212Snjl } 1699132212Snjl 1700132212Snjl /* Recreate the handle association if the user created a device. */ 1701132212Snjl if (dev != NULL) 1702132212Snjl AcpiAttachData(h, acpi_fake_objhandler, dev); 1703132212Snjl 1704132212Snjl return (AE_OK); 1705132212Snjl} 1706132212Snjl 1707132212Snjlstatic ACPI_STATUS 1708132212Snjlacpi_device_scan_children(device_t bus, device_t dev, int max_depth, 1709132212Snjl acpi_scan_cb_t user_fn, void *arg) 1710132212Snjl{ 1711131281Snjl ACPI_HANDLE h; 1712132212Snjl struct acpi_device_scan_ctx ctx; 1713131281Snjl 1714132212Snjl if (acpi_disabled("children")) 1715132212Snjl return (AE_OK); 1716132212Snjl 1717132212Snjl if (dev == NULL) 1718132212Snjl h = ACPI_ROOT_OBJECT; 1719132212Snjl else if ((h = acpi_get_handle(dev)) == NULL) 1720131281Snjl return (AE_BAD_PARAMETER); 1721132212Snjl ctx.user_fn = user_fn; 1722132212Snjl ctx.arg = arg; 1723132212Snjl ctx.parent = h; 1724132212Snjl return (AcpiWalkNamespace(ACPI_TYPE_ANY, h, max_depth, 1725199337Sjkim acpi_device_scan_cb, NULL, &ctx, NULL)); 1726131281Snjl} 1727131281Snjl 1728138306Snjl/* 1729138306Snjl * Even though ACPI devices are not PCI, we use the PCI approach for setting 1730138306Snjl * device power states since it's close enough to ACPI. 1731138306Snjl */ 173283180Smsmithstatic int 1733214072Sjkimacpi_set_powerstate(device_t child, int state) 1734138306Snjl{ 1735138306Snjl ACPI_HANDLE h; 1736138306Snjl ACPI_STATUS status; 1737138306Snjl 1738138306Snjl h = acpi_get_handle(child); 1739191695Sjkim if (state < ACPI_STATE_D0 || state > ACPI_D_STATES_MAX) 1740138306Snjl return (EINVAL); 1741138306Snjl if (h == NULL) 1742138306Snjl return (0); 1743138306Snjl 1744138306Snjl /* Ignore errors if the power methods aren't present. */ 1745138306Snjl status = acpi_pwr_switch_consumer(h, state); 1746214072Sjkim if (ACPI_SUCCESS(status)) { 1747214072Sjkim if (bootverbose) 1748214072Sjkim device_printf(child, "set ACPI power state D%d on %s\n", 1749214072Sjkim state, acpi_name(h)); 1750214072Sjkim } else if (status != AE_NOT_FOUND) 1751214072Sjkim device_printf(child, 1752214072Sjkim "failed to set ACPI power state D%d on %s: %s\n", state, 1753214072Sjkim acpi_name(h), AcpiFormatException(status)); 1754138306Snjl 1755214072Sjkim return (0); 1756138306Snjl} 1757138306Snjl 1758138306Snjlstatic int 175983180Smsmithacpi_isa_pnp_probe(device_t bus, device_t child, struct isa_pnp_id *ids) 176083180Smsmith{ 1761123619Snjl int result, cid_count, i; 1762123619Snjl uint32_t lid, cids[8]; 176382537Smsmith 176496926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 176582537Smsmith 176682537Smsmith /* 176782537Smsmith * ISA-style drivers attached to ACPI may persist and 176882537Smsmith * probe manually if we return ENOENT. We never want 176982537Smsmith * that to happen, so don't ever return it. 177082537Smsmith */ 177182537Smsmith result = ENXIO; 177282537Smsmith 1773119529Snjl /* Scan the supplied IDs for a match */ 1774111948Stakawata lid = acpi_isa_get_logicalid(child); 1775123619Snjl cid_count = acpi_isa_get_compatid(child, cids, 8); 177682537Smsmith while (ids && ids->ip_id) { 1777123619Snjl if (lid == ids->ip_id) { 177882537Smsmith result = 0; 177982537Smsmith goto out; 178082537Smsmith } 1781123619Snjl for (i = 0; i < cid_count; i++) { 1782123619Snjl if (cids[i] == ids->ip_id) { 1783123619Snjl result = 0; 1784123619Snjl goto out; 1785123619Snjl } 1786123619Snjl } 178782537Smsmith ids++; 178882537Smsmith } 1789119529Snjl 179082537Smsmith out: 1791136455Snjl if (result == 0 && ids->ip_desc) 1792136455Snjl device_set_desc(child, ids->ip_desc); 1793136455Snjl 1794123619Snjl return_VALUE (result); 179582537Smsmith} 179682537Smsmith 1797181987Sjhb#if defined(__i386__) || defined(__amd64__) 179882537Smsmith/* 1799181987Sjhb * Look for a MCFG table. If it is present, use the settings for 1800181987Sjhb * domain (segment) 0 to setup PCI config space access via the memory 1801181987Sjhb * map. 1802181987Sjhb */ 1803181987Sjhbstatic void 1804181987Sjhbacpi_enable_pcie(void) 1805181987Sjhb{ 1806181987Sjhb ACPI_TABLE_HEADER *hdr; 1807181987Sjhb ACPI_MCFG_ALLOCATION *alloc, *end; 1808181987Sjhb ACPI_STATUS status; 1809181987Sjhb 1810181987Sjhb status = AcpiGetTable(ACPI_SIG_MCFG, 1, &hdr); 1811181987Sjhb if (ACPI_FAILURE(status)) 1812181987Sjhb return; 1813181987Sjhb 1814181987Sjhb end = (ACPI_MCFG_ALLOCATION *)((char *)hdr + hdr->Length); 1815181987Sjhb alloc = (ACPI_MCFG_ALLOCATION *)((ACPI_TABLE_MCFG *)hdr + 1); 1816181987Sjhb while (alloc < end) { 1817181987Sjhb if (alloc->PciSegment == 0) { 1818181987Sjhb pcie_cfgregopen(alloc->Address, alloc->StartBusNumber, 1819181987Sjhb alloc->EndBusNumber); 1820181987Sjhb return; 1821181987Sjhb } 1822181987Sjhb alloc++; 1823181987Sjhb } 1824181987Sjhb} 1825181987Sjhb#endif 1826181987Sjhb 1827181987Sjhb/* 1828139900Snjl * Scan all of the ACPI namespace and attach child devices. 182967761Smsmith * 1830139900Snjl * We should only expect to find devices in the \_PR, \_TZ, \_SI, and 1831139900Snjl * \_SB scopes, and \_PR and \_TZ became obsolete in the ACPI 2.0 spec. 1832139900Snjl * However, in violation of the spec, some systems place their PCI link 1833139900Snjl * devices in \, so we have to walk the whole namespace. We check the 1834139900Snjl * type of namespace nodes, so this should be ok. 183567761Smsmith */ 183667761Smsmithstatic void 183767761Smsmithacpi_probe_children(device_t bus) 183867761Smsmith{ 183967761Smsmith 184096926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 184169744Smsmith 184267761Smsmith /* 184367761Smsmith * Scan the namespace and insert placeholders for all the devices that 1844132114Snjl * we find. We also probe/attach any early devices. 184567761Smsmith * 184667761Smsmith * Note that we use AcpiWalkNamespace rather than AcpiGetDevices because 1847119529Snjl * we want to create nodes for all devices, not just those that are 1848119529Snjl * currently present. (This assumes that we don't want to create/remove 1849119529Snjl * devices as they appear, which might be smarter.) 185067761Smsmith */ 185182372Smsmith ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "namespace scan\n")); 1852139900Snjl AcpiWalkNamespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, 100, acpi_probe_child, 1853199337Sjkim NULL, bus, NULL); 185467761Smsmith 1855134217Snjl /* Pre-allocate resources for our rman from any sysresource devices. */ 1856134217Snjl acpi_sysres_alloc(bus); 1857134217Snjl 1858216674Sjhb /* Reserve resources already allocated to children. */ 1859216674Sjhb acpi_reserve_resources(bus); 1860216674Sjhb 1861132114Snjl /* Create any static children by calling device identify methods. */ 1862132114Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "device identify routines\n")); 1863132114Snjl bus_generic_probe(bus); 1864132114Snjl 1865216488Sjhb /* Probe/attach all children, created statically and from the namespace. */ 1866203785Savg ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "acpi bus_generic_attach\n")); 186767761Smsmith bus_generic_attach(bus); 186867761Smsmith 1869129802Snjl /* Attach wake sysctls. */ 1870129803Snjl acpi_wake_sysctl_walk(bus); 1871129802Snjl 187282537Smsmith ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "done attaching children\n")); 187369744Smsmith return_VOID; 187467761Smsmith} 187567761Smsmith 1876130450Snjl/* 1877177985Sjhb * Determine the probe order for a given device. 1878130450Snjl */ 1879177985Sjhbstatic void 1880130450Snjlacpi_probe_order(ACPI_HANDLE handle, int *order) 1881130439Snjl{ 1882231161Sjkim ACPI_OBJECT_TYPE type; 1883130439Snjl 1884231161Sjkim /* 1885231161Sjkim * 0. CPUs 1886231161Sjkim * 1. I/O port and memory system resource holders 1887231161Sjkim * 2. Clocks and timers (to handle early accesses) 1888231161Sjkim * 3. Embedded controllers (to handle early accesses) 1889231161Sjkim * 4. PCI Link Devices 1890231161Sjkim */ 1891231161Sjkim AcpiGetType(handle, &type); 1892231161Sjkim if (type == ACPI_TYPE_PROCESSOR) 1893231161Sjkim *order = 0; 1894231161Sjkim else if (acpi_MatchHid(handle, "PNP0C01") || 1895231161Sjkim acpi_MatchHid(handle, "PNP0C02")) 1896231161Sjkim *order = 1; 1897231161Sjkim else if (acpi_MatchHid(handle, "PNP0100") || 1898231161Sjkim acpi_MatchHid(handle, "PNP0103") || 1899231161Sjkim acpi_MatchHid(handle, "PNP0B00")) 1900231161Sjkim *order = 2; 1901231161Sjkim else if (acpi_MatchHid(handle, "PNP0C09")) 1902231161Sjkim *order = 3; 1903231161Sjkim else if (acpi_MatchHid(handle, "PNP0C0F")) 1904231161Sjkim *order = 4; 1905130439Snjl} 1906130439Snjl 190767761Smsmith/* 190867761Smsmith * Evaluate a child device and determine whether we might attach a device to 190967761Smsmith * it. 191067761Smsmith */ 191167761Smsmithstatic ACPI_STATUS 191267761Smsmithacpi_probe_child(ACPI_HANDLE handle, UINT32 level, void *context, void **status) 191367761Smsmith{ 1914216471Sjkim struct acpi_prw_data prw; 1915139900Snjl ACPI_OBJECT_TYPE type; 1916157774Siwasaki ACPI_HANDLE h; 1917139900Snjl device_t bus, child; 1918214765Sjkim char *handle_str; 1919235834Sjhb int order; 192067761Smsmith 192196926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 192269744Smsmith 1923214765Sjkim if (acpi_disabled("children")) 1924214765Sjkim return_ACPI_STATUS (AE_OK); 1925214765Sjkim 1926119529Snjl /* Skip this device if we think we'll have trouble with it. */ 192769744Smsmith if (acpi_avoid(handle)) 1928119529Snjl return_ACPI_STATUS (AE_OK); 192969744Smsmith 1930130439Snjl bus = (device_t)context; 193191120Smsmith if (ACPI_SUCCESS(AcpiGetType(handle, &type))) { 1932214765Sjkim handle_str = acpi_name(handle); 1933131281Snjl switch (type) { 193467761Smsmith case ACPI_TYPE_DEVICE: 1935139900Snjl /* 1936139900Snjl * Since we scan from \, be sure to skip system scope objects. 1937214765Sjkim * \_SB_ and \_TZ_ are defined in ACPICA as devices to work around 1938214998Sjkim * BIOS bugs. For example, \_SB_ is to allow \_SB_._INI to be run 1939214765Sjkim * during the intialization and \_TZ_ is to support Notify() on it. 1940139900Snjl */ 1941214765Sjkim if (strcmp(handle_str, "\\_SB_") == 0 || 1942214765Sjkim strcmp(handle_str, "\\_TZ_") == 0) 1943139900Snjl break; 1944216471Sjkim if (acpi_parse_prw(handle, &prw) == 0) 1945216471Sjkim AcpiSetupGpeForWake(handle, prw.gpe_handle, prw.gpe_bit); 1946223207Sjhb 1947223207Sjhb /* 1948223207Sjhb * Ignore devices that do not have a _HID or _CID. They should 1949223207Sjhb * be discovered by other buses (e.g. the PCI bus driver). 1950223207Sjhb */ 1951223207Sjhb if (!acpi_has_hid(handle)) 1952223207Sjhb break; 1953214765Sjkim /* FALLTHROUGH */ 1954214765Sjkim case ACPI_TYPE_PROCESSOR: 1955214765Sjkim case ACPI_TYPE_THERMAL: 1956214765Sjkim case ACPI_TYPE_POWER: 195767761Smsmith /* 1958177041Sjhb * Create a placeholder device for this node. Sort the 1959177041Sjhb * placeholder so that the probe/attach passes will run 1960177041Sjhb * breadth-first. Orders less than ACPI_DEV_BASE_ORDER 1961177041Sjhb * are reserved for special objects (i.e., system 1962212172Savg * resources). 196367761Smsmith */ 1964139900Snjl ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "scanning '%s'\n", handle_str)); 1965231161Sjkim order = level * 10 + ACPI_DEV_BASE_ORDER; 1966158346Snjl acpi_probe_order(handle, &order); 1967235834Sjhb child = BUS_ADD_CHILD(bus, order, NULL, -1); 196882537Smsmith if (child == NULL) 196982537Smsmith break; 1970130417Snjl 1971130417Snjl /* Associate the handle with the device_t and vice versa. */ 197267761Smsmith acpi_set_handle(child, handle); 1973130417Snjl AcpiAttachData(handle, acpi_fake_objhandler, child); 197482537Smsmith 197582537Smsmith /* 197683491Smsmith * Check that the device is present. If it's not present, 197783491Smsmith * leave it disabled (so that we have a device_t attached to 197883491Smsmith * the handle, but we don't probe it). 1979151566Snjl * 1980151566Snjl * XXX PCI link devices sometimes report "present" but not 1981151566Snjl * "functional" (i.e. if disabled). Go ahead and probe them 1982151566Snjl * anyway since we may enable them later. 198383491Smsmith */ 1984157774Siwasaki if (type == ACPI_TYPE_DEVICE && !acpi_DeviceIsPresent(child)) { 1985157774Siwasaki /* Never disable PCI link devices. */ 1986157774Siwasaki if (acpi_MatchHid(handle, "PNP0C0F")) 1987157774Siwasaki break; 1988157774Siwasaki /* 1989157774Siwasaki * Docking stations should remain enabled since the system 1990157774Siwasaki * may be undocked at boot. 1991157774Siwasaki */ 1992157774Siwasaki if (ACPI_SUCCESS(AcpiGetHandle(handle, "_DCK", &h))) 1993157774Siwasaki break; 1994157774Siwasaki 199583491Smsmith device_disable(child); 199683491Smsmith break; 199783491Smsmith } 199883491Smsmith 199983491Smsmith /* 200082537Smsmith * Get the device's resource settings and attach them. 200182537Smsmith * Note that if the device has _PRS but no _CRS, we need 200282537Smsmith * to decide when it's appropriate to try to configure the 200382537Smsmith * device. Ignore the return value here; it's OK for the 200482537Smsmith * device not to have any resources. 200582537Smsmith */ 2006127679Snjl acpi_parse_resources(child, handle, &acpi_res_parse_set, NULL); 200769744Smsmith break; 200867761Smsmith } 200967761Smsmith } 2010119529Snjl 2011119529Snjl return_ACPI_STATUS (AE_OK); 201267761Smsmith} 201367761Smsmith 2014130417Snjl/* 2015130417Snjl * AcpiAttachData() requires an object handler but never uses it. This is a 2016130417Snjl * placeholder object handler so we can store a device_t in an ACPI_HANDLE. 2017130417Snjl */ 2018130417Snjlvoid 2019197105Sjkimacpi_fake_objhandler(ACPI_HANDLE h, void *data) 2020130417Snjl{ 2021130417Snjl} 2022130417Snjl 202367761Smsmithstatic void 202467761Smsmithacpi_shutdown_final(void *arg, int howto) 202567761Smsmith{ 2026191696Sjkim struct acpi_softc *sc = (struct acpi_softc *)arg; 2027233579Sjkim register_t intr; 2028159524Snjl ACPI_STATUS status; 202978991Smsmith 2030127193Snjl /* 2031131004Snjl * XXX Shutdown code should only run on the BSP (cpuid 0). 2032131004Snjl * Some chipsets do not power off the system correctly if called from 2033131004Snjl * an AP. 2034127193Snjl */ 2035119529Snjl if ((howto & RB_POWEROFF) != 0) { 2036128655Snjl status = AcpiEnterSleepStatePrep(ACPI_STATE_S5); 2037128655Snjl if (ACPI_FAILURE(status)) { 2038191696Sjkim device_printf(sc->acpi_dev, "AcpiEnterSleepStatePrep failed - %s\n", 2039191696Sjkim AcpiFormatException(status)); 2040128655Snjl return; 2041128655Snjl } 2042191696Sjkim device_printf(sc->acpi_dev, "Powering system off\n"); 2043233579Sjkim intr = intr_disable(); 2044239340Sjkim status = AcpiEnterSleepState(ACPI_STATE_S5); 2045233579Sjkim if (ACPI_FAILURE(status)) { 2046233579Sjkim intr_restore(intr); 2047191696Sjkim device_printf(sc->acpi_dev, "power-off failed - %s\n", 2048191696Sjkim AcpiFormatException(status)); 2049233579Sjkim } else { 2050131004Snjl DELAY(1000000); 2051233579Sjkim intr_restore(intr); 2052191696Sjkim device_printf(sc->acpi_dev, "power-off failed - timeout\n"); 2053131004Snjl } 2054213755Sjkim } else if ((howto & RB_HALT) == 0 && sc->acpi_handle_reboot) { 2055159524Snjl /* Reboot using the reset register. */ 2056213755Sjkim status = AcpiReset(); 2057213755Sjkim if (ACPI_SUCCESS(status)) { 2058213755Sjkim DELAY(1000000); 2059213755Sjkim device_printf(sc->acpi_dev, "reset failed - timeout\n"); 2060213755Sjkim } else if (status != AE_NOT_EXIST) 2061191696Sjkim device_printf(sc->acpi_dev, "reset failed - %s\n", 2062191696Sjkim AcpiFormatException(status)); 2063159524Snjl } else if (sc->acpi_do_disable && panicstr == NULL) { 2064159524Snjl /* 2065159524Snjl * Only disable ACPI if the user requested. On some systems, writing 2066159524Snjl * the disable value to SMI_CMD hangs the system. 2067159524Snjl */ 2068191696Sjkim device_printf(sc->acpi_dev, "Shutting down\n"); 206996947Siwasaki AcpiTerminate(); 207067761Smsmith } 207167761Smsmith} 207267761Smsmith 207370897Siwasakistatic void 207470897Siwasakiacpi_enable_fixed_events(struct acpi_softc *sc) 207570897Siwasaki{ 207678991Smsmith static int first_time = 1; 207770897Siwasaki 207878991Smsmith /* Enable and clear fixed events and install handlers. */ 2079167814Sjkim if ((AcpiGbl_FADT.Flags & ACPI_FADT_POWER_BUTTON) == 0) { 2080118924Snjl AcpiClearEvent(ACPI_EVENT_POWER_BUTTON); 208178991Smsmith AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON, 2082125679Snjl acpi_event_power_button_sleep, sc); 2083119529Snjl if (first_time) 2084120186Snjl device_printf(sc->acpi_dev, "Power Button (fixed)\n"); 208578991Smsmith } 2086167814Sjkim if ((AcpiGbl_FADT.Flags & ACPI_FADT_SLEEP_BUTTON) == 0) { 2087118924Snjl AcpiClearEvent(ACPI_EVENT_SLEEP_BUTTON); 208878991Smsmith AcpiInstallFixedEventHandler(ACPI_EVENT_SLEEP_BUTTON, 2089125679Snjl acpi_event_sleep_button_sleep, sc); 2090119529Snjl if (first_time) 2091120186Snjl device_printf(sc->acpi_dev, "Sleep Button (fixed)\n"); 209278991Smsmith } 209370897Siwasaki 209478991Smsmith first_time = 0; 209570897Siwasaki} 209670897Siwasaki 209767761Smsmith/* 209878915Smsmith * Returns true if the device is actually present and should 209978915Smsmith * be attached to. This requires the present, enabled, UI-visible 210078915Smsmith * and diagnostics-passed bits to be set. 210178915Smsmith */ 210278915SmsmithBOOLEAN 210378915Smsmithacpi_DeviceIsPresent(device_t dev) 210478915Smsmith{ 2105123619Snjl ACPI_DEVICE_INFO *devinfo; 210678915Smsmith ACPI_HANDLE h; 2107197105Sjkim BOOLEAN present; 210878991Smsmith 2109197105Sjkim if ((h = acpi_get_handle(dev)) == NULL || 2110197105Sjkim ACPI_FAILURE(AcpiGetObjectInfo(h, &devinfo))) 2111119529Snjl return (FALSE); 2112119529Snjl 2113119529Snjl /* If no _STA method, must be present */ 2114197105Sjkim present = (devinfo->Valid & ACPI_VALID_STA) == 0 || 2115197105Sjkim ACPI_DEVICE_PRESENT(devinfo->CurrentStatus) ? TRUE : FALSE; 2116119529Snjl 2117197105Sjkim AcpiOsFree(devinfo); 2118197105Sjkim return (present); 211978915Smsmith} 212078915Smsmith 212178915Smsmith/* 212291120Smsmith * Returns true if the battery is actually present and inserted. 212391120Smsmith */ 212491120SmsmithBOOLEAN 212591120Smsmithacpi_BatteryIsPresent(device_t dev) 212691120Smsmith{ 2127123619Snjl ACPI_DEVICE_INFO *devinfo; 212891120Smsmith ACPI_HANDLE h; 2129197105Sjkim BOOLEAN present; 213091120Smsmith 2131197105Sjkim if ((h = acpi_get_handle(dev)) == NULL || 2132197105Sjkim ACPI_FAILURE(AcpiGetObjectInfo(h, &devinfo))) 2133119529Snjl return (FALSE); 2134119529Snjl 2135119529Snjl /* If no _STA method, must be present */ 2136197105Sjkim present = (devinfo->Valid & ACPI_VALID_STA) == 0 || 2137197105Sjkim ACPI_BATTERY_PRESENT(devinfo->CurrentStatus) ? TRUE : FALSE; 2138119529Snjl 2139197105Sjkim AcpiOsFree(devinfo); 2140197105Sjkim return (present); 214191120Smsmith} 214291120Smsmith 214391120Smsmith/* 2144223207Sjhb * Returns true if a device has at least one valid device ID. 2145223207Sjhb */ 2146223207Sjhbstatic BOOLEAN 2147223207Sjhbacpi_has_hid(ACPI_HANDLE h) 2148223207Sjhb{ 2149223207Sjhb ACPI_DEVICE_INFO *devinfo; 2150223207Sjhb BOOLEAN ret; 2151223207Sjhb 2152223207Sjhb if (h == NULL || 2153223207Sjhb ACPI_FAILURE(AcpiGetObjectInfo(h, &devinfo))) 2154223207Sjhb return (FALSE); 2155223207Sjhb 2156223207Sjhb ret = FALSE; 2157223207Sjhb if ((devinfo->Valid & ACPI_VALID_HID) != 0) 2158223207Sjhb ret = TRUE; 2159223207Sjhb else if ((devinfo->Valid & ACPI_VALID_CID) != 0) 2160223207Sjhb if (devinfo->CompatibleIdList.Count > 0) 2161223207Sjhb ret = TRUE; 2162223207Sjhb 2163223207Sjhb AcpiOsFree(devinfo); 2164223207Sjhb return (ret); 2165223207Sjhb} 2166223207Sjhb 2167223207Sjhb/* 2168130439Snjl * Match a HID string against a handle 216967761Smsmith */ 2170208436SmavBOOLEAN 2171131281Snjlacpi_MatchHid(ACPI_HANDLE h, const char *hid) 217267761Smsmith{ 2173123619Snjl ACPI_DEVICE_INFO *devinfo; 2174197105Sjkim BOOLEAN ret; 2175197105Sjkim int i; 217669744Smsmith 2177197105Sjkim if (hid == NULL || h == NULL || 2178197105Sjkim ACPI_FAILURE(AcpiGetObjectInfo(h, &devinfo))) 2179197105Sjkim return (FALSE); 2180197105Sjkim 2181123619Snjl ret = FALSE; 2182123867Sjhb if ((devinfo->Valid & ACPI_VALID_HID) != 0 && 2183197105Sjkim strcmp(hid, devinfo->HardwareId.String) == 0) 2184123619Snjl ret = TRUE; 2185197105Sjkim else if ((devinfo->Valid & ACPI_VALID_CID) != 0) 2186197105Sjkim for (i = 0; i < devinfo->CompatibleIdList.Count; i++) { 2187197105Sjkim if (strcmp(hid, devinfo->CompatibleIdList.Ids[i].String) == 0) { 2188123619Snjl ret = TRUE; 2189123619Snjl break; 2190123619Snjl } 2191123619Snjl } 2192119529Snjl 2193197105Sjkim AcpiOsFree(devinfo); 2194123619Snjl return (ret); 219567761Smsmith} 219667761Smsmith 219767761Smsmith/* 219878915Smsmith * Return the handle of a named object within our scope, ie. that of (parent) 219978915Smsmith * or one if its parents. 220078915Smsmith */ 220178915SmsmithACPI_STATUS 220278915Smsmithacpi_GetHandleInScope(ACPI_HANDLE parent, char *path, ACPI_HANDLE *result) 220378915Smsmith{ 220478915Smsmith ACPI_HANDLE r; 220578915Smsmith ACPI_STATUS status; 220678915Smsmith 2207119529Snjl /* Walk back up the tree to the root */ 220878915Smsmith for (;;) { 2209119529Snjl status = AcpiGetHandle(parent, path, &r); 2210119529Snjl if (ACPI_SUCCESS(status)) { 221178915Smsmith *result = r; 2212119529Snjl return (AE_OK); 221378915Smsmith } 2214133051Snjl /* XXX Return error here? */ 221578915Smsmith if (status != AE_NOT_FOUND) 2216119529Snjl return (AE_OK); 221791120Smsmith if (ACPI_FAILURE(AcpiGetParent(parent, &r))) 2218119529Snjl return (AE_NOT_FOUND); 221978915Smsmith parent = r; 222078915Smsmith } 222178915Smsmith} 222278915Smsmith 222378915Smsmith/* 222478915Smsmith * Allocate a buffer with a preset data size. 222578915Smsmith */ 222678915SmsmithACPI_BUFFER * 222778915Smsmithacpi_AllocBuffer(int size) 222878915Smsmith{ 222978915Smsmith ACPI_BUFFER *buf; 223078915Smsmith 223178915Smsmith if ((buf = malloc(size + sizeof(*buf), M_ACPIDEV, M_NOWAIT)) == NULL) 2232119529Snjl return (NULL); 223378915Smsmith buf->Length = size; 223478915Smsmith buf->Pointer = (void *)(buf + 1); 2235119529Snjl return (buf); 223678915Smsmith} 223778915Smsmith 2238126560SnjlACPI_STATUS 2239126766Snjlacpi_SetInteger(ACPI_HANDLE handle, char *path, UINT32 number) 2240126560Snjl{ 2241126560Snjl ACPI_OBJECT arg1; 2242126560Snjl ACPI_OBJECT_LIST args; 2243126560Snjl 2244126560Snjl arg1.Type = ACPI_TYPE_INTEGER; 2245126560Snjl arg1.Integer.Value = number; 2246126560Snjl args.Count = 1; 2247126560Snjl args.Pointer = &arg1; 2248126560Snjl 2249126560Snjl return (AcpiEvaluateObject(handle, path, &args, NULL)); 2250126560Snjl} 2251126560Snjl 225278915Smsmith/* 225378915Smsmith * Evaluate a path that should return an integer. 225478915Smsmith */ 225578915SmsmithACPI_STATUS 2256126766Snjlacpi_GetInteger(ACPI_HANDLE handle, char *path, UINT32 *number) 225778915Smsmith{ 2258119529Snjl ACPI_STATUS status; 225978915Smsmith ACPI_BUFFER buf; 226088420Siwasaki ACPI_OBJECT param; 226178915Smsmith 226278915Smsmith if (handle == NULL) 226378915Smsmith handle = ACPI_ROOT_OBJECT; 226483169Sjhb 226583169Sjhb /* 226683169Sjhb * Assume that what we've been pointed at is an Integer object, or 226783169Sjhb * a method that will return an Integer. 226883169Sjhb */ 226978915Smsmith buf.Pointer = ¶m; 227078915Smsmith buf.Length = sizeof(param); 2271119529Snjl status = AcpiEvaluateObject(handle, path, NULL, &buf); 2272119529Snjl if (ACPI_SUCCESS(status)) { 2273119529Snjl if (param.Type == ACPI_TYPE_INTEGER) 227478915Smsmith *number = param.Integer.Value; 2275119529Snjl else 2276119529Snjl status = AE_TYPE; 227778915Smsmith } 227883169Sjhb 227983169Sjhb /* 228083169Sjhb * In some applications, a method that's expected to return an Integer 228183169Sjhb * may instead return a Buffer (probably to simplify some internal 228283169Sjhb * arithmetic). We'll try to fetch whatever it is, and if it's a Buffer, 228383169Sjhb * convert it into an Integer as best we can. 228483169Sjhb * 228583169Sjhb * This is a hack. 228683169Sjhb */ 2287119529Snjl if (status == AE_BUFFER_OVERFLOW) { 228891120Smsmith if ((buf.Pointer = AcpiOsAllocate(buf.Length)) == NULL) { 2289119529Snjl status = AE_NO_MEMORY; 229083169Sjhb } else { 2291119529Snjl status = AcpiEvaluateObject(handle, path, NULL, &buf); 2292119529Snjl if (ACPI_SUCCESS(status)) 2293119529Snjl status = acpi_ConvertBufferToInteger(&buf, number); 2294119739Snjl AcpiOsFree(buf.Pointer); 229583169Sjhb } 229683169Sjhb } 2297119529Snjl return (status); 229878915Smsmith} 229978915Smsmith 230088420SiwasakiACPI_STATUS 2301126766Snjlacpi_ConvertBufferToInteger(ACPI_BUFFER *bufp, UINT32 *number) 230288420Siwasaki{ 230388420Siwasaki ACPI_OBJECT *p; 2304126767Snjl UINT8 *val; 230588420Siwasaki int i; 230688420Siwasaki 230788420Siwasaki p = (ACPI_OBJECT *)bufp->Pointer; 230888420Siwasaki if (p->Type == ACPI_TYPE_INTEGER) { 230988420Siwasaki *number = p->Integer.Value; 2310119529Snjl return (AE_OK); 231188420Siwasaki } 231288420Siwasaki if (p->Type != ACPI_TYPE_BUFFER) 2313119529Snjl return (AE_TYPE); 231488420Siwasaki if (p->Buffer.Length > sizeof(int)) 2315119529Snjl return (AE_BAD_DATA); 2316119529Snjl 231788420Siwasaki *number = 0; 2318126767Snjl val = p->Buffer.Pointer; 231988420Siwasaki for (i = 0; i < p->Buffer.Length; i++) 2320126767Snjl *number += val[i] << (i * 8); 2321119529Snjl return (AE_OK); 232288420Siwasaki} 232388420Siwasaki 232478915Smsmith/* 232578915Smsmith * Iterate over the elements of an a package object, calling the supplied 232678915Smsmith * function for each element. 232778915Smsmith * 232878915Smsmith * XXX possible enhancement might be to abort traversal on error. 232978915Smsmith */ 233078915SmsmithACPI_STATUS 2331119529Snjlacpi_ForeachPackageObject(ACPI_OBJECT *pkg, 2332119529Snjl void (*func)(ACPI_OBJECT *comp, void *arg), void *arg) 233378915Smsmith{ 233478915Smsmith ACPI_OBJECT *comp; 233578915Smsmith int i; 2336133933Snjl 2337119529Snjl if (pkg == NULL || pkg->Type != ACPI_TYPE_PACKAGE) 2338119529Snjl return (AE_BAD_PARAMETER); 233978915Smsmith 2340119529Snjl /* Iterate over components */ 2341119529Snjl i = 0; 2342119529Snjl comp = pkg->Package.Elements; 2343119529Snjl for (; i < pkg->Package.Count; i++, comp++) 234478915Smsmith func(comp, arg); 234578915Smsmith 2346119529Snjl return (AE_OK); 234778915Smsmith} 234878915Smsmith 234979282Smsmith/* 235079282Smsmith * Find the (index)th resource object in a set. 235179282Smsmith */ 235279282SmsmithACPI_STATUS 235380604Smsmithacpi_FindIndexedResource(ACPI_BUFFER *buf, int index, ACPI_RESOURCE **resp) 235479282Smsmith{ 235580604Smsmith ACPI_RESOURCE *rp; 235679282Smsmith int i; 235778915Smsmith 235880604Smsmith rp = (ACPI_RESOURCE *)buf->Pointer; 235979282Smsmith i = index; 236080604Smsmith while (i-- > 0) { 2361139339Snjl /* Range check */ 236280604Smsmith if (rp > (ACPI_RESOURCE *)((u_int8_t *)buf->Pointer + buf->Length)) 2363119529Snjl return (AE_BAD_PARAMETER); 2364119529Snjl 2365119529Snjl /* Check for terminator */ 2366151948Sjkim if (rp->Type == ACPI_RESOURCE_TYPE_END_TAG || rp->Length == 0) 2367119529Snjl return (AE_NOT_FOUND); 2368126015Snjl rp = ACPI_NEXT_RESOURCE(rp); 236979282Smsmith } 237079282Smsmith if (resp != NULL) 237180604Smsmith *resp = rp; 2372119529Snjl 2373119529Snjl return (AE_OK); 237479282Smsmith} 237579282Smsmith 237680604Smsmith/* 237780604Smsmith * Append an ACPI_RESOURCE to an ACPI_BUFFER. 237880604Smsmith * 237980604Smsmith * Given a pointer to an ACPI_RESOURCE structure, expand the ACPI_BUFFER 238080604Smsmith * provided to contain it. If the ACPI_BUFFER is empty, allocate a sensible 238180604Smsmith * backing block. If the ACPI_RESOURCE is NULL, return an empty set of 238280604Smsmith * resources. 238380604Smsmith */ 238480604Smsmith#define ACPI_INITIAL_RESOURCE_BUFFER_SIZE 512 238580604Smsmith 238680604SmsmithACPI_STATUS 238780604Smsmithacpi_AppendBufferResource(ACPI_BUFFER *buf, ACPI_RESOURCE *res) 238880604Smsmith{ 238980604Smsmith ACPI_RESOURCE *rp; 239080604Smsmith void *newp; 2391133933Snjl 2392119529Snjl /* Initialise the buffer if necessary. */ 239380604Smsmith if (buf->Pointer == NULL) { 239480604Smsmith buf->Length = ACPI_INITIAL_RESOURCE_BUFFER_SIZE; 239580604Smsmith if ((buf->Pointer = AcpiOsAllocate(buf->Length)) == NULL) 2396119529Snjl return (AE_NO_MEMORY); 239780604Smsmith rp = (ACPI_RESOURCE *)buf->Pointer; 2398151948Sjkim rp->Type = ACPI_RESOURCE_TYPE_END_TAG; 2399249767Sjhb rp->Length = ACPI_RS_SIZE_MIN; 240080604Smsmith } 240180604Smsmith if (res == NULL) 2402119529Snjl return (AE_OK); 2403133933Snjl 240480604Smsmith /* 240580604Smsmith * Scan the current buffer looking for the terminator. 240680604Smsmith * This will either find the terminator or hit the end 240780604Smsmith * of the buffer and return an error. 240880604Smsmith */ 240980604Smsmith rp = (ACPI_RESOURCE *)buf->Pointer; 241080604Smsmith for (;;) { 2411119529Snjl /* Range check, don't go outside the buffer */ 241280604Smsmith if (rp >= (ACPI_RESOURCE *)((u_int8_t *)buf->Pointer + buf->Length)) 2413119529Snjl return (AE_BAD_PARAMETER); 2414151948Sjkim if (rp->Type == ACPI_RESOURCE_TYPE_END_TAG || rp->Length == 0) 241580604Smsmith break; 2416126015Snjl rp = ACPI_NEXT_RESOURCE(rp); 241780604Smsmith } 241880604Smsmith 241980604Smsmith /* 242080604Smsmith * Check the size of the buffer and expand if required. 242180604Smsmith * 242280604Smsmith * Required size is: 242380604Smsmith * size of existing resources before terminator + 242480604Smsmith * size of new resource and header + 242580604Smsmith * size of terminator. 242680604Smsmith * 242780604Smsmith * Note that this loop should really only run once, unless 242880604Smsmith * for some reason we are stuffing a *really* huge resource. 242980604Smsmith */ 243080604Smsmith while ((((u_int8_t *)rp - (u_int8_t *)buf->Pointer) + 2431151948Sjkim res->Length + ACPI_RS_SIZE_NO_DATA + 2432151948Sjkim ACPI_RS_SIZE_MIN) >= buf->Length) { 243380604Smsmith if ((newp = AcpiOsAllocate(buf->Length * 2)) == NULL) 2434119529Snjl return (AE_NO_MEMORY); 243580604Smsmith bcopy(buf->Pointer, newp, buf->Length); 2436119529Snjl rp = (ACPI_RESOURCE *)((u_int8_t *)newp + 243781092Smsmith ((u_int8_t *)rp - (u_int8_t *)buf->Pointer)); 243880604Smsmith AcpiOsFree(buf->Pointer); 243980604Smsmith buf->Pointer = newp; 244080604Smsmith buf->Length += buf->Length; 244180604Smsmith } 2442133933Snjl 2443119529Snjl /* Insert the new resource. */ 2444151948Sjkim bcopy(res, rp, res->Length + ACPI_RS_SIZE_NO_DATA); 2445133933Snjl 2446119529Snjl /* And add the terminator. */ 2447126015Snjl rp = ACPI_NEXT_RESOURCE(rp); 2448151948Sjkim rp->Type = ACPI_RESOURCE_TYPE_END_TAG; 2449249767Sjhb rp->Length = ACPI_RS_SIZE_MIN; 245080604Smsmith 2451119529Snjl return (AE_OK); 245280604Smsmith} 245380604Smsmith 2454303229SjhbACPI_STATUS 2455303229Sjhbacpi_EvaluateOSC(ACPI_HANDLE handle, uint8_t *uuid, int revision, int count, 2456303229Sjhb uint32_t *caps_in, uint32_t *caps_out, bool query) 2457303229Sjhb{ 2458303229Sjhb ACPI_OBJECT arg[4], *ret; 2459303229Sjhb ACPI_OBJECT_LIST arglist; 2460303229Sjhb ACPI_BUFFER buf; 2461303229Sjhb ACPI_STATUS status; 2462303229Sjhb 2463303229Sjhb arglist.Pointer = arg; 2464303229Sjhb arglist.Count = 4; 2465303229Sjhb arg[0].Type = ACPI_TYPE_BUFFER; 2466303229Sjhb arg[0].Buffer.Length = ACPI_UUID_LENGTH; 2467303229Sjhb arg[0].Buffer.Pointer = uuid; 2468303229Sjhb arg[1].Type = ACPI_TYPE_INTEGER; 2469303229Sjhb arg[1].Integer.Value = revision; 2470303229Sjhb arg[2].Type = ACPI_TYPE_INTEGER; 2471303229Sjhb arg[2].Integer.Value = count; 2472303229Sjhb arg[3].Type = ACPI_TYPE_BUFFER; 2473303229Sjhb arg[3].Buffer.Length = count * sizeof(*caps_in); 2474303229Sjhb arg[3].Buffer.Pointer = (uint8_t *)caps_in; 2475303229Sjhb caps_in[0] = query ? 1 : 0; 2476303229Sjhb buf.Pointer = NULL; 2477303229Sjhb buf.Length = ACPI_ALLOCATE_BUFFER; 2478303229Sjhb status = AcpiEvaluateObjectTyped(handle, "_OSC", &arglist, &buf, 2479303229Sjhb ACPI_TYPE_BUFFER); 2480303229Sjhb if (ACPI_FAILURE(status)) 2481303229Sjhb return (status); 2482303229Sjhb if (caps_out != NULL) { 2483303229Sjhb ret = buf.Pointer; 2484303229Sjhb if (ret->Buffer.Length != count * sizeof(*caps_out)) { 2485303229Sjhb AcpiOsFree(buf.Pointer); 2486303229Sjhb return (AE_BUFFER_OVERFLOW); 2487303229Sjhb } 2488303229Sjhb bcopy(ret->Buffer.Pointer, caps_out, ret->Buffer.Length); 2489303229Sjhb } 2490303229Sjhb AcpiOsFree(buf.Pointer); 2491303229Sjhb return (status); 2492303229Sjhb} 2493303229Sjhb 2494103015Sjhb/* 2495103015Sjhb * Set interrupt model. 2496103015Sjhb */ 2497103015SjhbACPI_STATUS 2498103015Sjhbacpi_SetIntrModel(int model) 2499103015Sjhb{ 2500103015Sjhb 2501126560Snjl return (acpi_SetInteger(ACPI_ROOT_OBJECT, "_PIC", model)); 2502103015Sjhb} 2503103015Sjhb 2504170976Snjl/* 2505197439Sjhb * Walk subtables of a table and call a callback routine for each 2506197439Sjhb * subtable. The caller should provide the first subtable and a 2507197439Sjhb * pointer to the end of the table. This can be used to walk tables 2508197439Sjhb * such as MADT and SRAT that use subtable entries. 2509197439Sjhb */ 2510197439Sjhbvoid 2511197439Sjhbacpi_walk_subtables(void *first, void *end, acpi_subtable_handler *handler, 2512197439Sjhb void *arg) 2513197439Sjhb{ 2514197439Sjhb ACPI_SUBTABLE_HEADER *entry; 2515197439Sjhb 2516197439Sjhb for (entry = first; (void *)entry < end; ) { 2517197439Sjhb /* Avoid an infinite loop if we hit a bogus entry. */ 2518197439Sjhb if (entry->Length < sizeof(ACPI_SUBTABLE_HEADER)) 2519197439Sjhb return; 2520197439Sjhb 2521197439Sjhb handler(entry, arg); 2522197439Sjhb entry = ACPI_ADD_PTR(ACPI_SUBTABLE_HEADER, entry, entry->Length); 2523197439Sjhb } 2524197439Sjhb} 2525197439Sjhb 2526197439Sjhb/* 2527170976Snjl * DEPRECATED. This interface has serious deficiencies and will be 2528170976Snjl * removed. 2529170976Snjl * 2530170976Snjl * Immediately enter the sleep state. In the old model, acpiconf(8) ran 2531170976Snjl * rc.suspend and rc.resume so we don't have to notify devd(8) to do this. 2532170976Snjl */ 2533170976SnjlACPI_STATUS 2534170976Snjlacpi_SetSleepState(struct acpi_softc *sc, int state) 2535170976Snjl{ 2536170976Snjl static int once; 2537170976Snjl 2538170976Snjl if (!once) { 2539191696Sjkim device_printf(sc->acpi_dev, 2540170976Snjl"warning: acpi_SetSleepState() deprecated, need to update your software\n"); 2541170976Snjl once = 1; 2542170976Snjl } 2543170976Snjl return (acpi_EnterSleepState(sc, state)); 2544170976Snjl} 2545170976Snjl 2546189903Sjkim#if defined(__amd64__) || defined(__i386__) 254787566Siwasakistatic void 2548236220Siwasakiacpi_sleep_force_task(void *context) 2549236220Siwasaki{ 2550236220Siwasaki struct acpi_softc *sc = (struct acpi_softc *)context; 2551236220Siwasaki 2552236220Siwasaki if (ACPI_FAILURE(acpi_EnterSleepState(sc, sc->acpi_next_sstate))) 2553236220Siwasaki device_printf(sc->acpi_dev, "force sleep state S%d failed\n", 2554236220Siwasaki sc->acpi_next_sstate); 2555236220Siwasaki} 2556236220Siwasaki 2557236220Siwasakistatic void 2558170976Snjlacpi_sleep_force(void *arg) 2559170976Snjl{ 2560191696Sjkim struct acpi_softc *sc = (struct acpi_softc *)arg; 2561170976Snjl 2562191696Sjkim device_printf(sc->acpi_dev, 2563191696Sjkim "suspend request timed out, forcing sleep now\n"); 2564236220Siwasaki /* 2565236220Siwasaki * XXX Suspending from callout cause the freeze in DEVICE_SUSPEND(). 2566236220Siwasaki * Suspend from acpi_task thread in stead. 2567236220Siwasaki */ 2568236220Siwasaki if (ACPI_FAILURE(AcpiOsExecute(OSL_NOTIFY_HANDLER, 2569236220Siwasaki acpi_sleep_force_task, sc))) 2570236220Siwasaki device_printf(sc->acpi_dev, "AcpiOsExecute() for sleeping failed\n"); 2571170976Snjl} 2572189903Sjkim#endif 2573170976Snjl 2574170976Snjl/* 2575170976Snjl * Request that the system enter the given suspend state. All /dev/apm 2576170976Snjl * devices and devd(8) will be notified. Userland then has a chance to 2577170976Snjl * save state and acknowledge the request. The system sleeps once all 2578170976Snjl * acks are in. 2579170976Snjl */ 2580170976Snjlint 2581170976Snjlacpi_ReqSleepState(struct acpi_softc *sc, int state) 2582170976Snjl{ 2583197536Sjkim#if defined(__amd64__) || defined(__i386__) 2584170976Snjl struct apm_clone_data *clone; 2585210150Sjkim ACPI_STATUS status; 2586170976Snjl 2587191695Sjkim if (state < ACPI_STATE_S1 || state > ACPI_S_STATES_MAX) 2588170976Snjl return (EINVAL); 2589191695Sjkim if (!acpi_sleep_states[state]) 2590191695Sjkim return (EOPNOTSUPP); 2591170976Snjl 2592289032Scperciva /* 2593289032Scperciva * If a reboot/shutdown/suspend request is already in progress or 2594289032Scperciva * suspend is blocked due to an upcoming shutdown, just return. 2595289032Scperciva */ 2596289032Scperciva if (rebooting || sc->acpi_next_sstate != 0 || suspend_blocked) { 2597235772Siwasaki return (0); 2598235772Siwasaki } 2599235772Siwasaki 2600235692Siwasaki /* Wait until sleep is enabled. */ 2601235692Siwasaki while (sc->acpi_sleep_disabled) { 2602235692Siwasaki AcpiOsSleep(1000); 2603235692Siwasaki } 2604235692Siwasaki 2605210150Sjkim ACPI_LOCK(acpi); 2606170976Snjl 2607235692Siwasaki sc->acpi_next_sstate = state; 2608170976Snjl 2609210150Sjkim /* S5 (soft-off) should be entered directly with no waiting. */ 2610210150Sjkim if (state == ACPI_STATE_S5) { 2611210150Sjkim ACPI_UNLOCK(acpi); 2612210150Sjkim status = acpi_EnterSleepState(sc, state); 2613210150Sjkim return (ACPI_SUCCESS(status) ? 0 : ENXIO); 2614210150Sjkim } 2615210150Sjkim 2616170976Snjl /* Record the pending state and notify all apm devices. */ 2617170976Snjl STAILQ_FOREACH(clone, &sc->apm_cdevs, entries) { 2618170976Snjl clone->notify_status = APM_EV_NONE; 2619170976Snjl if ((clone->flags & ACPI_EVF_DEVD) == 0) { 2620170976Snjl selwakeuppri(&clone->sel_read, PZERO); 2621208925Sjhb KNOTE_LOCKED(&clone->sel_read.si_note, 0); 2622170976Snjl } 2623170976Snjl } 2624170976Snjl 2625175727Siwasaki /* If devd(8) is not running, immediately enter the sleep state. */ 2626190339Sjkim if (!devctl_process_running()) { 2627175732Siwasaki ACPI_UNLOCK(acpi); 2628210150Sjkim status = acpi_EnterSleepState(sc, state); 2629210150Sjkim return (ACPI_SUCCESS(status) ? 0 : ENXIO); 2630175727Siwasaki } 2631175727Siwasaki 2632170976Snjl /* 2633170976Snjl * Set a timeout to fire if userland doesn't ack the suspend request 2634170976Snjl * in time. This way we still eventually go to sleep if we were 2635170976Snjl * overheating or running low on battery, even if userland is hung. 2636170976Snjl * We cancel this timeout once all userland acks are in or the 2637170976Snjl * suspend request is aborted. 2638170976Snjl */ 2639170976Snjl callout_reset(&sc->susp_force_to, 10 * hz, acpi_sleep_force, sc); 2640170976Snjl ACPI_UNLOCK(acpi); 2641190339Sjkim 2642190339Sjkim /* Now notify devd(8) also. */ 2643190339Sjkim acpi_UserNotify("Suspend", ACPI_ROOT_OBJECT, state); 2644190339Sjkim 2645170976Snjl return (0); 2646189903Sjkim#else 2647189903Sjkim /* This platform does not support acpi suspend/resume. */ 2648189903Sjkim return (EOPNOTSUPP); 2649189903Sjkim#endif 2650170976Snjl} 2651170976Snjl 2652170976Snjl/* 2653170976Snjl * Acknowledge (or reject) a pending sleep state. The caller has 2654170976Snjl * prepared for suspend and is now ready for it to proceed. If the 2655170976Snjl * error argument is non-zero, it indicates suspend should be cancelled 2656170976Snjl * and gives an errno value describing why. Once all votes are in, 2657170976Snjl * we suspend the system. 2658170976Snjl */ 2659170976Snjlint 2660170976Snjlacpi_AckSleepState(struct apm_clone_data *clone, int error) 2661170976Snjl{ 2662189903Sjkim#if defined(__amd64__) || defined(__i386__) 2663170976Snjl struct acpi_softc *sc; 2664170976Snjl int ret, sleeping; 2665170976Snjl 2666170976Snjl /* If no pending sleep state, return an error. */ 2667170976Snjl ACPI_LOCK(acpi); 2668170976Snjl sc = clone->acpi_sc; 2669170976Snjl if (sc->acpi_next_sstate == 0) { 2670170976Snjl ACPI_UNLOCK(acpi); 2671170976Snjl return (ENXIO); 2672170976Snjl } 2673170976Snjl 2674170976Snjl /* Caller wants to abort suspend process. */ 2675170976Snjl if (error) { 2676170976Snjl sc->acpi_next_sstate = 0; 2677170976Snjl callout_stop(&sc->susp_force_to); 2678191696Sjkim device_printf(sc->acpi_dev, 2679191696Sjkim "listener on %s cancelled the pending suspend\n", 2680170976Snjl devtoname(clone->cdev)); 2681170976Snjl ACPI_UNLOCK(acpi); 2682170976Snjl return (0); 2683170976Snjl } 2684170976Snjl 2685170976Snjl /* 2686170976Snjl * Mark this device as acking the suspend request. Then, walk through 2687170976Snjl * all devices, seeing if they agree yet. We only count devices that 2688170976Snjl * are writable since read-only devices couldn't ack the request. 2689170976Snjl */ 2690189903Sjkim sleeping = TRUE; 2691170976Snjl clone->notify_status = APM_EV_ACKED; 2692170976Snjl STAILQ_FOREACH(clone, &sc->apm_cdevs, entries) { 2693170976Snjl if ((clone->flags & ACPI_EVF_WRITE) != 0 && 2694170976Snjl clone->notify_status != APM_EV_ACKED) { 2695170976Snjl sleeping = FALSE; 2696170976Snjl break; 2697170976Snjl } 2698170976Snjl } 2699170976Snjl 2700170976Snjl /* If all devices have voted "yes", we will suspend now. */ 2701170976Snjl if (sleeping) 2702170976Snjl callout_stop(&sc->susp_force_to); 2703170976Snjl ACPI_UNLOCK(acpi); 2704170976Snjl ret = 0; 2705170976Snjl if (sleeping) { 2706170976Snjl if (ACPI_FAILURE(acpi_EnterSleepState(sc, sc->acpi_next_sstate))) 2707170976Snjl ret = ENODEV; 2708170976Snjl } 2709170976Snjl return (ret); 2710189903Sjkim#else 2711189903Sjkim /* This platform does not support acpi suspend/resume. */ 2712189903Sjkim return (EOPNOTSUPP); 2713189903Sjkim#endif 2714170976Snjl} 2715170976Snjl 2716170976Snjlstatic void 271787566Siwasakiacpi_sleep_enable(void *arg) 271887566Siwasaki{ 2719190339Sjkim struct acpi_softc *sc = (struct acpi_softc *)arg; 2720133051Snjl 2721191695Sjkim /* Reschedule if the system is not fully up and running. */ 2722191695Sjkim if (!AcpiGbl_SystemAwakeAndRunning) { 2723191695Sjkim timeout(acpi_sleep_enable, sc, hz * ACPI_MINIMUM_AWAKETIME); 2724191695Sjkim return; 2725191695Sjkim } 2726191695Sjkim 2727190339Sjkim ACPI_LOCK(acpi); 2728191695Sjkim sc->acpi_sleep_disabled = FALSE; 2729190339Sjkim ACPI_UNLOCK(acpi); 273087566Siwasaki} 273187566Siwasaki 2732190339Sjkimstatic ACPI_STATUS 2733190339Sjkimacpi_sleep_disable(struct acpi_softc *sc) 2734190339Sjkim{ 2735190339Sjkim ACPI_STATUS status; 2736190339Sjkim 2737191695Sjkim /* Fail if the system is not fully up and running. */ 2738191695Sjkim if (!AcpiGbl_SystemAwakeAndRunning) 2739191695Sjkim return (AE_ERROR); 2740191695Sjkim 2741190339Sjkim ACPI_LOCK(acpi); 2742190339Sjkim status = sc->acpi_sleep_disabled ? AE_ERROR : AE_OK; 2743191695Sjkim sc->acpi_sleep_disabled = TRUE; 2744190339Sjkim ACPI_UNLOCK(acpi); 2745190339Sjkim 2746190339Sjkim return (status); 2747190339Sjkim} 2748190339Sjkim 2749133612Snjlenum acpi_sleep_state { 2750133612Snjl ACPI_SS_NONE, 2751133612Snjl ACPI_SS_GPE_SET, 2752133612Snjl ACPI_SS_DEV_SUSPEND, 2753133612Snjl ACPI_SS_SLP_PREP, 2754133612Snjl ACPI_SS_SLEPT, 2755133612Snjl}; 2756133612Snjl 275767761Smsmith/* 2758170976Snjl * Enter the desired system sleep state. 275967761Smsmith * 2760119529Snjl * Currently we support S1-S5 but S4 is only S4BIOS 276167761Smsmith */ 2762170976Snjlstatic ACPI_STATUS 2763170976Snjlacpi_EnterSleepState(struct acpi_softc *sc, int state) 276467761Smsmith{ 2765233579Sjkim register_t intr; 2766233579Sjkim ACPI_STATUS status; 2767246251Savg ACPI_EVENT_STATUS power_button_status; 2768133612Snjl enum acpi_sleep_state slp_state; 2769236403Siwasaki int sleep_result; 277067761Smsmith 277196926Speter ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state); 277269744Smsmith 2773191695Sjkim if (state < ACPI_STATE_S1 || state > ACPI_S_STATES_MAX) 2774191627Savg return_ACPI_STATUS (AE_BAD_PARAMETER); 2775191695Sjkim if (!acpi_sleep_states[state]) { 2776191695Sjkim device_printf(sc->acpi_dev, "Sleep state S%d not supported by BIOS\n", 2777191695Sjkim state); 2778191695Sjkim return (AE_SUPPORT); 2779191695Sjkim } 2780191627Savg 2781191695Sjkim /* Re-entry once we're suspending is not allowed. */ 2782191695Sjkim status = acpi_sleep_disable(sc); 2783191695Sjkim if (ACPI_FAILURE(status)) { 2784191695Sjkim device_printf(sc->acpi_dev, 2785191695Sjkim "suspend request ignored (not ready yet)\n"); 2786191695Sjkim return (status); 2787191695Sjkim } 2788191695Sjkim 2789191627Savg if (state == ACPI_STATE_S5) { 2790191627Savg /* 2791191627Savg * Shut down cleanly and power off. This will call us back through the 2792191627Savg * shutdown handlers. 2793191627Savg */ 2794191627Savg shutdown_nice(RB_POWEROFF); 2795191627Savg return_ACPI_STATUS (AE_OK); 2796191627Savg } 2797191627Savg 2798282750Savg EVENTHANDLER_INVOKE(power_suspend_early); 2799282750Savg stop_all_proc(); 2800220647Sjkim EVENTHANDLER_INVOKE(power_suspend); 2801220647Sjkim 2802210003Sjkim if (smp_started) { 2803210003Sjkim thread_lock(curthread); 2804210003Sjkim sched_bind(curthread, 0); 2805210003Sjkim thread_unlock(curthread); 2806210003Sjkim } 2807189903Sjkim 2808196403Sjhb /* 2809196403Sjhb * Be sure to hold Giant across DEVICE_SUSPEND/RESUME since non-MPSAFE 2810196403Sjhb * drivers need this. 2811196403Sjhb */ 2812196403Sjhb mtx_lock(&Giant); 2813189903Sjkim 2814133612Snjl slp_state = ACPI_SS_NONE; 281580160Siwasaki 2816191627Savg sc->acpi_sstate = state; 2817100497Siwasaki 2818191627Savg /* Enable any GPEs as appropriate and requested by the user. */ 2819191627Savg acpi_wake_prep_walk(state); 2820191627Savg slp_state = ACPI_SS_GPE_SET; 2821129783Snjl 2822191627Savg /* 2823191627Savg * Inform all devices that we are going to sleep. If at least one 2824191627Savg * device fails, DEVICE_SUSPEND() automatically resumes the tree. 2825191627Savg * 2826191627Savg * XXX Note that a better two-pass approach with a 'veto' pass 2827191627Savg * followed by a "real thing" pass would be better, but the current 2828191627Savg * bus interface does not provide for this. 2829191627Savg */ 2830191627Savg if (DEVICE_SUSPEND(root_bus) != 0) { 2831191627Savg device_printf(sc->acpi_dev, "device_suspend failed\n"); 2832191627Savg goto backout; 2833191627Savg } 2834191627Savg slp_state = ACPI_SS_DEV_SUSPEND; 283587055Siwasaki 2836191627Savg /* If testing device suspend only, back out of everything here. */ 2837191627Savg if (acpi_susp_bounce) 2838191627Savg goto backout; 2839169973Snjl 2840191627Savg status = AcpiEnterSleepStatePrep(state); 2841191627Savg if (ACPI_FAILURE(status)) { 2842191627Savg device_printf(sc->acpi_dev, "AcpiEnterSleepStatePrep failed - %s\n", 2843191627Savg AcpiFormatException(status)); 2844191627Savg goto backout; 2845191627Savg } 2846191627Savg slp_state = ACPI_SS_SLP_PREP; 284787055Siwasaki 2848191627Savg if (sc->acpi_sleep_delay > 0) 2849191627Savg DELAY(sc->acpi_sleep_delay * 1000000); 2850102402Siwasaki 2851236408Sjkim intr = intr_disable(); 2852191627Savg if (state != ACPI_STATE_S1) { 2853236403Siwasaki sleep_result = acpi_sleep_machdep(sc, state); 2854236403Siwasaki acpi_wakeup_machdep(sc, state, sleep_result, 0); 2855246250Savg 2856246250Savg /* 2857246250Savg * XXX According to ACPI specification SCI_EN bit should be restored 2858246250Savg * by ACPI platform (BIOS, firmware) to its pre-sleep state. 2859246250Savg * Unfortunately some BIOSes fail to do that and that leads to 2860246250Savg * unexpected and serious consequences during wake up like a system 2861246250Savg * getting stuck in SMI handlers. 2862246250Savg * This hack is picked up from Linux, which claims that it follows 2863246250Savg * Windows behavior. 2864246250Savg */ 2865246250Savg if (sleep_result == 1 && state != ACPI_STATE_S4) 2866246250Savg AcpiWriteBitRegister(ACPI_BITREG_SCI_ENABLE, ACPI_ENABLE_EVENT); 2867246250Savg 2868239340Sjkim AcpiLeaveSleepStatePrep(state); 2869246251Savg 2870246251Savg if (sleep_result == 1 && state == ACPI_STATE_S3) { 2871246251Savg /* 2872246251Savg * Prevent mis-interpretation of the wakeup by power button 2873246251Savg * as a request for power off. 2874246251Savg * Ideally we should post an appropriate wakeup event, 2875246251Savg * perhaps using acpi_event_power_button_wake or alike. 2876246251Savg * 2877246251Savg * Clearing of power button status after wakeup is mandated 2878246251Savg * by ACPI specification in section "Fixed Power Button". 2879246251Savg * 2880246251Savg * XXX As of ACPICA 20121114 AcpiGetEventStatus provides 2881246251Savg * status as 0/1 corressponding to inactive/active despite 2882246251Savg * its type being ACPI_EVENT_STATUS. In other words, 2883246251Savg * we should not test for ACPI_EVENT_FLAG_SET for time being. 2884246251Savg */ 2885246251Savg if (ACPI_SUCCESS(AcpiGetEventStatus(ACPI_EVENT_POWER_BUTTON, 2886246251Savg &power_button_status)) && power_button_status != 0) { 2887246251Savg AcpiClearEvent(ACPI_EVENT_POWER_BUTTON); 2888246251Savg device_printf(sc->acpi_dev, 2889246251Savg "cleared fixed power button status\n"); 2890246251Savg } 2891246251Savg } 2892246251Savg 2893236403Siwasaki intr_restore(intr); 2894236403Siwasaki 2895236403Siwasaki /* call acpi_wakeup_machdep() again with interrupt enabled */ 2896236403Siwasaki acpi_wakeup_machdep(sc, state, sleep_result, 1); 2897236403Siwasaki 2898236403Siwasaki if (sleep_result == -1) 2899231844Sjkim goto backout; 290080028Stakawata 2901191627Savg /* Re-enable ACPI hardware on wakeup from sleep state 4. */ 2902191627Savg if (state == ACPI_STATE_S4) 2903191627Savg AcpiEnable(); 2904191627Savg } else { 2905239340Sjkim status = AcpiEnterSleepState(state); 2906239340Sjkim AcpiLeaveSleepStatePrep(state); 2907233579Sjkim intr_restore(intr); 2908191627Savg if (ACPI_FAILURE(status)) { 2909191627Savg device_printf(sc->acpi_dev, "AcpiEnterSleepState failed - %s\n", 2910191627Savg AcpiFormatException(status)); 2911191627Savg goto backout; 291267761Smsmith } 291367761Smsmith } 2914191627Savg slp_state = ACPI_SS_SLEPT; 291587566Siwasaki 2916133612Snjl /* 2917133612Snjl * Back out state according to how far along we got in the suspend 2918133612Snjl * process. This handles both the error and success cases. 2919133612Snjl */ 2920191627Savgbackout: 2921133612Snjl if (slp_state >= ACPI_SS_GPE_SET) { 2922133612Snjl acpi_wake_prep_walk(state); 2923133612Snjl sc->acpi_sstate = ACPI_STATE_S0; 2924133612Snjl } 2925236221Siwasaki if (slp_state >= ACPI_SS_DEV_SUSPEND) 2926236221Siwasaki DEVICE_RESUME(root_bus); 2927236403Siwasaki if (slp_state >= ACPI_SS_SLP_PREP) 2928133943Snjl AcpiLeaveSleepState(state); 2929231227Sjkim if (slp_state >= ACPI_SS_SLEPT) { 2930231227Sjkim acpi_resync_clock(sc); 2931133612Snjl acpi_enable_fixed_events(sc); 2932231227Sjkim } 2933210150Sjkim sc->acpi_next_sstate = 0; 2934133612Snjl 2935196403Sjhb mtx_unlock(&Giant); 2936189903Sjkim 2937210003Sjkim if (smp_started) { 2938210003Sjkim thread_lock(curthread); 2939210003Sjkim sched_unbind(curthread); 2940210003Sjkim thread_unlock(curthread); 2941210003Sjkim } 2942189903Sjkim 2943282750Savg resume_all_proc(); 2944282750Savg 2945220647Sjkim EVENTHANDLER_INVOKE(power_resume); 2946220647Sjkim 2947190339Sjkim /* Allow another sleep request after a while. */ 2948191627Savg timeout(acpi_sleep_enable, sc, hz * ACPI_MINIMUM_AWAKETIME); 2949190339Sjkim 2950190339Sjkim /* Run /etc/rc.resume after we are back. */ 2951190339Sjkim if (devctl_process_running()) 2952190339Sjkim acpi_UserNotify("Resume", ACPI_ROOT_OBJECT, state); 2953190339Sjkim 2954119529Snjl return_ACPI_STATUS (status); 295567761Smsmith} 295667761Smsmith 2957231227Sjkimstatic void 2958190340Sjkimacpi_resync_clock(struct acpi_softc *sc) 2959190340Sjkim{ 2960246252Savg#ifdef __amd64__ 2961190340Sjkim if (!acpi_reset_clock) 2962190340Sjkim return; 2963190340Sjkim 2964190340Sjkim /* 2965190340Sjkim * Warm up timecounter again and reset system clock. 2966190340Sjkim */ 2967190340Sjkim (void)timecounter->tc_get_timecount(timecounter); 2968190340Sjkim (void)timecounter->tc_get_timecount(timecounter); 2969190340Sjkim inittodr(time_second + sc->acpi_sleep_delay); 2970231227Sjkim#endif 2971190340Sjkim} 2972190340Sjkim 2973129783Snjl/* Enable or disable the device's wake GPE. */ 2974129783Snjlint 2975129783Snjlacpi_wake_set_enable(device_t dev, int enable) 2976129783Snjl{ 2977129783Snjl struct acpi_prw_data prw; 2978129783Snjl ACPI_STATUS status; 2979129783Snjl int flags; 2980129783Snjl 2981131341Snjl /* Make sure the device supports waking the system and get the GPE. */ 2982167814Sjkim if (acpi_parse_prw(acpi_get_handle(dev), &prw) != 0) 2983129783Snjl return (ENXIO); 2984129783Snjl 2985131341Snjl flags = acpi_get_flags(dev); 2986129783Snjl if (enable) { 2987216471Sjkim status = AcpiSetGpeWakeMask(prw.gpe_handle, prw.gpe_bit, 2988216471Sjkim ACPI_GPE_ENABLE); 2989129783Snjl if (ACPI_FAILURE(status)) { 2990129783Snjl device_printf(dev, "enable wake failed\n"); 2991129783Snjl return (ENXIO); 2992129783Snjl } 2993131341Snjl acpi_set_flags(dev, flags | ACPI_FLAG_WAKE_ENABLED); 2994129783Snjl } else { 2995216471Sjkim status = AcpiSetGpeWakeMask(prw.gpe_handle, prw.gpe_bit, 2996216471Sjkim ACPI_GPE_DISABLE); 2997129783Snjl if (ACPI_FAILURE(status)) { 2998129783Snjl device_printf(dev, "disable wake failed\n"); 2999129783Snjl return (ENXIO); 3000129783Snjl } 3001131341Snjl acpi_set_flags(dev, flags & ~ACPI_FLAG_WAKE_ENABLED); 3002129783Snjl } 3003129783Snjl 3004129783Snjl return (0); 3005129783Snjl} 3006129783Snjl 3007131341Snjlstatic int 3008131341Snjlacpi_wake_sleep_prep(ACPI_HANDLE handle, int sstate) 3009129783Snjl{ 3010129783Snjl struct acpi_prw_data prw; 3011131341Snjl device_t dev; 3012129783Snjl 3013131341Snjl /* Check that this is a wake-capable device and get its GPE. */ 3014129783Snjl if (acpi_parse_prw(handle, &prw) != 0) 3015129783Snjl return (ENXIO); 3016131341Snjl dev = acpi_get_device(handle); 3017129783Snjl 3018129783Snjl /* 3019131341Snjl * The destination sleep state must be less than (i.e., higher power) 3020131341Snjl * or equal to the value specified by _PRW. If this GPE cannot be 3021131341Snjl * enabled for the next sleep state, then disable it. If it can and 3022131341Snjl * the user requested it be enabled, turn on any required power resources 3023131341Snjl * and set _PSW. 3024129783Snjl */ 3025131341Snjl if (sstate > prw.lowest_wake) { 3026216471Sjkim AcpiSetGpeWakeMask(prw.gpe_handle, prw.gpe_bit, ACPI_GPE_DISABLE); 3027129783Snjl if (bootverbose) 3028131341Snjl device_printf(dev, "wake_prep disabled wake for %s (S%d)\n", 3029131341Snjl acpi_name(handle), sstate); 3030131341Snjl } else if (dev && (acpi_get_flags(dev) & ACPI_FLAG_WAKE_ENABLED) != 0) { 3031131341Snjl acpi_pwr_wake_enable(handle, 1); 3032129805Snjl acpi_SetInteger(handle, "_PSW", 1); 3033131341Snjl if (bootverbose) 3034131341Snjl device_printf(dev, "wake_prep enabled for %s (S%d)\n", 3035131341Snjl acpi_name(handle), sstate); 3036129783Snjl } 3037129783Snjl 3038129783Snjl return (0); 3039129783Snjl} 3040129783Snjl 3041131341Snjlstatic int 3042131341Snjlacpi_wake_run_prep(ACPI_HANDLE handle, int sstate) 3043129805Snjl{ 3044129805Snjl struct acpi_prw_data prw; 3045131341Snjl device_t dev; 3046129805Snjl 3047131341Snjl /* 3048131341Snjl * Check that this is a wake-capable device and get its GPE. Return 3049131341Snjl * now if the user didn't enable this device for wake. 3050131341Snjl */ 3051129805Snjl if (acpi_parse_prw(handle, &prw) != 0) 3052129805Snjl return (ENXIO); 3053131341Snjl dev = acpi_get_device(handle); 3054131341Snjl if (dev == NULL || (acpi_get_flags(dev) & ACPI_FLAG_WAKE_ENABLED) == 0) 3055131341Snjl return (0); 3056129805Snjl 3057129805Snjl /* 3058131341Snjl * If this GPE couldn't be enabled for the previous sleep state, it was 3059131341Snjl * disabled before going to sleep so re-enable it. If it was enabled, 3060131341Snjl * clear _PSW and turn off any power resources it used. 3061129805Snjl */ 3062131341Snjl if (sstate > prw.lowest_wake) { 3063216471Sjkim AcpiSetGpeWakeMask(prw.gpe_handle, prw.gpe_bit, ACPI_GPE_ENABLE); 3064131341Snjl if (bootverbose) 3065131341Snjl device_printf(dev, "run_prep re-enabled %s\n", acpi_name(handle)); 3066131341Snjl } else { 3067131341Snjl acpi_SetInteger(handle, "_PSW", 0); 3068131341Snjl acpi_pwr_wake_enable(handle, 0); 3069131341Snjl if (bootverbose) 3070131341Snjl device_printf(dev, "run_prep cleaned up for %s\n", 3071131341Snjl acpi_name(handle)); 3072131341Snjl } 3073129805Snjl 3074129805Snjl return (0); 3075129805Snjl} 3076129805Snjl 3077129783Snjlstatic ACPI_STATUS 3078131341Snjlacpi_wake_prep(ACPI_HANDLE handle, UINT32 level, void *context, void **status) 3079129783Snjl{ 3080131341Snjl int sstate; 3081129783Snjl 3082131341Snjl /* If suspending, run the sleep prep function, otherwise wake. */ 3083131341Snjl sstate = *(int *)context; 3084131341Snjl if (AcpiGbl_SystemAwakeAndRunning) 3085131341Snjl acpi_wake_sleep_prep(handle, sstate); 3086131341Snjl else 3087131341Snjl acpi_wake_run_prep(handle, sstate); 3088129783Snjl return (AE_OK); 3089129783Snjl} 3090129783Snjl 3091131341Snjl/* Walk the tree rooted at acpi0 to prep devices for suspend/resume. */ 3092129783Snjlstatic int 3093131341Snjlacpi_wake_prep_walk(int sstate) 3094129783Snjl{ 3095129783Snjl ACPI_HANDLE sb_handle; 3096129783Snjl 3097129783Snjl if (ACPI_SUCCESS(AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &sb_handle))) 3098131341Snjl AcpiWalkNamespace(ACPI_TYPE_DEVICE, sb_handle, 100, 3099199337Sjkim acpi_wake_prep, NULL, &sstate, NULL); 3100129783Snjl return (0); 3101129783Snjl} 3102129783Snjl 3103129802Snjl/* Walk the tree rooted at acpi0 to attach per-device wake sysctls. */ 3104129802Snjlstatic int 3105129802Snjlacpi_wake_sysctl_walk(device_t dev) 3106129802Snjl{ 3107129802Snjl int error, i, numdevs; 3108129802Snjl device_t *devlist; 3109129802Snjl device_t child; 3110131341Snjl ACPI_STATUS status; 3111129802Snjl 3112129802Snjl error = device_get_children(dev, &devlist, &numdevs); 3113146431Snjl if (error != 0 || numdevs == 0) { 3114146431Snjl if (numdevs == 0) 3115146431Snjl free(devlist, M_TEMP); 3116129802Snjl return (error); 3117146431Snjl } 3118129802Snjl for (i = 0; i < numdevs; i++) { 3119129802Snjl child = devlist[i]; 3120131341Snjl acpi_wake_sysctl_walk(child); 3121129802Snjl if (!device_is_attached(child)) 3122129802Snjl continue; 3123131341Snjl status = AcpiEvaluateObject(acpi_get_handle(child), "_PRW", NULL, NULL); 3124131341Snjl if (ACPI_SUCCESS(status)) { 3125129802Snjl SYSCTL_ADD_PROC(device_get_sysctl_ctx(child), 3126129802Snjl SYSCTL_CHILDREN(device_get_sysctl_tree(child)), OID_AUTO, 3127129802Snjl "wake", CTLTYPE_INT | CTLFLAG_RW, child, 0, 3128129802Snjl acpi_wake_set_sysctl, "I", "Device set to wake the system"); 3129129802Snjl } 3130129802Snjl } 3131129802Snjl free(devlist, M_TEMP); 3132129802Snjl 3133129802Snjl return (0); 3134129802Snjl} 3135129802Snjl 3136129802Snjl/* Enable or disable wake from userland. */ 3137129802Snjlstatic int 3138129802Snjlacpi_wake_set_sysctl(SYSCTL_HANDLER_ARGS) 3139129802Snjl{ 3140129802Snjl int enable, error; 3141129802Snjl device_t dev; 3142129802Snjl 3143129802Snjl dev = (device_t)arg1; 3144131341Snjl enable = (acpi_get_flags(dev) & ACPI_FLAG_WAKE_ENABLED) ? 1 : 0; 3145129802Snjl 3146129802Snjl error = sysctl_handle_int(oidp, &enable, 0, req); 3147129802Snjl if (error != 0 || req->newptr == NULL) 3148129802Snjl return (error); 3149129802Snjl if (enable != 0 && enable != 1) 3150129802Snjl return (EINVAL); 3151129802Snjl 3152129802Snjl return (acpi_wake_set_enable(dev, enable)); 3153129802Snjl} 3154129802Snjl 3155129783Snjl/* Parse a device's _PRW into a structure. */ 3156131341Snjlint 3157129783Snjlacpi_parse_prw(ACPI_HANDLE h, struct acpi_prw_data *prw) 3158129783Snjl{ 3159129783Snjl ACPI_STATUS status; 3160129783Snjl ACPI_BUFFER prw_buffer; 3161129783Snjl ACPI_OBJECT *res, *res2; 3162131341Snjl int error, i, power_count; 3163129783Snjl 3164129783Snjl if (h == NULL || prw == NULL) 3165129783Snjl return (EINVAL); 3166129783Snjl 3167129783Snjl /* 3168129783Snjl * The _PRW object (7.2.9) is only required for devices that have the 3169129783Snjl * ability to wake the system from a sleeping state. 3170129783Snjl */ 3171129783Snjl error = EINVAL; 3172129783Snjl prw_buffer.Pointer = NULL; 3173129783Snjl prw_buffer.Length = ACPI_ALLOCATE_BUFFER; 3174129783Snjl status = AcpiEvaluateObject(h, "_PRW", NULL, &prw_buffer); 3175129783Snjl if (ACPI_FAILURE(status)) 3176129783Snjl return (ENOENT); 3177129783Snjl res = (ACPI_OBJECT *)prw_buffer.Pointer; 3178129783Snjl if (res == NULL) 3179129783Snjl return (ENOENT); 3180129783Snjl if (!ACPI_PKG_VALID(res, 2)) 3181129783Snjl goto out; 3182129783Snjl 3183129783Snjl /* 3184129783Snjl * Element 1 of the _PRW object: 3185129783Snjl * The lowest power system sleeping state that can be entered while still 3186129783Snjl * providing wake functionality. The sleeping state being entered must 3187129783Snjl * be less than (i.e., higher power) or equal to this value. 3188129783Snjl */ 3189129783Snjl if (acpi_PkgInt32(res, 1, &prw->lowest_wake) != 0) 3190129783Snjl goto out; 3191129783Snjl 3192129783Snjl /* 3193129783Snjl * Element 0 of the _PRW object: 3194129783Snjl */ 3195129783Snjl switch (res->Package.Elements[0].Type) { 3196129783Snjl case ACPI_TYPE_INTEGER: 3197129783Snjl /* 3198129783Snjl * If the data type of this package element is numeric, then this 3199129783Snjl * _PRW package element is the bit index in the GPEx_EN, in the 3200129783Snjl * GPE blocks described in the FADT, of the enable bit that is 3201129783Snjl * enabled for the wake event. 3202129783Snjl */ 3203129783Snjl prw->gpe_handle = NULL; 3204129783Snjl prw->gpe_bit = res->Package.Elements[0].Integer.Value; 3205129783Snjl error = 0; 3206129783Snjl break; 3207129783Snjl case ACPI_TYPE_PACKAGE: 3208129783Snjl /* 3209129783Snjl * If the data type of this package element is a package, then this 3210129783Snjl * _PRW package element is itself a package containing two 3211129783Snjl * elements. The first is an object reference to the GPE Block 3212129783Snjl * device that contains the GPE that will be triggered by the wake 3213129783Snjl * event. The second element is numeric and it contains the bit 3214129783Snjl * index in the GPEx_EN, in the GPE Block referenced by the 3215129783Snjl * first element in the package, of the enable bit that is enabled for 3216129783Snjl * the wake event. 3217129783Snjl * 3218129783Snjl * For example, if this field is a package then it is of the form: 3219129783Snjl * Package() {\_SB.PCI0.ISA.GPE, 2} 3220129783Snjl */ 3221129783Snjl res2 = &res->Package.Elements[0]; 3222129783Snjl if (!ACPI_PKG_VALID(res2, 2)) 3223129783Snjl goto out; 3224129783Snjl prw->gpe_handle = acpi_GetReference(NULL, &res2->Package.Elements[0]); 3225129783Snjl if (prw->gpe_handle == NULL) 3226129783Snjl goto out; 3227129783Snjl if (acpi_PkgInt32(res2, 1, &prw->gpe_bit) != 0) 3228129783Snjl goto out; 3229129783Snjl error = 0; 3230129783Snjl break; 3231129783Snjl default: 3232129783Snjl goto out; 3233129783Snjl } 3234129783Snjl 3235131341Snjl /* Elements 2 to N of the _PRW object are power resources. */ 3236131341Snjl power_count = res->Package.Count - 2; 3237131341Snjl if (power_count > ACPI_PRW_MAX_POWERRES) { 3238131341Snjl printf("ACPI device %s has too many power resources\n", acpi_name(h)); 3239131341Snjl power_count = 0; 3240131341Snjl } 3241131341Snjl prw->power_res_count = power_count; 3242131341Snjl for (i = 0; i < power_count; i++) 3243131341Snjl prw->power_res[i] = res->Package.Elements[i]; 3244129783Snjl 3245129783Snjlout: 3246129783Snjl if (prw_buffer.Pointer != NULL) 3247129783Snjl AcpiOsFree(prw_buffer.Pointer); 3248129783Snjl return (error); 3249129783Snjl} 3250129783Snjl 325167761Smsmith/* 325267761Smsmith * ACPI Event Handlers 325367761Smsmith */ 325467761Smsmith 325567761Smsmith/* System Event Handlers (registered by EVENTHANDLER_REGISTER) */ 325667761Smsmith 325767761Smsmithstatic void 325867761Smsmithacpi_system_eventhandler_sleep(void *arg, int state) 325967761Smsmith{ 3260191696Sjkim struct acpi_softc *sc = (struct acpi_softc *)arg; 3261170976Snjl int ret; 3262133051Snjl 326396926Speter ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state); 326467761Smsmith 3265191695Sjkim /* Check if button action is disabled or unknown. */ 3266191695Sjkim if (state == ACPI_STATE_UNKNOWN) 3267171119Snjl return; 3268171119Snjl 3269170976Snjl /* Request that the system prepare to enter the given suspend state. */ 3270191696Sjkim ret = acpi_ReqSleepState(sc, state); 3271170976Snjl if (ret != 0) 3272191696Sjkim device_printf(sc->acpi_dev, 3273191696Sjkim "request to enter state S%d failed (err %d)\n", state, ret); 3274133051Snjl 327569744Smsmith return_VOID; 327667761Smsmith} 327767761Smsmith 327867761Smsmithstatic void 327967761Smsmithacpi_system_eventhandler_wakeup(void *arg, int state) 328067761Smsmith{ 3281133051Snjl 328296926Speter ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state); 328369744Smsmith 3284133051Snjl /* Currently, nothing to do for wakeup. */ 328569744Smsmith 328669744Smsmith return_VOID; 328767761Smsmith} 328867761Smsmith 328967761Smsmith/* 329067761Smsmith * ACPICA Event Handlers (FixedEvent, also called from button notify handler) 329167761Smsmith */ 3292217279Sjkimstatic void 3293217279Sjkimacpi_invoke_sleep_eventhandler(void *context) 3294217279Sjkim{ 3295217279Sjkim 3296217279Sjkim EVENTHANDLER_INVOKE(acpi_sleep_event, *(int *)context); 3297217279Sjkim} 3298217279Sjkim 3299217279Sjkimstatic void 3300217279Sjkimacpi_invoke_wake_eventhandler(void *context) 3301217279Sjkim{ 3302217279Sjkim 3303217279Sjkim EVENTHANDLER_INVOKE(acpi_wakeup_event, *(int *)context); 3304217279Sjkim} 3305217279Sjkim 330667761SmsmithUINT32 3307125679Snjlacpi_event_power_button_sleep(void *context) 330867761Smsmith{ 330967761Smsmith struct acpi_softc *sc = (struct acpi_softc *)context; 331067761Smsmith 331196926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 331269744Smsmith 3313217279Sjkim if (ACPI_FAILURE(AcpiOsExecute(OSL_NOTIFY_HANDLER, 3314217279Sjkim acpi_invoke_sleep_eventhandler, &sc->acpi_power_button_sx))) 3315217279Sjkim return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); 3316119529Snjl return_VALUE (ACPI_INTERRUPT_HANDLED); 331767761Smsmith} 331867761Smsmith 331967761SmsmithUINT32 3320125679Snjlacpi_event_power_button_wake(void *context) 332167761Smsmith{ 332267761Smsmith struct acpi_softc *sc = (struct acpi_softc *)context; 332367761Smsmith 332496926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 332569744Smsmith 3326217279Sjkim if (ACPI_FAILURE(AcpiOsExecute(OSL_NOTIFY_HANDLER, 3327217279Sjkim acpi_invoke_wake_eventhandler, &sc->acpi_power_button_sx))) 3328217279Sjkim return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); 3329119529Snjl return_VALUE (ACPI_INTERRUPT_HANDLED); 333067761Smsmith} 333167761Smsmith 333267761SmsmithUINT32 3333125679Snjlacpi_event_sleep_button_sleep(void *context) 333467761Smsmith{ 333567761Smsmith struct acpi_softc *sc = (struct acpi_softc *)context; 333667761Smsmith 333796926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 333869744Smsmith 3339217279Sjkim if (ACPI_FAILURE(AcpiOsExecute(OSL_NOTIFY_HANDLER, 3340217279Sjkim acpi_invoke_sleep_eventhandler, &sc->acpi_sleep_button_sx))) 3341217279Sjkim return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); 3342119529Snjl return_VALUE (ACPI_INTERRUPT_HANDLED); 334367761Smsmith} 334467761Smsmith 334567761SmsmithUINT32 3346125679Snjlacpi_event_sleep_button_wake(void *context) 334767761Smsmith{ 334867761Smsmith struct acpi_softc *sc = (struct acpi_softc *)context; 334967761Smsmith 335096926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 335169744Smsmith 3352217279Sjkim if (ACPI_FAILURE(AcpiOsExecute(OSL_NOTIFY_HANDLER, 3353217279Sjkim acpi_invoke_wake_eventhandler, &sc->acpi_sleep_button_sx))) 3354217279Sjkim return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); 3355119529Snjl return_VALUE (ACPI_INTERRUPT_HANDLED); 335667761Smsmith} 335767761Smsmith 335867761Smsmith/* 3359133051Snjl * XXX This static buffer is suboptimal. There is no locking so only 3360133051Snjl * use this for single-threaded callers. 336167761Smsmith */ 336267761Smsmithchar * 336367761Smsmithacpi_name(ACPI_HANDLE handle) 336467761Smsmith{ 3365133051Snjl ACPI_BUFFER buf; 3366133051Snjl static char data[256]; 336767761Smsmith 3368133051Snjl buf.Length = sizeof(data); 3369133051Snjl buf.Pointer = data; 337078991Smsmith 3371133584Snjl if (handle && ACPI_SUCCESS(AcpiGetName(handle, ACPI_FULL_PATHNAME, &buf))) 3372133051Snjl return (data); 3373133051Snjl return ("(unknown)"); 337467761Smsmith} 337567761Smsmith 337667761Smsmith/* 337767761Smsmith * Debugging/bug-avoidance. Avoid trying to fetch info on various 337867761Smsmith * parts of the namespace. 337967761Smsmith */ 338067761Smsmithint 338167761Smsmithacpi_avoid(ACPI_HANDLE handle) 338267761Smsmith{ 338396277Sjhb char *cp, *env, *np; 338467761Smsmith int len; 338567761Smsmith 338667761Smsmith np = acpi_name(handle); 338767761Smsmith if (*np == '\\') 338867761Smsmith np++; 338996277Sjhb if ((env = getenv("debug.acpi.avoid")) == NULL) 3390119529Snjl return (0); 339167761Smsmith 3392119529Snjl /* Scan the avoid list checking for a match */ 339396277Sjhb cp = env; 339467761Smsmith for (;;) { 3395133051Snjl while (*cp != 0 && isspace(*cp)) 339667761Smsmith cp++; 339767761Smsmith if (*cp == 0) 339867761Smsmith break; 339967761Smsmith len = 0; 3400133051Snjl while (cp[len] != 0 && !isspace(cp[len])) 340167761Smsmith len++; 340294936Smux if (!strncmp(cp, np, len)) { 340396277Sjhb freeenv(env); 340467761Smsmith return(1); 340594936Smux } 340667761Smsmith cp += len; 340767761Smsmith } 340896277Sjhb freeenv(env); 3409119529Snjl 3410119529Snjl return (0); 341167761Smsmith} 341267761Smsmith 341367761Smsmith/* 341469744Smsmith * Debugging/bug-avoidance. Disable ACPI subsystem components. 341569744Smsmith */ 341669744Smsmithint 341769744Smsmithacpi_disabled(char *subsys) 341869744Smsmith{ 341995384Smux char *cp, *env; 342069744Smsmith int len; 342169744Smsmith 3422126517Snjl if ((env = getenv("debug.acpi.disabled")) == NULL) 3423119529Snjl return (0); 3424126517Snjl if (strcmp(env, "all") == 0) { 342595384Smux freeenv(env); 3426119529Snjl return (1); 342794936Smux } 342869744Smsmith 3429126517Snjl /* Scan the disable list, checking for a match. */ 343095384Smux cp = env; 343169744Smsmith for (;;) { 3432126517Snjl while (*cp != '\0' && isspace(*cp)) 343369744Smsmith cp++; 3434126517Snjl if (*cp == '\0') 343569744Smsmith break; 343669744Smsmith len = 0; 3437126517Snjl while (cp[len] != '\0' && !isspace(cp[len])) 343869744Smsmith len++; 3439126517Snjl if (strncmp(cp, subsys, len) == 0) { 344095384Smux freeenv(env); 3441119529Snjl return (1); 344294936Smux } 344369744Smsmith cp += len; 344469744Smsmith } 344595384Smux freeenv(env); 3446119529Snjl 3447119529Snjl return (0); 344869744Smsmith} 344969744Smsmith 3450295131Sjhbstatic void 3451295131Sjhbacpi_lookup(void *arg, const char *name, device_t *dev) 3452295131Sjhb{ 3453295131Sjhb ACPI_HANDLE handle; 3454295131Sjhb 3455295131Sjhb if (*dev != NULL) 3456295131Sjhb return; 3457295131Sjhb 3458295131Sjhb /* 3459295131Sjhb * Allow any handle name that is specified as an absolute path and 3460295131Sjhb * starts with '\'. We could restrict this to \_SB and friends, 3461295131Sjhb * but see acpi_probe_children() for notes on why we scan the entire 3462295131Sjhb * namespace for devices. 3463295131Sjhb * 3464295131Sjhb * XXX: The pathname argument to AcpiGetHandle() should be fixed to 3465295131Sjhb * be const. 3466295131Sjhb */ 3467295131Sjhb if (name[0] != '\\') 3468295131Sjhb return; 3469295131Sjhb if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, __DECONST(char *, name), 3470295131Sjhb &handle))) 3471295131Sjhb return; 3472295131Sjhb *dev = acpi_get_device(handle); 3473295131Sjhb} 3474295131Sjhb 347569744Smsmith/* 347667761Smsmith * Control interface. 347767761Smsmith * 347869744Smsmith * We multiplex ioctls for all participating ACPI devices here. Individual 3479119529Snjl * drivers wanting to be accessible via /dev/acpi should use the 3480119529Snjl * register/deregister interface to make their handlers visible. 348167761Smsmith */ 348269744Smsmithstruct acpi_ioctl_hook 348369744Smsmith{ 3484119529Snjl TAILQ_ENTRY(acpi_ioctl_hook) link; 3485119529Snjl u_long cmd; 3486119529Snjl acpi_ioctl_fn fn; 3487119529Snjl void *arg; 348869744Smsmith}; 348969744Smsmith 349069744Smsmithstatic TAILQ_HEAD(,acpi_ioctl_hook) acpi_ioctl_hooks; 349169744Smsmithstatic int acpi_ioctl_hooks_initted; 349269744Smsmith 349369744Smsmithint 3494119529Snjlacpi_register_ioctl(u_long cmd, acpi_ioctl_fn fn, void *arg) 349569744Smsmith{ 349669744Smsmith struct acpi_ioctl_hook *hp; 349769744Smsmith 349869744Smsmith if ((hp = malloc(sizeof(*hp), M_ACPIDEV, M_NOWAIT)) == NULL) 3499119529Snjl return (ENOMEM); 350069744Smsmith hp->cmd = cmd; 350169744Smsmith hp->fn = fn; 350269744Smsmith hp->arg = arg; 3503133612Snjl 3504133612Snjl ACPI_LOCK(acpi); 350569744Smsmith if (acpi_ioctl_hooks_initted == 0) { 350669744Smsmith TAILQ_INIT(&acpi_ioctl_hooks); 350769744Smsmith acpi_ioctl_hooks_initted = 1; 350869744Smsmith } 350969744Smsmith TAILQ_INSERT_TAIL(&acpi_ioctl_hooks, hp, link); 3510133612Snjl ACPI_UNLOCK(acpi); 3511133612Snjl 3512119529Snjl return (0); 351369744Smsmith} 351469744Smsmith 3515139339Snjlvoid 3516119529Snjlacpi_deregister_ioctl(u_long cmd, acpi_ioctl_fn fn) 351769744Smsmith{ 351869744Smsmith struct acpi_ioctl_hook *hp; 351969744Smsmith 3520133612Snjl ACPI_LOCK(acpi); 352169744Smsmith TAILQ_FOREACH(hp, &acpi_ioctl_hooks, link) 3522133612Snjl if (hp->cmd == cmd && hp->fn == fn) 352369744Smsmith break; 352469744Smsmith 352569744Smsmith if (hp != NULL) { 352669744Smsmith TAILQ_REMOVE(&acpi_ioctl_hooks, hp, link); 352769744Smsmith free(hp, M_ACPIDEV); 352869744Smsmith } 3529133612Snjl ACPI_UNLOCK(acpi); 353069744Smsmith} 353169744Smsmith 353267761Smsmithstatic int 3533192450Simpacpiopen(struct cdev *dev, int flag, int fmt, struct thread *td) 353467761Smsmith{ 3535119529Snjl return (0); 353667761Smsmith} 353767761Smsmith 353867761Smsmithstatic int 3539192450Simpacpiclose(struct cdev *dev, int flag, int fmt, struct thread *td) 354067761Smsmith{ 3541119529Snjl return (0); 354267761Smsmith} 354367761Smsmith 354467761Smsmithstatic int 3545192450Simpacpiioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 354667761Smsmith{ 354769744Smsmith struct acpi_softc *sc; 354869744Smsmith struct acpi_ioctl_hook *hp; 3549133051Snjl int error, state; 355067761Smsmith 3551133075Sobrien error = 0; 3552133075Sobrien hp = NULL; 355367761Smsmith sc = dev->si_drv1; 355467761Smsmith 355569744Smsmith /* 355669744Smsmith * Scan the list of registered ioctls, looking for handlers. 355769744Smsmith */ 3558133612Snjl ACPI_LOCK(acpi); 3559133051Snjl if (acpi_ioctl_hooks_initted) 356069744Smsmith TAILQ_FOREACH(hp, &acpi_ioctl_hooks, link) { 3561133051Snjl if (hp->cmd == cmd) 3562133051Snjl break; 356369744Smsmith } 3564133612Snjl ACPI_UNLOCK(acpi); 3565133051Snjl if (hp) 3566133051Snjl return (hp->fn(cmd, addr, hp->arg)); 356769744Smsmith 356869744Smsmith /* 3569119529Snjl * Core ioctls are not permitted for non-writable user. 3570110894Stakawata * Currently, other ioctls just fetch information. 3571110894Stakawata * Not changing system behavior. 3572110894Stakawata */ 3573131281Snjl if ((flag & FWRITE) == 0) 3574119529Snjl return (EPERM); 3575110894Stakawata 3576119529Snjl /* Core system ioctls. */ 357767761Smsmith switch (cmd) { 3578170976Snjl case ACPIIO_REQSLPSTATE: 3579170976Snjl state = *(int *)addr; 3580170976Snjl if (state != ACPI_STATE_S5) 3581191695Sjkim return (acpi_ReqSleepState(sc, state)); 3582191695Sjkim device_printf(sc->acpi_dev, "power off via acpi ioctl not supported\n"); 3583191695Sjkim error = EOPNOTSUPP; 3584170976Snjl break; 3585170976Snjl case ACPIIO_ACKSLPSTATE: 3586170976Snjl error = *(int *)addr; 3587170976Snjl error = acpi_AckSleepState(sc->acpi_clone, error); 3588170976Snjl break; 3589170976Snjl case ACPIIO_SETSLPSTATE: /* DEPRECATED */ 359067761Smsmith state = *(int *)addr; 3591191695Sjkim if (state < ACPI_STATE_S0 || state > ACPI_S_STATES_MAX) 3592191695Sjkim return (EINVAL); 3593191695Sjkim if (!acpi_sleep_states[state]) 3594191695Sjkim return (EOPNOTSUPP); 3595191695Sjkim if (ACPI_FAILURE(acpi_SetSleepState(sc, state))) 3596191695Sjkim error = ENXIO; 359767761Smsmith break; 359867761Smsmith default: 3599133051Snjl error = ENXIO; 360067761Smsmith break; 360167761Smsmith } 360270340Siwasaki 3603119529Snjl return (error); 360467761Smsmith} 360567761Smsmith 360671001Sjhbstatic int 3607191695Sjkimacpi_sname2sstate(const char *sname) 3608191695Sjkim{ 3609191695Sjkim int sstate; 3610191695Sjkim 3611191695Sjkim if (toupper(sname[0]) == 'S') { 3612191695Sjkim sstate = sname[1] - '0'; 3613191695Sjkim if (sstate >= ACPI_STATE_S0 && sstate <= ACPI_STATE_S5 && 3614191695Sjkim sname[2] == '\0') 3615191695Sjkim return (sstate); 3616191695Sjkim } else if (strcasecmp(sname, "NONE") == 0) 3617191695Sjkim return (ACPI_STATE_UNKNOWN); 3618191695Sjkim return (-1); 3619191695Sjkim} 3620191695Sjkim 3621191697Sjkimstatic const char * 3622191695Sjkimacpi_sstate2sname(int sstate) 3623191695Sjkim{ 3624191695Sjkim static const char *snames[] = { "S0", "S1", "S2", "S3", "S4", "S5" }; 3625191695Sjkim 3626191695Sjkim if (sstate >= ACPI_STATE_S0 && sstate <= ACPI_STATE_S5) 3627191695Sjkim return (snames[sstate]); 3628191695Sjkim else if (sstate == ACPI_STATE_UNKNOWN) 3629191695Sjkim return ("NONE"); 3630191695Sjkim return (NULL); 3631191695Sjkim} 3632191695Sjkim 3633191695Sjkimstatic int 3634113366Siwasakiacpi_supported_sleep_state_sysctl(SYSCTL_HANDLER_ARGS) 3635113366Siwasaki{ 3636113366Siwasaki int error; 3637133051Snjl struct sbuf sb; 3638191695Sjkim UINT8 state; 3639113366Siwasaki 3640133051Snjl sbuf_new(&sb, NULL, 32, SBUF_AUTOEXTEND); 3641191695Sjkim for (state = ACPI_STATE_S1; state < ACPI_S_STATE_COUNT; state++) 3642191695Sjkim if (acpi_sleep_states[state]) 3643191695Sjkim sbuf_printf(&sb, "%s ", acpi_sstate2sname(state)); 3644133051Snjl sbuf_trim(&sb); 3645133051Snjl sbuf_finish(&sb); 3646133051Snjl error = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); 3647133051Snjl sbuf_delete(&sb); 3648119529Snjl return (error); 3649113366Siwasaki} 3650113366Siwasaki 3651113366Siwasakistatic int 365271001Sjhbacpi_sleep_state_sysctl(SYSCTL_HANDLER_ARGS) 365371001Sjhb{ 365471001Sjhb char sleep_state[10]; 3655191695Sjkim int error, new_state, old_state; 365671001Sjhb 3657191695Sjkim old_state = *(int *)oidp->oid_arg1; 3658191695Sjkim strlcpy(sleep_state, acpi_sstate2sname(old_state), sizeof(sleep_state)); 365971001Sjhb error = sysctl_handle_string(oidp, sleep_state, sizeof(sleep_state), req); 366071001Sjhb if (error == 0 && req->newptr != NULL) { 3661191695Sjkim new_state = acpi_sname2sstate(sleep_state); 3662191695Sjkim if (new_state < ACPI_STATE_S1) 3663191695Sjkim return (EINVAL); 3664191699Sjkim if (new_state < ACPI_S_STATE_COUNT && !acpi_sleep_states[new_state]) 3665191695Sjkim return (EOPNOTSUPP); 3666191695Sjkim if (new_state != old_state) 3667191695Sjkim *(int *)oidp->oid_arg1 = new_state; 366871001Sjhb } 3669119529Snjl return (error); 367071001Sjhb} 367171001Sjhb 3672121493Snjl/* Inform devctl(4) when we receive a Notify. */ 3673121493Snjlvoid 3674121493Snjlacpi_UserNotify(const char *subsystem, ACPI_HANDLE h, uint8_t notify) 3675121493Snjl{ 3676121493Snjl char notify_buf[16]; 3677121493Snjl ACPI_BUFFER handle_buf; 3678121493Snjl ACPI_STATUS status; 3679121493Snjl 3680121493Snjl if (subsystem == NULL) 3681121493Snjl return; 3682121493Snjl 3683121493Snjl handle_buf.Pointer = NULL; 3684121493Snjl handle_buf.Length = ACPI_ALLOCATE_BUFFER; 3685306536Sjkim status = AcpiNsHandleToPathname(h, &handle_buf, FALSE); 3686121493Snjl if (ACPI_FAILURE(status)) 3687121493Snjl return; 3688121493Snjl snprintf(notify_buf, sizeof(notify_buf), "notify=0x%02x", notify); 3689121493Snjl devctl_notify("ACPI", subsystem, handle_buf.Pointer, notify_buf); 3690121493Snjl AcpiOsFree(handle_buf.Pointer); 3691121493Snjl} 3692121493Snjl 369367761Smsmith#ifdef ACPI_DEBUG 369469744Smsmith/* 369569744Smsmith * Support for parsing debug options from the kernel environment. 369669744Smsmith * 369769744Smsmith * Bits may be set in the AcpiDbgLayer and AcpiDbgLevel debug registers 369869744Smsmith * by specifying the names of the bits in the debug.acpi.layer and 369969744Smsmith * debug.acpi.level environment variables. Bits may be unset by 370069744Smsmith * prefixing the bit name with !. 370169744Smsmith */ 370267761Smsmithstruct debugtag 370367761Smsmith{ 370467761Smsmith char *name; 370567761Smsmith UINT32 value; 370667761Smsmith}; 370767761Smsmith 370867761Smsmithstatic struct debugtag dbg_layer[] = { 370978915Smsmith {"ACPI_UTILITIES", ACPI_UTILITIES}, 371078915Smsmith {"ACPI_HARDWARE", ACPI_HARDWARE}, 371178915Smsmith {"ACPI_EVENTS", ACPI_EVENTS}, 371278915Smsmith {"ACPI_TABLES", ACPI_TABLES}, 371378915Smsmith {"ACPI_NAMESPACE", ACPI_NAMESPACE}, 371478915Smsmith {"ACPI_PARSER", ACPI_PARSER}, 371578915Smsmith {"ACPI_DISPATCHER", ACPI_DISPATCHER}, 371678915Smsmith {"ACPI_EXECUTER", ACPI_EXECUTER}, 371778915Smsmith {"ACPI_RESOURCES", ACPI_RESOURCES}, 3718102553Siwasaki {"ACPI_CA_DEBUGGER", ACPI_CA_DEBUGGER}, 371982372Smsmith {"ACPI_OS_SERVICES", ACPI_OS_SERVICES}, 3720102553Siwasaki {"ACPI_CA_DISASSEMBLER", ACPI_CA_DISASSEMBLER}, 3721120450Snjl {"ACPI_ALL_COMPONENTS", ACPI_ALL_COMPONENTS}, 372282372Smsmith 372378915Smsmith {"ACPI_AC_ADAPTER", ACPI_AC_ADAPTER}, 372478915Smsmith {"ACPI_BATTERY", ACPI_BATTERY}, 3725126517Snjl {"ACPI_BUS", ACPI_BUS}, 372678915Smsmith {"ACPI_BUTTON", ACPI_BUTTON}, 3727126517Snjl {"ACPI_EC", ACPI_EC}, 3728126517Snjl {"ACPI_FAN", ACPI_FAN}, 3729126517Snjl {"ACPI_POWERRES", ACPI_POWERRES}, 373082372Smsmith {"ACPI_PROCESSOR", ACPI_PROCESSOR}, 373178991Smsmith {"ACPI_THERMAL", ACPI_THERMAL}, 3732126517Snjl {"ACPI_TIMER", ACPI_TIMER}, 373391120Smsmith {"ACPI_ALL_DRIVERS", ACPI_ALL_DRIVERS}, 373467761Smsmith {NULL, 0} 373567761Smsmith}; 373667761Smsmith 373767761Smsmithstatic struct debugtag dbg_level[] = { 3738114442Sjhb {"ACPI_LV_INIT", ACPI_LV_INIT}, 373982372Smsmith {"ACPI_LV_DEBUG_OBJECT", ACPI_LV_DEBUG_OBJECT}, 3740114442Sjhb {"ACPI_LV_INFO", ACPI_LV_INFO}, 3741233313Sjkim {"ACPI_LV_REPAIR", ACPI_LV_REPAIR}, 374282372Smsmith {"ACPI_LV_ALL_EXCEPTIONS", ACPI_LV_ALL_EXCEPTIONS}, 3743102553Siwasaki 3744102553Siwasaki /* Trace verbosity level 1 [Standard Trace Level] */ 3745120450Snjl {"ACPI_LV_INIT_NAMES", ACPI_LV_INIT_NAMES}, 374682372Smsmith {"ACPI_LV_PARSE", ACPI_LV_PARSE}, 3747102553Siwasaki {"ACPI_LV_LOAD", ACPI_LV_LOAD}, 374882372Smsmith {"ACPI_LV_DISPATCH", ACPI_LV_DISPATCH}, 374982372Smsmith {"ACPI_LV_EXEC", ACPI_LV_EXEC}, 375082372Smsmith {"ACPI_LV_NAMES", ACPI_LV_NAMES}, 375182372Smsmith {"ACPI_LV_OPREGION", ACPI_LV_OPREGION}, 375282372Smsmith {"ACPI_LV_BFIELD", ACPI_LV_BFIELD}, 375382372Smsmith {"ACPI_LV_TABLES", ACPI_LV_TABLES}, 375482372Smsmith {"ACPI_LV_VALUES", ACPI_LV_VALUES}, 375582372Smsmith {"ACPI_LV_OBJECTS", ACPI_LV_OBJECTS}, 375682372Smsmith {"ACPI_LV_RESOURCES", ACPI_LV_RESOURCES}, 375782372Smsmith {"ACPI_LV_USER_REQUESTS", ACPI_LV_USER_REQUESTS}, 375882372Smsmith {"ACPI_LV_PACKAGE", ACPI_LV_PACKAGE}, 3759102553Siwasaki {"ACPI_LV_VERBOSITY1", ACPI_LV_VERBOSITY1}, 3760102553Siwasaki 3761102553Siwasaki /* Trace verbosity level 2 [Function tracing and memory allocation] */ 3762102553Siwasaki {"ACPI_LV_ALLOCATIONS", ACPI_LV_ALLOCATIONS}, 3763102553Siwasaki {"ACPI_LV_FUNCTIONS", ACPI_LV_FUNCTIONS}, 3764102553Siwasaki {"ACPI_LV_OPTIMIZATIONS", ACPI_LV_OPTIMIZATIONS}, 3765102553Siwasaki {"ACPI_LV_VERBOSITY2", ACPI_LV_VERBOSITY2}, 376682372Smsmith {"ACPI_LV_ALL", ACPI_LV_ALL}, 3767102553Siwasaki 3768102553Siwasaki /* Trace verbosity level 3 [Threading, I/O, and Interrupts] */ 3769102553Siwasaki {"ACPI_LV_MUTEX", ACPI_LV_MUTEX}, 3770102553Siwasaki {"ACPI_LV_THREADS", ACPI_LV_THREADS}, 3771102553Siwasaki {"ACPI_LV_IO", ACPI_LV_IO}, 3772102553Siwasaki {"ACPI_LV_INTERRUPTS", ACPI_LV_INTERRUPTS}, 3773102553Siwasaki {"ACPI_LV_VERBOSITY3", ACPI_LV_VERBOSITY3}, 3774102553Siwasaki 3775102553Siwasaki /* Exceptionally verbose output -- also used in the global "DebugLevel" */ 377699682Siwasaki {"ACPI_LV_AML_DISASSEMBLE", ACPI_LV_AML_DISASSEMBLE}, 377799682Siwasaki {"ACPI_LV_VERBOSE_INFO", ACPI_LV_VERBOSE_INFO}, 377899682Siwasaki {"ACPI_LV_FULL_TABLES", ACPI_LV_FULL_TABLES}, 377999682Siwasaki {"ACPI_LV_EVENTS", ACPI_LV_EVENTS}, 378099682Siwasaki {"ACPI_LV_VERBOSE", ACPI_LV_VERBOSE}, 378167761Smsmith {NULL, 0} 378267761Smsmith}; 378367761Smsmith 378467761Smsmithstatic void 378567761Smsmithacpi_parse_debug(char *cp, struct debugtag *tag, UINT32 *flag) 378667761Smsmith{ 378767761Smsmith char *ep; 378867761Smsmith int i, l; 378969744Smsmith int set; 379067761Smsmith 379167761Smsmith while (*cp) { 379267761Smsmith if (isspace(*cp)) { 379367761Smsmith cp++; 379467761Smsmith continue; 379567761Smsmith } 379667761Smsmith ep = cp; 379767761Smsmith while (*ep && !isspace(*ep)) 379867761Smsmith ep++; 379969744Smsmith if (*cp == '!') { 380069744Smsmith set = 0; 380169744Smsmith cp++; 380269744Smsmith if (cp == ep) 380369744Smsmith continue; 380469744Smsmith } else { 380569744Smsmith set = 1; 380669744Smsmith } 380767761Smsmith l = ep - cp; 380867761Smsmith for (i = 0; tag[i].name != NULL; i++) { 380967761Smsmith if (!strncmp(cp, tag[i].name, l)) { 3810119529Snjl if (set) 381169744Smsmith *flag |= tag[i].value; 3812119529Snjl else 381369744Smsmith *flag &= ~tag[i].value; 381467761Smsmith } 381567761Smsmith } 381667761Smsmith cp = ep; 381767761Smsmith } 381867761Smsmith} 381967761Smsmith 382067761Smsmithstatic void 382177432Smsmithacpi_set_debugging(void *junk) 382267761Smsmith{ 3823128989Snjl char *layer, *level; 382469744Smsmith 3825120494Snjl if (cold) { 3826120494Snjl AcpiDbgLayer = 0; 3827120494Snjl AcpiDbgLevel = 0; 3828120494Snjl } 3829107199Siwasaki 3830128989Snjl layer = getenv("debug.acpi.layer"); 3831128989Snjl level = getenv("debug.acpi.level"); 3832128989Snjl if (layer == NULL && level == NULL) 3833128989Snjl return; 3834128989Snjl 3835128989Snjl printf("ACPI set debug"); 3836128989Snjl if (layer != NULL) { 3837128989Snjl if (strcmp("NONE", layer) != 0) 3838128989Snjl printf(" layer '%s'", layer); 3839128989Snjl acpi_parse_debug(layer, &dbg_layer[0], &AcpiDbgLayer); 3840128989Snjl freeenv(layer); 384195081Smike } 3842128989Snjl if (level != NULL) { 3843128989Snjl if (strcmp("NONE", level) != 0) 3844128989Snjl printf(" level '%s'", level); 3845128989Snjl acpi_parse_debug(level, &dbg_level[0], &AcpiDbgLevel); 3846128989Snjl freeenv(level); 384795081Smike } 3848128989Snjl printf("\n"); 384967761Smsmith} 3850133051Snjl 3851119529SnjlSYSINIT(acpi_debugging, SI_SUB_TUNABLES, SI_ORDER_ANY, acpi_set_debugging, 3852119529Snjl NULL); 3853120494Snjl 3854120494Snjlstatic int 3855120494Snjlacpi_debug_sysctl(SYSCTL_HANDLER_ARGS) 3856120494Snjl{ 3857123337Snjl int error, *dbg; 3858120494Snjl struct debugtag *tag; 3859123337Snjl struct sbuf sb; 3860273847Shselasky char temp[128]; 3861120494Snjl 3862123337Snjl if (sbuf_new(&sb, NULL, 128, SBUF_AUTOEXTEND) == NULL) 3863123337Snjl return (ENOMEM); 3864120494Snjl if (strcmp(oidp->oid_arg1, "debug.acpi.layer") == 0) { 3865120494Snjl tag = &dbg_layer[0]; 3866120494Snjl dbg = &AcpiDbgLayer; 3867120494Snjl } else { 3868120494Snjl tag = &dbg_level[0]; 3869120494Snjl dbg = &AcpiDbgLevel; 3870120494Snjl } 3871120494Snjl 3872120494Snjl /* Get old values if this is a get request. */ 3873133612Snjl ACPI_SERIAL_BEGIN(acpi); 3874120494Snjl if (*dbg == 0) { 3875123337Snjl sbuf_cpy(&sb, "NONE"); 3876120494Snjl } else if (req->newptr == NULL) { 3877120494Snjl for (; tag->name != NULL; tag++) { 3878123337Snjl if ((*dbg & tag->value) == tag->value) 3879123337Snjl sbuf_printf(&sb, "%s ", tag->name); 3880120494Snjl } 3881120494Snjl } 3882123337Snjl sbuf_trim(&sb); 3883123337Snjl sbuf_finish(&sb); 3884273847Shselasky strlcpy(temp, sbuf_data(&sb), sizeof(temp)); 3885123337Snjl sbuf_delete(&sb); 3886120494Snjl 3887273847Shselasky error = sysctl_handle_string(oidp, temp, sizeof(temp), req); 3888273847Shselasky 3889273847Shselasky /* Check for error or no change */ 3890120494Snjl if (error == 0 && req->newptr != NULL) { 3891120494Snjl *dbg = 0; 3892273847Shselasky setenv((char *)oidp->oid_arg1, temp); 3893120494Snjl acpi_set_debugging(NULL); 3894120494Snjl } 3895133612Snjl ACPI_SERIAL_END(acpi); 3896120494Snjl 3897120494Snjl return (error); 3898120494Snjl} 3899133051Snjl 3900120494SnjlSYSCTL_PROC(_debug_acpi, OID_AUTO, layer, CTLFLAG_RW | CTLTYPE_STRING, 3901120494Snjl "debug.acpi.layer", 0, acpi_debug_sysctl, "A", ""); 3902120494SnjlSYSCTL_PROC(_debug_acpi, OID_AUTO, level, CTLFLAG_RW | CTLTYPE_STRING, 3903120494Snjl "debug.acpi.level", 0, acpi_debug_sysctl, "A", ""); 3904133051Snjl#endif /* ACPI_DEBUG */ 390585835Siwasaki 390685835Siwasakistatic int 3907204916Sjkimacpi_debug_objects_sysctl(SYSCTL_HANDLER_ARGS) 3908204916Sjkim{ 3909204916Sjkim int error; 3910204916Sjkim int old; 3911204916Sjkim 3912204916Sjkim old = acpi_debug_objects; 3913204916Sjkim error = sysctl_handle_int(oidp, &acpi_debug_objects, 0, req); 3914204916Sjkim if (error != 0 || req->newptr == NULL) 3915204916Sjkim return (error); 3916204916Sjkim if (old == acpi_debug_objects || (old && acpi_debug_objects)) 3917204916Sjkim return (0); 3918204916Sjkim 3919204916Sjkim ACPI_SERIAL_BEGIN(acpi); 3920204916Sjkim AcpiGbl_EnableAmlDebugObject = acpi_debug_objects ? TRUE : FALSE; 3921204916Sjkim ACPI_SERIAL_END(acpi); 3922204916Sjkim 3923204916Sjkim return (0); 3924204916Sjkim} 3925204916Sjkim 3926204916Sjkimstatic int 3927214390Sjkimacpi_parse_interfaces(char *str, struct acpi_interface *iface) 3928214390Sjkim{ 3929214390Sjkim char *p; 3930214390Sjkim size_t len; 3931214390Sjkim int i, j; 3932214390Sjkim 3933214390Sjkim p = str; 3934214390Sjkim while (isspace(*p) || *p == ',') 3935214390Sjkim p++; 3936214390Sjkim len = strlen(p); 3937214390Sjkim if (len == 0) 3938214390Sjkim return (0); 3939214390Sjkim p = strdup(p, M_TEMP); 3940214390Sjkim for (i = 0; i < len; i++) 3941214390Sjkim if (p[i] == ',') 3942214390Sjkim p[i] = '\0'; 3943214390Sjkim i = j = 0; 3944214390Sjkim while (i < len) 3945214390Sjkim if (isspace(p[i]) || p[i] == '\0') 3946214390Sjkim i++; 3947214390Sjkim else { 3948214390Sjkim i += strlen(p + i) + 1; 3949214390Sjkim j++; 3950214390Sjkim } 3951214390Sjkim if (j == 0) { 3952214390Sjkim free(p, M_TEMP); 3953214390Sjkim return (0); 3954214390Sjkim } 3955214390Sjkim iface->data = malloc(sizeof(*iface->data) * j, M_TEMP, M_WAITOK); 3956214390Sjkim iface->num = j; 3957214390Sjkim i = j = 0; 3958214390Sjkim while (i < len) 3959214390Sjkim if (isspace(p[i]) || p[i] == '\0') 3960214390Sjkim i++; 3961214390Sjkim else { 3962214390Sjkim iface->data[j] = p + i; 3963214390Sjkim i += strlen(p + i) + 1; 3964214390Sjkim j++; 3965214390Sjkim } 3966214390Sjkim 3967214390Sjkim return (j); 3968214390Sjkim} 3969214390Sjkim 3970214390Sjkimstatic void 3971214390Sjkimacpi_free_interfaces(struct acpi_interface *iface) 3972214390Sjkim{ 3973214390Sjkim 3974214390Sjkim free(iface->data[0], M_TEMP); 3975214390Sjkim free(iface->data, M_TEMP); 3976214390Sjkim} 3977214390Sjkim 3978214390Sjkimstatic void 3979214390Sjkimacpi_reset_interfaces(device_t dev) 3980214390Sjkim{ 3981214390Sjkim struct acpi_interface list; 3982214390Sjkim ACPI_STATUS status; 3983214390Sjkim int i; 3984214390Sjkim 3985214390Sjkim if (acpi_parse_interfaces(acpi_install_interface, &list) > 0) { 3986214390Sjkim for (i = 0; i < list.num; i++) { 3987214390Sjkim status = AcpiInstallInterface(list.data[i]); 3988214390Sjkim if (ACPI_FAILURE(status)) 3989214390Sjkim device_printf(dev, 3990214390Sjkim "failed to install _OSI(\"%s\"): %s\n", 3991214390Sjkim list.data[i], AcpiFormatException(status)); 3992214390Sjkim else if (bootverbose) 3993214390Sjkim device_printf(dev, "installed _OSI(\"%s\")\n", 3994214390Sjkim list.data[i]); 3995214390Sjkim } 3996214390Sjkim acpi_free_interfaces(&list); 3997214390Sjkim } 3998214390Sjkim if (acpi_parse_interfaces(acpi_remove_interface, &list) > 0) { 3999214390Sjkim for (i = 0; i < list.num; i++) { 4000214390Sjkim status = AcpiRemoveInterface(list.data[i]); 4001214390Sjkim if (ACPI_FAILURE(status)) 4002214390Sjkim device_printf(dev, 4003214390Sjkim "failed to remove _OSI(\"%s\"): %s\n", 4004214390Sjkim list.data[i], AcpiFormatException(status)); 4005214390Sjkim else if (bootverbose) 4006214390Sjkim device_printf(dev, "removed _OSI(\"%s\")\n", 4007214390Sjkim list.data[i]); 4008214390Sjkim } 4009214390Sjkim acpi_free_interfaces(&list); 4010214390Sjkim } 4011214390Sjkim} 4012214390Sjkim 4013214390Sjkimstatic int 401485835Siwasakiacpi_pm_func(u_long cmd, void *arg, ...) 401585835Siwasaki{ 401685835Siwasaki int state, acpi_state; 401785835Siwasaki int error; 401885835Siwasaki struct acpi_softc *sc; 401985835Siwasaki va_list ap; 402085835Siwasaki 402185835Siwasaki error = 0; 402285835Siwasaki switch (cmd) { 402385835Siwasaki case POWER_CMD_SUSPEND: 402485835Siwasaki sc = (struct acpi_softc *)arg; 402585835Siwasaki if (sc == NULL) { 402685835Siwasaki error = EINVAL; 402785835Siwasaki goto out; 402885835Siwasaki } 402985835Siwasaki 403085835Siwasaki va_start(ap, arg); 403185835Siwasaki state = va_arg(ap, int); 4032139339Snjl va_end(ap); 403385835Siwasaki 403485835Siwasaki switch (state) { 403585835Siwasaki case POWER_SLEEP_STATE_STANDBY: 403685835Siwasaki acpi_state = sc->acpi_standby_sx; 403785835Siwasaki break; 403885835Siwasaki case POWER_SLEEP_STATE_SUSPEND: 403985835Siwasaki acpi_state = sc->acpi_suspend_sx; 404085835Siwasaki break; 404185835Siwasaki case POWER_SLEEP_STATE_HIBERNATE: 404285835Siwasaki acpi_state = ACPI_STATE_S4; 404385835Siwasaki break; 404485835Siwasaki default: 404585835Siwasaki error = EINVAL; 404685835Siwasaki goto out; 404785835Siwasaki } 404885835Siwasaki 4049170976Snjl if (ACPI_FAILURE(acpi_EnterSleepState(sc, acpi_state))) 4050170976Snjl error = ENXIO; 405185835Siwasaki break; 405285835Siwasaki default: 405385835Siwasaki error = EINVAL; 405485835Siwasaki goto out; 405585835Siwasaki } 405685835Siwasaki 405785835Siwasakiout: 405885835Siwasaki return (error); 405985835Siwasaki} 406085835Siwasaki 406185835Siwasakistatic void 406285835Siwasakiacpi_pm_register(void *arg) 406385835Siwasaki{ 4064119529Snjl if (!cold || resource_disabled("acpi", 0)) 4065107199Siwasaki return; 4066107199Siwasaki 4067107199Siwasaki power_pm_register(POWER_PM_TYPE_ACPI, acpi_pm_func, NULL); 406885835Siwasaki} 406985835Siwasaki 407085835SiwasakiSYSINIT(power, SI_SUB_KLD, SI_ORDER_ANY, acpi_pm_register, 0); 4071