Merge branches 'acpi-scan', 'acpi-osl' and 'acpi-apei'
* acpi-scan: ACPI / scan: AMBA bus probing support ACPI: introduce a function to find the first physical device * acpi-osl: ACPI / OSL: Add support to install tables via initrd ACPI / OSL: Clean up initrd table override code * acpi-apei: ACPI / APEI: ERST: Fixed leaked resources in erst_init ACPI / APEI: Fix leaked resources
This commit is contained in:
commit
caf5aa19f7
10 changed files with 275 additions and 100 deletions
|
@ -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
|
||||
|
|
122
drivers/acpi/acpi_amba.c
Normal file
122
drivers/acpi/acpi_amba.c
Normal file
|
@ -0,0 +1,122 @@
|
|||
|
||||
/*
|
||||
* ACPI support for platform bus type.
|
||||
*
|
||||
* Copyright (C) 2015, Linaro Ltd
|
||||
* Author: Graeme Gregory <graeme.gregory@linaro.org>
|
||||
*
|
||||
* 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 <linux/acpi.h>
|
||||
#include <linux/amba/bus.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#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);
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
|
@ -29,6 +30,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);
|
||||
|
@ -106,6 +112,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
|
||||
|
|
|
@ -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 <linux/earlycpio.h>
|
||||
#include <linux/memblock.h>
|
||||
|
@ -636,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)
|
||||
|
||||
|
@ -746,20 +755,112 @@ 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)
|
||||
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;
|
||||
|
||||
*length = 0;
|
||||
*address = 0;
|
||||
if (!acpi_tables_addr)
|
||||
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_length = table->length;
|
||||
|
||||
/* Only override tables matched */
|
||||
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);
|
||||
goto next_table;
|
||||
}
|
||||
|
||||
*length = table_length;
|
||||
*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,
|
||||
acpi_physical_address *address,
|
||||
u32 *table_length)
|
||||
{
|
||||
*table_length = 0;
|
||||
*address = 0;
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
void __init acpi_initrd_initialize_tables(void)
|
||||
{
|
||||
}
|
||||
#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;
|
||||
|
@ -775,69 +876,6 @@ acpi_os_table_override(struct acpi_table_header * 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)
|
||||
{
|
||||
#ifndef CONFIG_ACPI_INITRD_TABLE_OVERRIDE
|
||||
*table_length = 0;
|
||||
*address = 0;
|
||||
return AE_OK;
|
||||
#else
|
||||
int table_offset = 0;
|
||||
struct acpi_table_header *table;
|
||||
|
||||
*table_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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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,
|
||||
ACPI_OEM_TABLE_ID_SIZE)) {
|
||||
acpi_os_unmap_memory(table,
|
||||
ACPI_HEADER_SIZE);
|
||||
continue;
|
||||
}
|
||||
|
||||
table_offset -= table->length;
|
||||
*table_length = table->length;
|
||||
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
|
||||
*address = acpi_tables_addr + table_offset;
|
||||
break;
|
||||
} while (table_offset + ACPI_HEADER_SIZE < all_tables_size);
|
||||
|
||||
if (*address != 0)
|
||||
acpi_table_taint(existing_table);
|
||||
return AE_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
static irqreturn_t acpi_irq(int irq, void *dev_id)
|
||||
{
|
||||
u32 handled;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <linux/errno.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bootmem.h>
|
||||
#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;
|
||||
|
|
Loading…
Reference in a new issue