From patchwork Fri Jul 8 16:13:09 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 9221295 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 4644560467 for ; Fri, 8 Jul 2016 16:14:52 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 37F4922638 for ; Fri, 8 Jul 2016 16:14:52 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2A79D23B23; Fri, 8 Jul 2016 16:14:52 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5DAC022638 for ; Fri, 8 Jul 2016 16:14:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932721AbcGHQO0 (ORCPT ); Fri, 8 Jul 2016 12:14:26 -0400 Received: from mail-wm0-f65.google.com ([74.125.82.65]:36512 "EHLO mail-wm0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932566AbcGHQOC (ORCPT ); Fri, 8 Jul 2016 12:14:02 -0400 Received: by mail-wm0-f65.google.com with SMTP id x83so7844077wma.3; Fri, 08 Jul 2016 09:14:00 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=ni/u14qZvCMOVdLGoc7CRIoHf24xxwarHKabp+o5VI8=; b=Wx7ICdJcImTTnp0VSmr3lQ9G6bXPi5jEA8GIduVMpVseQcNuRw82q6IxR1TuhvI2Ta LgsSoposIqUfaAN9wfcZZSr7mKoHtFBIYaxWsEVAXAG8YZP22TdAhJy0odHi3IgVTmaf YXvUsgS96WkmbYe5UlnYT4gQQ4kqzG0pRrlZ1z7gY8zA5jG92nQMsiqdlvlTAqNCaBM4 YSLn5S7Uj5QHOZlPCZAq61VJ4fuO9iaksTvGVhuuf93mCQO3FJo1HANQ8F2r9KTW6hte dyzEp+AzmLwhFb1RaIIcdxaEQXCBZemx2Gn4f9WpFGA9+so8S/vlrWjq/q3yDGDVrJUy jJRA== X-Gm-Message-State: ALyK8tKYWBudmygnK7PTuA4j/3QodK+Mgz3ea4CxZBlfeSUwI2QWIHYmWQ/cMVA2GYxC1Q== X-Received: by 10.28.226.130 with SMTP id z124mr4375554wmg.82.1467994439683; Fri, 08 Jul 2016 09:13:59 -0700 (PDT) Received: from localhost.localdomain ([109.98.36.115]) by smtp.gmail.com with ESMTPSA id t3sm3726508wmf.6.2016.07.08.09.13.58 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 08 Jul 2016 09:13:59 -0700 (PDT) From: Octavian Purdila To: "Rafael J . Wysocki" Cc: linux-acpi@vger.kernel.org, linux-efi@vger.kernel.org, linux-i2c@vger.kernel.org, linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org, leonard.crestez@intel.com, Octavian Purdila Subject: [PATCH v7 3/8] acpi: add support for ACPI reconfiguration notifiers Date: Fri, 8 Jul 2016 19:13:09 +0300 Message-Id: <1467994394-23983-4-git-send-email-octavian.purdila@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1467994394-23983-1-git-send-email-octavian.purdila@intel.com> References: <1467994394-23983-1-git-send-email-octavian.purdila@intel.com> Sender: linux-spi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-spi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add support for ACPI reconfiguration notifiers to allow subsystems to react to changes in the ACPI tables that happen after the initial enumeration. This is similar with the way dynamic device tree notifications work. The reconfigure notifications supported for now are device add and device remove. Since ACPICA allows only one table notification handler, this patch makes the table notifier function generic and moves it out of the sysfs specific code. Signed-off-by: Octavian Purdila Reviewed-by: Mika Westerberg --- drivers/acpi/bus.c | 9 +++++++ drivers/acpi/internal.h | 3 +++ drivers/acpi/scan.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++- drivers/acpi/sysfs.c | 6 ++--- include/linux/acpi.h | 18 +++++++++++++ 5 files changed, 99 insertions(+), 5 deletions(-) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 262ca31..97e270e 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -990,6 +990,13 @@ void __init acpi_subsystem_init(void) } } +static acpi_status acpi_bus_table_handler(u32 event, void *table, void *context) +{ + acpi_scan_table_handler(event, table, context); + + return acpi_sysfs_table_handler(event, table, context); +} + static int __init acpi_bus_init(void) { int result; @@ -1043,6 +1050,8 @@ static int __init acpi_bus_init(void) * _PDC control method may load dynamic SSDT tables, * and we need to install the table handler before that. */ + status = acpi_install_table_handler(acpi_bus_table_handler, NULL); + acpi_sysfs_init(); acpi_early_processor_set_pdc(); diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 27cc7fe..940218f 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -87,6 +87,9 @@ bool acpi_queue_hotplug_work(struct work_struct *work); void acpi_device_hotplug(struct acpi_device *adev, u32 src); bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent); +acpi_status acpi_sysfs_table_handler(u32 event, void *table, void *context); +void acpi_scan_table_handler(u32 event, void *table, void *context); + /* -------------------------------------------------------------------------- Device Node Initialization / Removal -------------------------------------------------------------------------- */ diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index f80f8a7..405056b 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -494,6 +494,8 @@ static void acpi_device_del(struct acpi_device *device) device_del(&device->dev); } +static BLOCKING_NOTIFIER_HEAD(acpi_reconfig_chain); + static LIST_HEAD(acpi_device_del_list); static DEFINE_MUTEX(acpi_device_del_lock); @@ -514,6 +516,9 @@ static void acpi_device_del_work_fn(struct work_struct *work_not_used) mutex_unlock(&acpi_device_del_lock); + blocking_notifier_call_chain(&acpi_reconfig_chain, + ACPI_RECONFIG_DEVICE_REMOVE, adev); + acpi_device_del(adev); /* * Drop references to all power resources that might have been @@ -1676,7 +1681,7 @@ static void acpi_default_enumeration(struct acpi_device *device) bool is_spi_i2c_slave = false; /* - * Do not enemerate SPI/I2C slaves as they will be enuerated by their + * Do not enumerate SPI/I2C slaves as they will be enumerated by their * respective parents. */ INIT_LIST_HEAD(&resource_list); @@ -1686,6 +1691,9 @@ static void acpi_default_enumeration(struct acpi_device *device) if (!is_spi_i2c_slave) { acpi_create_platform_device(device); acpi_device_set_enumerated(device); + } else { + blocking_notifier_call_chain(&acpi_reconfig_chain, + ACPI_RECONFIG_DEVICE_ADD, device); } } @@ -1917,6 +1925,8 @@ static int acpi_bus_scan_fixed(void) return result < 0 ? result : 0; } +static bool acpi_scan_initialized; + int __init acpi_scan_init(void) { int result; @@ -1961,6 +1971,8 @@ int __init acpi_scan_init(void) acpi_update_all_gpes(); + acpi_scan_initialized = true; + out: mutex_unlock(&acpi_scan_lock); return result; @@ -2004,3 +2016,57 @@ int __init __acpi_probe_device_table(struct acpi_probe_entry *ap_head, int nr) return count; } + +struct acpi_table_events_work { + struct work_struct work; + void *table; + u32 event; +}; + +static void acpi_table_events_fn(struct work_struct *work) +{ + struct acpi_table_events_work *tew; + + tew = container_of(work, struct acpi_table_events_work, work); + + if (tew->event == ACPI_TABLE_EVENT_LOAD) { + acpi_scan_lock_acquire(); + acpi_bus_scan(ACPI_ROOT_OBJECT); + acpi_scan_lock_release(); + } + + kfree(tew); +} + +void acpi_scan_table_handler(u32 event, void *table, void *context) +{ + struct acpi_table_events_work *tew; + + if (!acpi_scan_initialized) + return; + + if (event != ACPI_TABLE_EVENT_LOAD) + return; + + tew = kmalloc(sizeof(*tew), GFP_KERNEL); + if (!tew) + return; + + INIT_WORK(&tew->work, acpi_table_events_fn); + tew->table = table; + tew->event = event; + + schedule_work(&tew->work); +} + +int acpi_reconfig_notifier_register(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&acpi_reconfig_chain, nb); +} +EXPORT_SYMBOL(acpi_reconfig_notifier_register); + +int acpi_reconfig_notifier_unregister(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&acpi_reconfig_chain, nb); +} +EXPORT_SYMBOL(acpi_reconfig_notifier_unregister); diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index 4b3a9e2..358165e 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -378,8 +378,7 @@ static void acpi_table_attr_init(struct acpi_table_attr *table_attr, return; } -static acpi_status -acpi_sysfs_table_handler(u32 event, void *table, void *context) +acpi_status acpi_sysfs_table_handler(u32 event, void *table, void *context) { struct acpi_table_attr *table_attr; @@ -452,9 +451,8 @@ static int acpi_tables_sysfs_init(void) kobject_uevent(tables_kobj, KOBJ_ADD); kobject_uevent(dynamic_tables_kobj, KOBJ_ADD); - status = acpi_install_table_handler(acpi_sysfs_table_handler, NULL); - return ACPI_FAILURE(status) ? -EINVAL : 0; + return 0; err_dynamic_tables: kobject_put(tables_kobj); err: diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 7089e99..ac93253 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -542,6 +542,14 @@ static inline void acpi_device_clear_enumerated(struct acpi_device *adev) adev->flags.visited = false; } +enum acpi_reconfig_event { + ACPI_RECONFIG_DEVICE_ADD = 0, + ACPI_RECONFIG_DEVICE_REMOVE, +}; + +int acpi_reconfig_notifier_register(struct notifier_block *nb); +int acpi_reconfig_notifier_unregister(struct notifier_block *nb); + #else /* !CONFIG_ACPI */ #define acpi_disabled 1 @@ -696,6 +704,16 @@ static inline void acpi_device_clear_enumerated(struct acpi_device *adev) { } +static inline int acpi_reconfig_notifier_register(struct notifier_block *nb) +{ + return -EINVAL; +} + +static inline int acpi_reconfig_notifier_unregister(struct notifier_block *nb) +{ + return -EINVAL; +} + #endif /* !CONFIG_ACPI */ #ifdef CONFIG_ACPI