diff --git a/drivers/acpi/prmt.c b/drivers/acpi/prmt.c
index c78453c..1cfaa59 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 16c8de5..81af6c3 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 4edfb83..faf310e 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 24dd896..e2a954d 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 0fe75ee..189a2fc 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 1eea334..0000000
--- 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 status structure associated with
- *          the uncorrectable error being handled and reported.
- *
- * This routine handles an ibm,sdram-4xx-ddr2 controller ECC
- * uncorrectable error.
- */
-static void
-ppc4xx_edac_handle_ue(struct mem_ctl_info *mci,
-		      const struct ppc4xx_ecc_status *status)
-{
-	const u64 bear = ((u64)status->bearh << 32 | status->bearl);
-	const unsigned long page = bear >> PAGE_SHIFT;
-	const unsigned long offset = bear & ~PAGE_MASK;
-	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_UNCORRECTED, mci, 1,
-					     page, offset, 0,
-					     row, 0, -1,
-					     message, "");
-}
-
-/**
- * ppc4xx_edac_check - check controller for ECC errors
- * @mci: A pointer to the EDAC memory controller instance
- *       associated with the ibm,sdram-4xx-ddr2 controller being
- *       checked.
- *
- * This routine is used to check and post ECC errors and is called by
- * both the EDAC polling thread and this driver's CE and UE interrupt
- * handler.
- */
-static void
-ppc4xx_edac_check(struct mem_ctl_info *mci)
-{
-#ifdef DEBUG
-	static unsigned int count;
-#endif
-	struct ppc4xx_ecc_status status;
-
-	ppc4xx_ecc_get_status(mci, &status);
-
-#ifdef DEBUG
-	if (count++ % 30 == 0)
-		ppc4xx_ecc_dump_status(mci, &status);
-#endif
-
-	if (status.ecces & SDRAM_ECCES_UE)
-		ppc4xx_edac_handle_ue(mci, &status);
-
-	if (status.ecces & SDRAM_ECCES_CE)
-		ppc4xx_edac_handle_ce(mci, &status);
-
-	ppc4xx_ecc_clear_status(mci, &status);
-}
-
-/**
- * ppc4xx_edac_isr - SEC (CE) and DED (UE) interrupt service routine
- * @irq:    The virtual interrupt number being serviced.
- * @dev_id: A pointer to the EDAC memory controller instance
- *          associated with the interrupt being handled.
- *
- * This routine implements the interrupt handler for both correctable
- * (CE) and uncorrectable (UE) ECC errors for the ibm,sdram-4xx-ddr2
- * controller. It simply calls through to the same routine used during
- * polling to check, report and clear the ECC status.
- *
- * Unconditionally returns IRQ_HANDLED.
- */
-static irqreturn_t
-ppc4xx_edac_isr(int irq, void *dev_id)
-{
-	struct mem_ctl_info *mci = dev_id;
-
-	ppc4xx_edac_check(mci);
-
-	return IRQ_HANDLED;
-}
-
-/**
- * ppc4xx_edac_get_dtype - return the controller memory width
- * @mcopt1: The 32-bit Memory Controller Option 1 register value
- *          currently set for the controller, from which the width
- *          is derived.
- *
- * This routine returns the EDAC device type width appropriate for the
- * current controller configuration.
- *
- * TODO: This needs to be conditioned dynamically through feature
- * flags or some such when other controller variants are supported as
- * the 405EX[r] is 16-/32-bit and the others are 32-/64-bit with the
- * 16- and 64-bit field definition/value/enumeration (b1) overloaded
- * among them.
- *
- * Returns a device type width enumeration.
- */
-static enum dev_type ppc4xx_edac_get_dtype(u32 mcopt1)
-{
-	switch (mcopt1 & SDRAM_MCOPT1_WDTH_MASK) {
-	case SDRAM_MCOPT1_WDTH_16:
-		return DEV_X2;
-	case SDRAM_MCOPT1_WDTH_32:
-		return DEV_X4;
-	default:
-		return DEV_UNKNOWN;
-	}
-}
-
-/**
- * ppc4xx_edac_get_mtype - return controller memory type
- * @mcopt1: The 32-bit Memory Controller Option 1 register value
- *          currently set for the controller, from which the memory type
- *          is derived.
- *
- * This routine returns the EDAC memory type appropriate for the
- * current controller configuration.
- *
- * Returns a memory type enumeration.
- */
-static enum mem_type ppc4xx_edac_get_mtype(u32 mcopt1)
-{
-	bool rden = ((mcopt1 & SDRAM_MCOPT1_RDEN_MASK) == SDRAM_MCOPT1_RDEN);
-
-	switch (mcopt1 & SDRAM_MCOPT1_DDR_TYPE_MASK) {
-	case SDRAM_MCOPT1_DDR2_TYPE:
-		return rden ? MEM_RDDR2 : MEM_DDR2;
-	case SDRAM_MCOPT1_DDR1_TYPE:
-		return rden ? MEM_RDDR : MEM_DDR;
-	default:
-		return MEM_UNKNOWN;
-	}
-}
-
-/**
- * ppc4xx_edac_init_csrows - initialize driver instance rows
- * @mci: A pointer to the EDAC memory controller instance
- *       associated with the ibm,sdram-4xx-ddr2 controller for which
- *       the csrows (i.e. banks/ranks) are being initialized.
- * @mcopt1: The 32-bit Memory Controller Option 1 register value
- *          currently set for the controller, from which bank width
- *          and memory typ information is derived.
- *
- * This routine initializes the virtual "chip select rows" associated
- * with the EDAC memory controller instance. An ibm,sdram-4xx-ddr2
- * controller bank/rank is mapped to a row.
- *
- * Returns 0 if OK; otherwise, -EINVAL if the memory bank size
- * configuration cannot be determined.
- */
-static int ppc4xx_edac_init_csrows(struct mem_ctl_info *mci, u32 mcopt1)
-{
-	const struct ppc4xx_edac_pdata *pdata = mci->pvt_info;
-	int status = 0;
-	enum mem_type mtype;
-	enum dev_type dtype;
-	enum edac_type edac_mode;
-	int row, j;
-	u32 mbxcf, size, nr_pages;
-
-	/* Establish the memory type and width */
-
-	mtype = ppc4xx_edac_get_mtype(mcopt1);
-	dtype = ppc4xx_edac_get_dtype(mcopt1);
-
-	/* Establish EDAC mode */
-
-	if (mci->edac_cap & EDAC_FLAG_SECDED)
-		edac_mode = EDAC_SECDED;
-	else if (mci->edac_cap & EDAC_FLAG_EC)
-		edac_mode = EDAC_EC;
-	else
-		edac_mode = EDAC_NONE;
-
-	/*
-	 * Initialize each chip select row structure which correspond
-	 * 1:1 with a controller bank/rank.
-	 */
-
-	for (row = 0; row < mci->nr_csrows; row++) {
-		struct csrow_info *csi = mci->csrows[row];
-
-		/*
-		 * Get the configuration settings for this
-		 * row/bank/rank and skip disabled banks.
-		 */
-
-		mbxcf = mfsdram(&pdata->dcr_host, SDRAM_MBXCF(row));
-
-		if ((mbxcf & SDRAM_MBCF_BE_MASK) != SDRAM_MBCF_BE_ENABLE)
-			continue;
-
-		/* Map the bank configuration size setting to pages. */
-
-		size = mbxcf & SDRAM_MBCF_SZ_MASK;
-
-		switch (size) {
-		case SDRAM_MBCF_SZ_4MB:
-		case SDRAM_MBCF_SZ_8MB:
-		case SDRAM_MBCF_SZ_16MB:
-		case SDRAM_MBCF_SZ_32MB:
-		case SDRAM_MBCF_SZ_64MB:
-		case SDRAM_MBCF_SZ_128MB:
-		case SDRAM_MBCF_SZ_256MB:
-		case SDRAM_MBCF_SZ_512MB:
-		case SDRAM_MBCF_SZ_1GB:
-		case SDRAM_MBCF_SZ_2GB:
-		case SDRAM_MBCF_SZ_4GB:
-		case SDRAM_MBCF_SZ_8GB:
-			nr_pages = SDRAM_MBCF_SZ_TO_PAGES(size);
-			break;
-		default:
-			ppc4xx_edac_mc_printk(KERN_ERR, mci,
-					      "Unrecognized memory bank %d "
-					      "size 0x%08x\n",
-					      row, SDRAM_MBCF_SZ_DECODE(size));
-			status = -EINVAL;
-			goto done;
-		}
-
-		/*
-		 * It's unclear exactly what grain should be set to
-		 * here. The SDRAM_ECCES register allows resolution of
-		 * an error down to a nibble which would potentially
-		 * argue for a grain of '1' byte, even though we only
-		 * know the associated address for uncorrectable
-		 * errors. This value is not used at present for
-		 * anything other than error reporting so getting it
-		 * wrong should be of little consequence. Other
-		 * possible values would be the PLB width (16), the
-		 * page size (PAGE_SIZE) or the memory width (2 or 4).
-		 */
-		for (j = 0; j < csi->nr_channels; j++) {
-			struct dimm_info *dimm = csi->channels[j]->dimm;
-
-			dimm->nr_pages  = nr_pages / csi->nr_channels;
-			dimm->grain	= 1;
-
-			dimm->mtype	= mtype;
-			dimm->dtype	= dtype;
-
-			dimm->edac_mode	= edac_mode;
-		}
-	}
-
- done:
-	return status;
-}
-
-/**
- * ppc4xx_edac_mc_init - initialize driver instance
- * @mci: A pointer to the EDAC memory controller instance being
- *       initialized.
- * @op: A pointer to the OpenFirmware device tree node associated
- *      with the controller this EDAC instance is bound to.
- * @dcr_host: A pointer to the DCR data containing the DCR mapping
- *            for this controller instance.
- * @mcopt1: The 32-bit Memory Controller Option 1 register value
- *          currently set for the controller, from which ECC capabilities
- *          and scrub mode are derived.
- *
- * This routine performs initialization of the EDAC memory controller
- * instance and related driver-private data associated with the
- * ibm,sdram-4xx-ddr2 memory controller the instance is bound to.
- *
- * Returns 0 if OK; otherwise, < 0 on error.
- */
-static int ppc4xx_edac_mc_init(struct mem_ctl_info *mci,
-			       struct platform_device *op,
-			       const dcr_host_t *dcr_host, u32 mcopt1)
-{
-	int status = 0;
-	const u32 memcheck = (mcopt1 & SDRAM_MCOPT1_MCHK_MASK);
-	struct ppc4xx_edac_pdata *pdata = NULL;
-	const struct device_node *np = op->dev.of_node;
-
-	if (of_match_device(ppc4xx_edac_match, &op->dev) == NULL)
-		return -EINVAL;
-
-	/* Initial driver pointers and private data */
-
-	mci->pdev		= &op->dev;
-
-	dev_set_drvdata(mci->pdev, mci);
-
-	pdata			= mci->pvt_info;
-
-	pdata->dcr_host		= *dcr_host;
-
-	/* Initialize controller capabilities and configuration */
-
-	mci->mtype_cap		= (MEM_FLAG_DDR | MEM_FLAG_RDDR |
-				   MEM_FLAG_DDR2 | MEM_FLAG_RDDR2);
-
-	mci->edac_ctl_cap	= (EDAC_FLAG_NONE |
-				   EDAC_FLAG_EC |
-				   EDAC_FLAG_SECDED);
-
-	mci->scrub_cap		= SCRUB_NONE;
-	mci->scrub_mode		= SCRUB_NONE;
-
-	/*
-	 * Update the actual capabilites based on the MCOPT1[MCHK]
-	 * settings. Scrubbing is only useful if reporting is enabled.
-	 */
-
-	switch (memcheck) {
-	case SDRAM_MCOPT1_MCHK_CHK:
-		mci->edac_cap	= EDAC_FLAG_EC;
-		break;
-	case SDRAM_MCOPT1_MCHK_CHK_REP:
-		mci->edac_cap	= (EDAC_FLAG_EC | EDAC_FLAG_SECDED);
-		mci->scrub_mode	= SCRUB_SW_SRC;
-		break;
-	default:
-		mci->edac_cap	= EDAC_FLAG_NONE;
-		break;
-	}
-
-	/* Initialize strings */
-
-	mci->mod_name		= PPC4XX_EDAC_MODULE_NAME;
-	mci->ctl_name		= ppc4xx_edac_match->compatible;
-	mci->dev_name		= np->full_name;
-
-	/* Initialize callbacks */
-
-	mci->edac_check		= ppc4xx_edac_check;
-	mci->ctl_page_to_phys	= NULL;
-
-	/* Initialize chip select rows */
-
-	status = ppc4xx_edac_init_csrows(mci, mcopt1);
-
-	if (status)
-		ppc4xx_edac_mc_printk(KERN_ERR, mci,
-				      "Failed to initialize rows!\n");
-
-	return status;
-}
-
-/**
- * ppc4xx_edac_register_irq - setup and register controller interrupts
- * @op: A pointer to the OpenFirmware device tree node associated
- *      with the controller this EDAC instance is bound to.
- * @mci: A pointer to the EDAC memory controller instance
- *       associated with the ibm,sdram-4xx-ddr2 controller for which
- *       interrupts are being registered.
- *
- * This routine parses the correctable (CE) and uncorrectable error (UE)
- * interrupts from the device tree node and maps and assigns them to
- * the associated EDAC memory controller instance.
- *
- * Returns 0 if OK; otherwise, -ENODEV if the interrupts could not be
- * mapped and assigned.
- */
-static int ppc4xx_edac_register_irq(struct platform_device *op,
-				    struct mem_ctl_info *mci)
-{
-	int status = 0;
-	int ded_irq, sec_irq;
-	struct ppc4xx_edac_pdata *pdata = mci->pvt_info;
-	struct device_node *np = op->dev.of_node;
-
-	ded_irq = irq_of_parse_and_map(np, INTMAP_ECCDED_INDEX);
-	sec_irq = irq_of_parse_and_map(np, INTMAP_ECCSEC_INDEX);
-
-	if (!ded_irq || !sec_irq) {
-		ppc4xx_edac_mc_printk(KERN_ERR, mci,
-				      "Unable to map interrupts.\n");
-		status = -ENODEV;
-		goto fail;
-	}
-
-	status = request_irq(ded_irq,
-			     ppc4xx_edac_isr,
-			     0,
-			     "[EDAC] MC ECCDED",
-			     mci);
-
-	if (status < 0) {
-		ppc4xx_edac_mc_printk(KERN_ERR, mci,
-				      "Unable to request irq %d for ECC DED",
-				      ded_irq);
-		status = -ENODEV;
-		goto fail1;
-	}
-
-	status = request_irq(sec_irq,
-			     ppc4xx_edac_isr,
-			     0,
-			     "[EDAC] MC ECCSEC",
-			     mci);
-
-	if (status < 0) {
-		ppc4xx_edac_mc_printk(KERN_ERR, mci,
-				      "Unable to request irq %d for ECC SEC",
-				      sec_irq);
-		status = -ENODEV;
-		goto fail2;
-	}
-
-	ppc4xx_edac_mc_printk(KERN_INFO, mci, "ECCDED irq is %d\n", ded_irq);
-	ppc4xx_edac_mc_printk(KERN_INFO, mci, "ECCSEC irq is %d\n", sec_irq);
-
-	pdata->irqs.ded = ded_irq;
-	pdata->irqs.sec = sec_irq;
-
-	return 0;
-
- fail2:
-	free_irq(sec_irq, mci);
-
- fail1:
-	free_irq(ded_irq, mci);
-
- fail:
-	return status;
-}
-
-/**
- * ppc4xx_edac_map_dcrs - locate and map controller registers
- * @np: A pointer to the device tree node containing the DCR
- *      resources to map.
- * @dcr_host: A pointer to the DCR data to populate with the
- *            DCR mapping.
- *
- * This routine attempts to locate in the device tree and map the DCR
- * register resources associated with the controller's indirect DCR
- * address and data windows.
- *
- * Returns 0 if the DCRs were successfully mapped; otherwise, < 0 on
- * error.
- */
-static int ppc4xx_edac_map_dcrs(const struct device_node *np,
-				dcr_host_t *dcr_host)
-{
-	unsigned int dcr_base, dcr_len;
-
-	if (np == NULL || dcr_host == NULL)
-		return -EINVAL;
-
-	/* Get the DCR resource extent and sanity check the values. */
-
-	dcr_base = dcr_resource_start(np, 0);
-	dcr_len = dcr_resource_len(np, 0);
-
-	if (dcr_base == 0 || dcr_len == 0) {
-		ppc4xx_edac_printk(KERN_ERR,
-				   "Failed to obtain DCR property.\n");
-		return -ENODEV;
-	}
-
-	if (dcr_len != SDRAM_DCR_RESOURCE_LEN) {
-		ppc4xx_edac_printk(KERN_ERR,
-				   "Unexpected DCR length %d, expected %d.\n",
-				   dcr_len, SDRAM_DCR_RESOURCE_LEN);
-		return -ENODEV;
-	}
-
-	/*  Attempt to map the DCR extent. */
-
-	*dcr_host = dcr_map(np, dcr_base, dcr_len);
-
-	if (!DCR_MAP_OK(*dcr_host)) {
-		ppc4xx_edac_printk(KERN_INFO, "Failed to map DCRs.\n");
-		    return -ENODEV;
-	}
-
-	return 0;
-}
-
-/**
- * ppc4xx_edac_probe - check controller and bind driver
- * @op: A pointer to the OpenFirmware device tree node associated
- *      with the controller being probed for driver binding.
- *
- * This routine probes a specific ibm,sdram-4xx-ddr2 controller
- * instance for binding with the driver.
- *
- * Returns 0 if the controller instance was successfully bound to the
- * driver; otherwise, < 0 on error.
- */
-static int ppc4xx_edac_probe(struct platform_device *op)
-{
-	int status = 0;
-	u32 mcopt1, memcheck;
-	dcr_host_t dcr_host;
-	const struct device_node *np = op->dev.of_node;
-	struct mem_ctl_info *mci = NULL;
-	struct edac_mc_layer layers[2];
-	static int ppc4xx_edac_instance;
-
-	/*
-	 * At this point, we only support the controller realized on
-	 * the AMCC PPC 405EX[r]. Reject anything else.
-	 */
-
-	if (!of_device_is_compatible(np, "ibm,sdram-405ex") &&
-	    !of_device_is_compatible(np, "ibm,sdram-405exr")) {
-		ppc4xx_edac_printk(KERN_NOTICE,
-				   "Only the PPC405EX[r] is supported.\n");
-		return -ENODEV;
-	}
-
-	/*
-	 * Next, get the DCR property and attempt to map it so that we
-	 * can probe the controller.
-	 */
-
-	status = ppc4xx_edac_map_dcrs(np, &dcr_host);
-
-	if (status)
-		return status;
-
-	/*
-	 * First determine whether ECC is enabled at all. If not,
-	 * there is no useful checking or monitoring that can be done
-	 * for this controller.
-	 */
-
-	mcopt1 = mfsdram(&dcr_host, SDRAM_MCOPT1);
-	memcheck = (mcopt1 & SDRAM_MCOPT1_MCHK_MASK);
-
-	if (memcheck == SDRAM_MCOPT1_MCHK_NON) {
-		ppc4xx_edac_printk(KERN_INFO, "%pOF: No ECC memory detected or "
-				   "ECC is disabled.\n", np);
-		status = -ENODEV;
-		goto done;
-	}
-
-	/*
-	 * At this point, we know ECC is enabled, allocate an EDAC
-	 * controller instance and perform the appropriate
-	 * initialization.
-	 */
-	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
-	layers[0].size = ppc4xx_edac_nr_csrows;
-	layers[0].is_virt_csrow = true;
-	layers[1].type = EDAC_MC_LAYER_CHANNEL;
-	layers[1].size = ppc4xx_edac_nr_chans;
-	layers[1].is_virt_csrow = false;
-	mci = edac_mc_alloc(ppc4xx_edac_instance, ARRAY_SIZE(layers), layers,
-			    sizeof(struct ppc4xx_edac_pdata));
-	if (mci == NULL) {
-		ppc4xx_edac_printk(KERN_ERR, "%pOF: "
-				   "Failed to allocate EDAC MC instance!\n",
-				   np);
-		status = -ENOMEM;
-		goto done;
-	}
-
-	status = ppc4xx_edac_mc_init(mci, op, &dcr_host, mcopt1);
-
-	if (status) {
-		ppc4xx_edac_mc_printk(KERN_ERR, mci,
-				      "Failed to initialize instance!\n");
-		goto fail;
-	}
-
-	/*
-	 * We have a valid, initialized EDAC instance bound to the
-	 * controller. Attempt to register it with the EDAC subsystem
-	 * and, if necessary, register interrupts.
-	 */
-
-	if (edac_mc_add_mc(mci)) {
-		ppc4xx_edac_mc_printk(KERN_ERR, mci,
-				      "Failed to add instance!\n");
-		status = -ENODEV;
-		goto fail;
-	}
-
-	if (edac_op_state == EDAC_OPSTATE_INT) {
-		status = ppc4xx_edac_register_irq(op, mci);
-
-		if (status)
-			goto fail1;
-	}
-
-	ppc4xx_edac_instance++;
-
-	return 0;
-
- fail1:
-	edac_mc_del_mc(mci->pdev);
-
- fail:
-	edac_mc_free(mci);
-
- done:
-	return status;
-}
-
-/**
- * ppc4xx_edac_remove - unbind driver from controller
- * @op: A pointer to the OpenFirmware device tree node associated
- *      with the controller this EDAC instance is to be unbound/removed
- *      from.
- *
- * This routine unbinds the EDAC memory controller instance associated
- * with the specified ibm,sdram-4xx-ddr2 controller described by the
- * OpenFirmware device tree node passed as a parameter.
- *
- * Unconditionally returns 0.
- */
-static void ppc4xx_edac_remove(struct platform_device *op)
-{
-	struct mem_ctl_info *mci = dev_get_drvdata(&op->dev);
-	struct ppc4xx_edac_pdata *pdata = mci->pvt_info;
-
-	if (edac_op_state == EDAC_OPSTATE_INT) {
-		free_irq(pdata->irqs.sec, mci);
-		free_irq(pdata->irqs.ded, mci);
-	}
-
-	dcr_unmap(pdata->dcr_host, SDRAM_DCR_RESOURCE_LEN);
-
-	edac_mc_del_mc(mci->pdev);
-	edac_mc_free(mci);
-}
-
-/**
- * ppc4xx_edac_opstate_init - initialize EDAC reporting method
- *
- * This routine ensures that the EDAC memory controller reporting
- * method is mapped to a sane value as the EDAC core defines the value
- * to EDAC_OPSTATE_INVAL by default. We don't call the global
- * opstate_init as that defaults to polling and we want interrupt as
- * the default.
- */
-static inline void __init
-ppc4xx_edac_opstate_init(void)
-{
-	switch (edac_op_state) {
-	case EDAC_OPSTATE_POLL:
-	case EDAC_OPSTATE_INT:
-		break;
-	default:
-		edac_op_state = EDAC_OPSTATE_INT;
-		break;
-	}
-
-	ppc4xx_edac_printk(KERN_INFO, "Reporting type: %s\n",
-			   ((edac_op_state == EDAC_OPSTATE_POLL) ?
-			    EDAC_OPSTATE_POLL_STR :
-			    ((edac_op_state == EDAC_OPSTATE_INT) ?
-			     EDAC_OPSTATE_INT_STR :
-			     EDAC_OPSTATE_UNKNOWN_STR)));
-}
-
-static struct platform_driver ppc4xx_edac_driver = {
-	.probe			= ppc4xx_edac_probe,
-	.remove_new		= ppc4xx_edac_remove,
-	.driver = {
-		.name = PPC4XX_EDAC_MODULE_NAME,
-		.of_match_table = ppc4xx_edac_match,
-	},
-};
-
-/**
- * ppc4xx_edac_init - driver/module insertion entry point
- *
- * This routine is the driver/module insertion entry point. It
- * initializes the EDAC memory controller reporting state and
- * registers the driver as an OpenFirmware device tree platform
- * driver.
- */
-static int __init
-ppc4xx_edac_init(void)
-{
-	ppc4xx_edac_printk(KERN_INFO, PPC4XX_EDAC_MODULE_REVISION "\n");
-
-	ppc4xx_edac_opstate_init();
-
-	return platform_driver_register(&ppc4xx_edac_driver);
-}
-
-/**
- * ppc4xx_edac_exit - driver/module removal entry point
- *
- * This routine is the driver/module removal entry point. It
- * unregisters the driver as an OpenFirmware device tree platform
- * driver.
- */
-static void __exit
-ppc4xx_edac_exit(void)
-{
-	platform_driver_unregister(&ppc4xx_edac_driver);
-}
-
-module_init(ppc4xx_edac_init);
-module_exit(ppc4xx_edac_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Grant Erickson <gerickson@nuovations.com>");
-MODULE_DESCRIPTION("EDAC MC Driver for the PPC4xx IBM DDR2 Memory Controller");
-module_param(edac_op_state, int, 0444);
-MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting State: "
-		 "0=" EDAC_OPSTATE_POLL_STR ", 2=" EDAC_OPSTATE_INT_STR);
diff --git a/drivers/edac/ppc4xx_edac.h b/drivers/edac/ppc4xx_edac.h
deleted file mode 100644
index b38459a..0000000
--- a/drivers/edac/ppc4xx_edac.h
+++ /dev/null
@@ -1,167 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (c) 2008 Nuovation System Designs, LLC
- *   Grant Erickson <gerickson@nuovations.com>
- *
- * This file defines processor mnemonics for accessing and managing
- * the IBM DDR1/DDR2 ECC controller found in the 405EX[r], 440SP,
- * 440SPe, 460EX, 460GT and 460SX.
- */
-
-#ifndef __PPC4XX_EDAC_H
-#define __PPC4XX_EDAC_H
-
-#include <linux/types.h>
-
-/*
- * Macro for generating register field mnemonics
- */
-#define PPC_REG_BITS			32
-#define PPC_REG_VAL(bit, val)		((val) << ((PPC_REG_BITS - 1) - (bit)))
-#define PPC_REG_DECODE(bit, val)	((val) >> ((PPC_REG_BITS - 1) - (bit)))
-
-/*
- * IBM 4xx DDR1/DDR2 SDRAM memory controller registers (at least those
- * relevant to ECC)
- */
-#define SDRAM_BESR			0x00	/* Error status (read/clear) */
-#define SDRAM_BESRT			0x01	/* Error statuss (test/set)  */
-#define SDRAM_BEARL			0x02	/* Error address low	     */
-#define SDRAM_BEARH			0x03	/* Error address high	     */
-#define SDRAM_WMIRQ			0x06	/* Write master (read/clear) */
-#define SDRAM_WMIRQT			0x07	/* Write master (test/set)   */
-#define SDRAM_MCOPT1			0x20	/* Controller options 1	     */
-#define SDRAM_MBXCF_BASE		0x40	/* Bank n configuration base */
-#define	SDRAM_MBXCF(n)			(SDRAM_MBXCF_BASE + (4 * (n)))
-#define SDRAM_MB0CF			SDRAM_MBXCF(0)
-#define SDRAM_MB1CF			SDRAM_MBXCF(1)
-#define SDRAM_MB2CF			SDRAM_MBXCF(2)
-#define SDRAM_MB3CF			SDRAM_MBXCF(3)
-#define SDRAM_ECCCR			0x98	/* ECC error status	     */
-#define SDRAM_ECCES			SDRAM_ECCCR
-
-/*
- * PLB Master IDs
- */
-#define	SDRAM_PLB_M0ID_FIRST		0
-#define	SDRAM_PLB_M0ID_ICU		SDRAM_PLB_M0ID_FIRST
-#define	SDRAM_PLB_M0ID_PCIE0		1
-#define	SDRAM_PLB_M0ID_PCIE1		2
-#define	SDRAM_PLB_M0ID_DMA		3
-#define	SDRAM_PLB_M0ID_DCU		4
-#define	SDRAM_PLB_M0ID_OPB		5
-#define	SDRAM_PLB_M0ID_MAL		6
-#define	SDRAM_PLB_M0ID_SEC		7
-#define	SDRAM_PLB_M0ID_AHB		8
-#define SDRAM_PLB_M0ID_LAST		SDRAM_PLB_M0ID_AHB
-#define SDRAM_PLB_M0ID_COUNT		(SDRAM_PLB_M0ID_LAST - \
-					 SDRAM_PLB_M0ID_FIRST + 1)
-
-/*
- * Memory Controller Bus Error Status Register
- */
-#define SDRAM_BESR_MASK			PPC_REG_VAL(7, 0xFF)
-#define SDRAM_BESR_M0ID_MASK		PPC_REG_VAL(3, 0xF)
-#define	SDRAM_BESR_M0ID_DECODE(n)	PPC_REG_DECODE(3, n)
-#define SDRAM_BESR_M0ID_ICU		PPC_REG_VAL(3, SDRAM_PLB_M0ID_ICU)
-#define SDRAM_BESR_M0ID_PCIE0		PPC_REG_VAL(3, SDRAM_PLB_M0ID_PCIE0)
-#define SDRAM_BESR_M0ID_PCIE1		PPC_REG_VAL(3, SDRAM_PLB_M0ID_PCIE1)
-#define SDRAM_BESR_M0ID_DMA		PPC_REG_VAL(3, SDRAM_PLB_M0ID_DMA)
-#define SDRAM_BESR_M0ID_DCU		PPC_REG_VAL(3, SDRAM_PLB_M0ID_DCU)
-#define SDRAM_BESR_M0ID_OPB		PPC_REG_VAL(3, SDRAM_PLB_M0ID_OPB)
-#define SDRAM_BESR_M0ID_MAL		PPC_REG_VAL(3, SDRAM_PLB_M0ID_MAL)
-#define SDRAM_BESR_M0ID_SEC		PPC_REG_VAL(3, SDRAM_PLB_M0ID_SEC)
-#define SDRAM_BESR_M0ID_AHB		PPC_REG_VAL(3, SDRAM_PLB_M0ID_AHB)
-#define SDRAM_BESR_M0ET_MASK		PPC_REG_VAL(6, 0x7)
-#define SDRAM_BESR_M0ET_NONE		PPC_REG_VAL(6, 0)
-#define SDRAM_BESR_M0ET_ECC		PPC_REG_VAL(6, 1)
-#define SDRAM_BESR_M0RW_MASK		PPC_REG_VAL(7, 1)
-#define SDRAM_BESR_M0RW_WRITE		PPC_REG_VAL(7, 0)
-#define SDRAM_BESR_M0RW_READ		PPC_REG_VAL(7, 1)
-
-/*
- * Memory Controller PLB Write Master Interrupt Register
- */
-#define SDRAM_WMIRQ_MASK		PPC_REG_VAL(8, 0x1FF)
-#define	SDRAM_WMIRQ_ENCODE(id)		PPC_REG_VAL((id % \
-						     SDRAM_PLB_M0ID_COUNT), 1)
-#define SDRAM_WMIRQ_ICU			PPC_REG_VAL(SDRAM_PLB_M0ID_ICU, 1)
-#define SDRAM_WMIRQ_PCIE0		PPC_REG_VAL(SDRAM_PLB_M0ID_PCIE0, 1)
-#define SDRAM_WMIRQ_PCIE1		PPC_REG_VAL(SDRAM_PLB_M0ID_PCIE1, 1)
-#define SDRAM_WMIRQ_DMA			PPC_REG_VAL(SDRAM_PLB_M0ID_DMA, 1)
-#define SDRAM_WMIRQ_DCU			PPC_REG_VAL(SDRAM_PLB_M0ID_DCU, 1)
-#define SDRAM_WMIRQ_OPB			PPC_REG_VAL(SDRAM_PLB_M0ID_OPB, 1)
-#define SDRAM_WMIRQ_MAL			PPC_REG_VAL(SDRAM_PLB_M0ID_MAL, 1)
-#define SDRAM_WMIRQ_SEC			PPC_REG_VAL(SDRAM_PLB_M0ID_SEC, 1)
-#define SDRAM_WMIRQ_AHB			PPC_REG_VAL(SDRAM_PLB_M0ID_AHB, 1)
-
-/*
- * Memory Controller Options 1 Register
- */
-#define SDRAM_MCOPT1_MCHK_MASK	    PPC_REG_VAL(3, 0x3)	 /* ECC mask	     */
-#define SDRAM_MCOPT1_MCHK_NON	    PPC_REG_VAL(3, 0x0)	 /* No ECC gen	     */
-#define SDRAM_MCOPT1_MCHK_GEN	    PPC_REG_VAL(3, 0x2)	 /* ECC gen	     */
-#define SDRAM_MCOPT1_MCHK_CHK	    PPC_REG_VAL(3, 0x1)	 /* ECC gen and chk  */
-#define SDRAM_MCOPT1_MCHK_CHK_REP   PPC_REG_VAL(3, 0x3)	 /* ECC gen/chk/rpt  */
-#define SDRAM_MCOPT1_MCHK_DECODE(n) ((((u32)(n)) >> 28) & 0x3)
-#define SDRAM_MCOPT1_RDEN_MASK	    PPC_REG_VAL(4, 0x1)	 /* Rgstrd DIMM mask */
-#define SDRAM_MCOPT1_RDEN	    PPC_REG_VAL(4, 0x1)	 /* Rgstrd DIMM enbl */
-#define SDRAM_MCOPT1_WDTH_MASK	    PPC_REG_VAL(7, 0x1)	 /* Width mask	     */
-#define SDRAM_MCOPT1_WDTH_32	    PPC_REG_VAL(7, 0x0)	 /* 32 bits	     */
-#define SDRAM_MCOPT1_WDTH_16	    PPC_REG_VAL(7, 0x1)	 /* 16 bits	     */
-#define SDRAM_MCOPT1_DDR_TYPE_MASK  PPC_REG_VAL(11, 0x1) /* DDR type mask    */
-#define SDRAM_MCOPT1_DDR1_TYPE	    PPC_REG_VAL(11, 0x0) /* DDR1 type	     */
-#define SDRAM_MCOPT1_DDR2_TYPE	    PPC_REG_VAL(11, 0x1) /* DDR2 type	     */
-
-/*
- * Memory Bank 0 - n Configuration Register
- */
-#define SDRAM_MBCF_BA_MASK		PPC_REG_VAL(12, 0x1FFF)
-#define SDRAM_MBCF_SZ_MASK		PPC_REG_VAL(19, 0xF)
-#define SDRAM_MBCF_SZ_DECODE(mbxcf)	PPC_REG_DECODE(19, mbxcf)
-#define SDRAM_MBCF_SZ_4MB		PPC_REG_VAL(19, 0x0)
-#define SDRAM_MBCF_SZ_8MB		PPC_REG_VAL(19, 0x1)
-#define SDRAM_MBCF_SZ_16MB		PPC_REG_VAL(19, 0x2)
-#define SDRAM_MBCF_SZ_32MB		PPC_REG_VAL(19, 0x3)
-#define SDRAM_MBCF_SZ_64MB		PPC_REG_VAL(19, 0x4)
-#define SDRAM_MBCF_SZ_128MB		PPC_REG_VAL(19, 0x5)
-#define SDRAM_MBCF_SZ_256MB		PPC_REG_VAL(19, 0x6)
-#define SDRAM_MBCF_SZ_512MB		PPC_REG_VAL(19, 0x7)
-#define SDRAM_MBCF_SZ_1GB		PPC_REG_VAL(19, 0x8)
-#define SDRAM_MBCF_SZ_2GB		PPC_REG_VAL(19, 0x9)
-#define SDRAM_MBCF_SZ_4GB		PPC_REG_VAL(19, 0xA)
-#define SDRAM_MBCF_SZ_8GB		PPC_REG_VAL(19, 0xB)
-#define SDRAM_MBCF_AM_MASK		PPC_REG_VAL(23, 0xF)
-#define SDRAM_MBCF_AM_MODE0		PPC_REG_VAL(23, 0x0)
-#define SDRAM_MBCF_AM_MODE1		PPC_REG_VAL(23, 0x1)
-#define SDRAM_MBCF_AM_MODE2		PPC_REG_VAL(23, 0x2)
-#define SDRAM_MBCF_AM_MODE3		PPC_REG_VAL(23, 0x3)
-#define SDRAM_MBCF_AM_MODE4		PPC_REG_VAL(23, 0x4)
-#define SDRAM_MBCF_AM_MODE5		PPC_REG_VAL(23, 0x5)
-#define SDRAM_MBCF_AM_MODE6		PPC_REG_VAL(23, 0x6)
-#define SDRAM_MBCF_AM_MODE7		PPC_REG_VAL(23, 0x7)
-#define SDRAM_MBCF_AM_MODE8		PPC_REG_VAL(23, 0x8)
-#define SDRAM_MBCF_AM_MODE9		PPC_REG_VAL(23, 0x9)
-#define SDRAM_MBCF_BE_MASK		PPC_REG_VAL(31, 0x1)
-#define SDRAM_MBCF_BE_DISABLE		PPC_REG_VAL(31, 0x0)
-#define SDRAM_MBCF_BE_ENABLE		PPC_REG_VAL(31, 0x1)
-
-/*
- * ECC Error Status
- */
-#define SDRAM_ECCES_MASK		PPC_REG_VAL(21, 0x3FFFFF)
-#define SDRAM_ECCES_BNCE_MASK		PPC_REG_VAL(15, 0xFFFF)
-#define SDRAM_ECCES_BNCE_ENCODE(lane)	PPC_REG_VAL(((lane) & 0xF), 1)
-#define SDRAM_ECCES_CKBER_MASK		PPC_REG_VAL(17, 0x3)
-#define SDRAM_ECCES_CKBER_NONE		PPC_REG_VAL(17, 0)
-#define SDRAM_ECCES_CKBER_16_ECC_0_3	PPC_REG_VAL(17, 2)
-#define SDRAM_ECCES_CKBER_32_ECC_0_3	PPC_REG_VAL(17, 1)
-#define SDRAM_ECCES_CKBER_32_ECC_4_8	PPC_REG_VAL(17, 2)
-#define SDRAM_ECCES_CKBER_32_ECC_0_8	PPC_REG_VAL(17, 3)
-#define SDRAM_ECCES_CE			PPC_REG_VAL(18, 1)
-#define SDRAM_ECCES_UE			PPC_REG_VAL(19, 1)
-#define SDRAM_ECCES_BKNER_MASK		PPC_REG_VAL(21, 0x3)
-#define SDRAM_ECCES_BK0ER		PPC_REG_VAL(20, 1)
-#define SDRAM_ECCES_BK1ER		PPC_REG_VAL(21, 1)
-
-#endif /* __PPC4XX_EDAC_H */
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index e5c05a8..d5f1221 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -29,6 +29,8 @@
 
 /* Static vars */
 static LIST_HEAD(sbridge_edac_list);
