Skip to content

Commit

Permalink
Merge branches 'release' and 'hwmon-conflicts' into release
Browse files Browse the repository at this point in the history
  • Loading branch information
Len Brown committed Feb 7, 2008
2 parents 8976b6f + 443dea7 commit 299cfe3
Show file tree
Hide file tree
Showing 4 changed files with 204 additions and 5 deletions.
4 changes: 3 additions & 1 deletion drivers/acpi/dispatcher/dsopcode.c
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,9 @@ acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc)

status = acpi_os_validate_address(obj_desc->region.space_id,
obj_desc->region.address,
(acpi_size) obj_desc->region.length);
(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
Expand Down
176 changes: 174 additions & 2 deletions drivers/acpi/osl.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
#include <asm/uaccess.h>

#include <linux/efi.h>
#include <linux/ioport.h>
#include <linux/list.h>

#define _COMPONENT ACPI_OS_SERVICES
ACPI_MODULE_NAME("osl");
Expand Down Expand Up @@ -74,6 +76,18 @@ static void *acpi_irq_context;
static struct workqueue_struct *kacpid_wq;
static struct workqueue_struct *kacpi_notify_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;
};

static LIST_HEAD(resource_list_head);
static DEFINE_SPINLOCK(acpi_res_lock);

#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */
static char osi_additional_string[OSI_STRING_LENGTH_MAX];

Expand Down Expand Up @@ -1091,6 +1105,128 @@ static int __init acpi_wake_gpes_always_on_setup(char *str)

__setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup);

/* Check of resource interference between native drivers and ACPI
* OperationRegions (SystemIO and System Memory only).
* IO ports and memory declared in ACPI might be used by the ACPI subsystem
* in arbitrary AML code and can interfere with legacy drivers.
* acpi_enforce_resources= can be set to:
*
* - strict (2)
* -> further driver trying to access the resources will not load
* - lax (default) (1)
* -> further driver trying to access the resources will load, but you
* get a system message that something might go wrong...
*
* - no (0)
* -> ACPI Operation Region resources will not be registered
*
*/
#define ENFORCE_RESOURCES_STRICT 2
#define ENFORCE_RESOURCES_LAX 1
#define ENFORCE_RESOURCES_NO 0

static unsigned int acpi_enforce_resources = ENFORCE_RESOURCES_LAX;

static int __init acpi_enforce_resources_setup(char *str)
{
if (str == NULL || *str == '\0')
return 0;

if (!strcmp("strict", str))
acpi_enforce_resources = ENFORCE_RESOURCES_STRICT;
else if (!strcmp("lax", str))
acpi_enforce_resources = ENFORCE_RESOURCES_LAX;
else if (!strcmp("no", str))
acpi_enforce_resources = ENFORCE_RESOURCES_NO;

return 1;
}

__setup("acpi_enforce_resources=", acpi_enforce_resources_setup);

/* Check for resource conflicts between ACPI OperationRegions and native
* drivers */
int acpi_check_resource_conflict(struct resource *res)
{
struct acpi_res_list *res_list_elem;
int ioport;
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;

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);

if (clash) {
if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) {
printk(KERN_INFO "%sACPI: %s resource %s [0x%llx-0x%llx]"
" conflicts with ACPI region %s"
" [0x%llx-0x%llx]\n",
acpi_enforce_resources == ENFORCE_RESOURCES_LAX
? KERN_WARNING : KERN_ERR,
ioport ? "I/O" : "Memory", res->name,
(long long) res->start, (long long) res->end,
res_list_elem->name,
(long long) res_list_elem->start,
(long long) res_list_elem->end);
printk(KERN_INFO "ACPI: Device needs an ACPI driver\n");
}
if (acpi_enforce_resources == ENFORCE_RESOURCES_STRICT)
return -EBUSY;
}
return 0;
}
EXPORT_SYMBOL(acpi_check_resource_conflict);

int acpi_check_region(resource_size_t start, resource_size_t n,
const char *name)
{
struct resource res = {
.start = start,
.end = start + n - 1,
.name = name,
.flags = IORESOURCE_IO,
};

return acpi_check_resource_conflict(&res);
}
EXPORT_SYMBOL(acpi_check_region);

int acpi_check_mem_region(resource_size_t start, resource_size_t n,
const char *name)
{
struct resource res = {
.start = start,
.end = start + n - 1,
.name = name,
.flags = IORESOURCE_MEM,
};

return acpi_check_resource_conflict(&res);

}
EXPORT_SYMBOL(acpi_check_mem_region);

/*
* Acquire a spinlock.
*
Expand Down Expand Up @@ -1292,10 +1428,46 @@ acpi_status
acpi_os_validate_address (
u8 space_id,
acpi_physical_address address,
acpi_size length)
acpi_size length,
char *name)
{
struct acpi_res_list *res;
if (acpi_enforce_resources == ENFORCE_RESOURCES_NO)
return AE_OK;

return AE_OK;
switch (space_id) {
case ACPI_ADR_SPACE_SYSTEM_IO:
case ACPI_ADR_SPACE_SYSTEM_MEMORY:
/* Only interference checks against SystemIO and SytemMemory
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);
list_add(&res->resource_list, &resource_list_head);
spin_unlock(&acpi_res_lock);
pr_debug("Added %s resource: start: 0x%llx, end: 0x%llx, "
"name: %s\n", (space_id == ACPI_ADR_SPACE_SYSTEM_IO)
? "SystemIO" : "System Memory",
(unsigned long long)res->start,
(unsigned long long)res->end,
res->name);
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
4 changes: 2 additions & 2 deletions include/acpi/acpiosxf.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,8 @@ acpi_status acpi_os_validate_interface(char *interface);
acpi_status acpi_osi_invalidate(char* interface);

acpi_status
acpi_os_validate_address(u8 space_id,
acpi_physical_address address, acpi_size length);
acpi_os_validate_address(u8 space_id, acpi_physical_address address,
acpi_size length, char *name);

u64 acpi_os_get_timer(void);

Expand Down
25 changes: 25 additions & 0 deletions include/linux/acpi.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#ifndef _LINUX_ACPI_H
#define _LINUX_ACPI_H

#include <linux/ioport.h> /* for struct resource */

#ifdef CONFIG_ACPI

Expand Down Expand Up @@ -238,6 +239,13 @@ extern int pnpacpi_disabled;
#define PXM_INVAL (-1)
#define NID_INVAL (-1)

int acpi_check_resource_conflict(struct resource *res);

int acpi_check_region(resource_size_t start, resource_size_t n,
const char *name);
int acpi_check_mem_region(resource_size_t start, resource_size_t n,
const char *name);

#else /* CONFIG_ACPI */

static inline int acpi_boot_init(void)
Expand All @@ -250,5 +258,22 @@ static inline int acpi_boot_table_init(void)
return 0;
}

static inline int acpi_check_resource_conflict(struct resource *res)
{
return 0;
}

static inline int acpi_check_region(resource_size_t start, resource_size_t n,
const char *name)
{
return 0;
}

static inline int acpi_check_mem_region(resource_size_t start,
resource_size_t n, const char *name)
{
return 0;
}

#endif /* !CONFIG_ACPI */
#endif /*_LINUX_ACPI_H*/

0 comments on commit 299cfe3

Please sign in to comment.