From patchwork Sun Nov 4 12:50:04 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Liu X-Patchwork-Id: 197029 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id A47782C00B4 for ; Sun, 4 Nov 2012 23:50:57 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753337Ab2KDMut (ORCPT ); Sun, 4 Nov 2012 07:50:49 -0500 Received: from mail-pa0-f46.google.com ([209.85.220.46]:63072 "EHLO mail-pa0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753535Ab2KDMuk (ORCPT ); Sun, 4 Nov 2012 07:50:40 -0500 Received: by mail-pa0-f46.google.com with SMTP id hz1so3347088pad.19 for ; Sun, 04 Nov 2012 04:50:39 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; bh=KmiERtXY/5w9Xf0h/PcxBgUT0BVKkNtN++0d917c8Fw=; b=QMc1pyCA1iTuIct68ri3W7o+uiLloRBkQOeUtxtxTrJ6EWE+0vfz3ywfMy0mSIRmxh jErqf2xlocS34eFt3ZRHm+sjt9G4hcUVzATa2UcT67k0jW8oXFEC6Di6svkTf16x2S16 Mw+ZGJA0xFcNVfI26knvZrBUi+LCWSPB6B0FpTO5donz9Zvu8XpaQpHp6pSGZZ9kiZbn +Fm3bwsjWMHe2X70Wwfh9vWkzySomMuz50XQfv8XOZ4deSi4w5/bZm8Zpb2eDzDOA9dG ppe/Kk74YGtUBmucCc1abXJBT2qXOmXyv/NjwEmpto8juAE+78MuRlstiUxTD4V7fxa7 xmiQ== Received: by 10.68.217.104 with SMTP id ox8mr21987204pbc.35.1352033439755; Sun, 04 Nov 2012 04:50:39 -0800 (PST) Received: from localhost.localdomain ([120.196.98.117]) by mx.google.com with ESMTPS id a4sm8922768pax.12.2012.11.04.04.50.34 (version=TLSv1/SSLv3 cipher=OTHER); Sun, 04 Nov 2012 04:50:39 -0800 (PST) From: Jiang Liu To: "Rafael J . Wysocki" , Yinghai Lu , Tony Luck , Yasuaki Ishimatsu , Wen Congyang , Tang Chen , Taku Izumi , Bjorn Helgaas Cc: Jiang Liu , Kenji Kaneshige , Huang Ying , Bob Moore , Len Brown , "Srivatsa S . Bhat" , Yijing Wang , Hanjun Guo , Jiang Liu , linux-kernel@vger.kernel.org, linux-acpi@vger.kernel.org, linux-pci@vger.kernel.org, linux-mm@kvack.org Subject: [ACPIHP PATCH part2 02/13] ACPIHP: use klist to manage ACPI devices attached to a slot Date: Sun, 4 Nov 2012 20:50:04 +0800 Message-Id: <1352033415-5606-3-git-send-email-jiang.liu@huawei.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1352033415-5606-1-git-send-email-jiang.liu@huawei.com> References: <1352033415-5606-1-git-send-email-jiang.liu@huawei.com> Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org To achieve best performance for hot-adding and resolve dependencies when hot-removing, system devices should be configured/unconfigured in specific order. The optimal order for hot-adding should be "container -> memory -> CPU -> PCI host bridge" and it should be in reverse order for hot-removing. So classify system devices into groups according to types of devices, and use klist to manage devices belonging to the same group. Signed-off-by: Hanjun Guo Signed-off-by: Jiang Liu --- drivers/acpi/hotplug/core.c | 116 +++++++++++++++++++++++++++++++++++++++++++ include/acpi/acpi_hotplug.h | 26 ++++++++++ 2 files changed, 142 insertions(+) diff --git a/drivers/acpi/hotplug/core.c b/drivers/acpi/hotplug/core.c index c835a97..7ef8f9b 100644 --- a/drivers/acpi/hotplug/core.c +++ b/drivers/acpi/hotplug/core.c @@ -96,6 +96,23 @@ static char *acpihp_dev_pcihb_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); @@ -113,6 +130,7 @@ static void acpihp_slot_release(struct device *dev) */ struct acpihp_slot *acpihp_alloc_slot(acpi_handle handle, char *name) { + int i; struct acpihp_slot *slot; if (name && strlen(name) >= ACPIHP_SLOT_NAME_MAX_SIZE) { @@ -129,6 +147,9 @@ struct acpihp_slot *acpihp_alloc_slot(acpi_handle handle, char *name) slot->handle = handle; INIT_LIST_HEAD(&slot->slot_list); INIT_LIST_HEAD(&slot->drvdata_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); if (name) strncpy(slot->name, name, sizeof(slot->name) - 1); mutex_init(&slot->slot_mutex); @@ -387,6 +408,101 @@ acpi_status acpihp_slot_poweroff(struct acpihp_slot *slot) } EXPORT_SYMBOL_GPL(acpihp_slot_poweroff); +/* Insert an ACPI device onto a hotplug slot's device list. */ +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 (slot == NULL) { + ACPIHP_DEBUG("invalid parameter, slot is NULL.\n"); + return -EINVAL; + } else if (dev == NULL) { + ACPIHP_SLOT_DEBUG(slot, "invalid parameter, dev is NULL.\n"); + return -EINVAL; + } else if (type < ACPIHP_DEV_TYPE_UNKNOWN || + type >= ACPIHP_DEV_TYPE_MAX) { + ACPIHP_SLOT_DEBUG(slot, "device type %d is invalid.\n", type); + return -EINVAL; + } + + np = kzalloc(sizeof(*np), GFP_KERNEL); + if (np == NULL) { + ACPIHP_SLOT_WARN(slot, "fails to allocate memory.\n"); + return -ENOMEM; + } + + np->dev = dev; + np->state = state; + klist_add_tail(&np->node, &slot->dev_lists[type]); + ACPIHP_SLOT_DEBUG(slot, "add device %s to klist.\n", dev_name(dev)); + + return 0; +} +EXPORT_SYMBOL_GPL(acpihp_slot_add_device); + +/* Remove an ACPI device from a hotplug slot's device list. */ +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 (slot == NULL) { + ACPIHP_DEBUG("invalid parameter, slot is NULL.\n"); + return -EINVAL; + } else if (dev == NULL) { + ACPIHP_SLOT_DEBUG(slot, "invalid parameter, dev is NULL.\n"); + return -EINVAL; + } else if (type < ACPIHP_DEV_TYPE_UNKNOWN || + type >= ACPIHP_DEV_TYPE_MAX) { + ACPIHP_SLOT_DEBUG(slot, "device type %d is invalid.\n", type); + 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_SLOT_DEBUG(slot, + "remove device %s from klist.\n", + dev_name(dev)); + klist_del(&np->node); + ret = 0; + break; + } + } + klist_iter_exit(&iter); + + return ret; +} +EXPORT_SYMBOL_GPL(acpihp_slot_remove_device); + +/* Remove all ACPI devices from the list */ +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 d39dece..d733f7f 100644 --- a/include/acpi/acpi_hotplug.h +++ b/include/acpi/acpi_hotplug.h @@ -46,6 +46,23 @@ 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 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. @@ -198,6 +215,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_WARN(fmt, ...) \