+static char sb_msg[256];
+static char sb_msg_full[512];
 
 /*
  * Alter this version for the module when modifications are made
@@ -3079,7 +3081,6 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
 	struct mem_ctl_info *new_mci;
 	struct sbridge_pvt *pvt = mci->pvt_info;
 	enum hw_event_mc_err_type tp_event;
-	char *optype, msg[256], msg_full[512];
 	bool ripv = GET_BITFIELD(m->mcgstatus, 0, 0);
 	bool overflow = GET_BITFIELD(m->status, 62, 62);
 	bool uncorrected_error = GET_BITFIELD(m->status, 61, 61);
@@ -3095,10 +3096,10 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
 	 * aligned address reported by patrol scrubber.
 	 */
 	u32 lsb = GET_BITFIELD(m->misc, 0, 5);
+	char *optype, *area_type = "DRAM";
 	long channel_mask, first_channel;
 	u8  rank = 0xff, socket, ha;
 	int rc, dimm;
-	char *area_type = "DRAM";
 
 	if (pvt->info.type != SANDY_BRIDGE)
 		recoverable = true;
@@ -3168,32 +3169,32 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
 			channel = knl_channel_remap(m->bank == 16, channel);
 			channel_mask = 1 << channel;
 
-			snprintf(msg, sizeof(msg),
-				"%s%s err_code:%04x:%04x channel:%d (DIMM_%c)",
-				overflow ? " OVERFLOW" : "",
-				(uncorrected_error && recoverable)
-				? " recoverable" : " ",
-				mscod, errcode, channel, A + channel);
+			snprintf(sb_msg, sizeof(sb_msg),
+				 "%s%s err_code:%04x:%04x channel:%d (DIMM_%c)",
+				 overflow ? " OVERFLOW" : "",
+				 (uncorrected_error && recoverable)
+				 ? " recoverable" : " ",
+				 mscod, errcode, channel, A + channel);
 			edac_mc_handle_error(tp_event, mci, core_err_cnt,
 				m->addr >> PAGE_SHIFT, m->addr & ~PAGE_MASK, 0,
 				channel, 0, -1,
-				optype, msg);
+				optype, sb_msg);
 		}
 		return;
 	} else if (lsb < 12) {
 		rc = get_memory_error_data(mci, m->addr, &socket, &ha,
 					   &channel_mask, &rank,
-					   &area_type, msg);
+					   &area_type, sb_msg);
 	} else {
 		rc = get_memory_error_data_from_mce(mci, m, &socket, &ha,
-						    &channel_mask, msg);
+						    &channel_mask, sb_msg);
 	}
 
 	if (rc < 0)
 		goto err_parsing;
 	new_mci = get_mci_for_node_id(socket, ha);
 	if (!new_mci) {
-		strcpy(msg, "Error: socket got corrupted!");
+		strscpy(sb_msg, "Error: socket got corrupted!");
 		goto err_parsing;
 	}
 	mci = new_mci;
