diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/acpi/dispatcher/dsopcode.c | 4 | ||||
-rw-r--r-- | drivers/acpi/osl.c | 176 |
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 |
49 | ACPI_MODULE_NAME("osl"); | 51 | ACPI_MODULE_NAME("osl"); |
@@ -74,6 +76,18 @@ static void *acpi_irq_context; | |||
74 | static struct workqueue_struct *kacpid_wq; | 76 | static struct workqueue_struct *kacpid_wq; |
75 | static struct workqueue_struct *kacpi_notify_wq; | 77 | static struct workqueue_struct *kacpi_notify_wq; |
76 | 78 | ||
79 | struct 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 | |||
88 | static LIST_HEAD(resource_list_head); | ||
89 | static DEFINE_SPINLOCK(acpi_res_lock); | ||
90 | |||
77 | #define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ | 91 | #define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ |
78 | static char osi_additional_string[OSI_STRING_LENGTH_MAX]; | 92 | static 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 | |||
1128 | static unsigned int acpi_enforce_resources = ENFORCE_RESOURCES_LAX; | ||
1129 | |||
1130 | static 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 */ | ||
1149 | int 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 | } | ||
1199 | EXPORT_SYMBOL(acpi_check_resource_conflict); | ||
1200 | |||
1201 | int 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 | } | ||
1213 | EXPORT_SYMBOL(acpi_check_region); | ||
1214 | |||
1215 | int 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 | } | ||
1228 | EXPORT_SYMBOL(acpi_check_mem_region); | ||
1229 | |||
1094 | /* | 1230 | /* |
1095 | * Acquire a spinlock. | 1231 | * Acquire a spinlock. |
1096 | * | 1232 | * |
@@ -1292,10 +1428,46 @@ acpi_status | |||
1292 | acpi_os_validate_address ( | 1428 | acpi_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 |