include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / drivers / edac / mpc85xx_edac.c
index fd1726e..4471647 100644 (file)
  */
 #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>
-#include <asm/mpc85xx.h>
 #include "edac_module.h"
 #include "edac_core.h"
 #include "mpc85xx_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;
@@ -41,9 +43,9 @@ static u32 orig_pci_err_en;
 #endif
 
 static u32 orig_l2_err_disable;
-static u32 orig_hid1;
-
-const char *mpc85xx_ctl_name = "MPC85xx";
+#ifdef CONFIG_MPC85xx
+static u32 orig_hid1[2];
+#endif
 
 /************************ MC SYSFS parts ***********************************/
 
@@ -198,14 +200,15 @@ static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit mpc85xx_pci_err_probe(struct platform_device *pdev)
+static int __devinit mpc85xx_pci_err_probe(struct of_device *op,
+                                          const struct of_device_id *match)
 {
        struct edac_pci_ctl_info *pci;
        struct mpc85xx_pci_pdata *pdata;
-       struct resource *r;
+       struct resource r;
        int res = 0;
 
-       if (!devres_open_group(&pdev->dev, mpc85xx_pci_err_probe, GFP_KERNEL))
+       if (!devres_open_group(&op->dev, mpc85xx_pci_err_probe, GFP_KERNEL))
                return -ENOMEM;
 
        pci = edac_pci_alloc_ctl_info(sizeof(*pdata), "mpc85xx_pci_err");
@@ -215,34 +218,36 @@ static int __devinit mpc85xx_pci_err_probe(struct platform_device *pdev)
        pdata = pci->pvt_info;
        pdata->name = "mpc85xx_pci_err";
        pdata->irq = NO_IRQ;
-       platform_set_drvdata(pdev, pci);
-       pci->dev = &pdev->dev;
+       dev_set_drvdata(&op->dev, pci);
+       pci->dev = &op->dev;
        pci->mod_name = EDAC_MOD_STR;
        pci->ctl_name = pdata->name;
-       pci->dev_name = pdev->dev.bus_id;
+       pci->dev_name = dev_name(&op->dev);
 
        if (edac_op_state == EDAC_OPSTATE_POLL)
                pci->edac_check = mpc85xx_pci_check;
 
        pdata->edac_idx = edac_pci_idx++;
 
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!r) {
+       res = of_address_to_resource(op->node, 0, &r);
+       if (res) {
                printk(KERN_ERR "%s: Unable to get resource for "
                       "PCI err regs\n", __func__);
                goto err;
        }
 
-       if (!devm_request_mem_region(&pdev->dev, r->start,
-                                    r->end - r->start + 1, pdata->name)) {
+       /* we only need the error registers */
+       r.start += 0xe00;
+
+       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(&pdev->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;
@@ -269,14 +274,15 @@ static int __devinit mpc85xx_pci_err_probe(struct platform_device *pdev)
        }
 
        if (edac_op_state == EDAC_OPSTATE_INT) {
-               pdata->irq = platform_get_irq(pdev, 0);
-               res = devm_request_irq(&pdev->dev, pdata->irq,
+               pdata->irq = irq_of_parse_and_map(op->node, 0);
+               res = devm_request_irq(&op->dev, pdata->irq,
                                       mpc85xx_pci_isr, IRQF_DISABLED,
                                       "[EDAC] PCI err", pci);
                if (res < 0) {
                        printk(KERN_ERR
                               "%s: Unable to requiest irq %d for "
                               "MPC85xx PCI err\n", __func__, pdata->irq);
+                       irq_dispose_mapping(pdata->irq);
                        res = -ENODEV;
                        goto err2;
                }
@@ -285,23 +291,23 @@ static int __devinit mpc85xx_pci_err_probe(struct platform_device *pdev)
                       pdata->irq);
        }
 
-       devres_remove_group(&pdev->dev, mpc85xx_pci_err_probe);
+       devres_remove_group(&op->dev, mpc85xx_pci_err_probe);
        debugf3("%s(): success\n", __func__);
        printk(KERN_INFO EDAC_MOD_STR " PCI err registered\n");
 
        return 0;
 
 err2:
-       edac_pci_del_device(&pdev->dev);
+       edac_pci_del_device(&op->dev);
 err:
        edac_pci_free_ctl_info(pci);
-       devres_release_group(&pdev->dev, mpc85xx_pci_err_probe);
+       devres_release_group(&op->dev, mpc85xx_pci_err_probe);
        return res;
 }
 
-static int mpc85xx_pci_err_remove(struct platform_device *pdev)
+static int mpc85xx_pci_err_remove(struct of_device *op)
 {
-       struct edac_pci_ctl_info *pci = platform_get_drvdata(pdev);
+       struct edac_pci_ctl_info *pci = dev_get_drvdata(&op->dev);
        struct mpc85xx_pci_pdata *pdata = pci->pvt_info;
 
        debugf0("%s()\n", __func__);
@@ -321,12 +327,26 @@ static int mpc85xx_pci_err_remove(struct platform_device *pdev)
        return 0;
 }
 
-static struct platform_driver mpc85xx_pci_err_driver = {
+static struct of_device_id mpc85xx_pci_err_of_match[] = {
+       {
+        .compatible = "fsl,mpc8540-pcix",
+        },
+       {
+        .compatible = "fsl,mpc8540-pci",
+       },
+       {},
+};
+
+static struct of_platform_driver mpc85xx_pci_err_driver = {
+       .owner = THIS_MODULE,
+       .name = "mpc85xx_pci_err",
+       .match_table = mpc85xx_pci_err_of_match,
        .probe = mpc85xx_pci_err_probe,
        .remove = __devexit_p(mpc85xx_pci_err_remove),
        .driver = {
-               .name = "mpc85xx_pci_err",
-       }
+                  .name = "mpc85xx_pci_err",
+                  .owner = THIS_MODULE,
+                  },
 };
 
 #endif                         /* CONFIG_PCI */
@@ -613,24 +633,23 @@ static int mpc85xx_l2_err_remove(struct of_device *op)
 }
 
 static struct of_device_id mpc85xx_l2_err_of_match[] = {
-       {
-        .compatible = "fsl,8540-l2-cache-controller",
-        },
-       {
-        .compatible = "fsl,8541-l2-cache-controller",
-        },
-       {
-        .compatible = "fsl,8544-l2-cache-controller",
-        },
-       {
-        .compatible = "fsl,8548-l2-cache-controller",
-        },
-       {
-        .compatible = "fsl,8555-l2-cache-controller",
-        },
-       {
-        .compatible = "fsl,8568-l2-cache-controller",
-        },
+/* deprecate the fsl,85.. forms in the future, 2.6.30? */
+       { .compatible = "fsl,8540-l2-cache-controller", },
+       { .compatible = "fsl,8541-l2-cache-controller", },
+       { .compatible = "fsl,8544-l2-cache-controller", },
+       { .compatible = "fsl,8548-l2-cache-controller", },
+       { .compatible = "fsl,8555-l2-cache-controller", },
+       { .compatible = "fsl,8568-l2-cache-controller", },
+       { .compatible = "fsl,mpc8536-l2-cache-controller", },
+       { .compatible = "fsl,mpc8540-l2-cache-controller", },
+       { .compatible = "fsl,mpc8541-l2-cache-controller", },
+       { .compatible = "fsl,mpc8544-l2-cache-controller", },
+       { .compatible = "fsl,mpc8548-l2-cache-controller", },
+       { .compatible = "fsl,mpc8555-l2-cache-controller", },
+       { .compatible = "fsl,mpc8560-l2-cache-controller", },
+       { .compatible = "fsl,mpc8568-l2-cache-controller", },
+       { .compatible = "fsl,mpc8572-l2-cache-controller", },
+       { .compatible = "fsl,p2020-l2-cache-controller", },
        {},
 };
 
