diff options
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/dispatcher/dsopcode.c | 4 | ||||
-rw-r--r-- | drivers/acpi/osl.c | 175 |
2 files changed, 176 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 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 |
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 | ||
@@ -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 | |||
1139 | static unsigned int acpi_enforce_resources = ENFORCE_RESOURCES_LAX; | ||
1140 | |||
1141 | static 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 */ | ||
1160 | static 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 | |||
1211 | int 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 | } | ||
1223 | EXPORT_SYMBOL(acpi_check_region); | ||
1224 | |||
1225 | int 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 | } | ||
1238 | EXPORT_SYMBOL(acpi_check_mem_region); | ||
1239 | |||
1105 | /* | 1240 | /* |
1106 | * Acquire a spinlock. | 1241 | * Acquire a spinlock. |
1107 | * | 1242 | * |
@@ -1303,10 +1438,46 @@ acpi_status | |||
1303 | acpi_os_validate_address ( | 1438 | acpi_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 |