@@ -3218,7 +3219,7 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
 	 */
 	if (!pvt->is_lockstep && !pvt->is_cur_addr_mirrored && !pvt->is_close_pg)
 		channel = first_channel;
-	snprintf(msg_full, sizeof(msg_full),
+	snprintf(sb_msg_full, sizeof(sb_msg_full),
 		 "%s%s area:%s err_code:%04x:%04x socket:%d ha:%d channel_mask:%ld rank:%d %s",
 		 overflow ? " OVERFLOW" : "",
 		 (uncorrected_error && recoverable) ? " recoverable" : "",
@@ -3226,9 +3227,9 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
 		 mscod, errcode,
 		 socket, ha,
 		 channel_mask,
-		 rank, msg);
+		 rank, sb_msg);
 
-	edac_dbg(0, "%s\n", msg_full);
+	edac_dbg(0, "%s\n", sb_msg_full);
 
 	/* FIXME: need support for channel mask */
 
@@ -3239,12 +3240,12 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
 	edac_mc_handle_error(tp_event, mci, core_err_cnt,
 			     m->addr >> PAGE_SHIFT, m->addr & ~PAGE_MASK, 0,
 			     channel, dimm, -1,
-			     optype, msg_full);
+			     optype, sb_msg_full);
 	return;
 err_parsing:
 	edac_mc_handle_error(tp_event, mci, core_err_cnt, 0, 0, 0,
 			     -1, -1, -1,
-			     msg, "");
+			     sb_msg, "");
 
 }
 