@@ -648,18 +667,128 @@ 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)
+       if (!err_detect)
                return;
 
        mpc85xx_mc_printk(mci, KERN_ERR, "Err Detect Register: %#8.8x\n",
@@ -672,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;
 
@@ -681,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 */
@@ -742,6 +901,9 @@ static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci)
                case DSC_SDTYPE_DDR2:
                        mtype = MEM_RDDR2;
                        break;
+               case DSC_SDTYPE_DDR3:
+                       mtype = MEM_RDDR3;
+                       break;
                default:
                        mtype = MEM_UNKNOWN;
                        break;
@@ -754,6 +916,9 @@ static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci)
                case DSC_SDTYPE_DDR2:
                        mtype = MEM_DDR2;
                        break;
+               case DSC_SDTYPE_DDR3:
+                       mtype = MEM_DDR3;
+                       break;
                default:
                        mtype = MEM_UNKNOWN;
                        break;
@@ -767,19 +932,20 @@ static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci)
                csrow = &mci->csrows[index];
                cs_bnds = in_be32(pdata->mc_vbase + MPC85XX_MC_CS_BNDS_0 +
                                  (index * MPC85XX_MC_CS_BNDS_OFS));
-               start = (cs_bnds & 0xfff0000) << 4;
-               end = ((cs_bnds & 0xfff) << 20);
-               if (start)
-                       start |= 0xfffff;
-               if (end)
-                       end |= 0xfffff;
+
+               start = (cs_bnds & 0xffff0000) >> 16;
+               end   = (cs_bnds & 0x0000ffff);
 
                if (start == end)
                        continue;       /* not populated */
 
