aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/dispatcher/dsopcode.c4
-rw-r--r--drivers/acpi/osl.c175
-rw-r--r--include/acpi/acpiosxf.h4
-rw-r--r--include/linux/acpi.h17
4 files changed, 195 insertions, 5 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 e53fb516f9d4..222f7b1b66f7 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
@@ -1102,6 +1116,127 @@ static int __init acpi_wake_gpes_always_on_setup(char *str)
1102 1116
1103__setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup); 1117__setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup);
1104 1118
1119/* Check of resource interference between native drivers and ACPI
1120 * OperationRegions (SystemIO and System Memory only).
1121 * IO ports and memory declared in ACPI might be used by the ACPI subsystem
1122 * in arbitrary AML code and can interfere with legacy drivers.
1123 * acpi_enforce_resources= can be set to:
1124 *
1125 * - strict (2)
1126 * -> further driver trying to access the resources will not load
1127 * - lax (default) (1)
1128 * -> further driver trying to access the resources will load, but you
1129 * get a system message that something might go wrong...
1130 *
1131 * - no (0)
1132 * -> ACPI Operation Region resources will not be registered
1133 *
1134 */
1135#define ENFORCE_RESOURCES_STRICT 2
1136#define ENFORCE_RESOURCES_LAX 1
1137#define ENFORCE_RESOURCES_NO 0
1138
1139static unsigned int acpi_enforce_resources = ENFORCE_RESOURCES_LAX;
1140
1141static int __init acpi_enforce_resources_setup(char *str)
1142{
1143 if (str == NULL || *str == '\0')
1144 return 0;
1145
1146 if (!strcmp("strict", str))
1147 acpi_enforce_resources = ENFORCE_RESOURCES_STRICT;
1148 else if (!strcmp("lax", str))
1149 acpi_enforce_resources = ENFORCE_RESOURCES_LAX;
1150 else if (!strcmp("no", str))
1151 acpi_enforce_resources = ENFORCE_RESOURCES_NO;
1152
1153 return 1;
1154}
1155
1156__setup("acpi_enforce_resources=", acpi_enforce_resources_setup);
1157
1158/* Check for resource conflicts between ACPI OperationRegions and native
1159 * drivers */
1160static int acpi_check_resource_conflict(struct resource *res)
1161{
1162 struct acpi_res_list *res_list_elem;
1163 int ioport;
1164 int clash = 0;
1165
1166 if (acpi_enforce_resources == ENFORCE_RESOURCES_NO)
1167 return 0;
1168 if (!(res->flags & IORESOURCE_IO) && !(res->flags & IORESOURCE_MEM))
1169 return 0;
1170
1171 ioport = res->flags & IORESOURCE_IO;
1172
1173 spin_lock(&acpi_res_lock);
1174 list_for_each_entry(res_list_elem, &resource_list_head,
1175 resource_list) {
1176 if (ioport && (res_list_elem->resource_type
1177 != ACPI_ADR_SPACE_SYSTEM_IO))
1178 continue;
1179 if (!ioport && (res_list_elem->resource_type
1180 != ACPI_ADR_SPACE_SYSTEM_MEMORY))
1181 continue;
1182
1183 if (res->end < res_list_elem->start
1184 || res_list_elem->end < res->start)
1185 continue;
1186 clash = 1;
1187 break;
1188 }
1189 spin_unlock(&acpi_res_lock);
1190
1191 if (clash) {
1192 if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) {
1193 printk(KERN_INFO "%sACPI: %s resource %s [0x%llx-0x%llx]"
1194 " conflicts with ACPI region %s"
1195 " [0x%llx-0x%llx]\n",
1196 acpi_enforce_resources == ENFORCE_RESOURCES_LAX
1197 ? KERN_WARNING : KERN_ERR,
1198 ioport ? "I/O" : "Memory", res->name,
1199 (long long) res->start, (long long) res->end,
1200 res_list_elem->name,
1201 (long long) res_list_elem->start,
1202 (long long) res_list_elem->end);
1203 printk(KERN_INFO "ACPI: Device needs an ACPI driver\n");
1204 }
1205 if (acpi_enforce_resources == ENFORCE_RESOURCES_STRICT)
1206 return -EBUSY;
1207 }
1208 return 0;
1209}
1210
1211int acpi_check_region(resource_size_t start, resource_size_t n,
1212 const char *name)
1213{
1214 struct resource res = {
1215 .start = start,
1216 .end = start + n - 1,
1217 .name = name,
1218 .flags = IORESOURCE_IO,
1219 };
1220
1221 return acpi_check_resource_conflict(&res);
1222}
1223EXPORT_SYMBOL(acpi_check_region);
1224
1225int acpi_check_mem_region(resource_size_t start, resource_size_t n,
1226 const char *name)
1227{
1228 struct resource res = {
1229 .start = start,
1230 .end = start + n - 1,
1231 .name = name,
1232 .flags = IORESOURCE_MEM,
1233 };
1234
1235 return acpi_check_resource_conflict(&res);
1236
1237}
1238EXPORT_SYMBOL(acpi_check_mem_region);
1239
1105/* 1240/*
1106 * Acquire a spinlock. 1241 * Acquire a spinlock.
1107 * 1242 *
@@ -1303,10 +1438,46 @@ acpi_status
1303acpi_os_validate_address ( 1438acpi_os_validate_address (
1304 u8 space_id, 1439 u8 space_id,
1305 acpi_physical_address address, 1440 acpi_physical_address address,
1306 acpi_size length) 1441 acpi_size length,
1442 char *name)
1307{ 1443{
1444 struct acpi_res_list *res;
1445 if (acpi_enforce_resources == ENFORCE_RESOURCES_NO)
1446 return AE_OK;
1308 1447
1309 return AE_OK; 1448 switch (space_id) {
1449 case ACPI_ADR_SPACE_SYSTEM_IO:
1450 case ACPI_ADR_SPACE_SYSTEM_MEMORY:
1451 /* Only interference checks against SystemIO and SytemMemory
1452 are needed */
1453 res = kzalloc(sizeof(struct acpi_res_list), GFP_KERNEL);
1454 if (!res)
1455 return AE_OK;
1456 /* ACPI names are fixed to 4 bytes, still better use strlcpy */
1457 strlcpy(res->name, name, 5);
1458 res->start = address;
1459 res->end = address + length - 1;
1460 res->resource_type = space_id;
1461 spin_lock(&acpi_res_lock);
1462 list_add(&res->resource_list, &resource_list_head);
1463 spin_unlock(&acpi_res_lock);
1464 pr_debug("Added %s resource: start: 0x%llx, end: 0x%llx, "
1465 "name: %s\n", (space_id == ACPI_ADR_SPACE_SYSTEM_IO)
1466 ? "SystemIO" : "System Memory",
1467 (unsigned long long)res->start,
1468 (unsigned long long)res->end,
1469 res->name);
1470 break;
1471 case ACPI_ADR_SPACE_PCI_CONFIG:
1472 case ACPI_ADR_SPACE_EC:
1473 case ACPI_ADR_SPACE_SMBUS:
1474 case ACPI_ADR_SPACE_CMOS:
1475 case ACPI_ADR_SPACE_PCI_BAR_TARGET:
1476 case ACPI_ADR_SPACE_DATA_TABLE:
1477 case ACPI_ADR_SPACE_FIXED_HARDWARE:
1478 break;
1479 }
1480 return AE_OK;
1310} 1481}
1311 1482
1312#endif 1483#endif
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index ca882b8e7d10..c082c7de88a0 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -239,8 +239,8 @@ acpi_status acpi_os_validate_interface(char *interface);
239acpi_status acpi_osi_invalidate(char* interface); 239acpi_status acpi_osi_invalidate(char* interface);
240 240
241acpi_status 241acpi_status
242acpi_os_validate_address(u8 space_id, 242acpi_os_validate_address(u8 space_id, acpi_physical_address address,
243 acpi_physical_address address, acpi_size length); 243 acpi_size length, char *name);
244 244
245u64 acpi_os_get_timer(void); 245u64 acpi_os_get_timer(void);
246 246
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 63f2e6ed698f..893f90a5dea9 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -217,6 +217,11 @@ extern int pnpacpi_disabled;
217#define PXM_INVAL (-1) 217#define PXM_INVAL (-1)
218#define NID_INVAL (-1) 218#define NID_INVAL (-1)
219 219
220int acpi_check_region(resource_size_t start, resource_size_t n,
221 const char *name);
222int acpi_check_mem_region(resource_size_t start, resource_size_t n,
223 const char *name);
224
220#else /* CONFIG_ACPI */ 225#else /* CONFIG_ACPI */
221 226
222static inline int acpi_boot_init(void) 227static inline int acpi_boot_init(void)
@@ -229,5 +234,17 @@ static inline int acpi_boot_table_init(void)
229 return 0; 234 return 0;
230} 235}
231 236
237static inline int acpi_check_region(resource_size_t start, resource_size_t n,
238 const char *name)
239{
240 return 0;
241}
242
243static inline int acpi_check_mem_region(resource_size_t start,
244 resource_size_t n, const char *name)
245{
246 return 0;
247}
248
232#endif /* !CONFIG_ACPI */ 249#endif /* !CONFIG_ACPI */
233#endif /*_LINUX_ACPI_H*/ 250#endif /*_LINUX_ACPI_H*/