diff options
Diffstat (limited to 'drivers/acpi/apei')
| -rw-r--r-- | drivers/acpi/apei/Kconfig | 3 | ||||
| -rw-r--r-- | drivers/acpi/apei/Makefile | 2 | ||||
| -rw-r--r-- | drivers/acpi/apei/apei-base.c | 11 | ||||
| -rw-r--r-- | drivers/acpi/apei/apei-internal.h | 13 | ||||
| -rw-r--r-- | drivers/acpi/apei/cper.c | 402 | ||||
| -rw-r--r-- | drivers/acpi/apei/einj.c | 69 | ||||
| -rw-r--r-- | drivers/acpi/apei/erst.c | 3 | ||||
| -rw-r--r-- | drivers/acpi/apei/ghes.c | 94 | 
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, ®->address, sizeof(*paddr)); +	*paddr = get_unaligned(®->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, ¬rigger); @@ -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);  | 