-               csrow->first_page = start >> PAGE_SHIFT;
-               csrow->last_page = end >> PAGE_SHIFT;
-               csrow->nr_pages = csrow->last_page + 1 - csrow->first_page;
+               start <<= (24 - PAGE_SHIFT);
+               end   <<= (24 - PAGE_SHIFT);
+               end    |= (1 << (24 - PAGE_SHIFT)) - 1;
+
+               csrow->first_page = start;
+               csrow->last_page = end;
+               csrow->nr_pages = end + 1 - start;
                csrow->grain = 8;
                csrow->mtype = mtype;
                csrow->dtype = DEV_UNKNOWN;
@@ -865,10 +1031,6 @@ static int __devinit mpc85xx_mc_err_probe(struct of_device *op,
 
        mpc85xx_init_csrows(mci);
 
-#ifdef CONFIG_EDAC_DEBUG
-       edac_mc_register_mcidev_debug((struct attribute **)debug_attr);
-#endif
-
        /* store the original error disable bits */
        orig_ddr_err_disable =
            in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE);
@@ -896,7 +1058,8 @@ static int __devinit mpc85xx_mc_err_probe(struct of_device *op,
                /* register interrupts */
                pdata->irq = irq_of_parse_and_map(op->node, 0);
                res = devm_request_irq(&op->dev, pdata->irq,
-                                      mpc85xx_mc_isr, IRQF_DISABLED,
+                                      mpc85xx_mc_isr,
+                                       IRQF_DISABLED | IRQF_SHARED,
                                       "[EDAC] MC err", mci);
                if (res < 0) {
                        printk(KERN_ERR "%s: Unable to request irq %d for "
@@ -946,24 +1109,24 @@ static int mpc85xx_mc_err_remove(struct of_device *op)
 }
 
 static struct of_device_id mpc85xx_mc_err_of_match[] = {
-       {
-        .compatible = "fsl,8540-memory-controller",
-        },
-       {
-        .compatible = "fsl,8541-memory-controller",
-        },
-       {
-        .compatible = "fsl,8544-memory-controller",
-        },
-       {
-        .compatible = "fsl,8548-memory-controller",
-        },
-       {
-        .compatible = "fsl,8555-memory-controller",
-        },
-       {
-        .compatible = "fsl,8568-memory-controller",
-        },
+/* deprecate the fsl,85.. forms in the future, 2.6.30? */
+       { .compatible = "fsl,8540-memory-controller", },
+       { .compatible = "fsl,8541-memory-controller", },
+       { .compatible = "fsl,8544-memory-controller", },
+       { .compatible = "fsl,8548-memory-controller", },
+       { .compatible = "fsl,8555-memory-controller", },
+       { .compatible = "fsl,8568-memory-controller", },
+       { .compatible = "fsl,mpc8536-memory-controller", },
+       { .compatible = "fsl,mpc8540-memory-controller", },
+       { .compatible = "fsl,mpc8541-memory-controller", },
+       { .compatible = "fsl,mpc8544-memory-controller", },
+       { .compatible = "fsl,mpc8548-memory-controller", },
+       { .compatible = "fsl,mpc8555-memory-controller", },
+       { .compatible = "fsl,mpc8560-memory-controller", },
+       { .compatible = "fsl,mpc8568-memory-controller", },
+       { .compatible = "fsl,mpc8572-memory-controller", },
+       { .compatible = "fsl,mpc8349-memory-controller", },
+       { .compatible = "fsl,p2020-memory-controller", },
        {},
 };
 
@@ -979,6 +1142,14 @@ static struct of_platform_driver mpc85xx_mc_err_driver = {
                   },
 };
 
+#ifdef CONFIG_MPC85xx
+static void __init mpc85xx_mc_clear_rfxe(void *data)
+{
+       orig_hid1[smp_processor_id()] = mfspr(SPRN_HID1);
+       mtspr(SPRN_HID1, (orig_hid1[smp_processor_id()] & ~0x20000));
+}
+#endif
+
 static int __init mpc85xx_mc_init(void)
 {
        int res = 0;
@@ -1005,30 +1176,39 @@ static int __init mpc85xx_mc_init(void)
                printk(KERN_WARNING EDAC_MOD_STR "L2 fails to register\n");
 
 #ifdef CONFIG_PCI
-       res = platform_driver_register(&mpc85xx_pci_err_driver);
+       res = of_register_platform_driver(&mpc85xx_pci_err_driver);
        if (res)
                printk(KERN_WARNING EDAC_MOD_STR "PCI fails to register\n");
 #endif
 
+#ifdef CONFIG_MPC85xx
        /*
         * need to clear HID1[RFXE] to disable machine check int
         * so we can catch it
         */
-       if (edac_op_state == EDAC_OPSTATE_INT) {
-               orig_hid1 = mfspr(SPRN_HID1);
-               mtspr(SPRN_HID1, (orig_hid1 & ~0x20000));
-       }
+       if (edac_op_state == EDAC_OPSTATE_INT)
+               on_each_cpu(mpc85xx_mc_clear_rfxe, NULL, 0);
+#endif
 
        return 0;
 }
 
 module_init(mpc85xx_mc_init);
 
+#ifdef CONFIG_MPC85xx
+static void __exit mpc85xx_mc_restore_hid1(void *data)
+{
+       mtspr(SPRN_HID1, orig_hid1[smp_processor_id()]);
+}
+#endif
+
 static void __exit mpc85xx_mc_exit(void)
 {
-       mtspr(SPRN_HID1, orig_hid1);
+#ifdef CONFIG_MPC85xx
+       on_each_cpu(mpc85xx_mc_restore_hid1, NULL, 0);
+#endif
 #ifdef CONFIG_PCI
-       platform_driver_unregister(&mpc85xx_pci_err_driver);
+       of_unregister_platform_driver(&mpc85xx_pci_err_driver);
 #endif
        of_unregister_platform_driver(&mpc85xx_l2_err_driver);
        of_unregister_platform_driver(&mpc85xx_mc_err_driver);