From patchwork Sat Aug 4 12:13:58 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Liu X-Patchwork-Id: 1273321 X-Patchwork-Delegate: bhelgaas@google.com Return-Path: X-Original-To: patchwork-linux-pci@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork1.kernel.org (Postfix) with ESMTP id 5F7DE3FD2B for ; Sat, 4 Aug 2012 12:16:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752261Ab2HDMPx (ORCPT ); Sat, 4 Aug 2012 08:15:53 -0400 Received: from szxga01-in.huawei.com ([119.145.14.64]:17453 "EHLO szxga01-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753078Ab2HDMO6 (ORCPT ); Sat, 4 Aug 2012 08:14:58 -0400 Received: from 172.24.2.119 (EHLO szxeml202-edg.china.huawei.com) ([172.24.2.119]) by szxrg01-dlp.huawei.com (MOS 4.3.4-GA FastPath queued) with ESMTP id AMQ61476; Sat, 04 Aug 2012 20:14:38 +0800 (CST) Received: from SZXEML405-HUB.china.huawei.com (10.82.67.60) by szxeml202-edg.china.huawei.com (172.24.2.42) with Microsoft SMTP Server (TLS) id 14.1.323.3; Sat, 4 Aug 2012 20:14:23 +0800 Received: from localhost (10.108.108.229) by szxeml405-hub.china.huawei.com (10.82.67.60) with Microsoft SMTP Server id 14.1.323.3; Sat, 4 Aug 2012 20:14:28 +0800 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 , , , , Jiang Liu , Hanjun Guo Subject: [RFC PATCH v2 11/16] ACPIHP: analyse dependences among ACPI system device hotplug slots Date: Sat, 4 Aug 2012 20:13:58 +0800 Message-ID: <1344082443-4608-12-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 X-Originating-IP: [10.108.108.229] X-CFilter-Loop: Reflected Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org From: Jiang Liu Some ACPI hotplug slots may have dependencies on other ACPI hotplug slots. For example, if a hotpluggable memory board is connected to a hotpluggble physical processor, the physical processor must be powered on before powering the memory board on. We could get dependency relationships by analyze ACPI namespace topology and evaluate ACPI _EDL method. So this patch implements several functions to analyze dependencies among ACPI hotplug slots. Signed-off-by: Jiang Liu Signed-off-by: Hanjun Guo --- drivers/acpi/hotplug/Makefile | 1 + drivers/acpi/hotplug/acpihp_drv.h | 14 ++++ drivers/acpi/hotplug/dependency.c | 167 +++++++++++++++++++++++++++++++++++++ 3 files changed, 182 insertions(+) create mode 100644 drivers/acpi/hotplug/dependency.c diff --git a/drivers/acpi/hotplug/Makefile b/drivers/acpi/hotplug/Makefile index d69832f..8477c71 100644 --- a/drivers/acpi/hotplug/Makefile +++ b/drivers/acpi/hotplug/Makefile @@ -11,3 +11,4 @@ acpihp_enum-y += slot_enum_ej0.o obj-$(CONFIG_ACPI_HOTPLUG_DRIVER) += acpihp_drv.o acpihp_drv-y = drv_main.o +acpihp_drv-y += dependency.o diff --git a/drivers/acpi/hotplug/acpihp_drv.h b/drivers/acpi/hotplug/acpihp_drv.h index 18330f7..c4ff91c 100644 --- a/drivers/acpi/hotplug/acpihp_drv.h +++ b/drivers/acpi/hotplug/acpihp_drv.h @@ -53,10 +53,24 @@ struct acpihp_slot_drv { struct acpihp_cancel_context cancel_ctx; }; +struct acpihp_slot_dependency { + struct list_head node; + struct acpihp_slot *slot; + u32 opcodes; +}; + void acpihp_drv_get_data(struct acpihp_slot *slot, struct acpihp_slot_drv **data); int acpihp_drv_enumerate_devices(struct acpihp_slot *slot); void acpihp_drv_update_slot_state(struct acpihp_slot *slot); int acpihp_drv_update_slot_status(struct acpihp_slot *slot); +int acpihp_drv_add_slot_to_dependency_list(struct acpihp_slot *slot, + struct list_head *slot_list); +void acpihp_drv_destroy_dependency_list(struct list_head *slot_list); +int acpihp_drv_filter_dependency_list(struct list_head *old_head, + struct list_head *new_head, u32 opcode); +int acpihp_drv_generate_dependency_list(struct acpihp_slot *slot, + struct list_head *slot_list, enum acpihp_drv_cmd cmd); + #endif /* __ACPIHP_DRV_H__ */ diff --git a/drivers/acpi/hotplug/dependency.c b/drivers/acpi/hotplug/dependency.c new file mode 100644 index 0000000..d2d7dbb --- /dev/null +++ b/drivers/acpi/hotplug/dependency.c @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2011 Huawei Tech. Co., Ltd. + * Copyright (C) 2011 Jiang Liu + * Copyright (C) 2011 Hanjun Guo + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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 +#include +#include +#include +#include +#include +#include "acpihp_drv.h" + +/* Insert a slot into the dependency list at the head */ +int acpihp_drv_add_slot_to_dependency_list(struct acpihp_slot *slot, + struct list_head *slot_list) +{ + struct acpihp_slot_dependency *dep; + + list_for_each_entry(dep, slot_list, node) + if (dep->slot == slot) + return 0; + + dep = kzalloc(sizeof(*dep), GFP_KERNEL); + if (!dep) { + ACPIHP_DEBUG("fails to allocate memory for %s.\n", slot->name); + return -ENOMEM; + } + dep->slot = slot; + list_add(&dep->node, slot_list); + + return 0; +} + +static int acpihp_drv_get_online_dependency(struct acpihp_slot *slot, + struct list_head *slot_list) +{ + int ret = 0; + struct acpihp_slot *temp; + + for (temp = slot; temp && ret == 0; temp = temp->parent) + ret = acpihp_drv_add_slot_to_dependency_list(temp, slot_list); + + return ret; +} + +static int acpihp_drv_for_each_edl(struct acpihp_slot *slot, void *argp, + int(*cb)(struct device *dev, void *argp)) +{ + /* TODO */ + return 0; +} + +static int acpihp_drv_add_offline_dependency(struct device *dev, void *argp) +{ + int ret; + struct acpihp_slot *slot; + struct list_head *list = argp; + + slot = container_of(dev, struct acpihp_slot, dev); + ret = acpihp_drv_add_slot_to_dependency_list(slot, list); + if (!ret) + ret = device_for_each_child(&slot->dev, argp, + &acpihp_drv_add_offline_dependency); + if (!ret) + ret = acpihp_drv_for_each_edl(slot, argp, + &acpihp_drv_add_offline_dependency); + + return ret; +} + +static int acpihp_drv_get_offline_dependency(struct acpihp_slot *slot, + struct list_head *slot_list) +{ + return acpihp_drv_add_offline_dependency(&slot->dev, slot_list); +} + +int acpihp_drv_generate_dependency_list(struct acpihp_slot *slot, + struct list_head *slot_list, enum acpihp_drv_cmd cmd) +{ + int retval; + + switch (cmd) { + case ACPIHP_DRV_CMD_POWERON: + /* fall through */ + case ACPIHP_DRV_CMD_CONNECT: + /* fall through */ + case ACPIHP_DRV_CMD_CONFIGURE: + retval = acpihp_drv_get_online_dependency(slot, slot_list); + break; + + case ACPIHP_DRV_CMD_POWEROFF: + /* fall through */ + case ACPIHP_DRV_CMD_DISCONNECT: + /* fall through */ + case ACPIHP_DRV_CMD_UNCONFIGURE: + retval = acpihp_drv_get_offline_dependency(slot, slot_list); + break; + + default: + retval = -EINVAL; + break; + } + + return retval; +} + +/* + * Generate a new list with slots from the old list which need to + * execute a specific operation. + */ +int acpihp_drv_filter_dependency_list(struct list_head *old_head, + struct list_head *new_head, u32 opcode) +{ + struct acpihp_slot_dependency *old_dep, *new_dep; + + /* Initialize new list to empty */ + INIT_LIST_HEAD(new_head); + + list_for_each_entry(old_dep, old_head, node) { + /* Skip if the specified operation is not needed. */ + if (!(old_dep->opcodes & opcode)) + continue; + + new_dep = kzalloc(sizeof(*new_dep), GFP_KERNEL); + if (!new_dep) { + ACPIHP_DEBUG("fails to filter depend list.\n"); + acpihp_drv_destroy_dependency_list(new_head); + return -ENOMEM; + } + + new_dep->slot = old_dep->slot; + new_dep->opcodes = old_dep->opcodes; + list_add_tail(&new_dep->node, new_head); + } + + return 0; +} + +void acpihp_drv_destroy_dependency_list(struct list_head *slot_list) +{ + struct acpihp_slot_dependency *asd, *temp; + + list_for_each_entry_safe(asd, temp, slot_list, node) { + list_del(&asd->node); + kfree(asd); + } +}