- Switch ghes_edac to use the CPER error reporting routines and simplify
the code considerably this way - Rip out the silly edac_align_ptr() contraption which was computing the size of the private structures of each driver and thus allowing for a one-shot memory allocation. This was clearly unnecessary and confusing so switch to simple and boring kmalloc* calls. - Last but not least, the usual garden variety of fixes, cleanups and improvements all over EDAC land -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEzv7L6UO9uDPlPSfHEsHwGGHeVUoFAmKLRJkACgkQEsHwGGHe VUorYQ//a3s/j1wIXB5J0q7c9xlumqhxJz9P2A42kZMEW6MR94Ovr2lDnN6FRN5z dlLLn/fxjh3El084jaKrfhHHyB0Z78Qte/Caf4E3HVuhmZ2dQw58vXAm3TNMsiPz DEnJrRJ/vuX/VEcuuvX9wwSovPqNINW4lb9cWcIfGPToX051coUvuxTQXmCO80Hd 2syv88S0a8tw94E6DeB+5hhAQdgdV2dK3rZChTNi1guDqHqv14E6oQowWe6+Dvq/ XGBbJtmjuWsh2ZtS1KDnGYO0jvzLxe/5kjdgXYUoftG30MVTkVV0pBk0G+lPQQBN 2nSLd9zEgSceB5SlNlfWtQQuL1I56q3chxT7mj5JBPRsqQmV6Rxg9E0jnyiUH6Cf Q9btDizjU7vUpDKe1Y8fJEMR3nXTIK58AnjcDmTZIu5hVZFY2nYnql0txClmkTUE Bffud97C7a8uiSECp6oS5vjQHK12xwqiD8KRIaAHlBDYnpqTOJw/mDoKUvV74yiJ TRvvPAiPgoA5ZLLkCFKxA7IzFXtgz9HL7m/MbbBo63ed187qvMyBxcyb8Teih/iy u6eK0W1fux+zEaS6q5Jp0v415aqVvoa0UHgImTlOJhBaWENlEQixHslFMaqnlDTV yhG405KxxMgW9/L9nI4kqP827zIr4iXJCVg3rJsOdytEzfwWy2o= =Hwmn -----END PGP SIGNATURE----- Merge tag 'edac_updates_for_v5.19_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ras/ras Pull EDAC updates from Borislav Petkov: - Switch ghes_edac to use the CPER error reporting routines and simplify the code considerably this way - Rip out the silly edac_align_ptr() contraption which was computing the size of the private structures of each driver and thus allowing for a one-shot memory allocation. This was clearly unnecessary and confusing so switch to simple and boring kmalloc* calls. - Last but not least, the usual garden variety of fixes, cleanups and improvements all over EDAC land * tag 'edac_updates_for_v5.19_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ras/ras: EDAC/xgene: Fix typo processsors -> processors EDAC/i5100: Remove unused inline function i5100_nrecmema_dm_buf_id() EDAC: Use kcalloc() EDAC/ghes: Change ghes_hw from global to static EDAC/armada_xp: Use devm_platform_ioremap_resource() EDAC/synopsys: Add a SPDX identifier EDAC/synopsys: Add driver support for i.MX platforms EDAC/dmc520: Don't print an error for each unconfigured interrupt line EDAC/mc: Get rid of edac_align_ptr() EDAC/device: Sanitize edac_device_alloc_ctl_info() definition EDAC/device: Get rid of the silly one-shot memory allocation in edac_device_alloc_ctl_info() EDAC/pci: Get rid of the silly one-shot memory allocation in edac_pci_alloc_ctl_info() EDAC/mc: Get rid of silly one-shot struct allocation in edac_mc_alloc() efi/cper: Reformat CPER memory error location to more readable EDAC/ghes: Unify CPER memory error location reporting efi/cper: Add a cper_mem_err_status_str() to decode error description powerpc/85xx: Remove fsl,85... bindings
This commit is contained in:
commit
0be3ff0ccb
|
@ -25,12 +25,6 @@ properties:
|
|||
- const: fsl,qoriq-memory-controller
|
||||
- enum:
|
||||
- fsl,bsc9132-memory-controller
|
||||
- fsl,8540-memory-controller
|
||||
- fsl,8541-memory-controller
|
||||
- fsl,8544-memory-controller
|
||||
- fsl,8548-memory-controller
|
||||
- fsl,8555-memory-controller
|
||||
- fsl,8568-memory-controller
|
||||
- fsl,mpc8536-memory-controller
|
||||
- fsl,mpc8540-memory-controller
|
||||
- fsl,mpc8541-memory-controller
|
||||
|
|
|
@ -6,12 +6,6 @@ The cache bindings explained below are Devicetree Specification compliant
|
|||
Required Properties:
|
||||
|
||||
- compatible : Should include one of the following:
|
||||
"fsl,8540-l2-cache-controller"
|
||||
"fsl,8541-l2-cache-controller"
|
||||
"fsl,8544-l2-cache-controller"
|
||||
"fsl,8548-l2-cache-controller"
|
||||
"fsl,8555-l2-cache-controller"
|
||||
"fsl,8568-l2-cache-controller"
|
||||
"fsl,b4420-l2-cache-controller"
|
||||
"fsl,b4860-l2-cache-controller"
|
||||
"fsl,bsc9131-l2-cache-controller"
|
||||
|
|
|
@ -55,6 +55,7 @@ config EDAC_DECODE_MCE
|
|||
config EDAC_GHES
|
||||
bool "Output ACPI APEI/GHES BIOS detected errors via EDAC"
|
||||
depends on ACPI_APEI_GHES && (EDAC=y)
|
||||
select UEFI_CPER
|
||||
help
|
||||
Not all machines support hardware-driven error report. Some of those
|
||||
provide a BIOS-driven error report mechanism via ACPI, using the
|
||||
|
@ -484,7 +485,7 @@ config EDAC_ARMADA_XP
|
|||
|
||||
config EDAC_SYNOPSYS
|
||||
tristate "Synopsys DDR Memory Controller"
|
||||
depends on ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_INTEL_SOCFPGA
|
||||
depends on ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_INTEL_SOCFPGA || ARCH_MXC
|
||||
help
|
||||
Support for error detection and correction on the Synopsys DDR
|
||||
memory controller.
|
||||
|
|
|
@ -286,17 +286,10 @@ static int axp_mc_probe(struct platform_device *pdev)
|
|||
struct edac_mc_layer layers[1];
|
||||
const struct of_device_id *id;
|
||||
struct mem_ctl_info *mci;
|
||||
struct resource *r;
|
||||
void __iomem *base;
|
||||
uint32_t config;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!r) {
|
||||
dev_err(&pdev->dev, "Unable to get mem resource\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
base = devm_ioremap_resource(&pdev->dev, r);
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base)) {
|
||||
dev_err(&pdev->dev, "Unable to map regs\n");
|
||||
return PTR_ERR(base);
|
||||
|
@ -516,15 +509,8 @@ static int aurora_l2_probe(struct platform_device *pdev)
|
|||
const struct of_device_id *id;
|
||||
uint32_t l2x0_aux_ctrl;
|
||||
void __iomem *base;
|
||||
struct resource *r;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!r) {
|
||||
dev_err(&pdev->dev, "Unable to get mem resource\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
base = devm_ioremap_resource(&pdev->dev, r);
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base)) {
|
||||
dev_err(&pdev->dev, "Unable to map regs\n");
|
||||
return PTR_ERR(base);
|
||||
|
|
|
@ -489,7 +489,7 @@ static int dmc520_edac_probe(struct platform_device *pdev)
|
|||
dev = &pdev->dev;
|
||||
|
||||
for (idx = 0; idx < NUMBER_OF_IRQS; idx++) {
|
||||
irq = platform_get_irq_byname(pdev, dmc520_irq_configs[idx].name);
|
||||
irq = platform_get_irq_byname_optional(pdev, dmc520_irq_configs[idx].name);
|
||||
irqs[idx] = irq;
|
||||
masks[idx] = dmc520_irq_configs[idx].mask;
|
||||
if (irq >= 0) {
|
||||
|
|
|
@ -47,99 +47,67 @@ static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev)
|
|||
}
|
||||
#endif /* CONFIG_EDAC_DEBUG */
|
||||
|
||||
struct edac_device_ctl_info *edac_device_alloc_ctl_info(
|
||||
unsigned sz_private,
|
||||
char *edac_device_name, unsigned nr_instances,
|
||||
char *edac_block_name, unsigned nr_blocks,
|
||||
unsigned offset_value, /* zero, 1, or other based offset */
|
||||
struct edac_dev_sysfs_block_attribute *attrib_spec, unsigned nr_attrib,
|
||||
int device_index)
|
||||
/*
|
||||
* @off_val: zero, 1, or other based offset
|
||||
*/
|
||||
struct edac_device_ctl_info *
|
||||
edac_device_alloc_ctl_info(unsigned pvt_sz, char *dev_name, unsigned nr_instances,
|
||||
char *blk_name, unsigned nr_blocks, unsigned off_val,
|
||||
struct edac_dev_sysfs_block_attribute *attrib_spec,
|
||||
unsigned nr_attrib, int device_index)
|
||||
{
|
||||
struct edac_device_ctl_info *dev_ctl;
|
||||
struct edac_device_instance *dev_inst, *inst;
|
||||
struct edac_device_block *dev_blk, *blk_p, *blk;
|
||||
struct edac_dev_sysfs_block_attribute *dev_attrib, *attrib_p, *attrib;
|
||||
unsigned total_size;
|
||||
unsigned count;
|
||||
struct edac_device_block *dev_blk, *blk_p, *blk;
|
||||
struct edac_device_instance *dev_inst, *inst;
|
||||
struct edac_device_ctl_info *dev_ctl;
|
||||
unsigned instance, block, attr;
|
||||
void *pvt, *p;
|
||||
void *pvt;
|
||||
int err;
|
||||
|
||||
edac_dbg(4, "instances=%d blocks=%d\n", nr_instances, nr_blocks);
|
||||
|
||||
/* Calculate the size of memory we need to allocate AND
|
||||
* determine the offsets of the various item arrays
|
||||
* (instance,block,attrib) from the start of an allocated structure.
|
||||
* We want the alignment of each item (instance,block,attrib)
|
||||
* to be at least as stringent as what the compiler would
|
||||
* provide if we could simply hardcode everything into a single struct.
|
||||
*/
|
||||
p = NULL;
|
||||
dev_ctl = edac_align_ptr(&p, sizeof(*dev_ctl), 1);
|
||||
|
||||
/* Calc the 'end' offset past end of ONE ctl_info structure
|
||||
* which will become the start of the 'instance' array
|
||||
*/
|
||||
dev_inst = edac_align_ptr(&p, sizeof(*dev_inst), nr_instances);
|
||||
|
||||
/* Calc the 'end' offset past the instance array within the ctl_info
|
||||
* which will become the start of the block array
|
||||
*/
|
||||
count = nr_instances * nr_blocks;
|
||||
dev_blk = edac_align_ptr(&p, sizeof(*dev_blk), count);
|
||||
|
||||
/* Calc the 'end' offset past the dev_blk array
|
||||
* which will become the start of the attrib array, if any.
|
||||
*/
|
||||
/* calc how many nr_attrib we need */
|
||||
if (nr_attrib > 0)
|
||||
count *= nr_attrib;
|
||||
dev_attrib = edac_align_ptr(&p, sizeof(*dev_attrib), count);
|
||||
|
||||
/* Calc the 'end' offset past the attributes array */
|
||||
pvt = edac_align_ptr(&p, sz_private, 1);
|
||||
|
||||
/* 'pvt' now points to where the private data area is.
|
||||
* At this point 'pvt' (like dev_inst,dev_blk and dev_attrib)
|
||||
* is baselined at ZERO
|
||||
*/
|
||||
total_size = ((unsigned long)pvt) + sz_private;
|
||||
|
||||
/* Allocate the amount of memory for the set of control structures */
|
||||
dev_ctl = kzalloc(total_size, GFP_KERNEL);
|
||||
if (dev_ctl == NULL)
|
||||
dev_ctl = kzalloc(sizeof(struct edac_device_ctl_info), GFP_KERNEL);
|
||||
if (!dev_ctl)
|
||||
return NULL;
|
||||
|
||||
/* Adjust pointers so they point within the actual memory we
|
||||
* just allocated rather than an imaginary chunk of memory
|
||||
* located at address 0.
|
||||
* 'dev_ctl' points to REAL memory, while the others are
|
||||
* ZERO based and thus need to be adjusted to point within
|
||||
* the allocated memory.
|
||||
*/
|
||||
dev_inst = (struct edac_device_instance *)
|
||||
(((char *)dev_ctl) + ((unsigned long)dev_inst));
|
||||
dev_blk = (struct edac_device_block *)
|
||||
(((char *)dev_ctl) + ((unsigned long)dev_blk));
|
||||
dev_attrib = (struct edac_dev_sysfs_block_attribute *)
|
||||
(((char *)dev_ctl) + ((unsigned long)dev_attrib));
|
||||
pvt = sz_private ? (((char *)dev_ctl) + ((unsigned long)pvt)) : NULL;
|
||||
dev_inst = kcalloc(nr_instances, sizeof(struct edac_device_instance), GFP_KERNEL);
|
||||
if (!dev_inst)
|
||||
goto free;
|
||||
|
||||
/* Begin storing the information into the control info structure */
|
||||
dev_ctl->dev_idx = device_index;
|
||||
dev_ctl->nr_instances = nr_instances;
|
||||
dev_ctl->instances = dev_inst;
|
||||
dev_ctl->pvt_info = pvt;
|
||||
|
||||
dev_blk = kcalloc(nr_instances * nr_blocks, sizeof(struct edac_device_block), GFP_KERNEL);
|
||||
if (!dev_blk)
|
||||
goto free;
|
||||
|
||||
dev_ctl->blocks = dev_blk;
|
||||
|
||||
if (nr_attrib) {
|
||||
dev_attrib = kcalloc(nr_attrib, sizeof(struct edac_dev_sysfs_block_attribute),
|
||||
GFP_KERNEL);
|
||||
if (!dev_attrib)
|
||||
goto free;
|
||||
|
||||
dev_ctl->attribs = dev_attrib;
|
||||
}
|
||||
|
||||
if (pvt_sz) {
|
||||
pvt = kzalloc(pvt_sz, GFP_KERNEL);
|
||||
if (!pvt)
|
||||
goto free;
|
||||
|
||||
dev_ctl->pvt_info = pvt;
|
||||
}
|
||||
|
||||
dev_ctl->dev_idx = device_index;
|
||||
dev_ctl->nr_instances = nr_instances;
|
||||
|
||||
/* Default logging of CEs and UEs */
|
||||
dev_ctl->log_ce = 1;
|
||||
dev_ctl->log_ue = 1;
|
||||
|
||||
/* Name of this edac device */
|
||||
snprintf(dev_ctl->name,sizeof(dev_ctl->name),"%s",edac_device_name);
|
||||
|
||||
edac_dbg(4, "edac_dev=%p next after end=%p\n",
|
||||
dev_ctl, pvt + sz_private);
|
||||
snprintf(dev_ctl->name, sizeof(dev_ctl->name),"%s", dev_name);
|
||||
|
||||
/* Initialize every Instance */
|
||||
for (instance = 0; instance < nr_instances; instance++) {
|
||||
|
@ -150,15 +118,14 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info(
|
|||
inst->blocks = blk_p;
|
||||
|
||||
/* name of this instance */
|
||||
snprintf(inst->name, sizeof(inst->name),
|
||||
"%s%u", edac_device_name, instance);
|
||||
snprintf(inst->name, sizeof(inst->name), "%s%u", dev_name, instance);
|
||||
|
||||
/* Initialize every block in each instance */
|
||||
for (block = 0; block < nr_blocks; block++) {
|
||||
blk = &blk_p[block];
|
||||
blk->instance = inst;
|
||||
snprintf(blk->name, sizeof(blk->name),
|
||||
"%s%d", edac_block_name, block+offset_value);
|
||||
"%s%d", blk_name, block + off_val);
|
||||
|
||||
edac_dbg(4, "instance=%d inst_p=%p block=#%d block_p=%p name='%s'\n",
|
||||
instance, inst, block, blk, blk->name);
|
||||
|
@ -210,10 +177,8 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info(
|
|||
* Initialize the 'root' kobj for the edac_device controller
|
||||
*/
|
||||
err = edac_device_register_sysfs_main_kobj(dev_ctl);
|
||||
if (err) {
|
||||
kfree(dev_ctl);
|
||||
return NULL;
|
||||
}
|
||||
if (err)
|
||||
goto free;
|
||||
|
||||
/* at this point, the root kobj is valid, and in order to
|
||||
* 'free' the object, then the function:
|
||||
|
@ -223,6 +188,11 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info(
|
|||
*/
|
||||
|
||||
return dev_ctl;
|
||||
|
||||
free:
|
||||
__edac_device_free_ctl_info(dev_ctl);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(edac_device_alloc_ctl_info);
|
||||
|
||||
|
|
|
@ -216,6 +216,8 @@ struct edac_device_ctl_info {
|
|||
*/
|
||||
u32 nr_instances;
|
||||
struct edac_device_instance *instances;
|
||||
struct edac_device_block *blocks;
|
||||
struct edac_dev_sysfs_block_attribute *attribs;
|
||||
|
||||
/* Event counters for the this whole EDAC Device */
|
||||
struct edac_device_counter counters;
|
||||
|
@ -348,4 +350,16 @@ edac_device_handle_ue(struct edac_device_ctl_info *edac_dev, int inst_nr,
|
|||
*/
|
||||
extern int edac_device_alloc_index(void);
|
||||
extern const char *edac_layer_name[];
|
||||
|
||||
/* Free the actual struct */
|
||||
static inline void __edac_device_free_ctl_info(struct edac_device_ctl_info *ci)
|
||||
{
|
||||
if (ci) {
|
||||
kfree(ci->pvt_info);
|
||||
kfree(ci->attribs);
|
||||
kfree(ci->blocks);
|
||||
kfree(ci->instances);
|
||||
kfree(ci);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -208,10 +208,7 @@ static void edac_device_ctrl_master_release(struct kobject *kobj)
|
|||
/* decrement the EDAC CORE module ref count */
|
||||
module_put(edac_dev->owner);
|
||||
|
||||
/* free the control struct containing the 'main' kobj
|
||||
* passed in to this routine
|
||||
*/
|
||||
kfree(edac_dev);
|
||||
__edac_device_free_ctl_info(edac_dev);
|
||||
}
|
||||
|
||||
/* ktype for the main (master) kobject */
|
||||
|
|
|
@ -170,61 +170,6 @@ const char * const edac_mem_types[] = {
|
|||
};
|
||||
EXPORT_SYMBOL_GPL(edac_mem_types);
|
||||
|
||||
/**
|
||||
* edac_align_ptr - Prepares the pointer offsets for a single-shot allocation
|
||||
* @p: pointer to a pointer with the memory offset to be used. At
|
||||
* return, this will be incremented to point to the next offset
|
||||
* @size: Size of the data structure to be reserved
|
||||
* @n_elems: Number of elements that should be reserved
|
||||
*
|
||||
* If 'size' is a constant, the compiler will optimize this whole function
|
||||
* down to either a no-op or the addition of a constant to the value of '*p'.
|
||||
*
|
||||
* The 'p' pointer is absolutely needed to keep the proper advancing
|
||||
* further in memory to the proper offsets when allocating the struct along
|
||||
* with its embedded structs, as edac_device_alloc_ctl_info() does it
|
||||
* above, for example.
|
||||
*
|
||||
* At return, the pointer 'p' will be incremented to be used on a next call
|
||||
* to this function.
|
||||
*/
|
||||
void *edac_align_ptr(void **p, unsigned int size, int n_elems)
|
||||
{
|
||||
unsigned int align, r;
|
||||
void *ptr = *p;
|
||||
|
||||
*p += size * n_elems;
|
||||
|
||||
/*
|
||||
* 'p' can possibly be an unaligned item X such that sizeof(X) is
|
||||
* 'size'. Adjust 'p' so that its alignment is at least as
|
||||
* stringent as what the compiler would provide for X and return
|
||||
* the aligned result.
|
||||
* Here we assume that the alignment of a "long long" is the most
|
||||
* stringent alignment that the compiler will ever provide by default.
|
||||
* As far as I know, this is a reasonable assumption.
|
||||
*/
|
||||
if (size > sizeof(long))
|
||||
align = sizeof(long long);
|
||||
else if (size > sizeof(int))
|
||||
align = sizeof(long);
|
||||
else if (size > sizeof(short))
|
||||
align = sizeof(int);
|
||||
else if (size > sizeof(char))
|
||||
align = sizeof(short);
|
||||
else
|
||||
return ptr;
|
||||
|
||||
r = (unsigned long)ptr % align;
|
||||
|
||||
if (r == 0)
|
||||
return ptr;
|
||||
|
||||
*p += align - r;
|
||||
|
||||
return (void *)(((unsigned long)ptr) + align - r);
|
||||
}
|
||||
|
||||
static void _edac_mc_free(struct mem_ctl_info *mci)
|
||||
{
|
||||
put_device(&mci->dev);
|
||||
|
@ -257,6 +202,8 @@ static void mci_release(struct device *dev)
|
|||
}
|
||||
kfree(mci->csrows);
|
||||
}
|
||||
kfree(mci->pvt_info);
|
||||
kfree(mci->layers);
|
||||
kfree(mci);
|
||||
}
|
||||
|
||||
|
@ -392,9 +339,8 @@ struct mem_ctl_info *edac_mc_alloc(unsigned int mc_num,
|
|||
{
|
||||
struct mem_ctl_info *mci;
|
||||
struct edac_mc_layer *layer;
|
||||
unsigned int idx, size, tot_dimms = 1;
|
||||
unsigned int idx, tot_dimms = 1;
|
||||
unsigned int tot_csrows = 1, tot_channels = 1;
|
||||
void *pvt, *ptr = NULL;
|
||||
bool per_rank = false;
|
||||
|
||||
if (WARN_ON(n_layers > EDAC_MAX_LAYERS || n_layers == 0))
|
||||
|
@ -416,41 +362,25 @@ struct mem_ctl_info *edac_mc_alloc(unsigned int mc_num,
|
|||
per_rank = true;
|
||||
}
|
||||
|
||||
/* Figure out the offsets of the various items from the start of an mc
|
||||
* structure. We want the alignment of each item to be at least as
|
||||
* stringent as what the compiler would provide if we could simply
|
||||
* hardcode everything into a single struct.
|
||||
*/
|
||||
mci = edac_align_ptr(&ptr, sizeof(*mci), 1);
|
||||
layer = edac_align_ptr(&ptr, sizeof(*layer), n_layers);
|
||||
pvt = edac_align_ptr(&ptr, sz_pvt, 1);
|
||||
size = ((unsigned long)pvt) + sz_pvt;
|
||||
|
||||
edac_dbg(1, "allocating %u bytes for mci data (%d %s, %d csrows/channels)\n",
|
||||
size,
|
||||
tot_dimms,
|
||||
per_rank ? "ranks" : "dimms",
|
||||
tot_csrows * tot_channels);
|
||||
|
||||
mci = kzalloc(size, GFP_KERNEL);
|
||||
if (mci == NULL)
|
||||
mci = kzalloc(sizeof(struct mem_ctl_info), GFP_KERNEL);
|
||||
if (!mci)
|
||||
return NULL;
|
||||
|
||||
mci->layers = kcalloc(n_layers, sizeof(struct edac_mc_layer), GFP_KERNEL);
|
||||
if (!mci->layers)
|
||||
goto error;
|
||||
|
||||
mci->pvt_info = kzalloc(sz_pvt, GFP_KERNEL);
|
||||
if (!mci->pvt_info)
|
||||
goto error;
|
||||
|
||||
mci->dev.release = mci_release;
|
||||
device_initialize(&mci->dev);
|
||||
|
||||
/* Adjust pointers so they point within the memory we just allocated
|
||||
* rather than an imaginary chunk of memory located at address 0.
|
||||
*/
|
||||
layer = (struct edac_mc_layer *)(((char *)mci) + ((unsigned long)layer));
|
||||
pvt = sz_pvt ? (((char *)mci) + ((unsigned long)pvt)) : NULL;
|
||||
|
||||
/* setup index and various internal pointers */
|
||||
mci->mc_idx = mc_num;
|
||||
mci->tot_dimms = tot_dimms;
|
||||
mci->pvt_info = pvt;
|
||||
mci->n_layers = n_layers;
|
||||
mci->layers = layer;
|
||||
memcpy(mci->layers, layers, sizeof(*layer) * n_layers);
|
||||
mci->nr_csrows = tot_csrows;
|
||||
mci->num_cschannel = tot_channels;
|
||||
|
|
|
@ -59,8 +59,6 @@ extern void edac_device_reset_delay_period(struct edac_device_ctl_info
|
|||
*edac_dev, unsigned long value);
|
||||
extern void edac_mc_reset_delay_period(unsigned long value);
|
||||
|
||||
extern void *edac_align_ptr(void **p, unsigned size, int n_elems);
|
||||
|
||||
/*
|
||||
* EDAC debugfs functions
|
||||
*/
|
||||
|
|
|
@ -29,32 +29,31 @@ static LIST_HEAD(edac_pci_list);
|
|||
static atomic_t pci_indexes = ATOMIC_INIT(0);
|
||||
|
||||
struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt,
|
||||
const char *edac_pci_name)
|
||||
const char *edac_pci_name)
|
||||
{
|
||||
struct edac_pci_ctl_info *pci;
|
||||
void *p = NULL, *pvt;
|
||||
unsigned int size;
|
||||
|
||||
edac_dbg(1, "\n");
|
||||
|
||||
pci = edac_align_ptr(&p, sizeof(*pci), 1);
|
||||
pvt = edac_align_ptr(&p, 1, sz_pvt);
|
||||
size = ((unsigned long)pvt) + sz_pvt;
|
||||
|
||||
/* Alloc the needed control struct memory */
|
||||
pci = kzalloc(size, GFP_KERNEL);
|
||||
if (pci == NULL)
|
||||
pci = kzalloc(sizeof(struct edac_pci_ctl_info), GFP_KERNEL);
|
||||
if (!pci)
|
||||
return NULL;
|
||||
|
||||
/* Now much private space */
|
||||
pvt = sz_pvt ? ((char *)pci) + ((unsigned long)pvt) : NULL;
|
||||
if (sz_pvt) {
|
||||
pci->pvt_info = kzalloc(sz_pvt, GFP_KERNEL);
|
||||
if (!pci->pvt_info)
|
||||
goto free;
|
||||
}
|
||||
|
||||
pci->pvt_info = pvt;
|
||||
pci->op_state = OP_ALLOC;
|
||||
|
||||
snprintf(pci->name, strlen(edac_pci_name) + 1, "%s", edac_pci_name);
|
||||
|
||||
return pci;
|
||||
|
||||
free:
|
||||
kfree(pci);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(edac_pci_alloc_ctl_info);
|
||||
|
||||
|
|
|
@ -15,11 +15,13 @@
|
|||
#include "edac_module.h"
|
||||
#include <ras/ras_event.h>
|
||||
|
||||
#define OTHER_DETAIL_LEN 400
|
||||
|
||||
struct ghes_pvt {
|
||||
struct mem_ctl_info *mci;
|
||||
|
||||
/* Buffers for the error handling routine */
|
||||
char other_detail[400];
|
||||
char other_detail[OTHER_DETAIL_LEN];
|
||||
char msg[80];
|
||||
};
|
||||
|
||||
|
@ -36,7 +38,7 @@ static struct ghes_pvt *ghes_pvt;
|
|||
* This driver's representation of the system hardware, as collected
|
||||
* from DMI.
|
||||
*/
|
||||
struct ghes_hw_desc {
|
||||
static struct ghes_hw_desc {
|
||||
int num_dimms;
|
||||
struct dimm_info *dimms;
|
||||
} ghes_hw;
|
||||
|
@ -235,8 +237,34 @@ static void ghes_scan_system(void)
|
|||
system_scanned = true;
|
||||
}
|
||||
|
||||
static int print_mem_error_other_detail(const struct cper_sec_mem_err *mem, char *msg,
|
||||
const char *location, unsigned int len)
|
||||
{
|
||||
u32 n;
|
||||
|
||||
if (!msg)
|
||||
return 0;
|
||||
|
||||
n = 0;
|
||||
len -= 1;
|
||||
|
||||
n += scnprintf(msg + n, len - n, "APEI location: %s ", location);
|
||||
|
||||
if (!(mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS))
|
||||
goto out;
|
||||
|
||||
n += scnprintf(msg + n, len - n, "status(0x%016llx): ", mem->error_status);
|
||||
n += scnprintf(msg + n, len - n, "%s ", cper_mem_err_status_str(mem->error_status));
|
||||
|
||||
out:
|
||||
msg[n] = '\0';
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
|
||||
{
|
||||
struct cper_mem_err_compact cmem;
|
||||
struct edac_raw_error_desc *e;
|
||||
struct mem_ctl_info *mci;
|
||||
struct ghes_pvt *pvt;
|
||||
|
@ -292,60 +320,10 @@ void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
|
|||
|
||||
/* Error type, mapped on e->msg */
|
||||
if (mem_err->validation_bits & CPER_MEM_VALID_ERROR_TYPE) {
|
||||
u8 etype = mem_err->error_type;
|
||||
|
||||
p = pvt->msg;
|
||||
switch (mem_err->error_type) {
|
||||
case 0:
|
||||
p += sprintf(p, "Unknown");
|
||||
break;
|
||||
case 1:
|
||||
p += sprintf(p, "No error");
|
||||
break;
|
||||
case 2:
|
||||
p += sprintf(p, "Single-bit ECC");
|
||||
break;
|
||||
case 3:
|
||||
p += sprintf(p, "Multi-bit ECC");
|
||||
break;
|
||||
case 4:
|
||||
p += sprintf(p, "Single-symbol ChipKill ECC");
|
||||
break;
|
||||
case 5:
|
||||
p += sprintf(p, "Multi-symbol ChipKill ECC");
|
||||
break;
|
||||
case 6:
|
||||
p += sprintf(p, "Master abort");
|
||||
break;
|
||||
case 7:
|
||||
p += sprintf(p, "Target abort");
|
||||
break;
|
||||
case 8:
|
||||
p += sprintf(p, "Parity Error");
|
||||
break;
|
||||
case 9:
|
||||
p += sprintf(p, "Watchdog timeout");
|
||||
break;
|
||||
case 10:
|
||||
p += sprintf(p, "Invalid address");
|
||||
break;
|
||||
case 11:
|
||||
p += sprintf(p, "Mirror Broken");
|
||||
break;
|
||||
case 12:
|
||||
p += sprintf(p, "Memory Sparing");
|
||||
break;
|
||||
case 13:
|
||||
p += sprintf(p, "Scrub corrected error");
|
||||
break;
|
||||
case 14:
|
||||
p += sprintf(p, "Scrub uncorrected error");
|
||||
break;
|
||||
case 15:
|
||||
p += sprintf(p, "Physical Memory Map-out event");
|
||||
break;
|
||||
default:
|
||||
p += sprintf(p, "reserved error (%d)",
|
||||
mem_err->error_type);
|
||||
}
|
||||
p += snprintf(p, sizeof(pvt->msg), "%s", cper_mem_err_type_str(etype));
|
||||
} else {
|
||||
strcpy(pvt->msg, "unknown error");
|
||||
}
|
||||
|
@ -362,52 +340,19 @@ void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
|
|||
|
||||
/* Memory error location, mapped on e->location */
|
||||
p = e->location;
|
||||
if (mem_err->validation_bits & CPER_MEM_VALID_NODE)
|
||||
p += sprintf(p, "node:%d ", mem_err->node);
|
||||
if (mem_err->validation_bits & CPER_MEM_VALID_CARD)
|
||||
p += sprintf(p, "card:%d ", mem_err->card);
|
||||
if (mem_err->validation_bits & CPER_MEM_VALID_MODULE)
|
||||
p += sprintf(p, "module:%d ", mem_err->module);
|
||||
if (mem_err->validation_bits & CPER_MEM_VALID_RANK_NUMBER)
|
||||
p += sprintf(p, "rank:%d ", mem_err->rank);
|
||||
if (mem_err->validation_bits & CPER_MEM_VALID_BANK)
|
||||
p += sprintf(p, "bank:%d ", mem_err->bank);
|
||||
if (mem_err->validation_bits & CPER_MEM_VALID_BANK_GROUP)
|
||||
p += sprintf(p, "bank_group:%d ",
|
||||
mem_err->bank >> CPER_MEM_BANK_GROUP_SHIFT);
|
||||
if (mem_err->validation_bits & CPER_MEM_VALID_BANK_ADDRESS)
|
||||
p += sprintf(p, "bank_address:%d ",
|
||||
mem_err->bank & CPER_MEM_BANK_ADDRESS_MASK);
|
||||
if (mem_err->validation_bits & (CPER_MEM_VALID_ROW | CPER_MEM_VALID_ROW_EXT)) {
|
||||
u32 row = mem_err->row;
|
||||
cper_mem_err_pack(mem_err, &cmem);
|
||||
p += cper_mem_err_location(&cmem, p);
|
||||
|
||||
row |= cper_get_mem_extension(mem_err->validation_bits, mem_err->extended);
|
||||
p += sprintf(p, "row:%d ", row);
|
||||
}
|
||||
if (mem_err->validation_bits & CPER_MEM_VALID_COLUMN)
|
||||
p += sprintf(p, "col:%d ", mem_err->column);
|
||||
if (mem_err->validation_bits & CPER_MEM_VALID_BIT_POSITION)
|
||||
p += sprintf(p, "bit_pos:%d ", mem_err->bit_pos);
|
||||
if (mem_err->validation_bits & CPER_MEM_VALID_MODULE_HANDLE) {
|
||||
const char *bank = NULL, *device = NULL;
|
||||
struct dimm_info *dimm;
|
||||
|
||||
dmi_memdev_name(mem_err->mem_dev_handle, &bank, &device);
|
||||
if (bank != NULL && device != NULL)
|
||||
p += sprintf(p, "DIMM location:%s %s ", bank, device);
|
||||
else
|
||||
p += sprintf(p, "DIMM DMI handle: 0x%.4x ",
|
||||
mem_err->mem_dev_handle);
|
||||
|
||||
p += cper_dimm_err_location(&cmem, p);
|
||||
dimm = find_dimm_by_handle(mci, mem_err->mem_dev_handle);
|
||||
if (dimm) {
|
||||
e->top_layer = dimm->idx;
|
||||
strcpy(e->label, dimm->label);
|
||||
}
|
||||
}
|
||||
if (mem_err->validation_bits & CPER_MEM_VALID_CHIP_ID)
|
||||
p += sprintf(p, "chipID: %d ",
|
||||
mem_err->extended >> CPER_MEM_CHIP_ID_SHIFT);
|
||||
if (p > e->location)
|
||||
*(p - 1) = '\0';
|
||||
|
||||
|
@ -416,78 +361,7 @@ void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
|
|||
|
||||
/* All other fields are mapped on e->other_detail */
|
||||
p = pvt->other_detail;
|
||||
p += snprintf(p, sizeof(pvt->other_detail),
|
||||
"APEI location: %s ", e->location);
|
||||
if (mem_err->validation_bits & CPER_MEM_VALID_ERROR_STATUS) {
|
||||
u64 status = mem_err->error_status;
|
||||
|
||||
p += sprintf(p, "status(0x%016llx): ", (long long)status);
|
||||
switch ((status >> 8) & 0xff) {
|
||||
case 1:
|
||||
p += sprintf(p, "Error detected internal to the component ");
|
||||
break;
|
||||
case 16:
|
||||
p += sprintf(p, "Error detected in the bus ");
|
||||
break;
|
||||
case 4:
|
||||
p += sprintf(p, "Storage error in DRAM memory ");
|
||||
break;
|
||||
case 5:
|
||||
p += sprintf(p, "Storage error in TLB ");
|
||||
break;
|
||||
case 6:
|
||||
p += sprintf(p, "Storage error in cache ");
|
||||
break;
|
||||
case 7:
|
||||
p += sprintf(p, "Error in one or more functional units ");
|
||||
break;
|
||||
case 8:
|
||||
p += sprintf(p, "component failed self test ");
|
||||
break;
|
||||
case 9:
|
||||
p += sprintf(p, "Overflow or undervalue of internal queue ");
|
||||
break;
|
||||
case 17:
|
||||
p += sprintf(p, "Virtual address not found on IO-TLB or IO-PDIR ");
|
||||
break;
|
||||
case 18:
|
||||
p += sprintf(p, "Improper access error ");
|
||||
break;
|
||||
case 19:
|
||||
p += sprintf(p, "Access to a memory address which is not mapped to any component ");
|
||||
break;
|
||||
case 20:
|
||||
p += sprintf(p, "Loss of Lockstep ");
|
||||
break;
|
||||
case 21:
|
||||
p += sprintf(p, "Response not associated with a request ");
|
||||
break;
|
||||
case 22:
|
||||
p += sprintf(p, "Bus parity error - must also set the A, C, or D Bits ");
|
||||
break;
|
||||
case 23:
|
||||
p += sprintf(p, "Detection of a PATH_ERROR ");
|
||||
break;
|
||||
case 25:
|
||||
p += sprintf(p, "Bus operation timeout ");
|
||||
break;
|
||||
case 26:
|
||||
p += sprintf(p, "A read was issued to data that has been poisoned ");
|
||||
break;
|
||||
default:
|
||||
p += sprintf(p, "reserved ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mem_err->validation_bits & CPER_MEM_VALID_REQUESTOR_ID)
|
||||
p += sprintf(p, "requestorID: 0x%016llx ",
|
||||
(long long)mem_err->requestor_id);
|
||||
if (mem_err->validation_bits & CPER_MEM_VALID_RESPONDER_ID)
|
||||
p += sprintf(p, "responderID: 0x%016llx ",
|
||||
(long long)mem_err->responder_id);
|
||||
if (mem_err->validation_bits & CPER_MEM_VALID_TARGET_ID)
|
||||
p += sprintf(p, "targetID: 0x%016llx ",
|
||||
(long long)mem_err->responder_id);
|
||||
p += print_mem_error_other_detail(mem_err, p, e->location, OTHER_DETAIL_LEN);
|
||||
if (p > pvt->other_detail)
|
||||
*(p - 1) = '\0';
|
||||
|
||||
|
|
|
@ -244,11 +244,6 @@ static inline u32 i5100_nrecmema_rank(u32 a)
|
|||
return a >> 8 & ((1 << 3) - 1);
|
||||
}
|
||||
|
||||
static inline u32 i5100_nrecmema_dm_buf_id(u32 a)
|
||||
{
|
||||
return a & ((1 << 8) - 1);
|
||||
}
|
||||
|
||||
static inline u32 i5100_nrecmemb_cas(u32 a)
|
||||
{
|
||||
return a >> 16 & ((1 << 13) - 1);
|
||||
|
|
|
@ -609,13 +609,6 @@ static int mpc85xx_l2_err_remove(struct platform_device *op)
|
|||
}
|
||||
|
||||
static const struct of_device_id mpc85xx_l2_err_of_match[] = {
|
||||
/* deprecate the fsl,85.. forms in the future, 2.6.30? */
|
||||
{ .compatible = "fsl,8540-l2-cache-controller", },
|
||||
{ .compatible = "fsl,8541-l2-cache-controller", },
|
||||
{ .compatible = "fsl,8544-l2-cache-controller", },
|
||||
{ .compatible = "fsl,8548-l2-cache-controller", },
|
||||
{ .compatible = "fsl,8555-l2-cache-controller", },
|
||||
{ .compatible = "fsl,8568-l2-cache-controller", },
|
||||
{ .compatible = "fsl,mpc8536-l2-cache-controller", },
|
||||
{ .compatible = "fsl,mpc8540-l2-cache-controller", },
|
||||
{ .compatible = "fsl,mpc8541-l2-cache-controller", },
|
||||
|
@ -644,13 +637,6 @@ static struct platform_driver mpc85xx_l2_err_driver = {
|
|||
};
|
||||
|
||||
static const struct of_device_id mpc85xx_mc_err_of_match[] = {
|
||||
/* deprecate the fsl,85.. forms in the future, 2.6.30? */
|
||||
{ .compatible = "fsl,8540-memory-controller", },
|
||||
{ .compatible = "fsl,8541-memory-controller", },
|
||||
{ .compatible = "fsl,8544-memory-controller", },
|
||||
{ .compatible = "fsl,8548-memory-controller", },
|
||||
{ .compatible = "fsl,8555-memory-controller", },
|
||||
{ .compatible = "fsl,8568-memory-controller", },
|
||||
{ .compatible = "fsl,mpc8536-memory-controller", },
|
||||
{ .compatible = "fsl,mpc8540-memory-controller", },
|
||||
{ .compatible = "fsl,mpc8541-memory-controller", },
|
||||
|
|
|
@ -1,22 +1,9 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Synopsys DDR ECC Driver
|
||||
* This driver is based on ppc4xx_edac.c drivers
|
||||
*
|
||||
* Copyright (C) 2012 - 2014 Xilinx, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details
|
||||
*/
|
||||
|
||||
#include <linux/edac.h>
|
||||
|
|
|
@ -501,7 +501,7 @@ static int xgene_edac_mc_remove(struct xgene_edac_mc_ctx *mcu)
|
|||
#define MEMERR_L2C_L2ESRA_PAGE_OFFSET 0x0804
|
||||
|
||||
/*
|
||||
* Processor Module Domain (PMD) context - Context for a pair of processsors.
|
||||
* Processor Module Domain (PMD) context - Context for a pair of processors.
|
||||
* Each PMD consists of 2 CPUs and a shared L2 cache. Each CPU consists of
|
||||
* its own L1 cache.
|
||||
*/
|
||||
|
|
|
@ -211,7 +211,33 @@ const char *cper_mem_err_type_str(unsigned int etype)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(cper_mem_err_type_str);
|
||||
|
||||
static int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg)
|
||||
const char *cper_mem_err_status_str(u64 status)
|
||||
{
|
||||
switch ((status >> 8) & 0xff) {
|
||||
case 1: return "Error detected internal to the component";
|
||||
case 4: return "Storage error in DRAM memory";
|
||||
case 5: return "Storage error in TLB";
|
||||
case 6: return "Storage error in cache";
|
||||
case 7: return "Error in one or more functional units";
|
||||
case 8: return "Component failed self test";
|
||||
case 9: return "Overflow or undervalue of internal queue";
|
||||
case 16: return "Error detected in the bus";
|
||||
case 17: return "Virtual address not found on IO-TLB or IO-PDIR";
|
||||
case 18: return "Improper access error";
|
||||
case 19: return "Access to a memory address which is not mapped to any component";
|
||||
case 20: return "Loss of Lockstep";
|
||||
case 21: return "Response not associated with a request";
|
||||
case 22: return "Bus parity error - must also set the A, C, or D Bits";
|
||||
case 23: return "Detection of a protocol error";
|
||||
case 24: return "Detection of a PATH_ERROR";
|
||||
case 25: return "Bus operation timeout";
|
||||
case 26: return "A read was issued to data that has been poisoned";
|
||||
default: return "Reserved";
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cper_mem_err_status_str);
|
||||
|
||||
int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg)
|
||||
{
|
||||
u32 len, n;
|
||||
|
||||
|
@ -221,51 +247,51 @@ static int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg)
|
|||
n = 0;
|
||||
len = CPER_REC_LEN;
|
||||
if (mem->validation_bits & CPER_MEM_VALID_NODE)
|
||||
n += scnprintf(msg + n, len - n, "node: %d ", mem->node);
|
||||
n += scnprintf(msg + n, len - n, "node:%d ", mem->node);
|
||||
if (mem->validation_bits & CPER_MEM_VALID_CARD)
|
||||
n += scnprintf(msg + n, len - n, "card: %d ", mem->card);
|
||||
n += scnprintf(msg + n, len - n, "card:%d ", mem->card);
|
||||
if (mem->validation_bits & CPER_MEM_VALID_MODULE)
|
||||
n += scnprintf(msg + n, len - n, "module: %d ", mem->module);
|
||||
n += scnprintf(msg + n, len - n, "module:%d ", mem->module);
|
||||
if (mem->validation_bits & CPER_MEM_VALID_RANK_NUMBER)
|
||||
n += scnprintf(msg + n, len - n, "rank: %d ", mem->rank);
|
||||
n += scnprintf(msg + n, len - n, "rank:%d ", mem->rank);
|
||||
if (mem->validation_bits & CPER_MEM_VALID_BANK)
|
||||
n += scnprintf(msg + n, len - n, "bank: %d ", mem->bank);
|
||||
n += scnprintf(msg + n, len - n, "bank:%d ", mem->bank);
|
||||
if (mem->validation_bits & CPER_MEM_VALID_BANK_GROUP)
|
||||
n += scnprintf(msg + n, len - n, "bank_group: %d ",
|
||||
n += scnprintf(msg + n, len - n, "bank_group:%d ",
|
||||
mem->bank >> CPER_MEM_BANK_GROUP_SHIFT);
|
||||
if (mem->validation_bits & CPER_MEM_VALID_BANK_ADDRESS)
|
||||
n += scnprintf(msg + n, len - n, "bank_address: %d ",
|
||||
n += scnprintf(msg + n, len - n, "bank_address:%d ",
|
||||
mem->bank & CPER_MEM_BANK_ADDRESS_MASK);
|
||||
if (mem->validation_bits & CPER_MEM_VALID_DEVICE)
|
||||
n += scnprintf(msg + n, len - n, "device: %d ", mem->device);
|
||||
n += scnprintf(msg + n, len - n, "device:%d ", mem->device);
|
||||
if (mem->validation_bits & (CPER_MEM_VALID_ROW | CPER_MEM_VALID_ROW_EXT)) {
|
||||
u32 row = mem->row;
|
||||
|
||||
row |= cper_get_mem_extension(mem->validation_bits, mem->extended);
|
||||
n += scnprintf(msg + n, len - n, "row: %d ", row);
|
||||
n += scnprintf(msg + n, len - n, "row:%d ", row);
|
||||
}
|
||||
if (mem->validation_bits & CPER_MEM_VALID_COLUMN)
|
||||
n += scnprintf(msg + n, len - n, "column: %d ", mem->column);
|
||||
n += scnprintf(msg + n, len - n, "column:%d ", mem->column);
|
||||
if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION)
|
||||
n += scnprintf(msg + n, len - n, "bit_position: %d ",
|
||||
n += scnprintf(msg + n, len - n, "bit_position:%d ",
|
||||
mem->bit_pos);
|
||||
if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID)
|
||||
n += scnprintf(msg + n, len - n, "requestor_id: 0x%016llx ",
|
||||
n += scnprintf(msg + n, len - n, "requestor_id:0x%016llx ",
|
||||
mem->requestor_id);
|
||||
if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID)
|
||||
n += scnprintf(msg + n, len - n, "responder_id: 0x%016llx ",
|
||||
n += scnprintf(msg + n, len - n, "responder_id:0x%016llx ",
|
||||
mem->responder_id);
|
||||
if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID)
|
||||
n += scnprintf(msg + n, len - n, "target_id: 0x%016llx ",
|
||||
n += scnprintf(msg + n, len - n, "target_id:0x%016llx ",
|
||||
mem->target_id);
|
||||
if (mem->validation_bits & CPER_MEM_VALID_CHIP_ID)
|
||||
n += scnprintf(msg + n, len - n, "chip_id: %d ",
|
||||
n += scnprintf(msg + n, len - n, "chip_id:%d ",
|
||||
mem->extended >> CPER_MEM_CHIP_ID_SHIFT);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static int cper_dimm_err_location(struct cper_mem_err_compact *mem, char *msg)
|
||||
int cper_dimm_err_location(struct cper_mem_err_compact *mem, char *msg)
|
||||
{
|
||||
u32 len, n;
|
||||
const char *bank = NULL, *device = NULL;
|
||||
|
@ -334,7 +360,9 @@ static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem,
|
|||
return;
|
||||
}
|
||||
if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS)
|
||||
printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status);
|
||||
printk("%s error_status: %s (0x%016llx)\n",
|
||||
pfx, cper_mem_err_status_str(mem->error_status),
|
||||
mem->error_status);
|
||||
if (mem->validation_bits & CPER_MEM_VALID_PA)
|
||||
printk("%s""physical_address: 0x%016llx\n",
|
||||
pfx, mem->physical_addr);
|
||||
|
|
|
@ -558,6 +558,7 @@ extern const char *const cper_proc_error_type_strs[4];
|
|||
u64 cper_next_record_id(void);
|
||||
const char *cper_severity_str(unsigned int);
|
||||
const char *cper_mem_err_type_str(unsigned int);
|
||||
const char *cper_mem_err_status_str(u64 status);
|
||||
void cper_print_bits(const char *prefix, unsigned int bits,
|
||||
const char * const strs[], unsigned int strs_size);
|
||||
void cper_mem_err_pack(const struct cper_sec_mem_err *,
|
||||
|
@ -568,5 +569,7 @@ void cper_print_proc_arm(const char *pfx,
|
|||
const struct cper_sec_proc_arm *proc);
|
||||
void cper_print_proc_ia(const char *pfx,
|
||||
const struct cper_sec_proc_ia *proc);
|
||||
int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg);
|
||||
int cper_dimm_err_location(struct cper_mem_err_compact *mem, char *msg);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue