diff options
Diffstat (limited to 'drivers/edac')
-rw-r--r-- | drivers/edac/amd76x_edac.c | 1 | ||||
-rw-r--r-- | drivers/edac/cpc925_edac.c | 1 | ||||
-rw-r--r-- | drivers/edac/e752x_edac.c | 118 | ||||
-rw-r--r-- | drivers/edac/e7xxx_edac.c | 1 | ||||
-rw-r--r-- | drivers/edac/edac_device_sysfs.c | 7 | ||||
-rw-r--r-- | drivers/edac/edac_mc_sysfs.c | 5 | ||||
-rw-r--r-- | drivers/edac/edac_mce_amd.c | 12 | ||||
-rw-r--r-- | drivers/edac/edac_pci_sysfs.c | 5 | ||||
-rw-r--r-- | drivers/edac/i3000_edac.c | 1 | ||||
-rw-r--r-- | drivers/edac/i3200_edac.c | 1 | ||||
-rw-r--r-- | drivers/edac/i5100_edac.c | 1 | ||||
-rw-r--r-- | drivers/edac/i82443bxgx_edac.c | 1 | ||||
-rw-r--r-- | drivers/edac/i82860_edac.c | 1 | ||||
-rw-r--r-- | drivers/edac/i82875p_edac.c | 1 | ||||
-rw-r--r-- | drivers/edac/i82975x_edac.c | 1 | ||||
-rw-r--r-- | drivers/edac/mpc85xx_edac.c | 165 | ||||
-rw-r--r-- | drivers/edac/mpc85xx_edac.h | 3 | ||||
-rw-r--r-- | drivers/edac/mv64x60_edac.c | 2 | ||||
-rw-r--r-- | drivers/edac/pasemi_edac.c | 1 | ||||
-rw-r--r-- | drivers/edac/r82600_edac.c | 1 | ||||
-rw-r--r-- | drivers/edac/x38_edac.c | 1 |
21 files changed, 284 insertions, 46 deletions
diff --git a/drivers/edac/amd76x_edac.c b/drivers/edac/amd76x_edac.c index 2b95f1a3edf..f2330f81cb5 100644 --- a/drivers/edac/amd76x_edac.c +++ b/drivers/edac/amd76x_edac.c @@ -16,7 +16,6 @@ #include <linux/init.h> #include <linux/pci.h> #include <linux/pci_ids.h> -#include <linux/slab.h> #include <linux/edac.h> #include "edac_core.h" diff --git a/drivers/edac/cpc925_edac.c b/drivers/edac/cpc925_edac.c index 3d50274f134..1609a19df49 100644 --- a/drivers/edac/cpc925_edac.c +++ b/drivers/edac/cpc925_edac.c @@ -25,6 +25,7 @@ #include <linux/edac.h> #include <linux/of.h> #include <linux/platform_device.h> +#include <linux/gfp.h> #include "edac_core.h" #include "edac_module.h" diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c index d205d493a68..ae3f80c5419 100644 --- a/drivers/edac/e752x_edac.c +++ b/drivers/edac/e752x_edac.c @@ -21,7 +21,6 @@ #include <linux/init.h> #include <linux/pci.h> #include <linux/pci_ids.h> -#include <linux/slab.h> #include <linux/edac.h> #include "edac_core.h" @@ -75,6 +74,14 @@ static struct edac_pci_ctl_info *e752x_pci; #define E752X_NR_CSROWS 8 /* number of csrows */ /* E752X register addresses - device 0 function 0 */ +#define E752X_MCHSCRB 0x52 /* Memory Scrub register (16b) */ + /* + * 6:5 Scrub Completion Count + * 3:2 Scrub Rate (i3100 only) + * 01=fast 10=normal + * 1:0 Scrub Mode enable + * 00=off 10=on + */ #define E752X_DRB 0x60 /* DRAM row boundary register (8b) */ #define E752X_DRA 0x70 /* DRAM row attribute register (8b) */ /* @@ -240,6 +247,41 @@ static const struct e752x_dev_info e752x_devs[] = { .ctl_name = "3100"}, }; +/* Valid scrub rates for the e752x/3100 hardware memory scrubber. We + * map the scrubbing bandwidth to a hardware register value. The 'set' + * operation finds the 'matching or higher value'. Note that scrubbing + * on the e752x can only be enabled/disabled. The 3100 supports + * a normal and fast mode. + */ + +#define SDRATE_EOT 0xFFFFFFFF + +struct scrubrate { + u32 bandwidth; /* bandwidth consumed by scrubbing in bytes/sec */ + u16 scrubval; /* register value for scrub rate */ +}; + +/* Rate below assumes same performance as i3100 using PC3200 DDR2 in + * normal mode. e752x bridges don't support choosing normal or fast mode, + * so the scrubbing bandwidth value isn't all that important - scrubbing is + * either on or off. + */ +static const struct scrubrate scrubrates_e752x[] = { + {0, 0x00}, /* Scrubbing Off */ + {500000, 0x02}, /* Scrubbing On */ + {SDRATE_EOT, 0x00} /* End of Table */ +}; + +/* Fast mode: 2 GByte PC3200 DDR2 scrubbed in 33s = 63161283 bytes/s + * Normal mode: 125 (32000 / 256) times slower than fast mode. + */ +static const struct scrubrate scrubrates_i3100[] = { + {0, 0x00}, /* Scrubbing Off */ + {500000, 0x0a}, /* Normal mode - 32k clocks */ + {62500000, 0x06}, /* Fast mode - 256 clocks */ + {SDRATE_EOT, 0x00} /* End of Table */ +}; + static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci, unsigned long page) { @@ -915,6 +957,68 @@ static void e752x_check(struct mem_ctl_info *mci) e752x_process_error_info(mci, &info, 1); } +/* Program byte/sec bandwidth scrub rate to hardware */ +static int set_sdram_scrub_rate(struct mem_ctl_info *mci, u32 *new_bw) +{ + const struct scrubrate *scrubrates; + struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info; + struct pci_dev *pdev = pvt->dev_d0f0; + int i; + + if (pvt->dev_info->ctl_dev == PCI_DEVICE_ID_INTEL_3100_0) + scrubrates = scrubrates_i3100; + else + scrubrates = scrubrates_e752x; + + /* Translate the desired scrub rate to a e752x/3100 register value. + * Search for the bandwidth that is equal or greater than the + * desired rate and program the cooresponding register value. + */ + for (i = 0; scrubrates[i].bandwidth != SDRATE_EOT; i++) + if (scrubrates[i].bandwidth >= *new_bw) + break; + + if (scrubrates[i].bandwidth == SDRATE_EOT) + return -1; + + pci_write_config_word(pdev, E752X_MCHSCRB, scrubrates[i].scrubval); + + return 0; +} + +/* Convert current scrub rate value into byte/sec bandwidth */ +static int get_sdram_scrub_rate(struct mem_ctl_info *mci, u32 *bw) +{ + const struct scrubrate *scrubrates; + struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info; + struct pci_dev *pdev = pvt->dev_d0f0; + u16 scrubval; + int i; + + if (pvt->dev_info->ctl_dev == PCI_DEVICE_ID_INTEL_3100_0) + scrubrates = scrubrates_i3100; + else + scrubrates = scrubrates_e752x; + + /* Find the bandwidth matching the memory scrubber configuration */ + pci_read_config_word(pdev, E752X_MCHSCRB, &scrubval); + scrubval = scrubval & 0x0f; + + for (i = 0; scrubrates[i].bandwidth != SDRATE_EOT; i++) + if (scrubrates[i].scrubval == scrubval) + break; + + if (scrubrates[i].bandwidth == SDRATE_EOT) { + e752x_printk(KERN_WARNING, + "Invalid sdram scrub control value: 0x%x\n", scrubval); + return -1; + } + + *bw = scrubrates[i].bandwidth; + + return 0; +} + /* Return 1 if dual channel mode is active. Else return 0. */ static inline int dual_channel_active(u16 ddrcsr) { @@ -1073,10 +1177,7 @@ fail: /* Setup system bus parity mask register. * Sysbus parity supported on: - * e7320/e7520/e7525 + Xeon - * i3100 + Xeon/Celeron - * Sysbus parity not supported on: - * i3100 + Pentium M/Celeron M/Core Duo/Core2 Duo + * e7320/e7520/e7525 + Xeon */ static void e752x_init_sysbus_parity_mask(struct e752x_pvt *pvt) { @@ -1087,10 +1188,7 @@ static void e752x_init_sysbus_parity_mask(struct e752x_pvt *pvt) /* Allow module parameter override, else see if CPU supports parity */ if (sysbus_parity != -1) { enable = sysbus_parity; - } else if (cpu_id[0] && - ((strstr(cpu_id, "Pentium") && strstr(cpu_id, " M ")) || - (strstr(cpu_id, "Celeron") && strstr(cpu_id, " M ")) || - (strstr(cpu_id, "Core") && strstr(cpu_id, "Duo")))) { + } else if (cpu_id[0] && !strstr(cpu_id, "Xeon")) { e752x_printk(KERN_INFO, "System Bus Parity not " "supported by CPU, disabling\n"); enable = 0; @@ -1187,6 +1285,8 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) mci->dev_name = pci_name(pdev); mci->edac_check = e752x_check; mci->ctl_page_to_phys = ctl_page_to_phys; + mci->set_sdram_scrub_rate = set_sdram_scrub_rate; + mci->get_sdram_scrub_rate = get_sdram_scrub_rate; /* set the map type. 1 = normal, 0 = reversed * Must be set before e752x_init_csrows in case csrow mapping diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c index c7d11cc4e21..1731d724581 100644 --- a/drivers/edac/e7xxx_edac.c +++ b/drivers/edac/e7xxx_edac.c @@ -26,7 +26,6 @@ #include <linux/init.h> #include <linux/pci.h> #include <linux/pci_ids.h> -#include <linux/slab.h> #include <linux/edac.h> #include "edac_core.h" diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c index 53764577035..070968178a2 100644 --- a/drivers/edac/edac_device_sysfs.c +++ b/drivers/edac/edac_device_sysfs.c @@ -12,6 +12,7 @@ #include <linux/ctype.h> #include <linux/module.h> +#include <linux/slab.h> #include "edac_core.h" #include "edac_module.h" @@ -137,7 +138,7 @@ static ssize_t edac_dev_ctl_info_store(struct kobject *kobj, } /* edac_dev file operations for an 'ctl_info' */ -static struct sysfs_ops device_ctl_info_ops = { +static const struct sysfs_ops device_ctl_info_ops = { .show = edac_dev_ctl_info_show, .store = edac_dev_ctl_info_store }; @@ -373,7 +374,7 @@ static ssize_t edac_dev_instance_store(struct kobject *kobj, } /* edac_dev file operations for an 'instance' */ -static struct sysfs_ops device_instance_ops = { +static const struct sysfs_ops device_instance_ops = { .show = edac_dev_instance_show, .store = edac_dev_instance_store }; @@ -476,7 +477,7 @@ static ssize_t edac_dev_block_store(struct kobject *kobj, } /* edac_dev file operations for a 'block' */ -static struct sysfs_ops device_block_ops = { +static const struct sysfs_ops device_block_ops = { .show = edac_dev_block_show, .store = edac_dev_block_store }; diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index e1d4ce08348..418b65f1a1d 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -10,6 +10,7 @@ */ #include <linux/ctype.h> +#include <linux/slab.h> #include <linux/bug.h> #include "edac_core.h" @@ -245,7 +246,7 @@ static ssize_t csrowdev_store(struct kobject *kobj, struct attribute *attr, return -EIO; } -static struct sysfs_ops csrowfs_ops = { +static const struct sysfs_ops csrowfs_ops = { .show = csrowdev_show, .store = csrowdev_store }; @@ -575,7 +576,7 @@ static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr, } /* Intermediate show/store table */ -static struct sysfs_ops mci_ops = { +static const struct sysfs_ops mci_ops = { .show = mcidev_show, .store = mcidev_store }; diff --git a/drivers/edac/edac_mce_amd.c b/drivers/edac/edac_mce_amd.c index 8fc91a01962..97e64bcdbc0 100644 --- a/drivers/edac/edac_mce_amd.c +++ b/drivers/edac/edac_mce_amd.c @@ -294,7 +294,6 @@ wrong_ls_mce: void amd_decode_nb_mce(int node_id, struct err_regs *regs, int handle_errors) { u32 ec = ERROR_CODE(regs->nbsl); - u32 xec = EXT_ERROR_CODE(regs->nbsl); if (!handle_errors) return; @@ -316,10 +315,15 @@ void amd_decode_nb_mce(int node_id, struct err_regs *regs, int handle_errors) if (regs->nbsh & K8_NBSH_ERR_CPU_VAL) pr_cont(", core: %u\n", (u8)(regs->nbsh & 0xf)); } else { - pr_cont(", core: %d\n", fls((regs->nbsh & 0xf) - 1)); + u8 assoc_cpus = regs->nbsh & 0xf; + + if (assoc_cpus > 0) + pr_cont(", core: %d", fls(assoc_cpus) - 1); + + pr_cont("\n"); } - pr_emerg("%s.\n", EXT_ERR_MSG(xec)); + pr_emerg("%s.\n", EXT_ERR_MSG(regs->nbsl)); if (BUS_ERROR(ec) && nb_bus_decoder) nb_bus_decoder(node_id, regs); @@ -369,7 +373,7 @@ static int amd_decode_mce(struct notifier_block *nb, unsigned long val, ((m->status & MCI_STATUS_PCC) ? "yes" : "no")); /* do the two bits[14:13] together */ - ecc = m->status & (3ULL << 45); + ecc = (m->status >> 45) & 0x3; if (ecc) pr_cont(", %sECC Error", ((ecc == 2) ? "C" : "U")); diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c index fb60a877d76..c39697df9cb 100644 --- a/drivers/edac/edac_pci_sysfs.c +++ b/drivers/edac/edac_pci_sysfs.c @@ -8,6 +8,7 @@ */ #include <linux/module.h> #include <linux/sysdev.h> +#include <linux/slab.h> #include <linux/ctype.h> #include "edac_core.h" @@ -121,7 +122,7 @@ static ssize_t edac_pci_instance_store(struct kobject *kobj, } /* fs_ops table */ -static struct sysfs_ops pci_instance_ops = { +static const struct sysfs_ops pci_instance_ops = { .show = edac_pci_instance_show, .store = edac_pci_instance_store }; @@ -261,7 +262,7 @@ static ssize_t edac_pci_dev_store(struct kobject *kobj, return -EIO; } -static struct sysfs_ops edac_pci_sysfs_ops = { +static const struct sysfs_ops edac_pci_sysfs_ops = { .show = edac_pci_dev_show, .store = edac_pci_dev_store }; diff --git a/drivers/edac/i3000_edac.c b/drivers/edac/i3000_edac.c index 6c9a0f2a593..c0510b3d703 100644 --- a/drivers/edac/i3000_edac.c +++ b/drivers/edac/i3000_edac.c @@ -13,7 +13,6 @@ #include <linux/init.h> #include <linux/pci.h> #include <linux/pci_ids.h> -#include <linux/slab.h> #include <linux/edac.h> #include "edac_core.h" diff --git a/drivers/edac/i3200_edac.c b/drivers/edac/i3200_edac.c index fde4db91c4d..d41f9002da4 100644 --- a/drivers/edac/i3200_edac.c +++ b/drivers/edac/i3200_edac.c @@ -11,7 +11,6 @@ #include <linux/init.h> #include <linux/pci.h> #include <linux/pci_ids.h> -#include <linux/slab.h> #include <linux/edac.h> #include <linux/io.h> #include "edac_core.h" diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c index 7785d8ffa40..ee9753cf362 100644 --- a/drivers/edac/i5100_edac.c +++ b/drivers/edac/i5100_edac.c @@ -19,7 +19,6 @@ #include <linux/init.h> #include <linux/pci.h> #include <linux/pci_ids.h> -#include <linux/slab.h> #include <linux/edac.h> #include <linux/delay.h> #include <linux/mmzone.h> diff --git a/drivers/edac/i82443bxgx_edac.c b/drivers/edac/i82443bxgx_edac.c index 577760a82a0..7f3884fcbd4 100644 --- a/drivers/edac/i82443bxgx_edac.c +++ b/drivers/edac/i82443bxgx_edac.c @@ -27,7 +27,6 @@ #include <linux/pci.h> #include <linux/pci_ids.h> -#include <linux/slab.h> #include <linux/edac.h> #include "edac_core.h" diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c index c0088ba9672..b8a95cf5071 100644 --- a/drivers/edac/i82860_edac.c +++ b/drivers/edac/i82860_edac.c @@ -13,7 +13,6 @@ #include <linux/init.h> #include <linux/pci.h> #include <linux/pci_ids.h> -#include <linux/slab.h> #include <linux/edac.h> #include "edac_core.h" diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c index b2d83b95033..b2fd1e89914 100644 --- a/drivers/edac/i82875p_edac.c +++ b/drivers/edac/i82875p_edac.c @@ -17,7 +17,6 @@ #include <linux/init.h> #include <linux/pci.h> #include <linux/pci_ids.h> -#include <linux/slab.h> #include <linux/edac.h> #include "edac_core.h" diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c index 2eed3ea2cf6..3218819b728 100644 --- a/drivers/edac/i82975x_edac.c +++ b/drivers/edac/i82975x_edac.c @@ -13,7 +13,6 @@ #include <linux/init.h> #include <linux/pci.h> #include <linux/pci_ids.h> -#include <linux/slab.h> #include <linux/edac.h> #include "edac_core.h" diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index ecd5928d711..4471647b480 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -11,13 +11,13 @@ */ #include <linux/module.h> #include <linux/init.h> -#include <linux/slab.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> @@ -239,16 +239,15 @@ static int __devinit mpc85xx_pci_err_probe(struct of_device *op, /* we only need the error registers */ r.start += 0xe00; - if (!devm_request_mem_region(&op->dev, r.start, - r.end - r.start + 1, pdata->name)) { + if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r), + pdata->name)) { printk(KERN_ERR "%s: Error while requesting mem region\n", __func__); res = -EBUSY; goto err; } - pdata->pci_vbase = devm_ioremap(&op->dev, r.start, - r.end - r.start + 1); + pdata->pci_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r)); if (!pdata->pci_vbase) { printk(KERN_ERR "%s: Unable to setup PCI err regs\n", __func__); res = -ENOMEM; @@ -668,15 +667,125 @@ static struct of_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; + } + } +} + 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; u32 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) @@ -692,6 +801,15 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci) } 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 = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ADDRESS); pfn = err_addr >> PAGE_SHIFT; @@ -701,14 +819,35 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci) break; } - mpc85xx_mc_printk(mci, KERN_ERR, "Capture Data High: %#8.8x\n", - in_be32(pdata->mc_vbase + - MPC85XX_MC_CAPTURE_DATA_HI)); - mpc85xx_mc_printk(mci, KERN_ERR, "Capture Data Low: %#8.8x\n", - in_be32(pdata->mc_vbase + - MPC85XX_MC_CAPTURE_DATA_LO)); - mpc85xx_mc_printk(mci, KERN_ERR, "syndrome: %#8.8x\n", syndrome); - mpc85xx_mc_printk(mci, KERN_ERR, "err addr: %#8.8x\n", err_addr); + 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.8x\n", err_addr); mpc85xx_mc_printk(mci, KERN_ERR, "PFN: %#8.8x\n", pfn); /* we are out of range */ diff --git a/drivers/edac/mpc85xx_edac.h b/drivers/edac/mpc85xx_edac.h index 52432ee7c4b..cb24df83946 100644 --- a/drivers/edac/mpc85xx_edac.h +++ b/drivers/edac/mpc85xx_edac.h @@ -48,6 +48,9 @@ #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 diff --git a/drivers/edac/mv64x60_edac.c b/drivers/edac/mv64x60_edac.c index a6b9fec13a7..7e5ff367705 100644 --- a/drivers/edac/mv64x60_edac.c +++ b/drivers/edac/mv64x60_edac.c @@ -12,10 +12,10 @@ #include <linux/module.h> #include <linux/init.h> -#include <linux/slab.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/edac.h> +#include <linux/gfp.h> #include "edac_core.h" #include "edac_module.h" diff --git a/drivers/edac/pasemi_edac.c b/drivers/edac/pasemi_edac.c index 8e6b91bd2e9..7f71ee43674 100644 --- a/drivers/edac/pasemi_edac.c +++ b/drivers/edac/pasemi_edac.c @@ -25,7 +25,6 @@ #include <linux/init.h> #include <linux/pci.h> #include <linux/pci_ids.h> -#include <linux/slab.h> #include <linux/edac.h> #include "edac_core.h" diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c index 9900675e959..d55f8e9de78 100644 --- a/drivers/edac/r82600_edac.c +++ b/drivers/edac/r82600_edac.c @@ -19,7 +19,6 @@ #include <linux/init.h> #include <linux/pci.h> #include <linux/pci_ids.h> -#include <linux/slab.h> #include <linux/edac.h> #include "edac_core.h" diff --git a/drivers/edac/x38_edac.c b/drivers/edac/x38_edac.c index d4ec6059317..b6f47de152f 100644 --- a/drivers/edac/x38_edac.c +++ b/drivers/edac/x38_edac.c @@ -13,7 +13,6 @@ #include <linux/init.h> #include <linux/pci.h> #include <linux/pci_ids.h> -#include <linux/slab.h> #include <linux/edac.h> #include "edac_core.h" |