diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index e457d31..711e18e 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -333,6 +333,17 @@ menuconfig ACPI_HOTPLUG
 	  If your hardware and firmware do not support adding or removing
 	  of system devices at runtime, you need not to enable this option.
 
+config ACPI_HOTPLUG_ENUM
+	tristate "ACPI Hotplug Slot Enumerator"
+	depends on ACPI_HOTPLUG
+	default y
+	help
+	  This driver enumerates ACPI hotplug slots for ACPI based system
+	  device hotplug.
+
+	  To compile this driver as a module, choose M here:
+	  the module will be called acpihp_enum.
+
 config ACPI_CONTAINER
 	tristate "Container and Module Devices (EXPERIMENTAL)"
 	depends on EXPERIMENTAL
diff --git a/drivers/acpi/hotplug/Makefile b/drivers/acpi/hotplug/Makefile
index 5e7790f..41c0da9 100644
--- a/drivers/acpi/hotplug/Makefile
+++ b/drivers/acpi/hotplug/Makefile
@@ -4,3 +4,6 @@
 
 obj-$(CONFIG_ACPI_HOTPLUG)			+= acpihp.o
 acpihp-y					= core.o
+
+obj-$(CONFIG_ACPI_HOTPLUG_ENUM)			+= acpihp_enum.o
+acpihp_enum-y					= slot_enum.o
diff --git a/drivers/acpi/hotplug/slot_enum.c b/drivers/acpi/hotplug/slot_enum.c
new file mode 100644
index 0000000..80396a3
--- /dev/null
+++ b/drivers/acpi/hotplug/slot_enum.c
@@ -0,0 +1,466 @@
+/*
+ * Copyright (C) 2011 Huawei Tech. Co., Ltd.
+ * Copyright (C) 2011 Jiang Liu <jiang.liu@huawei.com>
+ * Copyright (C) 2011 Gaohuai Han <hangaohuai@huawei.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <acpi/acpi.h>
+#include <acpi/acpi_hotplug.h>
+
+static LIST_HEAD(slot_list);
+static LIST_HEAD(slot_id_list);
+
+struct acpihp_slot_id {
+	struct list_head node;
+	unsigned long instance_id;
+	enum acpihp_slot_type type;
+};
+
+static struct acpihp_slot_ops *slot_ops_curr;
+
+/*
+ * Array of platform specific enumeration methods.
+ * Entries in the array should be sorted by descending priority order.
+ */
+static struct acpihp_slot_ops *slot_ops_array[] = {
+	NULL
+};
+
+static void acpihp_enum_cleanup_slots(void);
+
+static int __init acpihp_get_parent_slot(struct acpihp_slot *slot)
+{
+	acpi_handle handle, root_handle;
+	struct acpihp_slot *tmp;
+
+	slot->parent = NULL;
+	handle = slot->handle;
+	if (ACPI_FAILURE(acpi_get_handle(NULL, ACPI_NS_ROOT_PATH,
+			 &root_handle))) {
+		ACPIHP_WARN("fails to get ACPI root device.\n");
+		return -EINVAL;
+	}
+
+	do {
+		if (ACPI_FAILURE(acpi_get_parent(handle, &handle))) {
+			ACPIHP_DEBUG("fails to get parent device handle.\n");
+			return -ENODEV;
+		}
+		list_for_each_entry(tmp, &slot_list, slot_list)
+			if (tmp->handle == handle) {
+				slot->parent = tmp;
+				return 0;
+			}
+	} while (handle != root_handle);
+
+	return 0;
+}
+
+static int __init acpihp_get_slot_state(struct acpihp_slot *slot)
+{
+	unsigned long long sta;
+
+	/* An hotplug slot must implement _STA method. */
+	if (ACPI_FAILURE(acpi_evaluate_integer(slot->handle, METHOD_NAME__STA,
+					       NULL, &sta))) {
+		ACPIHP_DEBUG("fails to execute _STA method.\n");
+		return -EINVAL;
+	}
+
+	if (!(sta & ACPI_STA_DEVICE_PRESENT))
+		slot->state = ACPIHP_SLOT_STATE_ABSENT;
+	else if ((sta & ACPI_STA_DEVICE_ENABLED) ||
+		 (sta & ACPI_STA_DEVICE_FUNCTIONING))
+		slot->state = ACPIHP_SLOT_STATE_POWERED;
+	else
+		slot->state = ACPIHP_SLOT_STATE_PRESENT;
+
+	return 0;
+}
+
+static int __init acpihp_enum_create_slot(acpi_handle handle)
+{
+	struct acpihp_slot *slot;
+
+	slot = acpihp_create_slot(handle, "TEMP");
+	if (!slot) {
+		ACPIHP_DEBUG("fails to allocate memory for hotplug slot.\n");
+		return -ENOMEM;
+	}
+
+	slot->slot_ops = slot_ops_curr;
+
+	if (acpihp_get_parent_slot(slot))
+		goto out;
+	if (acpihp_get_slot_state(slot))
+		goto out;
+	if (ACPI_FAILURE(acpihp_slot_get_capabilities(slot,
+						      &slot->capabilities))) {
+		ACPIHP_DEBUG("fails to get slot capabilities.\n");
+		goto out;
+	}
+	if (ACPI_FAILURE(acpihp_mark_slot(handle, slot))) {
+		ACPIHP_DEBUG("fails to attach slot to ACPI device object.\n");
+		goto out;
+	}
+
+	list_add_tail(&slot->slot_list, &slot_list);
+
+	return 0;
+out:
+	acpihp_slot_put(slot);
+	return -EINVAL;
+}
+
+/*
+ * Scan hotplug slots for ACPI based system device hotplug.
+ * We only care about processor, memory, PCI host bridge and CONTAINER.
+ */
+static acpi_status __init acpihp_enum_scan_slot(acpi_handle handle, u32 lvl,
+						void *context, void **rv)
+{
+	enum acpihp_dev_type type;
+
+	if (acpihp_dev_get_type(handle, &type) ||
+	    type == ACPIHP_DEV_TYPE_UNKNOWN)
+		return AE_OK;
+
+	if (ACPI_SUCCESS(slot_ops_curr->check(handle)))
+		acpihp_enum_create_slot(handle);
+
+	/*
+	 * Don't scan hotplug slots under PCI host bridges, they should be
+	 * handled by acpiphp or pciehp drivers.
+	 */
+	if (type == ACPIHP_DEV_TYPE_HOST_BRIDGE)
+		return AE_CTRL_DEPTH;
+
+	return AE_OK;
+}
+
+/*
+ * Get types of child devices connected to this slot.
+ * We only care about CPU, memory, PCI host bridge and CONTAINER here.
+ * Values used here must be in consistence with acpihp_enum_get_slot_type().
+ */
+static acpi_status __init
+acpihp_enum_get_dev_type(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+	acpi_status status = AE_OK;
+	enum acpihp_dev_type type;
+	u32 *tp = (u32 *)rv;
+
+	if (!acpihp_dev_get_type(handle, &type)) {
+		switch (type) {
+		case ACPIHP_DEV_TYPE_CPU:
+			*tp |= 0x0001;
+			status = AE_CTRL_DEPTH;
+			break;
+		case ACPIHP_DEV_TYPE_MEM:
+			*tp |= 0x0002;
+			status = AE_CTRL_DEPTH;
+			break;
+		case ACPIHP_DEV_TYPE_HOST_BRIDGE:
+			*tp |= 0x0004;
+			status = AE_CTRL_DEPTH;
+			break;
+		case ACPIHP_DEV_TYPE_CONTAINER:
+			*tp |= 0x0008;
+			break;
+		default:
+			break;
+		}
+	}
+
+	return status;
+}
+
+/*
+ * Guess type of a hotplug slot according to child devices connecting to it.
+ */
+static enum acpihp_slot_type __init acpihp_enum_get_slot_type(u32 dev_types)
+{
+	BUG_ON(dev_types > 15);
+
+	switch (dev_types) {
+	case 0:
+		/* Generic CONTAINER */
+		return ACPIHP_SLOT_TYPE_COMMON;
+	case 1:
+		/* Physical processor with logical CPUs */
+		return ACPIHP_SLOT_TYPE_CPU;
+	case 2:
+		/* Memory board/box with memory devices */
+		return ACPIHP_SLOT_TYPE_MEM;
+	case 3:
+		/* Physical processor with CPUs and memory controllers */
+		return ACPIHP_SLOT_TYPE_CPU;
+	case 4:
+		/* IO eXtension board/box with IO host bridges */
+		return ACPIHP_SLOT_TYPE_IOX;
+	case 7:
+		/* Physical processor with CPUs, IO host bridges and MCs. */
+		return ACPIHP_SLOT_TYPE_CPU;
+	case 8:
+		/* Generic CONTAINER */
+		return ACPIHP_SLOT_TYPE_COMMON;
+	case 9:
+		/* System board with physical processors */
+		return ACPIHP_SLOT_TYPE_SYSTEM_BOARD;
+	case 11:
+		/* System board with physical processors and memory */
+		return ACPIHP_SLOT_TYPE_SYSTEM_BOARD;
+	case 15:
+		/* Node with processor, memory and IO host bridge */
+		return ACPIHP_SLOT_TYPE_NODE;
+	default:
+		return ACPIHP_SLOT_TYPE_UNKNOWN;
+	}
+}
+
+/*
+ * Guess type of a hotplug slot according to the device type of the
+ * corresponding ACPI object itself.
+ */
+static enum acpihp_slot_type __init
+acpihp_enum_check_slot_self(struct acpihp_slot *slot)
+{
+	enum acpihp_dev_type type;
+
+	if (acpihp_dev_get_type(slot->handle, &type))
+		return ACPIHP_SLOT_TYPE_UNKNOWN;
+
+	switch (type) {
+	case ACPIHP_DEV_TYPE_CPU:
+		/* Logical CPU used in virtualization environment */
+		return ACPIHP_SLOT_TYPE_CPU;
+	case ACPIHP_DEV_TYPE_MEM:
+		/* Memory board with single memory device */
+		return ACPIHP_SLOT_TYPE_MEM;
+	case ACPIHP_DEV_TYPE_HOST_BRIDGE:
+		/* IO eXtension board/box with single IO host bridge */
+		return ACPIHP_SLOT_TYPE_IOX;
+	default:
+		return ACPIHP_SLOT_TYPE_UNKNOWN;
+	}
+}
+
+static int __init acpihp_enum_generate_slot_name(struct acpihp_slot *slot)
+{
+	int found = 0;
+	struct list_head *list;
+	struct acpihp_slot_id *slot_id;
+	unsigned long long uid;
+
+	/* Respect firmware settings if _UID return an integer. */
+	if (ACPI_SUCCESS(acpi_evaluate_integer(slot->handle, METHOD_NAME__UID,
+					       NULL, &uid)))
+		goto set_name;
+
+	if (slot->parent)
+		list = &slot->parent->slot_id_list;
+	else
+		list = &slot_id_list;
+
+	list_for_each_entry(slot_id, list, node)
+		if (slot_id->type == slot->type) {
+			found = 1;
+			break;
+		}
+	if (!found) {
+		slot_id = kzalloc(sizeof(struct acpihp_slot_id), GFP_KERNEL);
+		if (!slot_id) {
+			ACPIHP_DEBUG("fails to allocate slot instance ID.\n");
+			return -ENOMEM;
+		}
+		slot_id->type = slot->type;
+		list_add_tail(&slot_id->node, list);
+	}
+
+	uid = slot_id->instance_id++;
+
+set_name:
+	snprintf(slot->name, sizeof(slot->name) - 1, "%s%02llx",
+		 acpihp_get_slot_type_name(slot->type), uid);
+	dev_set_name(&slot->dev, "%s", slot->name);
+
+	return 0;
+}
+
+/*
+ * Generate a meaningful name for the slot according to devices connecting
+ * to this slot
+ */
+static int __init acpihp_enum_rename_slot(struct acpihp_slot *slot)
+{
+	u32 child_types = 0;
+
+	slot->type = acpihp_enum_check_slot_self(slot);
+	if (slot->type == ACPIHP_SLOT_TYPE_UNKNOWN) {
+		acpi_walk_namespace(ACPI_TYPE_DEVICE, slot->handle,
+				ACPI_UINT32_MAX, acpihp_enum_get_dev_type,
+				NULL, NULL, (void **)&child_types);
+		acpi_walk_namespace(ACPI_TYPE_PROCESSOR, slot->handle,
+				ACPI_UINT32_MAX, acpihp_enum_get_dev_type,
+				NULL, NULL, (void **)&child_types);
+		slot->type = acpihp_enum_get_slot_type(child_types);
+	}
+
+	if (acpihp_enum_generate_slot_name(slot))
+		return -EINVAL;
+
+	return 0;
+}
+
+static void __init acpihp_enum_rename_and_register_slots(void)
+{
+	struct acpihp_slot *slot;
+
+	list_for_each_entry(slot, &slot_list, slot_list) {
+		/* generate a meaningful name for this slot */
+		if (acpihp_enum_rename_slot(slot))
+			continue;
+
+		if (acpihp_register_slot(slot))
+			ACPIHP_DEBUG("fails to register slot %s.\n",
+				     slot->name);
+	}
+}
+
+static int __init acpihp_enum_generate_slots(void)
+{
+	acpi_status status;
+
+	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+				     ACPI_UINT32_MAX, acpihp_enum_scan_slot,
+				     NULL, NULL, NULL);
+	if (!ACPI_SUCCESS(status))
+		goto out_err;
+
+	status = acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
+				     ACPI_UINT32_MAX, acpihp_enum_scan_slot,
+				     NULL, NULL, NULL);
+	if (!ACPI_SUCCESS(status))
+		goto out_err;
+
+	acpihp_enum_rename_and_register_slots();
+
+	return 0;
+
+out_err:
+	ACPIHP_DEBUG("fails to scan hotplug slots.\n");
+	acpihp_enum_cleanup_slots();
+
+	return -ENOTSUPP;
+}
+
+static void acpihp_enum_unregister_slots(void)
+{
+	struct acpihp_slot *slot, *tmp;
+	struct acpihp_slot_id *slot_id, *slot_id_safe;
+
+	list_for_each_entry_safe(slot, tmp, &slot_list, slot_list) {
+		acpihp_unregister_slot(slot);
+		list_del_init(&slot->slot_list);
+		acpihp_unmark_slot(slot->handle);
+		list_for_each_entry_safe(slot_id, slot_id_safe,
+					 &slot->slot_id_list, node) {
+			list_del(&slot_id->node);
+			kfree(slot_id);
+		}
+		acpihp_slot_put(slot);
+	}
+}
+
+static void acpihp_enum_cleanup_slots(void)
+{
+	struct acpihp_slot_id *slot_id, *tmp;
+
+	acpihp_enum_unregister_slots();
+	list_for_each_entry_safe(slot_id, tmp, &slot_id_list, node) {
+		list_del(&slot_id->node);
+		kfree(slot_id);
+	}
+}
+
+static int __init acpihp_enum_init(void)
+{
+	int i;
+	int retval;
+
+	/* probe for suitable enumerator. */
+	for (i = 0; slot_ops_array[i]; i++)
+		if (ACPI_SUCCESS(slot_ops_array[i]->init())) {
+			slot_ops_curr = slot_ops_array[i];
+			break;
+		}
+	if (slot_ops_curr == NULL) {
+		ACPIHP_DEBUG("no ACPI hotplug slot found.\n");
+		return -ENXIO;
+	}
+
+	retval = acpihp_register_class();
+	if (retval != 0) {
+		ACPIHP_DEBUG("fails to register ACPI hotplug slot class.\n");
+		goto out_fini;
+	}
+
+	retval = acpihp_enum_generate_slots();
+	if (retval != 0) {
+		ACPIHP_DEBUG("fails to enumerate ACPI hotplug slots.\n");
+		goto out_unregister_class;
+	}
+
+	/* Back out if no ACPI hotplug slot  found. */
+	if (list_empty(&slot_list)) {
+		ACPIHP_DEBUG("no ACPI hotplug slot found.\n");
+		retval = -ENODEV;
+		goto out_unregister_class;
+	}
+
+	return 0;
+
+out_unregister_class:
+	acpihp_unregister_class();
+out_fini:
+	slot_ops_curr->fini();
+	ACPIHP_DEBUG("fails to initialize hotplug slot enumerator.\n");
+
+	return retval;
+}
+
+static void __exit acpihp_enum_exit(void)
+{
+	acpihp_enum_cleanup_slots();
+	acpihp_unregister_class();
+	slot_ops_curr->fini();
+}
+
+module_init(acpihp_enum_init);
+module_exit(acpihp_enum_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Jiang Liu <jiang.liu@huawei.com>");
+MODULE_AUTHOR("Gaohuai Han <hangaohuai@huawei.com>");
