aboutsummaryrefslogtreecommitdiff
path: root/drivers/acpi/apei
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/apei')
-rw-r--r--drivers/acpi/apei/Kconfig3
-rw-r--r--drivers/acpi/apei/Makefile2
-rw-r--r--drivers/acpi/apei/apei-base.c11
-rw-r--r--drivers/acpi/apei/apei-internal.h13
-rw-r--r--drivers/acpi/apei/cper.c402
-rw-r--r--drivers/acpi/apei/einj.c69
-rw-r--r--drivers/acpi/apei/erst.c3
-rw-r--r--drivers/acpi/apei/ghes.c94
8 files changed, 112 insertions, 485 deletions
diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig
index f0c1ce95a0e..c4dac715096 100644
--- a/drivers/acpi/apei/Kconfig
+++ b/drivers/acpi/apei/Kconfig
@@ -2,6 +2,7 @@ config ACPI_APEI
bool "ACPI Platform Error Interface (APEI)"
select MISC_FILESYSTEMS
select PSTORE
+ select UEFI_CPER
depends on X86
help
APEI allows to report errors (for example from the chipset)
@@ -11,7 +12,7 @@ config ACPI_APEI
config ACPI_APEI_GHES
bool "APEI Generic Hardware Error Source"
- depends on ACPI_APEI && X86
+ depends on ACPI_APEI
select ACPI_HED
select IRQ_WORK
select GENERIC_ALLOCATOR
diff --git a/drivers/acpi/apei/Makefile b/drivers/acpi/apei/Makefile
index d1d1bc0a4ee..5d575a95594 100644
--- a/drivers/acpi/apei/Makefile
+++ b/drivers/acpi/apei/Makefile
@@ -3,4 +3,4 @@ obj-$(CONFIG_ACPI_APEI_GHES) += ghes.o
obj-$(CONFIG_ACPI_APEI_EINJ) += einj.o
obj-$(CONFIG_ACPI_APEI_ERST_DEBUG) += erst-dbg.o
-apei-y := apei-base.o hest.o cper.o erst.o
+apei-y := apei-base.o hest.o erst.o
diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c
index 46f80e2c92f..8678dfe5366 100644
--- a/drivers/acpi/apei/apei-base.c
+++ b/drivers/acpi/apei/apei-base.c
@@ -34,13 +34,13 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/acpi.h>
-#include <linux/acpi_io.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/kref.h>
#include <linux/rculist.h>
#include <linux/interrupt.h>
#include <linux/debugfs.h>
+#include <asm/unaligned.h>
#include "apei-internal.h"
@@ -567,8 +567,7 @@ static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr,
bit_offset = reg->bit_offset;
access_size_code = reg->access_width;
space_id = reg->space_id;
- /* Handle possible alignment issues */
- memcpy(paddr, &reg->address, sizeof(*paddr));
+ *paddr = get_unaligned(&reg->address);
if (!*paddr) {
pr_warning(FW_BUG APEI_PFX
"Invalid physical address in GAR [0x%llx/%u/%u/%u/%u]\n",
@@ -758,9 +757,9 @@ int apei_osc_setup(void)
.cap.pointer = capbuf,
};
- capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
- capbuf[OSC_SUPPORT_TYPE] = 1;
- capbuf[OSC_CONTROL_TYPE] = 0;
+ capbuf[OSC_QUERY_DWORD] = OSC_QUERY_ENABLE;
+ capbuf[OSC_SUPPORT_DWORD] = 1;
+ capbuf[OSC_CONTROL_DWORD] = 0;
if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle))
|| ACPI_FAILURE(acpi_run_osc(handle, &context)))
diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h
index f220d642136..e5bcd919d4e 100644
--- a/drivers/acpi/apei/apei-internal.h
+++ b/drivers/acpi/apei/apei-internal.h
@@ -8,7 +8,6 @@
#include <linux/cper.h>
#include <linux/acpi.h>
-#include <linux/acpi_io.h>
struct apei_exec_context;
@@ -122,11 +121,11 @@ struct dentry;
struct dentry *apei_get_debugfs_dir(void);
#define apei_estatus_for_each_section(estatus, section) \
- for (section = (struct acpi_hest_generic_data *)(estatus + 1); \
+ for (section = (struct acpi_generic_data *)(estatus + 1); \
(void *)section - (void *)estatus < estatus->data_length; \
section = (void *)(section+1) + section->error_data_length)
-static inline u32 apei_estatus_len(struct acpi_hest_generic_status *estatus)
+static inline u32 cper_estatus_len(struct acpi_generic_status *estatus)
{
if (estatus->raw_data_length)
return estatus->raw_data_offset + \
@@ -135,10 +134,10 @@ static inline u32 apei_estatus_len(struct acpi_hest_generic_status *estatus)
return sizeof(*estatus) + estatus->data_length;
}
-void apei_estatus_print(const char *pfx,
- const struct acpi_hest_generic_status *estatus);
-int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus);
-int apei_estatus_check(const struct acpi_hest_generic_status *estatus);
+void cper_estatus_print(const char *pfx,
+ const struct acpi_generic_status *estatus);
+int cper_estatus_check_header(const struct acpi_generic_status *estatus);
+int cper_estatus_check(const struct acpi_generic_status *estatus);
int apei_osc_setup(void);
#endif
diff --git a/drivers/acpi/apei/cper.c b/drivers/acpi/apei/cper.c
deleted file mode 100644
index 33dc6a00480..00000000000
--- a/drivers/acpi/apei/cper.c
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- * UEFI Common Platform Error Record (CPER) support
- *
- * Copyright (C) 2010, Intel Corp.
- * Author: Huang Ying <ying.huang@intel.com>
- *
- * CPER is the format used to describe platform hardware error by
- * various APEI tables, such as ERST, BERT and HEST etc.
- *
- * For more information about CPER, please refer to Appendix N of UEFI
- * Specification version 2.3.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/time.h>
-#include <linux/cper.h>
-#include <linux/acpi.h>
-#include <linux/pci.h>
-#include <linux/aer.h>
-
-/*
- * CPER record ID need to be unique even after reboot, because record
- * ID is used as index for ERST storage, while CPER records from
- * multiple boot may co-exist in ERST.
- */
-u64 cper_next_record_id(void)
-{
- static atomic64_t seq;
-
- if (!atomic64_read(&seq))
- atomic64_set(&seq, ((u64)get_seconds()) << 32);
-
- return atomic64_inc_return(&seq);
-}
-EXPORT_SYMBOL_GPL(cper_next_record_id);
-
-static const char *cper_severity_strs[] = {
- "recoverable",
- "fatal",
- "corrected",
- "info",
-};
-
-static const char *cper_severity_str(unsigned int severity)
-{
- return severity < ARRAY_SIZE(cper_severity_strs) ?
- cper_severity_strs[severity] : "unknown";
-}
-
-/*
- * cper_print_bits - print strings for set bits
- * @pfx: prefix for each line, including log level and prefix string
- * @bits: bit mask
- * @strs: string array, indexed by bit position
- * @strs_size: size of the string array: @strs
- *
- * For each set bit in @bits, print the corresponding string in @strs.
- * If the output length is longer than 80, multiple line will be
- * printed, with @pfx is printed at the beginning of each line.
- */
-void cper_print_bits(const char *pfx, unsigned int bits,
- const char *strs[], unsigned int strs_size)
-{
- int i, len = 0;
- const char *str;
- char buf[84];
-
- for (i = 0; i < strs_size; i++) {
- if (!(bits & (1U << i)))
- continue;
- str = strs[i];
- if (!str)
- continue;
- if (len && len + strlen(str) + 2 > 80) {
- printk("%s\n", buf);
- len = 0;
- }
- if (!len)
- len = snprintf(buf, sizeof(buf), "%s%s", pfx, str);
- else
- len += snprintf(buf+len, sizeof(buf)-len, ", %s", str);
- }
- if (len)
- printk("%s\n", buf);
-}
-
-static const char *cper_proc_type_strs[] = {
- "IA32/X64",
- "IA64",
-};
-
-static const char *cper_proc_isa_strs[] = {
- "IA32",
- "IA64",
- "X64",
-};
-
-static const char *cper_proc_error_type_strs[] = {
- "cache error",
- "TLB error",
- "bus error",
- "micro-architectural error",
-};
-
-static const char *cper_proc_op_strs[] = {
- "unknown or generic",
- "data read",
- "data write",
- "instruction execution",
-};
-
-static const char *cper_proc_flag_strs[] = {
- "restartable",
- "precise IP",
- "overflow",
- "corrected",
-};
-
-static void cper_print_proc_generic(const char *pfx,
- const struct cper_sec_proc_generic *proc)
-{
- if (proc->validation_bits & CPER_PROC_VALID_TYPE)
- printk("%s""processor_type: %d, %s\n", pfx, proc->proc_type,
- proc->proc_type < ARRAY_SIZE(cper_proc_type_strs) ?
- cper_proc_type_strs[proc->proc_type] : "unknown");
- if (proc->validation_bits & CPER_PROC_VALID_ISA)
- printk("%s""processor_isa: %d, %s\n", pfx, proc->proc_isa,
- proc->proc_isa < ARRAY_SIZE(cper_proc_isa_strs) ?
- cper_proc_isa_strs[proc->proc_isa] : "unknown");
- if (proc->validation_bits & CPER_PROC_VALID_ERROR_TYPE) {
- printk("%s""error_type: 0x%02x\n", pfx, proc->proc_error_type);
- cper_print_bits(pfx, proc->proc_error_type,
- cper_proc_error_type_strs,
- ARRAY_SIZE(cper_proc_error_type_strs));
- }
- if (proc->validation_bits & CPER_PROC_VALID_OPERATION)
- printk("%s""operation: %d, %s\n", pfx, proc->operation,
- proc->operation < ARRAY_SIZE(cper_proc_op_strs) ?
- cper_proc_op_strs[proc->operation] : "unknown");
- if (proc->validation_bits & CPER_PROC_VALID_FLAGS) {
- printk("%s""flags: 0x%02x\n", pfx, proc->flags);
- cper_print_bits(pfx, proc->flags, cper_proc_flag_strs,
- ARRAY_SIZE(cper_proc_flag_strs));
- }
- if (proc->validation_bits & CPER_PROC_VALID_LEVEL)
- printk("%s""level: %d\n", pfx, proc->level);
- if (proc->validation_bits & CPER_PROC_VALID_VERSION)
- printk("%s""version_info: 0x%016llx\n", pfx, proc->cpu_version);
- if (proc->validation_bits & CPER_PROC_VALID_ID)
- printk("%s""processor_id: 0x%016llx\n", pfx, proc->proc_id);
- if (proc->validation_bits & CPER_PROC_VALID_TARGET_ADDRESS)
- printk("%s""target_address: 0x%016llx\n",
- pfx, proc->target_addr);
- if (proc->validation_bits & CPER_PROC_VALID_REQUESTOR_ID)
- printk("%s""requestor_id: 0x%016llx\n",
- pfx, proc->requestor_id);
- if (proc->validation_bits & CPER_PROC_VALID_RESPONDER_ID)
- printk("%s""responder_id: 0x%016llx\n",
- pfx, proc->responder_id);
- if (proc->validation_bits & CPER_PROC_VALID_IP)
- printk("%s""IP: 0x%016llx\n", pfx, proc->ip);
-}
-
-static const char *cper_mem_err_type_strs[] = {
- "unknown",
- "no error",
- "single-bit ECC",
- "multi-bit ECC",
- "single-symbol chipkill ECC",
- "multi-symbol chipkill ECC",
- "master abort",
- "target abort",
- "parity error",
- "watchdog timeout",
- "invalid address",
- "mirror Broken",
- "memory sparing",
- "scrub corrected error",
- "scrub uncorrected error",
-};
-
-static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem)
-{
- if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS)
- printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status);
- if (mem->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS)
- printk("%s""physical_address: 0x%016llx\n",
- pfx, mem->physical_addr);
- if (mem->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS_MASK)
- printk("%s""physical_address_mask: 0x%016llx\n",
- pfx, mem->physical_addr_mask);
- if (mem->validation_bits & CPER_MEM_VALID_NODE)
- printk("%s""node: %d\n", pfx, mem->node);
- if (mem->validation_bits & CPER_MEM_VALID_CARD)
- printk("%s""card: %d\n", pfx, mem->card);
- if (mem->validation_bits & CPER_MEM_VALID_MODULE)
- printk("%s""module: %d\n", pfx, mem->module);
- if (mem->validation_bits & CPER_MEM_VALID_BANK)
- printk("%s""bank: %d\n", pfx, mem->bank);
- if (mem->validation_bits & CPER_MEM_VALID_DEVICE)
- printk("%s""device: %d\n", pfx, mem->device);
- if (mem->validation_bits & CPER_MEM_VALID_ROW)
- printk("%s""row: %d\n", pfx, mem->row);
- if (mem->validation_bits & CPER_MEM_VALID_COLUMN)
- printk("%s""column: %d\n", pfx, mem->column);
- if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION)
- printk("%s""bit_position: %d\n", pfx, mem->bit_pos);
- if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID)
- printk("%s""requestor_id: 0x%016llx\n", pfx, mem->requestor_id);
- if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID)
- printk("%s""responder_id: 0x%016llx\n", pfx, mem->responder_id);
- if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID)
- printk("%s""target_id: 0x%016llx\n", pfx, mem->target_id);
- if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) {
- u8 etype = mem->error_type;
- printk("%s""error_type: %d, %s\n", pfx, etype,
- etype < ARRAY_SIZE(cper_mem_err_type_strs) ?
- cper_mem_err_type_strs[etype] : "unknown");
- }
-}
-
-static const char *cper_pcie_port_type_strs[] = {
- "PCIe end point",
- "legacy PCI end point",
- "unknown",
- "unknown",
- "root port",
- "upstream switch port",
- "downstream switch port",
- "PCIe to PCI/PCI-X bridge",
- "PCI/PCI-X to PCIe bridge",
- "root complex integrated endpoint device",
- "root complex event collector",
-};
-
-static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
- const struct acpi_hest_generic_data *gdata)
-{
- if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE)
- printk("%s""port_type: %d, %s\n", pfx, pcie->port_type,
- pcie->port_type < ARRAY_SIZE(cper_pcie_port_type_strs) ?
- cper_pcie_port_type_strs[pcie->port_type] : "unknown");
- if (pcie->validation_bits & CPER_PCIE_VALID_VERSION)
- printk("%s""version: %d.%d\n", pfx,
- pcie->version.major, pcie->version.minor);
- if (pcie->validation_bits & CPER_PCIE_VALID_COMMAND_STATUS)
- printk("%s""command: 0x%04x, status: 0x%04x\n", pfx,
- pcie->command, pcie->status);
- if (pcie->validation_bits & CPER_PCIE_VALID_DEVICE_ID) {
- const __u8 *p;
- printk("%s""device_id: %04x:%02x:%02x.%x\n", pfx,
- pcie->device_id.segment, pcie->device_id.bus,
- pcie->device_id.device, pcie->device_id.function);
- printk("%s""slot: %d\n", pfx,
- pcie->device_id.slot >> CPER_PCIE_SLOT_SHIFT);
- printk("%s""secondary_bus: 0x%02x\n", pfx,
- pcie->device_id.secondary_bus);
- printk("%s""vendor_id: 0x%04x, device_id: 0x%04x\n", pfx,
- pcie->device_id.vendor_id, pcie->device_id.device_id);
- p = pcie->device_id.class_code;
- printk("%s""class_code: %02x%02x%02x\n", pfx, p[0], p[1], p[2]);
- }
- if (pcie->validation_bits & CPER_PCIE_VALID_SERIAL_NUMBER)
- printk("%s""serial number: 0x%04x, 0x%04x\n", pfx,
- pcie->serial_number.lower, pcie->serial_number.upper);
- if (pcie->validation_bits & CPER_PCIE_VALID_BRIDGE_CONTROL_STATUS)
- printk(
- "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
- pfx, pcie->bridge.secondary_status, pcie->bridge.control);
-}
-
-static const char *apei_estatus_section_flag_strs[] = {
- "primary",
- "containment warning",
- "reset",
- "threshold exceeded",
- "resource not accessible",
- "latent error",
-};
-
-static void apei_estatus_print_section(
- const char *pfx, const struct acpi_hest_generic_data *gdata, int sec_no)
-{
- uuid_le *sec_type = (uuid_le *)gdata->section_type;
- __u16 severity;
-
- severity = gdata->error_severity;
- printk("%s""section: %d, severity: %d, %s\n", pfx, sec_no, severity,
- cper_severity_str(severity));
- printk("%s""flags: 0x%02x\n", pfx, gdata->flags);
- cper_print_bits(pfx, gdata->flags, apei_estatus_section_flag_strs,
- ARRAY_SIZE(apei_estatus_section_flag_strs));
- if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
- printk("%s""fru_id: %pUl\n", pfx, (uuid_le *)gdata->fru_id);
- if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
- printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text);
-
- if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_GENERIC)) {
- struct cper_sec_proc_generic *proc_err = (void *)(gdata + 1);
- printk("%s""section_type: general processor error\n", pfx);
- if (gdata->error_data_length >= sizeof(*proc_err))
- cper_print_proc_generic(pfx, proc_err);
- else
- goto err_section_too_small;
- } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) {
- struct cper_sec_mem_err *mem_err = (void *)(gdata + 1);
- printk("%s""section_type: memory error\n", pfx);
- if (gdata->error_data_length >= sizeof(*mem_err))
- cper_print_mem(pfx, mem_err);
- else
- goto err_section_too_small;
- } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PCIE)) {
- struct cper_sec_pcie *pcie = (void *)(gdata + 1);
- printk("%s""section_type: PCIe error\n", pfx);
- if (gdata->error_data_length >= sizeof(*pcie))
- cper_print_pcie(pfx, pcie, gdata);
- else
- goto err_section_too_small;
- } else
- printk("%s""section type: unknown, %pUl\n", pfx, sec_type);
-
- return;
-
-err_section_too_small:
- pr_err(FW_WARN "error section length is too small\n");
-}
-
-void apei_estatus_print(const char *pfx,
- const struct acpi_hest_generic_status *estatus)
-{
- struct acpi_hest_generic_data *gdata;
- unsigned int data_len, gedata_len;
- int sec_no = 0;
- __u16 severity;
-
- printk("%s""APEI generic hardware error status\n", pfx);
- severity = estatus->error_severity;
- printk("%s""severity: %d, %s\n", pfx, severity,
- cper_severity_str(severity));
- data_len = estatus->data_length;
- gdata = (struct acpi_hest_generic_data *)(estatus + 1);
- while (data_len > sizeof(*gdata)) {
- gedata_len = gdata->error_data_length;
- apei_estatus_print_section(pfx, gdata, sec_no);
- data_len -= gedata_len + sizeof(*gdata);
- gdata = (void *)(gdata + 1) + gedata_len;
- sec_no++;
- }
-}
-EXPORT_SYMBOL_GPL(apei_estatus_print);
-
-int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus)
-{
- if (estatus->data_length &&
- estatus->data_length < sizeof(struct acpi_hest_generic_data))
- return -EINVAL;
- if (estatus->raw_data_length &&
- estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length)
- return -EINVAL;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(apei_estatus_check_header);
-
-int apei_estatus_check(const struct acpi_hest_generic_status *estatus)
-{
- struct acpi_hest_generic_data *gdata;
- unsigned int data_len, gedata_len;
- int rc;
-
- rc = apei_estatus_check_header(estatus);
- if (rc)
- return rc;
- data_len = estatus->data_length;
- gdata = (struct acpi_hest_generic_data *)(estatus + 1);
- while (data_len >= sizeof(*gdata)) {
- gedata_len = gdata->error_data_length;
- if (gedata_len > data_len - sizeof(*gdata))
- return -EINVAL;
- data_len -= gedata_len + sizeof(*gdata);
- gdata = (void *)(gdata + 1) + gedata_len;
- }
- if (data_len)
- return -EINVAL;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(apei_estatus_check);
diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c
index fb57d03e698..a095d4f858d 100644
--- a/drivers/acpi/apei/einj.c
+++ b/drivers/acpi/apei/einj.c
@@ -33,7 +33,7 @@
#include <linux/nmi.h>
#include <linux/delay.h>
#include <linux/mm.h>
-#include <acpi/acpi.h>
+#include <asm/unaligned.h>
#include "apei-internal.h"
@@ -202,7 +202,7 @@ static void check_vendor_extension(u64 paddr,
if (!offset)
return;
- v = acpi_os_map_memory(paddr + offset, sizeof(*v));
+ v = acpi_os_map_iomem(paddr + offset, sizeof(*v));
if (!v)
return;
sbdf = v->pcie_sbdf;
@@ -210,13 +210,13 @@ static void check_vendor_extension(u64 paddr,
sbdf >> 24, (sbdf >> 16) & 0xff,
(sbdf >> 11) & 0x1f, (sbdf >> 8) & 0x7,
v->vendor_id, v->device_id, v->rev_id);
- acpi_os_unmap_memory(v, sizeof(*v));
+ acpi_os_unmap_iomem(v, sizeof(*v));
}
static void *einj_get_parameter_address(void)
{
int i;
- u64 paddrv4 = 0, paddrv5 = 0;
+ u64 pa_v4 = 0, pa_v5 = 0;
struct acpi_whea_header *entry;
entry = EINJ_TAB_ENTRY(einj_tab);
@@ -225,34 +225,32 @@ static void *einj_get_parameter_address(void)
entry->instruction == ACPI_EINJ_WRITE_REGISTER &&
entry->register_region.space_id ==
ACPI_ADR_SPACE_SYSTEM_MEMORY)
- memcpy(&paddrv4, &entry->register_region.address,
- sizeof(paddrv4));
+ pa_v4 = get_unaligned(&entry->register_region.address);
if (entry->action == ACPI_EINJ_SET_ERROR_TYPE_WITH_ADDRESS &&
entry->instruction == ACPI_EINJ_WRITE_REGISTER &&
entry->register_region.space_id ==
ACPI_ADR_SPACE_SYSTEM_MEMORY)
- memcpy(&paddrv5, &entry->register_region.address,
- sizeof(paddrv5));
+ pa_v5 = get_unaligned(&entry->register_region.address);
entry++;
}
- if (paddrv5) {
+ if (pa_v5) {
struct set_error_type_with_address *v5param;
- v5param = acpi_os_map_memory(paddrv5, sizeof(*v5param));
+ v5param = acpi_os_map_iomem(pa_v5, sizeof(*v5param));
if (v5param) {
acpi5 = 1;
- check_vendor_extension(paddrv5, v5param);
+ check_vendor_extension(pa_v5, v5param);
return v5param;
}
}
- if (param_extension && paddrv4) {
+ if (param_extension && pa_v4) {
struct einj_parameter *v4param;
- v4param = acpi_os_map_memory(paddrv4, sizeof(*v4param));
+ v4param = acpi_os_map_iomem(pa_v4, sizeof(*v4param));
if (!v4param)
return NULL;
if (v4param->reserved1 || v4param->reserved2) {
- acpi_os_unmap_memory(v4param, sizeof(*v4param));
+ acpi_os_unmap_iomem(v4param, sizeof(*v4param));
return NULL;
}
return v4param;
@@ -416,7 +414,8 @@ out:
return rc;
}
-static int __einj_error_inject(u32 type, u64 param1, u64 param2)
+static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
+ u64 param3, u64 param4)
{
struct apei_exec_context ctx;
u64 val, trigger_paddr, timeout = FIRMWARE_TIMEOUT;
@@ -446,6 +445,12 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2)
break;
}
v5param->flags = vendor_flags;
+ } else if (flags) {
+ v5param->flags = flags;
+ v5param->memory_address = param1;
+ v5param->memory_address_range = param2;
+ v5param->apicid = param3;
+ v5param->pcie_sbdf = param4;
} else {
switch (type) {
case ACPI_EINJ_PROCESSOR_CORRECTABLE:
@@ -514,11 +519,17 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2)
}
/* Inject the specified hardware error */
-static int einj_error_inject(u32 type, u64 param1, u64 param2)
+static int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
+ u64 param3, u64 param4)
{
int rc;
unsigned long pfn;
+ /* If user manually set "flags", make sure it is legal */
+ if (flags && (flags &
+ ~(SETWA_FLAGS_APICID|SETWA_FLAGS_MEM|SETWA_FLAGS_PCIE_SBDF)))
+ return -EINVAL;
+
/*
* We need extra sanity checks for memory errors.
* Other types leap directly to injection.
@@ -532,7 +543,7 @@ static int einj_error_inject(u32 type, u64 param1, u64 param2)
if (type & ACPI5_VENDOR_BIT) {
if (vendor_flags != SETWA_FLAGS_MEM)
goto inject;
- } else if (!(type & MEM_ERROR_MASK))
+ } else if (!(type & MEM_ERROR_MASK) && !(flags & SETWA_FLAGS_MEM))
goto inject;
/*
@@ -546,15 +557,18 @@ static int einj_error_inject(u32 type, u64 param1, u64 param2)
inject:
mutex_lock(&einj_mutex);
- rc = __einj_error_inject(type, param1, param2);
+ rc = __einj_error_inject(type, flags, param1, param2, param3, param4);
mutex_unlock(&einj_mutex);
return rc;
}
static u32 error_type;
+static u32 error_flags;
static u64 error_param1;
static u64 error_param2;
+static u64 error_param3;
+static u64 error_param4;
static struct dentry *einj_debug_dir;
static int available_error_type_show(struct seq_file *m, void *v)
@@ -648,7 +662,8 @@ static int error_inject_set(void *data, u64 val)
if (!error_type)
return -EINVAL;
- return einj_error_inject(error_type, error_param1, error_param2);
+ return einj_error_inject(error_type, error_flags, error_param1, error_param2,
+ error_param3, error_param4);
}
DEFINE_SIMPLE_ATTRIBUTE(error_inject_fops, NULL,
@@ -729,6 +744,10 @@ static int __init einj_init(void)
rc = -ENOMEM;
einj_param = einj_get_parameter_address();
if ((param_extension || acpi5) && einj_param) {
+ fentry = debugfs_create_x32("flags", S_IRUSR | S_IWUSR,
+ einj_debug_dir, &error_flags);
+ if (!fentry)
+ goto err_unmap;
fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR,
einj_debug_dir, &error_param1);
if (!fentry)
@@ -737,6 +756,14 @@ static int __init einj_init(void)
einj_debug_dir, &error_param2);
if (!fentry)
goto err_unmap;
+ fentry = debugfs_create_x64("param3", S_IRUSR | S_IWUSR,
+ einj_debug_dir, &error_param3);
+ if (!fentry)
+ goto err_unmap;
+ fentry = debugfs_create_x64("param4", S_IRUSR | S_IWUSR,
+ einj_debug_dir, &error_param4);
+ if (!fentry)
+ goto err_unmap;
fentry = debugfs_create_x32("notrigger", S_IRUSR | S_IWUSR,
einj_debug_dir, &notrigger);
@@ -767,7 +794,7 @@ err_unmap:
sizeof(struct set_error_type_with_address) :
sizeof(struct einj_parameter);
- acpi_os_unmap_memory(einj_param, size);
+ acpi_os_unmap_iomem(einj_param, size);
}
apei_exec_post_unmap_gars(&ctx);
err_release:
@@ -789,7 +816,7 @@ static void __exit einj_exit(void)
sizeof(struct set_error_type_with_address) :
sizeof(struct einj_parameter);
- acpi_os_unmap_memory(einj_param, size);
+ acpi_os_unmap_iomem(einj_param, size);
}
einj_exec_ctx_init(&ctx);
apei_exec_post_unmap_gars(&ctx);
diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c
index 26311f23c82..ed65e9c4b5b 100644
--- a/drivers/acpi/apei/erst.c
+++ b/drivers/acpi/apei/erst.c
@@ -611,7 +611,7 @@ static void __erst_record_id_cache_compact(void)
if (entries[i] == APEI_ERST_INVALID_RECORD_ID)
continue;
if (wpos != i)
- memcpy(&entries[wpos], &entries[i], sizeof(entries[i]));
+ entries[wpos] = entries[i];
wpos++;
}
erst_record_id_cache.len = wpos;
@@ -942,6 +942,7 @@ static int erst_clearer(enum pstore_type_id type, u64 id, int count,
static struct pstore_info erst_info = {
.owner = THIS_MODULE,
.name = "erst",
+ .flags = PSTORE_FLAGS_FRAGILE,
.open = erst_open_pstore,
.close = erst_close_pstore,
.read = erst_reader,
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 8ec37bbdd69..dab7cb7349d 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -33,7 +33,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/acpi.h>
-#include <linux/acpi_io.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
@@ -75,13 +74,13 @@
#define GHES_ESTATUS_CACHE_LEN(estatus_len) \
(sizeof(struct ghes_estatus_cache) + (estatus_len))
#define GHES_ESTATUS_FROM_CACHE(estatus_cache) \
- ((struct acpi_hest_generic_status *) \
+ ((struct acpi_generic_status *) \
((struct ghes_estatus_cache *)(estatus_cache) + 1))
#define GHES_ESTATUS_NODE_LEN(estatus_len) \
(sizeof(struct ghes_estatus_node) + (estatus_len))
-#define GHES_ESTATUS_FROM_NODE(estatus_node) \
- ((struct acpi_hest_generic_status *) \
+#define GHES_ESTATUS_FROM_NODE(estatus_node) \
+ ((struct acpi_generic_status *) \
((struct ghes_estatus_node *)(estatus_node) + 1))
bool ghes_disable;
@@ -378,17 +377,17 @@ static int ghes_read_estatus(struct ghes *ghes, int silent)
ghes->flags |= GHES_TO_CLEAR;
rc = -EIO;
- len = apei_estatus_len(ghes->estatus);
+ len = cper_estatus_len(ghes->estatus);
if (len < sizeof(*ghes->estatus))
goto err_read_block;
if (len > ghes->generic->error_block_length)
goto err_read_block;
- if (apei_estatus_check_header(ghes->estatus))
+ if (cper_estatus_check_header(ghes->estatus))
goto err_read_block;
ghes_copy_tofrom_phys(ghes->estatus + 1,
buf_paddr + sizeof(*ghes->estatus),
len - sizeof(*ghes->estatus), 1);
- if (apei_estatus_check(ghes->estatus))
+ if (cper_estatus_check(ghes->estatus))
goto err_read_block;
rc = 0;
@@ -409,39 +408,43 @@ static void ghes_clear_estatus(struct ghes *ghes)
ghes->flags &= ~GHES_TO_CLEAR;
}
-static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int sev)
+static void ghes_handle_memory_failure(struct acpi_generic_data *gdata, int sev)
{
#ifdef CONFIG_ACPI_APEI_MEMORY_FAILURE
unsigned long pfn;
+ int flags = -1;
int sec_sev = ghes_severity(gdata->error_severity);
struct cper_sec_mem_err *mem_err;
mem_err = (struct cper_sec_mem_err *)(gdata + 1);
- if (sec_sev == GHES_SEV_CORRECTED &&
- (gdata->flags & CPER_SEC_ERROR_THRESHOLD_EXCEEDED) &&
- (mem_err->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS)) {
- pfn = mem_err->physical_addr >> PAGE_SHIFT;
- if (pfn_valid(pfn))
- memory_failure_queue(pfn, 0, MF_SOFT_OFFLINE);
- else if (printk_ratelimit())
- pr_warn(FW_WARN GHES_PFX
- "Invalid address in generic error data: %#llx\n",
- mem_err->physical_addr);
- }
- if (sev == GHES_SEV_RECOVERABLE &&
- sec_sev == GHES_SEV_RECOVERABLE &&
- mem_err->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS) {
- pfn = mem_err->physical_addr >> PAGE_SHIFT;
- memory_failure_queue(pfn, 0, 0);
+ if (!(mem_err->validation_bits & CPER_MEM_VALID_PA))
+ return;
+
+ pfn = mem_err->physical_addr >> PAGE_SHIFT;
+ if (!pfn_valid(pfn)) {
+ pr_warn_ratelimited(FW_WARN GHES_PFX
+ "Invalid address in generic error data: %#llx\n",
+ mem_err->physical_addr);
+ return;
}
+
+ /* iff following two events can be handled properly by now */
+ if (sec_sev == GHES_SEV_CORRECTED &&
+ (gdata->flags & CPER_SEC_ERROR_THRESHOLD_EXCEEDED))
+ flags = MF_SOFT_OFFLINE;
+ if (sev == GHES_SEV_RECOVERABLE && sec_sev == GHES_SEV_RECOVERABLE)
+ flags = 0;
+
+ if (flags != -1)
+ memory_failure_queue(pfn, 0, flags);
#endif
}
static void ghes_do_proc(struct ghes *ghes,
- const struct acpi_hest_generic_status *estatus)
+ const struct acpi_generic_status *estatus)
{
int sev, sec_sev;
- struct acpi_hest_generic_data *gdata;
+ struct acpi_generic_data *gdata;
sev = ghes_severity(estatus->error_severity);
apei_estatus_for_each_section(estatus, gdata) {
@@ -453,8 +456,7 @@ static void ghes_do_proc(struct ghes *ghes,
ghes_edac_report_mem_error(ghes, sev, mem_err);
#ifdef CONFIG_X86_MCE
- apei_mce_report_mem_error(sev == GHES_SEV_CORRECTED,
- mem_err);
+ apei_mce_report_mem_error(sev, mem_err);
#endif
ghes_handle_memory_failure(gdata, sev);
}
@@ -496,7 +498,7 @@ static void ghes_do_proc(struct ghes *ghes,
static void __ghes_print_estatus(const char *pfx,
const struct acpi_hest_generic *generic,
- const struct acpi_hest_generic_status *estatus)
+ const struct acpi_generic_status *estatus)
{
static atomic_t seqno;
unsigned int curr_seqno;
@@ -513,12 +515,12 @@ static void __ghes_print_estatus(const char *pfx,
snprintf(pfx_seq, sizeof(pfx_seq), "%s{%u}" HW_ERR, pfx, curr_seqno);
printk("%s""Hardware error from APEI Generic Hardware Error Source: %d\n",
pfx_seq, generic->header.source_id);
- apei_estatus_print(pfx_seq, estatus);
+ cper_estatus_print(pfx_seq, estatus);
}
static int ghes_print_estatus(const char *pfx,
const struct acpi_hest_generic *generic,
- const struct acpi_hest_generic_status *estatus)
+ const struct acpi_generic_status *estatus)
{
/* Not more than 2 messages every 5 seconds */
static DEFINE_RATELIMIT_STATE(ratelimit_corrected, 5*HZ, 2);
@@ -540,15 +542,15 @@ static int ghes_print_estatus(const char *pfx,
* GHES error status reporting throttle, to report more kinds of
* errors, instead of just most frequently occurred errors.
*/
-static int ghes_estatus_cached(struct acpi_hest_generic_status *estatus)
+static int ghes_estatus_cached(struct acpi_generic_status *estatus)
{
u32 len;
int i, cached = 0;
unsigned long long now;
struct ghes_estatus_cache *cache;
- struct acpi_hest_generic_status *cache_estatus;
+ struct acpi_generic_status *cache_estatus;
- len = apei_estatus_len(estatus);
+ len = cper_estatus_len(estatus);
rcu_read_lock();
for (i = 0; i < GHES_ESTATUS_CACHES_SIZE; i++) {
cache = rcu_dereference(ghes_estatus_caches[i]);
@@ -571,19 +573,19 @@ static int ghes_estatus_cached(struct acpi_hest_generic_status *estatus)
static struct ghes_estatus_cache *ghes_estatus_cache_alloc(
struct acpi_hest_generic *generic,
- struct acpi_hest_generic_status *estatus)
+ struct acpi_generic_status *estatus)
{
int alloced;
u32 len, cache_len;
struct ghes_estatus_cache *cache;
- struct acpi_hest_generic_status *cache_estatus;
+ struct acpi_generic_status *cache_estatus;
alloced = atomic_add_return(1, &ghes_estatus_cache_alloced);
if (alloced > GHES_ESTATUS_CACHE_ALLOCED_MAX) {
atomic_dec(&ghes_estatus_cache_alloced);
return NULL;
}
- len = apei_estatus_len(estatus);
+ len = cper_estatus_len(estatus);
cache_len = GHES_ESTATUS_CACHE_LEN(len);
cache = (void *)gen_pool_alloc(ghes_estatus_pool, cache_len);
if (!cache) {
@@ -603,7 +605,7 @@ static void ghes_estatus_cache_free(struct ghes_estatus_cache *cache)
{
u32 len;
- len = apei_estatus_len(GHES_ESTATUS_FROM_CACHE(cache));
+ len = cper_estatus_len(GHES_ESTATUS_FROM_CACHE(cache));
len = GHES_ESTATUS_CACHE_LEN(len);
gen_pool_free(ghes_estatus_pool, (unsigned long)cache, len);
atomic_dec(&ghes_estatus_cache_alloced);
@@ -619,7 +621,7 @@ static void ghes_estatus_cache_rcu_free(struct rcu_head *head)
static void ghes_estatus_cache_add(
struct acpi_hest_generic *generic,
- struct acpi_hest_generic_status *estatus)
+ struct acpi_generic_status *estatus)
{
int i, slot = -1, count;
unsigned long long now, duration, period, max_period = 0;
@@ -751,7 +753,7 @@ static void ghes_proc_in_irq(struct irq_work *irq_work)
struct llist_node *llnode, *next;
struct ghes_estatus_node *estatus_node;
struct acpi_hest_generic *generic;
- struct acpi_hest_generic_status *estatus;
+ struct acpi_generic_status *estatus;
u32 len, node_len;
llnode = llist_del_all(&ghes_estatus_llist);
@@ -765,7 +767,7 @@ static void ghes_proc_in_irq(struct irq_work *irq_work)
estatus_node = llist_entry(llnode, struct ghes_estatus_node,
llnode);
estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
- len = apei_estatus_len(estatus);
+ len = cper_estatus_len(estatus);
node_len = GHES_ESTATUS_NODE_LEN(len);
ghes_do_proc(estatus_node->ghes, estatus);
if (!ghes_estatus_cached(estatus)) {
@@ -784,7 +786,7 @@ static void ghes_print_queued_estatus(void)
struct llist_node *llnode;
struct ghes_estatus_node *estatus_node;
struct acpi_hest_generic *generic;
- struct acpi_hest_generic_status *estatus;
+ struct acpi_generic_status *estatus;
u32 len, node_len;
llnode = llist_del_all(&ghes_estatus_llist);
@@ -797,7 +799,7 @@ static void ghes_print_queued_estatus(void)
estatus_node = llist_entry(llnode, struct ghes_estatus_node,
llnode);
estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
- len = apei_estatus_len(estatus);
+ len = cper_estatus_len(estatus);
node_len = GHES_ESTATUS_NODE_LEN(len);
generic = estatus_node->generic;
ghes_print_estatus(NULL, generic, estatus);
@@ -843,7 +845,7 @@ static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs)
#ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
u32 len, node_len;
struct ghes_estatus_node *estatus_node;
- struct acpi_hest_generic_status *estatus;
+ struct acpi_generic_status *estatus;
#endif
if (!(ghes->flags & GHES_TO_CLEAR))
continue;
@@ -851,7 +853,7 @@ static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs)
if (ghes_estatus_cached(ghes->estatus))
goto next;
/* Save estatus for further processing in IRQ context */
- len = apei_estatus_len(ghes->estatus);
+ len = cper_estatus_len(ghes->estatus);
node_len = GHES_ESTATUS_NODE_LEN(len);
estatus_node = (void *)gen_pool_alloc(ghes_estatus_pool,
node_len);
@@ -923,7 +925,7 @@ static int ghes_probe(struct platform_device *ghes_dev)
rc = -EIO;
if (generic->error_block_length <
- sizeof(struct acpi_hest_generic_status)) {
+ sizeof(struct acpi_generic_status)) {
pr_warning(FW_BUG GHES_PFX "Invalid error block length: %u for generic hardware error source: %d\n",
generic->error_block_length,
generic->header.source_id);