diff --git a/drivers/edac/skx_base.c b/drivers/edac/skx_base.c
index af3fa80..14cfd39 100644
--- a/drivers/edac/skx_base.c
+++ b/drivers/edac/skx_base.c
@@ -587,54 +587,6 @@ static struct notifier_block skx_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/skx_test/addr.
- */
-static struct dentry *skx_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_skx_debug(void)
-{
-	skx_test = edac_debugfs_create_dir("skx_test");
-	if (!skx_test)
-		return;
-
-	if (!edac_debugfs_create_file("addr", 0200, skx_test,
-				      NULL, &fops_u64_wo)) {
-		debugfs_remove(skx_test);
-		skx_test = NULL;
-	}
-}
-
-static void teardown_skx_debug(void)
-{
-	debugfs_remove_recursive(skx_test);
-}
-#else
-static inline void setup_skx_debug(void) {}
-static inline void teardown_skx_debug(void) {}
-#endif /*CONFIG_EDAC_DEBUG*/
-
 /*
  * skx_init:
  *	make sure we are running on the correct cpu model
@@ -728,7 +680,7 @@ static int __init skx_init(void)
 	/* Ensure that the OPSTATE is set correctly for POLL or NMI */
 	opstate_init();
 
-	setup_skx_debug();
+	skx_setup_debug("skx_test");
 
 	mce_register_decode_chain(&skx_mce_dec);
 
