diff options
| -rw-r--r-- | drivers/acpi/dispatcher/dsopcode.c | 4 | ||||
| -rw-r--r-- | drivers/acpi/osl.c | 176 | ||||
| -rw-r--r-- | include/acpi/acpiosxf.h | 4 | ||||
| -rw-r--r-- | include/linux/acpi.h | 25 |
4 files changed, 204 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 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 |
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index 1a16cfbe9e0d..022a5fd80c8e 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h | |||
| @@ -242,8 +242,8 @@ acpi_status acpi_os_validate_interface(char *interface); | |||
| 242 | acpi_status acpi_osi_invalidate(char* interface); | 242 | acpi_status acpi_osi_invalidate(char* interface); |
| 243 | 243 | ||
| 244 | acpi_status | 244 | acpi_status |
| 245 | acpi_os_validate_address(u8 space_id, | 245 | acpi_os_validate_address(u8 space_id, acpi_physical_address address, |
| 246 | acpi_physical_address address, acpi_size length); | 246 | acpi_size length, char *name); |
| 247 | 247 | ||
| 248 | u64 acpi_os_get_timer(void); | 248 | u64 acpi_os_get_timer(void); |
| 249 | 249 | ||
diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 5a5a13b64d09..25fb4dcc0e6b 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #ifndef _LINUX_ACPI_H | 25 | #ifndef _LINUX_ACPI_H |
| 26 | #define _LINUX_ACPI_H | 26 | #define _LINUX_ACPI_H |
| 27 | 27 | ||
| 28 | #include <linux/ioport.h> /* for struct resource */ | ||
| 28 | 29 | ||
| 29 | #ifdef CONFIG_ACPI | 30 | #ifdef CONFIG_ACPI |
| 30 | 31 | ||
| @@ -238,6 +239,13 @@ extern int pnpacpi_disabled; | |||
| 238 | #define PXM_INVAL (-1) | 239 | #define PXM_INVAL (-1) |
| 239 | #define NID_INVAL (-1) | 240 | #define NID_INVAL (-1) |
| 240 | 241 | ||
| 242 | int acpi_check_resource_conflict(struct resource *res); | ||
| 243 | |||
| 244 | int acpi_check_region(resource_size_t start, resource_size_t n, | ||
| 245 | const char *name); | ||
| 246 | int acpi_check_mem_region(resource_size_t start, resource_size_t n, | ||
| 247 | const char *name); | ||
| 248 | |||
| 241 | #else /* CONFIG_ACPI */ | 249 | #else /* CONFIG_ACPI */ |
| 242 | 250 | ||
| 243 | static inline int acpi_boot_init(void) | 251 | static inline int acpi_boot_init(void) |
| @@ -250,5 +258,22 @@ static inline int acpi_boot_table_init(void) | |||
| 250 | return 0; | 258 | return 0; |
| 251 | } | 259 | } |
| 252 | 260 | ||
| 261 | static inline int acpi_check_resource_conflict(struct resource *res) | ||
| 262 | { | ||
| 263 | return 0; | ||
| 264 | } | ||
| 265 | |||
| 266 | static inline int acpi_check_region(resource_size_t start, resource_size_t n, | ||
| 267 | const char *name) | ||
| 268 | { | ||
| 269 | return 0; | ||
| 270 | } | ||
| 271 | |||
| 272 | static inline int acpi_check_mem_region(resource_size_t start, | ||
| 273 | resource_size_t n, const char *name) | ||
| 274 | { | ||
| 275 | return 0; | ||
| 276 | } | ||
| 277 | |||
| 253 | #endif /* !CONFIG_ACPI */ | 278 | #endif /* !CONFIG_ACPI */ |
| 254 | #endif /*_LINUX_ACPI_H*/ | 279 | #endif /*_LINUX_ACPI_H*/ |
