diff options
author | York Sun <york.sun@nxp.com> | 2016-08-11 13:15:18 -0700 |
---|---|---|
committer | Borislav Petkov <bp@suse.de> | 2016-09-01 10:28:00 +0200 |
commit | ea2eb9a8b6207ee40fdc346956686d8753aea944 (patch) | |
tree | d9deb6d1f8a3b3741cf6e816fcfd463d8be2c811 /drivers/edac | |
parent | 88857ebe7116b0f7702200628fa6b4d1297751a3 (diff) |
EDAC, fsl-ddr: Separate FSL DDR driver from MPC85xx
The mpc85xx-compatible DDR controllers are used on ARM-based SoCs too.
Carve out the DDR part from the mpc85xx EDAC driver in preparation to
support both architectures.
Signed-off-by: York Sun <york.sun@nxp.com>
Cc: Johannes Thumshirn <morbidrsa@gmail.com>
Cc: linux-edac <linux-edac@vger.kernel.org>
Cc: oss@buserror.net
Cc: stuart.yoder@nxp.com
Link: http://lkml.kernel.org/r/1470946525-3410-1-git-send-email-york.sun@nxp.com
Signed-off-by: Borislav Petkov <bp@suse.de>
Diffstat (limited to 'drivers/edac')
-rw-r--r-- | drivers/edac/Makefile | 5 | ||||
-rw-r--r-- | drivers/edac/fsl_ddr_edac.c | 592 | ||||
-rw-r--r-- | drivers/edac/fsl_ddr_edac.h | 86 | ||||
-rw-r--r-- | drivers/edac/mpc85xx_edac.c | 556 | ||||
-rw-r--r-- | drivers/edac/mpc85xx_edac.h | 66 |
5 files changed, 683 insertions, 622 deletions
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index f9e4a3e0e6e9..ee047a415722 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -50,7 +50,10 @@ amd64_edac_mod-$(CONFIG_EDAC_AMD64_ERROR_INJECTION) += amd64_edac_inj.o obj-$(CONFIG_EDAC_AMD64) += amd64_edac_mod.o obj-$(CONFIG_EDAC_PASEMI) += pasemi_edac.o -obj-$(CONFIG_EDAC_MPC85XX) += mpc85xx_edac.o + +mpc85xx_edac_mod-y := fsl_ddr_edac.o mpc85xx_edac.o +obj-$(CONFIG_EDAC_MPC85XX) += mpc85xx_edac_mod.o + obj-$(CONFIG_EDAC_MV64X60) += mv64x60_edac.o obj-$(CONFIG_EDAC_CELL) += cell_edac.o obj-$(CONFIG_EDAC_PPC4XX) += ppc4xx_edac.o diff --git a/drivers/edac/fsl_ddr_edac.c b/drivers/edac/fsl_ddr_edac.c new file mode 100644 index 000000000000..ca7636fbc799 --- /dev/null +++ b/drivers/edac/fsl_ddr_edac.c @@ -0,0 +1,592 @@ +/* + * Freescale Memory Controller kernel module + * + * Support Power-based SoCs including MPC85xx, MPC86xx, MPC83xx and + * ARM-based Layerscape SoCs including LS2xxx. Originally split + * out from mpc85xx_edac EDAC driver. + * + * Parts Copyrighted (c) 2013 by Freescale Semiconductor, Inc. + * + * Author: Dave Jiang <djiang@mvista.com> + * + * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + * + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/ctype.h> +#include <linux/io.h> +#include <linux/mod_devicetable.h> +#include <linux/edac.h> +#include <linux/smp.h> +#include <linux/gfp.h> + +#include <linux/of_platform.h> +#include <linux/of_device.h> +#include "edac_module.h" +#include "edac_core.h" +#include "fsl_ddr_edac.h" + +#define EDAC_MOD_STR "fsl_ddr_edac" + +static int edac_mc_idx; + +static u32 orig_ddr_err_disable; +static u32 orig_ddr_err_sbe; + +/************************ MC SYSFS parts ***********************************/ + +#define to_mci(k) container_of(k, struct mem_ctl_info, dev) + +static ssize_t mpc85xx_mc_inject_data_hi_show(struct device *dev, + struct device_attribute *mattr, + char *data) +{ + struct mem_ctl_info *mci = to_mci(dev); + struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + return sprintf(data, "0x%08x", + in_be32(pdata->mc_vbase + + MPC85XX_MC_DATA_ERR_INJECT_HI)); +} + +static ssize_t mpc85xx_mc_inject_data_lo_show(struct device *dev, + struct device_attribute *mattr, + char *data) +{ + struct mem_ctl_info *mci = to_mci(dev); + struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + return sprintf(data, "0x%08x", + in_be32(pdata->mc_vbase + + MPC85XX_MC_DATA_ERR_INJECT_LO)); +} + +static ssize_t mpc85xx_mc_inject_ctrl_show(struct device *dev, + struct device_attribute *mattr, + char *data) +{ + struct mem_ctl_info *mci = to_mci(dev); + struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + return sprintf(data, "0x%08x", + in_be32(pdata->mc_vbase + MPC85XX_MC_ECC_ERR_INJECT)); +} + +static ssize_t mpc85xx_mc_inject_data_hi_store(struct device *dev, + struct device_attribute *mattr, + const char *data, size_t count) +{ + struct mem_ctl_info *mci = to_mci(dev); + struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + if (isdigit(*data)) { + out_be32(pdata->mc_vbase + MPC85XX_MC_DATA_ERR_INJECT_HI, + simple_strtoul(data, NULL, 0)); + return count; + } + return 0; +} + +static ssize_t mpc85xx_mc_inject_data_lo_store(struct device *dev, + struct device_attribute *mattr, + const char *data, size_t count) +{ + struct mem_ctl_info *mci = to_mci(dev); + struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + if (isdigit(*data)) { + out_be32(pdata->mc_vbase + MPC85XX_MC_DATA_ERR_INJECT_LO, + simple_strtoul(data, NULL, 0)); + return count; + } + return 0; +} + +static ssize_t mpc85xx_mc_inject_ctrl_store(struct device *dev, + struct device_attribute *mattr, + const char *data, size_t count) +{ + struct mem_ctl_info *mci = to_mci(dev); + struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + if (isdigit(*data)) { + out_be32(pdata->mc_vbase + MPC85XX_MC_ECC_ERR_INJECT, + simple_strtoul(data, NULL, 0)); + return count; + } + return 0; +} + +DEVICE_ATTR(inject_data_hi, S_IRUGO | S_IWUSR, + mpc85xx_mc_inject_data_hi_show, mpc85xx_mc_inject_data_hi_store); +DEVICE_ATTR(inject_data_lo, S_IRUGO | S_IWUSR, + mpc85xx_mc_inject_data_lo_show, mpc85xx_mc_inject_data_lo_store); +DEVICE_ATTR(inject_ctrl, S_IRUGO | S_IWUSR, + mpc85xx_mc_inject_ctrl_show, mpc85xx_mc_inject_ctrl_store); + +static struct attribute *mpc85xx_dev_attrs[] = { + &dev_attr_inject_data_hi.attr, + &dev_attr_inject_data_lo.attr, + &dev_attr_inject_ctrl.attr, + NULL +}; + +ATTRIBUTE_GROUPS(mpc85xx_dev); + +/**************************** MC Err device ***************************/ + +/* + * Taken from table 8-55 in the MPC8641 User's Manual and/or 9-61 in the + * MPC8572 User's Manual. Each line represents a syndrome bit column as a + * 64-bit value, but split into an upper and lower 32-bit chunk. The labels + * below correspond to Freescale's manuals. + */ +static unsigned int ecc_table[16] = { + /* MSB LSB */ + /* [0:31] [32:63] */ + 0xf00fe11e, 0xc33c0ff7, /* Syndrome bit 7 */ + 0x00ff00ff, 0x00fff0ff, + 0x0f0f0f0f, 0x0f0fff00, + 0x11113333, 0x7777000f, + 0x22224444, 0x8888222f, + 0x44448888, 0xffff4441, + 0x8888ffff, 0x11118882, + 0xffff1111, 0x22221114, /* Syndrome bit 0 */ +}; + +/* + * Calculate the correct ECC value for a 64-bit value specified by high:low + */ +static u8 calculate_ecc(u32 high, u32 low) +{ + u32 mask_low; + u32 mask_high; + int bit_cnt; + u8 ecc = 0; + int i; + int j; + + for (i = 0; i < 8; i++) { + mask_high = ecc_table[i * 2]; + mask_low = ecc_table[i * 2 + 1]; + bit_cnt = 0; + + for (j = 0; j < 32; j++) { + if ((mask_high >> j) & 1) + bit_cnt ^= (high >> j) & 1; + if ((mask_low >> j) & 1) + bit_cnt ^= (low >> j) & 1; + } + + ecc |= bit_cnt << i; + } + + return ecc; +} + +/* + * Create the syndrome code which is generated if the data line specified by + * 'bit' failed. Eg generate an 8-bit codes seen in Table 8-55 in the MPC8641 + * User's Manual and 9-61 in the MPC8572 User's Manual. + */ +static u8 syndrome_from_bit(unsigned int bit) { + int i; + u8 syndrome = 0; + + /* + * Cycle through the upper or lower 32-bit portion of each value in + * ecc_table depending on if 'bit' is in the upper or lower half of + * 64-bit data. + */ + for (i = bit < 32; i < 16; i += 2) + syndrome |= ((ecc_table[i] >> (bit % 32)) & 1) << (i / 2); + + return syndrome; +} + +/* + * Decode data and ecc syndrome to determine what went wrong + * Note: This can only decode single-bit errors + */ +static void sbe_ecc_decode(u32 cap_high, u32 cap_low, u32 cap_ecc, + int *bad_data_bit, int *bad_ecc_bit) +{ + int i; + u8 syndrome; + + *bad_data_bit = -1; + *bad_ecc_bit = -1; + + /* + * Calculate the ECC of the captured data and XOR it with the captured + * ECC to find an ECC syndrome value we can search for + */ + syndrome = calculate_ecc(cap_high, cap_low) ^ cap_ecc; + + /* Check if a data line is stuck... */ + for (i = 0; i < 64; i++) { + if (syndrome == syndrome_from_bit(i)) { + *bad_data_bit = i; + return; + } + } + + /* If data is correct, check ECC bits for errors... */ + for (i = 0; i < 8; i++) { + if ((syndrome >> i) & 0x1) { + *bad_ecc_bit = i; + return; + } + } +} + +#define make64(high, low) (((u64)(high) << 32) | (low)) + +static void mpc85xx_mc_check(struct mem_ctl_info *mci) +{ + struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + struct csrow_info *csrow; + u32 bus_width; + u32 err_detect; + u32 syndrome; + u64 err_addr; + u32 pfn; + int row_index; + u32 cap_high; + u32 cap_low; + int bad_data_bit; + int bad_ecc_bit; + + err_detect = in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT); + if (!err_detect) + return; + + mpc85xx_mc_printk(mci, KERN_ERR, "Err Detect Register: %#8.8x\n", + err_detect); + + /* no more processing if not ECC bit errors */ + if (!(err_detect & (DDR_EDE_SBE | DDR_EDE_MBE))) { + out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, err_detect); + return; + } + + syndrome = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ECC); + + /* Mask off appropriate bits of syndrome based on bus width */ + bus_width = (in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG) & + DSC_DBW_MASK) ? 32 : 64; + if (bus_width == 64) + syndrome &= 0xff; + else + syndrome &= 0xffff; + + err_addr = make64( + in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_EXT_ADDRESS), + in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ADDRESS)); + pfn = err_addr >> PAGE_SHIFT; + + for (row_index = 0; row_index < mci->nr_csrows; row_index++) { + csrow = mci->csrows[row_index]; + if ((pfn >= csrow->first_page) && (pfn <= csrow->last_page)) + break; + } + + cap_high = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_DATA_HI); + cap_low = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_DATA_LO); + + /* + * Analyze single-bit errors on 64-bit wide buses + * TODO: Add support for 32-bit wide buses + */ + if ((err_detect & DDR_EDE_SBE) && (bus_width == 64)) { + sbe_ecc_decode(cap_high, cap_low, syndrome, + &bad_data_bit, &bad_ecc_bit); + + if (bad_data_bit != -1) + mpc85xx_mc_printk(mci, KERN_ERR, + "Faulty Data bit: %d\n", bad_data_bit); + if (bad_ecc_bit != -1) + mpc85xx_mc_printk(mci, KERN_ERR, + "Faulty ECC bit: %d\n", bad_ecc_bit); + + mpc85xx_mc_printk(mci, KERN_ERR, + "Expected Data / ECC:\t%#8.8x_%08x / %#2.2x\n", + cap_high ^ (1 << (bad_data_bit - 32)), + cap_low ^ (1 << bad_data_bit), + syndrome ^ (1 << bad_ecc_bit)); + } + + mpc85xx_mc_printk(mci, KERN_ERR, + "Captured Data / ECC:\t%#8.8x_%08x / %#2.2x\n", + cap_high, cap_low, syndrome); + mpc85xx_mc_printk(mci, KERN_ERR, "Err addr: %#8.8llx\n", err_addr); + mpc85xx_mc_printk(mci, KERN_ERR, "PFN: %#8.8x\n", pfn); + + /* we are out of range */ + if (row_index == mci->nr_csrows) + mpc85xx_mc_printk(mci, KERN_ERR, "PFN out of range!\n"); + + if (err_detect & DDR_EDE_SBE) + edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, + pfn, err_addr & ~PAGE_MASK, syndrome, + row_index, 0, -1, + mci->ctl_name, ""); + + if (err_detect & DDR_EDE_MBE) + edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, + pfn, err_addr & ~PAGE_MASK, syndrome, + row_index, 0, -1, + mci->ctl_name, ""); + + out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, err_detect); +} + +static irqreturn_t mpc85xx_mc_isr(int irq, void *dev_id) +{ + struct mem_ctl_info *mci = dev_id; + struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + u32 err_detect; + + err_detect = in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT); + if (!err_detect) + return IRQ_NONE; + + mpc85xx_mc_check(mci); + + return IRQ_HANDLED; +} + +static void mpc85xx_init_csrows(struct mem_ctl_info *mci) +{ + struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + struct csrow_info *csrow; + struct dimm_info *dimm; + u32 sdram_ctl; + u32 sdtype; + enum mem_type mtype; + u32 cs_bnds; + int index; + + sdram_ctl = in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG); + + sdtype = sdram_ctl & DSC_SDTYPE_MASK; + if (sdram_ctl & DSC_RD_EN) { + switch (sdtype) { + case DSC_SDTYPE_DDR: + mtype = MEM_RDDR; + break; + case DSC_SDTYPE_DDR2: + mtype = MEM_RDDR2; + break; + case DSC_SDTYPE_DDR3: + mtype = MEM_RDDR3; + break; + default: + mtype = MEM_UNKNOWN; + break; + } + } else { + switch (sdtype) { + case DSC_SDTYPE_DDR: + mtype = MEM_DDR; + break; + case DSC_SDTYPE_DDR2: + mtype = MEM_DDR2; + break; + case DSC_SDTYPE_DDR3: + mtype = MEM_DDR3; + break; + default: + mtype = MEM_UNKNOWN; + break; + } + } + + for (index = 0; index < mci->nr_csrows; index++) { + u32 start; + u32 end; + + csrow = mci->csrows[index]; + dimm = csrow->channels[0]->dimm; + + cs_bnds = in_be32(pdata->mc_vbase + MPC85XX_MC_CS_BNDS_0 + + (index * MPC85XX_MC_CS_BNDS_OFS)); + + start = (cs_bnds & 0xffff0000) >> 16; + end = (cs_bnds & 0x0000ffff); + + if (start == end) + continue; /* not populated */ + + start <<= (24 - PAGE_SHIFT); + end <<= (24 - PAGE_SHIFT); + end |= (1 << (24 - PAGE_SHIFT)) - 1; + + csrow->first_page = start; + csrow->last_page = end; + + dimm->nr_pages = end + 1 - start; + dimm->grain = 8; + dimm->mtype = mtype; + dimm->dtype = DEV_UNKNOWN; + if (sdram_ctl & DSC_X32_EN) + dimm->dtype = DEV_X32; + dimm->edac_mode = EDAC_SECDED; + } +} + +int mpc85xx_mc_err_probe(struct platform_device *op) +{ + struct mem_ctl_info *mci; + struct edac_mc_layer layers[2]; + struct mpc85xx_mc_pdata *pdata; + struct resource r; + u32 sdram_ctl; + int res; + + if (!devres_open_group(&op->dev, mpc85xx_mc_err_probe, GFP_KERNEL)) + return -ENOMEM; + + layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; + layers[0].size = 4; + layers[0].is_virt_csrow = true; + layers[1].type = EDAC_MC_LAYER_CHANNEL; + layers[1].size = 1; + layers[1].is_virt_csrow = false; + mci = edac_mc_alloc(edac_mc_idx, ARRAY_SIZE(layers), layers, + sizeof(*pdata)); + if (!mci) { + devres_release_group(&op->dev, mpc85xx_mc_err_probe); + return -ENOMEM; + } + + pdata = mci->pvt_info; + pdata->name = "mpc85xx_mc_err"; + pdata->irq = NO_IRQ; + mci->pdev = &op->dev; + pdata->edac_idx = edac_mc_idx++; + dev_set_drvdata(mci->pdev, mci); + mci->ctl_name = pdata->name; + mci->dev_name = pdata->name; + + res = of_address_to_resource(op->dev.of_node, 0, &r); + if (res) { + pr_err("%s: Unable to get resource for MC err regs\n", + __func__); + goto err; + } + + if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r), + pdata->name)) { + pr_err("%s: Error while requesting mem region\n", + __func__); + res = -EBUSY; + goto err; + } + + pdata->mc_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r)); + if (!pdata->mc_vbase) { + pr_err("%s: Unable to setup MC err regs\n", __func__); + res = -ENOMEM; + goto err; + } + + sdram_ctl = in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG); + if (!(sdram_ctl & DSC_ECC_EN)) { + /* no ECC */ + pr_warn("%s: No ECC DIMMs discovered\n", __func__); + res = -ENODEV; + goto err; + } + + edac_dbg(3, "init mci\n"); + mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_RDDR2 | + MEM_FLAG_DDR | MEM_FLAG_DDR2; + mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; + mci->edac_cap = EDAC_FLAG_SECDED; + mci->mod_name = EDAC_MOD_STR; + + if (edac_op_state == EDAC_OPSTATE_POLL) + mci->edac_check = mpc85xx_mc_check; + + mci->ctl_page_to_phys = NULL; + + mci->scrub_mode = SCRUB_SW_SRC; + + mpc85xx_init_csrows(mci); + + /* store the original error disable bits */ + orig_ddr_err_disable = + in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE); + out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE, 0); + + /* clear all error bits */ + out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, ~0); + + if (edac_mc_add_mc_with_groups(mci, mpc85xx_dev_groups)) { + edac_dbg(3, "failed edac_mc_add_mc()\n"); + goto err; + } + + if (edac_op_state == EDAC_OPSTATE_INT) { + out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_INT_EN, + DDR_EIE_MBEE | DDR_EIE_SBEE); + + /* store the original error management threshold */ + orig_ddr_err_sbe = in_be32(pdata->mc_vbase + + MPC85XX_MC_ERR_SBE) & 0xff0000; + + /* set threshold to 1 error per interrupt */ + out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_SBE, 0x10000); + + /* register interrupts */ + pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0); + res = devm_request_irq(&op->dev, pdata->irq, + mpc85xx_mc_isr, + IRQF_SHARED, + "[EDAC] MC err", mci); + if (res < 0) { + pr_err("%s: Unable to request irq %d for MPC85xx DRAM ERR\n", + __func__, pdata->irq); + irq_dispose_mapping(pdata->irq); + res = -ENODEV; + goto err2; + } + + pr_info(EDAC_MOD_STR " acquired irq %d for MC\n", + pdata->irq); + } + + devres_remove_group(&op->dev, mpc85xx_mc_err_probe); + edac_dbg(3, "success\n"); + pr_info(EDAC_MOD_STR " MC err registered\n"); + + return 0; + +err2: + edac_mc_del_mc(&op->dev); +err: + devres_release_group(&op->dev, mpc85xx_mc_err_probe); + edac_mc_free(mci); + return res; +} + +int mpc85xx_mc_err_remove(struct platform_device *op) +{ + struct mem_ctl_info *mci = dev_get_drvdata(&op->dev); + struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + + edac_dbg(0, "\n"); + + if (edac_op_state == EDAC_OPSTATE_INT) { + out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_INT_EN, 0); + irq_dispose_mapping(pdata->irq); + } + + out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE, + orig_ddr_err_disable); + out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_SBE, orig_ddr_err_sbe); + + edac_mc_del_mc(&op->dev); + edac_mc_free(mci); + return 0; +} diff --git a/drivers/edac/fsl_ddr_edac.h b/drivers/edac/fsl_ddr_edac.h new file mode 100644 index 000000000000..2f2c2b1890b9 --- /dev/null +++ b/drivers/edac/fsl_ddr_edac.h @@ -0,0 +1,86 @@ +/* + * Freescale Memory Controller kernel module + * + * Support Power-based SoCs including MPC85xx, MPC86xx, MPC83xx and + * ARM-based Layerscape SoCs including LS2xxx. Originally split + * out from mpc85xx_edac EDAC driver. + * + * Author: Dave Jiang <djiang@mvista.com> + * + * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + * + */ +#ifndef _FSL_DDR_EDAC_H_ +#define _FSL_DDR_EDAC_H_ + +#define mpc85xx_mc_printk(mci, level, fmt, arg...) \ + edac_mc_chipset_printk(mci, level, "FSL_DDR", fmt, ##arg) + +/* + * DRAM error defines + */ + +/* DDR_SDRAM_CFG */ +#define MPC85XX_MC_DDR_SDRAM_CFG 0x0110 +#define MPC85XX_MC_CS_BNDS_0 0x0000 +#define MPC85XX_MC_CS_BNDS_1 0x0008 +#define MPC85XX_MC_CS_BNDS_2 0x0010 +#define MPC85XX_MC_CS_BNDS_3 0x0018 +#define MPC85XX_MC_CS_BNDS_OFS 0x0008 + +#define MPC85XX_MC_DATA_ERR_INJECT_HI 0x0e00 +#define MPC85XX_MC_DATA_ERR_INJECT_LO 0x0e04 +#define MPC85XX_MC_ECC_ERR_INJECT 0x0e08 +#define MPC85XX_MC_CAPTURE_DATA_HI 0x0e20 +#define MPC85XX_MC_CAPTURE_DATA_LO 0x0e24 +#define MPC85XX_MC_CAPTURE_ECC 0x0e28 +#define MPC85XX_MC_ERR_DETECT 0x0e40 +#define MPC85XX_MC_ERR_DISABLE 0x0e44 +#define MPC85XX_MC_ERR_INT_EN 0x0e48 +#define MPC85XX_MC_CAPTURE_ATRIBUTES 0x0e4c +#define MPC85XX_MC_CAPTURE_ADDRESS 0x0e50 +#define MPC85XX_MC_CAPTURE_EXT_ADDRESS 0x0e54 +#define MPC85XX_MC_ERR_SBE 0x0e58 + +#define DSC_MEM_EN 0x80000000 +#define DSC_ECC_EN 0x20000000 +#define DSC_RD_EN 0x10000000 +#define DSC_DBW_MASK 0x00180000 +#define DSC_DBW_32 0x00080000 +#define DSC_DBW_64 0x00000000 + +#define DSC_SDTYPE_MASK 0x07000000 + +#define DSC_SDTYPE_DDR 0x02000000 +#define DSC_SDTYPE_DDR2 0x03000000 +#define DSC_SDTYPE_DDR3 0x07000000 +#define DSC_X32_EN 0x00000020 + +/* Err_Int_En */ +#define DDR_EIE_MSEE 0x1 /* memory select */ +#define DDR_EIE_SBEE 0x4 /* single-bit ECC error */ +#define DDR_EIE_MBEE 0x8 /* multi-bit ECC error */ + +/* Err_Detect */ +#define DDR_EDE_MSE 0x1 /* memory select */ +#define DDR_EDE_SBE 0x4 /* single-bit ECC error */ +#define DDR_EDE_MBE 0x8 /* multi-bit ECC error */ +#define DDR_EDE_MME 0x80000000 /* multiple memory errors */ + +/* Err_Disable */ +#define DDR_EDI_MSED 0x1 /* memory select disable */ +#define DDR_EDI_SBED 0x4 /* single-bit ECC error disable */ +#define DDR_EDI_MBED 0x8 /* multi-bit ECC error disable */ + +struct mpc85xx_mc_pdata { + char *name; + int edac_idx; + void __iomem *mc_vbase; + int irq; +}; +int mpc85xx_mc_err_probe(struct platform_device *op); +int mpc85xx_mc_err_remove(struct platform_device *op); +#endif diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index 73d809535eb3..c548a80f1823 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -27,15 +27,12 @@ #include "edac_module.h" #include "edac_core.h" #include "mpc85xx_edac.h" +#include "fsl_ddr_edac.h" static int edac_dev_idx; #ifdef CONFIG_PCI static int edac_pci_idx; #endif -static int edac_mc_idx; - -static u32 orig_ddr_err_disable; -static u32 orig_ddr_err_sbe; /* * PCI Err defines @@ -47,100 +44,6 @@ static u32 orig_pci_err_en; static u32 orig_l2_err_disable; -/************************ MC SYSFS parts ***********************************/ - -#define to_mci(k) container_of(k, struct mem_ctl_info, dev) - -static ssize_t mpc85xx_mc_inject_data_hi_show(struct device *dev, - struct device_attribute *mattr, - char *data) -{ - struct mem_ctl_info *mci = to_mci(dev); - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; - return sprintf(data, "0x%08x", - in_be32(pdata->mc_vbase + - MPC85XX_MC_DATA_ERR_INJECT_HI)); -} - -static ssize_t mpc85xx_mc_inject_data_lo_show(struct device *dev, - struct device_attribute *mattr, - char *data) -{ - struct mem_ctl_info *mci = to_mci(dev); - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; - return sprintf(data, "0x%08x", - in_be32(pdata->mc_vbase + - MPC85XX_MC_DATA_ERR_INJECT_LO)); -} - -static ssize_t mpc85xx_mc_inject_ctrl_show(struct device *dev, - struct device_attribute *mattr, - char *data) -{ - struct mem_ctl_info *mci = to_mci(dev); - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; - return sprintf(data, "0x%08x", - in_be32(pdata->mc_vbase + MPC85XX_MC_ECC_ERR_INJECT)); -} - -static ssize_t mpc85xx_mc_inject_data_hi_store(struct device *dev, - struct device_attribute *mattr, - const char *data, size_t count) -{ - struct mem_ctl_info *mci = to_mci(dev); - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; - if (isdigit(*data)) { - out_be32(pdata->mc_vbase + MPC85XX_MC_DATA_ERR_INJECT_HI, - simple_strtoul(data, NULL, 0)); - return count; - } - return 0; -} - -static ssize_t mpc85xx_mc_inject_data_lo_store(struct device *dev, - struct device_attribute *mattr, - const char *data, size_t count) -{ - struct mem_ctl_info *mci = to_mci(dev); - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; - if (isdigit(*data)) { - out_be32(pdata->mc_vbase + MPC85XX_MC_DATA_ERR_INJECT_LO, - simple_strtoul(data, NULL, 0)); - return count; - } - return 0; -} - -static ssize_t mpc85xx_mc_inject_ctrl_store(struct device *dev, - struct device_attribute *mattr, - const char *data, size_t count) -{ - struct mem_ctl_info *mci = to_mci(dev); - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; - if (isdigit(*data)) { - out_be32(pdata->mc_vbase + MPC85XX_MC_ECC_ERR_INJECT, - simple_strtoul(data, NULL, 0)); - return count; - } - return 0; -} - -DEVICE_ATTR(inject_data_hi, S_IRUGO | S_IWUSR, - mpc85xx_mc_inject_data_hi_show, mpc85xx_mc_inject_data_hi_store); -DEVICE_ATTR(inject_data_lo, S_IRUGO | S_IWUSR, - mpc85xx_mc_inject_data_lo_show, mpc85xx_mc_inject_data_lo_store); -DEVICE_ATTR(inject_ctrl, S_IRUGO | S_IWUSR, - mpc85xx_mc_inject_ctrl_show, mpc85xx_mc_inject_ctrl_store); - -static struct attribute *mpc85xx_dev_attrs[] = { - &dev_attr_inject_data_hi.attr, - &dev_attr_inject_data_lo.attr, - &dev_attr_inject_ctrl.attr, - NULL -}; - -ATTRIBUTE_GROUPS(mpc85xx_dev); - /**************************** PCI Err device ***************************/ #ifdef CONFIG_PCI @@ -725,463 +628,6 @@ static struct platform_driver mpc85xx_l2_err_driver = { }, }; -/**************************** MC Err device ***************************/ - -/* - * Taken from table 8-55 in the MPC8641 User's Manual and/or 9-61 in the - * MPC8572 User's Manual. Each line represents a syndrome bit column as a - * 64-bit value, but split into an upper and lower 32-bit chunk. The labels - * below correspond to Freescale's manuals. - */ -static unsigned int ecc_table[16] = { - /* MSB LSB */ - /* [0:31] [32:63] */ - 0xf00fe11e, 0xc33c0ff7, /* Syndrome bit 7 */ - 0x00ff00ff, 0x00fff0ff, - 0x0f0f0f0f, 0x0f0fff00, - 0x11113333, 0x7777000f, - 0x22224444, 0x8888222f, - 0x44448888, 0xffff4441, - 0x8888ffff, 0x11118882, - 0xffff1111, 0x22221114, /* Syndrome bit 0 */ -}; - -/* - * Calculate the correct ECC value for a 64-bit value specified by high:low - */ -static u8 calculate_ecc(u32 high, u32 low) -{ - u32 mask_low; - u32 mask_high; - int bit_cnt; - u8 ecc = 0; - int i; - int j; - - for (i = 0; i < 8; i++) { - mask_high = ecc_table[i * 2]; - mask_low = ecc_table[i * 2 + 1]; - bit_cnt = 0; - - for (j = 0; j < 32; j++) { - if ((mask_high >> j) & 1) - bit_cnt ^= (high >> j) & 1; - if ((mask_low >> j) & 1) - bit_cnt ^= (low >> j) & 1; - } - - ecc |= bit_cnt << i; - } - - return ecc; -} - -/* - * Create the syndrome code which is generated if the data line specified by - * 'bit' failed. Eg generate an 8-bit codes seen in Table 8-55 in the MPC8641 - * User's Manual and 9-61 in the MPC8572 User's Manual. - */ -static u8 syndrome_from_bit(unsigned int bit) { - int i; - u8 syndrome = 0; - - /* - * Cycle through the upper or lower 32-bit portion of each value in - * ecc_table depending on if 'bit' is in the upper or lower half of - * 64-bit data. - */ - for (i = bit < 32; i < 16; i += 2) - syndrome |= ((ecc_table[i] >> (bit % 32)) & 1) << (i / 2); - - return syndrome; -} - -/* - * Decode data and ecc syndrome to determine what went wrong - * Note: This can only decode single-bit errors - */ -static void sbe_ecc_decode(u32 cap_high, u32 cap_low, u32 cap_ecc, - int *bad_data_bit, int *bad_ecc_bit) -{ - int i; - u8 syndrome; - - *bad_data_bit = -1; - *bad_ecc_bit = -1; - - /* - * Calculate the ECC of the captured data and XOR it with the captured - * ECC to find an ECC syndrome value we can search for - */ - syndrome = calculate_ecc(cap_high, cap_low) ^ cap_ecc; - - /* Check if a data line is stuck... */ - for (i = 0; i < 64; i++) { - if (syndrome == syndrome_from_bit(i)) { - *bad_data_bit = i; - return; - } - } - - /* If data is correct, check ECC bits for errors... */ - for (i = 0; i < 8; i++) { - if ((syndrome >> i) & 0x1) { - *bad_ecc_bit = i; - return; - } - } -} - -#define make64(high, low) (((u64)(high) << 32) | (low)) - -static void mpc85xx_mc_check(struct mem_ctl_info *mci) -{ - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; - struct csrow_info *csrow; - u32 bus_width; - u32 err_detect; - u32 syndrome; - u64 err_addr; - u32 pfn; - int row_index; - u32 cap_high; - u32 cap_low; - int bad_data_bit; - int bad_ecc_bit; - - err_detect = in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT); - if (!err_detect) - return; - - mpc85xx_mc_printk(mci, KERN_ERR, "Err Detect Register: %#8.8x\n", - err_detect); - - /* no more processing if not ECC bit errors */ - if (!(err_detect & (DDR_EDE_SBE | DDR_EDE_MBE))) { - out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, err_detect); - return; - } - - syndrome = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ECC); - - /* Mask off appropriate bits of syndrome based on bus width */ - bus_width = (in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG) & - DSC_DBW_MASK) ? 32 : 64; - if (bus_width == 64) - syndrome &= 0xff; - else - syndrome &= 0xffff; - - err_addr = make64( - in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_EXT_ADDRESS), - in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ADDRESS)); - pfn = err_addr >> PAGE_SHIFT; - - for (row_index = 0; row_index < mci->nr_csrows; row_index++) { - csrow = mci->csrows[row_index]; - if ((pfn >= csrow->first_page) && (pfn <= csrow->last_page)) - break; - } - - cap_high = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_DATA_HI); - cap_low = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_DATA_LO); - - /* - * Analyze single-bit errors on 64-bit wide buses - * TODO: Add support for 32-bit wide buses - */ - if ((err_detect & DDR_EDE_SBE) && (bus_width == 64)) { - sbe_ecc_decode(cap_high, cap_low, syndrome, - &bad_data_bit, &bad_ecc_bit); - - if (bad_data_bit != -1) - mpc85xx_mc_printk(mci, KERN_ERR, - "Faulty Data bit: %d\n", bad_data_bit); - if (bad_ecc_bit != -1) - mpc85xx_mc_printk(mci, KERN_ERR, - "Faulty ECC bit: %d\n", bad_ecc_bit); - - mpc85xx_mc_printk(mci, KERN_ERR, - "Expected Data / ECC:\t%#8.8x_%08x / %#2.2x\n", - cap_high ^ (1 << (bad_data_bit - 32)), - cap_low ^ (1 << bad_data_bit), - syndrome ^ (1 << bad_ecc_bit)); - } - - mpc85xx_mc_printk(mci, KERN_ERR, - "Captured Data / ECC:\t%#8.8x_%08x / %#2.2x\n", - cap_high, cap_low, syndrome); - mpc85xx_mc_printk(mci, KERN_ERR, "Err addr: %#8.8llx\n", err_addr); - mpc85xx_mc_printk(mci, KERN_ERR, "PFN: %#8.8x\n", pfn); - - /* we are out of range */ - if (row_index == mci->nr_csrows) - mpc85xx_mc_printk(mci, KERN_ERR, "PFN out of range!\n"); - - if (err_detect & DDR_EDE_SBE) - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, - pfn, err_addr & ~PAGE_MASK, syndrome, - row_index, 0, -1, - mci->ctl_name, ""); - - if (err_detect & DDR_EDE_MBE) - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, - pfn, err_addr & ~PAGE_MASK, syndrome, - row_index, 0, -1, - mci->ctl_name, ""); - - out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, err_detect); -} - -static irqreturn_t mpc85xx_mc_isr(int irq, void *dev_id) -{ - struct mem_ctl_info *mci = dev_id; - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; - u32 err_detect; - - err_detect = in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT); - if (!err_detect) - return IRQ_NONE; - - mpc85xx_mc_check(mci); - - return IRQ_HANDLED; -} - -static void mpc85xx_init_csrows(struct mem_ctl_info *mci) -{ - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; - struct csrow_info *csrow; - struct dimm_info *dimm; - u32 sdram_ctl; - u32 sdtype; - enum mem_type mtype; - u32 cs_bnds; - int index; - - sdram_ctl = in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG); - - sdtype = sdram_ctl & DSC_SDTYPE_MASK; - if (sdram_ctl & DSC_RD_EN) { - switch (sdtype) { - case DSC_SDTYPE_DDR: - mtype = MEM_RDDR; - break; - case DSC_SDTYPE_DDR2: - mtype = MEM_RDDR2; - break; - case DSC_SDTYPE_DDR3: - mtype = MEM_RDDR3; - break; - default: - mtype = MEM_UNKNOWN; - break; - } - } else { - switch (sdtype) { - case DSC_SDTYPE_DDR: - mtype = MEM_DDR; - break; - case DSC_SDTYPE_DDR2: - mtype = MEM_DDR2; - break; - case DSC_SDTYPE_DDR3: - mtype = MEM_DDR3; - break; - default: - mtype = MEM_UNKNOWN; - break; - } - } - - for (index = 0; index < mci->nr_csrows; index++) { - u32 start; - u32 end; - - csrow = mci->csrows[index]; - dimm = csrow->channels[0]->dimm; - - cs_bnds = in_be32(pdata->mc_vbase + MPC85XX_MC_CS_BNDS_0 + - (index * MPC85XX_MC_CS_BNDS_OFS)); - - start = (cs_bnds & 0xffff0000) >> 16; - end = (cs_bnds & 0x0000ffff); - - if (start == end) - continue; /* not populated */ - - start <<= (24 - PAGE_SHIFT); - end <<= (24 - PAGE_SHIFT); - end |= (1 << (24 - PAGE_SHIFT)) - 1; - - csrow->first_page = start; - csrow->last_page = end; - - dimm->nr_pages = end + 1 - start; - dimm->grain = 8; - dimm->mtype = mtype; - dimm->dtype = DEV_UNKNOWN; - if (sdram_ctl & DSC_X32_EN) - dimm->dtype = DEV_X32; - dimm->edac_mode = EDAC_SECDED; - } -} - -static int mpc85xx_mc_err_probe(struct platform_device *op) -{ - struct mem_ctl_info *mci; - struct edac_mc_layer layers[2]; - struct mpc85xx_mc_pdata *pdata; - struct resource r; - u32 sdram_ctl; - int res; - - if (!devres_open_group(&op->dev, mpc85xx_mc_err_probe, GFP_KERNEL)) - return -ENOMEM; - - layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; - layers[0].size = 4; - layers[0].is_virt_csrow = true; - layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = 1; - layers[1].is_virt_csrow = false; - mci = edac_mc_alloc(edac_mc_idx, ARRAY_SIZE(layers), layers, - sizeof(*pdata)); - if (!mci) { - devres_release_group(&op->dev, mpc85xx_mc_err_probe); - return -ENOMEM; - } - - pdata = mci->pvt_info; - pdata->name = "mpc85xx_mc_err"; - pdata->irq = NO_IRQ; - mci->pdev = &op->dev; - pdata->edac_idx = edac_mc_idx++; - dev_set_drvdata(mci->pdev, mci); - mci->ctl_name = pdata->name; - mci->dev_name = pdata->name; - - res = of_address_to_resource(op->dev.of_node, 0, &r); - if (res) { - pr_err("%s: Unable to get resource for MC err regs\n", __func__); - goto err; - } - - if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r), - pdata->name)) { - pr_err("%s: Error while requesting mem region\n", __func__); - res = -EBUSY; - goto err; - } - - pdata->mc_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r)); - if (!pdata->mc_vbase) { - pr_err("%s: Unable to setup MC err regs\n", __func__); - res = -ENOMEM; - goto err; - } - - sdram_ctl = in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG); - if (!(sdram_ctl & DSC_ECC_EN)) { - /* no ECC */ - pr_warn("%s: No ECC DIMMs discovered\n", __func__); - res = -ENODEV; - goto err; - } - - edac_dbg(3, "init mci\n"); - mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_RDDR2 | - MEM_FLAG_DDR | MEM_FLAG_DDR2; - mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; - mci->edac_cap = EDAC_FLAG_SECDED; - mci->mod_name = EDAC_MOD_STR; - mci->mod_ver = MPC85XX_REVISION; - - if (edac_op_state == EDAC_OPSTATE_POLL) - mci->edac_check = mpc85xx_mc_check; - - mci->ctl_page_to_phys = NULL; - - mci->scrub_mode = SCRUB_SW_SRC; - - mpc85xx_init_csrows(mci); - - /* store the original error disable bits */ - orig_ddr_err_disable = - in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE); - out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE, 0); - - /* clear all error bits */ - out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, ~0); - - if (edac_mc_add_mc_with_groups(mci, mpc85xx_dev_groups)) { - edac_dbg(3, "failed edac_mc_add_mc()\n"); - goto err; - } - - if (edac_op_state == EDAC_OPSTATE_INT) { - out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_INT_EN, - DDR_EIE_MBEE | DDR_EIE_SBEE); - - /* store the original error management threshold */ - orig_ddr_err_sbe = in_be32(pdata->mc_vbase + - MPC85XX_MC_ERR_SBE) & 0xff0000; - - /* set threshold to 1 error per interrupt */ - out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_SBE, 0x10000); - - /* register interrupts */ - pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0); - res = devm_request_irq(&op->dev, pdata->irq, - mpc85xx_mc_isr, - IRQF_SHARED, - "[EDAC] MC err", mci); - if (res < 0) { - pr_err("%s: Unable to request irq %d for MPC85xx DRAM ERR\n", - __func__, pdata->irq); - irq_dispose_mapping(pdata->irq); - res = -ENODEV; - goto err2; - } - - pr_info(EDAC_MOD_STR " acquired irq %d for MC\n", pdata->irq); - } - - devres_remove_group(&op->dev, mpc85xx_mc_err_probe); - edac_dbg(3, "success\n"); - pr_info(EDAC_MOD_STR " MC err registered\n"); - - return 0; - -err2: - edac_mc_del_mc(&op->dev); -err: - devres_release_group(&op->dev, mpc85xx_mc_err_probe); - edac_mc_free(mci); - return res; -} - -static int mpc85xx_mc_err_remove(struct platform_device *op) -{ - struct mem_ctl_info *mci = dev_get_drvdata(&op->dev); - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; - - edac_dbg(0, "\n"); - - if (edac_op_state == EDAC_OPSTATE_INT) { - out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_INT_EN, 0); - irq_dispose_mapping(pdata->irq); - } - - out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE, - orig_ddr_err_disable); - out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_SBE, orig_ddr_err_sbe); - - edac_mc_del_mc(&op->dev); - edac_mc_free(mci); - return 0; -} - static const struct of_device_id mpc85xx_mc_err_of_match[] = { /* deprecate the fsl,85.. forms in the future, 2.6.30? */ { .compatible = "fsl,8540-memory-controller", }, diff --git a/drivers/edac/mpc85xx_edac.h b/drivers/edac/mpc85xx_edac.h index 9352e88d53e5..3f6fb16ad34f 100644 --- a/drivers/edac/mpc85xx_edac.h +++ b/drivers/edac/mpc85xx_edac.h @@ -17,65 +17,6 @@ #define mpc85xx_printk(level, fmt, arg...) \ edac_printk(level, "MPC85xx", fmt, ##arg) -#define mpc85xx_mc_printk(mci, level, fmt, arg...) \ - edac_mc_chipset_printk(mci, level, "MPC85xx", fmt, ##arg) - -/* - * DRAM error defines - */ - -/* DDR_SDRAM_CFG */ -#define MPC85XX_MC_DDR_SDRAM_CFG 0x0110 -#define MPC85XX_MC_CS_BNDS_0 0x0000 -#define MPC85XX_MC_CS_BNDS_1 0x0008 -#define MPC85XX_MC_CS_BNDS_2 0x0010 -#define MPC85XX_MC_CS_BNDS_3 0x0018 -#define MPC85XX_MC_CS_BNDS_OFS 0x0008 - -#define MPC85XX_MC_DATA_ERR_INJECT_HI 0x0e00 -#define MPC85XX_MC_DATA_ERR_INJECT_LO 0x0e04 -#define MPC85XX_MC_ECC_ERR_INJECT 0x0e08 -#define MPC85XX_MC_CAPTURE_DATA_HI 0x0e20 -#define MPC85XX_MC_CAPTURE_DATA_LO 0x0e24 -#define MPC85XX_MC_CAPTURE_ECC 0x0e28 -#define MPC85XX_MC_ERR_DETECT 0x0e40 -#define MPC85XX_MC_ERR_DISABLE 0x0e44 -#define MPC85XX_MC_ERR_INT_EN 0x0e48 -#define MPC85XX_MC_CAPTURE_ATRIBUTES 0x0e4c -#define MPC85XX_MC_CAPTURE_ADDRESS 0x0e50 -#define MPC85XX_MC_CAPTURE_EXT_ADDRESS 0x0e54 -#define MPC85XX_MC_ERR_SBE 0x0e58 - -#define DSC_MEM_EN 0x80000000 -#define DSC_ECC_EN 0x20000000 -#define DSC_RD_EN 0x10000000 -#define DSC_DBW_MASK 0x00180000 -#define DSC_DBW_32 0x00080000 -#define DSC_DBW_64 0x00000000 - -#define DSC_SDTYPE_MASK 0x07000000 - -#define DSC_SDTYPE_DDR 0x02000000 -#define DSC_SDTYPE_DDR2 0x03000000 -#define DSC_SDTYPE_DDR3 0x07000000 -#define DSC_X32_EN 0x00000020 - -/* Err_Int_En */ -#define DDR_EIE_MSEE 0x1 /* memory select */ -#define DDR_EIE_SBEE 0x4 /* single-bit ECC error */ -#define DDR_EIE_MBEE 0x8 /* multi-bit ECC error */ - -/* Err_Detect */ -#define DDR_EDE_MSE 0x1 /* memory select */ -#define DDR_EDE_SBE 0x4 /* single-bit ECC error */ -#define DDR_EDE_MBE 0x8 /* multi-bit ECC error */ -#define DDR_EDE_MME 0x80000000 /* multiple memory errors */ - -/* Err_Disable */ -#define DDR_EDI_MSED 0x1 /* memory select disable */ -#define DDR_EDI_SBED 0x4 /* single-bit ECC error disable */ -#define DDR_EDI_MBED 0x8 /* multi-bit ECC error disable */ - /* * L2 Err defines */ @@ -149,13 +90,6 @@ #define MPC85XX_PCIE_ERR_CAP_R2 0x0030 #define MPC85XX_PCIE_ERR_CAP_R3 0x0034 -struct mpc85xx_mc_pdata { - char *name; - int edac_idx; - void __iomem *mc_vbase; - int irq; -}; - struct mpc85xx_l2_pdata { char *name; int edac_idx; |