From patchwork Sat Nov 3 16:07:45 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Liu X-Patchwork-Id: 1692681 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 834873FDD1 for ; Sat, 3 Nov 2012 16:08:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756989Ab2KCQIi (ORCPT ); Sat, 3 Nov 2012 12:08:38 -0400 Received: from mail-da0-f46.google.com ([209.85.210.46]:53387 "EHLO mail-da0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756548Ab2KCQIg (ORCPT ); Sat, 3 Nov 2012 12:08:36 -0400 Received: by mail-da0-f46.google.com with SMTP id n41so2064309dak.19 for ; Sat, 03 Nov 2012 09:08:36 -0700 (PDT) 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=FHKwTxZVWFKXZuydmCaMtql0Td0XNoynAhg1EXY2aKk=; b=HA9bGVnYt/jL1aFl4LSzyi2KRgpM2vnTeybXQMHQzuHngrIjnbFd53Cytt8cm1JAD3 PqNM0kh13Cy1Zzpy3oRXfjpCr9dPwhdyXt6IpfI6Wv+FjtRGSO9yTAw61M3dN2i5cl/F f0aqWSdFfQrP8LYOOae8hFTRGyu7zMU4RU43ZLqjnuAtzNhYN1WkqTDDkVeUIOKEvUVm OsFl3wEJHYUyo9q9bvK7WWQYa2yUJfU8VTvsnS9nfMSFwy9lbz5GOgXjmmouSwMcmDXr zFAl7MkZEFAO35j8GcVkDOWAcCqml+gzAz/TEihAskRc/vBtVUqZjY+A27iHzjOguquS 9iNw== Received: by 10.68.232.2 with SMTP id tk2mr16513000pbc.92.1351958916235; Sat, 03 Nov 2012 09:08:36 -0700 (PDT) Received: from localhost.localdomain ([120.196.98.117]) by mx.google.com with ESMTPS id oi2sm7561234pbb.62.2012.11.03.09.08.23 (version=TLSv1/SSLv3 cipher=OTHER); Sat, 03 Nov 2012 09:08:28 -0700 (PDT) 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 part1 4/4] ACPIHP: implement a fake ACPI system device hotplug slot enumerator Date: Sun, 4 Nov 2012 00:07:45 +0800 Message-Id: <1351958865-24394-5-git-send-email-jiang.liu@huawei.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1351958865-24394-1-git-send-email-jiang.liu@huawei.com> References: <1351958865-24394-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 This patch implements a fake ACPI system device hotplug slot enumerator, which could be used to test and verify hotplug logic on platforms with hardware hotplug capabilities. The fake slot enumerator will be enabled by passing module parameter "fake_slot=value". The encoding of "value" is: 0x1: fake ACPI CONTAINER device as hotplug slot 0x2: fake ACPI memory device as hotplug slot 0x4: fake ACPI Processor object or Processor device as hotplug slot 0x8: fake ACPI PCI host bridge device as hotplug slot. Signed-off-by: Jiang Liu --- drivers/acpi/Kconfig | 10 +++ drivers/acpi/hotplug/Makefile | 1 + drivers/acpi/hotplug/acpihp.h | 3 + drivers/acpi/hotplug/slot.c | 3 + drivers/acpi/hotplug/slot_fake.c | 180 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 197 insertions(+) create mode 100644 drivers/acpi/hotplug/slot_fake.c diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index af0aaf6..4d15b49 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -353,6 +353,16 @@ config ACPI_HOTPLUG_SLOT To compile this driver as a module, choose M here: the module will be called acpihp_slot. +config ACPI_HOTPLUG_SLOT_FAKE + bool "Fake Hotplug Slots" + depends on ACPI_HOTPLUG_SLOT + default n + help + This options enables a method to fake system device hotplug slots + on hardware platforms without dynamic reconfiguration capabilities. + + Pass parameter "fake_slot=0xf" to enable this function. + 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 5420ae7..c19b350 100644 --- a/drivers/acpi/hotplug/Makefile +++ b/drivers/acpi/hotplug/Makefile @@ -8,3 +8,4 @@ acpihp-y = core.o obj-$(CONFIG_ACPI_HOTPLUG_SLOT) += acpihp_slot.o acpihp_slot-y = slot.o acpihp_slot-y += slot_ej0.o +acpihp_slot-$(CONFIG_ACPI_HOTPLUG_SLOT_FAKE) += slot_fake.o diff --git a/drivers/acpi/hotplug/acpihp.h b/drivers/acpi/hotplug/acpihp.h index 278c8c2..7c49eab 100644 --- a/drivers/acpi/hotplug/acpihp.h +++ b/drivers/acpi/hotplug/acpihp.h @@ -29,5 +29,8 @@ extern struct acpi_device *acpi_root; extern struct acpihp_slot_ops acpihp_slot_ej0; +#ifdef CONFIG_ACPI_HOTPLUG_SLOT_FAKE +extern struct acpihp_slot_ops acpihp_slot_fake; +#endif #endif diff --git a/drivers/acpi/hotplug/slot.c b/drivers/acpi/hotplug/slot.c index e5861fc..b72523d 100644 --- a/drivers/acpi/hotplug/slot.c +++ b/drivers/acpi/hotplug/slot.c @@ -44,6 +44,9 @@ static struct acpihp_slot_ops *slot_ops_curr; */ static struct acpihp_slot_ops *slot_ops_array[] = { &acpihp_slot_ej0, +#ifdef CONFIG_ACPI_HOTPLUG_SLOT_FAKE + &acpihp_slot_fake, +#endif NULL }; diff --git a/drivers/acpi/hotplug/slot_fake.c b/drivers/acpi/hotplug/slot_fake.c new file mode 100644 index 0000000..e70243a --- /dev/null +++ b/drivers/acpi/hotplug/slot_fake.c @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2012 Huawei Tech. Co., Ltd. + * Copyright (C) 2012 Jiang Liu + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include "acpihp.h" + +struct acpihp_slot_fake_data { + bool enabled; +}; + +/* + * Encoding of the fake_slot parameter: + * 0x1: fake ACPI CONTAINER device as hotplug slot + * 0x2: fake ACPI memory device as hotplug slot + * 0x4: fake ACPI Processor object or Processor device as hotplug slot + * 0x8: fake ACPI PCI host bridge device as hotplug slot. + * The above encoding must be kept in consistence with definition of + * 'enum acpihp_dev_type'. + */ +int acpihp_fake_slot; +module_param_named(fake_slot, acpihp_fake_slot, int, S_IRUGO); +MODULE_PARM_DESC(fake_slot, "fake ACPI hotplug slots"); + +static acpi_status acpihp_slot_fake_init(void) +{ + return acpihp_fake_slot ? AE_OK : AE_ERROR; +} + +static acpi_status +acpihp_slot_fake_check(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + int *valid = (int *)rv; + enum acpihp_dev_type type; + + if (!acpihp_dev_get_type(handle, &type)) { + switch (type) { + case ACPIHP_DEV_TYPE_CPU: + case ACPIHP_DEV_TYPE_MEM: + case ACPIHP_DEV_TYPE_HOST_BRIDGE: + *valid = 1; + return AE_CTRL_TERMINATE; + default: + break; + } + } + + return AE_OK; +} + +static acpi_status acpihp_slot_fake_capable(acpi_handle handle) +{ + int valid = 0; + acpi_status rc; + unsigned long long sta; + enum acpihp_dev_type type; + + /* Only care about CPU, memory, PCI host bridge and CONTAINER */ + if (acpihp_dev_get_type(handle, &type)) + return AE_ERROR; + if (type == ACPIHP_DEV_TYPE_CPU || type == ACPIHP_DEV_TYPE_MEM || + type == ACPIHP_DEV_TYPE_HOST_BRIDGE) { + if (acpihp_fake_slot & (1 << (type - 1))) + valid = 1; + } else if (type == ACPIHP_DEV_TYPE_CONTAINER && + acpihp_fake_slot & (1 << (type - 1))) { + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, + ACPI_UINT32_MAX, acpihp_slot_fake_check, + NULL, NULL, (void **)&valid); + acpi_walk_namespace(ACPI_TYPE_PROCESSOR, handle, + ACPI_UINT32_MAX, acpihp_slot_fake_check, + NULL, NULL, (void **)&valid); + } + if (valid == 0) + return AE_ERROR; + + /* Check whether device is present and enabled. */ + rc = acpi_evaluate_integer(handle, "_STA", NULL, &sta); + if (rc == AE_NOT_FOUND) + sta = ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED; + else if (ACPI_FAILURE(rc)) + sta = 0; + else if (sta & ACPI_STA_DEVICE_FUNCTIONING) + sta |= ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED; + if (!(sta & ACPI_STA_DEVICE_PRESENT) || + !(sta & ACPI_STA_DEVICE_ENABLED)) + return AE_ERROR; + + return AE_OK; +} + +static acpi_status acpihp_slot_fake_create(struct acpihp_slot *slot) +{ + struct acpihp_slot_fake_data *data; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return AE_ERROR; + + data->enabled = true; + slot->slot_data = data; + slot->capabilities = ACPIHP_SLOT_CAP_POWERON | + ACPIHP_SLOT_CAP_POWEROFF | + ACPIHP_SLOT_CAP_ONLINE | + ACPIHP_SLOT_CAP_OFFLINE; + + return AE_OK; +} + +static void acpihp_slot_fake_destroy(struct acpihp_slot *slot) +{ + struct acpihp_slot_fake_data *data = slot->slot_data; + + slot->slot_data = NULL; + kfree(data); +} + +static acpi_status +acpihp_slot_fake_get_status(struct acpihp_slot *slot, u64 *status) +{ + struct acpihp_slot_fake_data *data = slot->slot_data; + + if (data->enabled) + *status = ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | + ACPI_STA_DEVICE_FUNCTIONING; + else + *status = ACPI_STA_DEVICE_PRESENT; + + return AE_OK; +} + +static acpi_status acpihp_slot_fake_poweron(struct acpihp_slot *slot) +{ + struct acpihp_slot_fake_data *data = slot->slot_data; + + data->enabled = true; + + return AE_OK; +} + +static acpi_status acpihp_slot_fake_poweroff(struct acpihp_slot *slot) +{ + struct acpihp_slot_fake_data *data = slot->slot_data; + + data->enabled = false; + + return AE_OK; +} + +struct acpihp_slot_ops acpihp_slot_fake = { + .owner = THIS_MODULE, + .desc = "Fake Hotplug Slot Enumerator for Testing", + .init = acpihp_slot_fake_init, + .check = acpihp_slot_fake_capable, + .create = acpihp_slot_fake_create, + .destroy = acpihp_slot_fake_destroy, + .poweron = acpihp_slot_fake_poweron, + .poweroff = acpihp_slot_fake_poweroff, + .get_status = acpihp_slot_fake_get_status, +};