ACPICA: Add support for region address conflict checking
Allows drivers to determine if any memory or I/O addresses will conflict with addresses used by ACPI operation regions. Introduces a new interface, acpi_check_address_range. http://marc.info/?t=132251388700002&r=1&w=2 Reported-and-tested-by: Luca Tettamanti <kronos.it@gmail.com> Signed-off-by: Lin Ming <ming.m.lin@intel.com> Signed-off-by: Bob Moore <robert.moore@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
This commit is contained in:
Родитель
ecafe6faa2
Коммит
f654c0fefa
|
@ -135,6 +135,7 @@ acpi-y += \
|
|||
tbxfroot.o
|
||||
|
||||
acpi-y += \
|
||||
utaddress.o \
|
||||
utalloc.o \
|
||||
utcopy.o \
|
||||
utdebug.o \
|
||||
|
|
|
@ -123,6 +123,10 @@
|
|||
|
||||
#define ACPI_MAX_SLEEP 2000 /* Two seconds */
|
||||
|
||||
/* Address Range lists are per-space_id (Memory and I/O only) */
|
||||
|
||||
#define ACPI_ADDRESS_RANGE_MAX 2
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* ACPI Specification constants (Do not change unless the specification changes)
|
||||
|
|
|
@ -306,6 +306,8 @@ ACPI_EXTERN u8 acpi_gbl_acpi_hardware_present;
|
|||
ACPI_EXTERN u8 acpi_gbl_events_initialized;
|
||||
ACPI_EXTERN u8 acpi_gbl_osi_data;
|
||||
ACPI_EXTERN struct acpi_interface_info *acpi_gbl_supported_interfaces;
|
||||
ACPI_EXTERN struct acpi_address_range
|
||||
*acpi_gbl_address_range_list[ACPI_ADDRESS_RANGE_MAX];
|
||||
|
||||
#ifndef DEFINE_ACPI_GLOBALS
|
||||
|
||||
|
|
|
@ -630,6 +630,15 @@ union acpi_generic_state {
|
|||
|
||||
typedef acpi_status(*ACPI_EXECUTE_OP) (struct acpi_walk_state * walk_state);
|
||||
|
||||
/* Address Range info block */
|
||||
|
||||
struct acpi_address_range {
|
||||
struct acpi_address_range *next;
|
||||
struct acpi_namespace_node *region_node;
|
||||
acpi_physical_address start_address;
|
||||
acpi_physical_address end_address;
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Parser typedefs and structs
|
||||
|
|
|
@ -579,6 +579,24 @@ acpi_ut_create_list(char *list_name,
|
|||
|
||||
#endif /* ACPI_DBG_TRACK_ALLOCATIONS */
|
||||
|
||||
/*
|
||||
* utaddress - address range check
|
||||
*/
|
||||
acpi_status
|
||||
acpi_ut_add_address_range(acpi_adr_space_type space_id,
|
||||
acpi_physical_address address,
|
||||
u32 length, struct acpi_namespace_node *region_node);
|
||||
|
||||
void
|
||||
acpi_ut_remove_address_range(acpi_adr_space_type space_id,
|
||||
struct acpi_namespace_node *region_node);
|
||||
|
||||
u32
|
||||
acpi_ut_check_address_range(acpi_adr_space_type space_id,
|
||||
acpi_physical_address address, u32 length, u8 warn);
|
||||
|
||||
void acpi_ut_delete_address_lists(void);
|
||||
|
||||
/*
|
||||
* utxferror - various error/warning output functions
|
||||
*/
|
||||
|
|
|
@ -250,6 +250,13 @@ acpi_ds_get_bank_field_arguments(union acpi_operand_object *obj_desc)
|
|||
status = acpi_ds_execute_arguments(node, node->parent,
|
||||
extra_desc->extra.aml_length,
|
||||
extra_desc->extra.aml_start);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
status = acpi_ut_add_address_range(obj_desc->region.space_id,
|
||||
obj_desc->region.address,
|
||||
obj_desc->region.length, node);
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
|
@ -391,25 +398,8 @@ acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc)
|
|||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/* Validate the region address/length via the host OS */
|
||||
|
||||
status = acpi_os_validate_address(obj_desc->region.space_id,
|
||||
obj_desc->region.address,
|
||||
(acpi_size) obj_desc->region.length,
|
||||
acpi_ut_get_node_name(node));
|
||||
|
||||
if (ACPI_FAILURE(status)) {
|
||||
/*
|
||||
* Invalid address/length. We will emit an error message and mark
|
||||
* the region as invalid, so that it will cause an additional error if
|
||||
* it is ever used. Then return AE_OK.
|
||||
*/
|
||||
ACPI_EXCEPTION((AE_INFO, status,
|
||||
"During address validation of OpRegion [%4.4s]",
|
||||
node->name.ascii));
|
||||
obj_desc->common.flags |= AOPOBJ_INVALID;
|
||||
status = AE_OK;
|
||||
}
|
||||
|
||||
status = acpi_ut_add_address_range(obj_desc->region.space_id,
|
||||
obj_desc->region.address,
|
||||
obj_desc->region.length, node);
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,294 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Module Name: utaddress - op_region address range check
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000 - 2012, Intel Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* substantially similar to the "NO WARRANTY" disclaimer below
|
||||
* ("Disclaimer") and any redistribution must be conditioned upon
|
||||
* including a substantially similar Disclaimer requirement for further
|
||||
* binary redistribution.
|
||||
* 3. Neither the names of the above-listed copyright holders nor the names
|
||||
* of any contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#include <acpi/acpi.h>
|
||||
#include "accommon.h"
|
||||
#include "acnamesp.h"
|
||||
|
||||
#define _COMPONENT ACPI_UTILITIES
|
||||
ACPI_MODULE_NAME("utaddress")
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ut_add_address_range
|
||||
*
|
||||
* PARAMETERS: space_id - Address space ID
|
||||
* Address - op_region start address
|
||||
* Length - op_region length
|
||||
* region_node - op_region namespace node
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Add the Operation Region address range to the global list.
|
||||
* The only supported Space IDs are Memory and I/O. Called when
|
||||
* the op_region address/length operands are fully evaluated.
|
||||
*
|
||||
* MUTEX: Locks the namespace
|
||||
*
|
||||
* NOTE: Because this interface is only called when an op_region argument
|
||||
* list is evaluated, there cannot be any duplicate region_nodes.
|
||||
* Duplicate Address/Length values are allowed, however, so that multiple
|
||||
* address conflicts can be detected.
|
||||
*
|
||||
******************************************************************************/
|
||||
acpi_status
|
||||
acpi_ut_add_address_range(acpi_adr_space_type space_id,
|
||||
acpi_physical_address address,
|
||||
u32 length, struct acpi_namespace_node *region_node)
|
||||
{
|
||||
struct acpi_address_range *range_info;
|
||||
acpi_status status;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ut_add_address_range);
|
||||
|
||||
if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
|
||||
(space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
|
||||
/* Allocate/init a new info block, add it to the appropriate list */
|
||||
|
||||
range_info = ACPI_ALLOCATE(sizeof(struct acpi_address_range));
|
||||
if (!range_info) {
|
||||
return_ACPI_STATUS(AE_NO_MEMORY);
|
||||
}
|
||||
|
||||
range_info->start_address = address;
|
||||
range_info->end_address = (address + length - 1);
|
||||
range_info->region_node = region_node;
|
||||
|
||||
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_FREE(range_info);
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
range_info->next = acpi_gbl_address_range_list[space_id];
|
||||
acpi_gbl_address_range_list[space_id] = range_info;
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
|
||||
"\nAdded [%4.4s] address range: 0x%p-0x%p\n",
|
||||
acpi_ut_get_node_name(range_info->region_node),
|
||||
ACPI_CAST_PTR(void, address),
|
||||
ACPI_CAST_PTR(void, range_info->end_address)));
|
||||
|
||||
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
|
||||
return_ACPI_STATUS(AE_OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ut_remove_address_range
|
||||
*
|
||||
* PARAMETERS: space_id - Address space ID
|
||||
* region_node - op_region namespace node
|
||||
*
|
||||
* RETURN: None
|
||||
*
|
||||
* DESCRIPTION: Remove the Operation Region from the global list. The only
|
||||
* supported Space IDs are Memory and I/O. Called when an
|
||||
* op_region is deleted.
|
||||
*
|
||||
* MUTEX: Assumes the namespace is locked
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
void
|
||||
acpi_ut_remove_address_range(acpi_adr_space_type space_id,
|
||||
struct acpi_namespace_node *region_node)
|
||||
{
|
||||
struct acpi_address_range *range_info;
|
||||
struct acpi_address_range *prev;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ut_remove_address_range);
|
||||
|
||||
if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
|
||||
(space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
|
||||
return_VOID;
|
||||
}
|
||||
|
||||
/* Get the appropriate list head and check the list */
|
||||
|
||||
range_info = prev = acpi_gbl_address_range_list[space_id];
|
||||
while (range_info) {
|
||||
if (range_info->region_node == region_node) {
|
||||
if (range_info == prev) { /* Found at list head */
|
||||
acpi_gbl_address_range_list[space_id] =
|
||||
range_info->next;
|
||||
} else {
|
||||
prev->next = range_info->next;
|
||||
}
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
|
||||
"\nRemoved [%4.4s] address range: 0x%p-0x%p\n",
|
||||
acpi_ut_get_node_name(range_info->
|
||||
region_node),
|
||||
ACPI_CAST_PTR(void,
|
||||
range_info->
|
||||
start_address),
|
||||
ACPI_CAST_PTR(void,
|
||||
range_info->
|
||||
end_address)));
|
||||
|
||||
ACPI_FREE(range_info);
|
||||
return_VOID;
|
||||
}
|
||||
|
||||
prev = range_info;
|
||||
range_info = range_info->next;
|
||||
}
|
||||
|
||||
return_VOID;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ut_check_address_range
|
||||
*
|
||||
* PARAMETERS: space_id - Address space ID
|
||||
* Address - Start address
|
||||
* Length - Length of address range
|
||||
* Warn - TRUE if warning on overlap desired
|
||||
*
|
||||
* RETURN: Count of the number of conflicts detected. Zero is always
|
||||
* returned for Space IDs other than Memory or I/O.
|
||||
*
|
||||
* DESCRIPTION: Check if the input address range overlaps any of the
|
||||
* ASL operation region address ranges. The only supported
|
||||
* Space IDs are Memory and I/O.
|
||||
*
|
||||
* MUTEX: Assumes the namespace is locked.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
u32
|
||||
acpi_ut_check_address_range(acpi_adr_space_type space_id,
|
||||
acpi_physical_address address, u32 length, u8 warn)
|
||||
{
|
||||
struct acpi_address_range *range_info;
|
||||
acpi_physical_address end_address;
|
||||
char *pathname;
|
||||
u32 overlap_count = 0;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ut_check_address_range);
|
||||
|
||||
if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
|
||||
(space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
|
||||
return_UINT32(0);
|
||||
}
|
||||
|
||||
range_info = acpi_gbl_address_range_list[space_id];
|
||||
end_address = address + length - 1;
|
||||
|
||||
/* Check entire list for all possible conflicts */
|
||||
|
||||
while (range_info) {
|
||||
/*
|
||||
* Check if the requested Address/Length overlaps this address_range.
|
||||
* Four cases to consider:
|
||||
*
|
||||
* 1) Input address/length is contained completely in the address range
|
||||
* 2) Input address/length overlaps range at the range start
|
||||
* 3) Input address/length overlaps range at the range end
|
||||
* 4) Input address/length completely encompasses the range
|
||||
*/
|
||||
if ((address <= range_info->end_address) &&
|
||||
(end_address >= range_info->start_address)) {
|
||||
|
||||
/* Found an address range overlap */
|
||||
|
||||
overlap_count++;
|
||||
if (warn) { /* Optional warning message */
|
||||
pathname =
|
||||
acpi_ns_get_external_pathname(range_info->
|
||||
region_node);
|
||||
|
||||
ACPI_WARNING((AE_INFO,
|
||||
"0x%p-0x%p %s conflicts with Region %s %d",
|
||||
ACPI_CAST_PTR(void, address),
|
||||
ACPI_CAST_PTR(void, end_address),
|
||||
acpi_ut_get_region_name(space_id),
|
||||
pathname, overlap_count));
|
||||
ACPI_FREE(pathname);
|
||||
}
|
||||
}
|
||||
|
||||
range_info = range_info->next;
|
||||
}
|
||||
|
||||
return_UINT32(overlap_count);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ut_delete_address_lists
|
||||
*
|
||||
* PARAMETERS: None
|
||||
*
|
||||
* RETURN: None
|
||||
*
|
||||
* DESCRIPTION: Delete all global address range lists (called during
|
||||
* subsystem shutdown).
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
void acpi_ut_delete_address_lists(void)
|
||||
{
|
||||
struct acpi_address_range *next;
|
||||
struct acpi_address_range *range_info;
|
||||
int i;
|
||||
|
||||
/* Delete all elements in all address range lists */
|
||||
|
||||
for (i = 0; i < ACPI_ADDRESS_RANGE_MAX; i++) {
|
||||
next = acpi_gbl_address_range_list[i];
|
||||
|
||||
while (next) {
|
||||
range_info = next;
|
||||
next = range_info->next;
|
||||
ACPI_FREE(range_info);
|
||||
}
|
||||
|
||||
acpi_gbl_address_range_list[i] = NULL;
|
||||
}
|
||||
}
|
|
@ -215,11 +215,14 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
|
|||
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
|
||||
"***** Region %p\n", object));
|
||||
|
||||
/* Invalidate the region address/length via the host OS */
|
||||
|
||||
acpi_os_invalidate_address(object->region.space_id,
|
||||
object->region.address,
|
||||
(acpi_size) object->region.length);
|
||||
/*
|
||||
* Update address_range list. However, only permanent regions
|
||||
* are installed in this list. (Not created within a method)
|
||||
*/
|
||||
if (!(object->region.node->flags & ANOBJ_TEMPORARY)) {
|
||||
acpi_ut_remove_address_range(object->region.space_id,
|
||||
object->region.node);
|
||||
}
|
||||
|
||||
second_desc = acpi_ns_get_secondary_object(object);
|
||||
if (second_desc) {
|
||||
|
|
|
@ -264,6 +264,12 @@ acpi_status acpi_ut_init_globals(void)
|
|||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/* Address Range lists */
|
||||
|
||||
for (i = 0; i < ACPI_ADDRESS_RANGE_MAX; i++) {
|
||||
acpi_gbl_address_range_list[i] = NULL;
|
||||
}
|
||||
|
||||
/* Mutex locked flags */
|
||||
|
||||
for (i = 0; i < ACPI_NUM_MUTEX; i++) {
|
||||
|
|
|
@ -92,6 +92,7 @@ static void acpi_ut_terminate(void)
|
|||
gpe_xrupt_info = next_gpe_xrupt_info;
|
||||
}
|
||||
|
||||
acpi_ut_delete_address_lists();
|
||||
return_VOID;
|
||||
}
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "acnamesp.h"
|
||||
#include "acdebug.h"
|
||||
#include "actables.h"
|
||||
#include "acinterp.h"
|
||||
|
||||
#define _COMPONENT ACPI_UTILITIES
|
||||
ACPI_MODULE_NAME("utxface")
|
||||
|
@ -640,4 +641,41 @@ acpi_status acpi_install_interface_handler(acpi_interface_handler handler)
|
|||
}
|
||||
|
||||
ACPI_EXPORT_SYMBOL(acpi_install_interface_handler)
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_check_address_range
|
||||
*
|
||||
* PARAMETERS: space_id - Address space ID
|
||||
* Address - Start address
|
||||
* Length - Length
|
||||
* Warn - TRUE if warning on overlap desired
|
||||
*
|
||||
* RETURN: Count of the number of conflicts detected.
|
||||
*
|
||||
* DESCRIPTION: Check if the input address range overlaps any of the
|
||||
* ASL operation region address ranges.
|
||||
*
|
||||
****************************************************************************/
|
||||
u32
|
||||
acpi_check_address_range(acpi_adr_space_type space_id,
|
||||
acpi_physical_address address,
|
||||
acpi_size length, u8 warn)
|
||||
{
|
||||
u32 overlaps;
|
||||
acpi_status status;
|
||||
|
||||
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
overlaps = acpi_ut_check_address_range(space_id, address,
|
||||
(u32)length, warn);
|
||||
|
||||
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
|
||||
return (overlaps);
|
||||
}
|
||||
|
||||
ACPI_EXPORT_SYMBOL(acpi_check_address_range)
|
||||
#endif /* !ACPI_ASL_COMPILER */
|
||||
|
|
|
@ -83,19 +83,6 @@ static struct workqueue_struct *kacpi_notify_wq;
|
|||
struct workqueue_struct *kacpi_hotplug_wq;
|
||||
EXPORT_SYMBOL(kacpi_hotplug_wq);
|
||||
|
||||
struct acpi_res_list {
|
||||
resource_size_t start;
|
||||
resource_size_t end;
|
||||
acpi_adr_space_type resource_type; /* IO port, System memory, ...*/
|
||||
char name[5]; /* only can have a length of 4 chars, make use of this
|
||||
one instead of res->name, no need to kalloc then */
|
||||
struct list_head resource_list;
|
||||
int count;
|
||||
};
|
||||
|
||||
static LIST_HEAD(resource_list_head);
|
||||
static DEFINE_SPINLOCK(acpi_res_lock);
|
||||
|
||||
/*
|
||||
* This list of permanent mappings is for memory that may be accessed from
|
||||
* interrupt context, where we can't do the ioremap().
|
||||
|
@ -1278,44 +1265,28 @@ __setup("acpi_enforce_resources=", acpi_enforce_resources_setup);
|
|||
* drivers */
|
||||
int acpi_check_resource_conflict(const struct resource *res)
|
||||
{
|
||||
struct acpi_res_list *res_list_elem;
|
||||
int ioport = 0, clash = 0;
|
||||
acpi_adr_space_type space_id;
|
||||
acpi_size length;
|
||||
u8 warn = 0;
|
||||
int clash = 0;
|
||||
|
||||
if (acpi_enforce_resources == ENFORCE_RESOURCES_NO)
|
||||
return 0;
|
||||
if (!(res->flags & IORESOURCE_IO) && !(res->flags & IORESOURCE_MEM))
|
||||
return 0;
|
||||
|
||||
ioport = res->flags & IORESOURCE_IO;
|
||||
if (res->flags & IORESOURCE_IO)
|
||||
space_id = ACPI_ADR_SPACE_SYSTEM_IO;
|
||||
else
|
||||
space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY;
|
||||
|
||||
spin_lock(&acpi_res_lock);
|
||||
list_for_each_entry(res_list_elem, &resource_list_head,
|
||||
resource_list) {
|
||||
if (ioport && (res_list_elem->resource_type
|
||||
!= ACPI_ADR_SPACE_SYSTEM_IO))
|
||||
continue;
|
||||
if (!ioport && (res_list_elem->resource_type
|
||||
!= ACPI_ADR_SPACE_SYSTEM_MEMORY))
|
||||
continue;
|
||||
|
||||
if (res->end < res_list_elem->start
|
||||
|| res_list_elem->end < res->start)
|
||||
continue;
|
||||
clash = 1;
|
||||
break;
|
||||
}
|
||||
spin_unlock(&acpi_res_lock);
|
||||
length = res->end - res->start + 1;
|
||||
if (acpi_enforce_resources != ENFORCE_RESOURCES_NO)
|
||||
warn = 1;
|
||||
clash = acpi_check_address_range(space_id, res->start, length, warn);
|
||||
|
||||
if (clash) {
|
||||
if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) {
|
||||
printk(KERN_WARNING "ACPI: resource %s %pR"
|
||||
" conflicts with ACPI region %s "
|
||||
"[%s 0x%zx-0x%zx]\n",
|
||||
res->name, res, res_list_elem->name,
|
||||
(res_list_elem->resource_type ==
|
||||
ACPI_ADR_SPACE_SYSTEM_IO) ? "io" : "mem",
|
||||
(size_t) res_list_elem->start,
|
||||
(size_t) res_list_elem->end);
|
||||
if (acpi_enforce_resources == ENFORCE_RESOURCES_LAX)
|
||||
printk(KERN_NOTICE "ACPI: This conflict may"
|
||||
" cause random problems and system"
|
||||
|
@ -1467,155 +1438,6 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
|
|||
kmem_cache_free(cache, object);
|
||||
return (AE_OK);
|
||||
}
|
||||
|
||||
static inline int acpi_res_list_add(struct acpi_res_list *res)
|
||||
{
|
||||
struct acpi_res_list *res_list_elem;
|
||||
|
||||
list_for_each_entry(res_list_elem, &resource_list_head,
|
||||
resource_list) {
|
||||
|
||||
if (res->resource_type == res_list_elem->resource_type &&
|
||||
res->start == res_list_elem->start &&
|
||||
res->end == res_list_elem->end) {
|
||||
|
||||
/*
|
||||
* The Region(addr,len) already exist in the list,
|
||||
* just increase the count
|
||||
*/
|
||||
|
||||
res_list_elem->count++;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
res->count = 1;
|
||||
list_add(&res->resource_list, &resource_list_head);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline void acpi_res_list_del(struct acpi_res_list *res)
|
||||
{
|
||||
struct acpi_res_list *res_list_elem;
|
||||
|
||||
list_for_each_entry(res_list_elem, &resource_list_head,
|
||||
resource_list) {
|
||||
|
||||
if (res->resource_type == res_list_elem->resource_type &&
|
||||
res->start == res_list_elem->start &&
|
||||
res->end == res_list_elem->end) {
|
||||
|
||||
/*
|
||||
* If the res count is decreased to 0,
|
||||
* remove and free it
|
||||
*/
|
||||
|
||||
if (--res_list_elem->count == 0) {
|
||||
list_del(&res_list_elem->resource_list);
|
||||
kfree(res_list_elem);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
acpi_status
|
||||
acpi_os_invalidate_address(
|
||||
u8 space_id,
|
||||
acpi_physical_address address,
|
||||
acpi_size length)
|
||||
{
|
||||
struct acpi_res_list res;
|
||||
|
||||
switch (space_id) {
|
||||
case ACPI_ADR_SPACE_SYSTEM_IO:
|
||||
case ACPI_ADR_SPACE_SYSTEM_MEMORY:
|
||||
/* Only interference checks against SystemIO and SystemMemory
|
||||
are needed */
|
||||
res.start = address;
|
||||
res.end = address + length - 1;
|
||||
res.resource_type = space_id;
|
||||
spin_lock(&acpi_res_lock);
|
||||
acpi_res_list_del(&res);
|
||||
spin_unlock(&acpi_res_lock);
|
||||
break;
|
||||
case ACPI_ADR_SPACE_PCI_CONFIG:
|
||||
case ACPI_ADR_SPACE_EC:
|
||||
case ACPI_ADR_SPACE_SMBUS:
|
||||
case ACPI_ADR_SPACE_CMOS:
|
||||
case ACPI_ADR_SPACE_PCI_BAR_TARGET:
|
||||
case ACPI_ADR_SPACE_DATA_TABLE:
|
||||
case ACPI_ADR_SPACE_FIXED_HARDWARE:
|
||||
break;
|
||||
}
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_os_validate_address
|
||||
*
|
||||
* PARAMETERS: space_id - ACPI space ID
|
||||
* address - Physical address
|
||||
* length - Address length
|
||||
*
|
||||
* RETURN: AE_OK if address/length is valid for the space_id. Otherwise,
|
||||
* should return AE_AML_ILLEGAL_ADDRESS.
|
||||
*
|
||||
* DESCRIPTION: Validate a system address via the host OS. Used to validate
|
||||
* the addresses accessed by AML operation regions.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
acpi_status
|
||||
acpi_os_validate_address (
|
||||
u8 space_id,
|
||||
acpi_physical_address address,
|
||||
acpi_size length,
|
||||
char *name)
|
||||
{
|
||||
struct acpi_res_list *res;
|
||||
int added;
|
||||
if (acpi_enforce_resources == ENFORCE_RESOURCES_NO)
|
||||
return AE_OK;
|
||||
|
||||
switch (space_id) {
|
||||
case ACPI_ADR_SPACE_SYSTEM_IO:
|
||||
case ACPI_ADR_SPACE_SYSTEM_MEMORY:
|
||||
/* Only interference checks against SystemIO and SystemMemory
|
||||
are needed */
|
||||
res = kzalloc(sizeof(struct acpi_res_list), GFP_KERNEL);
|
||||
if (!res)
|
||||
return AE_OK;
|
||||
/* ACPI names are fixed to 4 bytes, still better use strlcpy */
|
||||
strlcpy(res->name, name, 5);
|
||||
res->start = address;
|
||||
res->end = address + length - 1;
|
||||
res->resource_type = space_id;
|
||||
spin_lock(&acpi_res_lock);
|
||||
added = acpi_res_list_add(res);
|
||||
spin_unlock(&acpi_res_lock);
|
||||
pr_debug("%s %s resource: start: 0x%llx, end: 0x%llx, "
|
||||
"name: %s\n", added ? "Added" : "Already exist",
|
||||
(space_id == ACPI_ADR_SPACE_SYSTEM_IO)
|
||||
? "SystemIO" : "System Memory",
|
||||
(unsigned long long)res->start,
|
||||
(unsigned long long)res->end,
|
||||
res->name);
|
||||
if (!added)
|
||||
kfree(res);
|
||||
break;
|
||||
case ACPI_ADR_SPACE_PCI_CONFIG:
|
||||
case ACPI_ADR_SPACE_EC:
|
||||
case ACPI_ADR_SPACE_SMBUS:
|
||||
case ACPI_ADR_SPACE_CMOS:
|
||||
case ACPI_ADR_SPACE_PCI_BAR_TARGET:
|
||||
case ACPI_ADR_SPACE_DATA_TABLE:
|
||||
case ACPI_ADR_SPACE_FIXED_HARDWARE:
|
||||
break;
|
||||
}
|
||||
return AE_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
acpi_status __init acpi_os_initialize(void)
|
||||
|
|
|
@ -238,13 +238,6 @@ acpi_os_write_pci_configuration(struct acpi_pci_id *pci_id,
|
|||
/*
|
||||
* Miscellaneous
|
||||
*/
|
||||
acpi_status
|
||||
acpi_os_validate_address(u8 space_id, acpi_physical_address address,
|
||||
acpi_size length, char *name);
|
||||
acpi_status
|
||||
acpi_os_invalidate_address(u8 space_id, acpi_physical_address address,
|
||||
acpi_size length);
|
||||
|
||||
u64 acpi_os_get_timer(void);
|
||||
|
||||
acpi_status acpi_os_signal(u32 function, void *info);
|
||||
|
|
|
@ -112,6 +112,11 @@ acpi_status acpi_install_interface(acpi_string interface_name);
|
|||
|
||||
acpi_status acpi_remove_interface(acpi_string interface_name);
|
||||
|
||||
u32
|
||||
acpi_check_address_range(acpi_adr_space_type space_id,
|
||||
acpi_physical_address address,
|
||||
acpi_size length, u8 warn);
|
||||
|
||||
/*
|
||||
* ACPI Memory management
|
||||
*/
|
||||
|
|
Загрузка…
Ссылка в новой задаче