diff options
| -rw-r--r-- | drivers/acpi/apei/einj.c | 38 |
1 files changed, 32 insertions, 6 deletions
diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c index 4fdc8a3b4f6c..6e6512e68a2d 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj.c | |||
| @@ -194,6 +194,26 @@ static int einj_check_trigger_header(struct acpi_einj_trigger *trigger_tab) | |||
| 194 | return 0; | 194 | return 0; |
| 195 | } | 195 | } |
| 196 | 196 | ||
| 197 | static struct acpi_generic_address *einj_get_trigger_parameter_region( | ||
| 198 | struct acpi_einj_trigger *trigger_tab, u64 param1, u64 param2) | ||
| 199 | { | ||
| 200 | int i; | ||
| 201 | struct acpi_whea_header *entry; | ||
| 202 | |||
| 203 | entry = (struct acpi_whea_header *) | ||
| 204 | ((char *)trigger_tab + sizeof(struct acpi_einj_trigger)); | ||
| 205 | for (i = 0; i < trigger_tab->entry_count; i++) { | ||
| 206 | if (entry->action == ACPI_EINJ_TRIGGER_ERROR && | ||
| 207 | entry->instruction == ACPI_EINJ_WRITE_REGISTER_VALUE && | ||
| 208 | entry->register_region.space_id == | ||
| 209 | ACPI_ADR_SPACE_SYSTEM_MEMORY && | ||
| 210 | (entry->register_region.address & param2) == (param1 & param2)) | ||
| 211 | return &entry->register_region; | ||
| 212 | entry++; | ||
| 213 | } | ||
| 214 | |||
| 215 | return NULL; | ||
| 216 | } | ||
| 197 | /* Execute instructions in trigger error action table */ | 217 | /* Execute instructions in trigger error action table */ |
| 198 | static int __einj_error_trigger(u64 trigger_paddr, u32 type, | 218 | static int __einj_error_trigger(u64 trigger_paddr, u32 type, |
| 199 | u64 param1, u64 param2) | 219 | u64 param1, u64 param2) |
| @@ -205,6 +225,7 @@ static int __einj_error_trigger(u64 trigger_paddr, u32 type, | |||
| 205 | struct resource *r; | 225 | struct resource *r; |
| 206 | u32 table_size; | 226 | u32 table_size; |
| 207 | int rc = -EIO; | 227 | int rc = -EIO; |
| 228 | struct acpi_generic_address *trigger_param_region = NULL; | ||
| 208 | 229 | ||
| 209 | r = request_mem_region(trigger_paddr, sizeof(*trigger_tab), | 230 | r = request_mem_region(trigger_paddr, sizeof(*trigger_tab), |
| 210 | "APEI EINJ Trigger Table"); | 231 | "APEI EINJ Trigger Table"); |
| @@ -266,12 +287,17 @@ static int __einj_error_trigger(u64 trigger_paddr, u32 type, | |||
| 266 | if (param_extension && (type & 0x0038) && param2) { | 287 | if (param_extension && (type & 0x0038) && param2) { |
| 267 | struct apei_resources addr_resources; | 288 | struct apei_resources addr_resources; |
| 268 | apei_resources_init(&addr_resources); | 289 | apei_resources_init(&addr_resources); |
| 269 | rc = apei_resources_add(&addr_resources, | 290 | trigger_param_region = einj_get_trigger_parameter_region( |
| 270 | param1 & param2, | 291 | trigger_tab, param1, param2); |
| 271 | ~param2 + 1, true); | 292 | if (trigger_param_region) { |
| 272 | if (rc) | 293 | rc = apei_resources_add(&addr_resources, |
| 273 | goto out_fini; | 294 | trigger_param_region->address, |
| 274 | rc = apei_resources_sub(&trigger_resources, &addr_resources); | 295 | trigger_param_region->bit_width/8, true); |
| 296 | if (rc) | ||
| 297 | goto out_fini; | ||
| 298 | rc = apei_resources_sub(&trigger_resources, | ||
| 299 | &addr_resources); | ||
| 300 | } | ||
| 275 | apei_resources_fini(&addr_resources); | 301 | apei_resources_fini(&addr_resources); |
| 276 | if (rc) | 302 | if (rc) |
| 277 | goto out_fini; | 303 | goto out_fini; |
