/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2016, Joyent, Inc.
*/
/*
* Copyright (c) 2009, Intel Corporation.
* All rights reserved.
*/
/*
* Solaris x86 ACPI CA services
*/
#include <sys/x86_archext.h>
#include <sys/archsystm.h>
/*
*
*/
"ACPI interpreter",
};
MODREV_1, /* MODREV_1 manual */
(void *)&modlmisc, /* module linkage */
NULL, /* list terminator */
};
/*
* Local prototypes
*/
struct parsed_prw {
int prw_gpebit;
int prw_level;
};
static void acpica_init_kstats(void);
static ACPI_STATUS acpica_init_PRW(
void *ctxp,
void **rvpp);
static ACPI_STATUS acpica_parse_PRW(
struct parsed_prw *prw);
/*
* Local data
*/
/*
* State of acpica subsystem
* After successful initialization, will be ACPICA_INITIALIZED
*/
void *AcpiGbl_DbBuffer;
/*
* Following are set by acpica_process_user_options()
*
* acpica_enable = FALSE prevents initialization of ACPI CA
* completely
*
* acpi_init_level determines level of ACPI CA functionality
* enabled in acpica_init()
*/
int acpica_enable;
/*
* Non-zero enables lax behavior with respect to some
* common ACPI BIOS issues; see ACPI CA documentation
* Setting this to zero causes ACPI CA to enforce strict
* compliance with ACPI specification
*/
/*
* For non-DEBUG builds, set the ACPI CA debug level to 0
* Field-patchable for diagnostic use.
*/
#ifdef DEBUG
int acpica_muzzle_debug_output = 0;
#else
#endif
/*
* ACPI DDI hooks
*/
int
_init(void)
{
int status;
extern int (*acpi_fp_setwake)();
extern kmutex_t cpu_map_lock;
goto load_error;
}
/* global ACPI CA initialization */
/* initialize table manager */
return (error);
}
int
{
}
int
_fini(void)
{
/*
* acpica module is never unloaded at run-time; there's always
* a PSM depending on it, at the very least
*/
return (EBUSY);
}
/*
* Install acpica-provided (default) address-space handlers
* that may be needed before AcpiEnableSubsystem() runs.
* See the comment in AcpiInstallAddressSpaceHandler().
* Default handlers for remaining address spaces are
* installed later, in AcpiEnableSubsystem.
*/
static int
{
/*
* Install ACPI CA default handlers
*/
res != AE_SAME_HANDLER) {
" system memory");
}
res != AE_SAME_HANDLER) {
" system I/O");
}
res != AE_SAME_HANDLER) {
" PCI Config");
}
res != AE_SAME_HANDLER) {
" Data Table");
}
return (rv);
}
/*
* Find the BIOS date, and return TRUE if supplied
* date is same or later than the BIOS date, or FALSE
* if the BIOS date can't be fetched for any reason
*/
static int
{
char *datep;
/* If firmware has no bios, skip the check */
"bios-free"))
return (TRUE);
/*
* PC BIOSes contain a string in the form of
* where mm, dd and yy are all ASCII digits.
* We map the string, pluck out the values,
* and accept all BIOSes from 1 Jan 1999 on
* as valid.
*/
return (FALSE);
/* year */
/* month */
/* day */
/* non-digit chars in BIOS date */
return (FALSE);
}
/*
* Adjust for 2-digit year; note to grand-children:
* need a new scheme before 2080 rolls around
*/
1900 : 2000;
return (FALSE);
return (TRUE);
if (bios_month < mm)
return (FALSE);
else if (bios_month > mm)
return (TRUE);
return (FALSE);
return (TRUE);
}
/*
* Check for Metropolis systems with BIOSes older than 10/12/04
* return TRUE if BIOS requires legacy mode, FALSE otherwise
*/
static int
{
/* get the FADT */
return (FALSE);
/* compare OEM Table ID to "SUNmetro" - no match, return false */
return (FALSE);
/* On a Metro - return FALSE if later than 10/12/04 */
}
/*
* Process acpi-user-options property if present
*/
static void
{
static int processed = 0;
int acpi_user_options;
char *acpi_prop;
/*
* return if acpi-user-options has already been processed
*/
if (processed)
return;
else
processed = 1;
/* converts acpi-user-options from type string to int, if any */
long data;
int ret;
if (ret == 0) {
"acpi-user-options");
"acpi-user-options", data);
}
}
/*
* fetch the optional options property
*/
DDI_PROP_DONTPASS, "acpi-user-options", 0);
/*
* Note that 'off' has precedence over 'on'
* Also note - all cases of ACPI_OUSER_MASK
* provided here, no default: case is present
*/
switch (acpi_user_options & ACPI_OUSER_MASK) {
case ACPI_OUSER_DFLT:
break;
case ACPI_OUSER_ON:
break;
case ACPI_OUSER_OFF:
case ACPI_OUSER_OFF | ACPI_OUSER_ON:
break;
}
/*
* special test here; may be generalized in the
* future - test for a machines that are known to
* work only in legacy mode, and set OUSER_LEGACY if
* we're on one
*/
if (acpica_metro_old_bios())
/*
* If legacy mode is specified, set initialization
* options to avoid entering ACPI mode and hooking SCI
* - basically try to act like legacy acpi_intp
*/
if ((acpi_user_options & ACPI_OUSER_LEGACY) != 0)
/*
* modify default ACPI CA debug output level for non-DEBUG builds
*/
AcpiDbgLevel = 0;
}
/*
* Initialize the CA subsystem if it hasn't been done already
*/
int
{
extern void acpica_find_ioapics(void);
/*
* Make sure user options are processed,
* then fail to initialize if ACPI CA has been
* disabled
*/
if (!acpica_enable)
return (AE_ERROR);
if (acpica_init_state == ACPICA_INITIALIZED) {
return (AE_OK);
}
goto error;
goto error;
/*
* Create ACPI-to-devinfo mapping now so _INI and _STA
* methods can access PCI config space when needed
*/
scan_d2a_map();
goto error;
/* do after AcpiEnableSubsystem() so GPEs are initialized */
acpica_ec_init(); /* initialize EC if present */
/* This runs all device _STA and _INI methods. */
goto error;
/*
* [ACPI, sec. 4.4.1.1]
* As of ACPICA version 20101217 (December 2010), the _PRW methods
* (Power Resources for Wake) are no longer automatically executed
* as part of the ACPICA initialization. The OS must do this.
*/
(void) AcpiUpdateAllGpes();
/*
* If we are running on the Xen hypervisor as dom0 we need to
* find the ioapics so we can prevent ACPI from trying to
* access them.
*/
if (acpica_init_state != ACPICA_INITIALIZED) {
}
/*
* Set acpi-status to 13 if acpica has been initialized successfully.
* This indicates that acpica is up and running. This variable name
* and value were chosen in order to remain compatible with acpi_intp.
*/
ACPI_BOOT_BOOTCONF) : 0);
/* Mark acpica subsystem as fully initialized. */
if (ACPI_SUCCESS(status) &&
}
return (status);
}
/*
* SCI handling
*/
{
/*
* Make sure user options are processed,
* then return error if ACPI CA has been
* disabled or system is not running in ACPI
* and won't need/understand SCI
*/
return (AE_ERROR);
/*
* according to Intel ACPI developers, SCI
* unless otherwise directed by overrides.
*/
/* get the SCI from the FADT */
return (AE_ERROR);
/* search for ISOs that modify it */
/* if we don't find a MADT, that's OK; no ISOs then */
return (AE_OK);
ACPI_MADT_TRIGGER_MASK) >> 2;
}
break;
}
/* advance to next entry */
}
/*
* One more check; if ISO said "conform", revert to default
*/
return (AE_OK);
}
/*
* Call-back function used for _PRW initialization. For every
* device node that has a _PRW method, evaluate, parse, and do
* AcpiSetupGpeForWake().
*/
static ACPI_STATUS
void *ctxp,
void **rvpp)
{
/*
* Attempt to evaluate _PRW object.
* If no valid object is found, return quietly, since not all
* devices have _PRW objects.
*/
if (ACPI_FAILURE(status))
goto done;
if (ACPI_FAILURE(status))
goto done;
(void) AcpiSetupGpeForWake(devhdl,
done:
return (AE_OK);
}
/*
* Sets ACPI wake state for device referenced by dip.
* If level is S0 (0), disables wake event; otherwise,
* enables wake event which will wake system from level.
*/
static int
{
int rv;
/*
* initialize these early so we can use a common
* exit point below
*/
rv = 0;
/*
* Attempt to get a handle to a corresponding ACPI object.
* If no object is found, return quietly, since not all
* devices have corresponding ACPI objects.
*/
if (ACPI_FAILURE(status)) {
#ifdef DEBUG
#endif
goto done;
}
/*
* ACPI3.0 7.2.1: only use the _PSW method if OSPM does not support
* _DSW or if the _DSW method is not present.
*
* _DSW arguments:
* args[1] - Target system state
* args[2] - Target device state
*/
if (status == AE_NOT_FOUND) {
if (status != AE_NOT_FOUND) {
"!_PSW failure %d for device %s",
}
}
} else {
}
}
/*
* Attempt to evaluate _PRW object.
* If no valid object is found, return quietly, since not all
* devices have _PRW objects.
*/
if (ACPI_FAILURE(status))
goto done;
if (ACPI_FAILURE(status))
goto done;
rv = -1;
if (level == 0) {
if (ACPI_FAILURE(status))
goto done;
if (ACPI_SUCCESS(status)) {
if (ACPI_FAILURE(status))
goto done;
}
}
rv = 0;
done:
return (rv);
}
static ACPI_STATUS
struct parsed_prw *p_prw)
{
return (AE_NULL_OBJECT);
return (AE_TYPE);
/* fetch the lowest wake level from the _PRW */
/*
* process the GPE description
*/
case ACPI_TYPE_INTEGER:
break;
case ACPI_TYPE_PACKAGE:
return (AE_TYPE);
return (AE_NULL_OBJECT);
break;
default:
return (AE_TYPE);
}
return (AE_OK);
}
/*
* kstat access to a limited set of ACPI propertis
*/
static void
{
/*
* Create a small set of named kstats; just return in the rare
* case of a failure, * in which case, the kstats won't be present.
*/
return;
/*
* initialize kstat 'S3' to reflect the presence of \_S3 in
* the ACPI namespace (1 = present, 0 = not present)
*/
knp++; /* advance to next named kstat */
/*
* initialize kstat 'preferred_pm_profile' to the value
* contained in the (always present) FADT
*/
/*
* install the named kstats
*/
}
/*
* Attempt to save the current ACPI settings (_CRS) for the device
* which corresponds to the supplied devinfo node. The settings are
* saved as a property on the dip. If no ACPI object is found to be
* associated with the devinfo node, no action is taken and no error
* is reported.
*/
void
{
int ret;
return;
}
/*
* If the supplied devinfo node has an ACPI settings property attached,
* restore them to the associated ACPI device using _SRS. The property
* is deleted from the devinfo node afterward.
*/
void
{
return;
return;
}
void
acpi_reset_system(void)
{
int ten;
/*
* Wait up to 500 milliseconds for AcpiReset() to make its
* way.
*/
ten = 50000;
while (ten-- > 0)
tenmicrosec();
}
}