Commit 12fb28ea authored by Ben Cheatham's avatar Ben Cheatham Committed by Dan Williams
Browse files

EINJ: Add CXL error type support



Move CXL protocol error types from einj.c (now einj-core.c) to einj-cxl.c.
einj-cxl.c implements the necessary handling for CXL protocol error
injection and exposes an API for the CXL core to use said functionality,
while also allowing the EINJ module to be built without CXL support.
Because CXL error types targeting CXL 1.0/1.1 ports require special
handling, only allow them to be injected through the new cxl debugfs
interface (next commit) and return an error when attempting to inject
through the legacy interface.

Reviewed-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: default avatarBen Cheatham <Benjamin.Cheatham@amd.com>
Link: https://lore.kernel.org/r/20240311142508.31717-3-Benjamin.Cheatham@amd.com


Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent 5621fafa
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -5289,6 +5289,7 @@ M: Dan Williams <dan.j.williams@intel.com>
L:	linux-cxl@vger.kernel.org
S:	Maintained
F:	drivers/cxl/
F:	include/linux/cxl-einj.h
F:	include/linux/cxl-event.h
F:	include/uapi/linux/cxl_mem.h
F:	tools/testing/cxl/
+13 −0
Original line number Diff line number Diff line
@@ -60,6 +60,19 @@ config ACPI_APEI_EINJ
	  mainly used for debugging and testing the other parts of
	  APEI and some other RAS features.

config ACPI_APEI_EINJ_CXL
	bool "CXL Error INJection Support"
	default ACPI_APEI_EINJ
	depends on ACPI_APEI_EINJ
	depends on CXL_BUS && CXL_BUS <= ACPI_APEI_EINJ
	help
	  Support for CXL protocol Error INJection through debugfs/cxl.
	  Availability and which errors are supported is dependent on
	  the host platform. Look to ACPI v6.5 section 18.6.4 and kernel
	  EINJ documentation for more information.

	  If unsure say 'n'

config ACPI_APEI_ERST_DEBUG
	tristate "APEI Error Record Serialization Table (ERST) Debug Support"
	depends on ACPI_APEI
+2 −0
Original line number Diff line number Diff line
@@ -2,6 +2,8 @@
obj-$(CONFIG_ACPI_APEI)		+= apei.o
obj-$(CONFIG_ACPI_APEI_GHES)	+= ghes.o
obj-$(CONFIG_ACPI_APEI_EINJ)	+= einj.o
einj-y				:= einj-core.o
einj-$(CONFIG_ACPI_APEI_EINJ_CXL) += einj-cxl.o
obj-$(CONFIG_ACPI_APEI_ERST_DEBUG) += erst-dbg.o

apei-y := apei-base.o hest.o erst.o bert.o
+18 −0
Original line number Diff line number Diff line
@@ -130,4 +130,22 @@ static inline u32 cper_estatus_len(struct acpi_hest_generic_status *estatus)
}

int apei_osc_setup(void);

int einj_get_available_error_type(u32 *type);
int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, u64 param3,
		      u64 param4);
int einj_cxl_rch_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
			      u64 param3, u64 param4);
bool einj_is_cxl_error_type(u64 type);
int einj_validate_error_type(u64 type);

#ifndef ACPI_EINJ_CXL_CACHE_CORRECTABLE
#define ACPI_EINJ_CXL_CACHE_CORRECTABLE     BIT(12)
#define ACPI_EINJ_CXL_CACHE_UNCORRECTABLE   BIT(13)
#define ACPI_EINJ_CXL_CACHE_FATAL           BIT(14)
#define ACPI_EINJ_CXL_MEM_CORRECTABLE       BIT(15)
#define ACPI_EINJ_CXL_MEM_UNCORRECTABLE     BIT(16)
#define ACPI_EINJ_CXL_MEM_FATAL             BIT(17)
#endif

#endif
+58 −18
Original line number Diff line number Diff line
@@ -37,6 +37,12 @@
#define MEM_ERROR_MASK		(ACPI_EINJ_MEMORY_CORRECTABLE | \
				ACPI_EINJ_MEMORY_UNCORRECTABLE | \
				ACPI_EINJ_MEMORY_FATAL)
#define CXL_ERROR_MASK		(ACPI_EINJ_CXL_CACHE_CORRECTABLE | \
				ACPI_EINJ_CXL_CACHE_UNCORRECTABLE | \
				ACPI_EINJ_CXL_CACHE_FATAL | \
				ACPI_EINJ_CXL_MEM_CORRECTABLE | \
				ACPI_EINJ_CXL_MEM_UNCORRECTABLE | \
				ACPI_EINJ_CXL_MEM_FATAL)

