summaryrefslogtreecommitdiff
path: root/usr/src/uts/intel
diff options
context:
space:
mode:
authorJohn Sonnenschein <johns@joyent.com>2011-12-15 22:43:18 +0000
committerJohn Sonnenschein <johns@joyent.com>2011-12-15 22:43:18 +0000
commitc4aa323138d7633d35c7cbf4123aa100970a91f9 (patch)
tree596fe3d0c3374835bf0e2e1d31e3ea8f3659422a /usr/src/uts/intel
parent73c531dd5303a633bcaaf609c6eeb2554096b478 (diff)
parentf9b22ee9e48b04a9ef01426e92a13c5b164c0763 (diff)
downloadillumos-joyent-c4aa323138d7633d35c7cbf4123aa100970a91f9.tar.gz
Merge branch 'master' into gcc4
Diffstat (limited to 'usr/src/uts/intel')
-rw-r--r--usr/src/uts/intel/io/acpica/acpica.c159
-rw-r--r--usr/src/uts/intel/io/acpica/acpica_ec.c568
-rw-r--r--usr/src/uts/intel/io/acpica/osl.c2
-rw-r--r--usr/src/uts/intel/sys/acpi/platform/acsolaris.h4
4 files changed, 510 insertions, 223 deletions
diff --git a/usr/src/uts/intel/io/acpica/acpica.c b/usr/src/uts/intel/io/acpica/acpica.c
index 9c9c73dc03..999002f5c3 100644
--- a/usr/src/uts/intel/io/acpica/acpica.c
+++ b/usr/src/uts/intel/io/acpica/acpica.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, Joyent, Inc. All rights reserved.
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
/*
* Copyright (c) 2009, Intel Corporation.
@@ -65,7 +66,22 @@ static struct modlinkage modlinkage = {
* Local prototypes
*/
+struct parsed_prw {
+ ACPI_HANDLE prw_gpeobj;
+ int prw_gpebit;
+ int prw_level;
+};
+
static void acpica_init_kstats(void);
+static ACPI_STATUS acpica_init_PRW(
+ ACPI_HANDLE hdl,
+ UINT32 lvl,
+ void *ctxp,
+ void **rvpp);
+
+static ACPI_STATUS acpica_parse_PRW(
+ ACPI_BUFFER *prw_buf,
+ struct parsed_prw *prw);
/*
* Local data
@@ -166,7 +182,11 @@ _fini(void)
}
/*
- * Install acpica-provided address-space handlers
+ * 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
acpica_install_handlers()
@@ -200,6 +220,13 @@ acpica_install_handlers()
rv = AE_ERROR;
}
+ if (AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
+ ACPI_ADR_SPACE_DATA_TABLE,
+ ACPI_DEFAULT_HANDLER, NULL, NULL) != AE_OK) {
+ cmn_err(CE_WARN, "!acpica: no default handler for"
+ " Data Table");
+ rv = AE_ERROR;
+ }
return (rv);
}
@@ -421,12 +448,23 @@ acpica_init()
/* do after AcpiEnableSubsystem() so GPEs are initialized */
acpica_ec_init(); /* initialize EC if present */
+ /* This runs all device _STA and _INI methods. */
if (ACPI_FAILURE(status = AcpiInitializeObjects(0)))
goto error;
acpica_init_state = ACPICA_INITIALIZED;
/*
+ * [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) AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+ UINT32_MAX, acpica_init_PRW, NULL, NULL, NULL);
+ (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.
@@ -539,6 +577,47 @@ acpica_get_sci(int *sci_irq, iflag_t *sci_flags)
}
/*
+ * Call-back function used for _PRW initialization. For every
+ * device node that has a _PRW method, evaluate, parse, and do
+ * AcpiSetupGpeForWake().
+ */
+static ACPI_STATUS
+acpica_init_PRW(
+ ACPI_HANDLE devhdl,
+ UINT32 depth,
+ void *ctxp,
+ void **rvpp)
+{
+ ACPI_STATUS status;
+ ACPI_BUFFER prw_buf;
+ struct parsed_prw prw;
+
+ prw_buf.Pointer = NULL;
+ prw_buf.Length = ACPI_ALLOCATE_BUFFER;
+
+ /*
+ * Attempt to evaluate _PRW object.
+ * If no valid object is found, return quietly, since not all
+ * devices have _PRW objects.
+ */
+ status = AcpiEvaluateObject(devhdl, "_PRW", NULL, &prw_buf);
+ if (ACPI_FAILURE(status))
+ goto done;
+ status = acpica_parse_PRW(&prw_buf, &prw);
+ if (ACPI_FAILURE(status))
+ goto done;
+
+ (void) AcpiSetupGpeForWake(devhdl,
+ prw.prw_gpeobj, prw.prw_gpebit);
+
+done:
+ if (prw_buf.Pointer != NULL)
+ AcpiOsFree(prw_buf.Pointer);
+
+ 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.
@@ -547,12 +626,12 @@ static int
acpica_ddi_setwake(dev_info_t *dip, int level)
{
ACPI_STATUS status;
- ACPI_HANDLE devobj, gpeobj;
- ACPI_OBJECT *prw, *gpe;
+ ACPI_HANDLE devobj;
ACPI_BUFFER prw_buf;
ACPI_OBJECT_LIST arglist;
ACPI_OBJECT args[3];
- int gpebit, pwr_res_count, prw_level, rv;
+ struct parsed_prw prw;
+ int rv;
/*
* initialize these early so we can use a common
@@ -627,12 +706,49 @@ acpica_ddi_setwake(dev_info_t *dip, int level)
* devices have _PRW objects.
*/
status = AcpiEvaluateObject(devobj, "_PRW", NULL, &prw_buf);
- prw = prw_buf.Pointer;
- if (ACPI_FAILURE(status) || prw_buf.Length == 0 || prw == NULL ||
- prw->Type != ACPI_TYPE_PACKAGE || prw->Package.Count < 2 ||
- prw->Package.Elements[1].Type != ACPI_TYPE_INTEGER) {
+ if (ACPI_FAILURE(status))
+ goto done;
+ status = acpica_parse_PRW(&prw_buf, &prw);
+ if (ACPI_FAILURE(status))
goto done;
+
+ rv = -1;
+ if (level == 0) {
+ status = AcpiDisableGpe(prw.prw_gpeobj, prw.prw_gpebit);
+ if (ACPI_FAILURE(status))
+ goto done;
+ } else if (prw.prw_level >= level) {
+ status = AcpiSetGpeWakeMask(prw.prw_gpeobj, prw.prw_gpebit,
+ ACPI_GPE_ENABLE);
+ if (ACPI_SUCCESS(status)) {
+ status = AcpiEnableGpe(prw.prw_gpeobj, prw.prw_gpebit);
+ if (ACPI_FAILURE(status))
+ goto done;
+ }
}
+ rv = 0;
+done:
+ if (prw_buf.Pointer != NULL)
+ AcpiOsFree(prw_buf.Pointer);
+ return (rv);
+}
+
+static ACPI_STATUS
+acpica_parse_PRW(
+ ACPI_BUFFER *prw_buf,
+ struct parsed_prw *p_prw)
+{
+ ACPI_HANDLE gpeobj;
+ ACPI_OBJECT *prw, *gpe;
+ int gpebit, prw_level;
+
+ if (prw_buf->Length == 0 || prw_buf->Pointer == NULL)
+ return (AE_NULL_OBJECT);
+
+ prw = prw_buf->Pointer;
+ if (prw->Type != ACPI_TYPE_PACKAGE || prw->Package.Count < 2 ||
+ prw->Package.Elements[1].Type != ACPI_TYPE_INTEGER)
+ return (AE_TYPE);
/* fetch the lowest wake level from the _PRW */
prw_level = prw->Package.Elements[1].Integer.Value;
@@ -649,30 +765,21 @@ acpica_ddi_setwake(dev_info_t *dip, int level)
gpe = &prw->Package.Elements[0];
if (gpe->Package.Count != 2 ||
gpe->Package.Elements[1].Type != ACPI_TYPE_INTEGER)
- goto done;
+ return (AE_TYPE);
gpeobj = gpe->Package.Elements[0].Reference.Handle;
gpebit = gpe->Package.Elements[1].Integer.Value;
if (gpeobj == NULL)
- goto done;
+ return (AE_NULL_OBJECT);
+ break;
default:
- goto done;
+ return (AE_TYPE);
}
- rv = -1;
- if (level == 0) {
- if (ACPI_FAILURE(AcpiDisableGpe(gpeobj, gpebit)))
- goto done;
- } else if (prw_level >= level) {
- if (ACPI_SUCCESS(
- AcpiSetGpeWakeMask(gpeobj, gpebit, ACPI_GPE_ENABLE)))
- if (ACPI_FAILURE(AcpiEnableGpe(gpeobj, gpebit)))
- goto done;
- }
- rv = 0;
-done:
- if (prw_buf.Pointer != NULL)
- AcpiOsFree(prw_buf.Pointer);
- return (rv);
+ p_prw->prw_gpeobj = gpeobj;
+ p_prw->prw_gpebit = gpebit;
+ p_prw->prw_level = prw_level;
+
+ return (AE_OK);
}
/*
diff --git a/usr/src/uts/intel/io/acpica/acpica_ec.c b/usr/src/uts/intel/io/acpica/acpica_ec.c
index 2de53b578c..e76c87e273 100644
--- a/usr/src/uts/intel/io/acpica/acpica_ec.c
+++ b/usr/src/uts/intel/io/acpica/acpica_ec.c
@@ -22,6 +22,7 @@
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright 2011 Joyent, Inc. All rights reserved.
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
/*
* Solaris x86 ACPI CA Embedded Controller operation region handler
@@ -42,12 +43,6 @@
#include <sys/acpica.h>
/*
- * Internal prototypes
- */
-static int ec_wait_ibf_clear(int sc_addr);
-static int ec_wait_obf_set(int sc_addr);
-
-/*
* EC status bits
* Low to high
* Output buffer full?
@@ -80,11 +75,13 @@ static int ec_wait_obf_set(int sc_addr);
/*
* EC softstate
*/
-struct ec_softstate {
- uint8_t ec_ok; /* != 0 when EC handler is attached */
+static struct ec_softstate {
+ uint8_t ec_ok; /* != 0 if we have ec_base, ec_sc */
uint16_t ec_base; /* base of EC I/O port - data */
- uint16_t ec_sc; /* EC status/command */
- ACPI_HANDLE ec_obj; /* handle to ACPI object for EC */
+ uint16_t ec_sc; /* EC status/command */
+ ACPI_HANDLE ec_dev_hdl; /* EC device handle */
+ ACPI_HANDLE ec_gpe_hdl; /* GPE info */
+ ACPI_INTEGER ec_gpe_bit;
kmutex_t ec_mutex; /* serialize access to EC */
} ec;
@@ -101,6 +98,12 @@ typedef struct io_port_des {
} io_port_des_t;
/*
+ * Patchable to ignore an ECDT, in case using that
+ * causes problems on someone's system.
+ */
+int ec_ignore_ecdt = 0;
+
+/*
* Patchable timeout values for EC input-buffer-full-clear
* and output-buffer-full-set. These are in 10uS units and
* default to 1 second.
@@ -109,14 +112,43 @@ int ibf_clear_timeout = 100000;
int obf_set_timeout = 100000;
/*
- * ACPI CA address space handler interface functions
+ * ACPI CA EC address space handler support functions
*/
-/*ARGSUSED*/
-static ACPI_STATUS
-ec_setup(ACPI_HANDLE reg, UINT32 func, void *context, void **ret)
+
+/*
+ * Busy-wait for IBF to clear
+ * return < 0 for time out, 0 for no error
+ */
+static int
+ec_wait_ibf_clear(int sc_addr)
{
+ int cnt;
- return (AE_OK);
+ cnt = ibf_clear_timeout;
+ while (inb(sc_addr) & EC_IBF) {
+ if (cnt-- <= 0)
+ return (-1);
+ drv_usecwait(10);
+ }
+ return (0);
+}
+
+/*
+ * Busy-wait for OBF to set
+ * return < 0 for time out, 0 for no error
+ */
+static int
+ec_wait_obf_set(int sc_addr)
+{
+ int cnt;
+
+ cnt = obf_set_timeout;
+ while (!(inb(sc_addr) & EC_OBF)) {
+ if (cnt-- <= 0)
+ return (-1);
+ drv_usecwait(10);
+ }
+ return (0);
}
/*
@@ -172,7 +204,7 @@ ec_rd(int addr)
* Only called from ec_handler(), which validates ec_ok
*/
static int
-ec_wr(int addr, uint8_t *val)
+ec_wr(int addr, uint8_t val)
{
int cnt;
uint8_t sc;
@@ -206,7 +238,7 @@ ec_wr(int addr, uint8_t *val)
return (-1);
}
- outb(ec.ec_base, *val); /* write data */
+ outb(ec.ec_base, val); /* write data */
if (ec_wait_ibf_clear(ec.ec_sc) < 0) {
cmn_err(CE_NOTE, "!ec_wr:3: timed-out waiting "
"for IBF to clear");
@@ -248,12 +280,16 @@ ec_query(void)
return (rv);
}
+/*
+ * ACPI CA EC address space handler
+ * Requires: ec.ec_sc, ec.ec_base
+ */
static ACPI_STATUS
ec_handler(UINT32 func, ACPI_PHYSICAL_ADDRESS addr, UINT32 width,
- ACPI_INTEGER *val, void *context, void *regcontext)
+ UINT64 *val, void *context, void *regcontext)
{
_NOTE(ARGUNUSED(context, regcontext))
- int tmp;
+ int i, tw, tmp;
/* Guard against unexpected invocation */
if (ec.ec_ok == 0)
@@ -263,52 +299,71 @@ ec_handler(UINT32 func, ACPI_PHYSICAL_ADDRESS addr, UINT32 width,
* Add safety checks for BIOSes not strictly compliant
* with ACPI spec
*/
- if (((width % 8) != 0) || (width > 8)) {
+ if ((width % 8) != 0) {
cmn_err(CE_NOTE, "!ec_handler: invalid width %d", width);
- return (AE_ERROR);
+ return (AE_BAD_PARAMETER);
+ }
+ if (val == NULL) {
+ cmn_err(CE_NOTE, "!ec_handler: NULL value pointer");
+ return (AE_BAD_PARAMETER);
}
- switch (func) {
- case ACPI_READ:
- tmp = ec_rd(addr);
- if (tmp < 0)
- return (AE_ERROR);
- *val = tmp;
- break;
- case ACPI_WRITE:
- if (ec_wr(addr, (uint8_t *)val) < 0)
- return (AE_ERROR);
- break;
- default:
- return (AE_ERROR);
+ while (width > 0) {
+
+ /* One UINT64 *val at a time. */
+ tw = min(width, 64);
+
+ if (func == ACPI_READ)
+ *val = 0;
+
+ /* Do I/O of up to 64 bits */
+ for (i = 0; i < tw; i += 8, addr++) {
+ switch (func) {
+ case ACPI_READ:
+ tmp = ec_rd(addr);
+ if (tmp < 0)
+ return (AE_ERROR);
+ *val |= ((UINT64)tmp) << i;
+ break;
+ case ACPI_WRITE:
+ tmp = ((*val) >> i) & 0xFF;
+ if (ec_wr(addr, (uint8_t)tmp) < 0)
+ return (AE_ERROR);
+ break;
+ default:
+ return (AE_ERROR);
+ }
+ }
+ val++;
+ width -= tw;
}
return (AE_OK);
}
-
+/*
+ * Called via taskq entry enqueued by ec_gpe_handler,
+ * which validates ec_ok
+ */
static void
ec_gpe_callback(void *ctx)
{
_NOTE(ARGUNUSED(ctx))
-
char query_str[5];
int query;
if (!(inb(ec.ec_sc) & EC_SCI))
- return;
-
- if (ec.ec_ok == 0) {
- cmn_err(CE_WARN, "!ec_gpe_callback: EC handler unavailable");
- return;
- }
+ goto out;
query = ec_query();
- if (query >= 0) {
- (void) snprintf(query_str, 5, "_Q%02X", (uint8_t)query);
- (void) AcpiEvaluateObject(ec.ec_obj, query_str, NULL, NULL);
- }
+ if (query < 0)
+ goto out;
+
+ (void) snprintf(query_str, 5, "_Q%02X", (uint8_t)query);
+ (void) AcpiEvaluateObject(ec.ec_dev_hdl, query_str, NULL, NULL);
+out:
+ AcpiFinishGpe(ec.ec_gpe_hdl, ec.ec_gpe_bit);
}
static UINT32
@@ -318,75 +373,129 @@ ec_gpe_handler(ACPI_HANDLE GpeDevice, UINT32 GpeNumber, void *ctx)
_NOTE(ARGUNUSED(GpeNumber))
_NOTE(ARGUNUSED(ctx))
+ /*
+ * With ec_ok==0, we will not install a GPE handler,
+ * so this is just paranoia. But if this were to
+ * happen somehow, don't add the taskq entry, and
+ * tell the caller we're done with this GPE call.
+ */
+ if (ec.ec_ok == 0)
+ return (ACPI_REENABLE_GPE);
+
AcpiOsExecute(OSL_GPE_HANDLER, ec_gpe_callback, NULL);
+
+ /*
+ * Returning zero tells the ACPI system that we will
+ * handle this event asynchronously.
+ */
return (0);
}
/*
- * Busy-wait for IBF to clear
- * return < 0 for time out, 0 for no error
+ * Some systems describe the EC using an "ECDT" (table).
+ * If we find one use it (unless ec_ignore_ecdt is set).
+ * Modern systems don't provide an ECDT.
*/
-static int
-ec_wait_ibf_clear(int sc_addr)
+static ACPI_STATUS
+ec_probe_ecdt(void)
{
- int cnt;
+ ACPI_TABLE_HEADER *th;
+ ACPI_TABLE_ECDT *ecdt;
+ ACPI_HANDLE dev_hdl;
+ ACPI_STATUS status;
+
+ status = AcpiGetTable(ACPI_SIG_ECDT, 1, &th);
+#ifndef DEBUG
+ if (status == AE_NOT_FOUND)
+ return (status);
+#endif
+ if (ACPI_FAILURE(status)) {
+ cmn_err(CE_NOTE, "!acpica: ECDT not found");
+ return (status);
+ }
+ if (ec_ignore_ecdt) {
+ /* pretend it was not found */
+ cmn_err(CE_NOTE, "!acpica: ECDT ignored");
+ return (AE_NOT_FOUND);
+ }
- cnt = ibf_clear_timeout;
- while (inb(sc_addr) & EC_IBF) {
- if (cnt-- <= 0)
- return (-1);
- drv_usecwait(10);
+ ecdt = (ACPI_TABLE_ECDT *)th;
+ if (ecdt->Control.BitWidth != 8 ||
+ ecdt->Data.BitWidth != 8) {
+ cmn_err(CE_NOTE, "!acpica: bad ECDT I/O width");
+ return (AE_BAD_VALUE);
}
+ status = AcpiGetHandle(NULL, (char *)ecdt->Id, &dev_hdl);
+ if (ACPI_FAILURE(status)) {
+ cmn_err(CE_NOTE, "!acpica: no ECDT device handle");
+ return (status);
+ }
+
+ /*
+ * Success. Save info for attach.
+ */
+ ec.ec_base = ecdt->Data.Address;
+ ec.ec_sc = ecdt->Control.Address;
+ ec.ec_dev_hdl = dev_hdl;
+ ec.ec_gpe_hdl = NULL;
+ ec.ec_gpe_bit = ecdt->Gpe;
+ ec.ec_ok = 1;
+
+#ifdef DEBUG
+ cmn_err(CE_NOTE, "!acpica:ec_probe_ecdt: success");
+#endif
return (0);
}
/*
- * Busy-wait for OBF to set
- * return < 0 for time out, 0 for no error
+ * Called from AcpiWalkDevices() when an EC device is found
*/
-static int
-ec_wait_obf_set(int sc_addr)
+static ACPI_STATUS
+ec_find(ACPI_HANDLE obj, UINT32 nest, void *context, void **rv)
{
- int cnt;
+ _NOTE(ARGUNUSED(nest, rv))
- cnt = obf_set_timeout;
- while (!(inb(sc_addr) & EC_OBF)) {
- if (cnt-- <= 0)
- return (-1);
- drv_usecwait(10);
- }
- return (0);
+ *((ACPI_HANDLE *)context) = obj;
+ return (AE_OK);
}
-
-
/*
- * Called from AcpiWalkDevices() when an EC device is found
+ * Normal way to get the details about the EC,
+ * by searching the name space.
*/
static ACPI_STATUS
-acpica_install_ec(ACPI_HANDLE obj, UINT32 nest, void *context, void **rv)
+ec_probe_ns(void)
{
- _NOTE(ARGUNUSED(nest, context, rv))
-
- int status, i;
+ ACPI_HANDLE dev_hdl;
ACPI_BUFFER buf, crs;
- ACPI_INTEGER gpe;
- int io_port_cnt;
-
- /*
- * Save the one EC object we have
- */
- ec.ec_obj = obj;
+ ACPI_OBJECT *gpe_obj;
+ ACPI_HANDLE gpe_hdl;
+ ACPI_INTEGER gpe_bit;
+ ACPI_STATUS status;
+ int i, io_port_cnt;
+ uint16_t ec_sc, ec_base;
+
+ dev_hdl = NULL;
+ (void) AcpiGetDevices("PNP0C09", &ec_find, (void *)&dev_hdl, NULL);
+ if (dev_hdl == NULL) {
+#ifdef DEBUG
+ /* Not an error, just no EC on this machine. */
+ cmn_err(CE_WARN, "!acpica:ec_probe_ns: "
+ "PNP0C09 not found");
+#endif
+ return (AE_NOT_FOUND);
+ }
/*
* Find ec_base and ec_sc addresses
*/
crs.Length = ACPI_ALLOCATE_BUFFER;
- if (ACPI_FAILURE(AcpiEvaluateObjectTyped(obj, "_CRS", NULL, &crs,
- ACPI_TYPE_BUFFER))) {
- cmn_err(CE_WARN, "!acpica_install_ec: _CRS object evaluate"
- "failed");
- return (AE_OK);
+ status = AcpiEvaluateObjectTyped(dev_hdl, "_CRS", NULL, &crs,
+ ACPI_TYPE_BUFFER);
+ if (ACPI_FAILURE(status)) {
+ cmn_err(CE_WARN, "!acpica:ec_probe_ns: "
+ "_CRS object evaluate failed");
+ return (status);
}
for (i = 0, io_port_cnt = 0;
@@ -399,13 +508,13 @@ acpica_install_ec(ACPI_HANDLE obj, UINT32 nest, void *context, void **rv)
continue;
io_port = (io_port_des_t *)tmp;
/*
- * Assuming first port is ec_base and second is ec_sc
+ * first port is ec_base and second is ec_sc
*/
- if (io_port_cnt)
- ec.ec_sc = (io_port->min_base_hi << 8) |
+ if (io_port_cnt == 0)
+ ec_base = (io_port->min_base_hi << 8) |
io_port->min_base_lo;
- else
- ec.ec_base = (io_port->min_base_hi << 8) |
+ if (io_port_cnt == 1)
+ ec_sc = (io_port->min_base_hi << 8) |
io_port->min_base_lo;
io_port_cnt++;
@@ -415,152 +524,219 @@ acpica_install_ec(ACPI_HANDLE obj, UINT32 nest, void *context, void **rv)
i += 7;
}
AcpiOsFree(crs.Pointer);
-
- /*
- * Drain the EC data register if something is left over from
- * legacy mode
- */
- if (inb(ec.ec_sc) & EC_OBF) {
-#ifndef DEBUG
- inb(ec.ec_base); /* read and discard value */
-#else
- cmn_err(CE_NOTE, "!EC had something: 0x%x\n", inb(ec.ec_base));
-#endif
+ if (io_port_cnt < 2) {
+ cmn_err(CE_WARN, "!acpica:ec_probe_ns: "
+ "_CRS parse failed");
+ return (AE_BAD_VALUE);
}
/*
- * Get GPE
+ * Get the GPE info.
*/
buf.Length = ACPI_ALLOCATE_BUFFER;
- /*
- * grab contents of GPE object
- */
- if (ACPI_FAILURE(AcpiEvaluateObjectTyped(obj, "_GPE", NULL, &buf,
- ACPI_TYPE_INTEGER))) {
- /* emit a warning but ignore the error */
- cmn_err(CE_WARN, "!acpica_install_ec: _GPE object evaluate"
- "failed");
- gpe = -1;
- } else {
- gpe = ((ACPI_OBJECT *)buf.Pointer)->Integer.Value;
- AcpiOsFree(buf.Pointer);
+ status = AcpiEvaluateObject(dev_hdl, "_GPE", NULL, &buf);
+ if (ACPI_FAILURE(status)) {
+ cmn_err(CE_WARN, "!acpica:ec_probe_ns: "
+ "_GPE object evaluate");
+ return (status);
}
-
+ gpe_obj = (ACPI_OBJECT *)buf.Pointer;
/*
- * Initialize EC mutex here
+ * process the GPE description
*/
- mutex_init(&ec.ec_mutex, NULL, MUTEX_DRIVER, NULL);
+ switch (gpe_obj->Type) {
+ case ACPI_TYPE_INTEGER:
+ gpe_hdl = NULL;
+ gpe_bit = gpe_obj->Integer.Value;
+ break;
+ case ACPI_TYPE_PACKAGE:
+ if (gpe_obj->Package.Count != 2)
+ goto bad_gpe;
+ gpe_obj = gpe_obj->Package.Elements;
+ if (gpe_obj[1].Type != ACPI_TYPE_INTEGER)
+ goto bad_gpe;
+ gpe_hdl = gpe_obj[0].Reference.Handle;
+ gpe_bit = gpe_obj[1].Integer.Value;
+ break;
+ bad_gpe:
+ default:
+ status = AE_BAD_VALUE;
+ break;
+ }
+ AcpiOsFree(buf.Pointer);
+ if (ACPI_FAILURE(status)) {
+ cmn_err(CE_WARN, "!acpica:ec_probe_ns: "
+ "_GPE parse failed");
+ return (status);
+ }
/*
- * Assume the EC handler is available now; the next attempt
- * to install the address space handler may actually need
- * to use the EC handler to install it (chicken/egg)
+ * Success. Save info for attach.
*/
+ ec.ec_base = ec_base;
+ ec.ec_sc = ec_sc;
+ ec.ec_dev_hdl = dev_hdl;
+ ec.ec_gpe_hdl = gpe_hdl;
+ ec.ec_gpe_bit = gpe_bit;
ec.ec_ok = 1;
- if (AcpiInstallAddressSpaceHandler(obj,
- ACPI_ADR_SPACE_EC, &ec_handler, &ec_setup, NULL) != AE_OK) {
- cmn_err(CE_WARN, "!acpica: failed to add EC handler\n");
- ec.ec_ok = 0; /* EC handler failed to install */
- membar_producer(); /* force ec_ok store before mutex_destroy */
- mutex_destroy(&ec.ec_mutex);
- return (AE_ERROR);
- }
+#ifdef DEBUG
+ cmn_err(CE_NOTE, "!acpica:ec_probe_ns: success");
+#endif
+ return (0);
+}
+
+/*
+ * Setup the Embedded Controller (EC) address space handler.
+ * Entered only if one of the EC probe methods found an EC.
+ */
+static void
+ec_init(void)
+{
+ ACPI_STATUS rc;
+ int x;
+
+ /* paranoia */
+ if (ec.ec_ok == 0)
+ return;
/*
- * In case the EC handler was successfully installed but no
- * GPE was found, return sucess; a warning was emitted above
+ * Drain the EC data register if something is left over from
+ * legacy mode
*/
- if (gpe < 0)
- return (AE_OK);
+ if (inb(ec.ec_sc) & EC_OBF) {
+ x = inb(ec.ec_base); /* read and discard value */
+#ifdef DEBUG
+ cmn_err(CE_NOTE, "!EC had something: 0x%x", x);
+#endif
+ }
/*
- * Have a valid EC GPE; enable it
+ * Install an "EC address space" handler.
+ *
+ * This call does a name space walk under the passed
+ * object looking for child objects with an EC space
+ * region for which to install this handler. Using
+ * the ROOT object makes sure we find them all.
+ *
+ * XXX: Some systems return an error from this call
+ * after a partial success, i.e. where the NS walk
+ * installs on some nodes and fails on other nodes.
+ * In such cases, disabling the EC and GPE handlers
+ * makes things worse, so just report the error and
+ * leave the EC handler enabled.
+ *
+ * At one point, it seemed that doing this part of
+ * EC setup earlier may help, which is why this is
+ * now a separate function from ec_attach. Someone
+ * needs to figure our why some systems give us an
+ * error return from this call. (TODO)
*/
- if ((status = AcpiInstallGpeHandler(NULL, gpe, ACPI_GPE_EDGE_TRIGGERED,
- ec_gpe_handler, NULL)) != AE_OK) {
- cmn_err(CE_WARN, "!acpica: failed to install gpe handler status"
- " = %d", status);
- /*
- * don't return an error here - GPE won't work but the EC
- * handler may be OK
- */
+ rc = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
+ ACPI_ADR_SPACE_EC, &ec_handler, NULL, NULL);
+ if (rc != AE_OK) {
+ cmn_err(CE_WARN, "!acpica:ec_init: "
+ "install AS handler, rc=0x%x", rc);
+ return;
}
-
- (void) AcpiEnableGpe(NULL, gpe);
-
- return (AE_OK);
+#ifdef DEBUG
+ cmn_err(CE_NOTE, "!acpica:ec_init: success");
+#endif
}
-#ifdef DEBUG
-/*ARGSUSED*/
-static ACPI_STATUS
-acpica_install_smbus_v1(ACPI_HANDLE obj, UINT32 nest, void *context, void **rv)
+/*
+ * Attach the EC General-Purpose Event (GPE) handler.
+ */
+static void
+ec_attach(void)
{
+ ACPI_STATUS rc;
- cmn_err(CE_NOTE, "!acpica: found an SMBC Version 1.0\n");
- return (AE_OK);
-}
+ /*
+ * Guard against call without probe results.
+ */
+ if (ec.ec_ok == 0) {
+ cmn_err(CE_WARN, "!acpica:ec_attach: "
+ "no EC device found");
+ return;
+ }
-/*ARGSUSED*/
-static ACPI_STATUS
-acpica_install_smbus_v2(ACPI_HANDLE obj, UINT32 nest, void *context, void **rv)
-{
+ /*
+ * Install the GPE handler and enable it.
+ */
+ rc = AcpiInstallGpeHandler(ec.ec_gpe_hdl, ec.ec_gpe_bit,
+ ACPI_GPE_EDGE_TRIGGERED, ec_gpe_handler, NULL);
+ if (rc != AE_OK) {
+ cmn_err(CE_WARN, "!acpica:ec_attach: "
+ "install GPE handler, rc=0x%x", rc);
+ goto errout;
+ }
- cmn_err(CE_NOTE, "!acpica: found an SMBC Version 2.0\n");
- return (AE_OK);
-}
-#endif /* DEBUG */
+ rc = AcpiEnableGpe(ec.ec_gpe_hdl, ec.ec_gpe_bit);
+ if (rc != AE_OK) {
+ cmn_err(CE_WARN, "!acpica:ec_attach: "
+ "enable GPE handler, rc=0x%x", rc);
+ goto errout;
+ }
-#ifdef NOTYET
-static void
-prgas(ACPI_GENERIC_ADDRESS *gas)
-{
- cmn_err(CE_CONT, "gas: %d %d %d %d %lx",
- gas->AddressSpaceId, gas->RegisterBitWidth, gas->RegisterBitOffset,
- gas->AccessWidth, (long)gas->Address);
+#ifdef DEBUG
+ cmn_err(CE_NOTE, "!acpica:ec_attach: success");
+#endif
+ return;
+
+errout:
+ AcpiRemoveGpeHandler(ec.ec_gpe_hdl, ec.ec_gpe_bit,
+ ec_gpe_handler);
}
+/*
+ * System Management Bus Controller (SMBC)
+ * These also go through the EC.
+ * (not yet supported)
+ */
static void
-acpica_probe_ecdt()
+smbus_attach(void)
{
- EC_BOOT_RESOURCES *ecdt;
-
+#ifdef DEBUG
+ ACPI_HANDLE obj;
- if (AcpiGetTable("ECDT", 1, (ACPI_TABLE_HEADER **) &ecdt) != AE_OK) {
- cmn_err(CE_NOTE, "!acpica: ECDT not found\n");
- return;
+ obj = NULL;
+ (void) AcpiGetDevices("ACPI0001", &ec_find, (void *)&obj, NULL);
+ if (obj != NULL) {
+ cmn_err(CE_NOTE, "!acpica: found an SMBC Version 1.0");
}
- cmn_err(CE_NOTE, "EcControl: ");
- prgas(&ecdt->EcControl);
-
- cmn_err(CE_NOTE, "EcData: ");
- prgas(&ecdt->EcData);
+ obj = NULL;
+ (void) AcpiGetDevices("ACPI0005", &ec_find, (void *)&obj, NULL);
+ if (obj != NULL) {
+ cmn_err(CE_NOTE, "!acpica: found an SMBC Version 2.0");
+ }
+#endif /* DEBUG */
}
-#endif /* NOTYET */
+/*
+ * Initialize the EC, if present.
+ */
void
acpica_ec_init(void)
{
-#ifdef NOTYET
+ ACPI_STATUS rc;
+
/*
- * Search the ACPI tables for an ECDT; if
- * found, use it to install an EC handler
+ * Initialize EC mutex here
*/
- acpica_probe_ecdt();
-#endif /* NOTYET */
-
- /* EC handler defaults to not available */
- ec.ec_ok = 0;
+ mutex_init(&ec.ec_mutex, NULL, MUTEX_DRIVER, NULL);
/*
- * General model is: use GetDevices callback to install
- * handler(s) when device is present.
+ * First search the ACPI tables for an ECDT, and
+ * if not found, search the name space for it.
*/
- (void) AcpiGetDevices("PNP0C09", &acpica_install_ec, NULL, NULL);
-#ifdef DEBUG
- (void) AcpiGetDevices("ACPI0001", &acpica_install_smbus_v1, NULL, NULL);
- (void) AcpiGetDevices("ACPI0005", &acpica_install_smbus_v2, NULL, NULL);
-#endif /* DEBUG */
+ rc = ec_probe_ecdt();
+ if (ACPI_FAILURE(rc))
+ rc = ec_probe_ns();
+ if (ACPI_SUCCESS(rc)) {
+ ec_init();
+ ec_attach();
+ }
+ smbus_attach();
}
diff --git a/usr/src/uts/intel/io/acpica/osl.c b/usr/src/uts/intel/io/acpica/osl.c
index 783db12211..d5bfab754f 100644
--- a/usr/src/uts/intel/io/acpica/osl.c
+++ b/usr/src/uts/intel/io/acpica/osl.c
@@ -713,7 +713,7 @@ AcpiOsGetThreadId(void)
* ACPI CA assumes that thread ID is castable to a pointer,
* so we use the current thread pointer.
*/
- return (ACPI_CAST_PTHREAD_T ((uintptr_t)curthread));
+ return (ACPI_CAST_PTHREAD_T((uintptr_t)curthread));
}
/*
diff --git a/usr/src/uts/intel/sys/acpi/platform/acsolaris.h b/usr/src/uts/intel/sys/acpi/platform/acsolaris.h
index d48d1a8fed..b0cd8bfcf3 100644
--- a/usr/src/uts/intel/sys/acpi/platform/acsolaris.h
+++ b/usr/src/uts/intel/sys/acpi/platform/acsolaris.h
@@ -19,6 +19,7 @@
* CDDL HEADER END
*/
/*
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -36,6 +37,9 @@ extern "C" {
#include <sys/cpu.h>
#include <sys/thread.h>
+/* Function name used for debug output. */
+#define ACPI_GET_FUNCTION_NAME __func__
+
uint32_t __acpi_acquire_global_lock(void *);
uint32_t __acpi_release_global_lock(void *);
void __acpi_wbinvd(void);