From 3b95bd160547f56a68aeb972c33ae9511e7a8380 Mon Sep 17 00:00:00 2001 From: Aleksey Makarov Date: Tue, 16 Feb 2016 15:52:38 +0300 Subject: ACPI: introduce a function to find the first physical device Factor out the code that finds the first physical device of a given ACPI device. It is used in several places. Signed-off-by: Aleksey Makarov Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_platform.c | 19 ++----------------- drivers/acpi/bus.c | 26 ++++++++++++++++++++------ drivers/acpi/internal.h | 1 + 3 files changed, 23 insertions(+), 23 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c index 296b7a14893a..c3af1088bf6b 100644 --- a/drivers/acpi/acpi_platform.c +++ b/drivers/acpi/acpi_platform.c @@ -43,7 +43,6 @@ static const struct acpi_device_id forbidden_id_list[] = { struct platform_device *acpi_create_platform_device(struct acpi_device *adev) { struct platform_device *pdev = NULL; - struct acpi_device *acpi_parent; struct platform_device_info pdevinfo; struct resource_entry *rentry; struct list_head resource_list; @@ -82,22 +81,8 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) * attached to it, that physical device should be the parent of the * platform device we are about to create. */ - pdevinfo.parent = NULL; - acpi_parent = adev->parent; - if (acpi_parent) { - struct acpi_device_physical_node *entry; - struct list_head *list; - - mutex_lock(&acpi_parent->physical_node_lock); - list = &acpi_parent->physical_node_list; - if (!list_empty(list)) { - entry = list_first_entry(list, - struct acpi_device_physical_node, - node); - pdevinfo.parent = entry->dev; - } - mutex_unlock(&acpi_parent->physical_node_lock); - } + pdevinfo.parent = adev->parent ? + acpi_get_first_physical_node(adev->parent) : NULL; pdevinfo.name = dev_name(&adev->dev); pdevinfo.id = -1; pdevinfo.res = resources; diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 891c42d1cd65..0e8567846f1a 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -479,24 +479,38 @@ static void acpi_device_remove_notify_handler(struct acpi_device *device) Device Matching -------------------------------------------------------------------------- */ -static struct acpi_device *acpi_primary_dev_companion(struct acpi_device *adev, - const struct device *dev) +/** + * acpi_get_first_physical_node - Get first physical node of an ACPI device + * @adev: ACPI device in question + * + * Return: First physical node of ACPI device @adev + */ +struct device *acpi_get_first_physical_node(struct acpi_device *adev) { struct mutex *physical_node_lock = &adev->physical_node_lock; + struct device *phys_dev; mutex_lock(physical_node_lock); if (list_empty(&adev->physical_node_list)) { - adev = NULL; + phys_dev = NULL; } else { const struct acpi_device_physical_node *node; node = list_first_entry(&adev->physical_node_list, struct acpi_device_physical_node, node); - if (node->dev != dev) - adev = NULL; + + phys_dev = node->dev; } mutex_unlock(physical_node_lock); - return adev; + return phys_dev; +} + +static struct acpi_device *acpi_primary_dev_companion(struct acpi_device *adev, + const struct device *dev) +{ + const struct device *phys_dev = acpi_get_first_physical_node(adev); + + return phys_dev && phys_dev == dev ? adev : NULL; } /** diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 1e6833a5cd44..8668891cb1fa 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -106,6 +106,7 @@ bool acpi_device_is_present(struct acpi_device *adev); bool acpi_device_is_battery(struct acpi_device *adev); bool acpi_device_is_first_physical_node(struct acpi_device *adev, const struct device *dev); +struct device *acpi_get_first_physical_node(struct acpi_device *adev); /* -------------------------------------------------------------------------- Device Matching and Notification -- cgit v1.2.3 From 6ce2e188a6ae339340d9bbf5bb0b81db20454353 Mon Sep 17 00:00:00 2001 From: Graeme Gregory Date: Wed, 20 Jan 2016 20:29:27 +0600 Subject: ACPI / scan: AMBA bus probing support On ARM64 some devices use the AMBA device and not the platform bus for probing so add support for this. Uses a dummy clock for apb_pclk as ACPI does not have a suitable clock representation and to keep the core AMBA bus code unchanged between probing methods. Acked-by: Russell King Signed-off-by: Graeme Gregory Signed-off-by: Aleksey Makarov Signed-off-by: Rafael J. Wysocki --- drivers/acpi/Makefile | 1 + drivers/acpi/acpi_amba.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/internal.h | 5 ++ drivers/acpi/scan.c | 1 + 4 files changed, 129 insertions(+) create mode 100644 drivers/acpi/acpi_amba.c (limited to 'drivers/acpi') diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index cb648a49543a..edeb2d1d99be 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -43,6 +43,7 @@ acpi-y += pci_root.o pci_link.o pci_irq.o acpi-y += acpi_lpss.o acpi_apd.o acpi-y += acpi_platform.o acpi-y += acpi_pnp.o +acpi-$(CONFIG_ARM_AMBA) += acpi_amba.o acpi-y += int340x_thermal.o acpi-y += power.o acpi-y += event.o diff --git a/drivers/acpi/acpi_amba.c b/drivers/acpi/acpi_amba.c new file mode 100644 index 000000000000..2a61b54ab968 --- /dev/null +++ b/drivers/acpi/acpi_amba.c @@ -0,0 +1,122 @@ + +/* + * ACPI support for platform bus type. + * + * Copyright (C) 2015, Linaro Ltd + * Author: Graeme Gregory + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" + +static const struct acpi_device_id amba_id_list[] = { + {"ARMH0061", 0}, /* PL061 GPIO Device */ + {"", 0}, +}; + +static void amba_register_dummy_clk(void) +{ + static struct clk *amba_dummy_clk; + + /* If clock already registered */ + if (amba_dummy_clk) + return; + + amba_dummy_clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, + CLK_IS_ROOT, 0); + clk_register_clkdev(amba_dummy_clk, "apb_pclk", NULL); +} + +static int amba_handler_attach(struct acpi_device *adev, + const struct acpi_device_id *id) +{ + struct amba_device *dev; + struct resource_entry *rentry; + struct list_head resource_list; + bool address_found = false; + int irq_no = 0; + int ret; + + /* If the ACPI node already has a physical device attached, skip it. */ + if (adev->physical_node_count) + return 0; + + dev = amba_device_alloc(dev_name(&adev->dev), 0, 0); + if (!dev) { + dev_err(&adev->dev, "%s(): amba_device_alloc() failed\n", + __func__); + return -ENOMEM; + } + + INIT_LIST_HEAD(&resource_list); + ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); + if (ret < 0) + goto err_free; + + list_for_each_entry(rentry, &resource_list, node) { + switch (resource_type(rentry->res)) { + case IORESOURCE_MEM: + if (!address_found) { + dev->res = *rentry->res; + address_found = true; + } + break; + case IORESOURCE_IRQ: + if (irq_no < AMBA_NR_IRQS) + dev->irq[irq_no++] = rentry->res->start; + break; + default: + dev_warn(&adev->dev, "Invalid resource\n"); + break; + } + } + + acpi_dev_free_resource_list(&resource_list); + + /* + * If the ACPI node has a parent and that parent has a physical device + * attached to it, that physical device should be the parent of + * the amba device we are about to create. + */ + if (adev->parent) + dev->dev.parent = acpi_get_first_physical_node(adev->parent); + + ACPI_COMPANION_SET(&dev->dev, adev); + + ret = amba_device_add(dev, &iomem_resource); + if (ret) { + dev_err(&adev->dev, "%s(): amba_device_add() failed (%d)\n", + __func__, ret); + goto err_free; + } + + return 1; + +err_free: + amba_device_put(dev); + return ret; +} + +static struct acpi_scan_handler amba_handler = { + .ids = amba_id_list, + .attach = amba_handler_attach, +}; + +void __init acpi_amba_init(void) +{ + amba_register_dummy_clk(); + acpi_scan_add_handler(&amba_handler); +} diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 8668891cb1fa..9860df04b7c2 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -29,6 +29,11 @@ void acpi_processor_init(void); void acpi_platform_init(void); void acpi_pnp_init(void); void acpi_int340x_thermal_init(void); +#ifdef CONFIG_ARM_AMBA +void acpi_amba_init(void); +#else +static inline void acpi_amba_init(void) {} +#endif int acpi_sysfs_init(void); void acpi_container_init(void); void acpi_memory_hotplug_init(void); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 407a3760e8de..5f28cf778349 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1930,6 +1930,7 @@ int __init acpi_scan_init(void) acpi_memory_hotplug_init(); acpi_pnp_init(); acpi_int340x_thermal_init(); + acpi_amba_init(); acpi_scan_add_handler(&generic_device_handler); -- cgit v1.2.3 From a543132ee04d1599a0abe913eaf43d1986021d24 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 2 Mar 2016 14:16:17 +0800 Subject: ACPI / OSL: Clean up initrd table override code This patch cleans up the initrd table override code by merging redundant logics and re-ordering code blocks. No functional changes. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/osl.c | 114 ++++++++++++++++++++++++----------------------------- 1 file changed, 52 insertions(+), 62 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 67da6fb72274..a8c417c2f480 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -602,6 +602,14 @@ acpi_os_predefined_override(const struct acpi_predefined_names *init_val, return AE_OK; } +static void acpi_table_taint(struct acpi_table_header *table) +{ + pr_warn(PREFIX + "Override [%4.4s-%8.8s], this is unsafe: tainting kernel\n", + table->signature, table->oem_table_id); + add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE); +} + #ifdef CONFIG_ACPI_INITRD_TABLE_OVERRIDE #include #include @@ -746,96 +754,78 @@ void __init acpi_initrd_override(void *data, size_t size) } } } -#endif /* CONFIG_ACPI_INITRD_TABLE_OVERRIDE */ - -static void acpi_table_taint(struct acpi_table_header *table) -{ - pr_warn(PREFIX - "Override [%4.4s-%8.8s], this is unsafe: tainting kernel\n", - table->signature, table->oem_table_id); - add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE); -} - - -acpi_status -acpi_os_table_override(struct acpi_table_header * existing_table, - struct acpi_table_header ** new_table) -{ - if (!existing_table || !new_table) - return AE_BAD_PARAMETER; - - *new_table = NULL; - -#ifdef CONFIG_ACPI_CUSTOM_DSDT - if (strncmp(existing_table->signature, "DSDT", 4) == 0) - *new_table = (struct acpi_table_header *)AmlCode; -#endif - if (*new_table != NULL) - acpi_table_taint(existing_table); - return AE_OK; -} acpi_status acpi_os_physical_table_override(struct acpi_table_header *existing_table, - acpi_physical_address *address, - u32 *table_length) + acpi_physical_address *address, u32 *length) { -#ifndef CONFIG_ACPI_INITRD_TABLE_OVERRIDE - *table_length = 0; - *address = 0; - return AE_OK; -#else int table_offset = 0; struct acpi_table_header *table; + u32 table_length; - *table_length = 0; + *length = 0; *address = 0; - if (!acpi_tables_addr) return AE_OK; - do { - if (table_offset + ACPI_HEADER_SIZE > all_tables_size) { - WARN_ON(1); - return AE_OK; - } - + while (table_offset + ACPI_HEADER_SIZE <= all_tables_size) { table = acpi_os_map_memory(acpi_tables_addr + table_offset, ACPI_HEADER_SIZE); - if (table_offset + table->length > all_tables_size) { acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); WARN_ON(1); return AE_OK; } - table_offset += table->length; + table_length = table->length; - if (memcmp(existing_table->signature, table->signature, 4)) { - acpi_os_unmap_memory(table, - ACPI_HEADER_SIZE); - continue; - } - - /* Only override tables with matching oem id */ - if (memcmp(table->oem_table_id, existing_table->oem_table_id, + /* Only override tables matched */ + if (memcmp(existing_table->signature, table->signature, 4) || + memcmp(table->oem_table_id, existing_table->oem_table_id, ACPI_OEM_TABLE_ID_SIZE)) { - acpi_os_unmap_memory(table, - ACPI_HEADER_SIZE); - continue; + acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); + goto next_table; } - table_offset -= table->length; - *table_length = table->length; - acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); + *length = table_length; *address = acpi_tables_addr + table_offset; + acpi_table_taint(existing_table); + acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); break; - } while (table_offset + ACPI_HEADER_SIZE < all_tables_size); - if (*address != 0) - acpi_table_taint(existing_table); +next_table: + table_offset += table_length; + } return AE_OK; +} +#else +acpi_status +acpi_os_physical_table_override(struct acpi_table_header *existing_table, + acpi_physical_address *address, + u32 *table_length) +{ + *table_length = 0; + *address = 0; + return AE_OK; +} +#endif /* CONFIG_ACPI_INITRD_TABLE_OVERRIDE */ + +acpi_status +acpi_os_table_override(struct acpi_table_header *existing_table, + struct acpi_table_header **new_table) +{ + if (!existing_table || !new_table) + return AE_BAD_PARAMETER; + + *new_table = NULL; + +#ifdef CONFIG_ACPI_CUSTOM_DSDT + if (strncmp(existing_table->signature, "DSDT", 4) == 0) + *new_table = (struct acpi_table_header *)AmlCode; #endif + if (*new_table != NULL) + acpi_table_taint(existing_table); + return AE_OK; } static irqreturn_t acpi_irq(int irq, void *dev_id) -- cgit v1.2.3 From c85cc817e5b6c45a78c3b34170dfeb6469b56d82 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 2 Mar 2016 14:16:25 +0800 Subject: ACPI / OSL: Add support to install tables via initrd This patch adds support to install tables from initrd. If a table in the initrd wasn't used by the override mechanism, the table would be installed after initializing all RSDT/XSDT tables. Link: https://lkml.org/lkml/2014/2/28/368 Reported-by: Thomas Renninger Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/internal.h | 1 + drivers/acpi/osl.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++- drivers/acpi/tables.c | 2 ++ 3 files changed, 52 insertions(+), 1 deletion(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 1e6833a5cd44..27c2cb90e8e4 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -20,6 +20,7 @@ #define PREFIX "ACPI: " +void acpi_initrd_initialize_tables(void); acpi_status acpi_os_initialize1(void); void init_acpi_device_notify(void); int acpi_scan_init(void); diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index a8c417c2f480..814d5f83b75e 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -644,6 +644,7 @@ static const char * const table_sigs[] = { #define ACPI_OVERRIDE_TABLES 64 static struct cpio_data __initdata acpi_initrd_files[ACPI_OVERRIDE_TABLES]; +static DECLARE_BITMAP(acpi_initrd_installed, ACPI_OVERRIDE_TABLES); #define MAP_CHUNK_SIZE (NR_FIX_BTMAPS << PAGE_SHIFT) @@ -760,6 +761,7 @@ acpi_os_physical_table_override(struct acpi_table_header *existing_table, acpi_physical_address *address, u32 *length) { int table_offset = 0; + int table_index = 0; struct acpi_table_header *table; u32 table_length; @@ -780,7 +782,8 @@ acpi_os_physical_table_override(struct acpi_table_header *existing_table, table_length = table->length; /* Only override tables matched */ - if (memcmp(existing_table->signature, table->signature, 4) || + if (test_bit(table_index, acpi_initrd_installed) || + memcmp(existing_table->signature, table->signature, 4) || memcmp(table->oem_table_id, existing_table->oem_table_id, ACPI_OEM_TABLE_ID_SIZE)) { acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); @@ -791,13 +794,54 @@ acpi_os_physical_table_override(struct acpi_table_header *existing_table, *address = acpi_tables_addr + table_offset; acpi_table_taint(existing_table); acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); + set_bit(table_index, acpi_initrd_installed); break; next_table: table_offset += table_length; + table_index++; } return AE_OK; } + +void __init acpi_initrd_initialize_tables(void) +{ + int table_offset = 0; + int table_index = 0; + u32 table_length; + struct acpi_table_header *table; + + if (!acpi_tables_addr) + return; + + while (table_offset + ACPI_HEADER_SIZE <= all_tables_size) { + table = acpi_os_map_memory(acpi_tables_addr + table_offset, + ACPI_HEADER_SIZE); + if (table_offset + table->length > all_tables_size) { + acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); + WARN_ON(1); + return; + } + + table_length = table->length; + + /* Skip RSDT/XSDT which should only be used for override */ + if (test_bit(table_index, acpi_initrd_installed) || + ACPI_COMPARE_NAME(table->signature, ACPI_SIG_RSDT) || + ACPI_COMPARE_NAME(table->signature, ACPI_SIG_XSDT)) { + acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); + goto next_table; + } + + acpi_table_taint(table); + acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); + acpi_install_table(acpi_tables_addr + table_offset, TRUE); + set_bit(table_index, acpi_initrd_installed); +next_table: + table_offset += table_length; + table_index++; + } +} #else acpi_status acpi_os_physical_table_override(struct acpi_table_header *existing_table, @@ -808,6 +852,10 @@ acpi_os_physical_table_override(struct acpi_table_header *existing_table, *address = 0; return AE_OK; } + +void __init acpi_initrd_initialize_tables(void) +{ +} #endif /* CONFIG_ACPI_INITRD_TABLE_OVERRIDE */ acpi_status diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 6c0f0794aa82..57c0a4525dba 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -32,6 +32,7 @@ #include #include #include +#include "internal.h" #define ACPI_MAX_TABLES 128 @@ -456,6 +457,7 @@ int __init acpi_table_init(void) status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0); if (ACPI_FAILURE(status)) return -EINVAL; + acpi_initrd_initialize_tables(); check_multiple_madt(); return 0; -- cgit v1.2.3 From e56c92565dfe2c8de203f42f7d5237d14784b93d Mon Sep 17 00:00:00 2001 From: Josh Hunt Date: Tue, 8 Mar 2016 10:52:11 -0500 Subject: ACPI / APEI: Fix leaked resources We leak the NVS and arch resources (if used), in apei_resources_request. They are allocated to make sure we exclude them from the APEI resources, but they are never freed at the end of the function. Free them now. Signed-off-by: Josh Hunt Reviewed-by: Chen, Gong Signed-off-by: Rafael J. Wysocki --- drivers/acpi/apei/apei-base.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c index a2c8d7adb6eb..da370e1d31f4 100644 --- a/drivers/acpi/apei/apei-base.c +++ b/drivers/acpi/apei/apei-base.c @@ -536,7 +536,8 @@ int apei_resources_request(struct apei_resources *resources, goto err_unmap_ioport; } - return 0; + goto arch_res_fini; + err_unmap_ioport: list_for_each_entry(res, &resources->ioport, list) { if (res == res_bak) @@ -551,7 +552,8 @@ err_unmap_iomem: release_mem_region(res->start, res->end - res->start); } arch_res_fini: - apei_resources_fini(&arch_res); + if (arch_apei_filter_addr) + apei_resources_fini(&arch_res); nvs_res_fini: apei_resources_fini(&nvs_resources); return rc; -- cgit v1.2.3 From 3a03d126ece4388d05937090a87bade560117751 Mon Sep 17 00:00:00 2001 From: Josh Hunt Date: Tue, 8 Mar 2016 10:52:12 -0500 Subject: ACPI / APEI: ERST: Fixed leaked resources in erst_init erst_init currently leaks resources allocated from its call to apei_resources_init(). The data allocated there gets copied into apei_resources_all and can be freed when we're done with it. Signed-off-by: Josh Hunt Reviewed-by: Chen, Gong Signed-off-by: Rafael J. Wysocki --- drivers/acpi/apei/erst.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 6e6bc1059301..006c3894c6ea 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -1207,6 +1207,9 @@ static int __init erst_init(void) "Failed to allocate %lld bytes for persistent store error log.\n", erst_erange.size); + /* Cleanup ERST Resources */ + apei_resources_fini(&erst_resources); + return 0; err_release_erange: -- cgit v1.2.3