/*
 * ACPI version 5 provides a SET_ERROR_TYPE_WITH_ADDRESS action.
@@ -141,7 +147,7 @@ static DEFINE_MUTEX(einj_mutex);
/*
 * Exported APIs use this flag to exit early if einj_probe() failed.
 */
static bool einj_initialized __ro_after_init;
bool einj_initialized __ro_after_init;

static void *einj_param;

@@ -166,7 +172,7 @@ static int __einj_get_available_error_type(u32 *type)
}

/* Get error injection capabilities of the platform */
static int einj_get_available_error_type(u32 *type)
int einj_get_available_error_type(u32 *type)
{
	int rc;

@@ -536,8 +542,8 @@ static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
}

/* Inject the specified hardware error */
static int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
			     u64 param3, u64 param4)
int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, u64 param3,
		      u64 param4)
{
	int rc;
	u64 base_addr, size;
@@ -560,8 +566,17 @@ static int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
	if (type & ACPI5_VENDOR_BIT) {
		if (vendor_flags != SETWA_FLAGS_MEM)
			goto inject;
	} else if (!(type & MEM_ERROR_MASK) && !(flags & SETWA_FLAGS_MEM))
	} else if (!(type & MEM_ERROR_MASK) && !(flags & SETWA_FLAGS_MEM)) {
		goto inject;
	}

	/*
	 * Injections targeting a CXL 1.0/1.1 port have to be injected
	 * via the einj_cxl_rch_error_inject() path as that does the proper
	 * validation of the given RCRB base (MMIO) address.
	 */
	if (einj_is_cxl_error_type(type) && (flags & SETWA_FLAGS_MEM))
		return -EINVAL;

	/*
	 * Disallow crazy address masks that give BIOS leeway to pick
@@ -593,6 +608,21 @@ static int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
	return rc;
}

int einj_cxl_rch_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
			      u64 param3, u64 param4)
{
	int rc;

	if (!(einj_is_cxl_error_type(type) && (flags & SETWA_FLAGS_MEM)))
		return -EINVAL;

	mutex_lock(&einj_mutex);
	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;
@@ -613,12 +643,6 @@ static struct { u32 mask; const char *str; } const einj_error_type_string[] = {
	{ BIT(9), "Platform Correctable" },
	{ BIT(10), "Platform Uncorrectable non-fatal" },
	{ BIT(11), "Platform Uncorrectable fatal"},
	{ BIT(12), "CXL.cache Protocol Correctable" },
	{ BIT(13), "CXL.cache Protocol Uncorrectable non-fatal" },
	{ BIT(14), "CXL.cache Protocol Uncorrectable fatal" },
	{ BIT(15), "CXL.mem Protocol Correctable" },
	{ BIT(16), "CXL.mem Protocol Uncorrectable non-fatal" },
	{ BIT(17), "CXL.mem Protocol Uncorrectable fatal" },
	{ BIT(31), "Vendor Defined Error Types" },
};

@@ -647,22 +671,26 @@ static int error_type_get(void *data, u64 *val)
	return 0;
}

static int error_type_set(void *data, u64 val)
bool einj_is_cxl_error_type(u64 type)
{
	return (type & CXL_ERROR_MASK) && (!(type & ACPI5_VENDOR_BIT));
}

int einj_validate_error_type(u64 type)
{
	u32 tval, vendor, available_error_type = 0;
	int rc;
	u32 available_error_type = 0;
	u32 tval, vendor;

	/* Only low 32 bits for error type are valid */
	if (val & GENMASK_ULL(63, 32))
	if (type & GENMASK_ULL(63, 32))
		return -EINVAL;

	/*
	 * Vendor defined types have 0x80000000 bit set, and
	 * are not enumerated by ACPI_EINJ_GET_ERROR_TYPE
	 */
	vendor = val & ACPI5_VENDOR_BIT;
	tval = val & 0x7fffffff;
	vendor = type & ACPI5_VENDOR_BIT;
	tval = type & GENMASK(30, 0);

	/* Only one error type can be specified */
	if (tval & (tval - 1))
@@ -671,9 +699,21 @@ static int error_type_set(void *data, u64 val)
		rc = einj_get_available_error_type(&available_error_type);
		if (rc)
			return rc;
		if (!(val & available_error_type))
		if (!(type & available_error_type))
			return -EINVAL;
	}

	return 0;
}

static int error_type_set(void *data, u64 val)
{
	int rc;

	rc = einj_validate_error_type(val);
	if (rc)
		return rc;

	error_type = val;

	return 0;
Loading