changeset 10394:5f92fec873b0

PSARC 2009/104 Hot-Plug Support for ACPI-based Systems 6846955 Device tree creation and acpi virtual nexus driver for acpi based x86 systems 6849408 Device matching rule in ppm.conf is not flexible enough Contributed by Gerry Liu <jiang.liu@intel.com>
author Michael Corcoran <Michael.Corcoran@Sun.COM>
date Thu, 27 Aug 2009 16:35:32 -0700
parents f08ea7a5507b
children 95d68776d751
files usr/src/pkgdefs/SUNWcakr.i/prototype_com usr/src/pkgdefs/SUNWhea/prototype_i386 usr/src/uts/common/io/ppm/ppm_subr.c usr/src/uts/i86pc/Makefile.files usr/src/uts/i86pc/Makefile.i86pc.shared usr/src/uts/i86pc/Makefile.rules usr/src/uts/i86pc/acpidev/Makefile usr/src/uts/i86pc/acpinex/Makefile usr/src/uts/i86pc/io/acpi/acpidev/acpidev_container.c usr/src/uts/i86pc/io/acpi/acpidev/acpidev_cpu.c usr/src/uts/i86pc/io/acpi/acpidev/acpidev_device.c usr/src/uts/i86pc/io/acpi/acpidev/acpidev_drv.c usr/src/uts/i86pc/io/acpi/acpidev/acpidev_memory.c usr/src/uts/i86pc/io/acpi/acpidev/acpidev_resource.c usr/src/uts/i86pc/io/acpi/acpidev/acpidev_scope.c usr/src/uts/i86pc/io/acpi/acpidev/acpidev_util.c usr/src/uts/i86pc/io/acpi/acpinex/acpinex_drv.c usr/src/uts/i86pc/io/ppm.conf usr/src/uts/i86pc/os/ddi_impl.c usr/src/uts/i86pc/sys/Makefile usr/src/uts/i86pc/sys/acpidev.h usr/src/uts/i86pc/sys/acpidev_impl.h usr/src/uts/i86pc/sys/acpidev_rsc.h usr/src/uts/i86pc/sys/acpinex.h usr/src/uts/intel/io/acpica/namespace/nsxfname.c usr/src/uts/intel/io/acpica/osl.c usr/src/uts/intel/os/driver_aliases usr/src/uts/intel/os/name_to_major
diffstat 28 files changed, 6186 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/pkgdefs/SUNWcakr.i/prototype_com	Thu Aug 27 13:21:41 2009 -0700
+++ b/usr/src/pkgdefs/SUNWcakr.i/prototype_com	Thu Aug 27 16:35:32 2009 -0700
@@ -67,12 +67,14 @@
 f none platform/i86pc/kernel/drv/amd64/acpippm 755 root sys
 f none platform/i86pc/kernel/drv/acpippm 755 root sys
 f none platform/i86pc/kernel/drv/acpippm.conf 644 root sys
+f none platform/i86pc/kernel/drv/amd64/acpinex 755 root sys
 f none platform/i86pc/kernel/drv/amd64/ppm 755 root sys
 f none platform/i86pc/kernel/drv/amd64/isa 755 root sys
 f none platform/i86pc/kernel/drv/amd64/npe 755 root sys
 f none platform/i86pc/kernel/drv/amd64/pci 755 root sys
 f none platform/i86pc/kernel/drv/amd64/pit_beep 755 root sys
 f none platform/i86pc/kernel/drv/amd64/rootnex 755 root sys
+f none platform/i86pc/kernel/drv/acpinex 755 root sys
 f none platform/i86pc/kernel/drv/cpudrv 755 root sys
 f none platform/i86pc/kernel/drv/isa 755 root sys
 f none platform/i86pc/kernel/drv/npe 755 root sys
@@ -91,8 +93,10 @@
 f none platform/i86pc/kernel/mach/uppc 755 root sys
 d none platform/i86pc/kernel/misc 755 root sys
 d none platform/i86pc/kernel/misc/amd64 755 root sys
+f none platform/i86pc/kernel/misc/amd64/acpidev 755 root sys
 f none platform/i86pc/kernel/misc/amd64/gfx_private 755 root sys
 f none platform/i86pc/kernel/misc/amd64/pcie 755 root sys
+f none platform/i86pc/kernel/misc/acpidev 755 root sys
 f none platform/i86pc/kernel/misc/gfx_private 755 root sys
 f none platform/i86pc/kernel/misc/pcie 755 root sys
 f none platform/i86pc/kernel/unix 755 root sys
--- a/usr/src/pkgdefs/SUNWhea/prototype_i386	Thu Aug 27 13:21:41 2009 -0700
+++ b/usr/src/pkgdefs/SUNWhea/prototype_i386	Thu Aug 27 16:35:32 2009 -0700
@@ -120,6 +120,7 @@
 d none usr/platform/i86pc/include 755 root bin
 d none usr/platform/i86pc/include/sys 755 root bin
 f none usr/platform/i86pc/include/sys/asm_misc.h 644 root bin
+f none usr/platform/i86pc/include/sys/acpidev.h 644 root bin
 f none usr/platform/i86pc/include/sys/clock.h 644 root bin
 f none usr/platform/i86pc/include/sys/cram.h 644 root bin
 f none usr/platform/i86pc/include/sys/debug_info.h 644 root bin
--- a/usr/src/uts/common/io/ppm/ppm_subr.c	Thu Aug 27 13:21:41 2009 -0700
+++ b/usr/src/uts/common/io/ppm/ppm_subr.c	Thu Aug 27 16:35:32 2009 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * ppm driver subroutines
  */
@@ -399,6 +397,9 @@
 	char path[MAXNAMELEN];
 	ppm_domain_t *domp;
 	ppm_db_t *dbp;
+#ifdef	__x86
+	char *devtype = NULL;
+#endif	/* __x86 */
 
 	PPM_GET_PATHNAME(dip, path);
 	for (domp = ppm_domain_p; domp; domp = domp->next) {
@@ -411,6 +412,25 @@
 				if (dip == ddi_root_node() &&
 				    strcmp(dbp->name, "/") == 0)
 					return (domp);
+
+#ifdef	__x86
+				/*
+				 * Special rule to catch all CPU devices on x86.
+				 */
+				if (domp->model == PPMD_CPU &&
+				    strcmp(dbp->name, "/") == 0 &&
+				    ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
+				    DDI_PROP_DONTPASS, "device_type",
+				    &devtype) == DDI_SUCCESS) {
+					if (strcmp(devtype, "cpu") == 0) {
+						ddi_prop_free(devtype);
+						return (domp);
+					} else {
+						ddi_prop_free(devtype);
+					}
+				}
+#endif	/* __x86 */
+
 				if (ppm_match_devs(path, dbp) == 0)
 					return (domp);
 			}
--- a/usr/src/uts/i86pc/Makefile.files	Thu Aug 27 13:21:41 2009 -0700
+++ b/usr/src/uts/i86pc/Makefile.files	Thu Aug 27 16:35:32 2009 -0700
@@ -185,6 +185,7 @@
 			mp_platform_common.o hpet_acpi.o
 
 ACPI_DRV_OBJS	+= acpi_drv.o acpi_video.o
+ACPINEX_OBJS	+= acpinex_drv.o
 
 CPUDRV_OBJS	+= \
 	cpudrv.o \
@@ -193,6 +194,13 @@
 PPM_OBJS	+= ppm_subr.o ppm.o ppm_plat.o
 
 ACPIPPM_OBJS	+= acpippm.o acpisleep.o
+ACPIDEV_OBJS += acpidev_drv.o \
+	acpidev_scope.o acpidev_device.o \
+	acpidev_container.o \
+	acpidev_cpu.o \
+	acpidev_memory.o \
+	acpidev_resource.o \
+	acpidev_util.o
 
 ROOTNEX_OBJS += rootnex.o iommu_rscs.o dmar_acpi.o intel_iommu.o
 TZMON_OBJS	+= tzmon.o
--- a/usr/src/uts/i86pc/Makefile.i86pc.shared	Thu Aug 27 13:21:41 2009 -0700
+++ b/usr/src/uts/i86pc/Makefile.i86pc.shared	Thu Aug 27 16:35:32 2009 -0700
@@ -254,6 +254,7 @@
 DRV_KMODS	+= xsvc
 DRV_KMODS	+= tzmon
 DRV_KMODS	+= acpi_drv 
+DRV_KMODS	+= acpinex
 DRV_KMODS	+= ioat
 DRV_KMODS	+= fipe
 
@@ -301,6 +302,7 @@
 #	'Misc' Modules (/kernel/misc):
 #
 MISC_KMODS	+= gfx_private pcie
+MISC_KMODS	+= acpidev
 
 #
 #	'Dacf' modules (/kernel/dacf)
--- a/usr/src/uts/i86pc/Makefile.rules	Thu Aug 27 13:21:41 2009 -0700
+++ b/usr/src/uts/i86pc/Makefile.rules	Thu Aug 27 16:35:32 2009 -0700
@@ -71,6 +71,14 @@
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
 
