mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
12fb28ea6b
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: Jonathan Cameron <Jonathan.Cameron@huawei.com> Signed-off-by: Ben Cheatham <Benjamin.Cheatham@amd.com> Link: https://lore.kernel.org/r/20240311142508.31717-3-Benjamin.Cheatham@amd.com Signed-off-by: Dan Williams <dan.j.williams@intel.com>
114 lines
2.8 KiB
C
114 lines
2.8 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* CXL Error INJection support. Used by CXL core to inject
|
|
* protocol errors into CXL ports.
|
|
*
|
|
* Copyright (C) 2023 Advanced Micro Devices, Inc.
|
|
*
|
|
* Author: Ben Cheatham <benjamin.cheatham@amd.com>
|
|
*/
|
|
#include <linux/einj-cxl.h>
|
|
#include <linux/seq_file.h>
|
|
#include <linux/pci.h>
|
|
|
|
#include "apei-internal.h"
|
|
|
|
/* Defined in einj-core.c */
|
|
extern bool einj_initialized;
|
|
|
|
static struct { u32 mask; const char *str; } const einj_cxl_error_type_string[] = {
|
|
{ ACPI_EINJ_CXL_CACHE_CORRECTABLE, "CXL.cache Protocol Correctable" },
|
|
{ ACPI_EINJ_CXL_CACHE_UNCORRECTABLE, "CXL.cache Protocol Uncorrectable non-fatal" },
|
|
{ ACPI_EINJ_CXL_CACHE_FATAL, "CXL.cache Protocol Uncorrectable fatal" },
|
|
{ ACPI_EINJ_CXL_MEM_CORRECTABLE, "CXL.mem Protocol Correctable" },
|
|
{ ACPI_EINJ_CXL_MEM_UNCORRECTABLE, "CXL.mem Protocol Uncorrectable non-fatal" },
|
|
{ ACPI_EINJ_CXL_MEM_FATAL, "CXL.mem Protocol Uncorrectable fatal" },
|
|
};
|
|
|
|
int einj_cxl_available_error_type_show(struct seq_file *m, void *v)
|
|
{
|
|
int cxl_err, rc;
|
|
u32 available_error_type = 0;
|
|
|
|
rc = einj_get_available_error_type(&available_error_type);
|
|
if (rc)
|
|
return rc;
|
|
|
|
for (int pos = 0; pos < ARRAY_SIZE(einj_cxl_error_type_string); pos++) {
|
|
cxl_err = ACPI_EINJ_CXL_CACHE_CORRECTABLE << pos;
|
|
|
|
if (available_error_type & cxl_err)
|
|
seq_printf(m, "0x%08x\t%s\n",
|
|
einj_cxl_error_type_string[pos].mask,
|
|
einj_cxl_error_type_string[pos].str);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_NS_GPL(einj_cxl_available_error_type_show, CXL);
|
|
|
|
static int cxl_dport_get_sbdf(struct pci_dev *dport_dev, u64 *sbdf)
|
|
{
|
|
struct pci_bus *pbus;
|
|
struct pci_host_bridge *bridge;
|
|
u64 seg = 0, bus;
|
|
|
|
pbus = dport_dev->bus;
|
|
bridge = pci_find_host_bridge(pbus);
|
|
|
|
if (!bridge)
|
|
return -ENODEV;
|
|
|
|
if (bridge->domain_nr != PCI_DOMAIN_NR_NOT_SET)
|
|
seg = bridge->domain_nr;
|
|
|
|
bus = pbus->number;
|
|
*sbdf = (seg << 24) | (bus << 16) | dport_dev->devfn;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int einj_cxl_inject_rch_error(u64 rcrb, u64 type)
|
|
{
|
|
int rc;
|
|
|
|
/* Only CXL error types can be specified */
|
|
if (!einj_is_cxl_error_type(type))
|
|
return -EINVAL;
|
|
|
|
rc = einj_validate_error_type(type);
|
|
if (rc)
|
|
return rc;
|
|
|
|
return einj_cxl_rch_error_inject(type, 0x2, rcrb, GENMASK_ULL(63, 0),
|
|
0, 0);
|
|
}
|
|
EXPORT_SYMBOL_NS_GPL(einj_cxl_inject_rch_error, CXL);
|
|
|
|
int einj_cxl_inject_error(struct pci_dev *dport, u64 type)
|
|
{
|
|
u64 param4 = 0;
|
|
int rc;
|
|
|
|
/* Only CXL error types can be specified */
|
|
if (!einj_is_cxl_error_type(type))
|
|
return -EINVAL;
|
|
|
|
rc = einj_validate_error_type(type);
|
|
if (rc)
|
|
return rc;
|
|
|
|
rc = cxl_dport_get_sbdf(dport, ¶m4);
|
|
if (rc)
|
|
return rc;
|
|
|
|
return einj_error_inject(type, 0x4, 0, 0, 0, param4);
|
|
}
|
|
EXPORT_SYMBOL_NS_GPL(einj_cxl_inject_error, CXL);
|
|
|
|
bool einj_cxl_is_initialized(void)
|
|
{
|
|
return einj_initialized;
|
|
}
|
|
EXPORT_SYMBOL_NS_GPL(einj_cxl_is_initialized, CXL);
|