diff options
| -rw-r--r-- | drivers/acpi/dispatcher/dsopcode.c | 4 | ||||
| -rw-r--r-- | drivers/acpi/osl.c | 175 | ||||
| -rw-r--r-- | include/acpi/acpiosxf.h | 4 | ||||
| -rw-r--r-- | include/linux/acpi.h | 17 |
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 |
| 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 |
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); | |||
| 239 | acpi_status acpi_osi_invalidate(char* interface); | 239 | acpi_status acpi_osi_invalidate(char* interface); |
| 240 | 240 | ||
| 241 | acpi_status | 241 | acpi_status |
| 242 | acpi_os_validate_address(u8 space_id, | 242 | acpi_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 | ||
| 245 | u64 acpi_os_get_timer(void); | 245 | u64 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 | ||
| 220 | int acpi_check_region(resource_size_t start, resource_size_t n, | ||
| 221 | const char *name); | ||
| 222 | int 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 | ||
| 222 | static inline int acpi_boot_init(void) | 227 | static 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 | ||
| 237 | static inline int acpi_check_region(resource_size_t start, resource_size_t n, | ||
| 238 | const char *name) | ||
| 239 | { | ||
| 240 | return 0; | ||
| 241 | } | ||
| 242 | |||
| 243 | static 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*/ |