+$(OBJS_DIR)/%.o:		$(UTSBASE)/i86pc/io/acpi/acpidev/%.c
+	$(COMPILE.c) -o $@ $<
+	$(CTFCONVERT_O)
+
+$(OBJS_DIR)/%.o:		$(UTSBASE)/i86pc/io/acpi/acpinex/%.c
+	$(COMPILE.c) -o $@ $<
+	$(CTFCONVERT_O)
+
 $(OBJS_DIR)/%.o:		$(UTSBASE)/i86pc/io/ioat/%.c
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
@@ -281,6 +289,12 @@
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/i86pc/io/fipe/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
+$(LINTS_DIR)/%.ln:		$(UTSBASE)/i86pc/io/acpi/acpidev/%.c
+	@($(LHEAD) $(LINT.c) $< $(LTAIL))
+
+$(LINTS_DIR)/%.ln:		$(UTSBASE)/i86pc/io/acpi/acpinex/%.c
+	@($(LHEAD) $(LINT.c) $< $(LTAIL))
+
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/i86pc/io/ioat/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/i86pc/acpidev/Makefile	Thu Aug 27 16:35:32 2009 -0700
@@ -0,0 +1,87 @@
+#
+# 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
+# or http://www.opensolaris.org/os/licensing.
+# 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
+#
+#
+# uts/i86pc/acpidev/Makefile
+#
+# Copyright (c) 2009, Intel Corporation.
+# All rights reserved.
+#
+#	This makefile drives the production of the ACPI device configuration
+#	kernel module.
+#
+#	i86pc architecture dependent
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE	= ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= acpidev
+OBJECTS		= $(ACPIDEV_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(ACPIDEV_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_PSM_MISC_DIR)/$(MODULE)
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/i86pc/Makefile.i86pc
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
+
+#
+# Depends on acpica ACPI CA interpreter
+#
+LDFLAGS		+= -dy -N misc/acpica
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS)
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+#
+#	Include common targets.
+#
+include $(UTSBASE)/i86pc/Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/i86pc/acpinex/Makefile	Thu Aug 27 16:35:32 2009 -0700
@@ -0,0 +1,87 @@
+#
+# 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
+# or http://www.opensolaris.org/os/licensing.
+# 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
+#
+#
+# uts/i86pc/acpinex/Makefile
+#
+# Copyright (c) 2009, Intel Corporation.
+# All rights reserved.
+#
+#	This makefile drives the production of the ACPI virtual nexus 
+#	kernel module.
+#
+#	intel platform dependent
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE	= ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= acpinex
+OBJECTS		= $(ACPINEX_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(ACPINEX_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_PSM_DRV_DIR)/$(MODULE)
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/i86pc/Makefile.i86pc
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
+
+#
+# Depends on acpica ACPI CA interpreter
+#
+LDFLAGS		+= -dy -N misc/acpica -N misc/acpidev
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS)
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+#
+#	Include common targets.
+#
+include $(UTSBASE)/i86pc/Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/i86pc/io/acpi/acpidev/acpidev_container.c	Thu Aug 27 16:35:32 2009 -0700
@@ -0,0 +1,281 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 (c) 2009, Intel Corporation.
+ * All rights reserved.
+ */
+
+/*
+ * There are three types of container objects defined in the ACPI Spec as below.
+ * PNP0A05: Generic Container Device
+ *   A device whose settings are totally controlled by its ACPI resource
+ *   information, and otherwise needs no device or bus-specific driver support.
+ *   This was originally known as Generic ISA Bus Device.
+ *   This ID should only be used for containers that do not produce resources
+ *   for consumption by child devices. Any system resources claimed by a PNP0A05
+ *   device's _CRS object must be consumed by the container itself.
+ * PNP0A06: Generic Container Device
+ *   This device behaves exactly the same as the PNP0A05 device.
+ *   This was originally known as Extended I/O Bus.
+ *   This ID should only be used for containers that do not produce resources
+ *   for consumption by child devices. Any system resources claimed by a PNP0A06
+ *   device's _CRS object must be consumed by the container itself.
+ * ACPI0004: Module Device.
+ *   This device is a container object that acts as a bus node in a namespace.
+ *   A Module Device without any of the _CRS, _PRS and _SRS methods behaves
+ *   the same way as the Generic Container Devices (PNP0A05 or PNP0A06).
+ *   If the Module Device contains a _CRS method, only the resources
+ *   described in the _CRS are available for consumption by its child devices.
+ *   Also, the Module Device can support _PRS and _SRS methods if _CRS is
+ *   supported.
+ */
+
+#include <sys/types.h>
+#include <sys/atomic.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/acpi/acpi.h>
+#include <sys/acpica.h>
+#include <sys/acpidev.h>
+#include <sys/acpidev_impl.h>
+
+static ACPI_STATUS acpidev_container_probe(acpidev_walk_info_t *infop);
+static acpidev_filter_result_t acpidev_container_filter(
+    acpidev_walk_info_t *infop, char *devname, int maxlen);
+static ACPI_STATUS acpidev_container_init(acpidev_walk_info_t *infop);
+static acpidev_filter_result_t acpidev_container_filter_func(
+    acpidev_walk_info_t *infop, ACPI_HANDLE hdl, acpidev_filter_rule_t *rulep,
+    char *devname, int devnamelen);
+
+/*
+ * Default class driver for ACPI container objects.
+ */
+acpidev_class_t acpidev_class_container = {
+	0,				/* adc_refcnt */
+	ACPIDEV_CLASS_REV1,		/* adc_version */
+	ACPIDEV_CLASS_ID_CONTAINER,	/* adc_class_id */
+	"ACPI Container",		/* adc_class_name */
+	ACPIDEV_TYPE_CONTAINER,		/* adc_dev_type */
+	NULL,				/* adc_private */
+	NULL,				/* adc_pre_probe */
+	NULL,				/* adc_post_probe */
+	acpidev_container_probe,	/* adc_probe */
+	acpidev_container_filter,	/* adc_filter */
+	acpidev_container_init,		/* adc_init */
+	NULL,				/* adc_fini */
+};
+
+static char *acpidev_container_device_ids[] = {
+	ACPIDEV_HID_MODULE,
+	ACPIDEV_HID_CONTAINER1,
+	ACPIDEV_HID_CONTAINER2,
+};
+
+static char *acpidev_container_uid_formats[] = {
+	"CPUSCK%x",
+};
+
+/* Filter rule table for container objects. */
+static acpidev_filter_rule_t acpidev_container_filters[] = {
+	{	/* Ignore all container objects under ACPI root object */
+		NULL,
+		0,
+		ACPIDEV_FILTER_SKIP,
+		NULL,
+		1,
+		1,
+		NULL,
+		NULL,
+	},
+	{	/* Create node and scan child for all other container objects */
+		acpidev_container_filter_func,
+		0,
+		ACPIDEV_FILTER_DEFAULT,
+		&acpidev_class_list_device,
+		2,
+		INT_MAX,
+		NULL,
+		ACPIDEV_NODE_NAME_CONTAINER,
+	}
+};
+
+static ACPI_STATUS
+acpidev_container_probe(acpidev_walk_info_t *infop)
+{
+	ACPI_STATUS rc;
+	int flags;
+
+	ASSERT(infop != NULL);
+	ASSERT(infop->awi_hdl != NULL);
+	ASSERT(infop->awi_info != NULL);
+
+	if (infop->awi_info->Type != ACPI_TYPE_DEVICE ||
+	    acpidev_match_device_id(infop->awi_info,
+	    ACPIDEV_ARRAY_PARAM(acpidev_container_device_ids)) == 0) {
+		return (AE_OK);
+	}
+
+	if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE) {
+		flags = ACPIDEV_PROCESS_FLAG_SCAN | ACPIDEV_PROCESS_FLAG_CREATE;
+		rc = acpidev_process_object(infop, flags);
+	} else if (infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE) {
+		flags = ACPIDEV_PROCESS_FLAG_SCAN;
+		rc = acpidev_process_object(infop, flags);
+	} else if (infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
+		flags = ACPIDEV_PROCESS_FLAG_SCAN | ACPIDEV_PROCESS_FLAG_CREATE;
+		rc = acpidev_process_object(infop, flags);
+	} else {
+		ACPIDEV_DEBUG(CE_WARN, "acpidev: unknown operation type %u in "
+		    "acpidev_container_probe().", infop->awi_op_type);
+		rc = AE_BAD_PARAMETER;
+	}
+	if (ACPI_FAILURE(rc) && rc != AE_NOT_EXIST && rc != AE_ALREADY_EXISTS) {
+		cmn_err(CE_WARN,
+		    "!acpidev: failed to process container object %s.",
+		    infop->awi_name);
+	} else {
+		rc = AE_OK;
+	}
+
+	return (rc);
+}
+
+/*ARGSUSED*/
+static ACPI_STATUS
+acpidev_container_search_dev(ACPI_HANDLE hdl, UINT32 lvl, void *ctx,
+    void **retval)
+{
+	int *fp = (int *)ctx;
+
+	*fp = lvl;
+
+	return (AE_CTRL_TERMINATE);
+}
+
+static acpidev_filter_result_t
+acpidev_container_filter_func(acpidev_walk_info_t *infop, ACPI_HANDLE hdl,
+    acpidev_filter_rule_t *rulep, char *devname, int devnamelen)
+{
+	ACPI_BUFFER buf;
+	void *retval;
+	int proc_lvl, cpu_lvl, module_lvl;
+	acpidev_filter_result_t res;
+	static char *cpu_hids[] = {
+		ACPIDEV_HID_CPU,
+	};
+	static char *module_hids[] = {
+		ACPIDEV_HID_MODULE,
+	};
+
+	res = acpidev_filter_default(infop, hdl, rulep, devname, devnamelen);
+	/* Return if we don't need to generate a device name. */
+	if (devname == NULL || res == ACPIDEV_FILTER_FAILED ||
+	    res == ACPIDEV_FILTER_SKIP) {
+		return (res);
+	}
+
+	/* Try to figure out the most specific device name for the object. */
+	retval = NULL;
+	proc_lvl = INT_MAX;
+	cpu_lvl = INT_MAX;
+	module_lvl = INT_MAX;
+
+	/* Search for ACPI Processor object. */
+	(void) AcpiWalkNamespace(ACPI_TYPE_PROCESSOR, hdl, 2,
+	    acpidev_container_search_dev, &proc_lvl, &retval);
+
+	/* Search for CPU Device object. */
+	(void) acpidev_get_device_by_id(hdl, ACPIDEV_ARRAY_PARAM(cpu_hids), 2,
+	    B_FALSE, acpidev_container_search_dev, &cpu_lvl, &retval);
+
+	/* Search for Module Device object. */
+	(void) acpidev_get_device_by_id(hdl, ACPIDEV_ARRAY_PARAM(module_hids),
+	    2, B_FALSE, acpidev_container_search_dev, &module_lvl, &retval);
+
+	buf.Pointer = devname;
+	buf.Length = devnamelen;
+	if (cpu_lvl > proc_lvl) {
+		cpu_lvl = proc_lvl;
+	}
+	if (cpu_lvl == 1) {
+		/* CPU as child, most likely a physical CPU. */
+		(void) strncpy(devname, ACPIDEV_NODE_NAME_MODULE_CPU,
+		    devnamelen);
+	} else if (cpu_lvl == 2 && module_lvl == 1) {
+		/* CPU as grandchild, most likely a system board. */
+		(void) strncpy(devname, ACPIDEV_NODE_NAME_MODULE_SBD,
+		    devnamelen);
+	} else if (ACPI_FAILURE(AcpiGetName(infop->awi_hdl,
+	    ACPI_SINGLE_NAME, &buf))) {
+		/*
+		 * Failed to get ACPI object name; use ACPI object name
+		 * as the default name.
+		 */
+		(void) strncpy(devname, ACPIDEV_NODE_NAME_CONTAINER,
+		    devnamelen);
+	}
+
+	return (res);
+}
+
+static acpidev_filter_result_t
+acpidev_container_filter(acpidev_walk_info_t *infop, char *devname, int maxlen)
+{
+	acpidev_filter_result_t res;
+
+	ASSERT(infop != NULL);
+	if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE ||
+	    infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE ||
+	    infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
+		res = acpidev_filter_device(infop, infop->awi_hdl,
+		    ACPIDEV_ARRAY_PARAM(acpidev_container_filters),
+		    devname, maxlen);
+	} else {
+		res = ACPIDEV_FILTER_FAILED;
+	}
+
+	return (res);
+}
+
+static ACPI_STATUS
+acpidev_container_init(acpidev_walk_info_t *infop)
+{
+	static char *compatible[] = {
+		ACPIDEV_TYPE_CONTAINER,
+		ACPIDEV_HID_VIRTNEX,
+		ACPIDEV_TYPE_VIRTNEX,
+	};
+
+	ASSERT(infop != NULL);
+	ASSERT(infop->awi_hdl != NULL);
+	ASSERT(infop->awi_dip != NULL);
+
+	if (ACPI_FAILURE(acpidev_set_compatible(infop,
+	    ACPIDEV_ARRAY_PARAM(compatible)))) {
+		return (AE_ERROR);
+	}
+	if (ACPI_FAILURE(acpidev_set_unitaddr(infop,
+	    ACPIDEV_ARRAY_PARAM(acpidev_container_uid_formats), NULL))) {
+		return (AE_ERROR);
+	}
+
+	return (AE_OK);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/i86pc/io/acpi/acpidev/acpidev_cpu.c	Thu Aug 27 16:35:32 2009 -0700
@@ -0,0 +1,661 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2009, Intel Corporation.
+ * All rights reserved.
+ */
+
+/*
+ * [Support of X2APIC]
+ * According to the ACPI Spec, when using the X2APIC interrupt model, logical
+ * processors with APIC ID values of 255 and greater are required to have a
+ * Processor Device object and must convey the Processor's APIC information to
+ * OSPM using the Processor Local X2APIC structure. Logical Processors with APIC
+ * ID values less than 255 must use the Processor Local XAPIC structure to
+ * convey their APIC information to OSPM.
+ */
+
+#include <sys/types.h>
+#include <sys/atomic.h>
+#include <sys/bootconf.h>
+#include <sys/cpuvar.h>
+#include <sys/machsystm.h>
+#include <sys/psm_types.h>
+#include <sys/x86_archext.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/acpi/acpi.h>
+#include <sys/acpica.h>
+#include <sys/acpidev.h>
+#include <sys/acpidev_impl.h>
+
+struct acpidev_cpu_map_item {
+	uint32_t	proc_id;
+	uint32_t	apic_id;
+};
+
+struct acpidev_cpu_MAT_arg {
+	boolean_t	found;
+	boolean_t	enabled;
+	uint32_t	proc_id;
+	uint32_t	apic_id;
+};
+
+static ACPI_STATUS acpidev_cpu_pre_probe(acpidev_walk_info_t *infop);
+static ACPI_STATUS acpidev_cpu_post_probe(acpidev_walk_info_t *infop);
+static ACPI_STATUS acpidev_cpu_probe(acpidev_walk_info_t *infop);
+static acpidev_filter_result_t acpidev_cpu_filter(acpidev_walk_info_t *infop,
+    char *devname, int maxlen);
+static ACPI_STATUS acpidev_cpu_init(acpidev_walk_info_t *infop);
+
+static acpidev_filter_result_t acpidev_cpu_filter_func(
+    acpidev_walk_info_t *infop, ACPI_HANDLE hdl, acpidev_filter_rule_t *afrp,
+    char *devname, int len);
+static int acpidev_cpu_query_dip(cpu_t *, dev_info_t **);
+
+/*
+ * Default class driver for ACPI processor/CPU objects.
+ */
+acpidev_class_t acpidev_class_cpu = {
+	0,				/* adc_refcnt */
+	ACPIDEV_CLASS_REV1,		/* adc_version */
+	ACPIDEV_CLASS_ID_CPU,		/* adc_class_id */
+	"ACPI CPU",			/* adc_class_name */
+	ACPIDEV_TYPE_CPU,		/* adc_dev_type */
+	NULL,				/* adc_private */
+	acpidev_cpu_pre_probe,		/* adc_pre_probe */
+	acpidev_cpu_post_probe,		/* adc_post_probe */
+	acpidev_cpu_probe,		/* adc_probe */
+	acpidev_cpu_filter,		/* adc_filter */
+	acpidev_cpu_init,		/* adc_init */
+	NULL,				/* adc_fini */
+};
+
+/*
+ * List of class drivers which will be called in order when handling
+ * children of ACPI cpu/processor objects.
+ */
+acpidev_class_list_t *acpidev_class_list_cpu = NULL;
+
+/* Filter rule table for the first probe at boot time. */
+static acpidev_filter_rule_t acpidev_cpu_filters[] = {
+	{	/* Skip all processors under root node, should be there. */
+		NULL,
+		0,
+		ACPIDEV_FILTER_SKIP,
+		NULL,
+		1,
+		1,
+		NULL,
+		NULL,
+	},
+	{	/* Create and scan other processor objects */
+		acpidev_cpu_filter_func,
+		0,
+		ACPIDEV_FILTER_DEFAULT,
+		&acpidev_class_list_cpu,
+		2,
+		INT_MAX,
+		NULL,
+		ACPIDEV_NODE_NAME_CPU,
+	}
+};
+
+/* ACPI/PNP hardware id for processor. */
+static char *acpidev_processor_device_ids[] = {
+	ACPIDEV_HID_CPU,
+};
+
+static char *acpidev_cpu_uid_formats[] = {
+	"SCK%x-CPU%x",
+};
+
+static ACPI_HANDLE acpidev_cpu_map_hdl = NULL;
+static uint32_t acpidev_cpu_map_count = 0;
+static struct acpidev_cpu_map_item *acpidev_cpu_map = NULL;
+
+extern int (*psm_cpu_create_devinfo)(cpu_t *, dev_info_t **);
+static int (*psm_cpu_create_devinfo_old)(cpu_t *, dev_info_t **) = NULL;
+
+/* Count how many enabled CPUs are in the MADT table. */
+static ACPI_STATUS
+acpidev_cpu_count_MADT(ACPI_SUBTABLE_HEADER *ap, void *context)
+{
+	uint32_t *cntp;
+	ACPI_MADT_LOCAL_APIC *mpa;
+	ACPI_MADT_LOCAL_X2APIC *mpx2a;
+
+	cntp = (uint32_t *)context;
+	switch (ap->Type) {
+	case ACPI_MADT_TYPE_LOCAL_APIC:
+		mpa = (ACPI_MADT_LOCAL_APIC *)ap;
+		if (mpa->LapicFlags & ACPI_MADT_ENABLED) {
+			ASSERT(mpa->Id != 255);
+			(*cntp)++;
+		}
+		break;
+
+	case ACPI_MADT_TYPE_LOCAL_X2APIC:
+		mpx2a = (ACPI_MADT_LOCAL_X2APIC *)ap;
+		/* See comment at beginning about 255 limitation. */
+		if ((mpx2a->LapicFlags & ACPI_MADT_ENABLED) &&
+		    (mpx2a->LocalApicId >= 255)) {
+			(*cntp)++;
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return (AE_OK);
+}
+
+/* Extract information from the enabled CPUs using the MADT table. */
+static ACPI_STATUS
+acpidev_cpu_parse_MADT(ACPI_SUBTABLE_HEADER *ap, void *context)
+{
+	uint32_t *cntp;
+	ACPI_MADT_LOCAL_APIC *mpa;
+	ACPI_MADT_LOCAL_X2APIC *mpx2a;
+
+	cntp = (uint32_t *)context;
+	switch (ap->Type) {
+	case ACPI_MADT_TYPE_LOCAL_APIC:
+		mpa = (ACPI_MADT_LOCAL_APIC *)ap;
+		if (mpa->LapicFlags & ACPI_MADT_ENABLED) {
+			ASSERT(mpa->Id != 255);
+			ASSERT(*cntp < acpidev_cpu_map_count);
+			acpidev_cpu_map[*cntp].proc_id = mpa->ProcessorId;
+			acpidev_cpu_map[*cntp].apic_id = mpa->Id;
+			(*cntp)++;
+		}
+		break;
+
+	case ACPI_MADT_TYPE_LOCAL_X2APIC:
+		mpx2a = (ACPI_MADT_LOCAL_X2APIC *)ap;
+		/* See comment at beginning about 255 limitation. */
+		if (mpx2a->LocalApicId < 255) {
+			ACPIDEV_DEBUG(CE_WARN,
+			    "acpidev: encountered CPU with X2APIC Id < 255.");
+		} else if (mpx2a->LapicFlags & ACPI_MADT_ENABLED) {
+			ASSERT(*cntp < acpidev_cpu_map_count);
+			acpidev_cpu_map[*cntp].proc_id = mpx2a->Uid;
+			acpidev_cpu_map[*cntp].apic_id = mpx2a->LocalApicId;
+			(*cntp)++;
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return (AE_OK);
+}
+
+static ACPI_STATUS
+acpidev_cpu_get_apicid(uint32_t procid, uint32_t *apicidp)
+{
+	uint32_t i;
+
+	for (i = 0; i < acpidev_cpu_map_count; i++) {
+		if (acpidev_cpu_map[i].proc_id == procid) {
+			*apicidp = acpidev_cpu_map[i].apic_id;
+			return (AE_OK);
+		}
+	}
+
+	return (AE_NOT_FOUND);
+}
+
+/*
+ * Extract information for enabled CPUs from the buffer returned
+ * by the _MAT method.
+ */
+static ACPI_STATUS
+acpidev_cpu_query_MAT(ACPI_SUBTABLE_HEADER *ap, void *context)
+{
+	ACPI_MADT_LOCAL_APIC *mpa;
+	ACPI_MADT_LOCAL_X2APIC *mpx2a;
+	struct acpidev_cpu_MAT_arg *rp;
+
+	rp = (struct acpidev_cpu_MAT_arg *)context;
+	switch (ap->Type) {
+	case ACPI_MADT_TYPE_LOCAL_APIC:
+		mpa = (ACPI_MADT_LOCAL_APIC *)ap;
+		ASSERT(mpa->Id != 255);
+		rp->found = B_TRUE;
+		rp->proc_id = mpa->ProcessorId;
+		rp->apic_id = mpa->Id;
+		if (mpa->LapicFlags & ACPI_MADT_ENABLED) {
+			rp->enabled = B_TRUE;
+		} else {
+			rp->enabled = B_FALSE;
+		}
+		return (AE_CTRL_TERMINATE);
+
+	case ACPI_MADT_TYPE_LOCAL_X2APIC:
+		mpx2a = (ACPI_MADT_LOCAL_X2APIC *)ap;
+		if (mpx2a->LocalApicId >= 255) {
+			rp->found = B_TRUE;
+			rp->proc_id = mpx2a->Uid;
+			rp->apic_id = mpx2a->LocalApicId;
+			if (mpx2a->LapicFlags & ACPI_MADT_ENABLED) {
+				rp->enabled = B_TRUE;
+			} else {
+				rp->enabled = B_FALSE;
+			}
+			return (AE_CTRL_TERMINATE);
+		} else {
+			ACPIDEV_DEBUG(CE_WARN, "acpidev: encountered CPU "
+			    "with X2APIC Id < 255 in _MAT.");
+		}
+		break;
+
+	case ACPI_MADT_TYPE_LOCAL_APIC_NMI:
+		/* UNIMPLEMENTED */
+		break;
+
+	case ACPI_MADT_TYPE_LOCAL_X2APIC_NMI:
+		/* UNIMPLEMENTED */
+		break;
+
+	default:
+		/*
+		 * According to the ACPI Spec, the buffer returned by _MAT
+		 * for a processor object should only contain Local APIC,
+		 * Local SAPIC, and local APIC NMI entries.
+		 * x2APIC Specification extends it to support Processor
+		 * x2APIC and x2APIC NMI Structure.
+		 */
+		ACPIDEV_DEBUG(CE_NOTE,
+		    "acpidev: unknown APIC entry type %u in _MAT.", ap->Type);
+		break;
+	}
+
+	return (AE_OK);
+}
+
+/*
+ * Query ACPI processor ID by evaluating ACPI _MAT, _UID, and PROCESSOR
+ * objects.
+ */
+static ACPI_STATUS
+acpidev_cpu_get_procid(acpidev_walk_info_t *infop, uint32_t *idp)
+{
+	int id;
+	ACPI_HANDLE hdl;
+	struct acpidev_cpu_MAT_arg mat;
+
+	if (infop->awi_info->Type != ACPI_TYPE_PROCESSOR &&
+	    infop->awi_info->Type != ACPI_TYPE_DEVICE) {
+		ACPIDEV_DEBUG(CE_WARN,
+		    "acpidev: object %s is not PROCESSOR or DEVICE.",
+		    infop->awi_name);
+		return (AE_BAD_PARAMETER);
+	}
+	hdl = infop->awi_hdl;
+
+	/*
+	 * First try to evaluate _MAT.
+	 * According to the ACPI Spec3.0b, it's legal for ACPI PROCESSOR objects
+	 * to have ACPI method objects.
+	 */
+	bzero(&mat, sizeof (mat));
+	(void) acpidev_walk_apic(NULL, hdl, ACPIDEV_METHOD_NAME_MAT,
+	    acpidev_cpu_query_MAT, &mat);
+	if (mat.found) {
+		*idp = mat.proc_id;
+		return (AE_OK);
+	}
+
+	/* Then evalute PROCESSOR object. */
+	if (infop->awi_info->Type == ACPI_TYPE_PROCESSOR) {
+		ACPI_BUFFER rb;
+
+		rb.Pointer = NULL;
+		rb.Length = ACPI_ALLOCATE_BUFFER;
+		if (ACPI_SUCCESS(AcpiEvaluateObjectTyped(hdl, NULL, NULL, &rb,
+		    ACPI_TYPE_PROCESSOR))) {
+			*idp = ((ACPI_OBJECT *)rb.Pointer)->Processor.ProcId;
+			AcpiOsFree(rb.Pointer);
+			return (AE_OK);
+		} else {
+			ACPIDEV_DEBUG(CE_WARN,
+			    "acpidev: failed to evaluate ACPI object %s.",
+			    infop->awi_name);
+		}
+	}
+
+	/*
+	 * Finally, try to evalute the _UID method.
+	 * According to the ACPI Spec3.0b, it's legal for ACPI PROCESSOR objects
+	 * to have ACPI method objects.
+	 * The CPU _UID method should return Processor Id as an integer on x86.
+	 */
+	if (ACPI_SUCCESS(acpica_eval_int(hdl, METHOD_NAME__UID, &id))) {
+		*idp = id;
+		return (AE_OK);
+	}
+
+	return (AE_NOT_FOUND);
+}
+
+static ACPI_STATUS
+acpidev_cpu_pre_probe(acpidev_walk_info_t *infop)
+{
+	uint32_t count = 0;
+
+	/* Parse and cache APIC info in MADT on the first probe at boot time. */
+	ASSERT(infop != NULL);
+	if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE &&
+	    acpidev_cpu_map_hdl == NULL) {
+		(void) acpidev_walk_apic(NULL, NULL, NULL,
+		    acpidev_cpu_count_MADT, &acpidev_cpu_map_count);
+		acpidev_cpu_map = kmem_zalloc(sizeof (acpidev_cpu_map[0])
+		    * acpidev_cpu_map_count, KM_SLEEP);
+		(void) acpidev_walk_apic(NULL, NULL, NULL,
+		    acpidev_cpu_parse_MADT, &count);
+		ASSERT(count == acpidev_cpu_map_count);
+		acpidev_cpu_map_hdl = infop->awi_hdl;
+	}
+
+	return (AE_OK);
+}
+
+static ACPI_STATUS
+acpidev_cpu_post_probe(acpidev_walk_info_t *infop)
+{
+	/* Free cached APIC info on the second probe at boot time. */
+	ASSERT(infop != NULL);
+	if (infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE &&
+	    acpidev_cpu_map_hdl != NULL &&
+	    infop->awi_hdl == acpidev_cpu_map_hdl) {
+		if (acpidev_cpu_map != NULL && acpidev_cpu_map_count != 0) {
+			kmem_free(acpidev_cpu_map, sizeof (acpidev_cpu_map[0])
+			    * acpidev_cpu_map_count);
+		}
+		acpidev_cpu_map = NULL;
+		acpidev_cpu_map_count = 0;
+		acpidev_cpu_map_hdl = NULL;
+
+		/* replace psm_cpu_create_devinfo with local implementation. */
+		psm_cpu_create_devinfo_old = psm_cpu_create_devinfo;
+		psm_cpu_create_devinfo = acpidev_cpu_query_dip;
+	}
+
+	return (AE_OK);
+}
+
+static ACPI_STATUS
+acpidev_cpu_probe(acpidev_walk_info_t *infop)
+{
+	ACPI_STATUS rc = AE_OK;
+	int flags;
+
+	ASSERT(infop != NULL);
+	ASSERT(infop->awi_hdl != NULL);
+	ASSERT(infop->awi_info != NULL);
+	ASSERT(infop->awi_class_curr == &acpidev_class_cpu);
+	if (infop->awi_info->Type != ACPI_TYPE_PROCESSOR &&
+	    (infop->awi_info->Type != ACPI_TYPE_DEVICE ||
+	    acpidev_match_device_id(infop->awi_info,
+	    ACPIDEV_ARRAY_PARAM(acpidev_processor_device_ids)) == 0)) {
+		return (AE_OK);
+	}
+
+	/*
+	 * Mark device as offline. It will be changed to online state
+	 * when the corresponding CPU starts up.
+	 */
+	if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE) {
+		flags = ACPIDEV_PROCESS_FLAG_SCAN |
+		    ACPIDEV_PROCESS_FLAG_CREATE |
+		    ACPIDEV_PROCESS_FLAG_OFFLINE;
+		rc = acpidev_process_object(infop, flags);
+	} else if (infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE) {
+		flags = ACPIDEV_PROCESS_FLAG_SCAN;
+		rc = acpidev_process_object(infop, flags);
+	} else if (infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
+		flags = ACPIDEV_PROCESS_FLAG_SCAN |
+		    ACPIDEV_PROCESS_FLAG_CREATE |
+		    ACPIDEV_PROCESS_FLAG_OFFLINE;
+		rc = acpidev_process_object(infop, flags);
+	} else {
+		ACPIDEV_DEBUG(CE_WARN, "acpidev: unknown operation type %u in "
+		    "acpidev_cpu_probe().", infop->awi_op_type);
+		rc = AE_BAD_PARAMETER;
+	}
+	if (ACPI_FAILURE(rc) && rc != AE_NOT_EXIST && rc != AE_ALREADY_EXISTS) {
+		cmn_err(CE_WARN,
+		    "!acpidev: failed to process processor object %s.",
+		    infop->awi_name);
+	} else {
+		rc = AE_OK;
+	}
+
+	return (rc);
+}
+
+static acpidev_filter_result_t
+acpidev_cpu_filter_func(acpidev_walk_info_t *infop, ACPI_HANDLE hdl,
+    acpidev_filter_rule_t *afrp, char *devname, int len)
+{
+	acpidev_filter_result_t res;
+
+	ASSERT(afrp != NULL);
+	if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE ||
+	    infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE) {
+		uint32_t procid;
+		uint32_t apicid;
+
+		if (acpidev_cpu_get_procid(infop, &procid) != 0) {
+			ACPIDEV_DEBUG(CE_WARN,
+			    "acpidev: failed to query processor id for %s.",
+			    infop->awi_name);
+			return (ACPIDEV_FILTER_SKIP);
+		} else if (acpidev_cpu_get_apicid(procid, &apicid) != 0) {
+			ACPIDEV_DEBUG(CE_WARN,
+			    "acpidev: failed to query apic id for %s.",
+			    infop->awi_name);
+			return (ACPIDEV_FILTER_SKIP);
+		}
+
+		infop->awi_scratchpad[0] = procid;
+		infop->awi_scratchpad[1] = apicid;
+	} else if (infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
+		struct acpidev_cpu_MAT_arg mat;
+
+		bzero(&mat, sizeof (mat));
+		(void) acpidev_walk_apic(NULL, hdl, ACPIDEV_METHOD_NAME_MAT,
+		    acpidev_cpu_query_MAT, &mat);
+		if (!mat.found) {
+			cmn_err(CE_WARN,
+			    "!acpidev: failed to walk apic resource for %s.",
+			    infop->awi_name);
+			return (ACPIDEV_FILTER_SKIP);
+		} else if (!mat.enabled) {
+			ACPIDEV_DEBUG(CE_NOTE,
+			    "acpidev: CPU %s has been disabled.",
+			    infop->awi_name);
+			return (ACPIDEV_FILTER_SKIP);
+		}
+		/* Save processor id and APIC id in scratchpad memory. */
+		infop->awi_scratchpad[0] = mat.proc_id;
+		infop->awi_scratchpad[1] = mat.apic_id;
+	}
+
+	res = acpidev_filter_default(infop, hdl, afrp, devname, len);
+
+	return (res);
+}
+
+static acpidev_filter_result_t
+acpidev_cpu_filter(acpidev_walk_info_t *infop, char *devname, int maxlen)
+{
+	acpidev_filter_result_t res;
+
+	ASSERT(infop != NULL);
+	ASSERT(devname == NULL || maxlen >= ACPIDEV_MAX_NAMELEN);
+	if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE ||
+	    infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE ||
+	    infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
+		res = acpidev_filter_device(infop, infop->awi_hdl,
+		    ACPIDEV_ARRAY_PARAM(acpidev_cpu_filters), devname, maxlen);
+	} else {
+		res = ACPIDEV_FILTER_FAILED;
+	}
+
+	return (res);
+}
+
+static ACPI_STATUS
+acpidev_cpu_init(acpidev_walk_info_t *infop)
+{
+	int count;
+	dev_info_t *dip;
+	ACPI_HANDLE hdl;
+	char unitaddr[64];
+	char **compatpp;
+	static char *compatible[] = {
+		ACPIDEV_HID_PROCESSOR,
+		ACPIDEV_TYPE_CPU,
+		"cpu"
+	};
+
+	ASSERT(infop != NULL);
+	dip = infop->awi_dip;
+	hdl = infop->awi_hdl;
+
+	/* Create "apic_id" and "processor_id" properties. */
+	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+	    ACPIDEV_PROP_NAME_PROCESSOR_ID, infop->awi_scratchpad[0]) !=
+	    NDI_SUCCESS) {
+		cmn_err(CE_WARN,
+		    "!acpidev: failed to set processor_id property for %s.",
+		    infop->awi_name);
+		return (AE_ERROR);
+	}
+	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
+	    ACPIDEV_PROP_NAME_LOCALAPIC_ID, infop->awi_scratchpad[1]) !=
+	    NDI_SUCCESS) {
+		cmn_err(CE_WARN,
+		    "!acpidev: failed to set apic_id property for %s.",
+		    infop->awi_name);
+		return (AE_ERROR);
+	}
+
+	/* Set "compatible" property for CPU dip */
+	count = sizeof (compatible) / sizeof (compatible[0]);
+	if (infop->awi_info->Type == ACPI_TYPE_PROCESSOR) {
+		compatpp = compatible;
+	} else if (infop->awi_info->Type == ACPI_TYPE_DEVICE) {
+		/*
+		 * skip first item for pseudo processor HID.
+		 * acpidev_set_compatible() will handle HID/CID for CPU device.
+		 */
+		compatpp = &compatible[1];
+		count--;
+	} else {
+		return (AE_BAD_PARAMETER);
+	}
+	if (ACPI_FAILURE(acpidev_set_compatible(infop, compatpp, count))) {
+		return (AE_ERROR);
+	}
+
+	/*
+	 * Set device unit-address property.
+	 * First try to generate meaningful unit address from _UID,
+	 * then use Processor Id if that fails.
+	 */
+	if ((infop->awi_info->Valid & ACPI_VALID_UID) == 0 ||
+	    acpidev_generate_unitaddr(infop->awi_info->UniqueId.Value,
+	    ACPIDEV_ARRAY_PARAM(acpidev_cpu_uid_formats),
+	    unitaddr, sizeof (unitaddr)) == NULL) {
+		(void) snprintf(unitaddr, sizeof (unitaddr), "%u",
+		    (uint32_t)infop->awi_scratchpad[0]);
+	}
+	if (ACPI_FAILURE(acpidev_set_unitaddr(infop, NULL, 0, unitaddr))) {
+		return (AE_ERROR);
+	}
+
+	/*
+	 * Build binding information for CPUs.
+	 */
+	if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE ||
+	    infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE ||
+	    infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
+		if (ACPI_FAILURE(acpica_add_processor_to_map(
+		    infop->awi_scratchpad[0], hdl, infop->awi_scratchpad[1]))) {
+			cmn_err(CE_WARN, "!acpidev: failed to bind processor "
+			    "id/object handle for %s.", infop->awi_name);
+			return (AE_ERROR);
+		}
+	} else {
+		ACPIDEV_DEBUG(CE_WARN,
+		    "acpidev: unknown operation type %u in acpidev_cpu_init.",
+		    infop->awi_op_type);
+		return (AE_BAD_PARAMETER);
+	}
+
+	return (AE_OK);
+}
+
+static int
+acpidev_cpu_query_dip(cpu_t *cp, dev_info_t **dipp)
+{
+	uint32_t apicid;
+	ACPI_HANDLE hdl;
+	dev_info_t *dip = NULL;
+
+	*dipp = NULL;
+	/*
+	 * Try to get the dip associated with the CPU if ACPI_DEVCFG_CPU is
+	 * enabled.
+	 */
+	if (acpica_get_devcfg_feature(ACPI_DEVCFG_CPU)) {
+		apicid = cpuid_get_apicid(cp);
+		if (acpica_get_cpu_object_by_cpuid(cp->cpu_id, &hdl) == 0 ||
+		    (apicid != UINT32_MAX &&
+		    acpica_get_cpu_object_by_apicid(apicid, &hdl) == 0)) {
+			ASSERT(hdl != NULL);
+			if (ACPI_SUCCESS(acpica_get_devinfo(hdl, &dip))) {
+				ASSERT(dip != NULL);
+				ndi_hold_devi(dip);
+				*dipp = dip;
+				return (PSM_SUCCESS);
+			}
+		}
+	}
+
+	ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to get dip for cpu %d(%p).",
+	    cp->cpu_id, (void *)cp);
+	if (psm_cpu_create_devinfo_old != NULL) {
+		return (psm_cpu_create_devinfo_old(cp, dipp));
+	} else {
+		return (PSM_FAILURE);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/i86pc/io/acpi/acpidev/acpidev_device.c	Thu Aug 27 16:35:32 2009 -0700
@@ -0,0 +1,186 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 (c) 2009, Intel Corporation.
+ * All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/atomic.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/acpi/acpi.h>
+#include <sys/acpica.h>
+#include <sys/acpidev.h>
+#include <sys/acpidev_impl.h>
+
+static ACPI_STATUS acpidev_device_probe(acpidev_walk_info_t *infop);
+static acpidev_filter_result_t acpidev_device_filter(acpidev_walk_info_t *infop,
+    char *devname, int maxlen);
+static ACPI_STATUS acpidev_device_init(acpidev_walk_info_t *infop);
+
+static uint32_t acpidev_device_unitaddr = 0;
+
+/*
+ * Default class driver for ACPI DEVICE objects.
+ * The default policy for DEVICE objects is to scan child objects without
+ * creating device nodes. But some special DEVICE objects will have device
+ * nodes created for them.
+ */
+acpidev_class_t acpidev_class_device = {
+	0,				/* adc_refcnt */
+	ACPIDEV_CLASS_REV1,		/* adc_version */
+	ACPIDEV_CLASS_ID_DEVICE,	/* adc_class_id */
+	"ACPI Device",			/* adc_class_name */
+	ACPIDEV_TYPE_DEVICE,		/* adc_dev_type */
+	NULL,				/* adc_private */
+	NULL,				/* adc_pre_probe */
+	NULL,				/* adc_post_probe */
+	acpidev_device_probe,		/* adc_probe */
+	acpidev_device_filter,		/* adc_filter */
+	acpidev_device_init,		/* adc_init */
+	NULL,				/* adc_fini */
+};
+
+/*
+ * List of class drivers which will be called in order when handling
+ * children of ACPI DEVICE objects.
+ */
+acpidev_class_list_t *acpidev_class_list_device = NULL;
+
+/* Filter rule table for boot. */
+static acpidev_filter_rule_t acpidev_device_filters[] = {
+	{	/* _SB_ object type is hardcoded to DEVICE by acpica */
+		NULL,
+		0,
+		ACPIDEV_FILTER_DEFAULT,
+		&acpidev_class_list_device,
+		1,
+		1,
+		ACPIDEV_OBJECT_NAME_SB,
+		ACPIDEV_NODE_NAME_MODULE_SBD,
+	},
+	{	/* Ignore other device objects under ACPI root object */
+		NULL,
+		0,
+		ACPIDEV_FILTER_SKIP,
+		NULL,
+		1,
+		1,
+		NULL,
+		NULL,
+	},
+	{	/* Scan other device objects not directly under ACPI root */
+		NULL,
+		0,
+		ACPIDEV_FILTER_SKIP,
+		&acpidev_class_list_device,
+		2,
+		INT_MAX,
+		NULL,
+		NULL,
+	}
+};
+
+static ACPI_STATUS
+acpidev_device_probe(acpidev_walk_info_t *infop)
+{
+	ACPI_STATUS rc;
+	int flags;
+
+	ASSERT(infop != NULL);
+	ASSERT(infop->awi_hdl != NULL);
+	ASSERT(infop->awi_info != NULL);
+
+	if (infop->awi_info->Type != ACPI_TYPE_DEVICE) {
+		return (AE_OK);
+	}
+
+	if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE) {
+		flags = ACPIDEV_PROCESS_FLAG_SCAN | ACPIDEV_PROCESS_FLAG_CREATE;
+		rc = acpidev_process_object(infop, flags);
+	} else if (infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE) {
+		flags = ACPIDEV_PROCESS_FLAG_SCAN;
+		rc = acpidev_process_object(infop, flags);
+	} else if (infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
+		flags = ACPIDEV_PROCESS_FLAG_SCAN | ACPIDEV_PROCESS_FLAG_CREATE;
+		rc = acpidev_process_object(infop, flags);
+	} else {
+		ACPIDEV_DEBUG(CE_WARN,
+		    "acpidev: unknown operation type %u in "
+		    "acpi_device_probe().", infop->awi_op_type);
+		rc = AE_BAD_PARAMETER;
+	}
+	if (ACPI_FAILURE(rc) && rc != AE_NOT_EXIST && rc != AE_ALREADY_EXISTS) {
+		cmn_err(CE_WARN,
+		    "!acpidev: failed to process device object %s.",
+		    infop->awi_name);
+	} else {
+		rc = AE_OK;
+	}
+
+	return (rc);
+}
+
+static acpidev_filter_result_t
+acpidev_device_filter(acpidev_walk_info_t *infop, char *devname, int maxlen)
+{
+	acpidev_filter_result_t res;
+
+	ASSERT(infop != NULL);
+	if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE ||
+	    infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE ||
+	    infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
+		res = acpidev_filter_device(infop, infop->awi_hdl,
+		    ACPIDEV_ARRAY_PARAM(acpidev_device_filters),
+		    devname, maxlen);
+	} else {
+		ACPIDEV_DEBUG(CE_WARN, "acpidev: unknown operation type %u "
+		    "in acpidev_device_filter().", infop->awi_op_type);
+		res = ACPIDEV_FILTER_FAILED;
+	}
+
+	return (res);
+}
+
+/*ARGSUSED*/
+static ACPI_STATUS
+acpidev_device_init(acpidev_walk_info_t *infop)
+{
+	char unitaddr[32];
+	char *compatible[] = {
+		ACPIDEV_TYPE_DEVICE,
+		ACPIDEV_HID_VIRTNEX,
+		ACPIDEV_TYPE_VIRTNEX,
+	};
+
+	if (ACPI_FAILURE(acpidev_set_compatible(infop,
+	    ACPIDEV_ARRAY_PARAM(compatible)))) {
+		return (AE_ERROR);
+	}
+	(void) snprintf(unitaddr, sizeof (unitaddr), "%u",
+	    atomic_inc_32_nv(&acpidev_device_unitaddr) - 1);
+	if (ACPI_FAILURE(acpidev_set_unitaddr(infop, NULL, 0, unitaddr))) {
+		return (AE_ERROR);
+	}
+
+	return (AE_OK);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/i86pc/io/acpi/acpidev/acpidev_drv.c	Thu Aug 27 16:35:32 2009 -0700
@@ -0,0 +1,1125 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 (c) 2009, Intel Corporation.
+ * All rights reserved.
+ */
+
+/*
+ * Platform specific device enumerator for ACPI specific devices.
+ * "x86 system devices" refers to the suite of hardware components which are
+ * common to the x86 platform and play important roles in the system
+ * architecture but can't be enumerated/discovered through industry-standard
+ * bus specifications. Examples of these x86 system devices include:
+ *   * Logical processor/CPU
+ *   * Memory device
+ *   * Non-PCI discoverable IOMMU or DMA Remapping Engine
+ *   * Non-PCI discoverable IOxAPIC
+ *   * Non-PCI discoverable HPET (High Precision Event Timer)
+ *   * ACPI defined devices, including power button, sleep button, battery etc.
+ *
+ * X86 system devices may be discovered through BIOS/Firmware interfaces, such
+ * as SMBIOS tables, MPS tables and ACPI tables since their discovery isn't
+ * covered by any industry-standard bus specifications.
+ *
+ * In order to aid Solaris in flexibly managing x86 system devices,
+ * x86 system devices are placed into a specific firmware device
+ * subtree whose device path is '/devices/fw'.
+ *
+ * This driver populates the firmware device subtree with ACPI-discoverable
+ * system devices if possible. To achieve that, the ACPI object
+ * namespace is abstracted as ACPI virtual buses which host system devices.
+ * Another nexus driver for the ACPI virtual bus will manage all devices
+ * connected to it.
+ *
+ * For more detailed information, please refer to PSARC/2009/104.
+ */
+
+#include <sys/types.h>
+#include <sys/bitmap.h>
+#include <sys/cmn_err.h>
+#include <sys/ddi_subrdefs.h>
+#include <sys/errno.h>
+#include <sys/modctl.h>
+#include <sys/mutex.h>
+#include <sys/obpdefs.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/acpi/acpi.h>
+#include <sys/acpica.h>
+#include <sys/acpidev.h>
+#include <sys/acpidev_impl.h>
+
+/* Patchable through /etc/system */
+int acpidev_options = 0;
+int acpidev_debug = 0;
+
+acpidev_class_list_t *acpidev_class_list_root = NULL;
+
+/* ACPI device autoconfig global status */
+typedef enum acpidev_status {
+	ACPIDEV_STATUS_FAILED = -2,	/* ACPI device autoconfig failed */
+	ACPIDEV_STATUS_DISABLED = -1,	/* ACPI device autoconfig disabled */
+	ACPIDEV_STATUS_UNKNOWN = 0,	/* initial status */
+	ACPIDEV_STATUS_INITIALIZED,	/* ACPI device autoconfig initialized */
+	ACPIDEV_STATUS_FIRST_PASS,	/* first probing finished */
+	ACPIDEV_STATUS_READY		/* second probing finished */
+} acpidev_status_t;
+
+static acpidev_status_t acpidev_status = ACPIDEV_STATUS_UNKNOWN;
+static kmutex_t	acpidev_drv_lock;
+static krwlock_t acpidev_class_lock;
+static dev_info_t *acpidev_root_dip = NULL;
+static ulong_t acpidev_object_type_mask[BT_BITOUL(ACPI_TYPE_NS_NODE_MAX + 1)];
+
+/* Boot time ACPI device enumerator. */
+static void acpidev_boot_probe(int type);
+
+/* DDI module auto configuration interface */
+extern struct mod_ops mod_miscops;
+
+static struct modlmisc modlmisc = {
+	&mod_miscops,
+	"ACPI device enumerator"
+};
+
+static struct modlinkage modlinkage = {
+	MODREV_1,
+	(void *)&modlmisc,
+	NULL
+};
+
+int
+_init(void)
+{
+	int err;
+
+	if ((err = mod_install(&modlinkage)) == 0) {
+		bzero(acpidev_object_type_mask,
+		    sizeof (acpidev_object_type_mask));
+		mutex_init(&acpidev_drv_lock, NULL, MUTEX_DRIVER, NULL);
+		rw_init(&acpidev_class_lock, NULL, RW_DEFAULT, NULL);
+		impl_bus_add_probe(acpidev_boot_probe);
+	} else {
+		cmn_err(CE_WARN, "!acpidev: failed to install driver.");
+	}
+
+	return (err);
+}
+
+int
+_fini(void)
+{
+	/* No support for module unload. */
+	return (EBUSY);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+	return (mod_info(&modlinkage, modinfop));
+}
+
+/* Check blacklists and load platform specific driver modules. */
+static ACPI_STATUS
+acpidev_load_plat_modules(void)
+{
+	return (AE_OK);
+}
+
+/* Unload platform specific driver modules. */
+static void
+acpidev_unload_plat_modules(void)
+{
+}
+
+/* Unregister all device class drivers from the device driver lists. */
+static void
+acpidev_class_list_fini(void)
+{
+	acpidev_unload_plat_modules();
+
+	if ((acpidev_options & ACPIDEV_OUSER_NO_MEM) == 0) {
+		(void) acpidev_unregister_class(&acpidev_class_list_device,
+		    &acpidev_class_memory);
+	}
+
+	if (acpidev_options & ACPIDEV_OUSER_NO_CPU) {
+		(void) acpidev_unregister_class(&acpidev_class_list_device,
+		    &acpidev_class_cpu);
+		(void) acpidev_unregister_class(&acpidev_class_list_scope,
+		    &acpidev_class_cpu);
+		(void) acpidev_unregister_class(&acpidev_class_list_root,
+		    &acpidev_class_cpu);
+	}
+
+	if ((acpidev_options & ACPIDEV_OUSER_NO_CONTAINER) == 0) {
+		(void) acpidev_unregister_class(&acpidev_class_list_device,
+		    &acpidev_class_container);
+	}
+
+	(void) acpidev_unregister_class(&acpidev_class_list_device,
+	    &acpidev_class_device);
+	(void) acpidev_unregister_class(&acpidev_class_list_root,
+	    &acpidev_class_device);
+
+	(void) acpidev_unregister_class(&acpidev_class_list_root,
+	    &acpidev_class_scope);
+}
+
+/* Register all device class drivers onto the driver lists. */
+static ACPI_STATUS
+acpidev_class_list_init(uint64_t *fp)
+{
+	ACPI_STATUS rc = AE_OK;
+
+	/* Set bit in mask for supported object types. */
+	BT_SET(acpidev_object_type_mask, ACPI_TYPE_LOCAL_SCOPE);
+	BT_SET(acpidev_object_type_mask, ACPI_TYPE_DEVICE);
+
+	/*
+	 * Register the ACPI scope class driver onto the class driver lists.
+	 * Currently only ACPI scope objects under ACPI root node, such as _PR,
+	 * _SB, _TZ etc, need to be handled, so only register the scope class
+	 * driver onto the root list.
+	 */
+	if (ACPI_FAILURE(acpidev_register_class(&acpidev_class_list_root,
+	    &acpidev_class_scope, B_FALSE))) {
+		goto error_out;
+	}
+
+	/*
+	 * Register the ACPI device class driver onto the class driver lists.
+	 * The ACPI device class driver should be registered at the tail to
+	 * handle all device objects which haven't been handled by other
+	 * HID/CID specific device class drivers.
+	 */
+	if (ACPI_FAILURE(acpidev_register_class(&acpidev_class_list_root,
+	    &acpidev_class_device, B_TRUE))) {
+		goto error_root_device;
+	}
+	if (ACPI_FAILURE(acpidev_register_class(&acpidev_class_list_device,
+	    &acpidev_class_device, B_TRUE))) {
+		goto error_device_device;
+	}
+
+	/* Check and register support for ACPI container device. */
+	if ((acpidev_options & ACPIDEV_OUSER_NO_CONTAINER) == 0) {
+		if (ACPI_FAILURE(acpidev_register_class(
+		    &acpidev_class_list_device, &acpidev_class_container,
+		    B_FALSE))) {
+			goto error_device_container;
+		}
+		*fp |= ACPI_DEVCFG_CONTAINER;
+	}
+
+	/* Check and register support for ACPI CPU device. */
+	if ((acpidev_options & ACPIDEV_OUSER_NO_CPU) == 0) {
+		/* Handle ACPI CPU Device */
+		if (ACPI_FAILURE(acpidev_register_class(
+		    &acpidev_class_list_device, &acpidev_class_cpu, B_FALSE))) {
+			goto error_device_cpu;
+		}
+		/* Handle ACPI Processor under _PR */
+		if (ACPI_FAILURE(acpidev_register_class(
+		    &acpidev_class_list_scope, &acpidev_class_cpu, B_FALSE))) {
+			goto error_scope_cpu;
+		}
+		/* House-keeping for CPU scan */
+		if (ACPI_FAILURE(acpidev_register_class(
+		    &acpidev_class_list_root, &acpidev_class_cpu, B_FALSE))) {
+			goto error_root_cpu;
+		}
+		BT_SET(acpidev_object_type_mask, ACPI_TYPE_PROCESSOR);
+		*fp |= ACPI_DEVCFG_CPU;
+	}
+
+	/* Check support for ACPI memory device. */
+	if ((acpidev_options & ACPIDEV_OUSER_NO_MEM) == 0) {
+		/*
+		 * Register the ACPI memory class driver onto the
+		 * acpidev_class_list_device list because ACPI module
+		 * class driver uses that list.
+		 */
+		if (ACPI_FAILURE(acpidev_register_class(
+		    &acpidev_class_list_device, &acpidev_class_memory,
+		    B_FALSE))) {
+			goto error_device_memory;
+		}
+		*fp |= ACPI_DEVCFG_MEMORY;
+	}
+
+	/* Check blacklist and load platform specific modules. */
+	rc = acpidev_load_plat_modules();
+	if (ACPI_FAILURE(rc)) {
+		ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to check blacklist "
+		    "or load pratform modules.");
+		goto error_plat;
+	}
+
+	return (AE_OK);
+
+error_plat:
+	if ((acpidev_options & ACPIDEV_OUSER_NO_MEM) == 0) {
+		(void) acpidev_unregister_class(&acpidev_class_list_device,
+		    &acpidev_class_memory);
+	}
+error_device_memory:
+	if (acpidev_options & ACPIDEV_OUSER_NO_CPU) {
+		(void) acpidev_unregister_class(&acpidev_class_list_root,
+		    &acpidev_class_cpu);
+	}
+error_root_cpu:
+	if (acpidev_options & ACPIDEV_OUSER_NO_CPU) {
+		(void) acpidev_unregister_class(&acpidev_class_list_scope,
+		    &acpidev_class_cpu);
+	}
+error_scope_cpu:
+	if (acpidev_options & ACPIDEV_OUSER_NO_CPU) {
+		(void) acpidev_unregister_class(&acpidev_class_list_device,
+		    &acpidev_class_cpu);
+	}
+error_device_cpu:
+	if ((acpidev_options & ACPIDEV_OUSER_NO_CONTAINER) == 0) {
+		(void) acpidev_unregister_class(&acpidev_class_list_device,
+		    &acpidev_class_container);
+	}
+error_device_container:
+	(void) acpidev_unregister_class(&acpidev_class_list_device,
+	    &acpidev_class_device);
+error_device_device:
+	(void) acpidev_unregister_class(&acpidev_class_list_root,
+	    &acpidev_class_device);
+error_root_device:
+	(void) acpidev_unregister_class(&acpidev_class_list_root,
+	    &acpidev_class_scope);
+error_out:
+	ACPIDEV_DEBUG(CE_WARN,
+	    "acpidev: failed to register built-in class drivers.");
+	*fp = 0;
+
+	return (AE_ERROR);
+}
+
+/*
+ * Called in single threaded context during boot, no protection for
+ * reentrance.
+ */
+static ACPI_STATUS
+acpidev_create_root_node(void)
+{
+	int circ, rv = AE_OK;
+	dev_info_t *dip = NULL;
+	acpidev_data_handle_t objhdl;
+	char *compatibles[] = {
+		ACPIDEV_HID_ROOTNEX,
+		ACPIDEV_TYPE_ROOTNEX,
+		ACPIDEV_HID_VIRTNEX,
+		ACPIDEV_TYPE_VIRTNEX,
+	};
+
+	ndi_devi_enter(ddi_root_node(), &circ);
+	ASSERT(acpidev_root_dip == NULL);
+
+	/* Query whether device node already exists. */
+	dip = ddi_find_devinfo(ACPIDEV_NODE_NAME_ROOT, -1, 0);
+	if (dip != NULL && ddi_get_parent(dip) == ddi_root_node()) {
+		ndi_devi_exit(ddi_root_node(), circ);
+		cmn_err(CE_WARN, "!acpidev: node /devices/%s already exists, "
+		    "disable driver.", ACPIDEV_NODE_NAME_ROOT);
+		return (AE_ALREADY_EXISTS);
+	}
+
+	/* Create the device node if it doesn't exist. */
+	rv = ndi_devi_alloc(ddi_root_node(), ACPIDEV_NODE_NAME_ROOT,
+	    (pnode_t)DEVI_SID_NODEID, &dip);
+	if (rv != NDI_SUCCESS) {
+		ndi_devi_exit(ddi_root_node(), circ);
+		ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to create device node "
+		    "for ACPI root with errcode %d.", rv);
+		return (AE_ERROR);
+	}
+
+	/* Build cross reference between dip and ACPI object. */
+	if (ACPI_FAILURE(acpica_tag_devinfo(dip, ACPI_ROOT_OBJECT))) {
+		(void) ddi_remove_child(dip, 0);
+		ndi_devi_exit(ddi_root_node(), circ);
+		ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to tag object %s.",
+		    ACPIDEV_OBJECT_NAME_SB);
+		return (AE_ERROR);
+	}
+
+	/* Set device properties. */
+	rv = ndi_prop_update_string_array(DDI_DEV_T_NONE, dip,
+	    OBP_COMPATIBLE, ACPIDEV_ARRAY_PARAM(compatibles));
+	if (rv == NDI_SUCCESS) {
+		rv = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
+		    OBP_DEVICETYPE, ACPIDEV_TYPE_ROOTNEX);
+	}
+	if (rv != DDI_SUCCESS) {
+		ACPIDEV_DEBUG(CE_WARN,
+		    "acpidev: failed to set device property for /devices/%s.",
+		    ACPIDEV_NODE_NAME_ROOT);
+		goto error_out;
+	}
+
+	/* Manually create an object handle for the root node */
+	objhdl = acpidev_data_create_handle(ACPI_ROOT_OBJECT);
+	if (objhdl == NULL) {
+		ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to create object "
+		    "handle for the root node.");
+		goto error_out;
+	}
+	objhdl->aod_level = 0;
+	objhdl->aod_hdl = ACPI_ROOT_OBJECT;
+	objhdl->aod_dip = dip;
+	objhdl->aod_class = &acpidev_class_scope;
+	objhdl->aod_status = acpidev_query_device_status(ACPI_ROOT_OBJECT);
+	objhdl->aod_iflag = ACPIDEV_ODF_STATUS_VALID |
+	    ACPIDEV_ODF_DEVINFO_CREATED | ACPIDEV_ODF_DEVINFO_TAGGED;
+
+	/* Bind device driver. */
+	(void) ndi_devi_bind_driver(dip, 0);
+
+	acpidev_root_dip = dip;
+	ndi_devi_exit(ddi_root_node(), circ);
+
+	return (AE_OK);
+
+error_out:
+	(void) acpica_untag_devinfo(dip, ACPI_ROOT_OBJECT);
+	(void) ddi_remove_child(dip, 0);
+	ndi_devi_exit(ddi_root_node(), circ);
+	return (AE_ERROR);
+}
+
+static void
+acpidev_initialize(void)
+{
+	int rc;
+	char *str = NULL;
+	uint64_t features = 0;
+
+	/* Check whether it has already been initialized. */
+	if (acpidev_status == ACPIDEV_STATUS_DISABLED) {
+		cmn_err(CE_CONT, "?acpidev: ACPI device autoconfig "
+		    "disabled by user.\n");
+		return;
+	} else if (acpidev_status != ACPIDEV_STATUS_UNKNOWN) {
+		ACPIDEV_DEBUG(CE_NOTE,
+		    "acpidev: initialization called more than once.");
+		return;
+	}
+
+	/* Check whether ACPI device autoconfig has been disabled by user. */
+	rc = ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
+	    DDI_PROP_DONTPASS, "acpidev-autoconfig", &str);
+	if (rc == DDI_SUCCESS) {
+		if (strcasecmp(str, "off") == 0 || strcasecmp(str, "no") == 0) {
+			cmn_err(CE_CONT, "?acpidev: ACPI device autoconfig "
+			    "disabled by user.\n");
+			ddi_prop_free(str);
+			acpidev_status = ACPIDEV_STATUS_DISABLED;
+			return;
+		}
+		ddi_prop_free(str);
+	}
+
+	/* Initialize acpica subsystem. */
+	if (ACPI_FAILURE(acpica_init())) {
+		cmn_err(CE_WARN,
+		    "!acpidev: failed to initialize acpica subsystem.");
+		acpidev_status = ACPIDEV_STATUS_FAILED;
+		return;
+	}
+
+	/* Check ACPICA subsystem status. */
+	if (!acpica_get_core_feature(ACPI_FEATURE_FULL_INIT)) {
+		cmn_err(CE_WARN, "!acpidev: ACPICA hasn't been fully "
+		    "initialized, ACPI device autoconfig will be disabled.");
+		acpidev_status = ACPIDEV_STATUS_DISABLED;
+		return;
+	}
+
+	/* Converts acpidev-options from type string to int, if any */
+	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
+	    DDI_PROP_DONTPASS, "acpidev-options", &str) == DDI_PROP_SUCCESS) {
+		long data;
+		rc = ddi_strtol(str, NULL, 0, &data);
+		if (rc == 0) {
+			(void) e_ddi_prop_remove(DDI_DEV_T_NONE,
+			    ddi_root_node(), "acpidev-options");
+			(void) e_ddi_prop_update_int(DDI_DEV_T_NONE,
+			    ddi_root_node(), "acpidev-options", data);
+		}
+		ddi_prop_free(str);
+	}
+	/* Get acpidev_options user options. */
+	acpidev_options = ddi_prop_get_int(DDI_DEV_T_ANY, ddi_root_node(),
+	    DDI_PROP_DONTPASS, "acpidev-options", acpidev_options);
+
+	/* Register all device class drivers. */
+	if (ACPI_FAILURE(acpidev_class_list_init(&features))) {
+		cmn_err(CE_WARN,
+		    "!acpidev: failed to initalize class driver lists.");
+		acpidev_status = ACPIDEV_STATUS_FAILED;
+		return;
+	}
+
+	/* Create root node for ACPI/firmware device subtree. */
+	if (ACPI_FAILURE(acpidev_create_root_node())) {
+		cmn_err(CE_WARN, "!acpidev: failed to create root node "
+		    "for acpi device tree.");
+		acpidev_class_list_fini();
+		acpidev_status = ACPIDEV_STATUS_FAILED;
+		return;
+	}
+
+	/* Notify acpica to enable ACPI device auto configuration. */
+	acpica_set_core_feature(ACPI_FEATURE_DEVCFG);
+	acpica_set_devcfg_feature(features);
+
+	ACPIDEV_DEBUG(CE_NOTE, "!acpidev: ACPI device autoconfig initialized.");
+	acpidev_status = ACPIDEV_STATUS_INITIALIZED;
+}
+
+/*
+ * Probe devices in ACPI namespace which can't be enumerated by other methods
+ * at boot time.
+ */
+static ACPI_STATUS
+acpidev_boot_probe_device(acpidev_op_type_t op_type)
+{
+	ACPI_STATUS rc = AE_OK;
+	acpidev_walk_info_t *infop;
+
+	ASSERT(acpidev_root_dip != NULL);
+	ASSERT(op_type == ACPIDEV_OP_BOOT_PROBE ||
+	    op_type == ACPIDEV_OP_BOOT_REPROBE);
+
+	infop = acpidev_alloc_walk_info(op_type, 0, ACPI_ROOT_OBJECT,
+	    &acpidev_class_list_root, NULL);
+	if (infop == NULL) {
+		ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to allocate walk info "
+		    "object in acpi_boot_probe_device().");
+		return (AE_ERROR);
+	}
+	/* Enumerate ACPI devices. */
+	rc = acpidev_probe_child(infop);
+	if (ACPI_FAILURE(rc)) {
+		cmn_err(CE_WARN, "!acpidev: failed to probe child object "
+		    "under ACPI root node.");
+	}
+	acpidev_free_walk_info(infop);
+
+	return (rc);
+}
+
+/*
+ * Platform specific device prober for ACPI virtual bus.
+ * It will be called in single-threaded environment to enumerate devices in
+ * ACPI namespace at boot time.
+ */
+static void
+acpidev_boot_probe(int type)
+{
+	ACPI_STATUS rc;
+
+	/* Initialize subsystem on first pass. */
+	mutex_enter(&acpidev_drv_lock);
+	if (type == 0) {
+		acpidev_initialize();
+		if (acpidev_status != ACPIDEV_STATUS_INITIALIZED &&
+		    acpidev_status != ACPIDEV_STATUS_DISABLED) {
+			cmn_err(CE_WARN, "!acpidev: driver disabled due to "
+			    "initalization failure.");
+		}
+	}
+
+	/* Probe ACPI devices */
+	if (type == 0 && acpidev_status == ACPIDEV_STATUS_INITIALIZED) {
+		rc = acpidev_boot_probe_device(ACPIDEV_OP_BOOT_PROBE);
+		if (ACPI_SUCCESS(rc)) {
+			acpidev_status = ACPIDEV_STATUS_FIRST_PASS;
+		} else {
+			ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to probe ACPI "
+			    "devices during boot.");
+			acpidev_status = ACPIDEV_STATUS_FAILED;
+		}
+	} else if (type != 0 && acpidev_status == ACPIDEV_STATUS_FIRST_PASS) {
+		rc = acpidev_boot_probe_device(ACPIDEV_OP_BOOT_REPROBE);
+		if (ACPI_SUCCESS(rc)) {
+			acpidev_status = ACPIDEV_STATUS_READY;
+		} else {
+			ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to reprobe "
+			    "ACPI devices during boot.");
+			acpidev_status = ACPIDEV_STATUS_FAILED;
+		}
+	} else if (acpidev_status != ACPIDEV_STATUS_FAILED &&
+	    acpidev_status != ACPIDEV_STATUS_DISABLED &&
+	    acpidev_status != ACPIDEV_STATUS_READY) {
+		cmn_err(CE_WARN,
+		    "!acpidev: invalid ACPI device autoconfig global status.");
+	}
+	mutex_exit(&acpidev_drv_lock);
+}
+
+ACPI_STATUS
+acpidev_probe_child(acpidev_walk_info_t *infop)
+{
+	int circ;
+	dev_info_t *pdip;
+	ACPI_STATUS res, rc = AE_OK;
+	ACPI_HANDLE child;
+	ACPI_OBJECT_TYPE type;
+	acpidev_class_list_t *it;
+	acpidev_walk_info_t *cinfop;
+	acpidev_data_handle_t datap;
+
+	/* Validate parameter first. */
+	ASSERT(infop != NULL);
+	if (infop == NULL) {
+		ACPIDEV_DEBUG(CE_WARN,
+		    "acpidev: infop is NULL in acpidev_probe_child().");
+		return (AE_BAD_PARAMETER);
+	}
+	ASSERT(infop->awi_level < ACPIDEV_MAX_ENUM_LEVELS - 1);
+	if (infop->awi_level >= ACPIDEV_MAX_ENUM_LEVELS - 1) {
+		ACPIDEV_DEBUG(CE_WARN, "acpidev: recursive level is too deep "
+		    "in acpidev_probe_child().");
+		return (AE_BAD_PARAMETER);
+	}
+	ASSERT(infop->awi_class_list != NULL);
+	ASSERT(infop->awi_hdl != NULL);
+	ASSERT(infop->awi_info != NULL);
+	ASSERT(infop->awi_name != NULL);
+	ASSERT(infop->awi_data != NULL);
+	if (infop->awi_class_list == NULL || infop->awi_hdl == NULL ||
+	    infop->awi_info == NULL || infop->awi_name == NULL ||
+	    infop->awi_data == NULL) {
+		ACPIDEV_DEBUG(CE_WARN,
+		    "acpidev: infop has NULL fields in acpidev_probe_child().");
+		return (AE_BAD_PARAMETER);
+	}
+	pdip = acpidev_walk_info_get_pdip(infop);
+	if (pdip == NULL) {
+		ACPIDEV_DEBUG(CE_WARN,
+		    "acpidev: pdip is NULL in acpidev_probe_child().");
+		return (AE_BAD_PARAMETER);
+	}
+
+	ndi_devi_enter(pdip, &circ);
+	rw_enter(&acpidev_class_lock, RW_READER);
+
+	/* Call pre-probe callback functions. */
+	for (it = *(infop->awi_class_list); it != NULL; it = it->acl_next) {
+		if (it->acl_class->adc_pre_probe == NULL) {
+			continue;
+		}
+		infop->awi_class_curr = it->acl_class;
+		if (ACPI_FAILURE(it->acl_class->adc_pre_probe(infop))) {
+			ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to pre-probe "
+			    "device of type %s under %s.",
+			    it->acl_class->adc_class_name, infop->awi_name);
+		}
+	}
+
+	/* Walk child objects. */
+	child = NULL;
+	while (ACPI_SUCCESS(AcpiGetNextObject(ACPI_TYPE_ANY,
+	    infop->awi_hdl, child, &child))) {
+		/* Skip object if we're not interested in it. */
+		if (ACPI_FAILURE(AcpiGetType(child, &type)) ||
+		    type > ACPI_TYPE_NS_NODE_MAX ||
+		    BT_TEST(acpidev_object_type_mask, type) == 0) {
+			continue;
+		}
+
+		/* Allocate the walk info structure. */
+		cinfop = acpidev_alloc_walk_info(infop->awi_op_type,
+		    infop->awi_level + 1, child, NULL, infop);
+		if (cinfop == NULL) {
+			ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to allocate "
+			    "walk info child object of %s.",
+			    infop->awi_name);
+			/* Mark error and continue to handle next child. */
+			rc = AE_ERROR;
+			continue;
+		}
+
+		/*
+		 * Remember the class list used to handle this object.
+		 * It should be the same list for different passes of scans.
+		 */
+		ASSERT(cinfop->awi_data != NULL);
+		datap = cinfop->awi_data;
+		if (cinfop->awi_op_type == ACPIDEV_OP_BOOT_PROBE) {
+			datap->aod_class_list = infop->awi_class_list;
+		} else if (datap->aod_class_list != infop->awi_class_list) {
+			ACPIDEV_DEBUG(CE_WARN,
+			    "acpidev: class list for %s has been changed",
+			    infop->awi_name);
+			acpidev_free_walk_info(cinfop);
+			continue;
+		}
+
+		/* Call registered process callbacks. */
+		for (it = *(infop->awi_class_list); it != NULL;
+		    it = it->acl_next) {
+			if (it->acl_class->adc_probe == NULL) {
+				continue;
+			}
+			cinfop->awi_class_curr = it->acl_class;
+			res = it->acl_class->adc_probe(cinfop);
+			if (ACPI_FAILURE(res)) {
+				rc = res;
+				ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to "
+				    "process object of type %s under %s.",
+				    it->acl_class->adc_class_name,
+				    infop->awi_name);
+			}
+		}
+
+		/* Free resources. */
+		acpidev_free_walk_info(cinfop);
+	}
+
+	/* Call post-probe callback functions. */
+	for (it = *(infop->awi_class_list); it != NULL; it = it->acl_next) {
+		if (it->acl_class->adc_post_probe == NULL) {
+			continue;
+		}
+		infop->awi_class_curr = it->acl_class;
+		if (ACPI_FAILURE(it->acl_class->adc_post_probe(infop))) {
+			ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to post-probe "
+			    "device of type %s under %s.",
+			    it->acl_class->adc_class_name, infop->awi_name);
+		}
+	}
+
+	rw_exit(&acpidev_class_lock);
+	ndi_devi_exit(pdip, circ);
+
+	return (rc);
+}
+
+ACPI_STATUS
+acpidev_process_object(acpidev_walk_info_t *infop, int flags)
+{
+	ACPI_STATUS rc = AE_OK;
+	char *devname;
+	dev_info_t *dip, *pdip;
+	ACPI_HANDLE hdl;
+	ACPI_DEVICE_INFO *adip;
+	acpidev_class_t *clsp;
+	acpidev_data_handle_t datap;
+	acpidev_filter_result_t res;
+
+	/* Validate parameters first. */
+	ASSERT(infop != NULL);
+	if (infop == NULL) {
+		ACPIDEV_DEBUG(CE_WARN,
+		    "acpidev: infop is NULL in acpidev_process_object().");
+		return (AE_BAD_PARAMETER);
+	}
+	ASSERT(infop->awi_hdl != NULL);
+	ASSERT(infop->awi_info != NULL);
+	ASSERT(infop->awi_data != NULL);
+	ASSERT(infop->awi_class_curr != NULL);
+	ASSERT(infop->awi_class_curr->adc_filter != NULL);
+	hdl = infop->awi_hdl;
+	adip = infop->awi_info;
+	datap = infop->awi_data;
+	clsp = infop->awi_class_curr;
+	if (hdl == NULL || datap == NULL || adip == NULL || clsp == NULL ||
+	    clsp->adc_filter == NULL) {
+		ACPIDEV_DEBUG(CE_WARN, "acpidev: infop has NULL pointer in "
+		    "acpidev_process_object().");
+		return (AE_BAD_PARAMETER);
+	}
+	pdip = acpidev_walk_info_get_pdip(infop);
+	if (pdip == NULL) {
+		ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to get pdip for %s "
+		    "in acpidev_process_object().", infop->awi_name);
+		return (AE_BAD_PARAMETER);
+	}
+
+	/*
+	 * Check whether the object has already been handled.
+	 * Tag and child dip pointer are used to indicate the object has been
+	 * handled by the ACPI auto configure driver. It has the
+	 * following usages:
+	 * 1) Prevent creating dip for objects which already have a dip
+	 *    when reloading the ACPI auto configure driver.
+	 * 2) Prevent creating multiple dips for ACPI objects with ACPI
+	 *    aliases. Currently ACPICA framework has no way to tell whether
+	 *    an object is an alias or not for some types of object. So tag
+	 *    is used to indicate that the object has been handled.
+	 * 3) Prevent multiple class drivers from creating multiple devices for
+	 *    the same ACPI object.
+	 */
+	if ((flags & ACPIDEV_PROCESS_FLAG_CREATE) &&
+	    (flags & ACPIDEV_PROCESS_FLAG_CHECK) &&
+	    !(infop->awi_flags & ACPIDEV_WI_DISABLE_CREATE) &&
+	    (infop->awi_flags & ACPIDEV_WI_DEVICE_CREATED)) {
+		ASSERT(infop->awi_dip != NULL);
+		ACPIDEV_DEBUG(CE_NOTE,
+		    "acpidev: device has already been created for object %s.",
+		    infop->awi_name);
+		return (AE_ALREADY_EXISTS);
+	}
+
+	/*
+	 * Determine action according to following rules based on device
+	 * status returned by _STA method. Please refer to ACPI3.0b section
+	 * 6.3.1 and 6.5.1.
+	 * present functioning enabled	Action
+	 *	0	0	x	Do nothing
+	 *	1	x	0	Create node in OFFLINE and scan child
+	 *	1	x	1	Create node and scan child
+	 *	x	1	0	Create node in OFFLINE and scan child
+	 *	x	1	1	Create node and scan child
+	 */
+	if ((datap->aod_iflag & ACPIDEV_ODF_STATUS_VALID) == 0 ||
+	    (flags & ACPIDEV_PROCESS_FLAG_SYNCSTATUS)) {
+		if (adip->Valid & ACPI_VALID_STA) {
+			datap->aod_status = adip->CurrentStatus;
+		} else {
+			datap->aod_status = acpidev_query_device_status(hdl);
+		}
+		datap->aod_iflag |= ACPIDEV_ODF_STATUS_VALID;
+	}
+	if (!acpidev_check_device_present(datap->aod_status)) {
+		ACPIDEV_DEBUG(CE_NOTE, "acpidev: object %s doesn't exist.",
+		    infop->awi_name);
+		return (AE_NOT_EXIST);
+	}
+
+	ASSERT(infop->awi_data != NULL);
+	ASSERT(infop->awi_parent != NULL);
+	ASSERT(infop->awi_parent->awi_data != NULL);
+	/* Put device into offline state if parent is in offline state. */
+	if (infop->awi_parent->awi_data->aod_iflag &
+	    ACPIDEV_ODF_DEVINFO_OFFLINE) {
+		flags |= ACPIDEV_PROCESS_FLAG_OFFLINE;
+	/* Put device into offline state if it's disabled. */
+	} else if (!acpidev_check_device_enabled(datap->aod_status)) {
+		flags |= ACPIDEV_PROCESS_FLAG_OFFLINE;
+	}
+	/*
+	 * Mark current node status as OFFLINE even if a device node will not
+	 * be created for it. This is needed to handle the case when the current
+	 * node is SKIPPED (no device node will be created for it), so that all
+	 * descedants of current nodes could be correctly marked as OFFLINE.
+	 */
+	if (flags & ACPIDEV_PROCESS_FLAG_OFFLINE) {
+		infop->awi_data->aod_iflag |= ACPIDEV_ODF_DEVINFO_OFFLINE;
+	}
+
+	/* Evaluate filtering rules and generate device name. */
+	devname = kmem_zalloc(ACPIDEV_MAX_NAMELEN + 1, KM_SLEEP);
+	(void) memcpy(devname, (char *)&adip->Name, sizeof (adip->Name));
+	if (flags & ACPIDEV_PROCESS_FLAG_CREATE) {
+		res = clsp->adc_filter(infop, devname, ACPIDEV_MAX_NAMELEN);
+	} else {
+		res = clsp->adc_filter(infop, NULL, 0);
+	}
+
+	/* Create device if requested. */
+	if ((flags & ACPIDEV_PROCESS_FLAG_CREATE) &&
+	    !(infop->awi_flags & ACPIDEV_WI_DISABLE_CREATE) &&
+	    !(infop->awi_flags & ACPIDEV_WI_DEVICE_CREATED) &&
+	    (res == ACPIDEV_FILTER_DEFAULT || res == ACPIDEV_FILTER_CREATE)) {
+		int ret;
+
+		/*
+		 * Allocate dip and set default properties.
+		 * Properties can be overriden in class specific init routines.
+		 */
+		ASSERT(infop->awi_dip == NULL);
+		ndi_devi_alloc_sleep(pdip, devname, (pnode_t)DEVI_SID_NODEID,
+		    &dip);
+		infop->awi_dip = dip;
+		ret = ndi_prop_update_string(DDI_DEV_T_NONE, dip,
+		    OBP_DEVICETYPE, clsp->adc_dev_type);
+		if (ret != NDI_SUCCESS) {
+			ACPIDEV_DEBUG(CE_WARN,
+			    "acpidev: failed to set device property for %s.",
+			    infop->awi_name);
+			(void) ddi_remove_child(dip, 0);
+			infop->awi_dip = NULL;
+			kmem_free(devname, ACPIDEV_MAX_NAMELEN + 1);
+			return (AE_ERROR);
+		}
+
+		/* Build cross reference between dip and ACPI object. */
+		if ((flags & ACPIDEV_PROCESS_FLAG_NOTAG) == 0 &&
+		    ACPI_FAILURE(acpica_tag_devinfo(dip, hdl))) {
+			cmn_err(CE_WARN,
+			    "!acpidev: failed to tag object %s.",
+			    infop->awi_name);
+			(void) ddi_remove_child(dip, 0);
+			infop->awi_dip = NULL;
+			kmem_free(devname, ACPIDEV_MAX_NAMELEN + 1);
+			return (AE_ERROR);
+		}
+
+		/* Call class specific initialization callback. */
+		if (clsp->adc_init != NULL &&
+		    ACPI_FAILURE(clsp->adc_init(infop))) {
+			ACPIDEV_DEBUG(CE_WARN,
+			    "acpidev: failed to initialize device %s.",
+			    infop->awi_name);
+			if ((flags & ACPIDEV_PROCESS_FLAG_NOTAG) == 0) {
+				(void) acpica_untag_devinfo(dip, hdl);
+			}
+			(void) ddi_remove_child(dip, 0);
+			infop->awi_dip = NULL;
+			kmem_free(devname, ACPIDEV_MAX_NAMELEN + 1);
+			return (AE_ERROR);
+		}
+
+		/* Set device into offline state if requested. */
+		if (flags & ACPIDEV_PROCESS_FLAG_OFFLINE) {
+			mutex_enter(&(DEVI(dip)->devi_lock));
+			DEVI_SET_DEVICE_OFFLINE(dip);
+			mutex_exit(&(DEVI(dip)->devi_lock));
+		}
+
+		/* Mark status */
+		infop->awi_flags |= ACPIDEV_WI_DEVICE_CREATED;
+		datap->aod_iflag |= ACPIDEV_ODF_DEVINFO_CREATED;
+		datap->aod_dip = dip;
+		datap->aod_class = clsp;
+		/* Hold reference count on class driver. */
+		atomic_inc_32(&clsp->adc_refcnt);
+		if ((flags & ACPIDEV_PROCESS_FLAG_NOTAG) == 0) {
+			datap->aod_iflag |= ACPIDEV_ODF_DEVINFO_TAGGED;
+		}
+
+		/* Bind device driver. */
+		if ((flags & ACPIDEV_PROCESS_FLAG_NOBIND) != 0) {
+			mutex_enter(&(DEVI(dip)->devi_lock));
+			DEVI(dip)->devi_flags |= DEVI_NO_BIND;
+			mutex_exit(&(DEVI(dip)->devi_lock));
+		} else {
+			(void) ndi_devi_bind_driver(dip, 0);
+		}
+	}
+
+	/* Free resources */
+	kmem_free(devname, ACPIDEV_MAX_NAMELEN + 1);
+	rc = AE_OK;
+
+	/* Recursively scan child objects if requested. */
+	switch (res) {
+	case ACPIDEV_FILTER_DEFAULT:
+		/* FALLTHROUGH */
+	case ACPIDEV_FILTER_SCAN:
+		/* Check if we need to scan child. */
+		if ((flags & ACPIDEV_PROCESS_FLAG_SCAN) &&
+		    !(infop->awi_flags & ACPIDEV_WI_DISABLE_SCAN) &&
+		    !(infop->awi_flags & ACPIDEV_WI_CHILD_SCANNED)) {
+			/* probe child object. */
+			rc = acpidev_probe_child(infop);
+			if (ACPI_FAILURE(rc)) {
+				ACPIDEV_DEBUG(CE_WARN,
+				    "acpidev: failed to probe subtree of %s.",
+				    infop->awi_name);
+				rc = AE_ERROR;
+			}
+			/* Mark object as scanned. */
+			infop->awi_flags |= ACPIDEV_WI_CHILD_SCANNED;
+		}
+		break;
+
+	case ACPIDEV_FILTER_CREATE:
+		/* FALLTHROUGH */
+	case ACPIDEV_FILTER_CONTINUE:
+		/* FALLTHROUGH */
+	case ACPIDEV_FILTER_SKIP:
+		break;
+
+	case ACPIDEV_FILTER_FAILED:
+		ACPIDEV_DEBUG(CE_WARN,
+		    "acpidev: failed to probe device for %s.",
+		    infop->awi_name);
+		rc = AE_ERROR;
+		break;
+
+	default:
+		cmn_err(CE_WARN,
+		    "!acpidev: unknown filter result code %d.", res);
+		rc = AE_ERROR;
+		break;
+	}
+
+	return (rc);
+}
+
+/*ARGSUSED*/
+acpidev_filter_result_t
+acpidev_filter_default(acpidev_walk_info_t *infop, ACPI_HANDLE hdl,
+    acpidev_filter_rule_t *afrp, char *devname, int len)
+{
+	ASSERT(afrp != NULL);
+	ASSERT(devname == NULL || len >= ACPIDEV_MAX_NAMELEN);
+	if (infop->awi_level < afrp->adf_minlvl ||
+	    infop->awi_level > afrp->adf_maxlvl) {
+		return (ACPIDEV_FILTER_CONTINUE);
+	} else if (afrp->adf_pattern != NULL &&
+	    strncmp(afrp->adf_pattern,
+	    (char *)&infop->awi_info->Name,
+	    sizeof (infop->awi_info->Name))) {
+		return (ACPIDEV_FILTER_CONTINUE);
+	}
+	if (afrp->adf_replace != NULL && devname != NULL) {
+		(void) strncpy(devname, afrp->adf_replace, len - 1);
+		devname[len - 1] = 0;
+	}
+
+	return (afrp->adf_retcode);
+}
+
+acpidev_filter_result_t
+acpidev_filter_device(acpidev_walk_info_t *infop, ACPI_HANDLE hdl,
+    acpidev_filter_rule_t *afrp, int entries, char *devname, int len)
+{
+	acpidev_filter_result_t res;
+
+	/* Evaluate filtering rules. */
+	for (; entries > 0; entries--, afrp++) {
+		if (afrp->adf_filter_func != NULL) {
+			res = afrp->adf_filter_func(infop, hdl, afrp,
+			    devname, len);
+		} else {
+			res = acpidev_filter_default(infop, hdl, afrp,
+			    devname, len);
+		}
+		if (res == ACPIDEV_FILTER_DEFAULT ||
+		    res == ACPIDEV_FILTER_SCAN) {
+			infop->awi_class_list = afrp->adf_class_list;
+			break;
+		}
+	}
+
+	return (res);
+}
+
+dev_info_t *
+acpidev_root_node(void)
+{
+	return (acpidev_root_dip);
+}
+
+ACPI_STATUS
+acpidev_register_class(acpidev_class_list_t **listpp, acpidev_class_t *clsp,
+    boolean_t tail)
+{
+	ACPI_STATUS rc;
+	acpidev_class_list_t *item;
+	acpidev_class_list_t *temp;
+
+	ASSERT(clsp != NULL);
+	ASSERT(listpp != NULL);
+	if (listpp == NULL || clsp == NULL) {
+		ACPIDEV_DEBUG(CE_WARN,
+		    "acpidev: invalid parameter in acpidev_register_class().");
+		return (AE_BAD_PARAMETER);
+	} else if (clsp->adc_version != ACPIDEV_CLASS_REV) {
+		cmn_err(CE_WARN,
+		    "!acpidev: class driver %s version mismatch.",
+		    clsp->adc_class_name);
+		return (AE_BAD_DATA);
+	}
+
+	rc = AE_OK;
+	item = kmem_zalloc(sizeof (*item), KM_SLEEP);
+	item->acl_class = clsp;
+	rw_enter(&acpidev_class_lock, RW_WRITER);
+	/* Check for duplicated item. */
+	for (temp = *listpp; temp != NULL; temp = temp->acl_next) {
+		if (temp->acl_class == clsp) {
+			cmn_err(CE_WARN,
+			    "!acpidev: register duplicate class driver %s.",
+			    clsp->adc_class_name);
+			rc = AE_ALREADY_EXISTS;
+			break;
+		}
+	}
+	if (ACPI_SUCCESS(rc)) {
+		if (tail) {
+			while (*listpp) {
+				listpp = &(*listpp)->acl_next;
+			}
+		}
+		item->acl_next = *listpp;
+		*listpp = item;
+	}
+	rw_exit(&acpidev_class_lock);
+	if (ACPI_FAILURE(rc)) {
+		kmem_free(item, sizeof (*item));
+	}
+
+	return (rc);
+}
+
+ACPI_STATUS
+acpidev_unregister_class(acpidev_class_list_t **listpp,
+    acpidev_class_t *clsp)
+{
+	ACPI_STATUS rc = AE_NOT_FOUND;
+	acpidev_class_list_t *temp;
+
+	ASSERT(clsp != NULL);
+	ASSERT(listpp != NULL);
+	if (listpp == NULL || clsp == NULL) {
+		ACPIDEV_DEBUG(CE_WARN, "acpidev: invalid parameter "
+		    "in acpidev_unregister_class().");
+		return (AE_BAD_PARAMETER);
+	}
+
+	rw_enter(&acpidev_class_lock, RW_WRITER);
+	for (temp = NULL; *listpp; listpp = &(*listpp)->acl_next) {
+		if ((*listpp)->acl_class == clsp) {
+			temp = *listpp;
+			*listpp = (*listpp)->acl_next;
+			break;
+		}
+	}
+	if (temp == NULL) {
+		ACPIDEV_DEBUG(CE_WARN, "acpidev: class %p(%s) doesn't exist "
+		    "in acpidev_unregister_class().",
+		    (void *)clsp, clsp->adc_class_name);
+		rc = AE_NOT_FOUND;
+	} else if (temp->acl_class->adc_refcnt != 0) {
+		ACPIDEV_DEBUG(CE_WARN, "acpidev: class %p(%s) is still in use "
+		    "in acpidev_unregister_class()..",
+		    (void *)clsp, clsp->adc_class_name);
+		rc = AE_ERROR;
+	} else {
+		kmem_free(temp, sizeof (*temp));
+		rc = AE_OK;
+	}
+	rw_exit(&acpidev_class_lock);
+
+	return (rc);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/i86pc/io/acpi/acpidev/acpidev_memory.c	Thu Aug 27 16:35:32 2009 -0700
@@ -0,0 +1,185 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 (c) 2009, Intel Corporation.
+ * All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/atomic.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/acpi/acpi.h>
+#include <sys/acpica.h>
+#include <sys/acpidev.h>
+#include <sys/acpidev_rsc.h>
+#include <sys/acpidev_impl.h>
+
+static ACPI_STATUS acpidev_memory_probe(acpidev_walk_info_t *infop);
+static acpidev_filter_result_t acpidev_memory_filter(
+    acpidev_walk_info_t *infop, char *devname, int maxlen);
+static ACPI_STATUS acpidev_memory_init(acpidev_walk_info_t *infop);
+
+/*
+ * Default class driver for ACPI memory objects.
+ */
+acpidev_class_t acpidev_class_memory = {
+	0,				/* adc_refcnt */
+	ACPIDEV_CLASS_REV1,		/* adc_version */
+	ACPIDEV_CLASS_ID_MEMORY,	/* adc_class_id */
+	"ACPI memory",			/* adc_class_name */
+	ACPIDEV_TYPE_MEMORY,		/* adc_dev_type */
+	NULL,				/* adc_private */
+	NULL,				/* adc_pre_probe */
+	NULL,				/* adc_post_probe */
+	acpidev_memory_probe,		/* adc_probe */
+	acpidev_memory_filter,		/* adc_filter */
+	acpidev_memory_init,		/* adc_init */
+	NULL,				/* adc_fini */
+};
+
+/*
+ * List of class drivers which will be called in order when handling
+ * children of ACPI memory objects.
+ */
+acpidev_class_list_t *acpidev_class_list_memory = NULL;
+
+static char *acpidev_memory_device_ids[] = {
+	ACPIDEV_HID_MEMORY,
+};
+
+static char *acpidev_memory_uid_formats[] = {
+	"MEM%x-%x",
+};
+
+/* Filter rule table for memory objects. */
+static acpidev_filter_rule_t acpidev_memory_filters[] = {
+	{	/* Ignore all memory objects under the ACPI root object */
+		NULL,
+		0,
+		ACPIDEV_FILTER_SKIP,
+		NULL,
+		1,
+		1,
+		NULL,
+		NULL,
+	},
+	{	/* Create node and scan child for all other memory objects */
+		NULL,
+		0,
+		ACPIDEV_FILTER_DEFAULT,
+		&acpidev_class_list_device,
+		2,
+		INT_MAX,
+		NULL,
+		ACPIDEV_NODE_NAME_MEMORY,
+	}
+};
+
+static ACPI_STATUS
+acpidev_memory_probe(acpidev_walk_info_t *infop)
+{
+	ACPI_STATUS rc;
+	int flags;
+
+	ASSERT(infop != NULL);
+	ASSERT(infop->awi_hdl != NULL);
+	ASSERT(infop->awi_info != NULL);
+	if (infop->awi_info->Type != ACPI_TYPE_DEVICE ||
+	    acpidev_match_device_id(infop->awi_info,
+	    ACPIDEV_ARRAY_PARAM(acpidev_memory_device_ids)) == 0) {
+		return (AE_OK);
+	}
+
+	if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE) {
+		flags = ACPIDEV_PROCESS_FLAG_SCAN | ACPIDEV_PROCESS_FLAG_CREATE;
+		rc = acpidev_process_object(infop, flags);
+	} else if (infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE) {
+		flags = ACPIDEV_PROCESS_FLAG_SCAN;
+		rc = acpidev_process_object(infop, flags);
+	} else if (infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
+		flags = ACPIDEV_PROCESS_FLAG_SCAN | ACPIDEV_PROCESS_FLAG_CREATE;
+		rc = acpidev_process_object(infop, flags);
+	} else {
+		ACPIDEV_DEBUG(CE_WARN, "acpidev: unknown operation type %u "
+		    "in acpidev_memory_probe.", infop->awi_op_type);
+		rc = AE_BAD_PARAMETER;
+	}
+	if (ACPI_FAILURE(rc) && rc != AE_NOT_EXIST && rc != AE_ALREADY_EXISTS) {
+		cmn_err(CE_WARN,
+		    "!acpidev: failed to process memory object %s.",
+		    infop->awi_name);
+	} else {
+		rc = AE_OK;
+	}
+
+	return (rc);
+}
+
+static acpidev_filter_result_t
+acpidev_memory_filter(acpidev_walk_info_t *infop, char *devname, int maxlen)
+{
+	acpidev_filter_result_t res;
+
+	ASSERT(infop != NULL);
+	if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE ||
+	    infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE ||
+	    infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
+		res = acpidev_filter_device(infop, infop->awi_hdl,
+		    ACPIDEV_ARRAY_PARAM(acpidev_memory_filters),
+		    devname, maxlen);
+	} else {
+		res = ACPIDEV_FILTER_FAILED;
+	}
+
+	return (res);
+}
+
+/*ARGSUSED*/
+static ACPI_STATUS
+acpidev_memory_init(acpidev_walk_info_t *infop)
+{
+	char *compatible[] = {
+		ACPIDEV_TYPE_MEMORY,
+		"mem"
+	};
+
+	ASSERT(infop != NULL);
+	ASSERT(infop->awi_hdl != NULL);
+	ASSERT(infop->awi_dip != NULL);
+	if (ACPI_FAILURE(acpidev_resource_process(infop, B_TRUE))) {
+		cmn_err(CE_WARN, "!acpidev: failed to process resources of "
+		    "memory device %s.", infop->awi_name);
+		return (AE_ERROR);
+	}
+
+	if (ACPI_FAILURE(acpidev_set_compatible(infop,
+	    ACPIDEV_ARRAY_PARAM(compatible)))) {
+		return (AE_ERROR);
+	}
+
+	if (ACPI_FAILURE(acpidev_set_unitaddr(infop,
+	    ACPIDEV_ARRAY_PARAM(acpidev_memory_uid_formats), NULL))) {
+		return (AE_ERROR);
+	}
+
+	return (AE_OK);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/i86pc/io/acpi/acpidev/acpidev_resource.c	Thu Aug 27 16:35:32 2009 -0700
@@ -0,0 +1,1110 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 (c) 2009, Intel Corporation.
+ * All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/cmn_err.h>
+#include <sys/sysmacros.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/acpi/acpi.h>
+#include <sys/acpica.h>
+#include <sys/acpidev.h>
+#include <sys/acpidev_rsc.h>
+#include <sys/acpidev_impl.h>
+
+#define	ACPIDEV_RES_INIT_ITEMS		8
+#define	ACPIDEV_RES_INCR_ITEMS		8
+
+/* Data structure to hold parsed resources during walking. */
+struct acpidev_resource_handle {
+	boolean_t			acpidev_consumer;
+	int				acpidev_reg_count;
+	int				acpidev_reg_max;
+	acpidev_phys_spec_t		*acpidev_regp;
+	acpidev_phys_spec_t		acpidev_regs[ACPIDEV_RES_INIT_ITEMS];
+	int				acpidev_range_count;
+	int				acpidev_range_max;
+	acpidev_ranges_t		*acpidev_rangep;
+	acpidev_ranges_t		acpidev_ranges[ACPIDEV_RES_INIT_ITEMS];
+	int				acpidev_bus_count;
+	int				acpidev_bus_max;
+	acpidev_bus_range_t		*acpidev_busp;
+	acpidev_bus_range_t		acpidev_buses[ACPIDEV_RES_INIT_ITEMS];
+	int				acpidev_irq_count;
+	int				acpidev_irqp[ACPIDEV_RES_IRQ_MAX];
+	int				acpidev_dma_count;
+	int				acpidev_dmap[ACPIDEV_RES_DMA_MAX];
+};
+
+acpidev_resource_handle_t
+acpidev_resource_handle_alloc(boolean_t consumer)
+{
+	acpidev_resource_handle_t rhdl;
+
+	rhdl = kmem_zalloc(sizeof (*rhdl), KM_SLEEP);
+	rhdl->acpidev_consumer = consumer;
+	rhdl->acpidev_reg_max = ACPIDEV_RES_INIT_ITEMS;
+	rhdl->acpidev_regp = rhdl->acpidev_regs;
+	rhdl->acpidev_range_max = ACPIDEV_RES_INIT_ITEMS;
+	rhdl->acpidev_rangep = rhdl->acpidev_ranges;
+	rhdl->acpidev_bus_max = ACPIDEV_RES_INIT_ITEMS;
+	rhdl->acpidev_busp = rhdl->acpidev_buses;
+
+	return (rhdl);
+}
+
+void
+acpidev_resource_handle_free(acpidev_resource_handle_t rhdl)
+{
+	size_t sz;
+
+	ASSERT(rhdl != NULL);
+	if (rhdl != NULL) {
+		if (rhdl->acpidev_regp != rhdl->acpidev_regs) {
+			sz = sizeof (acpidev_phys_spec_t) *
+			    rhdl->acpidev_reg_max;
+			kmem_free(rhdl->acpidev_regp, sz);
+		}
+		if (rhdl->acpidev_rangep != rhdl->acpidev_ranges) {
+			sz = sizeof (acpidev_ranges_t) *
+			    rhdl->acpidev_range_max;
+			kmem_free(rhdl->acpidev_rangep, sz);
+		}
+		if (rhdl->acpidev_busp != rhdl->acpidev_buses) {
+			sz = sizeof (acpidev_bus_range_t) *
+			    rhdl->acpidev_bus_max;
+			kmem_free(rhdl->acpidev_busp, sz);
+		}
+		kmem_free(rhdl, sizeof (struct acpidev_resource_handle));
+	}
+}
+
+static void
+acpidev_resource_handle_grow(acpidev_resource_handle_t rhdl)
+{
+	size_t sz;
+
+	if (rhdl->acpidev_reg_count == rhdl->acpidev_reg_max) {
+		acpidev_phys_spec_t *regp;
+
+		/* Prefer linear incremental here. */
+		rhdl->acpidev_reg_max += ACPIDEV_RES_INCR_ITEMS;
+		sz = sizeof (*regp) * rhdl->acpidev_reg_max;
+		regp = kmem_zalloc(sz, KM_SLEEP);
+		sz = sizeof (*regp) * rhdl->acpidev_reg_count;
+		bcopy(rhdl->acpidev_regp, regp, sz);
+		if (rhdl->acpidev_regp != rhdl->acpidev_regs) {
+			kmem_free(rhdl->acpidev_regp, sz);
+		}
+		rhdl->acpidev_regp = regp;
+	}
+
+	if (rhdl->acpidev_range_count == rhdl->acpidev_range_max) {
+		acpidev_ranges_t *rngp;
+
+		/* Prefer linear incremental here. */
+		rhdl->acpidev_range_max += ACPIDEV_RES_INCR_ITEMS;
+		sz = sizeof (*rngp) * rhdl->acpidev_range_max;
+		rngp = kmem_zalloc(sz, KM_SLEEP);
+		sz = sizeof (*rngp) * rhdl->acpidev_range_count;
+		bcopy(rhdl->acpidev_rangep, rngp, sz);
+		if (rhdl->acpidev_rangep != rhdl->acpidev_ranges) {
+			kmem_free(rhdl->acpidev_rangep, sz);
+		}
+		rhdl->acpidev_rangep = rngp;
+	}
+
+	if (rhdl->acpidev_bus_count == rhdl->acpidev_bus_max) {
+		acpidev_bus_range_t *busp;
+
+		/* Prefer linear incremental here. */
+		rhdl->acpidev_bus_max += ACPIDEV_RES_INCR_ITEMS;
+		sz = sizeof (*busp) * rhdl->acpidev_bus_max;
+		busp = kmem_zalloc(sz, KM_SLEEP);
+		sz = sizeof (*busp) * rhdl->acpidev_bus_count;
+		bcopy(rhdl->acpidev_busp, busp, sz);
+		if (rhdl->acpidev_busp != rhdl->acpidev_buses) {
+			kmem_free(rhdl->acpidev_busp, sz);
+		}
+		rhdl->acpidev_busp = busp;
+	}
+}
+
+ACPI_STATUS
+acpidev_resource_insert_reg(acpidev_resource_handle_t rhdl,
+    acpidev_regspec_t *regp)
+{
+	ASSERT(rhdl != NULL);
+	ASSERT(regp != NULL);
+	if (rhdl->acpidev_reg_count >= rhdl->acpidev_reg_max) {
+		acpidev_resource_handle_grow(rhdl);
+	}
+	ASSERT(rhdl->acpidev_reg_count < rhdl->acpidev_reg_max);
+	rhdl->acpidev_regp[rhdl->acpidev_reg_count] = *regp;
+	rhdl->acpidev_reg_count++;
+
+	return (AE_OK);
+}
+
+ACPI_STATUS
+acpidev_resource_get_regs(acpidev_resource_handle_t rhdl,
+    uint_t mask, uint_t value, acpidev_regspec_t *regp, uint_t *cntp)
+{
+	uint_t i, j;
+
+	ASSERT(rhdl != NULL);
+	ASSERT(cntp != NULL);
+	if (rhdl == NULL || cntp == NULL || (regp == NULL && *cntp != 0)) {
+		return (AE_BAD_PARAMETER);
+	}
+	for (i = 0, j = 0; i < rhdl->acpidev_reg_count; i++) {
+		if ((rhdl->acpidev_regp[i].phys_hi & mask) == value) {
+			if (j < *cntp) {
+				regp[j] = rhdl->acpidev_regp[i];
+			}
+			j++;
+		}
+	}
+	if (j >= *cntp) {
+		*cntp = j;
+		return (AE_LIMIT);
+	} else {
+		*cntp = j;
+		return (AE_OK);
+	}
+}
+
+uint_t
+acpidev_resource_get_reg_count(acpidev_resource_handle_t rhdl,
+    uint_t mask, uint_t value)
+{
+	uint_t i, j;
+
+	ASSERT(rhdl != NULL);
+	for (i = 0, j = 0; i < rhdl->acpidev_reg_count; i++) {
+		if ((rhdl->acpidev_regp[i].phys_hi & mask) == value) {
+			j++;
+		}
+	}
+
+	return (j);
+}
+
+ACPI_STATUS
+acpidev_resource_insert_range(acpidev_resource_handle_t rhdl,
+    acpidev_ranges_t *rangep)
+{
+	ASSERT(rhdl != NULL);
+	ASSERT(rangep != NULL);
+	if (rhdl->acpidev_range_count >= rhdl->acpidev_range_max) {
+		acpidev_resource_handle_grow(rhdl);
+	}
+	ASSERT(rhdl->acpidev_range_count < rhdl->acpidev_range_max);
+	rhdl->acpidev_rangep[rhdl->acpidev_range_count] = *rangep;
+	rhdl->acpidev_range_count++;
+
+	return (AE_OK);
+}
+
+ACPI_STATUS
+acpidev_resource_get_ranges(acpidev_resource_handle_t rhdl,
+    uint_t mask, uint_t value, acpidev_ranges_t *rangep, uint_t *cntp)
+{
+	uint_t i, j;
+
+	ASSERT(rhdl != NULL);
+	ASSERT(cntp != NULL);
+	if (rhdl == NULL || cntp == NULL || (rangep == NULL && *cntp != 0)) {
+		return (AE_BAD_PARAMETER);
+	}
+	for (i = 0, j = 0; i < rhdl->acpidev_range_count; i++) {
+		if ((rhdl->acpidev_rangep[i].child_hi & mask) == value) {
+			if (j < *cntp) {
+				rangep[j] = rhdl->acpidev_rangep[i];
+			}
+			j++;
+		}
+	}
+	if (j >= *cntp) {
+		*cntp = j;
+		return (AE_LIMIT);
+	} else {
+		*cntp = j;
+		return (AE_OK);
+	}
+}
+
+uint_t
+acpidev_resource_get_range_count(acpidev_resource_handle_t rhdl,
+    uint_t mask, uint_t value)
+{
+	uint_t i, j;
+
+	ASSERT(rhdl != NULL);
+	for (i = 0, j = 0; i < rhdl->acpidev_range_count; i++) {
+		if ((rhdl->acpidev_rangep[i].child_hi & mask) == value) {
+			j++;
+		}
+	}
+
+	return (j);
+}
+
+ACPI_STATUS
+acpidev_resource_insert_bus(acpidev_resource_handle_t rhdl,
+    acpidev_bus_range_t *busp)
+{
+	ASSERT(rhdl != NULL);
+	ASSERT(busp != NULL);
+	if (rhdl->acpidev_bus_count >= rhdl->acpidev_bus_max) {
+		acpidev_resource_handle_grow(rhdl);
+	}
+	ASSERT(rhdl->acpidev_bus_count < rhdl->acpidev_bus_max);
+	rhdl->acpidev_busp[rhdl->acpidev_bus_count] = *busp;
+	rhdl->acpidev_bus_count++;
+
+	return (AE_OK);
+}
+
+ACPI_STATUS
+acpidev_resource_get_buses(acpidev_resource_handle_t rhdl,
+    acpidev_bus_range_t *busp, uint_t *cntp)
+{
+	uint_t i, j;
+
+	ASSERT(rhdl != NULL);
+	ASSERT(cntp != NULL);
+	if (rhdl == NULL || cntp == NULL || (busp == NULL && *cntp != 0)) {
+		return (AE_BAD_PARAMETER);
+	}
+	for (i = 0, j = 0; i < rhdl->acpidev_bus_count; i++) {
+		if (j < *cntp) {
+			busp[j] = rhdl->acpidev_busp[i];
+		}
+		j++;
+	}
+	if (j >= *cntp) {
+		*cntp = j;
+		return (AE_LIMIT);
+	} else {
+		*cntp = j;
+		return (AE_OK);
+	}
+}
+
+uint_t
+acpidev_resource_get_bus_count(acpidev_resource_handle_t rhdl)
+{
+	ASSERT(rhdl != NULL);
+	return (rhdl->acpidev_bus_count);
+}
+
+ACPI_STATUS
+acpidev_resource_insert_dma(acpidev_resource_handle_t rhdl, int dma)
+{
+	ASSERT(rhdl != NULL);
+	if (rhdl->acpidev_dma_count >= ACPIDEV_RES_DMA_MAX) {
+		ACPIDEV_DEBUG(CE_WARN,
+		    "acpidev: too many DMA resources, max %u.",
+		    ACPIDEV_RES_DMA_MAX);
+		return (AE_LIMIT);
+	}
+	rhdl->acpidev_dmap[rhdl->acpidev_dma_count] = dma;
+	rhdl->acpidev_dma_count++;
+
+	return (AE_OK);
+}
+
+ACPI_STATUS
+acpidev_resource_get_dmas(acpidev_resource_handle_t rhdl,
+    uint_t *dmap, uint_t *cntp)
+{
+	uint_t i, j;
+
+	ASSERT(rhdl != NULL);
+	ASSERT(cntp != NULL);
+	if (rhdl == NULL || cntp == NULL || (dmap == NULL && *cntp != 0)) {
+		return (AE_BAD_PARAMETER);
+	}
+	for (i = 0, j = 0; i < rhdl->acpidev_dma_count; i++) {
+		if (j < *cntp) {
+			dmap[j] = rhdl->acpidev_dmap[i];
+		}
+		j++;
+	}
+	if (j >= *cntp) {
+		*cntp = j;
+		return (AE_LIMIT);
+	} else {
+		*cntp = j;
+		return (AE_OK);
+	}
+}
+
+uint_t
+acpidev_resource_get_dma_count(acpidev_resource_handle_t rhdl)
+{
+	ASSERT(rhdl != NULL);
+	return (rhdl->acpidev_dma_count);
+}
+
+ACPI_STATUS
+acpidev_resource_insert_irq(acpidev_resource_handle_t rhdl, int irq)
+{
+	ASSERT(rhdl != NULL);
+	if (rhdl->acpidev_irq_count >= ACPIDEV_RES_IRQ_MAX) {
+		ACPIDEV_DEBUG(CE_WARN,
+		    "acpidev: too many IRQ resources, max %u.",
+		    ACPIDEV_RES_IRQ_MAX);
+		return (AE_LIMIT);
+	}
+	rhdl->acpidev_irqp[rhdl->acpidev_irq_count] = irq;
+	rhdl->acpidev_irq_count++;
+
+	return (AE_OK);
+}
+
+ACPI_STATUS
+acpidev_resource_get_irqs(acpidev_resource_handle_t rhdl,
+    uint_t *irqp, uint_t *cntp)
+{
+	uint_t i, j;
+
+	ASSERT(rhdl != NULL);
+	ASSERT(cntp != NULL);
+	if (rhdl == NULL || cntp == NULL || (irqp == NULL && *cntp != 0)) {
+		return (AE_BAD_PARAMETER);
+	}
+	for (i = 0, j = 0; i < rhdl->acpidev_irq_count; i++) {
+		if (j < *cntp) {
+			irqp[j] = rhdl->acpidev_irqp[i];
+		}
+		j++;
+	}
+	if (j >= *cntp) {
+		*cntp = j;
+		return (AE_LIMIT);
+	} else {
+		*cntp = j;
+		return (AE_OK);
+	}
+}
+
+uint_t
+acpidev_resource_get_irq_count(acpidev_resource_handle_t rhdl)
+{
+	ASSERT(rhdl != NULL);
+	return (rhdl->acpidev_irq_count);
+}
+
+static ACPI_STATUS
+acpidev_resource_address64(acpidev_resource_handle_t rhdl,
+    ACPI_RESOURCE_ADDRESS64 *addrp)
+{
+	ACPI_STATUS rc = AE_OK;
+	uint_t high;
+
+	ASSERT(addrp != NULL && rhdl != NULL);
+	if (addrp->AddressLength == 0) {
+		return (AE_OK);
+	}
+
+	switch (addrp->ResourceType) {
+	case ACPI_MEMORY_RANGE:
+		high = ACPIDEV_REG_TYPE_MEMORY;
+		if (addrp->Decode == ACPI_SUB_DECODE) {
+			high |= ACPIDEV_REG_SUB_DEC;
+		}
+		if (addrp->Info.Mem.Translation) {
+			high |= ACPIDEV_REG_TRANSLATED;
+		}
+		if (addrp->Info.Mem.Caching == ACPI_NON_CACHEABLE_MEMORY) {
+			high |= ACPIDEV_REG_MEM_COHERENT_NC;
+		} else if (addrp->Info.Mem.Caching == ACPI_CACHABLE_MEMORY) {
+			high |= ACPIDEV_REG_MEM_COHERENT_CA;
+		} else if (addrp->Info.Mem.Caching ==
+		    ACPI_WRITE_COMBINING_MEMORY) {
+			high |= ACPIDEV_REG_MEM_COHERENT_WC;
+		} else if (addrp->Info.Mem.Caching ==
+		    ACPI_PREFETCHABLE_MEMORY) {
+			high |= ACPIDEV_REG_MEM_COHERENT_PF;
+		} else {
+			ACPIDEV_DEBUG(CE_WARN,
+			    "acpidev: unknown memory caching type %u.",
+			    addrp->Info.Mem.Caching);
+			rc = AE_ERROR;
+			break;
+		}
+		if (addrp->Info.Mem.WriteProtect == ACPI_READ_WRITE_MEMORY) {
+			high |= ACPIDEV_REG_MEM_WRITABLE;
+		}
+
+		/* Generate 'reg' for producer. */
+		if (addrp->ProducerConsumer == ACPI_CONSUMER &&
+		    rhdl->acpidev_consumer == B_TRUE) {
+			acpidev_regspec_t reg;
+
+			reg.phys_hi = high;
+			reg.phys_mid = addrp->Minimum >> 32;
+			reg.phys_low = addrp->Minimum & 0xFFFFFFFF;
+			reg.size_hi = addrp->AddressLength >> 32;
+			reg.size_low = addrp->AddressLength & 0xFFFFFFFF;
+			rc = acpidev_resource_insert_reg(rhdl, &reg);
+			if (ACPI_FAILURE(rc)) {
+				ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to "
+				    "insert regspec into resource handle.");
+			}
+		/* Generate 'ranges' for producer. */
+		} else if (addrp->ProducerConsumer == ACPI_PRODUCER &&
+		    rhdl->acpidev_consumer == B_FALSE) {
+			uint64_t paddr;
+			acpidev_ranges_t range;
+
+			range.child_hi = high;
+			range.child_mid = addrp->Minimum >> 32;
+			range.child_low = addrp->Minimum & 0xFFFFFFFF;
+			/* It's IO on parent side if Translation is true. */
+			if (addrp->Info.Mem.Translation) {
+				range.parent_hi = ACPIDEV_REG_TYPE_IO;
+			} else {
+				range.parent_hi = high;
+			}
+			paddr = addrp->Minimum + addrp->TranslationOffset;
+			range.parent_mid = paddr >> 32;
+			range.parent_low = paddr & 0xFFFFFFFF;
+			range.size_hi = addrp->AddressLength >> 32;
+			range.size_low = addrp->AddressLength & 0xFFFFFFFF;
+			rc = acpidev_resource_insert_range(rhdl, &range);
+			if (ACPI_FAILURE(rc)) {
+				ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to "
+				    "insert range into resource handle.");
+			}
+		}
+		break;
+
+	case ACPI_IO_RANGE:
+		high = ACPIDEV_REG_TYPE_IO;
+		if (addrp->Decode == ACPI_SUB_DECODE) {
+			high |= ACPIDEV_REG_SUB_DEC;
+		}
+		if (addrp->Info.Io.Translation) {
+			high |= ACPIDEV_REG_TRANSLATED;
+		}
+		if (addrp->Info.Io.RangeType == ACPI_NON_ISA_ONLY_RANGES) {
+			high |= ACPIDEV_REG_IO_RANGE_NONISA;
+		} else if (addrp->Info.Io.RangeType == ACPI_ISA_ONLY_RANGES) {
+			high |= ACPIDEV_REG_IO_RANGE_ISA;
+		} else if (addrp->Info.Io.RangeType == ACPI_ENTIRE_RANGE) {
+			high |= ACPIDEV_REG_IO_RANGE_FULL;
+		} else {
+			ACPIDEV_DEBUG(CE_WARN,
+			    "acpidev: unknown IO range type %u.",
+			    addrp->Info.Io.RangeType);
+			rc = AE_ERROR;
+			break;
+		}
+		if (addrp->Info.Io.TranslationType == ACPI_SPARSE_TRANSLATION) {
+			high |= ACPIDEV_REG_IO_SPARSE;
+		}
+
+		/* Generate 'reg' for producer. */
+		if (addrp->ProducerConsumer == ACPI_CONSUMER &&
+		    rhdl->acpidev_consumer == B_TRUE) {
+			acpidev_regspec_t reg;
+
+			reg.phys_hi = high;
+			reg.phys_mid = addrp->Minimum >> 32;
+			reg.phys_low = addrp->Minimum & 0xFFFFFFFF;
+			reg.size_hi = addrp->AddressLength >> 32;
+			reg.size_low = addrp->AddressLength & 0xFFFFFFFF;
+			rc = acpidev_resource_insert_reg(rhdl, &reg);
+			if (ACPI_FAILURE(rc)) {
+				ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to "
+				    "insert regspec into resource handle.");
+			}
+		/* Generate 'ranges' for producer. */
+		} else if (addrp->ProducerConsumer == ACPI_PRODUCER &&
+		    rhdl->acpidev_consumer == B_FALSE) {
+			uint64_t paddr;
+			acpidev_ranges_t range;
+
+			range.child_hi = high;
+			range.child_mid = addrp->Minimum >> 32;
+			range.child_low = addrp->Minimum & 0xFFFFFFFF;
+			/* It's Memory on parent side if Translation is true. */
+			if (addrp->Info.Io.Translation) {
+				range.parent_hi = ACPIDEV_REG_TYPE_MEMORY;
+			} else {
+				range.parent_hi = high;
+			}
+			paddr = addrp->Minimum + addrp->TranslationOffset;
+			range.parent_mid = paddr >> 32;
+			range.parent_low = paddr & 0xFFFFFFFF;
+			range.size_hi = addrp->AddressLength >> 32;
+			range.size_low = addrp->AddressLength & 0xFFFFFFFF;
+			rc = acpidev_resource_insert_range(rhdl, &range);
+			if (ACPI_FAILURE(rc)) {
+				ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to "
+				    "insert range into resource handle.");
+			}
+		}
+		break;
+
+	case ACPI_BUS_NUMBER_RANGE:
+		/* Only support producer of BUS. */
+		if (addrp->ProducerConsumer == ACPI_PRODUCER &&
+		    rhdl->acpidev_consumer == B_FALSE) {
+			uint64_t end;
+			acpidev_bus_range_t bus;
+
+			end = addrp->Minimum + addrp->AddressLength;
+			if (end < addrp->Minimum || end > UINT_MAX) {
+				ACPIDEV_DEBUG(CE_WARN, "acpidev: bus range "
+				    "in ADDRESS64 is invalid.");
+				rc = AE_ERROR;
+				break;
+			}
+			bus.bus_start = addrp->Minimum & 0xFFFFFFFF;
+			bus.bus_end = end & 0xFFFFFFFF;
+			ASSERT(bus.bus_start <= bus.bus_end);
+			rc = acpidev_resource_insert_bus(rhdl, &bus);
+			if (ACPI_FAILURE(rc)) {
+				ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to "
+				    "insert bus range into resource handle.");
+			}
+		}
+		break;
+
+	default:
+		ACPIDEV_DEBUG(CE_WARN,
+		    "acpidev: unknown resource type %u in ADDRESS64.",
+		    addrp->ResourceType);
+		rc = AE_BAD_PARAMETER;
+	}
+
+	return (rc);
+}
+
+static ACPI_STATUS
+acpidev_resource_walk_producer(ACPI_RESOURCE *rscp, void *ctxp)
+{
+	ACPI_STATUS rc = AE_OK;
+	acpidev_resource_handle_t rhdl;
+
+	ASSERT(ctxp != NULL);
+	rhdl = (acpidev_resource_handle_t)ctxp;
+	ASSERT(rhdl->acpidev_consumer == B_FALSE);
+
+	switch (rscp->Type) {
+	case ACPI_RESOURCE_TYPE_DMA:
+	case ACPI_RESOURCE_TYPE_IRQ:
+	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
+	case ACPI_RESOURCE_TYPE_FIXED_IO:
+	case ACPI_RESOURCE_TYPE_MEMORY24:
+	case ACPI_RESOURCE_TYPE_MEMORY32:
+	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
+	case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
+	case ACPI_RESOURCE_TYPE_VENDOR:
+		ACPIDEV_DEBUG(CE_NOTE,
+		    "acpidev: unsupported producer resource type %u, ignored.",
+		    rscp->Type);
+		break;
+
+	case ACPI_RESOURCE_TYPE_IO:
+	{
+		acpidev_ranges_t range;
+
+		range.child_hi = ACPIDEV_REG_TYPE_IO;
+		range.child_hi |= ACPIDEV_REG_IO_RANGE_FULL;
+		if (rscp->Data.Io.IoDecode == ACPI_DECODE_16) {
+			range.child_hi |= ACPIDEV_REG_IO_DECODE16;
+		}
+		range.parent_hi = range.child_hi;
+		range.parent_mid = range.child_mid = 0;
+		range.parent_low = range.child_low = rscp->Data.Io.Minimum;
+		range.size_hi = 0;
+		range.size_low = rscp->Data.Io.AddressLength;
+		if ((uint64_t)range.child_low + range.size_low > UINT16_MAX) {
+			ACPIDEV_DEBUG(CE_WARN, "acpidev: invalid IO record, "
+			    "IO max is out of range.");
+			rc = AE_ERROR;
+		} else if (range.size_low != 0) {
+			rc = acpidev_resource_insert_range(rhdl, &range);
+			if (ACPI_FAILURE(rc)) {
+				ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to "
+				    "insert range into resource handle.");
+			}
+		}
+		break;
+	}
+
+	case ACPI_RESOURCE_TYPE_ADDRESS16:
+	case ACPI_RESOURCE_TYPE_ADDRESS32:
+	case ACPI_RESOURCE_TYPE_ADDRESS64:
+	{
+		ACPI_RESOURCE_ADDRESS64 addr64;
+
+		if (rscp->Data.Address.ProducerConsumer != ACPI_PRODUCER) {
+			ACPIDEV_DEBUG(CE_NOTE, "acpidev: producer encountered "
+			    "a CONSUMER resource, ignored.");
+		} else if (ACPI_FAILURE(AcpiResourceToAddress64(rscp,
+		    &addr64))) {
+			ACPIDEV_DEBUG(CE_WARN,
+			    "acpidev: failed to convert resource to ADDR64.");
+		} else if (ACPI_FAILURE(rc = acpidev_resource_address64(rhdl,
+		    &addr64))) {
+			ACPIDEV_DEBUG(CE_WARN,
+			    "acpidev: failed to handle ADDRESS resource.");
+		}
+		break;
+	}
+
+	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
+	{
+		ACPI_RESOURCE_ADDRESS64 addr64;
+
+		if (rscp->Data.ExtAddress64.ProducerConsumer != ACPI_PRODUCER) {
+			ACPIDEV_DEBUG(CE_NOTE, "acpidev: producer encountered "
+			    "a CONSUMER resource, ignored.");
+			break;
+		}
+
+		*(ACPI_RESOURCE_ADDRESS *)&addr64 = rscp->Data.Address;
+		addr64.Granularity = rscp->Data.ExtAddress64.Granularity;
+		addr64.Minimum = rscp->Data.ExtAddress64.Minimum;
+		addr64.Maximum = rscp->Data.ExtAddress64.Maximum;
+		addr64.TranslationOffset =
+		    rscp->Data.ExtAddress64.TranslationOffset;
+		addr64.AddressLength = rscp->Data.ExtAddress64.AddressLength;
+		if (ACPI_FAILURE(rc = acpidev_resource_address64(rhdl,
+		    &addr64))) {
+			ACPIDEV_DEBUG(CE_WARN,
+			    "acpidev: failed to handle EXTADDRESS resource.");
+		}
+		break;
+	}
+
+	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
+	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
+		ACPIDEV_DEBUG(CE_NOTE, "acpidev: producer encountered "
+		    "START_DEPENDENT or END_DEPENDENT tag, ignored.");
+		break;
+
+	case ACPI_RESOURCE_TYPE_END_TAG:
+		/* Finish walking when we encounter END_TAG. */
+		rc = AE_CTRL_TERMINATE;
+		break;
+
+	default:
+		ACPIDEV_DEBUG(CE_NOTE,
+		    "acpidev: unknown ACPI resource type %u, ignored.",
+		    rscp->Type);
+		break;
+	}
+
+	return (rc);
+}
+
+static ACPI_STATUS
+acpidev_resource_walk_consumer(ACPI_RESOURCE *rscp, void *ctxp)
+{
+	ACPI_STATUS rc = AE_OK;
+	acpidev_resource_handle_t rhdl;
+
+	ASSERT(ctxp != NULL);
+	rhdl = (acpidev_resource_handle_t)ctxp;
+	ASSERT(rhdl->acpidev_consumer == B_TRUE);
+
+	switch (rscp->Type) {
+	case ACPI_RESOURCE_TYPE_MEMORY24:
+	case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
+	case ACPI_RESOURCE_TYPE_VENDOR:
+		ACPIDEV_DEBUG(CE_NOTE,
+		    "acpidev: unsupported consumer resource type %u, ignored.",
+		    rscp->Type);
+		break;
+
+	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
+	{
+		int i;
+
+		if (rscp->Data.ExtendedIrq.ProducerConsumer != ACPI_CONSUMER) {
+			ACPIDEV_DEBUG(CE_NOTE, "acpidev: consumer encountered "
+			    "a PRODUCER resource, ignored.");
+			break;
+		}
+		for (i = 0; i < rscp->Data.ExtendedIrq.InterruptCount; i++) {
+			if (ACPI_SUCCESS(acpidev_resource_insert_irq(rhdl,
+			    rscp->Data.ExtendedIrq.Interrupts[i]))) {
+				continue;
+			}
+			ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to insert"
+			    "Extended IRQ into resource handle.");
+			rc = AE_ERROR;
+			break;
+		}
+		break;
+	}
+
+	case ACPI_RESOURCE_TYPE_IRQ:
+	{
+		int i;
+
+		for (i = 0; i < rscp->Data.Irq.InterruptCount; i++) {
+			if (ACPI_SUCCESS(acpidev_resource_insert_irq(rhdl,
+			    rscp->Data.Irq.Interrupts[i]))) {
+				continue;
+			}
+			ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to insert"
+			    "IRQ into resource handle.");
+			rc = AE_ERROR;
+			break;
+		}
+		break;
+	}
+
+	case ACPI_RESOURCE_TYPE_DMA:
+	{
+		int i;
+
+		for (i = 0; i < rscp->Data.Dma.ChannelCount; i++) {
+			if (ACPI_SUCCESS(acpidev_resource_insert_dma(rhdl,
+			    rscp->Data.Dma.Channels[i]))) {
+				continue;
+			}
+			ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to insert"
+			    "dma into resource handle.");
+			rc = AE_ERROR;
+			break;
+		}
+		break;
+	}
+
+	case ACPI_RESOURCE_TYPE_IO:
+	case ACPI_RESOURCE_TYPE_FIXED_IO:
+	{
+		acpidev_regspec_t reg;
+
+		reg.phys_hi = ACPIDEV_REG_TYPE_IO;
+		reg.phys_hi |= ACPIDEV_REG_IO_RANGE_FULL;
+		if (rscp->Type == ACPI_RESOURCE_TYPE_IO) {
+			if (rscp->Data.Io.IoDecode == ACPI_DECODE_16) {
+				reg.phys_hi |= ACPIDEV_REG_IO_DECODE16;
+			}
+			reg.phys_low = rscp->Data.Io.Minimum;
+			reg.size_low = rscp->Data.Io.AddressLength;
+		} else {
+			reg.phys_hi |= ACPIDEV_REG_IO_DECODE16;
+			reg.phys_low = rscp->Data.FixedIo.Address;
+			reg.size_low = rscp->Data.FixedIo.AddressLength;
+		}
+		reg.phys_mid = 0;
+		reg.size_hi = 0;
+		if ((uint64_t)reg.phys_low + reg.size_low > UINT16_MAX) {
+			ACPIDEV_DEBUG(CE_WARN, "acpidev: invalid IO/FIXEDIO "
+			    "record, IO max is out of range.");
+			rc = AE_ERROR;
+		} else if (reg.size_low != 0) {
+			rc = acpidev_resource_insert_reg(rhdl, &reg);
+			if (ACPI_FAILURE(rc)) {
+				ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to "
+				    "insert reg into resource handle.");
+			}
+		}
+		break;
+	}
+
+	case ACPI_RESOURCE_TYPE_MEMORY32:
+	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
+	{
+		acpidev_regspec_t reg;
+
+		reg.phys_hi = ACPIDEV_REG_TYPE_MEMORY;
+		reg.phys_hi |= ACPIDEV_REG_MEM_COHERENT_CA;
+		if (rscp->Type == ACPI_RESOURCE_TYPE_MEMORY32) {
+			if (rscp->Data.Memory32.WriteProtect ==
+			    ACPI_READ_WRITE_MEMORY) {
+				reg.phys_hi |= ACPIDEV_REG_MEM_WRITABLE;
+			}
+			reg.phys_low = rscp->Data.Memory32.Minimum;
+			reg.size_low = rscp->Data.Memory32.AddressLength;
+		} else {
+			if (rscp->Data.FixedMemory32.WriteProtect ==
+			    ACPI_READ_WRITE_MEMORY) {
+				reg.phys_hi |= ACPIDEV_REG_MEM_WRITABLE;
+			}
+			reg.phys_low = rscp->Data.FixedMemory32.Address;
+			reg.size_low = rscp->Data.FixedMemory32.AddressLength;
+		}
+		reg.phys_mid = 0;
+		reg.size_hi = 0;
+		if ((uint64_t)reg.phys_low + reg.size_low > UINT32_MAX) {
+			ACPIDEV_DEBUG(CE_WARN,
+			    "acpidev: invalid MEMORY32/FIXEDMEMORY32 record, "
+			    "memory max is out of range.");
+			rc = AE_ERROR;
+		} else if (reg.size_low != 0) {
+			rc = acpidev_resource_insert_reg(rhdl, &reg);
+			if (ACPI_FAILURE(rc)) {
+				ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to "
+				    "insert reg into resource handle.");
+			}
+		}
+		break;
+	}
+
+	case ACPI_RESOURCE_TYPE_ADDRESS16:
+	case ACPI_RESOURCE_TYPE_ADDRESS32:
+	case ACPI_RESOURCE_TYPE_ADDRESS64:
+	{
+		ACPI_RESOURCE_ADDRESS64 addr64;
+
+		if (rscp->Data.Address.ProducerConsumer != ACPI_CONSUMER) {
+			ACPIDEV_DEBUG(CE_NOTE, "acpidev: consumer encountered "
+			    "a PRODUCER resource, ignored.");
+		} else if (ACPI_FAILURE(AcpiResourceToAddress64(rscp,
+		    &addr64))) {
+			ACPIDEV_DEBUG(CE_WARN,
+			    "acpidev: failed to convert resource to ADDR64.");
+		} else if (ACPI_FAILURE(rc = acpidev_resource_address64(rhdl,
+		    &addr64))) {
+			ACPIDEV_DEBUG(CE_WARN,
+			    "acpidev: failed to handle ADDRESS resource.");
+		}
+		break;
+	}
+
+	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
+	{
+		ACPI_RESOURCE_ADDRESS64 addr64;
+
+		if (rscp->Data.ExtAddress64.ProducerConsumer != ACPI_CONSUMER) {
+			ACPIDEV_DEBUG(CE_NOTE, "acpidev: consumer encountered "
+			    "a PRODUCER resource, ignored.");
+			break;
+		}
+
+		*(ACPI_RESOURCE_ADDRESS *)&addr64 = rscp->Data.Address;
+		addr64.Granularity = rscp->Data.ExtAddress64.Granularity;
+		addr64.Minimum = rscp->Data.ExtAddress64.Minimum;
+		addr64.Maximum = rscp->Data.ExtAddress64.Maximum;
+		addr64.TranslationOffset =
+		    rscp->Data.ExtAddress64.TranslationOffset;
+		addr64.AddressLength = rscp->Data.ExtAddress64.AddressLength;
+		if (ACPI_FAILURE(rc = acpidev_resource_address64(rhdl,
+		    &addr64))) {
+			ACPIDEV_DEBUG(CE_WARN,
+			    "acpidev: failed to handle EXTADDRESS resource.");
+		}
+		break;
+	}
+
+	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
+	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
+		ACPIDEV_DEBUG(CE_NOTE, "acpidev: consumer encountered "
+		    "START_DEPENDENT or END_DEPENDENT tag, ignored.");
+		break;
+
+	case ACPI_RESOURCE_TYPE_END_TAG:
+		/* Finish walking when we encounter END_TAG. */
+		rc = AE_CTRL_TERMINATE;
+		break;
+
+	default:
+		ACPIDEV_DEBUG(CE_NOTE,
+		    "acpidev: unknown ACPI resource type %u, ignored.",
+		    rscp->Type);
+		break;
+	}
+
+	return (rc);
+}
+
+ACPI_STATUS
+acpidev_resource_walk(ACPI_HANDLE hdl, char *method,
+    boolean_t consumer, acpidev_resource_handle_t *rhdlp)
+{
+	ACPI_STATUS rc = AE_OK;
+	ACPI_HANDLE mhdl = NULL;
+	acpidev_resource_handle_t rhdl = NULL;
+
+	ASSERT(hdl != NULL);
+	ASSERT(method != NULL);
+	ASSERT(rhdlp != NULL);
+	if (hdl == NULL) {
+		ACPIDEV_DEBUG(CE_WARN,
+		    "acpidev: hdl is NULL in acpidev_resource_walk().");
+		return (AE_BAD_PARAMETER);
+	} else if (method == NULL) {
+		ACPIDEV_DEBUG(CE_WARN,
+		    "acpidev: method is NULL in acpidev_resource_walk().");
+		return (AE_BAD_PARAMETER);
+	} else if (rhdlp == NULL) {
+		ACPIDEV_DEBUG(CE_WARN, "acpidev: resource handle ptr is NULL "
+		    "in acpidev_resource_walk().");
+		return (AE_BAD_PARAMETER);
+	}
+
+	/* Check whether method exists under object. */
+	if (ACPI_FAILURE(AcpiGetHandle(hdl, method, &mhdl))) {
+		char *objname = acpidev_get_object_name(hdl);
+		ACPIDEV_DEBUG(CE_NOTE,
+		    "acpidev: method %s doesn't exist under %s",
+		    method, objname);
+		acpidev_free_object_name(hdl);
+		return (AE_NOT_FOUND);
+	}
+
+	/* Walk all resources. */
+	rhdl = acpidev_resource_handle_alloc(consumer);
+	if (consumer) {
+		rc = AcpiWalkResources(hdl, method,
+		    acpidev_resource_walk_consumer, rhdl);
+	} else {
+		rc = AcpiWalkResources(hdl, method,
+		    acpidev_resource_walk_producer, rhdl);
+	}
+	if (ACPI_SUCCESS(rc)) {
+		*rhdlp = rhdl;
+	} else {
+		acpidev_resource_handle_free(rhdl);
+	}
+	if (ACPI_FAILURE(rc)) {
+		char *objname = acpidev_get_object_name(hdl);
+		ACPIDEV_DEBUG(CE_WARN,
+		    "acpidev: failed to walk resource from method %s under %s.",
+		    method, objname);
+		acpidev_free_object_name(hdl);
+	}
+
+	return (rc);
+}
+
+ACPI_STATUS
+acpidev_resource_process(acpidev_walk_info_t *infop, boolean_t consumer)
+{
+	ACPI_STATUS rc;
+	char path[MAXPATHLEN];
+	acpidev_resource_handle_t rhdl = NULL;
+
+	ASSERT(infop != NULL);
+	if (infop == NULL) {
+		ACPIDEV_DEBUG(CE_WARN, "acpidev: invalid parameter "
+		    "in acpidev_resource_process().");
+		return (AE_BAD_PARAMETER);
+	}
+
+	/* Walk all resources. */
+	(void) ddi_pathname(infop->awi_dip, path);
+	rc = acpidev_resource_walk(infop->awi_hdl, METHOD_NAME__CRS,
+	    consumer, &rhdl);
+	if (ACPI_FAILURE(rc)) {
+		ACPIDEV_DEBUG(CE_WARN,
+		    "acpidev: failed to walk ACPI resources of %s(%s).",
+		    path, infop->awi_name);
+		return (rc);
+	}
+
+	if (consumer) {
+		/* Create device properties for consumer. */
+
+		/* Create 'reg' and 'assigned-addresses' properties. */
+		if (rhdl->acpidev_reg_count > 0 &&
+		    ndi_prop_update_int_array(DDI_DEV_T_NONE, infop->awi_dip,
+		    "reg", (int *)rhdl->acpidev_regp,
+		    rhdl->acpidev_reg_count * sizeof (acpidev_regspec_t) /
+		    sizeof (int)) != NDI_SUCCESS) {
+			ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to set "
+			    "'reg' property for %s.", path);
+			rc = AE_ERROR;
+			goto out;
+		}
+		if (rhdl->acpidev_reg_count > 0 &&
+		    ndi_prop_update_int_array(DDI_DEV_T_NONE, infop->awi_dip,
+		    "assigned-addresses", (int *)rhdl->acpidev_regp,
+		    rhdl->acpidev_reg_count * sizeof (acpidev_regspec_t) /
+		    sizeof (int)) != NDI_SUCCESS) {
+			ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to set "
+			    "'assigned-addresses' property for %s.", path);
+			rc = AE_ERROR;
+			goto out;
+		}
+
+		/* Create 'interrupts' property. */
+		if (rhdl->acpidev_irq_count > 0 &&
+		    ndi_prop_update_int_array(DDI_DEV_T_NONE, infop->awi_dip,
+		    "interrupts", (int *)rhdl->acpidev_irqp,
+		    rhdl->acpidev_irq_count) != NDI_SUCCESS) {
+			ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to set "
+			    "'interrupts' property for %s.", path);
+			rc = AE_ERROR;
+			goto out;
+		}
+
+		/* Create 'dma-channels' property. */
+		if (rhdl->acpidev_dma_count > 0 &&
+		    ndi_prop_update_int_array(DDI_DEV_T_NONE, infop->awi_dip,
+		    "dma-channels", (int *)rhdl->acpidev_dmap,
+		    rhdl->acpidev_dma_count) != NDI_SUCCESS) {
+			ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to set "
+			    "'dma-channels' property for %s.", path);
+			rc = AE_ERROR;
+			goto out;
+		}
+
+	} else {
+		/* Create device properties for producer. */
+
+		/* Create 'ranges' property. */
+		if (rhdl->acpidev_range_count > 0 &&
+		    ndi_prop_update_int_array(DDI_DEV_T_NONE, infop->awi_dip,
+		    "ranges", (int *)rhdl->acpidev_rangep,
+		    rhdl->acpidev_range_count * sizeof (acpidev_ranges_t) /
+		    sizeof (int)) != NDI_SUCCESS) {
+			ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to set "
+			    "'ranges' property for %s.", path);
+			rc = AE_ERROR;
+			goto out;
+		}
+
+		/* Create 'bus-range' property. */
+		if (rhdl->acpidev_bus_count > 0 &&
+		    ndi_prop_update_int_array(DDI_DEV_T_NONE, infop->awi_dip,
+		    "bus-range", (int *)rhdl->acpidev_busp,
+		    rhdl->acpidev_bus_count * sizeof (acpidev_bus_range_t) /
+		    sizeof (int)) != NDI_SUCCESS) {
+			ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to set "
+			    "'bus-range' property for %s.", path);
+			rc = AE_ERROR;
+			goto out;
+		}
+	}
+
+out:
+	/* Free resources allocated by acpidev_resource_walk. */
+	acpidev_resource_handle_free(rhdl);
+
+	return (rc);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/i86pc/io/acpi/acpidev/acpidev_scope.c	Thu Aug 27 16:35:32 2009 -0700
@@ -0,0 +1,187 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 (c) 2009, Intel Corporation.
+ * All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/atomic.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/acpi/acpi.h>
+#include <sys/acpica.h>
+#include <sys/acpidev.h>
+#include <sys/acpidev_impl.h>
+
+static ACPI_STATUS acpidev_scope_probe(acpidev_walk_info_t *infop);
+static acpidev_filter_result_t acpidev_scope_filter(acpidev_walk_info_t *infop,
+    char *devname, int maxlen);
+static ACPI_STATUS acpidev_scope_init(acpidev_walk_info_t *infop);
+
+/*
+ * Default class driver for ACPI scope objects.
+ * This class driver is used to handle predefined ACPI SCOPE objects
+ * under the ACPI root object, such as _PR_, _SB_ and _TZ_ etc.
+ * The default policy for ACPI SCOPE objects is SKIP.
+ */
+acpidev_class_t acpidev_class_scope = {
+	0,				/* adc_refcnt */
+	ACPIDEV_CLASS_REV1,		/* adc_version */
+	ACPIDEV_CLASS_ID_SCOPE,		/* adc_class_id */
+	"ACPI Scope",			/* adc_class_name */
+	ACPIDEV_TYPE_SCOPE,		/* adc_dev_type */
+	NULL,				/* adc_private */
+	NULL,				/* adc_pre_probe */
+	NULL,				/* adc_post_probe */
+	acpidev_scope_probe,		/* adc_probe */
+	acpidev_scope_filter,		/* adc_filter */
+	acpidev_scope_init,		/* adc_init */
+	NULL,				/* adc_fini */
+};
+
+acpidev_class_list_t *acpidev_class_list_scope = NULL;
+
+/*
+ * All SCOPE objects share a global pseudo unit address space across the system.
+ */
+static uint32_t acpidev_scope_unitaddr = 0;
+
+/* Filter rule table for ACPI SCOPE objects. */
+static acpidev_filter_rule_t acpidev_scope_filters[] = {
+	{	/* For safety, _SB_ is hardcoded as DEVICE by acpica */
+		NULL,
+		0,
+		ACPIDEV_FILTER_DEFAULT,
+		&acpidev_class_list_device,
+		1,
+		1,
+		ACPIDEV_OBJECT_NAME_SB,
+		ACPIDEV_NODE_NAME_MODULE_SBD,
+	},
+	{	/* Handle _PR_ object. */
+		NULL,
+		0,
+		ACPIDEV_FILTER_SCAN,
+		&acpidev_class_list_scope,
+		1,
+		1,
+		ACPIDEV_OBJECT_NAME_PR,
+		ACPIDEV_NODE_NAME_PROCESSOR,
+	},
+	{	/* Ignore all other scope objects. */
+		NULL,
+		0,
+		ACPIDEV_FILTER_SKIP,
+		NULL,
+		1,
+		INT_MAX,
+		NULL,
+		NULL,
+	}
+};
+
+static ACPI_STATUS
+acpidev_scope_probe(acpidev_walk_info_t *infop)
+{
+	ACPI_STATUS rc;
+	int flags;
+
+	ASSERT(infop != NULL);
+	ASSERT(infop->awi_hdl != NULL);
+	ASSERT(infop->awi_info != NULL);
+	if (infop->awi_info->Type != ACPI_TYPE_LOCAL_SCOPE) {
+		return (AE_OK);
+	}
+
+	if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE) {
+		flags = ACPIDEV_PROCESS_FLAG_SCAN | ACPIDEV_PROCESS_FLAG_CREATE;
+		rc = acpidev_process_object(infop, flags);
+	} else if (infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE) {
+		flags = ACPIDEV_PROCESS_FLAG_SCAN;
+		rc = acpidev_process_object(infop, flags);
+	} else if (infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
+		flags = ACPIDEV_PROCESS_FLAG_SCAN;
+		rc = acpidev_process_object(infop, flags);
+	} else {
+		ACPIDEV_DEBUG(CE_WARN, "acpidev: unknown operation type %u "
+		    "in acpidev_scope_probe().", infop->awi_op_type);
+		rc = AE_BAD_PARAMETER;
+	}
+	if (ACPI_FAILURE(rc) && rc != AE_NOT_EXIST && rc != AE_ALREADY_EXISTS) {
+		cmn_err(CE_WARN,
+		    "!acpidev: failed to process scope object %s.",
+		    infop->awi_name);
+	} else {
+		rc = AE_OK;
+	}
+
+	return (rc);
+}
+
+static acpidev_filter_result_t
+acpidev_scope_filter(acpidev_walk_info_t *infop, char *devname, int maxlen)
+{
+	acpidev_filter_result_t res;
+
+	ASSERT(infop != NULL);
+	if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE ||
+	    infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE ||
+	    infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
+		res = acpidev_filter_device(infop, infop->awi_hdl,
+		    ACPIDEV_ARRAY_PARAM(acpidev_scope_filters),
+		    devname, maxlen);
+	} else {
+		ACPIDEV_DEBUG(CE_WARN, "acpidev: unknown operation type %u "
+		    "in acpidev_scope_filter().", infop->awi_op_type);
+		res = ACPIDEV_FILTER_FAILED;
+	}
+
+	return (res);
+}
+
+/*ARGSUSED*/
+static ACPI_STATUS
+acpidev_scope_init(acpidev_walk_info_t *infop)
+{
+	char unitaddr[32];
+	char *compatible[] = {
+		ACPIDEV_HID_SCOPE,
+		ACPIDEV_TYPE_SCOPE,
+		ACPIDEV_HID_VIRTNEX,
+		ACPIDEV_TYPE_VIRTNEX,
+	};
+
+	ASSERT(infop != NULL);
+	ASSERT(infop->awi_hdl != NULL);
+	ASSERT(infop->awi_dip != NULL);
+	if (ACPI_FAILURE(acpidev_set_compatible(infop,
+	    ACPIDEV_ARRAY_PARAM(compatible)))) {
+		return (AE_ERROR);
+	}
+	(void) snprintf(unitaddr, sizeof (unitaddr), "%u",
+	    atomic_inc_32_nv(&acpidev_scope_unitaddr) - 1);
+	if (ACPI_FAILURE(acpidev_set_unitaddr(infop, NULL, 0, unitaddr))) {
+		return (AE_ERROR);
+	}
+
+	return (AE_OK);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/i86pc/io/acpi/acpidev/acpidev_util.c	Thu Aug 27 16:35:32 2009 -0700
@@ -0,0 +1,802 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2009, Intel Corporation.
+ * All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/cmn_err.h>
+#include <sys/sysmacros.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/acpi/acpi.h>
+#include <sys/acpica.h>
+#include <sys/acpidev.h>
+#include <sys/acpidev_impl.h>
+#include <util/sscanf.h>
+
+/* Data structures used to extract the numeric unit address from string _UID. */
+static acpidev_pseudo_uid_head_t acpidev_uid_heads[ACPIDEV_CLASS_ID_MAX];
+static char *acpidev_uid_formats[] = {
+	"%u",
+};
+
+static char *acpidev_unknown_object_name = "<unknown>";
+
+int
+acpidev_query_device_status(ACPI_HANDLE hdl)
+{
+	int status;
+
+	ASSERT(hdl != NULL);
+	if (hdl == NULL) {
+		ACPIDEV_DEBUG(CE_WARN,
+		    "acpidev: hdl is NULL in acpidev_query_device_status().");
+		return (0);
+	}
+
+	if (ACPI_FAILURE(acpica_eval_int(hdl, METHOD_NAME__STA, &status))) {
+		/*
+		 * Set the default value according to ACPI3.0b sec 6.3.7:
+		 * If a device object (including the processor object) does
+		 * not have an _STA object, then OSPM assumes that all of the
+		 * above bits are set (in other words, the device is present,
+		 * enabled, shown in the UI, and functioning).
+		 */
+		status = 0xF;
+	}
+
+	return (status);
+}
+
+boolean_t
+acpidev_check_device_present(int status)
+{
+	/*
+	 * According to ACPI3.0 Spec, if either the ACPI_STA_DEVICE_PRESENT bit
+	 * or the ACPI_STA_DEVICE_FUNCTIONING bit is set, the device exists.
+	 */
+	if (status & (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_FUNCTIONING)) {
+		return (B_TRUE);
+	}
+
+	return (B_FALSE);
+}
+
+boolean_t
+acpidev_check_device_enabled(int stat)
+{
+	/*
+	 * According to ACPI3.0 Spec, if either the ACPI_STA_DEVICE_PRESENT bit
+	 * or the ACPI_STA_DEVICE_FUNCTIONING bit is set, the device exists.
+	 * Return true if device exists and has been enabled.
+	 */
+	if ((stat & (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_FUNCTIONING)) &&
+	    (stat & ACPI_STA_DEVICE_ENABLED)) {
+		return (B_TRUE);
+	}
+
+	return (B_FALSE);
+}
+
+boolean_t
+acpidev_match_device_id(ACPI_DEVICE_INFO *infop, char **ids, int count)
+{
+	int i, j;
+
+	ASSERT(infop != NULL);
+	ASSERT(ids != NULL || count == 0);
+	/* Special case to match all devices if count is 0. */
+	if (count == 0) {
+		return (B_TRUE);
+	} else if (infop == NULL || ids == NULL) {
+		ACPIDEV_DEBUG(CE_WARN, "acpidev: invalid parameters in "
+		    "acpidev_match_device_id().");
+		return (B_FALSE);
+	}
+
+	/* Match _HID first. */
+	if (infop->Valid & ACPI_VALID_HID) {
+		for (i = 0; i < count; i++) {
+			if (strncmp(ids[i], infop->HardwareId.Value,
+			    sizeof (infop->HardwareId.Value)) == 0) {
+				return (B_TRUE);
+			}
+		}
+	}
+
+	/* Match _CID next. */
+	if (infop->Valid & ACPI_VALID_CID) {
+		for (i = 0; i < count; i++) {
+			for (j = 0; j < infop->CompatibilityId.Count; j++) {
+				if (strncmp(ids[i],
+				    infop->CompatibilityId.Id[j].Value,
+				    sizeof (ACPI_COMPATIBLE_ID)) == 0) {
+					return (B_TRUE);
+				}
+			}
+		}
+	}
+
+	return (B_FALSE);
+}
+
+struct acpidev_get_device_arg {
+	boolean_t		skip_non_exist;
+	int			id_count;
+	char 			**device_ids;
+	void			*user_arg;
+	ACPI_WALK_CALLBACK	user_func;
+};
+
+static ACPI_STATUS
+acpidev_get_device_callback(ACPI_HANDLE hdl, UINT32 level, void *arg,
+    void **retval)
+{
+	ACPI_STATUS rc;
+	ACPI_BUFFER buf;
+	ACPI_DEVICE_INFO *infop;
+	struct acpidev_get_device_arg *argp;
+
+	argp = (struct acpidev_get_device_arg *)arg;
+	ASSERT(argp != NULL);
+	ASSERT(hdl != NULL);
+
+	/* Query object information. */
+	buf.Length = ACPI_ALLOCATE_BUFFER;
+	rc = AcpiGetObjectInfo(hdl, &buf);
+	if (ACPI_FAILURE(rc)) {
+		cmn_err(CE_WARN, "!acpidev: failed to get ACPI object info "
+		    "in acpidev_get_device_callback().");
+		return (AE_CTRL_DEPTH);
+	}
+	infop = buf.Pointer;
+
+	/*
+	 * Skip scanning of children if the device is neither PRESENT nor
+	 * FUNCTIONING.
+	 * Please refer to ACPI Spec3.0b Sec 6.3.1 and 6.5.1.
+	 */
+	if (argp->skip_non_exist && (infop->Valid & ACPI_VALID_STA) &&
+	    !acpidev_check_device_present(infop->CurrentStatus)) {
+		rc = AE_CTRL_DEPTH;
+	/* Call user callback if matched. */
+	} else if (acpidev_match_device_id(infop, argp->device_ids,
+	    argp->id_count)) {
+		rc = argp->user_func(hdl, level, argp->user_arg, retval);
+	} else {
+		rc = AE_OK;
+	}
+
+	/* Free ACPI object info buffer. */
+	AcpiOsFree(infop);
+
+	return (rc);
+}
+
+ACPI_STATUS
+acpidev_get_device_by_id(ACPI_HANDLE hdl, char **ids, int count,
+    int maxdepth, boolean_t skip_non_exist,
+    ACPI_WALK_CALLBACK userfunc, void *userarg, void **retval)
+{
+	ACPI_STATUS rc;
+	struct acpidev_get_device_arg arg;
+
+	ASSERT(userfunc != NULL);
+	if (hdl == NULL || userfunc == NULL || (ids == NULL && count != 0)) {
+		ACPIDEV_DEBUG(CE_WARN, "acpidev: invalid parameters "
+		    "in acpidev_get_device_by_id().");
+		return (AE_BAD_PARAMETER);
+	}
+
+	/* Enumerate all descendant objects. */
+	arg.skip_non_exist = skip_non_exist;
+	arg.device_ids = ids;
+	arg.id_count = count;
+	arg.user_arg = userarg;
+	arg.user_func = userfunc;
+	rc = AcpiWalkNamespace(ACPI_TYPE_DEVICE, hdl, maxdepth,
+	    &acpidev_get_device_callback, &arg, retval);
+
+	return (rc);
+}
+
+ACPI_STATUS
+acpidev_walk_apic(ACPI_BUFFER *bufp, ACPI_HANDLE hdl, char *method,
+    acpidev_apic_walker_t func, void *context)
+{
+	ACPI_STATUS rc;
+	ssize_t len;
+	ACPI_BUFFER buf;
+	ACPI_SUBTABLE_HEADER *ap;
+	ACPI_TABLE_MADT *mp = NULL;
+
+	ASSERT(func != NULL);
+	if (func == NULL) {
+		ACPIDEV_DEBUG(CE_WARN,
+		    "acpidev: invalid parameters for acpidev_walk_apic().");
+		return (AE_BAD_PARAMETER);
+	}
+
+	buf.Pointer = NULL;
+	buf.Length = ACPI_ALLOCATE_BUFFER;
+
+	/* A walk buffer was passed in if bufp isn't NULL. */
+	if (bufp != NULL) {
+		ap = (ACPI_SUBTABLE_HEADER *)(bufp->Pointer);
+		len = bufp->Length;
+	} else if (method != NULL) {
+		/*
+		 * Otherwise, if we have an evaluate method, we get the walk
+		 * buffer from a successful invocation of AcpiEvaluateObject.
+		 */
+		ASSERT(hdl != NULL);
+		rc = AcpiEvaluateObject(hdl, method, NULL, &buf);
+		if (ACPI_FAILURE(rc) && rc != AE_NOT_FOUND) {
+			cmn_err(CE_WARN, "!acpidev: failed to evaluate %s "
+			    "in acpidev_walk_apic().", method);
+			return (rc);
+		}
+		ap = (ACPI_SUBTABLE_HEADER *)buf.Pointer;
+		len = buf.Length;
+	} else {
+		/* As a last resort, walk the MADT table. */
+		rc = AcpiGetTable(ACPI_SIG_MADT, 1, (ACPI_TABLE_HEADER **)&mp);
+		if (ACPI_FAILURE(rc)) {
+			cmn_err(CE_WARN, "!acpidev: failed to get MADT table "
+			    "in acpidev_walk_apic().");
+			return (rc);
+		}
+		ap = (ACPI_SUBTABLE_HEADER *)(mp + 1);
+		len = mp->Header.Length - sizeof (*mp);
+	}
+
+	ASSERT(len >= 0);
+	for (rc = AE_OK; len > 0 && ACPI_SUCCESS(rc); len -= ap->Length,
+	    ap = (ACPI_SUBTABLE_HEADER *)(((char *)ap) + ap->Length)) {
+		ASSERT(len >= sizeof (ACPI_SUBTABLE_HEADER));
+		if (len <= sizeof (ACPI_SUBTABLE_HEADER) ||
+		    ap->Length <= sizeof (ACPI_SUBTABLE_HEADER) ||
+		    len < ap->Length) {
+			cmn_err(CE_WARN,
+			    "!acpidev: invalid APIC entry in MADT/_MAT.");
+			break;
+		}
+		rc = (*func)(ap, context);
+	}
+
+	if (buf.Pointer != NULL) {
+		AcpiOsFree(buf.Pointer);
+	}
+
+	return (rc);
+}
+
+char *
+acpidev_get_object_name(ACPI_HANDLE hdl)
+{
+	ACPI_BUFFER buf;
+	char *objname = acpidev_unknown_object_name;
+
+	buf.Length = ACPI_ALLOCATE_BUFFER;
+	buf.Pointer = NULL;
+	if (ACPI_SUCCESS(AcpiGetName(hdl, ACPI_FULL_PATHNAME, &buf))) {
+		ASSERT(buf.Pointer != NULL);
+		objname = (char *)buf.Pointer;
+	}
+
+	return (objname);
+}
+
+void
+acpidev_free_object_name(char *objname)
+{
+	if (objname != acpidev_unknown_object_name && objname != NULL) {
+		AcpiOsFree(objname);
+	}
+}
+
+acpidev_walk_info_t *
+acpidev_alloc_walk_info(acpidev_op_type_t op_type, int lvl, ACPI_HANDLE hdl,
+    acpidev_class_list_t **listpp, acpidev_walk_info_t *pinfop)
+{
+	ACPI_BUFFER buf;
+	acpidev_walk_info_t *infop = NULL;
+	acpidev_data_handle_t datap = NULL;
+
+	ASSERT(0 <= lvl && lvl < ACPIDEV_MAX_ENUM_LEVELS);
+	infop = kmem_zalloc(sizeof (*infop), KM_SLEEP);
+	infop->awi_op_type = op_type;
+	infop->awi_level = lvl;
+	infop->awi_parent = pinfop;
+	infop->awi_class_list = listpp;
+	infop->awi_hdl = hdl;
+	infop->awi_name = acpidev_get_object_name(hdl);
+
+	/* Cache ACPI device information. */
+	buf.Length = ACPI_ALLOCATE_BUFFER;
+	if (ACPI_FAILURE(AcpiGetObjectInfo(hdl, &buf))) {
+		cmn_err(CE_WARN, "!acpidev: failed to get object info for %s "
+		    "in acpidev_alloc_walk_info().", infop->awi_name);
+		acpidev_free_object_name(infop->awi_name);
+		kmem_free(infop, sizeof (*infop));
+		return (NULL);
+	}
+	infop->awi_info = buf.Pointer;
+
+	/*
+	 * Get or create an ACPI object data handle, which will be used to
+	 * maintain object status information.
+	 */
+	if ((datap = acpidev_data_get_handle(hdl)) != NULL) {
+		ASSERT(datap->aod_hdl == hdl);
+		ASSERT(datap->aod_level == lvl);
+	} else if ((datap = acpidev_data_create_handle(hdl)) != NULL) {
+		datap->aod_level = lvl;
+		datap->aod_hdl = hdl;
+	} else {
+		ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to create object "
+		    "handle for %s in acpidev_alloc_walk_info().",
+		    infop->awi_name);
+		AcpiOsFree(infop->awi_info);
+		acpidev_free_object_name(infop->awi_name);
+		kmem_free(infop, sizeof (*infop));
+		return (NULL);
+	}
+	infop->awi_data = datap;
+	/* Sync DEVICE_CREATED flag. */
+	if (datap->aod_iflag & ACPIDEV_ODF_DEVINFO_CREATED) {
+		ASSERT(datap->aod_dip != NULL);
+		ASSERT(datap->aod_class != NULL);
+		infop->awi_dip = datap->aod_dip;
+		infop->awi_flags |= ACPIDEV_WI_DEVICE_CREATED;
+	}
+
+	return (infop);
+}
+
+void
+acpidev_free_walk_info(acpidev_walk_info_t *infop)
+{
+	/*
+	 * The ACPI object data handle will only be released when the
+	 * corresponding object is going to be destroyed.
+	 */
+	if (infop != NULL) {
+		if (infop->awi_info != NULL) {
+			AcpiOsFree(infop->awi_info);
+		}
+		if (infop->awi_name != NULL) {
+			acpidev_free_object_name(infop->awi_name);
+		}
+		kmem_free(infop, sizeof (*infop));
+	}
+}
+
+dev_info_t *
+acpidev_walk_info_get_pdip(acpidev_walk_info_t *infop)
+{
+	while (infop != NULL) {
+		if (infop->awi_dip != NULL) {
+			return (infop->awi_dip);
+		}
+		infop = infop->awi_parent;
+	}
+
+	return (NULL);
+}
+
+/*
+ * Called to release resources when the corresponding object is going
+ * to be destroyed.
+ */
+/*ARGSUSED*/
+static void
+acpidev_get_object_handler(ACPI_HANDLE hdl, UINT32 func, void *data)
+{
+	acpidev_data_handle_t objhdl = data;
+
+	kmem_free(objhdl, sizeof (acpidev_data_handle_t));
+}
+
+acpidev_data_handle_t
+acpidev_data_get_handle(ACPI_HANDLE hdl)
+{
+	void *ptr;
+	acpidev_data_handle_t objhdl = NULL;
+
+	if (ACPI_SUCCESS(AcpiGetData(hdl, acpidev_get_object_handler, &ptr))) {
+		objhdl = (acpidev_data_handle_t)ptr;
+	}
+
+	return (objhdl);
+}
+
+acpidev_data_handle_t
+acpidev_data_create_handle(ACPI_HANDLE hdl)
+{
+	acpidev_data_handle_t objhdl;
+
+	objhdl = kmem_zalloc(sizeof (*objhdl), KM_SLEEP);
+	if (ACPI_FAILURE(AcpiAttachData(hdl, acpidev_get_object_handler,
+	    (void *)objhdl))) {
+		cmn_err(CE_WARN,
+		    "!acpidev: failed to attach handle data to object.");
+		kmem_free(objhdl, sizeof (*objhdl));
+		return (NULL);
+	}
+
+	return (objhdl);
+}
+
+void
+acpidev_data_destroy_handle(ACPI_HANDLE hdl)
+{
+	void *ptr;
+
+	if (ACPI_SUCCESS(AcpiGetData(hdl, acpidev_get_object_handler, &ptr)) &&
+	    ACPI_SUCCESS(AcpiDetachData(hdl, acpidev_get_object_handler))) {
+		kmem_free(ptr, sizeof (acpidev_data_handle_t));
+	}
+}
+
+ACPI_HANDLE
+acpidev_data_get_object(acpidev_data_handle_t hdl)
+{
+	ASSERT(hdl != NULL);
+	return ((hdl != NULL) ? hdl->aod_hdl : NULL);
+}
+
+dev_info_t *
+acpidev_data_get_devinfo(acpidev_data_handle_t hdl)
+{
+	ASSERT(hdl != NULL);
+	if (hdl == NULL ||
+	    (hdl->aod_iflag & ACPIDEV_ODF_DEVINFO_CREATED) == 0) {
+		return (NULL);
+	} else {
+		ASSERT(hdl->aod_dip != NULL);
+		return (hdl->aod_dip);
+	}
+}
+
+int
+acpidev_data_get_status(acpidev_data_handle_t hdl)
+{
+	ASSERT(hdl != NULL);
+	if (hdl == NULL ||
+	    (hdl->aod_iflag & ACPIDEV_ODF_STATUS_VALID) == 0) {
+		return (0);
+	} else {
+		return (hdl->aod_status);
+	}
+}
+
+void
+acpidev_data_set_flag(acpidev_data_handle_t hdl, uint32_t flag)
+{
+	ASSERT(hdl != NULL);
+	hdl->aod_eflag |= flag;
+}
+
+void
+acpidev_data_clear_flag(acpidev_data_handle_t hdl, uint32_t flag)
+{
+	ASSERT(hdl != NULL);
+	hdl->aod_eflag &= ~flag;
+}
+
+uint32_t
+acpidev_data_get_flag(acpidev_data_handle_t hdl, uint32_t flag)
+{
+	ASSERT(hdl != NULL);
+	return (hdl->aod_eflag & flag);
+}
+
+static char *
+acpidev_generate_pseudo_unitaddr(char *uid, acpidev_class_id_t cid,
+    char *buf, size_t len)
+{
+	acpidev_pseudo_uid_t *up, **pp;
+
+	ASSERT(len >= 64);
+	ASSERT(cid >= 0 && cid < ACPIDEV_CLASS_ID_MAX);
+	if (cid < 0 || cid >= ACPIDEV_CLASS_ID_MAX) {
+		return (NULL);
+	}
+
+	mutex_enter(&acpidev_uid_heads[cid].apuh_lock);
+	for (pp = &acpidev_uid_heads[cid].apuh_first; *pp != NULL;
+	    pp = &(*pp)->apu_next) {
+		if (strcmp(uid, (*pp)->apu_uid) == 0 &&
+		    (*pp)->apu_cid == cid) {
+			break;
+		}
+	}
+	/* uid doesn't exist, create one and insert it into the list. */
+	if (*pp == NULL) {
+		up = kmem_zalloc(sizeof (*up), KM_SLEEP);
+		up->apu_uid = ddi_strdup(uid, KM_SLEEP);
+		up->apu_cid = cid;
+		up->apu_nid = acpidev_uid_heads[cid].apuh_id++;
+		*pp = up;
+	}
+	ASSERT(*pp != NULL);
+	mutex_exit(&acpidev_uid_heads[cid].apuh_lock);
+
+	/*
+	 * Generate a special format unit address with three fields to
+	 * guarantee uniqueness. Normal unit addresses for ACPI devices have
+	 * either one or two fields.
+	 */
+	if (snprintf(buf, len, "%u,%u,0", (*pp)->apu_nid, cid) > len) {
+		return (NULL);
+	}
+
+	return (buf);
+}
+
+static char *
+acpidev_gen_unitaddr(char *uid, char *fmt, char *buf, size_t len)
+{
+	size_t i, cnt;
+	uint_t id1, id2;
+
+	ASSERT(len >= 64);
+	if (fmt == NULL || strlen(fmt) == 0) {
+		return (NULL);
+	}
+
+	/*
+	 * Count '%' in format string to protect sscanf().
+	 * Only support '%u' and '%x', and maximum 2 conversions.
+	 */
+	for (cnt = 0, i = 0; fmt[i] != 0 && cnt <= 2; i++) {
+		if (fmt[i] != '%') {
+			continue;
+		} else if (fmt[i + 1] == 'u' || fmt[i + 1] == 'x') {
+			/* Skip next character. */
+			i++;
+			cnt++;
+		} else {
+			/* Invalid conversion, stop walking. */
+			cnt = SIZE_MAX;
+		}
+	}
+	if (cnt != 1 && cnt != 2) {
+		ACPIDEV_DEBUG(CE_WARN,
+		    "acpidev: invalid uid format string '%s'.", fmt);
+		return (NULL);
+	}
+
+	/* Scan uid and generate unitaddr. */
+	if (sscanf(uid, fmt, &id1, &id2) != cnt) {
+		return (NULL);
+	}
+	/*
+	 * Reverse the order of the two IDs to match the requirements of the
+	 * hotplug driver.
+	 */
+	if (cnt == 2 && snprintf(buf, len, "%u,%u", id2, id1) >= len) {
+		ACPIDEV_DEBUG(CE_WARN,
+		    "acpidev: generated unitaddr is too long.");
+		return (NULL);
+	} else if (cnt == 1 && snprintf(buf, len, "%u", id1) >= len) {
+		ACPIDEV_DEBUG(CE_WARN,
+		    "acpidev: generated unitaddr is too long.");
+		return (NULL);
+	}
+
+	return (buf);
+}
+
+char *
+acpidev_generate_unitaddr(char *uid, char **fmts, size_t nfmt,
+    char *buf, size_t len)
+{
+	size_t i;
+	uint_t count = 0;
+	ulong_t val;
+	char **formats = NULL;
+	char *rbuf = NULL;
+	char *endp = NULL;
+
+	ASSERT(len >= 64);
+
+	/* Use _UID as unit address if it's a decimal integer. */
+	if (ddi_strtoul(uid, &endp, 10, &val) == 0 &&
+	    (endp == NULL || *endp == 0)) {
+		if (snprintf(buf, len, "%s", uid) >= len) {
+			return (NULL);
+		} else {
+			return (buf);
+		}
+	}
+
+	/* First handle uid format strings from device property. */
+	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, ddi_root_node(),
+	    DDI_PROP_DONTPASS,
+	    ACPIDEV_PROP_NAME_UID_FORMAT, &formats, &count) == DDI_SUCCESS) {
+		/* Walk through format strings and try to generate unitaddr. */
+		for (i = 0; i < count && rbuf == NULL; i++) {
+			rbuf = acpidev_gen_unitaddr(uid, formats[i], buf, len);
+		}
+		ddi_prop_free(formats);
+	}
+
+	/* Then handle embedded uid format strings. */
+	if (fmts != NULL) {
+		for (i = 0; i < nfmt && rbuf == NULL; i++) {
+			rbuf = acpidev_gen_unitaddr(uid, fmts[i], buf, len);
+		}
+	}
+
+	return (rbuf);
+}
+
+/*
+ * The Solaris device "unit-address" property is composed of a comma-delimited
+ * list of hexadecimal values. According to the ACPI spec, the ACPI _UID method
+ * could return an integer or a string. If it returns an integer, it is used
+ * as the unit-address as is. If _UID returns a string, we try to extract some
+ * meaningful integers to compose the unit-address property. If we fail to
+ * extract any integers, a pseudo-sequential number will be generated for the
+ * unit-address.
+ */
+ACPI_STATUS
+acpidev_set_unitaddr(acpidev_walk_info_t *infop, char **fmts, size_t nfmt,
+    char *unitaddr)
+{
+	char unit[64];
+
+	ASSERT(infop != NULL);
+	ASSERT(infop->awi_dip != NULL);
+	ASSERT(infop->awi_info != NULL);
+	if (infop == NULL || infop->awi_dip == NULL ||
+	    infop->awi_info == NULL) {
+		ACPIDEV_DEBUG(CE_WARN,
+		    "acpidev: invalid parameters in acpidev_set_unitaddr().");
+		return (AE_BAD_PARAMETER);
+	}
+
+	if (infop->awi_info->Valid & ACPI_VALID_UID) {
+		if (ndi_prop_update_string(DDI_DEV_T_NONE, infop->awi_dip,
+		    ACPIDEV_PROP_NAME_ACPI_UID, infop->awi_info->UniqueId.Value)
+		    != NDI_SUCCESS) {
+			cmn_err(CE_WARN,
+			    "!acpidev: failed to set UID property for %s.",
+			    infop->awi_name);
+			return (AE_ERROR);
+		}
+	}
+
+	if (unitaddr == NULL && (infop->awi_info->Valid & ACPI_VALID_UID)) {
+		/* Try to generate unit address from _UID. */
+		if (fmts == NULL) {
+			fmts = acpidev_uid_formats;
+			nfmt = sizeof (acpidev_uid_formats) / sizeof (char *);
+		}
+		unitaddr = acpidev_generate_unitaddr(
+		    infop->awi_info->UniqueId.Value, fmts, nfmt,
+		    unit, sizeof (unit));
+		/* Generate pseudo sequential unit address. */
+		if (unitaddr == NULL) {
+			unitaddr = acpidev_generate_pseudo_unitaddr(
+			    infop->awi_info->UniqueId.Value,
+			    infop->awi_class_curr->adc_class_id,
+			    unit, sizeof (unit));
+		}
+		if (unitaddr == NULL) {
+			cmn_err(CE_WARN, "!acpidev: failed to generate unit "
+			    "address from %s.",
+			    infop->awi_info->UniqueId.Value);
+			return (AE_ERROR);
+		}
+	}
+	if (unitaddr == NULL) {
+		/*
+		 * Some ACPI objects may have no _UID method available, so we
+		 * can't generate the "unit-address" property for them.
+		 * On the other hand, it's legal to support such a device
+		 * without a unit address, so return success here.
+		 */
+		return (AE_OK);
+	}
+
+	if (ndi_prop_update_string(DDI_DEV_T_NONE, infop->awi_dip,
+	    ACPIDEV_PROP_NAME_UNIT_ADDR, unitaddr) != NDI_SUCCESS) {
+		cmn_err(CE_WARN, "!acpidev: failed to set unitaddr for %s.",
+		    infop->awi_name);
+		return (AE_ERROR);
+	}
+
+	return (AE_OK);
+}
+
+ACPI_STATUS
+acpidev_set_compatible(acpidev_walk_info_t *infop, char **compat, int acount)
+{
+	int count, i, j;
+	char **compatible = NULL;
+	ACPI_DEVICE_INFO *di;
+
+	/*
+	 * Generate compatible list for device based on:
+	 *	* Device HID if available
+	 *	* Device CIDs if available
+	 *	* property array passed in
+	 */
+	ASSERT(infop != NULL);
+	ASSERT(infop->awi_dip != NULL);
+	ASSERT(infop->awi_info != NULL);
+	ASSERT(compat != NULL || acount == 0);
+	if (infop == NULL || infop->awi_dip == NULL ||
+	    infop->awi_info == NULL || (compat == NULL && acount != 0)) {
+		ACPIDEV_DEBUG(CE_WARN, "acpidev: invalid parameters "
+		    "in acpidev_set_compatible().");
+		return (AE_BAD_PARAMETER);
+	}
+
+	/* Compute string count. */
+	count = acount;
+	di = infop->awi_info;
+	if (di->Valid & ACPI_VALID_HID) {
+		count++;
+	}
+	if (di->Valid & ACPI_VALID_CID) {
+		count += di->CompatibilityId.Count;
+	}
+	compatible = kmem_zalloc(sizeof (char *) * count, KM_SLEEP);
+
+	/* Generate string array. */
+	i = 0;
+	if (di->Valid & ACPI_VALID_HID) {
+		compatible[i++] = di->HardwareId.Value;
+	}
+	if (di->Valid & ACPI_VALID_CID) {
+		for (j = 0; j < di->CompatibilityId.Count; j++) {
+			compatible[i++] = di->CompatibilityId.Id[j].Value;
+		}
+	}
+	for (j = 0; j < acount; j++) {
+		compatible[i++] = compat[j];
+	}
+	ASSERT(i == count);
+
+	/* Set "compatible" property. */
+	if (ndi_prop_update_string_array(DDI_DEV_T_NONE, infop->awi_dip,
+	    OBP_COMPATIBLE, compatible, count) != NDI_SUCCESS) {
+		cmn_err(CE_WARN, "!acpidev: failed to set compatible "
+		    "property for %s in acpidev_set_compatible().",
+		    infop->awi_name);
+		kmem_free(compatible, count * sizeof (char *));
+		return (AE_ERROR);
+	}
+	kmem_free(compatible, count * sizeof (char *));
+
+	return (AE_OK);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/i86pc/io/acpi/acpinex/acpinex_drv.c	Thu Aug 27 16:35:32 2009 -0700
@@ -0,0 +1,574 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2009, Intel Corporation.
+ * All rights reserved.
+ */
+/*
+ * This module implements a nexus driver for the ACPI virtual bus.
+ * It does not handle any of the DDI functions passed up to it by the child
+ * drivers, but instead allows them to bubble up to the root node.
+ */
+
+#include <sys/types.h>
+#include <sys/cmn_err.h>
+#include <sys/conf.h>
+#include <sys/modctl.h>
+#include <sys/ddi.h>
+#include <sys/ddi_impldefs.h>
+#include <sys/ddifm.h>
+#include <sys/ndifm.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/acpidev.h>
+#include <sys/acpinex.h>
+
+/* Patchable through /etc/system. */
+#ifdef	DEBUG
+int acpinex_debug = 1;
+#else
+int acpinex_debug = 0;
+#endif
+
+/*
+ * Driver globals
+ */
+static kmutex_t acpinex_lock;
+static void *acpinex_softstates;
+
+static int acpinex_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
+static int acpinex_attach(dev_info_t *, ddi_attach_cmd_t);
+static int acpinex_detach(dev_info_t *, ddi_detach_cmd_t);
+static int acpinex_open(dev_t *, int, int, cred_t *);
+static int acpinex_close(dev_t, int, int, cred_t *);
+static int acpinex_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
+static int acpinex_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
+    off_t offset, off_t len, caddr_t *vaddrp);
+static int acpinex_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *,
+    void *);
+static int acpinex_fm_init_child(dev_info_t *, dev_info_t *, int,
+    ddi_iblock_cookie_t *);
+static void acpinex_fm_init(acpinex_softstate_t *softsp);
+static void acpinex_fm_fini(acpinex_softstate_t *softsp);
+
+extern void make_ddi_ppd(dev_info_t *, struct ddi_parent_private_data **);
+
+/*
+ * Configuration data structures
+ */
+static struct bus_ops acpinex_bus_ops = {
+	BUSO_REV,			/* busops_rev */
+	acpinex_bus_map,		/* bus_map */
+	NULL,				/* bus_get_intrspec */
+	NULL,				/* bus_add_intrspec */
+	NULL,				/* bus_remove_intrspec */
+	i_ddi_map_fault,		/* bus_map_fault */
+	ddi_dma_map,			/* bus_dma_map */
+	ddi_dma_allochdl,		/* bus_dma_allochdl */
+	ddi_dma_freehdl,		/* bus_dma_freehdl */
+	ddi_dma_bindhdl,		/* bus_dma_bindhdl */
+	ddi_dma_unbindhdl,		/* bus_dma_unbindhdl */
+	ddi_dma_flush,			/* bus_dma_flush */
+	ddi_dma_win,			/* bus_dma_win */
+	ddi_dma_mctl,			/* bus_dma_ctl */
+	acpinex_ctlops,			/* bus_ctl */
+	ddi_bus_prop_op,		/* bus_prop_op */
+	ndi_busop_get_eventcookie,	/* bus_get_eventcookie */
+	ndi_busop_add_eventcall,	/* bus_add_eventcall */
+	ndi_busop_remove_eventcall,	/* bus_remove_eventcall */
+	ndi_post_event,			/* bus_post_event */
+	NULL,				/* bus_intr_ctl */
+	NULL,				/* bus_config */
+	NULL,				/* bus_unconfig */
+	acpinex_fm_init_child,		/* bus_fm_init */
+	NULL,				/* bus_fm_fini */
+	NULL,				/* bus_fm_access_enter */
+	NULL,				/* bus_fm_access_exit */
+	NULL,				/* bus_power */
+	i_ddi_intr_ops			/* bus_intr_op */
+};
+
+static struct cb_ops acpinex_cb_ops = {
+	acpinex_open,			/* cb_open */
+	acpinex_close,			/* cb_close */
+	nodev,				/* cb_strategy */
+	nodev,				/* cb_print */
+	nodev,				/* cb_dump */
+	nodev,				/* cb_read */
+	nodev,				/* cb_write */
+	acpinex_ioctl,			/* cb_ioctl */
+	nodev,				/* cb_devmap */
+	nodev,				/* cb_mmap */
+	nodev,				/* cb_segmap */
+	nochpoll,			/* cb_poll */
+	ddi_prop_op,			/* cb_prop_op */
+	NULL,				/* cb_str */
+	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
+	CB_REV,				/* rev */
+	nodev,				/* int (*cb_aread)() */
+	nodev				/* int (*cb_awrite)() */
+};
+
+static struct dev_ops acpinex_ops = {
+	DEVO_REV,			/* devo_rev, */
+	0,				/* devo_refcnt */
+	acpinex_info,			/* devo_getinfo */
+	nulldev,			/* devo_identify */
+	nulldev,			/* devo_probe */
+	acpinex_attach,			/* devo_attach */
+	acpinex_detach,			/* devo_detach */
+	nulldev,			/* devo_reset */
+	&acpinex_cb_ops,		/* devo_cb_ops */
+	&acpinex_bus_ops,		/* devo_bus_ops */
+	nulldev,			/* devo_power */
+	ddi_quiesce_not_needed		/* devo_quiesce */
+};
+
+static struct modldrv modldrv = {
+	&mod_driverops,			/* Type of module */
+	"ACPI virtual bus driver",	/* name of module */
+	&acpinex_ops,			/* driver ops */
+};
+
+static struct modlinkage modlinkage = {
+	MODREV_1,			/* rev */
+	(void *)&modldrv,
+	NULL
+};
+
+/*
+ * Module initialization routines.
+ */
+int
+_init(void)
+{
+	int error;
+
+	/* Initialize soft state pointer. */
+	if ((error = ddi_soft_state_init(&acpinex_softstates,
+	    sizeof (acpinex_softstate_t), 8)) != 0) {
+		cmn_err(CE_WARN,
+		    "acpinex: failed to initialize soft state structure.");
+		return (error);
+	}
+
+	/* Install the module. */
+	if ((error = mod_install(&modlinkage)) != 0) {
+		cmn_err(CE_WARN, "acpinex: failed to install module.");
+		ddi_soft_state_fini(&acpinex_softstates);
+		return (error);
+	}
+
+	mutex_init(&acpinex_lock, NULL, MUTEX_DRIVER, NULL);
+
+	return (0);
+}
+
+int
+_fini(void)
+{
+	int error;
+
+	/* Remove the module. */
+	if ((error = mod_remove(&modlinkage)) != 0) {
+		return (error);
+	}
+
+	/* Free the soft state info. */
+	ddi_soft_state_fini(&acpinex_softstates);
+
+	mutex_destroy(&acpinex_lock);
+
+	return (0);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+	return (mod_info(&modlinkage, modinfop));
+}
+
+/* ARGSUSED */
+static int
+acpinex_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
+{
+	dev_t	dev;
+	int	instance;
+
+	if (infocmd == DDI_INFO_DEVT2INSTANCE) {
+		dev = (dev_t)arg;
+		instance = ACPINEX_GET_INSTANCE(getminor(dev));
+		*result = (void *)(uintptr_t)instance;
+		return (DDI_SUCCESS);
+	}
+
+	return (DDI_FAILURE);
+}
+
+static int
+acpinex_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
+{
+	int instance;
+	acpinex_softstate_t *softsp;
+
+	switch (cmd) {
+	case DDI_ATTACH:
+		break;
+
+	case DDI_RESUME:
+		return (DDI_SUCCESS);
+
+	default:
+		return (DDI_FAILURE);
+	}
+
+	/* Get and check instance number. */
+	instance = ddi_get_instance(devi);
+	if (instance >= ACPINEX_INSTANCE_MAX) {
+		cmn_err(CE_WARN, "acpinex: instance number %d is out of range "
+		    "in acpinex_attach(), max %d.",
+		    instance, ACPINEX_INSTANCE_MAX - 1);
+		return (DDI_FAILURE);
+	}
+
+	/* Get soft state structure. */
+	if (ddi_soft_state_zalloc(acpinex_softstates, instance)
+	    != DDI_SUCCESS) {
+		cmn_err(CE_WARN, "!acpinex: failed to allocate soft state "
+		    "object in acpinex_attach().");
+		return (DDI_FAILURE);
+	}
+	softsp = ddi_get_soft_state(acpinex_softstates, instance);
+
+	/* Initialize soft state structure */
+	softsp->ans_dip = devi;
+	(void) ddi_pathname(devi, softsp->ans_path);
+	if (ACPI_FAILURE(acpica_get_handle(devi, &softsp->ans_hdl))) {
+		ACPINEX_DEBUG(CE_WARN,
+		    "acpinex: failed to get ACPI handle for %s.",
+		    softsp->ans_path);
+		ddi_soft_state_free(acpinex_softstates, instance);
+		return (DDI_FAILURE);
+	}
+	mutex_init(&softsp->ans_lock, NULL, MUTEX_DRIVER, NULL);
+
+	/* nothing to suspend/resume here */
+	(void) ddi_prop_update_string(DDI_DEV_T_NONE, devi,
+	    "pm-hardware-state", "no-suspend-resume");
+
+	acpinex_fm_init(softsp);
+	ddi_report_dev(devi);
+
+	return (DDI_SUCCESS);
+}
+
+static int
+acpinex_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
+{
+	int instance;
+	acpinex_softstate_t *softsp;
+
+	instance = ddi_get_instance(devi);
+	if (instance >= ACPINEX_INSTANCE_MAX) {
+		cmn_err(CE_WARN, "acpinex: instance number %d is out of range "
+		    "in acpinex_detach(), max %d.",
+		    instance, ACPINEX_INSTANCE_MAX - 1);
+		return (DDI_FAILURE);
+	}
+
+	softsp = ddi_get_soft_state(acpinex_softstates, instance);
+	if (softsp == NULL) {
+		ACPINEX_DEBUG(CE_WARN, "acpinex: failed to get soft state "
+		    "object for instance %d in acpinex_detach()", instance);
+		return (DDI_FAILURE);
+	}
+
+	switch (cmd) {
+	case DDI_DETACH:
+		ddi_remove_minor_node(devi, NULL);
+		acpinex_fm_fini(softsp);
+		mutex_destroy(&softsp->ans_lock);
+		ddi_soft_state_free(acpinex_softstates, instance);
+		return (DDI_SUCCESS);
+
+	case DDI_SUSPEND:
+		return (DDI_SUCCESS);
+
+	default:
+		return (DDI_FAILURE);
+	}
+}
+
+static int
+name_child(dev_info_t *child, char *name, int namelen)
+{
+	char *unitaddr;
+
+	ddi_set_parent_data(child, NULL);
+
+	name[0] = '\0';
+	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
+	    ACPIDEV_PROP_NAME_UNIT_ADDR, &unitaddr) == DDI_SUCCESS) {
+		(void) strncpy(name, unitaddr, namelen - 1);
+		name[namelen - 1] = '\0';
+		ddi_prop_free(unitaddr);
+	} else {
+		ACPINEX_DEBUG(CE_NOTE,
+		    "acpinex: failed to lookup child unit-address prop for %p.",
+		    (void *)child);
+	}
+
+	return (DDI_SUCCESS);
+}
+
+static int
+init_child(dev_info_t *child)
+{
+	char name[MAXNAMELEN];
+
+	(void) name_child(child, name, MAXNAMELEN);
+	ddi_set_name_addr(child, name);
+	if ((ndi_dev_is_persistent_node(child) == 0) &&
+	    (ndi_merge_node(child, name_child) == DDI_SUCCESS)) {
+		impl_ddi_sunbus_removechild(child);
+		return (DDI_FAILURE);
+	}
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * Control ops entry point:
+ *
+ * Requests handled completely:
+ *      DDI_CTLOPS_INITCHILD
+ *      DDI_CTLOPS_UNINITCHILD
+ * All others are passed to the parent.
+ */
+static int
+acpinex_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op, void *arg,
+    void *result)
+{
+	int rval = DDI_SUCCESS;
+
+	switch (op) {
+	case DDI_CTLOPS_INITCHILD:
+		rval = init_child((dev_info_t *)arg);
+		break;
+
+	case DDI_CTLOPS_UNINITCHILD:
+		impl_ddi_sunbus_removechild((dev_info_t *)arg);
+		break;
+
+	case DDI_CTLOPS_REPORTDEV: {
+		if (rdip == (dev_info_t *)0)
+			return (DDI_FAILURE);
+		cmn_err(CE_CONT, "?acpinex: %s@%s, %s%d\n",
+		    ddi_node_name(rdip), ddi_get_name_addr(rdip),
+		    ddi_driver_name(rdip), ddi_get_instance(rdip));
+		break;
+	}
+
+	default:
+		rval = ddi_ctlops(dip, rdip, op, arg, result);
+		break;
+	}
+
+	return (rval);
+}
+
+/* ARGSUSED */
+static int
+acpinex_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
+    off_t offset, off_t len, caddr_t *vaddrp)
+{
+	ACPINEX_DEBUG(CE_WARN,
+	    "acpinex: acpinex_bus_map called and it's unimplemented.");
+	return (DDI_ME_UNIMPLEMENTED);
+}
+
+/* ARGSUSED */
+static int
+acpinex_open(dev_t *devi, int flags, int otyp, cred_t *credp)
+{
+	minor_t minor, instance;
+	acpinex_softstate_t *softsp;
+
+	minor = getminor(*devi);
+	instance = ACPINEX_GET_INSTANCE(minor);
+	if (instance >= ACPINEX_INSTANCE_MAX) {
+		ACPINEX_DEBUG(CE_WARN, "acpinex: instance number %d out of "
+		    "range in acpinex_open, max %d.",
+		    instance, ACPINEX_INSTANCE_MAX - 1);
+		return (EINVAL);
+	}
+
+	softsp = ddi_get_soft_state(acpinex_softstates, instance);
+	if (softsp == NULL) {
+		ACPINEX_DEBUG(CE_WARN, "acpinex: failed to get soft state "
+		    "object for instance %d in acpinex_open().", instance);
+		return (EINVAL);
+	}
+
+	if (ACPINEX_IS_DEVCTL(minor)) {
+		return (0);
+	} else {
+		ACPINEX_DEBUG(CE_WARN,
+		    "acpinex: invalid minor number %d in acpinex_open().",
+		    minor);
+		return (EINVAL);
+	}
+}
+
+/* ARGSUSED */
+static int
+acpinex_close(dev_t dev, int flags, int otyp, cred_t *credp)
+{
+	minor_t minor, instance;
+	acpinex_softstate_t *softsp;
+
+	minor = getminor(dev);
+	instance = ACPINEX_GET_INSTANCE(minor);
+	if (instance >= ACPINEX_INSTANCE_MAX) {
+		ACPINEX_DEBUG(CE_WARN, "acpinex: instance number %d out of "
+		    "range in acpinex_close(), max %d.",
+		    instance, ACPINEX_INSTANCE_MAX - 1);
+		return (EINVAL);
+	}
+
+	softsp = ddi_get_soft_state(acpinex_softstates, instance);
+	if (softsp == NULL) {
+		ACPINEX_DEBUG(CE_WARN, "acpinex: failed to get soft state "
+		    "object for instance %d in acpinex_close().", instance);
+		return (EINVAL);
+	}
+
+	if (ACPINEX_IS_DEVCTL(minor)) {
+		return (0);
+	} else {
+		ACPINEX_DEBUG(CE_WARN,
+		    "acpinex: invalid minor number %d in acpinex_close().",
+		    minor);
+		return (EINVAL);
+	}
+}
+
+/* ARGSUSED */
+static int
+acpinex_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
+    int *rvalp)
+{
+	int rv = 0;
+	minor_t minor, instance;
+	acpinex_softstate_t *softsp;
+
+	minor = getminor(dev);
+	instance = ACPINEX_GET_INSTANCE(minor);
+	if (instance >= ACPINEX_INSTANCE_MAX) {
+		ACPINEX_DEBUG(CE_NOTE, "acpinex: instance number %d out of "
+		    "range in acpinex_ioctl(), max %d.",
+		    instance, ACPINEX_INSTANCE_MAX - 1);
+		return (EINVAL);
+	}
+	softsp = ddi_get_soft_state(acpinex_softstates, instance);
+	if (softsp == NULL) {
+		ACPINEX_DEBUG(CE_WARN, "acpinex: failed to get soft state "
+		    "object for instance %d in acpinex_ioctl().", instance);
+		return (EINVAL);
+	}
+
+	rv = ENOTSUP;
+	ACPINEX_DEBUG(CE_WARN,
+	    "acpinex: invalid minor number %d in acpinex_ioctl().", minor);
+
+	return (rv);
+}
+
+/*
+ * FMA error callback.
+ * Register error handling callback with our parent. We will just call
+ * our children's error callbacks and return their status.
+ */
+/*ARGSUSED*/
+static int
+acpinex_err_callback(dev_info_t *dip, ddi_fm_error_t *derr,
+    const void *impl_data)
+{
+	/* Call our childrens error handlers */
+	return (ndi_fm_handler_dispatch(dip, NULL, derr));
+}
+
+/*
+ * Initialize our FMA resources
+ */
+static void
+acpinex_fm_init(acpinex_softstate_t *softsp)
+{
+	softsp->ans_fm_cap = DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE |
+	    DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE;
+
+	/*
+	 * Request our capability level and get our parent's capability and ibc.
+	 */
+	ddi_fm_init(softsp->ans_dip, &softsp->ans_fm_cap, &softsp->ans_fm_ibc);
+	if (softsp->ans_fm_cap & DDI_FM_ERRCB_CAPABLE) {
+		/*
+		 * Register error callback with our parent if supported.
+		 */
+		ddi_fm_handler_register(softsp->ans_dip, acpinex_err_callback,
+		    softsp);
+	}
+}
+
+/*
+ * Breakdown our FMA resources
+ */
+static void
+acpinex_fm_fini(acpinex_softstate_t *softsp)
+{
+	/* Clean up allocated fm structures */
+	if (softsp->ans_fm_cap & DDI_FM_ERRCB_CAPABLE) {
+		ddi_fm_handler_unregister(softsp->ans_dip);
+	}
+	ddi_fm_fini(softsp->ans_dip);
+}
+
+/*
+ * Initialize FMA resources for child devices.
+ * Called when child calls ddi_fm_init().
+ */
+/*ARGSUSED*/
+static int
+acpinex_fm_init_child(dev_info_t *dip, dev_info_t *tdip, int cap,
+    ddi_iblock_cookie_t *ibc)
+{
+	acpinex_softstate_t *softsp = ddi_get_soft_state(acpinex_softstates,
+	    ddi_get_instance(dip));
+
+	*ibc = softsp->ans_fm_ibc;
+
+	return (softsp->ans_fm_cap);
+}
--- a/usr/src/uts/i86pc/io/ppm.conf	Thu Aug 27 13:21:41 2009 -0700
+++ b/usr/src/uts/i86pc/io/ppm.conf	Thu Aug 27 16:35:32 2009 -0700
@@ -72,8 +72,10 @@
 
 #
 # CPU domain
