Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ACPI, APEI, Avoid too much error reporting in runtime

This patch fixed the following bug.

https://bugzilla.kernel.org/show_bug.cgi?id=43282

This is caused by a firmware bug checking (checking generic address
register provided by firmware) in runtime. The checking should be
done in address mapping time instead of runtime to avoid too much
error reporting in runtime.

Reported-by: Pawel Sikora <pluto@agmk.net>
Signed-off-by: Huang Ying <ying.huang@intel.com>
Tested-by: Jean Delvare <khali@linux-fr.org>
Cc: stable@vger.kernel.org
Signed-off-by: Len Brown <len.brown@intel.com>

authored by

Huang Ying and committed by
Len Brown
34ddeb03 cfaf0251

+27 -5
+15 -2
drivers/acpi/apei/apei-base.c
··· 243 243 u8 ins = entry->instruction; 244 244 245 245 if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER) 246 - return acpi_os_map_generic_address(&entry->register_region); 246 + return apei_map_generic_address(&entry->register_region); 247 247 248 248 return 0; 249 249 } ··· 276 276 u8 ins = entry->instruction; 277 277 278 278 if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER) 279 - acpi_os_unmap_generic_address(&entry->register_region); 279 + apei_unmap_generic_address(&entry->register_region); 280 280 281 281 return 0; 282 282 } ··· 605 605 606 606 return 0; 607 607 } 608 + 609 + int apei_map_generic_address(struct acpi_generic_address *reg) 610 + { 611 + int rc; 612 + u32 access_bit_width; 613 + u64 address; 614 + 615 + rc = apei_check_gar(reg, &address, &access_bit_width); 616 + if (rc) 617 + return rc; 618 + return acpi_os_map_generic_address(reg); 619 + } 620 + EXPORT_SYMBOL_GPL(apei_map_generic_address); 608 621 609 622 /* read GAR in interrupt (including NMI) or process context */ 610 623 int apei_read(u64 *val, struct acpi_generic_address *reg)
+9
drivers/acpi/apei/apei-internal.h
··· 7 7 #define APEI_INTERNAL_H 8 8 9 9 #include <linux/cper.h> 10 + #include <linux/acpi.h> 11 + #include <linux/acpi_io.h> 10 12 11 13 struct apei_exec_context; 12 14 ··· 69 67 70 68 /* IP has been set in instruction function */ 71 69 #define APEI_EXEC_SET_IP 1 70 + 71 + int apei_map_generic_address(struct acpi_generic_address *reg); 72 + 73 + static inline void apei_unmap_generic_address(struct acpi_generic_address *reg) 74 + { 75 + acpi_os_unmap_generic_address(reg); 76 + } 72 77 73 78 int apei_read(u64 *val, struct acpi_generic_address *reg); 74 79 int apei_write(u64 val, struct acpi_generic_address *reg);
+3 -3
drivers/acpi/apei/ghes.c
··· 301 301 if (!ghes) 302 302 return ERR_PTR(-ENOMEM); 303 303 ghes->generic = generic; 304 - rc = acpi_os_map_generic_address(&generic->error_status_address); 304 + rc = apei_map_generic_address(&generic->error_status_address); 305 305 if (rc) 306 306 goto err_free; 307 307 error_block_length = generic->error_block_length; ··· 321 321 return ghes; 322 322 323 323 err_unmap: 324 - acpi_os_unmap_generic_address(&generic->error_status_address); 324 + apei_unmap_generic_address(&generic->error_status_address); 325 325 err_free: 326 326 kfree(ghes); 327 327 return ERR_PTR(rc); ··· 330 330 static void ghes_fini(struct ghes *ghes) 331 331 { 332 332 kfree(ghes->estatus); 333 - acpi_os_unmap_generic_address(&ghes->generic->error_status_address); 333 + apei_unmap_generic_address(&ghes->generic->error_status_address); 334 334 } 335 335 336 336 enum {