@@ -742,7 +694,7 @@ static void __exit skx_exit(void)
 {
 	edac_dbg(2, "\n");
 	mce_unregister_decode_chain(&skx_mce_dec);
-	teardown_skx_debug();
+	skx_teardown_debug();
 	if (nvdimm_count)
 		skx_adxl_put();
 	skx_remove();
diff --git a/drivers/edac/skx_common.c b/drivers/edac/skx_common.c
index 8d18099..8571364 100644
--- a/drivers/edac/skx_common.c
+++ b/drivers/edac/skx_common.c
@@ -363,7 +363,7 @@ int skx_get_dimm_info(u32 mtr, u32 mcmtr, u32 amap, struct dimm_info *dimm,
 	if (imc->hbm_mc) {
 		banks = 32;
 		mtype = MEM_HBM2;
-	} else if (cfg->support_ddr5 && (amap & 0x8)) {
+	} else if (cfg->support_ddr5) {
 		banks = 32;
 		mtype = MEM_DDR5;
 	} else {
@@ -739,6 +739,53 @@ void skx_remove(void)
 }
 EXPORT_SYMBOL_GPL(skx_remove);
 
+#ifdef CONFIG_EDAC_DEBUG
+/*
+ * Debug feature.
+ * Exercise the address decode logic by writing an address to
+ * /sys/kernel/debug/edac/{skx,i10nm}_test/addr.
+ */
+static struct dentry *skx_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");
+
+void skx_setup_debug(const char *name)
+{
+	skx_test = edac_debugfs_create_dir(name);
+	if (!skx_test)
+		return;
+
+	if (!edac_debugfs_create_file("addr", 0200, skx_test,
+				      NULL, &fops_u64_wo)) {
+		debugfs_remove(skx_test);
+		skx_test = NULL;
+	}
+}
+EXPORT_SYMBOL_GPL(skx_setup_debug);
+
+void skx_teardown_debug(void)
+{
+	debugfs_remove_recursive(skx_test);
+}
+EXPORT_SYMBOL_GPL(skx_teardown_debug);
+#endif /*CONFIG_EDAC_DEBUG*/
+
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Tony Luck");
 MODULE_DESCRIPTION("MC Driver for Intel server processors");
diff --git a/drivers/edac/skx_common.h b/drivers/edac/skx_common.h
index 473421b..f945c1b 100644
--- a/drivers/edac/skx_common.h
+++ b/drivers/edac/skx_common.h
@@ -259,4 +259,12 @@ int skx_mce_check_error(struct notifier_block *nb, unsigned long val,
 
 void skx_remove(void);
 
+#ifdef CONFIG_EDAC_DEBUG
+void skx_setup_debug(const char *name);
+void skx_teardown_debug(void);
+#else
+static inline void skx_setup_debug(const char *name) {}
+static inline void skx_teardown_debug(void) {}
+#endif
+
 #endif /* _SKX_COMM_EDAC_H */
diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c
index ea7a9a3..d741616 100644
--- a/drivers/edac/synopsys_edac.c
+++ b/drivers/edac/synopsys_edac.c
@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/spinlock.h>
+#include <linux/sizes.h>
 #include <linux/interrupt.h>
 #include <linux/of.h>
 
@@ -337,6 +338,7 @@ struct synps_edac_priv {
  * @get_mtype:		Get mtype.
  * @get_dtype:		Get dtype.
  * @get_ecc_state:	Get ECC state.
+ * @get_mem_info:	Get EDAC memory info
  * @quirks:		To differentiate IPs.
  */
 struct synps_platform_data {
@@ -344,6 +346,9 @@ struct synps_platform_data {
 	enum mem_type (*get_mtype)(const void __iomem *base);
 	enum dev_type (*get_dtype)(const void __iomem *base);
 	bool (*get_ecc_state)(void __iomem *base);
+#ifdef CONFIG_EDAC_DEBUG
+	u64 (*get_mem_info)(struct synps_edac_priv *priv);
+#endif
 	int quirks;
 };
 
@@ -402,6 +407,25 @@ out:
 	return 0;
 }
 
+#ifdef CONFIG_EDAC_DEBUG
+/**
+ * zynqmp_get_mem_info - Get the current memory info.
+ * @priv:	DDR memory controller private instance data.
+ *
+ * Return: host interface address.
+ */
+static u64 zynqmp_get_mem_info(struct synps_edac_priv *priv)
+{
+	u64 hif_addr = 0, linear_addr;
+
+	linear_addr = priv->poison_addr;
+	if (linear_addr >= SZ_32G)
+		linear_addr = linear_addr - SZ_32G + SZ_2G;
+	hif_addr = linear_addr >> 3;
+	return hif_addr;
+}
+#endif
+
 /**
  * zynqmp_get_error_info - Get the current ECC error info.
  * @priv:	DDR memory controller private instance data.
@@ -922,6 +946,9 @@ static const struct synps_platform_data zynqmp_edac_def = {
 	.get_mtype	= zynqmp_get_mtype,
 	.get_dtype	= zynqmp_get_dtype,
 	.get_ecc_state	= zynqmp_get_ecc_state,
+#ifdef CONFIG_EDAC_DEBUG
+	.get_mem_info	= zynqmp_get_mem_info,
+#endif
 	.quirks         = (DDR_ECC_INTR_SUPPORT
 #ifdef CONFIG_EDAC_DEBUG
 			  | DDR_ECC_DATA_POISON_SUPPORT
@@ -975,10 +1002,16 @@ MODULE_DEVICE_TABLE(of, synps_edac_match);
 static void ddr_poison_setup(struct synps_edac_priv *priv)
 {
 	int col = 0, row = 0, bank = 0, bankgrp = 0, rank = 0, regval;
+	const struct synps_platform_data *p_data;
 	int index;
 	ulong hif_addr = 0;
 
-	hif_addr = priv->poison_addr >> 3;
+	p_data = priv->p_data;
+
+	if (p_data->get_mem_info)
+		hif_addr = p_data->get_mem_info(priv);
+	else
+		hif_addr = priv->poison_addr >> 3;
 
 	for (index = 0; index < DDR_MAX_ROW_SHIFT; index++) {
 		if (priv->row_shift[index])
diff --git a/drivers/ras/amd/atl/Kconfig b/drivers/ras/amd/atl/Kconfig
index df49c23..5516800 100644
--- a/drivers/ras/amd/atl/Kconfig
+++ b/drivers/ras/amd/atl/Kconfig
@@ -19,3 +19,7 @@ config AMD_ATL
 
 	  Enable this option if using DRAM ECC on Zen-based systems
 	  and OS-based error handling.
+
+config AMD_ATL_PRM
+	depends on AMD_ATL && ACPI_PRMT
+	def_bool y
diff --git a/drivers/ras/amd/atl/Makefile b/drivers/ras/amd/atl/Makefile
index 4acd5f0..b56892c 100644
--- a/drivers/ras/amd/atl/Makefile
+++ b/drivers/ras/amd/atl/Makefile
@@ -15,4 +15,6 @@ amd_atl-y		+= map.o
 amd_atl-y		+= system.o
 amd_atl-y		+= umc.o
 
+amd_atl-$(CONFIG_AMD_ATL_PRM) += prm.o
+
 obj-$(CONFIG_AMD_ATL)	+= amd_atl.o
diff --git a/drivers/ras/amd/atl/internal.h b/drivers/ras/amd/atl/internal.h
index 9de5d53..143d04c 100644
--- a/drivers/ras/amd/atl/internal.h
+++ b/drivers/ras/amd/atl/internal.h
@@ -282,6 +282,16 @@ unsigned long convert_umc_mca_addr_to_sys_addr(struct atl_err *err);
 u64 add_base_and_hole(struct addr_ctx *ctx, u64 addr);
 u64 remove_base_and_hole(struct addr_ctx *ctx, u64 addr);
 
+#ifdef CONFIG_AMD_ATL_PRM
+unsigned long prm_umc_norm_to_sys_addr(u8 socket_id, u64 umc_bank_inst_id, unsigned long addr);
+#else
+static inline unsigned long prm_umc_norm_to_sys_addr(u8 socket_id, u64 umc_bank_inst_id,
+						     unsigned long addr)
+{
+       return -ENODEV;
+}
+#endif
+
 /*
  * Make a gap in @data that is @num_bits long starting at @bit_num.
  * e.g. data		= 11111111'b
diff --git a/drivers/ras/amd/atl/prm.c b/drivers/ras/amd/atl/prm.c
new file mode 100644
index 0000000..0931a20
--- /dev/null
+++ b/drivers/ras/amd/atl/prm.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * AMD Address Translation Library
+ *
+ * prm.c : Plumbing code for ACPI Platform Runtime Mechanism (PRM)
+ *
+ * Information on AMD PRM modules and handlers including the GUIDs and buffer
+ * structures used here are defined in the AMD ACPI Porting Guide in the
+ * chapter "Platform Runtime Mechanism Table (PRMT)"
+ *
+ * Copyright (c) 2024, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Author: John Allen <john.allen@amd.com>
+ */
+
+#include "internal.h"
+
+#include <linux/prmt.h>
+
+/*
+ * PRM parameter buffer - normalized to system physical address, as described
+ * in the "PRM Parameter Buffer" section of the AMD ACPI Porting Guide.
+ */
+struct norm_to_sys_param_buf {
+	u64 norm_addr;
+	u8 socket;
+	u64 bank_id;
+	void *out_buf;
+} __packed;
+
+static const guid_t norm_to_sys_guid = GUID_INIT(0xE7180659, 0xA65D, 0x451D,
+						 0x92, 0xCD, 0x2B, 0x56, 0xF1,
+						 0x2B, 0xEB, 0xA6);
+
+unsigned long prm_umc_norm_to_sys_addr(u8 socket_id, u64 bank_id, unsigned long addr)
+{
+	struct norm_to_sys_param_buf p_buf;
+	unsigned long ret_addr;
+	int ret;
+
+	p_buf.norm_addr = addr;
+	p_buf.socket    = socket_id;
+	p_buf.bank_id   = bank_id;
+	p_buf.out_buf   = &ret_addr;
+
+	ret = acpi_call_prm_handler(norm_to_sys_guid, &p_buf);
+	if (!ret)
+		return ret_addr;
+
+	if (ret == -ENODEV)
+		pr_debug("PRM module/handler not available\n");
+	else
+		pr_notice_once("PRM address translation failed\n");
+
+	return ret;
+}
diff --git a/drivers/ras/amd/atl/umc.c b/drivers/ras/amd/atl/umc.c
index a1b4acc..dc8aa12 100644
--- a/drivers/ras/amd/atl/umc.c
+++ b/drivers/ras/amd/atl/umc.c
@@ -401,9 +401,14 @@ unsigned long convert_umc_mca_addr_to_sys_addr(struct atl_err *err)
 	u8 coh_st_inst_id = get_coh_st_inst_id(err);
 	unsigned long addr = get_addr(err->addr);
 	u8 die_id = get_die_id(err);
+	unsigned long ret_addr;
 
 	pr_debug("socket_id=0x%x die_id=0x%x coh_st_inst_id=0x%x addr=0x%016lx",
 		 socket_id, die_id, coh_st_inst_id, addr);
 
+	ret_addr = prm_umc_norm_to_sys_addr(socket_id, err->ipid, addr);
+	if (!IS_ERR_VALUE(ret_addr))
+		return ret_addr;
+
 	return norm_to_sys_addr(socket_id, die_id, coh_st_inst_id, addr);
 }
diff --git a/include/linux/prmt.h b/include/linux/prmt.h
index 24da836..9c09429 100644
--- a/include/linux/prmt.h
+++ b/include/linux/prmt.h
@@ -2,6 +2,11 @@
 
 #ifdef CONFIG_ACPI_PRMT
 void init_prmt(void);
+int acpi_call_prm_handler(guid_t handler_guid, void *param_buffer);
 #else
 static inline void init_prmt(void) { }
+static inline int acpi_call_prm_handler(guid_t handler_guid, void *param_buffer)
+{
+	return -EOPNOTSUPP;
+}
 #endif