+# A special rule exists on x86 to catch all CPU devices by using "/" as the
+# device path.
 #
-domain_cpu-devices="/cpus/cpu@*";
+domain_cpu-devices="/";
 domain_cpu-model="CPU";
 
 #
--- a/usr/src/uts/i86pc/os/ddi_impl.c	Thu Aug 27 13:21:41 2009 -0700
+++ b/usr/src/uts/i86pc/os/ddi_impl.c	Thu Aug 27 16:35:32 2009 -0700
@@ -2662,6 +2662,8 @@
 
 	(void) modload("misc", "xpv_autoconfig");
 #else
+	(void) modload("misc", "acpidev");
+
 	if (modload("misc", "pci_autoconfig") < 0) {
 		panic("failed to load misc/pci_autoconfig");
 	}
--- a/usr/src/uts/i86pc/sys/Makefile	Thu Aug 27 13:21:41 2009 -0700
+++ b/usr/src/uts/i86pc/sys/Makefile	Thu Aug 27 16:35:32 2009 -0700
@@ -37,6 +37,7 @@
 FILEMODE = 644
 
 HDRS=  \
+	acpidev.h	\
 	asm_misc.h	\
 	clock.h		\
 	cram.h		\
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/i86pc/sys/acpidev.h	Thu Aug 27 16:35:32 2009 -0700
@@ -0,0 +1,439 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 (c) 2009, Intel Corporation.
+ * All rights reserved.
+ */
+
+#ifndef	_SYS_ACPIDEV_H
+#define	_SYS_ACPIDEV_H
+#include <sys/types.h>
+#include <sys/obpdefs.h>
+#include <sys/sunddi.h>
+#include <sys/acpi/acpi.h>
+#include <sys/acpica.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Maximum recursion levels when enumerating objects in ACPI namespace. */
+#define	ACPIDEV_MAX_ENUM_LEVELS		32
+
+/* Maximum length of device name for ACPI object. */
+#define	ACPIDEV_MAX_NAMELEN		OBP_MAXDRVNAME
+
+/* Pseudo ACPI device HID for ACPI root object. */
+#define	ACPIDEV_HID_ROOTNEX		"SOLA0001"
+/* Pseudo ACPI device HID for ACPI virtual bus. */
+#define	ACPIDEV_HID_VIRTNEX		"SOLA0002"
+#define	ACPIDEV_HID_SCOPE		"SOLA0003"
+#define	ACPIDEV_HID_PROCESSOR		"SOLA0004"
+
+/* ACPI device HIDs/CIDs defined by ACPI specification. */
+#define	ACPIDEV_HID_CONTAINER1		"PNP0A05"
+#define	ACPIDEV_HID_CONTAINER2		"PNP0A06"
+#define	ACPIDEV_HID_MODULE		"ACPI0004"
+#define	ACPIDEV_HID_CPU			"ACPI0007"
+#define	ACPIDEV_HID_PCI_HOSTBRIDGE	"PNP0A03"
+#define	ACPIDEV_HID_PCIE_HOSTBRIDGE	"PNP0A08"
+#define	ACPIDEV_HID_MEMORY		"PNP0C80"
+
+/* Common ACPI object names. */
+#define	ACPIDEV_OBJECT_NAME_SB		ACPI_NS_SYSTEM_BUS
+#define	ACPIDEV_OBJECT_NAME_PR		"_PR_"
+
+/* Common ACPI method names. */
+#define	ACPIDEV_METHOD_NAME_MAT		"_MAT"
+
+/* Device names for ACPI objects. */
+#define	ACPIDEV_NODE_NAME_ROOT		"fw"
+#define	ACPIDEV_NODE_NAME_CONTAINER	"container"
+#define	ACPIDEV_NODE_NAME_MODULE_SBD	"sb"
+#define	ACPIDEV_NODE_NAME_MODULE_CPU	"socket"
+#define	ACPIDEV_NODE_NAME_CPU		"cpu"
+#define	ACPIDEV_NODE_NAME_PROCESSOR	"cpus"
+#define	ACPIDEV_NODE_NAME_MEMORY	"mem"
+
+/* Device types for ACPI objects. */
+#define	ACPIDEV_TYPE_ROOTNEX		"acpirootnex"
+#define	ACPIDEV_TYPE_VIRTNEX		"acpivirtnex"
+#define	ACPIDEV_TYPE_SCOPE		"acpiscope"
+#define	ACPIDEV_TYPE_DEVICE		"acpidevice"
+#define	ACPIDEV_TYPE_CONTAINER		"acpicontainer"
+#define	ACPIDEV_TYPE_CPU		"cpu"
+#define	ACPIDEV_TYPE_MEMORY		"acpimemory"
+
+/* Device property names for ACPI objects. */
+#define	ACPIDEV_PROP_NAME_UNIT_ADDR	"unit-address"
+#define	ACPIDEV_PROP_NAME_ACPI_UID	"acpi-uid"
+#define	ACPIDEV_PROP_NAME_PROCESSOR_ID	"acpi-processor-id"
+#define	ACPIDEV_PROP_NAME_LOCALAPIC_ID	"apic-id"
+
+#define	ACPIDEV_PROP_NAME_UID_FORMAT	"acpidev-uid-format"
+
+/* ACPI device class Id. */
+typedef enum acpidev_class_id {
+	ACPIDEV_CLASS_ID_INVALID = 0,
+	ACPIDEV_CLASS_ID_ROOTNEX = 1,
+	ACPIDEV_CLASS_ID_SCOPE = 2,
+	ACPIDEV_CLASS_ID_DEVICE = 3,
+	ACPIDEV_CLASS_ID_CONTAINER = 4,
+	ACPIDEV_CLASS_ID_CPU = 5,
+	ACPIDEV_CLASS_ID_MEMORY = 6,
+	ACPIDEV_CLASS_ID_MAX
+} acpidev_class_id_t;
+
+/* Flags for acpidev_options boot options. */
+#define	ACPIDEV_OUSER_NO_CPU		0x1
+#define	ACPIDEV_OUSER_NO_MEM		0x2
+#define	ACPIDEV_OUSER_NO_CONTAINER	0x4
+
+#ifdef	_KERNEL
+
+/* Forward declaration */
+typedef	struct acpidev_data_impl	*acpidev_data_handle_t;
+typedef struct acpidev_walk_info	acpidev_walk_info_t;
+typedef struct acpidev_filter_rule	acpidev_filter_rule_t;
+typedef struct acpidev_class		acpidev_class_t;
+typedef struct acpidev_class_list	acpidev_class_list_t;
+
+/* Type of ACPI device enumerating operation. */
+typedef enum acpidev_op_type {
+	ACPIDEV_OP_BOOT_PROBE = 0,	/* First pass probing at boot time. */
+	ACPIDEV_OP_BOOT_REPROBE,	/* Second pass probing at boot time. */
+	ACPIDEV_OP_HOTPLUG_PROBE	/* Probing for hotplug at runtime. */
+} acpidev_op_type_t;
+
+/*
+ * Structure to pass arguments when enumerating ACPI namespace.
+ */
+struct acpidev_walk_info {
+	/* Always valid for all callbacks. */
+	acpidev_op_type_t		awi_op_type;
+	int				awi_level;
+	acpidev_walk_info_t		*awi_parent;
+	acpidev_class_t			*awi_class_curr;
+
+	/* Valid for all callbacks except pre_probe and post_probe. */
+	int				awi_flags;
+	ACPI_HANDLE			awi_hdl;
+	ACPI_DEVICE_INFO		*awi_info;
+	char				*awi_name;
+	acpidev_data_handle_t		awi_data;
+
+	/* Need to validate it before access. */
+	dev_info_t			*awi_dip;
+	acpidev_class_list_t		**awi_class_list;
+
+	/* Used by class to store data temporarily. */
+	intptr_t			awi_scratchpad[4];
+};
+
+/* Disable creating device nodes for ACPI objects. */
+#define	ACPIDEV_WI_DISABLE_CREATE	0x1
+/* Device node has already been created for an ACPI object. */
+#define	ACPIDEV_WI_DEVICE_CREATED	0x2
+/* Disable enumerating children of ACPI objects. */
+#define	ACPIDEV_WI_DISABLE_SCAN		0x10
+/* Children of ACPI objects have already been enumerated. */
+#define	ACPIDEV_WI_CHILD_SCANNED	0x20
+
+/*
+ * Device filtering result code.
+ * Device filtering logic will be applied to determine how to handle ACPI
+ * objects according to the filtering result code when enumerating ACPI objects.
+ */
+typedef enum acpidev_filter_result {
+	ACPIDEV_FILTER_FAILED = -1,	/* operation failed */
+	ACPIDEV_FILTER_CONTINUE = 0,	/* continue to evaluate filter rules */
+	ACPIDEV_FILTER_DEFAULT,		/* create node and scan child */
+	ACPIDEV_FILTER_SCAN,		/* scan child of current node only */
+	ACPIDEV_FILTER_CREATE,		/* create device node only */
+	ACPIDEV_FILTER_SKIP,		/* skip current node */
+} acpidev_filter_result_t;
+
+typedef acpidev_filter_result_t (* acpidev_filter_func_t)(acpidev_walk_info_t *,
+    ACPI_HANDLE, acpidev_filter_rule_t *, char *, int);
+
+/*
+ * Device filter rule data structure.
+ * User provided callback will be called if adf_filter_func is not NULL,
+ * otherwise default filtering algorithm will be applied.
+ */
+struct acpidev_filter_rule {
+	acpidev_filter_func_t		adf_filter_func;
+	intptr_t			adf_filter_arg;
+	acpidev_filter_result_t		adf_retcode;
+	acpidev_class_list_t		**adf_class_list;
+	intptr_t			adf_minlvl;
+	intptr_t			adf_maxlvl;
+	char				*adf_pattern;
+	char				*adf_replace;
+};
+
+/* Callback function prototypes for ACPI device class driver. */
+typedef ACPI_STATUS (* acpidev_pre_probe_t)(acpidev_walk_info_t *);
+typedef ACPI_STATUS (* acpidev_post_probe_t)(acpidev_walk_info_t *);
+typedef ACPI_STATUS (* acpidev_probe_t)(acpidev_walk_info_t *);
+typedef acpidev_filter_result_t (* acpidev_filter_t)(acpidev_walk_info_t *,
+    char *, int);
+typedef ACPI_STATUS (* acpidev_init_t)(acpidev_walk_info_t *);
+typedef ACPI_STATUS (* acpidev_fini_t)(ACPI_HANDLE, dev_info_t *,
+    acpidev_class_t *);
+
+/* Device class driver interface. */
+struct acpidev_class {
+	volatile uint32_t		adc_refcnt;
+	int				adc_version;
+	acpidev_class_id_t		adc_class_id;
+	/* Name of device class, used in log messages. */
+	char				*adc_class_name;
+	/* Used as "device_type" property. */
+	char				*adc_dev_type;
+	/* Private storage for device driver. */
+	void				*adc_private;
+	/* Callback to setup environment before probing child objects. */
+	acpidev_pre_probe_t		adc_pre_probe;
+	/* Callback to clean environment after probing child objects. */
+	acpidev_post_probe_t		adc_post_probe;
+	/* Callback to probe child objects. */
+	acpidev_probe_t			adc_probe;
+	/* Callback to figure out policy to handle objects. */
+	acpidev_filter_t		adc_filter;
+	/* Callback to set device class specific device properties. */
+	acpidev_init_t			adc_init;
+	/* Callback to clean up resources when destroying device nodes. */
+	acpidev_fini_t			adc_fini;
+};
+
+/* Versions of the ACPI device class driver data structure. */
+#define	ACPIDEV_CLASS_REV1		1
+#define	ACPIDEV_CLASS_REV		ACPIDEV_CLASS_REV1
+
+/*
+ * Class drivers.
+ */
+extern acpidev_class_t			acpidev_class_scope;
+extern acpidev_class_t			acpidev_class_device;
+extern acpidev_class_t			acpidev_class_container;
+extern acpidev_class_t			acpidev_class_cpu;
+extern acpidev_class_t			acpidev_class_memory;
+
+/*
+ * Class driver lists.
+ */
+extern acpidev_class_list_t		*acpidev_class_list_root;
+extern acpidev_class_list_t		*acpidev_class_list_scope;
+extern acpidev_class_list_t		*acpidev_class_list_device;
+extern acpidev_class_list_t		*acpidev_class_list_cpu;
+extern acpidev_class_list_t		*acpidev_class_list_memory;
+
+/*
+ * Register a device class driver onto a driver list. All class drivers on the
+ * same list will be called in order when processing an ACPI object.
+ * This interface can be used to support machine/platform specific object
+ * handling by registering special plug-in class drivers to override system
+ * default behaviors.
+ * listpp:	pointer to driver list header
+ * clsp:	device class driver to register
+ * tail:	insert at tail of list if true
+ * Return values:
+ *	AE_OK: success
+ *	AE_BAD_PARAMETER: invalid parameter
+ *	AE_BAD_DATA: driver version mismatch
+ *	AE_ALREADY_EXISTS: class driver already exists on the list
+ */
+extern ACPI_STATUS acpidev_register_class(acpidev_class_list_t **listpp,
+    acpidev_class_t *clsp, boolean_t tail);
+
+/*
+ * Unregister a device class driver from a driver list.
+ * listpp: pointer to driver list header
+ * clsp: device class driver to unregister
+ * Return values:
+ *	AE_OK: success
+ *	AE_BAD_PARAMETER: invalid parameter
+ *	AE_NOT_FOUND: class driver doesn't exist in list
+ *	AE_ERROR: class driver is still in use.
+ */
+extern ACPI_STATUS acpidev_unregister_class(acpidev_class_list_t **listpp,
+    acpidev_class_t *clsp);
+
+/*
+ * Recursively enumerate child objects of an ACPI object.
+ * It does following things in turn:
+ * 1) Call pre_probe callback for each registered handler
+ * 2) Enumerate child objects and call probe callbacks for each object
+ * 3) Call post_probe callback for each registered handler
+ * Return AE_OK on success and error code on failure.
+ */
+extern ACPI_STATUS acpidev_probe_child(acpidev_walk_info_t *infop);
+
+/*
+ * Default handler to process ACPI objects.
+ * It creates a device node for an ACPI object and scans all child objects on
+ * demand.
+ * Return values:
+ * AE_OK: on success
+ * AE_NOT_EXIST: device doesn't exist according to _STA value.
+ * AE_ALREADY_EXISTS: object already handled by other handler.
+ * AE_ERROR: on other failure
+ */
+extern ACPI_STATUS acpidev_process_object(acpidev_walk_info_t *infop,
+    int flags);
+
+/* Flags for acpidev_process_device() */
+#define	ACPIDEV_PROCESS_FLAG_CREATE	0x1	/* Create device */
+#define	ACPIDEV_PROCESS_FLAG_SCAN	0x2	/* Scan child objects */
+#define	ACPIDEV_PROCESS_FLAG_CHECK	0x100	/* Check status */
+#define	ACPIDEV_PROCESS_FLAG_NOBIND	0x200	/* Skip binding driver */
+#define	ACPIDEV_PROCESS_FLAG_OFFLINE	0x400	/* Put device into offline. */
+#define	ACPIDEV_PROCESS_FLAG_NOTAG	0x800	/* Skip tag dip with object. */
+#define	ACPIDEV_PROCESS_FLAG_SYNCSTATUS	0x1000	/* Sync object status. */
+
+/*
+ * Filter ACPI objects according to filter rules, generate devname if needed.
+ * infop:	pointer to walker information structure
+ * hdl:		handle of ACPI object in question
+ * afrp:	pointer to filter rule array
+ * entries:	number of filter rules in array
+ * devname:	buffer to store generated device name
+ * len:		sizeof devname buffer
+ */
+extern acpidev_filter_result_t acpidev_filter_device(acpidev_walk_info_t *infop,
+    ACPI_HANDLE hdl, acpidev_filter_rule_t *afrp, int entries,
+    char *devname, int len);
+
+/* Default object filtering algorithm. */
+extern acpidev_filter_result_t acpidev_filter_default(
+    acpidev_walk_info_t *infop, ACPI_HANDLE hdl, acpidev_filter_rule_t *afrp,
+    char *devname, int len);
+
+/* Utility routines */
+extern dev_info_t *acpidev_root_node(void);
+extern char *acpidev_get_object_name(ACPI_HANDLE hdl);
+extern void acpidev_free_object_name(char *objname);
+
+extern acpidev_walk_info_t *acpidev_alloc_walk_info(acpidev_op_type_t op_type,
+    int lvl, ACPI_HANDLE hdl, acpidev_class_list_t **listpp,
+    acpidev_walk_info_t *pinfop);
+extern void acpidev_free_walk_info(acpidev_walk_info_t *infop);
+extern dev_info_t *acpidev_walk_info_get_pdip(acpidev_walk_info_t *infop);
+
+/* Interfaces to access data associated with ACPI object. */
+extern acpidev_data_handle_t acpidev_data_get_handle(ACPI_HANDLE hdl);
+extern acpidev_data_handle_t acpidev_data_create_handle(ACPI_HANDLE hdl);
+extern void acpidev_data_destroy_handle(ACPI_HANDLE hdl);
+extern ACPI_HANDLE acpidev_data_get_object(acpidev_data_handle_t hdl);
+extern dev_info_t *acpidev_data_get_devinfo(acpidev_data_handle_t hdl);
+extern int acpidev_data_get_status(acpidev_data_handle_t hdl);
+extern void acpidev_data_set_flag(acpidev_data_handle_t hdl, uint32_t flag);
+extern void acpidev_data_clear_flag(acpidev_data_handle_t hdl, uint32_t flag);
+extern uint32_t acpidev_data_get_flag(acpidev_data_handle_t hdl, uint32_t flag);
+
+/*
+ * Try to generate meaningful device unit address from uid.
+ * Return buf on success and NULL on failure.
+ */
+extern char *acpidev_generate_unitaddr(char *uid, char **fmts, size_t nfmt,
+    char *buf, size_t len);
+
+/*
+ * Set device unit address property if _UID is available or unitaddr is valid.
+ * Return AE_OK on success and error code on failure.
+ * N.B.: it returns AE_OK if _UID is unavailable and unitaddr is NULL.
+ */
+extern ACPI_STATUS acpidev_set_unitaddr(acpidev_walk_info_t *infop,
+    char **fmts, size_t nfmt, char *unitaddr);
+
+/*
+ * Generate the device 'compatible' property list for a device based on:
+ *	* Device HID if available
+ *	* Device CIDs if available
+ *	* property array passed in
+ * infop:	pointer to walk information structure
+ * compat:	pointer to property array
+ * acount:	entries in property array
+ * Return AE_OK on success and error code on failure.
+ */
+extern ACPI_STATUS acpidev_set_compatible(acpidev_walk_info_t *infop,
+    char **compat, int acount);
+
+/*
+ * Query ACPI device status.
+ * N.B.: it returns with all status bits set if _STA is not available.
+ */
+extern int acpidev_query_device_status(ACPI_HANDLE hdl);
+
+/*
+ * Check whether device exists.
+ * Return false if device doesn't exist.
+ */
+extern boolean_t acpidev_check_device_present(int status);
+
+/*
+ * Check whether device is enabled.
+ * Return false if device doesn't exist or hasn't been enabled.
+ */
+extern boolean_t acpidev_check_device_enabled(int status);
+
+/*
+ * Match device ids with ACPI object's _HID and _CIDs.
+ * infop: ACPI object information structure
+ * ids: array of ACPI HIDs and CIDs
+ * count: entries in array
+ * Return TRUE if one item matches or num is zero, else FALSE.
+ */
+extern boolean_t acpidev_match_device_id(ACPI_DEVICE_INFO *infop,
+    char **ids, int count);
+
+/*
+ * Implement almost the same function as AcpiGetDevices() with the following
+ * changes/enhancements:
+ * 1) Support limiting recursive levels.
+ * 2) Support matching multiple ids instead of one.
+ * 3) Report device without ACPI_STA_DEVICE_PRESENT flag which will be ignored
+ *    by AcpiGetDevices().
+ */
+extern ACPI_STATUS acpidev_get_device_by_id(ACPI_HANDLE hdl,
+    char **ids, int count, int maxdepth, boolean_t skip_non_exist,
+    ACPI_WALK_CALLBACK userfunc, void *userarg, void** retval);
+
+/* Callback for APIC entry walker. */
+typedef ACPI_STATUS (* acpidev_apic_walker_t)(ACPI_SUBTABLE_HEADER *, void *);
+
+/*
+ * Walk ACPI APIC entries from the first source available in following order:
+ * 1) ACPI buffer passed in if bufp isn't NULL.
+ * 2) Buffer returned by evaluating method if it isn't NULL.
+ * 3) MADT table as last resort.
+ */
+extern ACPI_STATUS acpidev_walk_apic(ACPI_BUFFER *bufp, ACPI_HANDLE hdl,
+    char *method, acpidev_apic_walker_t func, void *context);
+
+#endif	/* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _SYS_ACPIDEV_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/i86pc/sys/acpidev_impl.h	Thu Aug 27 16:35:32 2009 -0700
@@ -0,0 +1,92 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 (c) 2009, Intel Corporation.
+ * All rights reserved.
+ */
+
+#ifndef	_SYS_ACPIDEV_IMPL_H
+#define	_SYS_ACPIDEV_IMPL_H
+#include <sys/types.h>
+#include <sys/cmn_err.h>
+#include <sys/sunddi.h>
+#include <sys/acpi/acpi.h>
+#include <sys/acpica.h>
+#include <sys/acpidev.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef	_KERNEL
+
+#define	ACPIDEV_ARRAY_PARAM(a)		(a), (sizeof (a) / sizeof ((a)[0]))
+
+/* Debug support facilities. */
+extern int acpidev_debug;
+#define	ACPIDEV_DEBUG(lvl, ...)	if (acpidev_debug) cmn_err((lvl), __VA_ARGS__)
+
+/* Data attached to an ACPI object to maintain device status information. */
+struct acpidev_data_impl {
+	uint32_t			aod_eflag;	/* External flags */
+	uint32_t			aod_iflag;	/* Internal flags */
+	uint32_t			aod_level;
+	int				aod_status;	/* Cached _STA value */
+	ACPI_HANDLE			*aod_hdl;
+	dev_info_t			*aod_dip;
+	acpidev_class_t			*aod_class;
+	acpidev_class_list_t		**aod_class_list;
+};
+
+#define	ACPIDEV_ODF_STATUS_VALID	0x1
+#define	ACPIDEV_ODF_DEVINFO_CREATED	0x2
+#define	ACPIDEV_ODF_DEVINFO_TAGGED	0x4
+#define	ACPIDEV_ODF_DEVINFO_OFFLINE	0x8
+
+/*
+ * List of registered device class drivers.
+ * Class drivers on the same list will be called from head to tail in turn.
+ */
+struct acpidev_class_list {
+	acpidev_class_list_t		*acl_next;
+	acpidev_class_t			*acl_class;
+};
+
+typedef struct acpidev_pseudo_uid {
+	struct acpidev_pseudo_uid	*apu_next;
+	char				*apu_uid;
+	acpidev_class_id_t		apu_cid;
+	uint_t				apu_nid;
+} acpidev_pseudo_uid_t;
+
+typedef struct acpidev_pseudo_uid_head {
+	kmutex_t			apuh_lock;
+	uint32_t			apuh_id;
+	acpidev_pseudo_uid_t		*apuh_first;
+} acpidev_pseudo_uid_head_t;
+
+#endif	/* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _SYS_ACPIDEV_IMPL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/i86pc/sys/acpidev_rsc.h	Thu Aug 27 16:35:32 2009 -0700
@@ -0,0 +1,202 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2009, Intel Corporation.
+ * All rights reserved.
+ */
+
+#ifndef	_SYS_ACPIDEV_RSC_H
+#define	_SYS_ACPIDEV_RSC_H
+#include <sys/types.h>
+#include <sys/obpdefs.h>
+#include <sys/sunddi.h>
+#include <sys/acpi/acpi.h>
+#include <sys/acpica.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ACPI bus range structure. */
+typedef struct acpidev_bus_range {
+	uint_t	bus_start;
+	uint_t	bus_end;
+} acpidev_bus_range_t;
+
+/*
+ * This structure is modeled after the 1275 "reg" property and
+ * "assigned-addresses" property for PCI device nodes.
+ * There's no standard definition available for ACPI devices.
+ * This structure is used to store resources returned by the ACPI
+ * _CRS method.
+ *
+ * The physical address format is:
+ *         Bit#:      33222222 22221111 11111100 00000000
+ *                    10987654 32109876 54321098 76543210
+ * phys_hi cell:      xxxxxxxx xxxxxxxx xxxxxxxx TSxxxTTT
+ * phys_hi(memory):   xxxxxxxx xxxxxxxx wxxxxxcc --xxx000
+ * phys_hi(io):       xxxxxxxx xxxxxxxx sdxxxxaa --xxx001
+ * phys_mid cell:     hhhhhhhh hhhhhhhh hhhhhhhh hhhhhhhh
+ * phys_low cell:     llllllll llllllll llllllll llllllll
+ *
+ * TTT        is type of resource. Such as MEMORY, IO etc.
+ * S          is 1 if address range is subtractive decoding
+ * T          is 1 if resource type is different on primary and
+ *	      secondary bus
+ * cc         is memory coherence type
+ * w          is 1 if memory is writable
+ * aa         ranges of decoded ports, ISA only, non-ISA only or full.
+ * d          is 1 if IO port decode 16 bit address, otherwise 10 bits.
+ * s          is 1 if translation is sparse.
+ * hh...hhh   is the 32-bit unsigned number
+ * ll...lll   is the 32-bit unsigned number
+ *
+ * The physical size format is:
+ *
+ * size_hi cell:  hhhhhhhh hhhhhhhh hhhhhhhh hhhhhhhh
+ * size_low cell: llllllll llllllll llllllll llllllll
+ *
+ * hh...hhh   is the 32-bit unsigned number
+ * ll...lll   is the 32-bit unsigned number
+ */
+typedef struct acpidev_phys_spec {
+	uint_t	phys_hi;		/* resource address, hi word */
+	uint_t	phys_mid;		/* resource address, middle word */
+	uint_t	phys_low;		/* resource address, low word */
+	uint_t	size_hi;		/* high word of size field */
+	uint_t	size_low;		/* low word of size field */
+} acpidev_phys_spec_t;
+
+typedef struct acpidev_phys_spec	acpidev_regspec_t;
+
+#define	ACPIDEV_REG_TYPE_M		0x00000007
+#define	ACPIDEV_REG_TYPE_MEMORY		0x00000000
+#define	ACPIDEV_REG_TYPE_IO		0x00000001
+#define	ACPIDEV_REG_SUB_DEC		0x00000040
+#define	ACPIDEV_REG_TRANSLATED		0x00000080
+
+#define	ACPIDEV_REG_MEM_COHERENT_M	0x00000300
+#define	ACPIDEV_REG_MEM_COHERENT_NC	0x00000000	/* Non-cachable */
+#define	ACPIDEV_REG_MEM_COHERENT_CA	0x00000100	/* Cachable */
+#define	ACPIDEV_REG_MEM_COHERENT_WC	0x00000200	/* Write-combining */
+#define	ACPIDEV_REG_MEM_COHERENT_PF	0x00000300	/* Prefectable */
+#define	ACPIDEV_REG_MEM_WRITABLE	0x00008000	/* Writable */
+
+#define	ACPIDEV_REG_IO_RANGE_M		0x00000300
+#define	ACPIDEV_REG_IO_RANGE_NONISA	0x00000100
+#define	ACPIDEV_REG_IO_RANGE_ISA	0x00000200
+#define	ACPIDEV_REG_IO_RANGE_FULL	0x00000300
+#define	ACPIDEV_REG_IO_DECODE16		0x00004000	/* Decode 16bit addr. */
+#define	ACPIDEV_REG_IO_SPARSE		0x00008000 /* Sparse translation. */
+
+typedef struct acpidev_ranges {
+	uint_t	child_hi;		/* child's address, hi word */
+	uint_t	child_mid;		/* child's address, middle word */
+	uint_t	child_low;		/* child's address, low word */
+	uint_t	parent_hi;		/* parent's address, hi word */
+	uint_t	parent_mid;		/* parent's address, middle word */
+	uint_t	parent_low;		/* parent's address, low word */
+	uint_t	size_hi;		/* high word of size field */
+	uint_t	size_low;		/* low word of size field */
+} acpidev_ranges_t;
+
+#ifdef	_KERNEL
+
+/* Maximum possible number of IRQs. */
+#define	ACPIDEV_RES_IRQ_MAX		16
+/* Maximum possible number of DMAs. */
+#define	ACPIDEV_RES_DMA_MAX		8
+
+/* Forward declaration */
+typedef	struct acpidev_resource_handle	*acpidev_resource_handle_t;
+
+/*
+ * Resource handler relative interfaces.
+ * Return values of acpidev_resource_get_xxx interfaces:
+ * AE_OK: succeed with resources stored in buffer and count updated.
+ * AE_LIMIT: buffer is too small, count updated to number of resources.
+ * AE_BAD_PARAMETER: invalid parameter
+ */
+extern acpidev_resource_handle_t acpidev_resource_handle_alloc(
+    boolean_t consumer);
+extern void acpidev_resource_handle_free(acpidev_resource_handle_t rhdl);
+
+extern ACPI_STATUS acpidev_resource_insert_reg(acpidev_resource_handle_t rhdl,
+    acpidev_regspec_t *regp);
+extern ACPI_STATUS acpidev_resource_get_regs(acpidev_resource_handle_t rhdl,
+    uint_t mask, uint_t value, acpidev_regspec_t *regp, uint_t *cntp);
+extern uint_t acpidev_resource_get_reg_count(acpidev_resource_handle_t rhdl,
+    uint_t mask, uint_t value);
+
+extern ACPI_STATUS acpidev_resource_insert_range(acpidev_resource_handle_t rhdl,
+    acpidev_ranges_t *rangep);
+extern ACPI_STATUS acpidev_resource_get_ranges(acpidev_resource_handle_t rhdl,
+    uint_t mask, uint_t value, acpidev_ranges_t *rangep, uint_t *cntp);
+extern uint_t acpidev_resource_get_range_count(acpidev_resource_handle_t rhdl,
+    uint_t mask, uint_t value);
+
+extern ACPI_STATUS acpidev_resource_insert_bus(acpidev_resource_handle_t rhdl,
+    acpidev_bus_range_t *busp);
+extern ACPI_STATUS acpidev_resource_get_buses(acpidev_resource_handle_t rhdl,
+    acpidev_bus_range_t *busp, uint_t *cntp);
+extern uint_t acpidev_resource_get_bus_count(acpidev_resource_handle_t rhdl);
+
+extern ACPI_STATUS acpidev_resource_insert_dma(acpidev_resource_handle_t rhdl,
+    int dma);
+extern ACPI_STATUS acpidev_resource_get_dmas(acpidev_resource_handle_t rhdl,
+    uint_t *dmap, uint_t *cntp);
+extern uint_t acpidev_resource_get_dma_count(acpidev_resource_handle_t rhdl);
+
+extern ACPI_STATUS acpidev_resource_insert_irq(acpidev_resource_handle_t rhdl,
+    int irq);
+extern ACPI_STATUS acpidev_resource_get_irqs(acpidev_resource_handle_t rhdl,
+    uint_t *irqp, uint_t *cntp);
+extern uint_t acpidev_resource_get_irq_count(acpidev_resource_handle_t rhdl);
+
+/*
+ * Walk resources returned by 'method' and store parsed resources into rhdlp.
+ * Caller needs to release rhdlp after using it.
+ * Return AE_OK on success with resource handle stored in 'rhdlp'.
+ */
+extern ACPI_STATUS acpidev_resource_walk(ACPI_HANDLE hdl, char *method,
+    boolean_t consumer, acpidev_resource_handle_t *rhdlp);
+
+/*
+ * Walk resources returned by the ACPI _CRS method and create device properties.
+ * Create 'reg', 'assigned-addresses', 'dma-channels' and 'interrupts'
+ * properties for resource consumer.
+ * Create 'ranges' and 'bus-range' properties for resource producer.
+ */
+extern ACPI_STATUS acpidev_resource_process(acpidev_walk_info_t *infop,
+    boolean_t consumer);
+
+#endif	/* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _SYS_ACPIDEV_RSC_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/i86pc/sys/acpinex.h	Thu Aug 27 16:35:32 2009 -0700
@@ -0,0 +1,71 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 (c) 2009, Intel Corporation.
+ * All rights reserved.
+ */
+
+#ifndef	_ACPI_NEXUS_H
+#define	_ACPI_NEXUS_H
+#include <sys/types.h>
+#include <sys/dditypes.h>	/* needed for definition of dev_info_t */
+#include <sys/mutex.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#ifdef	_KERNEL
+
+#define	ACPINEX_INSTANCE_MAX		(1 << 10)
+#define	ACPINEX_INSTANCE_MASK		(ACPINEX_INSTANCE_MAX - 1)
+#define	ACPINEX_INSTANCE_SHIFT		8
+#define	ACPINEX_MINOR_TYPE_MASK		((1 << ACPINEX_INSTANCE_SHIFT) - 1)
+#define	ACPINEX_DEVCTL_MINOR		((1 << ACPINEX_INSTANCE_SHIFT) - 1)
+
+#define	ACPINEX_MAKE_DEVCTL_MINOR(instance) \
+	(((instance) << ACPINEX_INSTANCE_SHIFT) | ACPINEX_DEVCTL_MINOR)
+#define	ACPINEX_IS_DEVCTL(minor)	\
+	(((minor) & ACPINEX_MINOR_TYPE_MASK) == ACPINEX_DEVCTL_MINOR)
+
+#define	ACPINEX_GET_INSTANCE(minor)	((minor) >> ACPINEX_INSTANCE_SHIFT)
+
+extern int	acpinex_debug;
+#define	ACPINEX_DEBUG(lvl, ...)		\
+	if (acpinex_debug) cmn_err((lvl), __VA_ARGS__)
+
+/* Softstate structure for acpinex instance. */
+typedef struct {
+	dev_info_t			*ans_dip;
+	ACPI_HANDLE			ans_hdl;
+	int				ans_fm_cap;
+	ddi_iblock_cookie_t		ans_fm_ibc;
+	kmutex_t			ans_lock;
+	char				ans_path[MAXPATHLEN];
+} acpinex_softstate_t;
+
+#endif	/* _KERNEL */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _ACPI_NEXUS_H */
--- a/usr/src/uts/intel/io/acpica/namespace/nsxfname.c	Thu Aug 27 13:21:41 2009 -0700
+++ b/usr/src/uts/intel/io/acpica/namespace/nsxfname.c	Thu Aug 27 16:35:32 2009 -0700
@@ -388,7 +388,7 @@
 
     /* If not a device, we are all done */
 
