aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/apei
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/apei')
-rw-r--r--drivers/acpi/apei/einj.c38
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
197static 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 */
198static int __einj_error_trigger(u64 trigger_paddr, u32 type, 218static 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;