/*-
* Copyright (c) 2003, 2007 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Charles M. Hannum of By Noon Software, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 2003 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Frank van der Linden for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright 2001, 2003 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Jason R. Thorpe for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* The acpi_active variable is set when the ACPI subsystem is active.
* Machine-dependent code may wish to skip other steps (such as attaching
* subsystems that ACPI supercedes) when ACPI is active.
*/
int acpi_active = 0;
int acpi_suspended = 0;
int acpi_force_load = 0;
int acpi_verbose_loaded = 0;
/*
* This structure provides a context for the ACPI
* namespace walk performed in acpi_build_tree().
*/
struct acpi_walkcontext {
struct acpi_softc *aw_sc;
struct acpi_devnode *aw_parent;
};
/*
* Ignored HIDs.
*/
static const char * const acpi_ignored_ids[] = {
#if defined(i386) || defined(x86_64)
"ACPI0007", /* ACPI CPUs do not attach to acpi(4) */
"PNP0000", /* AT interrupt controller is handled internally */
"PNP0001", /* EISA interrupt controller is handled internally */
"PNP0200", /* AT DMA controller is handled internally */
"PNP0A??", /* PCI Busses are handled internally */
"PNP0B00", /* AT RTC is handled internally */
"PNP0C02", /* PnP motherboard resources */
"PNP0C0F", /* ACPI PCI link devices are handled internally */
#endif
#if defined(x86_64)
"PNP0C04", /* FPU is handled internally */
#endif
#if defined(__aarch64__)
"ACPI0004", /* ACPI module devices are handled internally */
"PNP0C0F", /* ACPI PCI link devices are handled internally */
#endif
NULL
};
/*
* Devices that should be attached early.
*/
static const char * const acpi_early_ids[] = {
"PNP0C09", /* acpiec(4) */
NULL
};
static int sysctl_hw_acpi_fixedstats(SYSCTLFN_PROTO);
static int sysctl_hw_acpi_sleepstate(SYSCTLFN_PROTO);
static int sysctl_hw_acpi_sleepstates(SYSCTLFN_PROTO);
/*
* Probe for ACPI support.
*
* This is called by the machine-dependent ACPI front-end.
* Note: this is not an autoconfiguration interface function.
*/
int
acpi_probe(void)
{
ACPI_TABLE_HEADER *rsdt;
ACPI_STATUS rv;
int quirks;
if (acpi_softc != NULL)
panic("%s: already probed", __func__);
aprint_normal("ACPI: BIOS is listed as broken:\n");
aprint_normal("ACPI: X/RSDT: OemId <%6.6s,%8.8s,%08x>, "
"AslId <%4.4s,%08x>\n", rsdt->OemId, rsdt->OemTableId,
rsdt->OemRevision, rsdt->AslCompilerId,
rsdt->AslCompilerRevision);
aprint_normal("ACPI: Not used. Set acpi_force_load to use.\n");
fail:
aprint_error("%s: failed to initialize ACPI: %s\n",
__func__, AcpiFormatException(rv));
}
/*
* XXX: This is incomplete.
*/
static int
acpi_detach(device_t self, int flags)
{
struct acpi_softc *sc = device_private(self);
ACPI_STATUS rv;
int rc;
/*
* Identify wake GPEs from the _PRW. Note that
* AcpiUpdateAllGpes() must be called afterwards.
*/
if (ad->ad_devinfo->Type == ACPI_TYPE_DEVICE)
acpi_wakedev_init(ad);
/*
* First scan for devices such as acpiec(4) that
* should be always attached before anything else.
* We want these devices to attach regardless of
* the device status and other restrictions.
*/
SIMPLEQ_FOREACH(ad, &sc->sc_head, ad_list) {
if (ad->ad_device != NULL)
continue;
if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE)
continue;
if (acpi_match_hid(ad->ad_devinfo, acpi_early_ids) == 0)
continue;
/*
* There is a bug in ACPICA: it defines the type
* of the scopes incorrectly for its own reasons.
*/
if (acpi_is_scope(ad) != false)
continue;
di = ad->ad_devinfo;
/*
* We only attach devices which are present, enabled, and
* functioning properly. However, if a device is enabled,
* it is decoding resources and we should claim these,
* if possible. This requires changes to bus_space(9).
*/
if (di->Type == ACPI_TYPE_DEVICE &&
!acpi_device_present(ad->ad_handle)) {
continue;
}
if (di->Type == ACPI_TYPE_POWER)
continue;
if (di->Type == ACPI_TYPE_PROCESSOR)
continue;
if (acpi_match_hid(di, acpi_early_ids) != 0)
continue;
if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE)
continue;
/*
* Scan power resource capabilities.
*
* If any power states are supported,
* at least _PR0 and _PR3 must be present.
*/
rv = AcpiGetHandle(ad->ad_handle, "_PR0", &tmp);
if (ACPI_SUCCESS(rv)) {
ad->ad_flags |= ACPI_DEVICE_POWER;
acpi_power_add(ad);
}
case ACPI_NOTIFY_BUS_CHECK:
case ACPI_NOTIFY_DEVICE_CHECK:
case ACPI_NOTIFY_DEVICE_WAKE:
case ACPI_NOTIFY_EJECT_REQUEST:
case ACPI_NOTIFY_DEVICE_CHECK_LIGHT:
case ACPI_NOTIFY_FREQUENCY_MISMATCH:
case ACPI_NOTIFY_BUS_MODE_MISMATCH:
case ACPI_NOTIFY_POWER_FAULT:
case ACPI_NOTIFY_CAPABILITIES_CHECK:
case ACPI_NOTIFY_DEVICE_PLD_CHECK:
case ACPI_NOTIFY_RESERVED:
case ACPI_NOTIFY_LOCALITY_UPDATE:
break;
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "notification 0x%02X for "
"%s (%p)\n", event, acpi_name(handle), handle));
/*
* We deliver notifications only to drivers
* that have been successfully attached and
* that have registered a handler with us.
* The opaque pointer is always the device_t.
*/
SIMPLEQ_FOREACH(ad, &sc->sc_head, ad_list) {
if (ad->ad_device == NULL)
continue;
if ((notify = atomic_load_acquire(&ad->ad_notify)) == NULL)
continue;
/*
* Evaluate supported sleep states.
*/
for (i = ACPI_STATE_S0; i <= ACPI_STATE_S5; i++) {
rv = AcpiGetSleepTypeData(i, &a, &b);
if (ACPI_SUCCESS(rv))
sc->sc_sleepstates |= __BIT(i);
}
}
/*
* Must be called with interrupts enabled.
*/
void
acpi_enter_sleep_state(int state)
{
struct acpi_softc *sc = acpi_softc;
ACPI_STATUS rv;
if (acpi_softc == NULL)
return;
if (state == sc->sc_sleepstate)
return;
if (state < ACPI_STATE_S0 || state > ACPI_STATE_S5)
return;
aprint_normal_dev(sc->sc_dev, "entering state S%d\n", state);
switch (state) {
case ACPI_STATE_S0:
sc->sc_sleepstate = ACPI_STATE_S0;
return;
case ACPI_STATE_S1:
case ACPI_STATE_S2:
case ACPI_STATE_S3:
case ACPI_STATE_S4:
if ((sc->sc_sleepstates & __BIT(state)) == 0) {
aprint_error_dev(sc->sc_dev, "sleep state "
"S%d is not available\n", state);
return;
}
/*
* Evaluate the _TTS method. This should be done before
* pmf_system_suspend(9) and the evaluation of _PTS.
* We should also re-evaluate this once we return to
* S0 or if we abort the sleep state transition in the
* middle (see ACPI 3.0, section 7.3.6). In reality,
* however, the _TTS method is seldom seen in the field.
*/
rv = acpi_eval_set_integer(NULL, "\\_TTS", state);
if (ACPI_SUCCESS(rv))
aprint_debug_dev(sc->sc_dev, "evaluated _TTS\n");
/*
* This will evaluate the _PTS and _SST methods,
* but unlike the documentation claims, not _GTS,
* which is evaluated in AcpiEnterSleepState().
* This must be called with interrupts enabled.
*/
rv = AcpiEnterSleepStatePrep(state);
if (ACPI_FAILURE(rv)) {
aprint_error_dev(sc->sc_dev, "failed to prepare "
"S%d: %s\n", state, AcpiFormatException(rv));
break;
}
/*
* After the _PTS method has been evaluated, we can
* enable wake and evaluate _PSW (ACPI 4.0, p. 284).
*/
acpi_wakedev_commit(sc, state);
sc->sc_sleepstate = state;
if (state == ACPI_STATE_S1) {
/*
* Before the transition to S1, CPU caches
* must be flushed (see ACPI 4.0, 7.3.4.2).
*
* Note that interrupts must be off before
* calling AcpiEnterSleepState(). Conversely,
* AcpiLeaveSleepState() should always be
* called with interrupts enabled.
*/
acpi_md_OsDisableInterrupt();
/*
* We let MD code handle this since there are multiple ways to do it:
*
* IA-32: Use AcpiFindRootPointer() to locate the RSDP.
*
* IA-64: Use the EFI.
*/
PhysicalAddress = acpi_md_OsGetRootPointer();
if (acpi_root_pointer == 0)
acpi_root_pointer = PhysicalAddress;