-    if (Info->Type == ACPI_TYPE_DEVICE)
+    if (Info->Type == ACPI_TYPE_DEVICE || Info->Type == ACPI_TYPE_PROCESSOR)
     {
         /*
          * Get extra info for ACPI Devices objects only:
--- a/usr/src/uts/intel/io/acpica/osl.c	Thu Aug 27 13:21:41 2009 -0700
+++ b/usr/src/uts/intel/io/acpica/osl.c	Thu Aug 27 16:35:32 2009 -0700
@@ -43,6 +43,7 @@
 #include <sys/kobj.h>
 #include <sys/taskq.h>
 #include <sys/strlog.h>
+#include <sys/x86_archext.h>
 #include <sys/note.h>
 #include <sys/promif.h>
 
@@ -120,6 +121,13 @@
 static int cpu_map_count = 0;
 static int cpu_map_built = 0;
 
+/*
+ * On systems with the uppc PSM only, acpica_map_cpu() won't be called at all.
+ * This flag is used to check for uppc-only systems by detecting whether
+ * acpica_map_cpu() has been called or not.
+ */
+static int cpu_map_called = 0;
+
 static int acpi_has_broken_bbn = -1;
 
 /* buffer for AcpiOsVprintf() */
@@ -1552,14 +1560,31 @@
 			break;
 		}
 	}
