Commit 890b3d0e authored by Huang Ying's avatar Huang Ying Committed by Greg Kroah-Hartman

ACPI, APEI, Avoid too much error reporting in runtime

commit 34ddeb03 upstream.

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: default avatarPawel Sikora <pluto@agmk.net>
Signed-off-by: default avatarHuang Ying <ying.huang@intel.com>
Tested-by: default avatarJean Delvare <khali@linux-fr.org>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent d54520f7
...@@ -243,7 +243,7 @@ static int pre_map_gar_callback(struct apei_exec_context *ctx, ...@@ -243,7 +243,7 @@ static int pre_map_gar_callback(struct apei_exec_context *ctx,
u8 ins = entry->instruction; u8 ins = entry->instruction;
if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER) if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER)
return acpi_os_map_generic_address(&entry->register_region); return apei_map_generic_address(&entry->register_region);
return 0; return 0;
} }
...@@ -276,7 +276,7 @@ static int post_unmap_gar_callback(struct apei_exec_context *ctx, ...@@ -276,7 +276,7 @@ static int post_unmap_gar_callback(struct apei_exec_context *ctx,
u8 ins = entry->instruction; u8 ins = entry->instruction;
if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER) if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER)
acpi_os_unmap_generic_address(&entry->register_region); apei_unmap_generic_address(&entry->register_region);
return 0; return 0;
} }
...@@ -606,6 +606,19 @@ static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr, ...@@ -606,6 +606,19 @@ static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr,
return 0; return 0;
} }
int apei_map_generic_address(struct acpi_generic_address *reg)
{
int rc;
u32 access_bit_width;
u64 address;
rc = apei_check_gar(reg, &address, &access_bit_width);
if (rc)
return rc;
return acpi_os_map_generic_address(reg);
}
EXPORT_SYMBOL_GPL(apei_map_generic_address);
/* read GAR in interrupt (including NMI) or process context */ /* read GAR in interrupt (including NMI) or process context */
int apei_read(u64 *val, struct acpi_generic_address *reg) int apei_read(u64 *val, struct acpi_generic_address *reg)
{ {
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
#define APEI_INTERNAL_H #define APEI_INTERNAL_H
#include <linux/cper.h> #include <linux/cper.h>
#include <linux/acpi.h>
#include <linux/acpi_io.h>
struct apei_exec_context; struct apei_exec_context;
...@@ -68,6 +70,13 @@ static inline int apei_exec_run_optional(struct apei_exec_context *ctx, u8 actio ...@@ -68,6 +70,13 @@ static inline int apei_exec_run_optional(struct apei_exec_context *ctx, u8 actio
/* IP has been set in instruction function */ /* IP has been set in instruction function */
#define APEI_EXEC_SET_IP 1 #define APEI_EXEC_SET_IP 1
int apei_map_generic_address(struct acpi_generic_address *reg);
static inline void apei_unmap_generic_address(struct acpi_generic_address *reg)
{
acpi_os_unmap_generic_address(reg);
}
int apei_read(u64 *val, struct acpi_generic_address *reg); int apei_read(u64 *val, struct acpi_generic_address *reg);
int apei_write(u64 val, struct acpi_generic_address *reg); int apei_write(u64 val, struct acpi_generic_address *reg);
......
...@@ -301,7 +301,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic) ...@@ -301,7 +301,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic)
if (!ghes) if (!ghes)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
ghes->generic = generic; ghes->generic = generic;
rc = acpi_os_map_generic_address(&generic->error_status_address); rc = apei_map_generic_address(&generic->error_status_address);
if (rc) if (rc)
goto err_free; goto err_free;
error_block_length = generic->error_block_length; error_block_length = generic->error_block_length;
...@@ -321,7 +321,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic) ...@@ -321,7 +321,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic)
return ghes; return ghes;
err_unmap: err_unmap:
acpi_os_unmap_generic_address(&generic->error_status_address); apei_unmap_generic_address(&generic->error_status_address);
err_free: err_free:
kfree(ghes); kfree(ghes);
return ERR_PTR(rc); return ERR_PTR(rc);
...@@ -330,7 +330,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic) ...@@ -330,7 +330,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic)
static void ghes_fini(struct ghes *ghes) static void ghes_fini(struct ghes *ghes)
{ {
kfree(ghes->estatus); kfree(ghes->estatus);
acpi_os_unmap_generic_address(&ghes->generic->error_status_address); apei_unmap_generic_address(&ghes->generic->error_status_address);
} }
enum { enum {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment