diff options
Diffstat (limited to 'drivers/acpi/apei')
-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; |