aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/dispatcher/dsopcode.c4
-rw-r--r--drivers/acpi/osl.c176
2 files changed, 177 insertions, 3 deletions
diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c
index fc9da4879cbf..f501e083aac7 100644
--- a/drivers/acpi/dispatcher/dsopcode.c
+++ b/drivers/acpi/dispatcher/dsopcode.c
@@ -359,7 +359,9 @@ acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc)
359 359
360 status = acpi_os_validate_address(obj_desc->region.space_id, 360 status = acpi_os_validate_address(obj_desc->region.space_id,
361 obj_desc->region.address, 361 obj_desc->region.address,
362 (acpi_size) obj_desc->region.length); 362 (acpi_size) obj_desc->region.length,
363 acpi_ut_get_node_name(node));
364
363 if (ACPI_FAILURE(status)) { 365 if (ACPI_FAILURE(status)) {
364 /* 366 /*
365 * Invalid address/length. We will emit an error message and mark 367 * Invalid address/length. We will emit an error message and mark
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 3b8aef3aefe5..6f49f6437289 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -44,6 +44,8 @@
44#include <asm/uaccess.h> 44#include <asm/uaccess.h>
45 45
46#include <linux/efi.h> 46#include <linux/efi.h>
47#include <linux/ioport.h>
48#include <linux/list.h>
47 49
48#define _COMPONENT ACPI_OS_SERVICES 50#define _COMPONENT ACPI_OS_SERVICES
49ACPI_MODULE_NAME("osl"); 51ACPI_MODULE_NAME("osl");
@@ -74,6 +76,18 @@ static void *acpi_irq_context;
74static struct workqueue_struct *kacpid_wq; 76static struct workqueue_struct *kacpid_wq;
75static struct workqueue_struct *kacpi_notify_wq; 77static struct workqueue_struct *kacpi_notify_wq;
76 78
79struct acpi_res_list {
80 resource_size_t start;
81 resource_size_t end;
82 acpi_adr_space_type resource_type; /* IO port, System memory, ...*/
83 char name[5]; /* only can have a length of 4 chars, make use of this
84 one instead of res->name, no need to kalloc then */
85 struct list_head resource_list;
86};
87
88static LIST_HEAD(resource_list_head);
89static DEFINE_SPINLOCK(acpi_res_lock);
90
77#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ 91#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */
78static char osi_additional_string[OSI_STRING_LENGTH_MAX]; 92static char osi_additional_string[OSI_STRING_LENGTH_MAX];
79 93
@@ -1091,6 +1105,128 @@ static int __init acpi_wake_gpes_always_on_setup(char *str)
1091 1105
1092__setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup); 1106__setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup);
1093 1107
1108/* Check of resource interference between native drivers and ACPI
1109 * OperationRegions (SystemIO and System Memory only).
1110 * IO ports and memory declared in ACPI might be used by the ACPI subsystem
1111 * in arbitrary AML code and can interfere with legacy drivers.
1112 * acpi_enforce_resources= can be set to:
1113 *
1114 * - strict (2)
1115 * -> further driver trying to access the resources will not load
1116 * - lax (default) (1)
1117 * -> further driver trying to access the resources will load, but you
1118 * get a system message that something might go wrong...
1119 *
1120 * - no (0)
1121 * -> ACPI Operation Region resources will not be registered
1122 *
1123 */
1124#define ENFORCE_RESOURCES_STRICT 2
1125#define ENFORCE_RESOURCES_LAX 1
1126#define ENFORCE_RESOURCES_NO 0
1127
1128static unsigned int acpi_enforce_resources = ENFORCE_RESOURCES_LAX;
1129
1130static int __init acpi_enforce_resources_setup(char *str)
1131{
1132 if (str == NULL || *str == '\0')
1133 return 0;
1134
1135 if (!strcmp("strict", str))
1136 acpi_enforce_resources = ENFORCE_RESOURCES_STRICT;
1137 else if (!strcmp("lax", str))
1138 acpi_enforce_resources = ENFORCE_RESOURCES_LAX;
1139 else if (!strcmp("no", str))
1140 acpi_enforce_resources = ENFORCE_RESOURCES_NO;
1141
1142 return 1;
1143}
1144
1145__setup("acpi_enforce_resources=", acpi_enforce_resources_setup);
1146
1147/* Check for resource conflicts between ACPI OperationRegions and native
1148 * drivers */
1149int acpi_check_resource_conflict(struct resource *res)
1150{
1151 struct acpi_res_list *res_list_elem;
1152 int ioport;
1153 int clash = 0;
1154
1155 if (acpi_enforce_resources == ENFORCE_RESOURCES_NO)
1156 return 0;
1157 if (!(res->flags & IORESOURCE_IO) && !(res->flags & IORESOURCE_MEM))
1158 return 0;
1159
1160 ioport = res->flags & IORESOURCE_IO;
1161
1162 spin_lock(&acpi_res_lock);
1163 list_for_each_entry(res_list_elem, &resource_list_head,
1164 resource_list) {
1165 if (ioport && (res_list_elem->resource_type
1166 != ACPI_ADR_SPACE_SYSTEM_IO))
1167 continue;
1168 if (!ioport && (res_list_elem->resource_type
1169 != ACPI_ADR_SPACE_SYSTEM_MEMORY))
1170 continue;
1171
1172 if (res->end < res_list_elem->start
1173 || res_list_elem->end < res->start)
1174 continue;
1175 clash = 1;
1176 break;
1177 }
1178 spin_unlock(&acpi_res_lock);
1179
1180 if (clash) {
1181 if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) {
1182 printk(KERN_INFO "%sACPI: %s resource %s [0x%llx-0x%llx]"
1183 " conflicts with ACPI region %s"
1184 " [0x%llx-0x%llx]\n",
1185 acpi_enforce_resources == ENFORCE_RESOURCES_LAX
1186 ? KERN_WARNING : KERN_ERR,
1187 ioport ? "I/O" : "Memory", res->name,
1188 (long long) res->start, (long long) res->end,
1189 res_list_elem->name,
1190 (long long) res_list_elem->start,
1191 (long long) res_list_elem->end);
1192 printk(KERN_INFO "ACPI: Device needs an ACPI driver\n");
1193 }
1194 if (acpi_enforce_resources == ENFORCE_RESOURCES_STRICT)
1195 return -EBUSY;
1196 }
1197 return 0;
1198}
1199EXPORT_SYMBOL(acpi_check_resource_conflict);
1200
1201int acpi_check_region(resource_size_t start, resource_size_t n,
1202 const char *name)
1203{
1204 struct resource res = {
1205 .start = start,
1206 .end = start + n - 1,
1207 .name = name,
1208 .flags = IORESOURCE_IO,
1209 };
1210
1211 return acpi_check_resource_conflict(&res);
1212}
1213EXPORT_SYMBOL(acpi_check_region);
1214
1215int acpi_check_mem_region(resource_size_t start, resource_size_t n,
1216 const char *name)
1217{
1218 struct resource res = {
1219 .start = start,
1220 .end = start + n - 1,
1221 .name = name,
1222 .flags = IORESOURCE_MEM,
1223 };
1224
1225 return acpi_check_resource_conflict(&res);
1226
1227}
1228EXPORT_SYMBOL(acpi_check_mem_region);
1229
1094/* 1230/*
1095 * Acquire a spinlock. 1231 * Acquire a spinlock.
1096 * 1232 *
@@ -1292,10 +1428,46 @@ acpi_status
1292acpi_os_validate_address ( 1428acpi_os_validate_address (
1293 u8 space_id, 1429 u8 space_id,
1294 acpi_physical_address address, 1430 acpi_physical_address address,
1295 acpi_size length) 1431 acpi_size length,
1432 char *name)
1296{ 1433{
1434 struct acpi_res_list *res;
1435 if (acpi_enforce_resources == ENFORCE_RESOURCES_NO)
1436 return AE_OK;
1297 1437
1298 return AE_OK; 1438 switch (space_id) {
1439 case ACPI_ADR_SPACE_SYSTEM_IO:
1440 case ACPI_ADR_SPACE_SYSTEM_MEMORY:
1441 /* Only interference checks against SystemIO and SytemMemory
1442 are needed */
1443 res = kzalloc(sizeof(struct acpi_res_list), GFP_KERNEL);
1444 if (!res)
1445 return AE_OK;
1446 /* ACPI names are fixed to 4 bytes, still better use strlcpy */
1447 strlcpy(res->name, name, 5);
1448 res->start = address;
1449 res->end = address + length - 1;
1450 res->resource_type = space_id;
1451 spin_lock(&acpi_res_lock);
1452 list_add(&res->resource_list, &resource_list_head);
1453 spin_unlock(&acpi_res_lock);
1454 pr_debug("Added %s resource: start: 0x%llx, end: 0x%llx, "
1455 "name: %s\n", (space_id == ACPI_ADR_SPACE_SYSTEM_IO)
1456 ? "SystemIO" : "System Memory",
1457 (unsigned long long)res->start,
1458 (unsigned long long)res->end,
1459 res->name);
1460 break;
1461 case ACPI_ADR_SPACE_PCI_CONFIG:
1462 case ACPI_ADR_SPACE_EC:
1463 case ACPI_ADR_SPACE_SMBUS:
1464 case ACPI_ADR_SPACE_CMOS:
1465 case ACPI_ADR_SPACE_PCI_BAR_TARGET:
1466 case ACPI_ADR_SPACE_DATA_TABLE:
1467 case ACPI_ADR_SPACE_FIXED_HARDWARE:
1468 break;
1469 }
1470 return AE_OK;
1299} 1471}
1300 1472
1301#endif 1473#endif