brintos

brintos / linux-shallow public Read only

0
0
Text · 24.0 KiB · 5c22720 Raw
921 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * APEI Error INJection support4 *5 * EINJ provides a hardware error injection mechanism, this is useful6 * for debugging and testing of other APEI and RAS features.7 *8 * For more information about EINJ, please refer to ACPI Specification9 * version 4.0, section 17.5.10 *11 * Copyright 2009-2010 Intel Corp.12 *   Author: Huang Ying <ying.huang@intel.com>13 */14 15#include <linux/kernel.h>16#include <linux/module.h>17#include <linux/init.h>18#include <linux/io.h>19#include <linux/debugfs.h>20#include <linux/seq_file.h>21#include <linux/nmi.h>22#include <linux/delay.h>23#include <linux/mm.h>24#include <linux/platform_device.h>25#include <linux/unaligned.h>26 27#include "apei-internal.h"28 29#undef pr_fmt30#define pr_fmt(fmt) "EINJ: " fmt31 32#define SLEEP_UNIT_MIN		1000			/* 1ms */33#define SLEEP_UNIT_MAX		5000			/* 5ms */34/* Firmware should respond within 1 seconds */35#define FIRMWARE_TIMEOUT	(1 * USEC_PER_SEC)36#define ACPI5_VENDOR_BIT	BIT(31)37#define MEM_ERROR_MASK		(ACPI_EINJ_MEMORY_CORRECTABLE | \38				ACPI_EINJ_MEMORY_UNCORRECTABLE | \39				ACPI_EINJ_MEMORY_FATAL)40#define CXL_ERROR_MASK		(ACPI_EINJ_CXL_CACHE_CORRECTABLE | \41				ACPI_EINJ_CXL_CACHE_UNCORRECTABLE | \42				ACPI_EINJ_CXL_CACHE_FATAL | \43				ACPI_EINJ_CXL_MEM_CORRECTABLE | \44				ACPI_EINJ_CXL_MEM_UNCORRECTABLE | \45				ACPI_EINJ_CXL_MEM_FATAL)46 47/*48 * ACPI version 5 provides a SET_ERROR_TYPE_WITH_ADDRESS action.49 */50static int acpi5;51 52struct set_error_type_with_address {53	u32	type;54	u32	vendor_extension;55	u32	flags;56	u32	apicid;57	u64	memory_address;58	u64	memory_address_range;59	u32	pcie_sbdf;60};61enum {62	SETWA_FLAGS_APICID = 1,63	SETWA_FLAGS_MEM = 2,64	SETWA_FLAGS_PCIE_SBDF = 4,65};66 67/*68 * Vendor extensions for platform specific operations69 */70struct vendor_error_type_extension {71	u32	length;72	u32	pcie_sbdf;73	u16	vendor_id;74	u16	device_id;75	u8	rev_id;76	u8	reserved[3];77};78 79static u32 notrigger;80 81static u32 vendor_flags;82static struct debugfs_blob_wrapper vendor_blob;83static struct debugfs_blob_wrapper vendor_errors;84static char vendor_dev[64];85 86/*87 * Some BIOSes allow parameters to the SET_ERROR_TYPE entries in the88 * EINJ table through an unpublished extension. Use with caution as89 * most will ignore the parameter and make their own choice of address90 * for error injection.  This extension is used only if91 * param_extension module parameter is specified.92 */93struct einj_parameter {94	u64 type;95	u64 reserved1;96	u64 reserved2;97	u64 param1;98	u64 param2;99};100 101#define EINJ_OP_BUSY			0x1102#define EINJ_STATUS_SUCCESS		0x0103#define EINJ_STATUS_FAIL		0x1104#define EINJ_STATUS_INVAL		0x2105 106#define EINJ_TAB_ENTRY(tab)						\107	((struct acpi_whea_header *)((char *)(tab) +			\108				    sizeof(struct acpi_table_einj)))109 110static bool param_extension;111module_param(param_extension, bool, 0);112 113static struct acpi_table_einj *einj_tab;114 115static struct apei_resources einj_resources;116 117static struct apei_exec_ins_type einj_ins_type[] = {118	[ACPI_EINJ_READ_REGISTER] = {119		.flags = APEI_EXEC_INS_ACCESS_REGISTER,120		.run   = apei_exec_read_register,121	},122	[ACPI_EINJ_READ_REGISTER_VALUE] = {123		.flags = APEI_EXEC_INS_ACCESS_REGISTER,124		.run   = apei_exec_read_register_value,125	},126	[ACPI_EINJ_WRITE_REGISTER] = {127		.flags = APEI_EXEC_INS_ACCESS_REGISTER,128		.run   = apei_exec_write_register,129	},130	[ACPI_EINJ_WRITE_REGISTER_VALUE] = {131		.flags = APEI_EXEC_INS_ACCESS_REGISTER,132		.run   = apei_exec_write_register_value,133	},134	[ACPI_EINJ_NOOP] = {135		.flags = 0,136		.run   = apei_exec_noop,137	},138};139 140/*141 * Prevent EINJ interpreter to run simultaneously, because the142 * corresponding firmware implementation may not work properly when143 * invoked simultaneously.144 */145static DEFINE_MUTEX(einj_mutex);146 147/*148 * Exported APIs use this flag to exit early if einj_probe() failed.149 */150bool einj_initialized __ro_after_init;151 152static void *einj_param;153 154static void einj_exec_ctx_init(struct apei_exec_context *ctx)155{156	apei_exec_ctx_init(ctx, einj_ins_type, ARRAY_SIZE(einj_ins_type),157			   EINJ_TAB_ENTRY(einj_tab), einj_tab->entries);158}159 160static int __einj_get_available_error_type(u32 *type)161{162	struct apei_exec_context ctx;163	int rc;164 165	einj_exec_ctx_init(&ctx);166	rc = apei_exec_run(&ctx, ACPI_EINJ_GET_ERROR_TYPE);167	if (rc)168		return rc;169	*type = apei_exec_ctx_get_output(&ctx);170 171	return 0;172}173 174/* Get error injection capabilities of the platform */175int einj_get_available_error_type(u32 *type)176{177	int rc;178 179	mutex_lock(&einj_mutex);180	rc = __einj_get_available_error_type(type);181	mutex_unlock(&einj_mutex);182 183	return rc;184}185 186static int einj_timedout(u64 *t)187{188	if ((s64)*t < SLEEP_UNIT_MIN) {189		pr_warn(FW_WARN "Firmware does not respond in time\n");190		return 1;191	}192	*t -= SLEEP_UNIT_MIN;193	usleep_range(SLEEP_UNIT_MIN, SLEEP_UNIT_MAX);194 195	return 0;196}197 198static void get_oem_vendor_struct(u64 paddr, int offset,199				  struct vendor_error_type_extension *v)200{201	unsigned long vendor_size;202	u64 target_pa = paddr + offset + sizeof(struct vendor_error_type_extension);203 204	vendor_size = v->length - sizeof(struct vendor_error_type_extension);205 206	if (vendor_size)207		vendor_errors.data = acpi_os_map_memory(target_pa, vendor_size);208 209	if (vendor_errors.data)210		vendor_errors.size = vendor_size;211}212 213static void check_vendor_extension(u64 paddr,214				   struct set_error_type_with_address *v5param)215{216	int	offset = v5param->vendor_extension;217	struct	vendor_error_type_extension *v;218	u32	sbdf;219 220	if (!offset)221		return;222	v = acpi_os_map_iomem(paddr + offset, sizeof(*v));223	if (!v)224		return;225	get_oem_vendor_struct(paddr, offset, v);226	sbdf = v->pcie_sbdf;227	sprintf(vendor_dev, "%x:%x:%x.%x vendor_id=%x device_id=%x rev_id=%x\n",228		sbdf >> 24, (sbdf >> 16) & 0xff,229		(sbdf >> 11) & 0x1f, (sbdf >> 8) & 0x7,230		 v->vendor_id, v->device_id, v->rev_id);231	acpi_os_unmap_iomem(v, sizeof(*v));232}233 234static void *einj_get_parameter_address(void)235{236	int i;237	u64 pa_v4 = 0, pa_v5 = 0;238	struct acpi_whea_header *entry;239 240	entry = EINJ_TAB_ENTRY(einj_tab);241	for (i = 0; i < einj_tab->entries; i++) {242		if (entry->action == ACPI_EINJ_SET_ERROR_TYPE &&243		    entry->instruction == ACPI_EINJ_WRITE_REGISTER &&244		    entry->register_region.space_id ==245		    ACPI_ADR_SPACE_SYSTEM_MEMORY)246			pa_v4 = get_unaligned(&entry->register_region.address);247		if (entry->action == ACPI_EINJ_SET_ERROR_TYPE_WITH_ADDRESS &&248		    entry->instruction == ACPI_EINJ_WRITE_REGISTER &&249		    entry->register_region.space_id ==250		    ACPI_ADR_SPACE_SYSTEM_MEMORY)251			pa_v5 = get_unaligned(&entry->register_region.address);252		entry++;253	}254	if (pa_v5) {255		struct set_error_type_with_address *v5param;256 257		v5param = acpi_os_map_iomem(pa_v5, sizeof(*v5param));258		if (v5param) {259			acpi5 = 1;260			check_vendor_extension(pa_v5, v5param);261			return v5param;262		}263	}264	if (param_extension && pa_v4) {265		struct einj_parameter *v4param;266 267		v4param = acpi_os_map_iomem(pa_v4, sizeof(*v4param));268		if (!v4param)269			return NULL;270		if (v4param->reserved1 || v4param->reserved2) {271			acpi_os_unmap_iomem(v4param, sizeof(*v4param));272			return NULL;273		}274		return v4param;275	}276 277	return NULL;278}279 280/* do sanity check to trigger table */281static int einj_check_trigger_header(struct acpi_einj_trigger *trigger_tab)282{283	if (trigger_tab->header_size != sizeof(struct acpi_einj_trigger))284		return -EINVAL;285	if (trigger_tab->table_size > PAGE_SIZE ||286	    trigger_tab->table_size < trigger_tab->header_size)287		return -EINVAL;288	if (trigger_tab->entry_count !=289	    (trigger_tab->table_size - trigger_tab->header_size) /290	    sizeof(struct acpi_einj_entry))291		return -EINVAL;292 293	return 0;294}295 296static struct acpi_generic_address *einj_get_trigger_parameter_region(297	struct acpi_einj_trigger *trigger_tab, u64 param1, u64 param2)298{299	int i;300	struct acpi_whea_header *entry;301 302	entry = (struct acpi_whea_header *)303		((char *)trigger_tab + sizeof(struct acpi_einj_trigger));304	for (i = 0; i < trigger_tab->entry_count; i++) {305		if (entry->action == ACPI_EINJ_TRIGGER_ERROR &&306		entry->instruction <= ACPI_EINJ_WRITE_REGISTER_VALUE &&307		entry->register_region.space_id ==308			ACPI_ADR_SPACE_SYSTEM_MEMORY &&309		(entry->register_region.address & param2) == (param1 & param2))310			return &entry->register_region;311		entry++;312	}313 314	return NULL;315}316/* Execute instructions in trigger error action table */317static int __einj_error_trigger(u64 trigger_paddr, u32 type,318				u64 param1, u64 param2)319{320	struct acpi_einj_trigger *trigger_tab = NULL;321	struct apei_exec_context trigger_ctx;322	struct apei_resources trigger_resources;323	struct acpi_whea_header *trigger_entry;324	struct resource *r;325	u32 table_size;326	int rc = -EIO;327	struct acpi_generic_address *trigger_param_region = NULL;328 329	r = request_mem_region(trigger_paddr, sizeof(*trigger_tab),330			       "APEI EINJ Trigger Table");331	if (!r) {332		pr_err("Can not request [mem %#010llx-%#010llx] for Trigger table\n",333		       (unsigned long long)trigger_paddr,334		       (unsigned long long)trigger_paddr +335			    sizeof(*trigger_tab) - 1);336		goto out;337	}338	trigger_tab = ioremap_cache(trigger_paddr, sizeof(*trigger_tab));339	if (!trigger_tab) {340		pr_err("Failed to map trigger table!\n");341		goto out_rel_header;342	}343	rc = einj_check_trigger_header(trigger_tab);344	if (rc) {345		pr_warn(FW_BUG "Invalid trigger error action table.\n");346		goto out_rel_header;347	}348 349	/* No action structures in the TRIGGER_ERROR table, nothing to do */350	if (!trigger_tab->entry_count)351		goto out_rel_header;352 353	rc = -EIO;354	table_size = trigger_tab->table_size;355	r = request_mem_region(trigger_paddr + sizeof(*trigger_tab),356			       table_size - sizeof(*trigger_tab),357			       "APEI EINJ Trigger Table");358	if (!r) {359		pr_err("Can not request [mem %#010llx-%#010llx] for Trigger Table Entry\n",360		       (unsigned long long)trigger_paddr + sizeof(*trigger_tab),361		       (unsigned long long)trigger_paddr + table_size - 1);362		goto out_rel_header;363	}364	iounmap(trigger_tab);365	trigger_tab = ioremap_cache(trigger_paddr, table_size);366	if (!trigger_tab) {367		pr_err("Failed to map trigger table!\n");368		goto out_rel_entry;369	}370	trigger_entry = (struct acpi_whea_header *)371		((char *)trigger_tab + sizeof(struct acpi_einj_trigger));372	apei_resources_init(&trigger_resources);373	apei_exec_ctx_init(&trigger_ctx, einj_ins_type,374			   ARRAY_SIZE(einj_ins_type),375			   trigger_entry, trigger_tab->entry_count);376	rc = apei_exec_collect_resources(&trigger_ctx, &trigger_resources);377	if (rc)378		goto out_fini;379	rc = apei_resources_sub(&trigger_resources, &einj_resources);380	if (rc)381		goto out_fini;382	/*383	 * Some firmware will access target address specified in384	 * param1 to trigger the error when injecting memory error.385	 * This will cause resource conflict with regular memory.  So386	 * remove it from trigger table resources.387	 */388	if ((param_extension || acpi5) && (type & MEM_ERROR_MASK) && param2) {389		struct apei_resources addr_resources;390 391		apei_resources_init(&addr_resources);392		trigger_param_region = einj_get_trigger_parameter_region(393			trigger_tab, param1, param2);394		if (trigger_param_region) {395			rc = apei_resources_add(&addr_resources,396				trigger_param_region->address,397				trigger_param_region->bit_width/8, true);398			if (rc)399				goto out_fini;400			rc = apei_resources_sub(&trigger_resources,401					&addr_resources);402		}403		apei_resources_fini(&addr_resources);404		if (rc)405			goto out_fini;406	}407	rc = apei_resources_request(&trigger_resources, "APEI EINJ Trigger");408	if (rc)409		goto out_fini;410	rc = apei_exec_pre_map_gars(&trigger_ctx);411	if (rc)412		goto out_release;413 414	rc = apei_exec_run(&trigger_ctx, ACPI_EINJ_TRIGGER_ERROR);415 416	apei_exec_post_unmap_gars(&trigger_ctx);417out_release:418	apei_resources_release(&trigger_resources);419out_fini:420	apei_resources_fini(&trigger_resources);421out_rel_entry:422	release_mem_region(trigger_paddr + sizeof(*trigger_tab),423			   table_size - sizeof(*trigger_tab));424out_rel_header:425	release_mem_region(trigger_paddr, sizeof(*trigger_tab));426out:427	if (trigger_tab)428		iounmap(trigger_tab);429 430	return rc;431}432 433static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,434			       u64 param3, u64 param4)435{436	struct apei_exec_context ctx;437	u64 val, trigger_paddr, timeout = FIRMWARE_TIMEOUT;438	int rc;439 440	einj_exec_ctx_init(&ctx);441 442	rc = apei_exec_run_optional(&ctx, ACPI_EINJ_BEGIN_OPERATION);443	if (rc)444		return rc;445	apei_exec_ctx_set_input(&ctx, type);446	if (acpi5) {447		struct set_error_type_with_address *v5param = einj_param;448 449		v5param->type = type;450		if (type & ACPI5_VENDOR_BIT) {451			switch (vendor_flags) {452			case SETWA_FLAGS_APICID:453				v5param->apicid = param1;454				break;455			case SETWA_FLAGS_MEM:456				v5param->memory_address = param1;457				v5param->memory_address_range = param2;458				break;459			case SETWA_FLAGS_PCIE_SBDF:460				v5param->pcie_sbdf = param1;461				break;462			}463			v5param->flags = vendor_flags;464		} else if (flags) {465			v5param->flags = flags;466			v5param->memory_address = param1;467			v5param->memory_address_range = param2;468			v5param->apicid = param3;469			v5param->pcie_sbdf = param4;470		} else {471			switch (type) {472			case ACPI_EINJ_PROCESSOR_CORRECTABLE:473			case ACPI_EINJ_PROCESSOR_UNCORRECTABLE:474			case ACPI_EINJ_PROCESSOR_FATAL:475				v5param->apicid = param1;476				v5param->flags = SETWA_FLAGS_APICID;477				break;478			case ACPI_EINJ_MEMORY_CORRECTABLE:479			case ACPI_EINJ_MEMORY_UNCORRECTABLE:480			case ACPI_EINJ_MEMORY_FATAL:481				v5param->memory_address = param1;482				v5param->memory_address_range = param2;483				v5param->flags = SETWA_FLAGS_MEM;484				break;485			case ACPI_EINJ_PCIX_CORRECTABLE:486			case ACPI_EINJ_PCIX_UNCORRECTABLE:487			case ACPI_EINJ_PCIX_FATAL:488				v5param->pcie_sbdf = param1;489				v5param->flags = SETWA_FLAGS_PCIE_SBDF;490				break;491			}492		}493	} else {494		rc = apei_exec_run(&ctx, ACPI_EINJ_SET_ERROR_TYPE);495		if (rc)496			return rc;497		if (einj_param) {498			struct einj_parameter *v4param = einj_param;499 500			v4param->param1 = param1;501			v4param->param2 = param2;502		}503	}504	rc = apei_exec_run(&ctx, ACPI_EINJ_EXECUTE_OPERATION);505	if (rc)506		return rc;507	for (;;) {508		rc = apei_exec_run(&ctx, ACPI_EINJ_CHECK_BUSY_STATUS);509		if (rc)510			return rc;511		val = apei_exec_ctx_get_output(&ctx);512		if (!(val & EINJ_OP_BUSY))513			break;514		if (einj_timedout(&timeout))515			return -EIO;516	}517	rc = apei_exec_run(&ctx, ACPI_EINJ_GET_COMMAND_STATUS);518	if (rc)519		return rc;520	val = apei_exec_ctx_get_output(&ctx);521	if (val == EINJ_STATUS_FAIL)522		return -EBUSY;523	else if (val == EINJ_STATUS_INVAL)524		return -EINVAL;525 526	/*527	 * The error is injected into the platform successfully, then it needs528	 * to trigger the error.529	 */530	rc = apei_exec_run(&ctx, ACPI_EINJ_GET_TRIGGER_TABLE);531	if (rc)532		return rc;533	trigger_paddr = apei_exec_ctx_get_output(&ctx);534	if (notrigger == 0) {535		rc = __einj_error_trigger(trigger_paddr, type, param1, param2);536		if (rc)537			return rc;538	}539	rc = apei_exec_run_optional(&ctx, ACPI_EINJ_END_OPERATION);540 541	return rc;542}543 544/* Inject the specified hardware error */545int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, u64 param3,546		      u64 param4)547{548	int rc;549	u64 base_addr, size;550 551	/* If user manually set "flags", make sure it is legal */552	if (flags && (flags &553		~(SETWA_FLAGS_APICID|SETWA_FLAGS_MEM|SETWA_FLAGS_PCIE_SBDF)))554		return -EINVAL;555 556	/*557	 * We need extra sanity checks for memory errors.558	 * Other types leap directly to injection.559	 */560 561	/* ensure param1/param2 existed */562	if (!(param_extension || acpi5))563		goto inject;564 565	/* ensure injection is memory related */566	if (type & ACPI5_VENDOR_BIT) {567		if (vendor_flags != SETWA_FLAGS_MEM)568			goto inject;569	} else if (!(type & MEM_ERROR_MASK) && !(flags & SETWA_FLAGS_MEM)) {570		goto inject;571	}572 573	/*574	 * Injections targeting a CXL 1.0/1.1 port have to be injected575	 * via the einj_cxl_rch_error_inject() path as that does the proper576	 * validation of the given RCRB base (MMIO) address.577	 */578	if (einj_is_cxl_error_type(type) && (flags & SETWA_FLAGS_MEM))579		return -EINVAL;580 581	/*582	 * Disallow crazy address masks that give BIOS leeway to pick583	 * injection address almost anywhere. Insist on page or584	 * better granularity and that target address is normal RAM or585	 * NVDIMM.586	 */587	base_addr = param1 & param2;588	size = ~param2 + 1;589 590	if (((param2 & PAGE_MASK) != PAGE_MASK) ||591	    ((region_intersects(base_addr, size, IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE)592				!= REGION_INTERSECTS) &&593	     (region_intersects(base_addr, size, IORESOURCE_MEM, IORES_DESC_PERSISTENT_MEMORY)594				!= REGION_INTERSECTS) &&595	     (region_intersects(base_addr, size, IORESOURCE_MEM, IORES_DESC_SOFT_RESERVED)596				!= REGION_INTERSECTS) &&597	     !arch_is_platform_page(base_addr)))598		return -EINVAL;599 600	if (is_zero_pfn(base_addr >> PAGE_SHIFT))601		return -EADDRINUSE;602 603inject:604	mutex_lock(&einj_mutex);605	rc = __einj_error_inject(type, flags, param1, param2, param3, param4);606	mutex_unlock(&einj_mutex);607 608	return rc;609}610 611int einj_cxl_rch_error_inject(u32 type, u32 flags, u64 param1, u64 param2,612			      u64 param3, u64 param4)613{614	int rc;615 616	if (!(einj_is_cxl_error_type(type) && (flags & SETWA_FLAGS_MEM)))617		return -EINVAL;618 619	mutex_lock(&einj_mutex);620	rc = __einj_error_inject(type, flags, param1, param2, param3, param4);621	mutex_unlock(&einj_mutex);622 623	return rc;624}625 626static u32 error_type;627static u32 error_flags;628static u64 error_param1;629static u64 error_param2;630static u64 error_param3;631static u64 error_param4;632static struct dentry *einj_debug_dir;633static struct { u32 mask; const char *str; } const einj_error_type_string[] = {634	{ BIT(0), "Processor Correctable" },635	{ BIT(1), "Processor Uncorrectable non-fatal" },636	{ BIT(2), "Processor Uncorrectable fatal" },637	{ BIT(3), "Memory Correctable" },638	{ BIT(4), "Memory Uncorrectable non-fatal" },639	{ BIT(5), "Memory Uncorrectable fatal" },640	{ BIT(6), "PCI Express Correctable" },641	{ BIT(7), "PCI Express Uncorrectable non-fatal" },642	{ BIT(8), "PCI Express Uncorrectable fatal" },643	{ BIT(9), "Platform Correctable" },644	{ BIT(10), "Platform Uncorrectable non-fatal" },645	{ BIT(11), "Platform Uncorrectable fatal"},646	{ BIT(31), "Vendor Defined Error Types" },647};648 649static int available_error_type_show(struct seq_file *m, void *v)650{651	int rc;652	u32 error_type = 0;653 654	rc = einj_get_available_error_type(&error_type);655	if (rc)656		return rc;657	for (int pos = 0; pos < ARRAY_SIZE(einj_error_type_string); pos++)658		if (error_type & einj_error_type_string[pos].mask)659			seq_printf(m, "0x%08x\t%s\n", einj_error_type_string[pos].mask,660				   einj_error_type_string[pos].str);661 662	return 0;663}664 665DEFINE_SHOW_ATTRIBUTE(available_error_type);666 667static int error_type_get(void *data, u64 *val)668{669	*val = error_type;670 671	return 0;672}673 674bool einj_is_cxl_error_type(u64 type)675{676	return (type & CXL_ERROR_MASK) && (!(type & ACPI5_VENDOR_BIT));677}678 679int einj_validate_error_type(u64 type)680{681	u32 tval, vendor, available_error_type = 0;682	int rc;683 684	/* Only low 32 bits for error type are valid */685	if (type & GENMASK_ULL(63, 32))686		return -EINVAL;687 688	/*689	 * Vendor defined types have 0x80000000 bit set, and690	 * are not enumerated by ACPI_EINJ_GET_ERROR_TYPE691	 */692	vendor = type & ACPI5_VENDOR_BIT;693	tval = type & GENMASK(30, 0);694 695	/* Only one error type can be specified */696	if (tval & (tval - 1))697		return -EINVAL;698	if (!vendor) {699		rc = einj_get_available_error_type(&available_error_type);700		if (rc)701			return rc;702		if (!(type & available_error_type))703			return -EINVAL;704	}705 706	return 0;707}708 709static int error_type_set(void *data, u64 val)710{711	int rc;712 713	rc = einj_validate_error_type(val);714	if (rc)715		return rc;716 717	error_type = val;718 719	return 0;720}721 722DEFINE_DEBUGFS_ATTRIBUTE(error_type_fops, error_type_get, error_type_set,723			 "0x%llx\n");724 725static int error_inject_set(void *data, u64 val)726{727	if (!error_type)728		return -EINVAL;729 730	return einj_error_inject(error_type, error_flags, error_param1, error_param2,731		error_param3, error_param4);732}733 734DEFINE_DEBUGFS_ATTRIBUTE(error_inject_fops, NULL, error_inject_set, "%llu\n");735 736static int einj_check_table(struct acpi_table_einj *einj_tab)737{738	if ((einj_tab->header_length !=739	     (sizeof(struct acpi_table_einj) - sizeof(einj_tab->header)))740	    && (einj_tab->header_length != sizeof(struct acpi_table_einj)))741		return -EINVAL;742	if (einj_tab->header.length < sizeof(struct acpi_table_einj))743		return -EINVAL;744	if (einj_tab->entries !=745	    (einj_tab->header.length - sizeof(struct acpi_table_einj)) /746	    sizeof(struct acpi_einj_entry))747		return -EINVAL;748 749	return 0;750}751 752static int __init einj_probe(struct platform_device *pdev)753{754	int rc;755	acpi_status status;756	struct apei_exec_context ctx;757 758	if (acpi_disabled) {759		pr_debug("ACPI disabled.\n");760		return -ENODEV;761	}762 763	status = acpi_get_table(ACPI_SIG_EINJ, 0,764				(struct acpi_table_header **)&einj_tab);765	if (status == AE_NOT_FOUND) {766		pr_debug("EINJ table not found.\n");767		return -ENODEV;768	} else if (ACPI_FAILURE(status)) {769		pr_err("Failed to get EINJ table: %s\n",770				acpi_format_exception(status));771		return -EINVAL;772	}773 774	rc = einj_check_table(einj_tab);775	if (rc) {776		pr_warn(FW_BUG "Invalid EINJ table.\n");777		goto err_put_table;778	}779 780	rc = -ENOMEM;781	einj_debug_dir = debugfs_create_dir("einj", apei_get_debugfs_dir());782 783	debugfs_create_file("available_error_type", S_IRUSR, einj_debug_dir,784			    NULL, &available_error_type_fops);785	debugfs_create_file_unsafe("error_type", 0600, einj_debug_dir,786				   NULL, &error_type_fops);787	debugfs_create_file_unsafe("error_inject", 0200, einj_debug_dir,788				   NULL, &error_inject_fops);789 790	apei_resources_init(&einj_resources);791	einj_exec_ctx_init(&ctx);792	rc = apei_exec_collect_resources(&ctx, &einj_resources);793	if (rc) {794		pr_err("Error collecting EINJ resources.\n");795		goto err_fini;796	}797 798	rc = apei_resources_request(&einj_resources, "APEI EINJ");799	if (rc) {800		pr_err("Error requesting memory/port resources.\n");801		goto err_fini;802	}803 804	rc = apei_exec_pre_map_gars(&ctx);805	if (rc) {806		pr_err("Error pre-mapping GARs.\n");807		goto err_release;808	}809 810	einj_param = einj_get_parameter_address();811	if ((param_extension || acpi5) && einj_param) {812		debugfs_create_x32("flags", S_IRUSR | S_IWUSR, einj_debug_dir,813				   &error_flags);814		debugfs_create_x64("param1", S_IRUSR | S_IWUSR, einj_debug_dir,815				   &error_param1);816		debugfs_create_x64("param2", S_IRUSR | S_IWUSR, einj_debug_dir,817				   &error_param2);818		debugfs_create_x64("param3", S_IRUSR | S_IWUSR, einj_debug_dir,819				   &error_param3);820		debugfs_create_x64("param4", S_IRUSR | S_IWUSR, einj_debug_dir,821				   &error_param4);822		debugfs_create_x32("notrigger", S_IRUSR | S_IWUSR,823				   einj_debug_dir, &notrigger);824	}825 826	if (vendor_dev[0]) {827		vendor_blob.data = vendor_dev;828		vendor_blob.size = strlen(vendor_dev);829		debugfs_create_blob("vendor", S_IRUSR, einj_debug_dir,830				    &vendor_blob);831		debugfs_create_x32("vendor_flags", S_IRUSR | S_IWUSR,832				   einj_debug_dir, &vendor_flags);833	}834 835	if (vendor_errors.size)836		debugfs_create_blob("oem_error", 0600, einj_debug_dir,837				    &vendor_errors);838 839	pr_info("Error INJection is initialized.\n");840 841	return 0;842 843err_release:844	apei_resources_release(&einj_resources);845err_fini:846	apei_resources_fini(&einj_resources);847	debugfs_remove_recursive(einj_debug_dir);848err_put_table:849	acpi_put_table((struct acpi_table_header *)einj_tab);850 851	return rc;852}853 854static void __exit einj_remove(struct platform_device *pdev)855{856	struct apei_exec_context ctx;857 858	if (einj_param) {859		acpi_size size = (acpi5) ?860			sizeof(struct set_error_type_with_address) :861			sizeof(struct einj_parameter);862 863		acpi_os_unmap_iomem(einj_param, size);864		if (vendor_errors.size)865			acpi_os_unmap_memory(vendor_errors.data, vendor_errors.size);866	}867	einj_exec_ctx_init(&ctx);868	apei_exec_post_unmap_gars(&ctx);869	apei_resources_release(&einj_resources);870	apei_resources_fini(&einj_resources);871	debugfs_remove_recursive(einj_debug_dir);872	acpi_put_table((struct acpi_table_header *)einj_tab);873}874 875static struct platform_device *einj_dev;876/*877 * einj_remove() lives in .exit.text. For drivers registered via878 * platform_driver_probe() this is ok because they cannot get unbound at879 * runtime. So mark the driver struct with __refdata to prevent modpost880 * triggering a section mismatch warning.881 */882static struct platform_driver einj_driver __refdata = {883	.remove_new = __exit_p(einj_remove),884	.driver = {885		.name = "acpi-einj",886	},887};888 889static int __init einj_init(void)890{891	struct platform_device_info einj_dev_info = {892		.name = "acpi-einj",893		.id = -1,894	};895	int rc;896 897	einj_dev = platform_device_register_full(&einj_dev_info);898	if (IS_ERR(einj_dev))899		return PTR_ERR(einj_dev);900 901	rc = platform_driver_probe(&einj_driver, einj_probe);902	einj_initialized = rc == 0;903 904	return 0;905}906 907static void __exit einj_exit(void)908{909	if (einj_initialized)910		platform_driver_unregister(&einj_driver);911 912	platform_device_unregister(einj_dev);913}914 915module_init(einj_init);916module_exit(einj_exit);917 918MODULE_AUTHOR("Huang Ying");919MODULE_DESCRIPTION("APEI Error INJection support");920MODULE_LICENSE("GPL");921