-	if (i >= cpu_map_count || (cpu_map[i]->obj == NULL)) {
+	if (i < cpu_map_count && (cpu_map[i]->obj != NULL)) {
+		*rh = cpu_map[cpu_id]->obj;
 		mutex_exit(&cpu_map_lock);
-		return (AE_ERROR);
+		return (AE_OK);
 	}
-	*rh = cpu_map[cpu_id]->obj;
+
+	/* Handle special case for uppc-only systems. */
+	if (cpu_map_called == 0) {
+		uint32_t apicid = cpuid_get_apicid(CPU);
+		if (apicid != UINT32_MAX) {
+			for (i = 0; i < cpu_map_count; i++) {
+				if (cpu_map[i]->apic_id == apicid) {
+					break;
+				}
+			}
+			if (i < cpu_map_count && (cpu_map[i]->obj != NULL)) {
+				*rh = cpu_map[cpu_id]->obj;
+				mutex_exit(&cpu_map_lock);
+				return (AE_OK);
+			}
+		}
+	}
 	mutex_exit(&cpu_map_lock);
 
-	return (AE_OK);
+	return (AE_ERROR);
 }
 
 /*
@@ -1923,9 +1948,10 @@
  * 1) acpica_add_processor_to_map() builds mapping among APIC id, ACPI
  *    processor id and ACPI object handle.
  * 2) acpica_map_cpu() builds mapping among cpu id and ACPI processor id.
- * On system with ACPI device configuration for CPU enabled, acpica_map_cpu()
- * will be called before acpica_add_processor_to_map(), otherwise
- * acpica_map_cpu() will be called after acpica_add_processor_to_map().
+ * On systems with which have ACPI device configuration for CPUs enabled,
+ * acpica_map_cpu() will be called after acpica_add_processor_to_map(),
+ * otherwise acpica_map_cpu() will be called before
+ * acpica_add_processor_to_map().
  */
 ACPI_STATUS
 acpica_add_processor_to_map(UINT32 acpi_id, ACPI_HANDLE obj, UINT32 apic_id)
