Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753276Ab2HDMPE (ORCPT ); Sat, 4 Aug 2012 08:15:04 -0400 Received: from szxga02-in.huawei.com ([119.145.14.65]:20753 "EHLO szxga02-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752712Ab2HDMOw (ORCPT ); Sat, 4 Aug 2012 08:14:52 -0400 From: Jiang Liu To: Yinghai Lu , Yasuaki Ishimatsu , Kenji Kaneshige , Wen Congyang , Tang Chen , Taku Izumi CC: Jiang Liu , Tony Luck , Huang Ying , Bob Moore , Len Brown , "Srivatsa S. Bhat" , Bjorn Helgaas , , , , Hanjun Guo , Jiang Liu Subject: [RFC PATCH v2 06/16] ACPIHP: group devices connecting to a hotplug slot according to device types Date: Sat, 4 Aug 2012 20:13:53 +0800 Message-ID: <1344082443-4608-7-git-send-email-jiang.liu@huawei.com> X-Mailer: git-send-email 1.7.11.msysgit.1 In-Reply-To: <1344082443-4608-1-git-send-email-jiang.liu@huawei.com> References: <1344082443-4608-1-git-send-email-jiang.liu@huawei.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [10.108.108.229] X-CFilter-Loop: Reflected Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 6552 Lines: 217 From: Jiang Liu ACPI devices connecting to an ACPI hotplug slot are divided into groups according to device types. Those devices will be configured/unconfigured in order of device types when hot-adding/hot-removing system devices. For example, when hot-adding a computer node with CPUs, memory, PCI host bridges, IOAPICs, the order optimized for performance should be: memory -> CPU -> IOAPIC -> PCI host bridge. Signed-off-by: Hanjun Guo Signed-off-by: Jiang Liu Signed-off-by: Jiang Liu --- drivers/acpi/hotplug/core.c | 113 +++++++++++++++++++++++++++++++++++++++++++ include/acpi/acpi_hotplug.h | 27 +++++++++++ 2 files changed, 140 insertions(+) diff --git a/drivers/acpi/hotplug/core.c b/drivers/acpi/hotplug/core.c index 6fac499..14b3d61 100644 --- a/drivers/acpi/hotplug/core.c +++ b/drivers/acpi/hotplug/core.c @@ -115,6 +115,23 @@ static char *acpihp_dev_ioapic_ids[] = { NULL }; +static void acpihp_dev_node_get(struct klist_node *lp) +{ + struct acpihp_dev_node *dp; + + dp = container_of(lp, struct acpihp_dev_node, node); + get_device(dp->dev); +} + +static void acpihp_dev_node_put(struct klist_node *lp) +{ + struct acpihp_dev_node *dp; + + dp = container_of(lp, struct acpihp_dev_node, node); + put_device(dp->dev); + kfree(dp); +} + static void acpihp_slot_release(struct device *dev) { struct acpihp_slot *slot = to_acpihp_slot(dev); @@ -134,6 +151,7 @@ static void acpihp_slot_release(struct device *dev) struct acpihp_slot *acpihp_create_slot(acpi_handle handle, char *name) { + int i; struct acpihp_slot *slot; if (name == NULL) { @@ -154,6 +172,9 @@ struct acpihp_slot *acpihp_create_slot(acpi_handle handle, char *name) INIT_LIST_HEAD(&slot->slot_list); INIT_LIST_HEAD(&slot->drvdata_list); INIT_LIST_HEAD(&slot->slot_id_list); + for (i = ACPIHP_DEV_TYPE_UNKNOWN; i < ACPIHP_DEV_TYPE_MAX; i++) + klist_init(&slot->dev_lists[i], + &acpihp_dev_node_get, &acpihp_dev_node_put); strncpy(slot->name, name, sizeof(slot->name) - 1); mutex_init(&slot->slot_mutex); @@ -433,6 +454,98 @@ acpi_status acpihp_slot_poweroff(struct acpihp_slot *slot) } EXPORT_SYMBOL_GPL(acpihp_slot_poweroff); +/* Insert a device onto a hotplug slot's device klist. */ +int acpihp_slot_add_device(struct acpihp_slot *slot, enum acpihp_dev_type type, + enum acpihp_dev_state state, struct device *dev) +{ + struct acpihp_dev_node *np; + + if (type < ACPIHP_DEV_TYPE_UNKNOWN || type >= ACPIHP_DEV_TYPE_MAX) { + ACPIHP_DEBUG("device type %d is invalid.\n", type); + return -EINVAL; + } else if (slot == NULL) { + ACPIHP_DEBUG("invalid parameter, slot is NULL.\n"); + return -EINVAL; + } else if (dev == NULL) { + ACPIHP_DEBUG("invalid parameter, dev is NULL.\n"); + return -EINVAL; + } + + np = kzalloc(sizeof(*np), GFP_KERNEL); + if (np == NULL) + return -ENOMEM; + + np->dev = dev; + np->state = state; + mutex_init(&np->lock); + klist_add_tail(&np->node, &slot->dev_lists[type]); + ACPIHP_DEBUG("add device %s to slot %s.\n", + dev_name(dev), slot->name); + + return 0; +} +EXPORT_SYMBOL_GPL(acpihp_slot_add_device); + +/* Remove a device from a hotplug slot's device klist. */ +int acpihp_slot_remove_device(struct acpihp_slot *slot, + enum acpihp_dev_type type, struct device *dev) +{ + int ret = -ENOENT; + struct klist_iter iter; + struct klist_node *ip; + struct acpihp_dev_node *np; + + if (type < ACPIHP_DEV_TYPE_UNKNOWN || type >= ACPIHP_DEV_TYPE_MAX) { + ACPIHP_DEBUG("device type %d is invalid.\n", type); + return -EINVAL; + } else if (slot == NULL) { + ACPIHP_DEBUG("invalid parameter, slot is NULL.\n"); + return -EINVAL; + } else if (dev == NULL) { + ACPIHP_DEBUG("invalid parameter, dev is NULL.\n"); + return -EINVAL; + } + + klist_iter_init(&slot->dev_lists[type], &iter); + while ((ip = klist_next(&iter)) != NULL) { + np = container_of(ip, struct acpihp_dev_node, node); + if (np->dev == dev) { + ACPIHP_DEBUG("remove device %s from slot %s.\n", + dev_name(dev), slot->name); + klist_del(&np->node); + ret = 0; + break; + } + } + klist_iter_exit(&iter); + + return ret; +} +EXPORT_SYMBOL_GPL(acpihp_slot_remove_device); + +/* Remove all devices from the klist */ +int acpihp_remove_device_list(struct klist *dev_list) +{ + struct klist_iter iter; + struct klist_node *ip; + struct acpihp_dev_node *np; + + if (dev_list == NULL) { + ACPIHP_DEBUG("invalid parameter, dev_list is NULL.\n"); + return -EINVAL; + } + + klist_iter_init(dev_list, &iter); + while ((ip = klist_next(&iter)) != NULL) { + np = container_of(ip, struct acpihp_dev_node, node); + klist_del(&np->node); + } + klist_iter_exit(&iter); + + return 0; +} +EXPORT_SYMBOL_GPL(acpihp_remove_device_list); + /* SYSFS interfaces */ static ssize_t acpihp_slot_object_show(struct device *d, struct device_attribute *attr, char *buf) diff --git a/include/acpi/acpi_hotplug.h b/include/acpi/acpi_hotplug.h index b81d934..cd8dd99 100644 --- a/include/acpi/acpi_hotplug.h +++ b/include/acpi/acpi_hotplug.h @@ -48,6 +48,24 @@ enum acpihp_dev_type { ACPIHP_DEV_TYPE_MAX }; +enum acpihp_dev_state { + DEVICE_STATE_UNKOWN = 0x00, + DEVICE_STATE_CONNECTED, + DEVICE_STATE_PRE_CONFIGURE, + DEVICE_STATE_CONFIGURED, + DEVICE_STATE_PRE_RELEASE, + DEVICE_STATE_RELEASED, + DEVICE_STATE_PRE_UNCONFIGURE, + DEVICE_STATE_MAX +}; + +struct acpihp_dev_node { + struct device *dev; + enum acpihp_dev_state state; + struct mutex lock; + struct klist_node node; +}; + /* * ACPI hotplug slot is an abstraction of receptacles where a group of * system devices could be attached, just like PCI slot in PCI hotplug. @@ -190,6 +208,15 @@ typedef acpi_status (*acpihp_walk_device_cb)(struct acpi_device *acpi_device, extern int acpihp_walk_devices(acpi_handle handle, acpihp_walk_device_cb cb, void *argp); +extern int acpihp_slot_add_device(struct acpihp_slot *slot, + enum acpihp_dev_type type, + enum acpihp_dev_state state, + struct device *dev); +extern int acpihp_slot_remove_device(struct acpihp_slot *slot, + enum acpihp_dev_type type, + struct device *dev); +extern int acpihp_remove_device_list(struct klist *dev_list); + extern int acpihp_debug; #define ACPIHP_DEBUG(fmt, ...) \ -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/