summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2024-09-16 06:36:37 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2024-09-16 06:36:37 +0200
commit7dfc15c47372e8bf8a693ca3dfaaec33a68ee116 (patch)
tree39406baf3f61b798f1f2c12911e9abe0e256c525
parent1636f57c7841101af8bd4872aafb79cfc74bf389 (diff)
parent92f8358bce13da0b2c37122573a2b2d7de0071df (diff)
downloadlinux-7dfc15c47372e8bf8a693ca3dfaaec33a68ee116.tar.gz
linux-7dfc15c47372e8bf8a693ca3dfaaec33a68ee116.tar.bz2
linux-7dfc15c47372e8bf8a693ca3dfaaec33a68ee116.zip
Merge tag 'edac_updates_for_v6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/ras/ras
Pull EDAC updates from Borislav Petkov: - Drop a now obsolete ppc4xx_edac driver - Fix conversion to physical memory addresses on Intel's Elkhart Lake and Ice Lake hardware when the system address is above the (Top-Of-Memory) TOM address - Pay attention to the memory hole on Zynq UltraScale+ MPSoC DDR controllers when injecting errors for testing purposes - Add support for translating normalized error addresses reported by an AMD memory controller into system physical addresses using an UEFI mechanism called platform runtime mechanism (PRM). - The usual cleanups and fixes * tag 'edac_updates_for_v6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/ras/ras: EDAC: Drop obsolete PPC4xx driver EDAC/sb_edac: Fix the compile warning of large frame size EDAC/{skx_common,i10nm}: Remove the AMAP register for determing DDR5 EDAC/{skx_common,skx,i10nm}: Move the common debug code to skx_common EDAC/igen6: Fix conversion of system address to physical memory address EDAC/synopsys: Fix error injection on Zynq UltraScale+ RAS/AMD/ATL: Translate normalized to system physical addresses using PRM ACPI: PRM: Add PRM handler direct call support
-rw-r--r--drivers/acpi/prmt.c24
-rw-r--r--drivers/edac/Kconfig9
-rw-r--r--drivers/edac/Makefile1
-rw-r--r--drivers/edac/i10nm_base.c61
-rw-r--r--drivers/edac/igen6_edac.c2
-rw-r--r--drivers/edac/ppc4xx_edac.c1425
-rw-r--r--drivers/edac/ppc4xx_edac.h167
-rw-r--r--drivers/edac/sb_edac.c35
-rw-r--r--drivers/edac/skx_base.c52
-rw-r--r--drivers/edac/skx_common.c49
-rw-r--r--drivers/edac/skx_common.h8
-rw-r--r--drivers/edac/synopsys_edac.c35
-rw-r--r--drivers/ras/amd/atl/Kconfig4
-rw-r--r--drivers/ras/amd/atl/Makefile2
-rw-r--r--drivers/ras/amd/atl/internal.h10
-rw-r--r--drivers/ras/amd/atl/prm.c57
-rw-r--r--drivers/ras/amd/atl/umc.c5
-rw-r--r--include/linux/prmt.h5
18 files changed, 222 insertions, 1729 deletions
diff --git a/drivers/acpi/prmt.c b/drivers/acpi/prmt.c
index c78453c74ef5..1cfaa5957ac4 100644
--- a/drivers/acpi/prmt.c
+++ b/drivers/acpi/prmt.c
@@ -214,6 +214,30 @@ static struct prm_handler_info *find_prm_handler(const guid_t *guid)
#define UPDATE_LOCK_ALREADY_HELD 4
#define UPDATE_UNLOCK_WITHOUT_LOCK 5
+int acpi_call_prm_handler(guid_t handler_guid, void *param_buffer)
+{
+ struct prm_handler_info *handler = find_prm_handler(&handler_guid);
+ struct prm_module_info *module = find_prm_module(&handler_guid);
+ struct prm_context_buffer context;
+ efi_status_t status;
+
+ if (!module || !handler)
+ return -ENODEV;
+
+ memset(&context, 0, sizeof(context));
+ ACPI_COPY_NAMESEG(context.signature, "PRMC");
+ context.identifier = handler->guid;
+ context.static_data_buffer = handler->static_data_buffer_addr;
+ context.mmio_ranges = module->mmio_info;
+
+ status = efi_call_acpi_prm_handler(handler->handler_addr,
+ (u64)param_buffer,
+ &context);
+
+ return efi_status_to_err(status);
+}
+EXPORT_SYMBOL_GPL(acpi_call_prm_handler);
+
/*
* This is the PlatformRtMechanism opregion space handler.
* @function: indicates the read/write. In fact as the PlatformRtMechanism
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 16c8de5050e5..81af6c344d6b 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -311,15 +311,6 @@ config EDAC_CELL
Cell Broadband Engine internal memory controller
on platform without a hypervisor
-config EDAC_PPC4XX
- tristate "PPC4xx IBM DDR2 Memory Controller"
- depends on 4xx
- help
- This enables support for EDAC on the ECC memory used
- with the IBM DDR2 memory controller found in various
- PowerPC 4xx embedded processors such as the 405EX[r],
- 440SP, 440SPe, 460EX, 460GT and 460SX.
-
config EDAC_AMD8131
tristate "AMD8131 HyperTransport PCI-X Tunnel"
depends on PCI && PPC_MAPLE
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index 4edfb83ffbee..faf310eec4a6 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -63,7 +63,6 @@ i10nm_edac-y := i10nm_base.o
obj-$(CONFIG_EDAC_I10NM) += i10nm_edac.o skx_edac_common.o
obj-$(CONFIG_EDAC_CELL) += cell_edac.o
-obj-$(CONFIG_EDAC_PPC4XX) += ppc4xx_edac.o
obj-$(CONFIG_EDAC_AMD8111) += amd8111_edac.o
obj-$(CONFIG_EDAC_AMD8131) += amd8131_edac.o
diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c
index 24dd896d9a9d..e2a954de913b 100644
--- a/drivers/edac/i10nm_base.c
+++ b/drivers/edac/i10nm_base.c
@@ -47,10 +47,6 @@
readl((m)->mbase + ((m)->hbm_mc ? 0xef8 : \
(res_cfg->type == GNR ? 0xaf8 : 0x20ef8)) + \
(i) * (m)->chan_mmio_sz)
-#define I10NM_GET_AMAP(m, i) \
- readl((m)->mbase + ((m)->hbm_mc ? 0x814 : \
- (res_cfg->type == GNR ? 0xc14 : 0x20814)) + \
- (i) * (m)->chan_mmio_sz)
#define I10NM_GET_REG32(m, i, offset) \
readl((m)->mbase + (i) * (m)->chan_mmio_sz + (offset))
#define I10NM_GET_REG64(m, i, offset) \
@@ -971,7 +967,7 @@ static int i10nm_get_dimm_config(struct mem_ctl_info *mci,
{
struct skx_pvt *pvt = mci->pvt_info;
struct skx_imc *imc = pvt->imc;
- u32 mtr, amap, mcddrtcfg = 0;
+ u32 mtr, mcddrtcfg = 0;
struct dimm_info *dimm;
int i, j, ndimms;
@@ -980,7 +976,6 @@ static int i10nm_get_dimm_config(struct mem_ctl_info *mci,
continue;
ndimms = 0;
- amap = I10NM_GET_AMAP(imc, i);
if (res_cfg->type != GNR)
mcddrtcfg = I10NM_GET_MCDDRTCFG(imc, i);
@@ -992,7 +987,7 @@ static int i10nm_get_dimm_config(struct mem_ctl_info *mci,
mtr, mcddrtcfg, imc->mc, i, j);
if (IS_DIMM_PRESENT(mtr))
- ndimms += skx_get_dimm_info(mtr, 0, amap, dimm,
+ ndimms += skx_get_dimm_info(mtr, 0, 0, dimm,
imc, i, j, cfg);
else if (IS_NVDIMM_PRESENT(mcddrtcfg, j))
ndimms += skx_get_nvdimm_info(dimm, imc, i, j,
@@ -1013,54 +1008,6 @@ static struct notifier_block i10nm_mce_dec = {
.priority = MCE_PRIO_EDAC,
};
-#ifdef CONFIG_EDAC_DEBUG
-/*
- * Debug feature.
- * Exercise the address decode logic by writing an address to
- * /sys/kernel/debug/edac/i10nm_test/addr.
- */
-static struct dentry *i10nm_test;
-
-static int debugfs_u64_set(void *data, u64 val)
-{
- struct mce m;
-
- pr_warn_once("Fake error to 0x%llx injected via debugfs\n", val);
-
- memset(&m, 0, sizeof(m));
- /* ADDRV + MemRd + Unknown channel */
- m.status = MCI_STATUS_ADDRV + 0x90;
- /* One corrected error */
- m.status |= BIT_ULL(MCI_STATUS_CEC_SHIFT);
- m.addr = val;
- skx_mce_check_error(NULL, 0, &m);
-
- return 0;
-}
-DEFINE_SIMPLE_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%llu\n");
-
-static void setup_i10nm_debug(void)
-{
- i10nm_test = edac_debugfs_create_dir("i10nm_test");
- if (!i10nm_test)
- return;
-
- if (!edac_debugfs_create_file("addr", 0200, i10nm_test,
- NULL, &fops_u64_wo)) {
- debugfs_remove(i10nm_test);
- i10nm_test = NULL;
- }
-}
-
-static void teardown_i10nm_debug(void)
-{
- debugfs_remove_recursive(i10nm_test);
-}
-#else
-static inline void setup_i10nm_debug(void) {}
-static inline void teardown_i10nm_debug(void) {}
-#endif /*CONFIG_EDAC_DEBUG*/
-
static int __init i10nm_init(void)
{
u8 mc = 0, src_id = 0, node_id = 0;
@@ -1159,7 +1106,7 @@ static int __init i10nm_init(void)
opstate_init();
mce_register_decode_chain(&i10nm_mce_dec);
- setup_i10nm_debug();
+ skx_setup_debug("i10nm_test");
if (retry_rd_err_log && res_cfg->offsets_scrub && res_cfg->offsets_demand) {
skx_set_decode(i10nm_mc_decode, show_retry_rd_err_log);
@@ -1187,7 +1134,7 @@ static void __exit i10nm_exit(void)
enable_retry_rd_err_log(false);
}
- teardown_i10nm_debug();
+ skx_teardown_debug();
mce_unregister_decode_chain(&i10nm_mce_dec);
skx_adxl_put();
skx_remove();
diff --git a/drivers/edac/igen6_edac.c b/drivers/edac/igen6_edac.c
index 0fe75eed8973..189a2fc29e74 100644
--- a/drivers/edac/igen6_edac.c
+++ b/drivers/edac/igen6_edac.c
@@ -316,7 +316,7 @@ static u64 ehl_err_addr_to_imc_addr(u64 eaddr, int mc)
if (igen6_tom <= _4GB)
return eaddr + igen6_tolud - _4GB;
- if (eaddr < _4GB)
+ if (eaddr >= igen6_tom)
return eaddr + igen6_tolud - igen6_tom;
return eaddr;
diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c
deleted file mode 100644
index 1eea3341a916..000000000000
--- a/drivers/edac/ppc4xx_edac.c
+++ /dev/null
@@ -1,1425 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2008 Nuovation System Designs, LLC
- * Grant Erickson <gerickson@nuovations.com>
- */
-
-#include <linux/edac.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/of_irq.h>
-#include <linux/of_platform.h>
-#include <linux/types.h>
-
-#include <asm/dcr.h>
-
-#include "edac_module.h"
-#include "ppc4xx_edac.h"
-
-/*
- * This file implements a driver for monitoring and handling events
- * associated with the IMB DDR2 ECC controller found in the AMCC/IBM
- * 405EX[r], 440SP, 440SPe, 460EX, 460GT and 460SX.
- *
- * As realized in the 405EX[r], this controller features:
- *
- * - Support for registered- and non-registered DDR1 and DDR2 memory.
- * - 32-bit or 16-bit memory interface with optional ECC.
- *
- * o ECC support includes:
- *
- * - 4-bit SEC/DED
- * - Aligned-nibble error detect
- * - Bypass mode
- *
- * - Two (2) memory banks/ranks.
- * - Up to 1 GiB per bank/rank in 32-bit mode and up to 512 MiB per
- * bank/rank in 16-bit mode.
- *
- * As realized in the 440SP and 440SPe, this controller changes/adds:
- *
- * - 64-bit or 32-bit memory interface with optional ECC.
- *
- * o ECC support includes:
- *
- * - 8-bit SEC/DED
- * - Aligned-nibble error detect
- * - Bypass mode
- *
- * - Up to 4 GiB per bank/rank in 64-bit mode and up to 2 GiB
- * per bank/rank in 32-bit mode.
- *
- * As realized in the 460EX and 460GT, this controller changes/adds:
- *
- * - 64-bit or 32-bit memory interface with optional ECC.
- *
- * o ECC support includes:
- *
- * - 8-bit SEC/DED
- * - Aligned-nibble error detect
- * - Bypass mode
- *
- * - Four (4) memory banks/ranks.
- * - Up to 16 GiB per bank/rank in 64-bit mode and up to 8 GiB
- * per bank/rank in 32-bit mode.
- *
- * At present, this driver has ONLY been tested against the controller
- * realization in the 405EX[r] on the AMCC Kilauea and Haleakala
- * boards (256 MiB w/o ECC memory soldered onto the board) and a
- * proprietary board based on those designs (128 MiB ECC memory, also
- * soldered onto the board).
- *
- * Dynamic feature detection and handling needs to be added for the
- * other realizations of this controller listed above.
- *
- * Eventually, this driver will likely be adapted to the above variant
- * realizations of this controller as well as broken apart to handle
- * the other known ECC-capable controllers prevalent in other 4xx
- * processors:
- *
- * - IBM SDRAM (405GP, 405CR and 405EP) "ibm,sdram-4xx"
- * - IBM DDR1 (440GP, 440GX, 440EP and 440GR) "ibm,sdram-4xx-ddr"
- * - Denali DDR1/DDR2 (440EPX and 440GRX) "denali,sdram-4xx-ddr2"
- *
- * For this controller, unfortunately, correctable errors report
- * nothing more than the beat/cycle and byte/lane the correction
- * occurred on and the check bit group that covered the error.
- *
- * In contrast, uncorrectable errors also report the failing address,
- * the bus master and the transaction direction (i.e. read or write)
- *
- * Regardless of whether the error is a CE or a UE, we report the
- * following pieces of information in the driver-unique message to the
- * EDAC subsystem:
- *
- * - Device tree path
- * - Bank(s)
- * - Check bit error group
- * - Beat(s)/lane(s)
- */
-
-/* Preprocessor Definitions */
-
-#define EDAC_OPSTATE_INT_STR "interrupt"
-#define EDAC_OPSTATE_POLL_STR "polled"
-#define EDAC_OPSTATE_UNKNOWN_STR "unknown"
-
-#define PPC4XX_EDAC_MODULE_NAME "ppc4xx_edac"
-#define PPC4XX_EDAC_MODULE_REVISION "v1.0.0"
-
-#define PPC4XX_EDAC_MESSAGE_SIZE 256
-
-/*
- * Kernel logging without an EDAC instance
- */
-#define ppc4xx_edac_printk(level, fmt, arg...) \
- edac_printk(level, "PPC4xx MC", fmt, ##arg)
-
-/*
- * Kernel logging with an EDAC instance
- */
-#define ppc4xx_edac_mc_printk(level, mci, fmt, arg...) \
- edac_mc_chipset_printk(mci, level, "PPC4xx", fmt, ##arg)
-
-/*
- * Macros to convert bank configuration size enumerations into MiB and
- * page values.
- */
-#define SDRAM_MBCF_SZ_MiB_MIN 4
-#define SDRAM_MBCF_SZ_TO_MiB(n) (SDRAM_MBCF_SZ_MiB_MIN \
- << (SDRAM_MBCF_SZ_DECODE(n)))
-#define SDRAM_MBCF_SZ_TO_PAGES(n) (SDRAM_MBCF_SZ_MiB_MIN \
- << (20 - PAGE_SHIFT + \
- SDRAM_MBCF_SZ_DECODE(n)))
-
-/*
- * The ibm,sdram-4xx-ddr2 Device Control Registers (DCRs) are
- * indirectly accessed and have a base and length defined by the
- * device tree. The base can be anything; however, we expect the
- * length to be precisely two registers, the first for the address
- * window and the second for the data window.
- */
-#define SDRAM_DCR_RESOURCE_LEN 2
-#define SDRAM_DCR_ADDR_OFFSET 0
-#define SDRAM_DCR_DATA_OFFSET 1
-
-/*
- * Device tree interrupt indices
- */
-#define INTMAP_ECCDED_INDEX 0 /* Double-bit Error Detect */
-#define INTMAP_ECCSEC_INDEX 1 /* Single-bit Error Correct */
-
-/* Type Definitions */
-
-/*
- * PPC4xx SDRAM memory controller private instance data
- */
-struct ppc4xx_edac_pdata {
- dcr_host_t dcr_host; /* Indirect DCR address/data window mapping */
- struct {
- int sec; /* Single-bit correctable error IRQ assigned */
- int ded; /* Double-bit detectable error IRQ assigned */
- } irqs;
-};
-
-/*
- * Various status data gathered and manipulated when checking and
- * reporting ECC status.
- */
-struct ppc4xx_ecc_status {
- u32 ecces;
- u32 besr;
- u32 bearh;
- u32 bearl;
- u32 wmirq;
-};
-
-/* Global Variables */
-
-/*
- * Device tree node type and compatible tuples this driver can match
- * on.
- */
-static const struct of_device_id ppc4xx_edac_match[] = {
- {
- .compatible = "ibm,sdram-4xx-ddr2"
- },
- { }
-};
-MODULE_DEVICE_TABLE(of, ppc4xx_edac_match);
-
-/*
- * TODO: The row and channel parameters likely need to be dynamically
- * set based on the aforementioned variant controller realizations.
- */
-static const unsigned ppc4xx_edac_nr_csrows = 2;
-static const unsigned ppc4xx_edac_nr_chans = 1;
-
-/*
- * Strings associated with PLB master IDs capable of being posted in
- * SDRAM_BESR or SDRAM_WMIRQ on uncorrectable ECC errors.
- */
-static const char * const ppc4xx_plb_masters[9] = {
- [SDRAM_PLB_M0ID_ICU] = "ICU",
- [SDRAM_PLB_M0ID_PCIE0] = "PCI-E 0",
- [SDRAM_PLB_M0ID_PCIE1] = "PCI-E 1",
- [SDRAM_PLB_M0ID_DMA] = "DMA",
- [SDRAM_PLB_M0ID_DCU] = "DCU",
- [SDRAM_PLB_M0ID_OPB] = "OPB",
- [SDRAM_PLB_M0ID_MAL] = "MAL",
- [SDRAM_PLB_M0ID_SEC] = "SEC",
- [SDRAM_PLB_M0ID_AHB] = "AHB"
-};
-
-/**
- * mfsdram - read and return controller register data
- * @dcr_host: A pointer to the DCR mapping.
- * @idcr_n: The indirect DCR register to read.
- *
- * This routine reads and returns the data associated with the
- * controller's specified indirect DCR register.
- *
- * Returns the read data.
- */
-static inline u32
-mfsdram(const dcr_host_t *dcr_host, unsigned int idcr_n)
-{
- return __mfdcri(dcr_host->base + SDRAM_DCR_ADDR_OFFSET,
- dcr_host->base + SDRAM_DCR_DATA_OFFSET,
- idcr_n);
-}
-
-/**
- * mtsdram - write controller register data
- * @dcr_host: A pointer to the DCR mapping.
- * @idcr_n: The indirect DCR register to write.
- * @value: The data to write.
- *
- * This routine writes the provided data to the controller's specified
- * indirect DCR register.
- */
-static inline void
-mtsdram(const dcr_host_t *dcr_host, unsigned int idcr_n, u32 value)
-{
- return __mtdcri(dcr_host->base + SDRAM_DCR_ADDR_OFFSET,
- dcr_host->base + SDRAM_DCR_DATA_OFFSET,
- idcr_n,
- value);
-}
-
-/**
- * ppc4xx_edac_check_bank_error - check a bank for an ECC bank error
- * @status: A pointer to the ECC status structure to check for an
- * ECC bank error.
- * @bank: The bank to check for an ECC error.
- *
- * This routine determines whether the specified bank has an ECC
- * error.
- *
- * Returns true if the specified bank has an ECC error; otherwise,
- * false.
- */
-static bool
-ppc4xx_edac_check_bank_error(const struct ppc4xx_ecc_status *status,
- unsigned int bank)
-{
- switch (bank) {
- case 0:
- return status->ecces & SDRAM_ECCES_BK0ER;
- case 1:
- return status->ecces & SDRAM_ECCES_BK1ER;
- default:
- return false;
- }
-}
-
-/**
- * ppc4xx_edac_generate_bank_message - generate interpretted bank status message
- * @mci: A pointer to the EDAC memory controller instance associated
- * with the bank message being generated.
- * @status: A pointer to the ECC status structure to generate the
- * message from.
- * @buffer: A pointer to the buffer in which to generate the
- * message.
- * @size: The size, in bytes, of space available in buffer.
- *
- * This routine generates to the provided buffer the portion of the
- * driver-unique report message associated with the ECCESS[BKNER]
- * field of the specified ECC status.
- *
- * Returns the number of characters generated on success; otherwise, <
- * 0 on error.
- */
-static int
-ppc4xx_edac_generate_bank_message(const struct mem_ctl_info *mci,
- const struct ppc4xx_ecc_status *status,
- char *buffer,
- size_t size)
-{
- int n, total = 0;
- unsigned int row, rows;
-
- n = snprintf(buffer, size, "%s: Banks: ", mci->dev_name);
-
- if (n < 0 || n >= size)
- goto fail;
-
- buffer += n;
- size -= n;
- total += n;
-
- for (rows = 0, row = 0; row < mci->nr_csrows; row++) {
- if (ppc4xx_edac_check_bank_error(status, row)) {
- n = snprintf(buffer, size, "%s%u",
- (rows++ ? ", " : ""), row);
-
- if (n < 0 || n >= size)
- goto fail;
-
- buffer += n;
- size -= n;
- total += n;
- }
- }
-
- n = snprintf(buffer, size, "%s; ", rows ? "" : "None");
-
- if (n < 0 || n >= size)
- goto fail;
-
- buffer += n;
- size -= n;
- total += n;
-
- fail:
- return total;
-}
-
-/**
- * ppc4xx_edac_generate_checkbit_message - generate interpretted checkbit message
- * @mci: A pointer to the EDAC memory controller instance associated
- * with the checkbit message being generated.
- * @status: A pointer to the ECC status structure to generate the
- * message from.
- * @buffer: A pointer to the buffer in which to generate the
- * message.
- * @size: The size, in bytes, of space available in buffer.
- *
- * This routine generates to the provided buffer the portion of the
- * driver-unique report message associated with the ECCESS[CKBER]
- * field of the specified ECC status.
- *
- * Returns the number of characters generated on success; otherwise, <
- * 0 on error.
- */
-static int
-ppc4xx_edac_generate_checkbit_message(const struct mem_ctl_info *mci,
- const struct ppc4xx_ecc_status *status,
- char *buffer,
- size_t size)
-{
- const struct ppc4xx_edac_pdata *pdata = mci->pvt_info;
- const char *ckber = NULL;
-
- switch (status->ecces & SDRAM_ECCES_CKBER_MASK) {
- case SDRAM_ECCES_CKBER_NONE:
- ckber = "None";
- break;
- case SDRAM_ECCES_CKBER_32_ECC_0_3:
- ckber = "ECC0:3";
- break;
- case SDRAM_ECCES_CKBER_32_ECC_4_8:
- switch (mfsdram(&pdata->dcr_host, SDRAM_MCOPT1) &
- SDRAM_MCOPT1_WDTH_MASK) {
- case SDRAM_MCOPT1_WDTH_16:
- ckber = "ECC0:3";
- break;
- case SDRAM_MCOPT1_WDTH_32:
- ckber = "ECC4:8";
- break;
- default:
- ckber = "Unknown";
- break;
- }
- break;
- case SDRAM_ECCES_CKBER_32_ECC_0_8:
- ckber = "ECC0:8";
- break;
- default:
- ckber = "Unknown";
- break;
- }
-
- return snprintf(buffer, size, "Checkbit Error: %s", ckber);
-}
-
-/**
- * ppc4xx_edac_generate_lane_message - generate interpretted byte lane message
- * @mci: A pointer to the EDAC memory controller instance associated
- * with the byte lane message being generated.
- * @status: A pointer to the ECC status structure to generate the
- * message from.
- * @buffer: A pointer to the buffer in which to generate the
- * message.
- * @size: The size, in bytes, of space available in buffer.
- *
- * This routine generates to the provided buffer the portion of the
- * driver-unique report message associated with the ECCESS[BNCE]
- * field of the specified ECC status.
- *
- * Returns the number of characters generated on success; otherwise, <
- * 0 on error.
- */
-static int
-ppc4xx_edac_generate_lane_message(const struct mem_ctl_info *mci,
- const struct ppc4xx_ecc_status *status,
- char *buffer,
- size_t size)
-{
- int n, total = 0;
- unsigned int lane, lanes;
- const unsigned int first_lane = 0;
- const unsigned int lane_count = 16;
-
- n = snprintf(buffer, size, "; Byte Lane Errors: ");
-
- if (n < 0 || n >= size)
- goto fail;
-
- buffer += n;
- size -= n;
- total += n;
-
- for (lanes = 0, lane = first_lane; lane < lane_count; lane++) {
- if ((status->ecces & SDRAM_ECCES_BNCE_ENCODE(lane)) != 0) {
- n = snprintf(buffer, size,
- "%s%u",
- (lanes++ ? ", " : ""), lane);
-
- if (n < 0 || n >= size)
- goto fail;
-
- buffer += n;
- size -= n;
- total += n;
- }
- }
-
- n = snprintf(buffer, size, "%s; ", lanes ? "" : "None");
-
- if (n < 0 || n >= size)
- goto fail;
-
- buffer += n;
- size -= n;
- total += n;
-
- fail:
- return total;
-}
-
-/**
- * ppc4xx_edac_generate_ecc_message - generate interpretted ECC status message
- * @mci: A pointer to the EDAC memory controller instance associated
- * with the ECCES message being generated.
- * @status: A pointer to the ECC status structure to generate the
- * message from.
- * @buffer: A pointer to the buffer in which to generate the
- * message.
- * @size: The size, in bytes, of space available in buffer.
- *
- * This routine generates to the provided buffer the portion of the
- * driver-unique report message associated with the ECCESS register of
- * the specified ECC status.
- *
- * Returns the number of characters generated on success; otherwise, <
- * 0 on error.
- */
-static int
-ppc4xx_edac_generate_ecc_message(const struct mem_ctl_info *mci,
- const struct ppc4xx_ecc_status *status,
- char *buffer,
- size_t size)
-{
- int n, total = 0;
-
- n = ppc4xx_edac_generate_bank_message(mci, status, buffer, size);
-
- if (n < 0 || n >= size)
- goto fail;
-
- buffer += n;
- size -= n;
- total += n;
-
- n = ppc4xx_edac_generate_checkbit_message(mci, status, buffer, size);
-
- if (n < 0 || n >= size)
- goto fail;
-
- buffer += n;
- size -= n;
- total += n;
-
- n = ppc4xx_edac_generate_lane_message(mci, status, buffer, size);
-
- if (n < 0 || n >= size)
- goto fail;
-
- buffer += n;
- size -= n;
- total += n;
-
- fail:
- return total;
-}
-
-/**
- * ppc4xx_edac_generate_plb_message - generate interpretted PLB status message
- * @mci: A pointer to the EDAC memory controller instance associated
- * with the PLB message being generated.
- * @status: A pointer to the ECC status structure to generate the
- * message from.
- * @buffer: A pointer to the buffer in which to generate the
- * message.
- * @size: The size, in bytes, of space available in buffer.
- *
- * This routine generates to the provided buffer the portion of the
- * driver-unique report message associated with the PLB-related BESR
- * and/or WMIRQ registers of the specified ECC status.
- *
- * Returns the number of characters generated on success; otherwise, <
- * 0 on error.
- */
-static int
-ppc4xx_edac_generate_plb_message(const struct mem_ctl_info *mci,
- const struct ppc4xx_ecc_status *status,
- char *buffer,
- size_t size)
-{
- unsigned int master;
- bool read;
-
- if ((status->besr & SDRAM_BESR_MASK) == 0)
- return 0;
-
- if ((status->besr & SDRAM_BESR_M0ET_MASK) == SDRAM_BESR_M0ET_NONE)
- return 0;
-
- read = ((status->besr & SDRAM_BESR_M0RW_MASK) == SDRAM_BESR_M0RW_READ);
-
- master = SDRAM_BESR_M0ID_DECODE(status->besr);
-
- return snprintf(buffer, size,
- "%s error w/ PLB master %u \"%s\"; ",
- (read ? "Read" : "Write"),
- master,
- (((master >= SDRAM_PLB_M0ID_FIRST) &&
- (master <= SDRAM_PLB_M0ID_LAST)) ?
- ppc4xx_plb_masters[master] : "UNKNOWN"));
-}
-
-/**
- * ppc4xx_edac_generate_message - generate interpretted status message
- * @mci: A pointer to the EDAC memory controller instance associated
- * with the driver-unique message being generated.
- * @status: A pointer to the ECC status structure to generate the
- * message from.
- * @buffer: A pointer to the buffer in which to generate the
- * message.
- * @size: The size, in bytes, of space available in buffer.
- *
- * This routine generates to the provided buffer the driver-unique
- * EDAC report message from the specified ECC status.
- */
-static void
-ppc4xx_edac_generate_message(const struct mem_ctl_info *mci,
- const struct ppc4xx_ecc_status *status,
- char *buffer,
- size_t size)
-{
- int n;
-
- if (buffer == NULL || size == 0)
- return;
-
- n = ppc4xx_edac_generate_ecc_message(mci, status, buffer, size);
-
- if (n < 0 || n >= size)
- return;
-
- buffer += n;
- size -= n;
-
- ppc4xx_edac_generate_plb_message(mci, status, buffer, size);
-}
-
-#ifdef DEBUG
-/**
- * ppc4xx_ecc_dump_status - dump controller ECC status registers
- * @mci: A pointer to the EDAC memory controller instance
- * associated with the status being dumped.
- * @status: A pointer to the ECC status structure to generate the
- * dump from.
- *
- * This routine dumps to the kernel log buffer the raw and
- * interpretted specified ECC status.
- */
-static void
-ppc4xx_ecc_dump_status(const struct mem_ctl_info *mci,
- const struct ppc4xx_ecc_status *status)
-{
- char message[PPC4XX_EDAC_MESSAGE_SIZE];
-
- ppc4xx_edac_generate_message(mci, status, message, sizeof(message));
-
- ppc4xx_edac_mc_printk(KERN_INFO, mci,
- "\n"
- "\tECCES: 0x%08x\n"
- "\tWMIRQ: 0x%08x\n"
- "\tBESR: 0x%08x\n"
- "\tBEAR: 0x%08x%08x\n"
- "\t%s\n",
- status->ecces,
- status->wmirq,
- status->besr,
- status->bearh,
- status->bearl,
- message);
-}
-#endif /* DEBUG */
-
-/**
- * ppc4xx_ecc_get_status - get controller ECC status
- * @mci: A pointer to the EDAC memory controller instance
- * associated with the status being retrieved.
- * @status: A pointer to the ECC status structure to populate the
- * ECC status with.
- *
- * This routine reads and masks, as appropriate, all the relevant
- * status registers that deal with ibm,sdram-4xx-ddr2 ECC errors.
- * While we read all of them, for correctable errors, we only expect
- * to deal with ECCES. For uncorrectable errors, we expect to deal
- * with all of them.
- */
-static void
-ppc4xx_ecc_get_status(const struct mem_ctl_info *mci,
- struct ppc4xx_ecc_status *status)
-{
- const struct ppc4xx_edac_pdata *pdata = mci->pvt_info;
- const dcr_host_t *dcr_host = &pdata->dcr_host;
-
- status->ecces = mfsdram(dcr_host, SDRAM_ECCES) & SDRAM_ECCES_MASK;
- status->wmirq = mfsdram(dcr_host, SDRAM_WMIRQ) & SDRAM_WMIRQ_MASK;
- status->besr = mfsdram(dcr_host, SDRAM_BESR) & SDRAM_BESR_MASK;
- status->bearl = mfsdram(dcr_host, SDRAM_BEARL);
- status->bearh = mfsdram(dcr_host, SDRAM_BEARH);
-}
-
-/**
- * ppc4xx_ecc_clear_status - clear controller ECC status
- * @mci: A pointer to the EDAC memory controller instance
- * associated with the status being cleared.
- * @status: A pointer to the ECC status structure containing the
- * values to write to clear the ECC status.
- *
- * This routine clears--by writing the masked (as appropriate) status
- * values back to--the status registers that deal with
- * ibm,sdram-4xx-ddr2 ECC errors.
- */
-static void
-ppc4xx_ecc_clear_status(const struct mem_ctl_info *mci,
- const struct ppc4xx_ecc_status *status)
-{
- const struct ppc4xx_edac_pdata *pdata = mci->pvt_info;
- const dcr_host_t *dcr_host = &pdata->dcr_host;
-
- mtsdram(dcr_host, SDRAM_ECCES, status->ecces & SDRAM_ECCES_MASK);
- mtsdram(dcr_host, SDRAM_WMIRQ, status->wmirq & SDRAM_WMIRQ_MASK);
- mtsdram(dcr_host, SDRAM_BESR, status->besr & SDRAM_BESR_MASK);
- mtsdram(dcr_host, SDRAM_BEARL, 0);
- mtsdram(dcr_host, SDRAM_BEARH, 0);
-}
-
-/**
- * ppc4xx_edac_handle_ce - handle controller correctable ECC error (CE)
- * @mci: A pointer to the EDAC memory controller instance
- * associated with the correctable error being handled and reported.
- * @status: A pointer to the ECC status structure associated with
- * the correctable error being handled and reported.
- *
- * This routine handles an ibm,sdram-4xx-ddr2 controller ECC
- * correctable error. Per the aforementioned discussion, there's not
- * enough status available to use the full EDAC correctable error
- * interface, so we just pass driver-unique message to the "no info"
- * interface.
- */
-static void
-ppc4xx_edac_handle_ce(struct mem_ctl_info *mci,
- const struct ppc4xx_ecc_status *status)
-{
- int row;
- char message[PPC4XX_EDAC_MESSAGE_SIZE];
-
- ppc4xx_edac_generate_message(mci, status, message, sizeof(message));
-
- for (row = 0; row < mci->nr_csrows; row++)
- if (ppc4xx_edac_check_bank_error(status, row))
- edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
- 0, 0, 0,
- row, 0, -1,
- message, "");
-}
-
-/**
- * ppc4xx_edac_handle_ue - handle controller uncorrectable ECC error (UE)
- * @mci: A pointer to the EDAC memory controller instance
- * associated with the uncorrectable error being handled and
- * reported.
- * @status: A pointer to the ECC