@@ -1947,6 +1973,9 @@
 	 * been disabled, there won't be a CPU map yet because uppc psm doesn't
 	 * call acpica_map_cpu(). So create one and use the passed-in processor
 	 * as CPU 0
+	 * Assumption: the first CPU returned by
+	 * AcpiGetDevices/AcpiWalkNamespace will be the BSP.
+	 * Unfortunately there appears to be no good way to ASSERT this.
 	 */
 	if (cpu_map == NULL &&
 	    !acpica_get_devcfg_feature(ACPI_DEVCFG_CPU)) {
@@ -2050,6 +2079,7 @@
 	}
 
 	mutex_enter(&cpu_map_lock);
+	cpu_map_called = 1;
 	for (i = 0; i < cpu_map_count; i++) {
 		if (cpu_map[i]->cpu_id == cpuid) {
 			rc = AE_ALREADY_EXISTS;
--- a/usr/src/uts/intel/os/driver_aliases	Thu Aug 27 13:21:41 2009 -0700
+++ b/usr/src/uts/intel/os/driver_aliases	Thu Aug 27 16:35:32 2009 -0700
@@ -52,3 +52,4 @@
 amd_iommu "pci1002,5a23"
 isa "pciclass,060100"
 hme "pci108e,1001"
+acpinex "acpivirtnex"
--- a/usr/src/uts/intel/os/name_to_major	Thu Aug 27 13:21:41 2009 -0700
+++ b/usr/src/uts/intel/os/name_to_major	Thu Aug 27 16:35:32 2009 -0700
@@ -155,3 +155,4 @@
 ipnet 261
 intel_nhm 262
 simnet 263
+acpinex 264