linux/drivers/edac/mv64x60_edac.c
<<
>>
Prefs
   1/*
   2 * Marvell MV64x60 Memory Controller kernel module for PPC platforms
   3 *
   4 * Author: Dave Jiang <djiang@mvista.com>
   5 *
   6 * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under
   7 * the terms of the GNU General Public License version 2. This program
   8 * is licensed "as is" without any warranty of any kind, whether express
   9 * or implied.
  10 *
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/init.h>
  15#include <linux/interrupt.h>
  16#include <linux/io.h>
  17#include <linux/edac.h>
  18#include <linux/gfp.h>
  19
  20#include "edac_core.h"
  21#include "edac_module.h"
  22#include "mv64x60_edac.h"
  23
  24static const char *mv64x60_ctl_name = "MV64x60";
  25static int edac_dev_idx;
  26static int edac_pci_idx;
  27static int edac_mc_idx;
  28
  29/*********************** PCI err device **********************************/
  30#ifdef CONFIG_PCI
  31static void mv64x60_pci_check(struct edac_pci_ctl_info *pci)
  32{
  33        struct mv64x60_pci_pdata *pdata = pci->pvt_info;
  34        u32 cause;
  35
  36        cause = in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_CAUSE);
  37        if (!cause)
  38                return;
  39
  40        printk(KERN_ERR "Error in PCI %d Interface\n", pdata->pci_hose);
  41        printk(KERN_ERR "Cause register: 0x%08x\n", cause);
  42        printk(KERN_ERR "Address Low: 0x%08x\n",
  43               in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_ADDR_LO));
  44        printk(KERN_ERR "Address High: 0x%08x\n",
  45               in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_ADDR_HI));
  46        printk(KERN_ERR "Attribute: 0x%08x\n",
  47               in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_ATTR));
  48        printk(KERN_ERR "Command: 0x%08x\n",
  49               in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_CMD));
  50        out_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_CAUSE, ~cause);
  51
  52        if (cause & MV64X60_PCI_PE_MASK)
  53                edac_pci_handle_pe(pci, pci->ctl_name);
  54
  55        if (!(cause & MV64X60_PCI_PE_MASK))
  56                edac_pci_handle_npe(pci, pci->ctl_name);
  57}
  58
  59static irqreturn_t mv64x60_pci_isr(int irq, void *dev_id)
  60{
  61        struct edac_pci_ctl_info *pci = dev_id;
  62        struct mv64x60_pci_pdata *pdata = pci->pvt_info;
  63        u32 val;
  64
  65        val = in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_CAUSE);
  66        if (!val)
  67                return IRQ_NONE;
  68
  69        mv64x60_pci_check(pci);
  70
  71        return IRQ_HANDLED;
  72}
  73
  74/*
  75 * Bit 0 of MV64x60_PCIx_ERR_MASK does not exist on the 64360 and because of
  76 * errata FEr-#11 and FEr-##16 for the 64460, it should be 0 on that chip as
  77 * well.  IOW, don't set bit 0.
  78 */
  79
  80/* Erratum FEr PCI-#16: clear bit 0 of PCI SERRn Mask reg. */
  81static int __init mv64x60_pci_fixup(struct platform_device *pdev)
  82{
  83        struct resource *r;
  84        void __iomem *pci_serr;
  85
  86        r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
  87        if (!r) {
  88                printk(KERN_ERR "%s: Unable to get resource for "
  89                       "PCI err regs\n", __func__);
  90                return -ENOENT;
  91        }
  92
  93        pci_serr = ioremap(r->start, resource_size(r));
  94        if (!pci_serr)
  95                return -ENOMEM;
  96
  97        out_le32(pci_serr, in_le32(pci_serr) & ~0x1);
  98        iounmap(pci_serr);
  99
 100        return 0;
 101}
 102
 103static int mv64x60_pci_err_probe(struct platform_device *pdev)
 104{
 105        struct edac_pci_ctl_info *pci;
 106        struct mv64x60_pci_pdata *pdata;
 107        struct resource *r;
 108        int res = 0;
 109
 110        if (!devres_open_group(&pdev->dev, mv64x60_pci_err_probe, GFP_KERNEL))
 111                return -ENOMEM;
 112
 113        pci = edac_pci_alloc_ctl_info(sizeof(*pdata), "mv64x60_pci_err");
 114        if (!pci)
 115                return -ENOMEM;
 116
 117        pdata = pci->pvt_info;
 118
 119        pdata->pci_hose = pdev->id;
 120        pdata->name = "mpc85xx_pci_err";
 121        platform_set_drvdata(pdev, pci);
 122        pci->dev = &pdev->dev;
 123        pci->dev_name = dev_name(&pdev->dev);
 124        pci->mod_name = EDAC_MOD_STR;
 125        pci->ctl_name = pdata->name;
 126
 127        if (edac_op_state == EDAC_OPSTATE_POLL)
 128                pci->edac_check = mv64x60_pci_check;
 129
 130        pdata->edac_idx = edac_pci_idx++;
 131
 132        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 133        if (!r) {
 134                printk(KERN_ERR "%s: Unable to get resource for "
 135                       "PCI err regs\n", __func__);
 136                res = -ENOENT;
 137                goto err;
 138        }
 139
 140        if (!devm_request_mem_region(&pdev->dev,
 141                                     r->start,
 142                                     resource_size(r),
 143                                     pdata->name)) {
 144                printk(KERN_ERR "%s: Error while requesting mem region\n",
 145                       __func__);
 146                res = -EBUSY;
 147                goto err;
 148        }
 149
 150        pdata->pci_vbase = devm_ioremap(&pdev->dev,
 151                                        r->start,
 152                                        resource_size(r));
 153        if (!pdata->pci_vbase) {
 154                printk(KERN_ERR "%s: Unable to setup PCI err regs\n", __func__);
 155                res = -ENOMEM;
 156                goto err;
 157        }
 158
 159        res = mv64x60_pci_fixup(pdev);
 160        if (res < 0) {
 161                printk(KERN_ERR "%s: PCI fixup failed\n", __func__);
 162                goto err;
 163        }
 164
 165        out_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_CAUSE, 0);
 166        out_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_MASK, 0);
 167        out_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_MASK,
 168                 MV64X60_PCIx_ERR_MASK_VAL);
 169
 170        if (edac_pci_add_device(pci, pdata->edac_idx) > 0) {
 171                edac_dbg(3, "failed edac_pci_add_device()\n");
 172                goto err;
 173        }
 174
 175        if (edac_op_state == EDAC_OPSTATE_INT) {
 176                pdata->irq = platform_get_irq(pdev, 0);
 177                res = devm_request_irq(&pdev->dev,
 178                                       pdata->irq,
 179                                       mv64x60_pci_isr,
 180                                       0,
 181                                       "[EDAC] PCI err",
 182                                       pci);
 183                if (res < 0) {
 184                        printk(KERN_ERR "%s: Unable to request irq %d for "
 185                               "MV64x60 PCI ERR\n", __func__, pdata->irq);
 186                        res = -ENODEV;
 187                        goto err2;
 188                }
 189                printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for PCI Err\n",
 190                       pdata->irq);
 191        }
 192
 193        devres_remove_group(&pdev->dev, mv64x60_pci_err_probe);
 194
 195        /* get this far and it's successful */
 196        edac_dbg(3, "success\n");
 197
 198        return 0;
 199
 200err2:
 201        edac_pci_del_device(&pdev->dev);
 202err:
 203        edac_pci_free_ctl_info(pci);
 204        devres_release_group(&pdev->dev, mv64x60_pci_err_probe);
 205        return res;
 206}
 207
 208static int mv64x60_pci_err_remove(struct platform_device *pdev)
 209{
 210        struct edac_pci_ctl_info *pci = platform_get_drvdata(pdev);
 211
 212        edac_dbg(0, "\n");
 213
 214        edac_pci_del_device(&pdev->dev);
 215
 216        edac_pci_free_ctl_info(pci);
 217
 218        return 0;
 219}
 220
 221static struct platform_driver mv64x60_pci_err_driver = {
 222        .probe = mv64x60_pci_err_probe,
 223        .remove = mv64x60_pci_err_remove,
 224        .driver = {
 225                   .name = "mv64x60_pci_err",
 226        }
 227};
 228
 229#endif /* CONFIG_PCI */
 230
 231/*********************** SRAM err device **********************************/
 232static void mv64x60_sram_check(struct edac_device_ctl_info *edac_dev)
 233{
 234        struct mv64x60_sram_pdata *pdata = edac_dev->pvt_info;
 235        u32 cause;
 236
 237        cause = in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_CAUSE);
 238        if (!cause)
 239                return;
 240
 241        printk(KERN_ERR "Error in internal SRAM\n");
 242        printk(KERN_ERR "Cause register: 0x%08x\n", cause);
 243        printk(KERN_ERR "Address Low: 0x%08x\n",
 244               in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_ADDR_LO));
 245        printk(KERN_ERR "Address High: 0x%08x\n",
 246               in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_ADDR_HI));
 247        printk(KERN_ERR "Data Low: 0x%08x\n",
 248               in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_DATA_LO));
 249        printk(KERN_ERR "Data High: 0x%08x\n",
 250               in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_DATA_HI));
 251        printk(KERN_ERR "Parity: 0x%08x\n",
 252               in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_PARITY));
 253        out_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_CAUSE, 0);
 254
 255        edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name);
 256}
 257
 258static irqreturn_t mv64x60_sram_isr(int irq, void *dev_id)
 259{
 260        struct edac_device_ctl_info *edac_dev = dev_id;
 261        struct mv64x60_sram_pdata *pdata = edac_dev->pvt_info;
 262        u32 cause;
 263
 264        cause = in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_CAUSE);
 265        if (!cause)
 266                return IRQ_NONE;
 267
 268        mv64x60_sram_check(edac_dev);
 269
 270        return IRQ_HANDLED;
 271}
 272
 273static int mv64x60_sram_err_probe(struct platform_device *pdev)
 274{
 275        struct edac_device_ctl_info *edac_dev;
 276        struct mv64x60_sram_pdata *pdata;
 277        struct resource *r;
 278        int res = 0;
 279
 280        if (!devres_open_group(&pdev->dev, mv64x60_sram_err_probe, GFP_KERNEL))
 281                return -ENOMEM;
 282
 283        edac_dev = edac_device_alloc_ctl_info(sizeof(*pdata),
 284                                              "sram", 1, NULL, 0, 0, NULL, 0,
 285                                              edac_dev_idx);
 286        if (!edac_dev) {
 287                devres_release_group(&pdev->dev, mv64x60_sram_err_probe);
 288                return -ENOMEM;
 289        }
 290
 291        pdata = edac_dev->pvt_info;
 292        pdata->name = "mv64x60_sram_err";
 293        edac_dev->dev = &pdev->dev;
 294        platform_set_drvdata(pdev, edac_dev);
 295        edac_dev->dev_name = dev_name(&pdev->dev);
 296
 297        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 298        if (!r) {
 299                printk(KERN_ERR "%s: Unable to get resource for "
 300                       "SRAM err regs\n", __func__);
 301                res = -ENOENT;
 302                goto err;
 303        }
 304
 305        if (!devm_request_mem_region(&pdev->dev,
 306                                     r->start,
 307                                     resource_size(r),
 308                                     pdata->name)) {
 309                printk(KERN_ERR "%s: Error while request mem region\n",
 310                       __func__);
 311                res = -EBUSY;
 312                goto err;
 313        }
 314
 315        pdata->sram_vbase = devm_ioremap(&pdev->dev,
 316                                         r->start,
 317                                         resource_size(r));
 318        if (!pdata->sram_vbase) {
 319                printk(KERN_ERR "%s: Unable to setup SRAM err regs\n",
 320                       __func__);
 321                res = -ENOMEM;
 322                goto err;
 323        }
 324
 325        /* setup SRAM err registers */
 326        out_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_CAUSE, 0);
 327
 328        edac_dev->mod_name = EDAC_MOD_STR;
 329        edac_dev->ctl_name = pdata->name;
 330
 331        if (edac_op_state == EDAC_OPSTATE_POLL)
 332                edac_dev->edac_check = mv64x60_sram_check;
 333
 334        pdata->edac_idx = edac_dev_idx++;
 335
 336        if (edac_device_add_device(edac_dev) > 0) {
 337                edac_dbg(3, "failed edac_device_add_device()\n");
 338                goto err;
 339        }
 340
 341        if (edac_op_state == EDAC_OPSTATE_INT) {
 342                pdata->irq = platform_get_irq(pdev, 0);
 343                res = devm_request_irq(&pdev->dev,
 344                                       pdata->irq,
 345                                       mv64x60_sram_isr,
 346                                       0,
 347                                       "[EDAC] SRAM err",
 348                                       edac_dev);
 349                if (res < 0) {
 350                        printk(KERN_ERR
 351                               "%s: Unable to request irq %d for "
 352                               "MV64x60 SRAM ERR\n", __func__, pdata->irq);
 353                        res = -ENODEV;
 354                        goto err2;
 355                }
 356
 357                printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for SRAM Err\n",
 358                       pdata->irq);
 359        }
 360
 361        devres_remove_group(&pdev->dev, mv64x60_sram_err_probe);
 362
 363        /* get this far and it's successful */
 364        edac_dbg(3, "success\n");
 365
 366        return 0;
 367
 368err2:
 369        edac_device_del_device(&pdev->dev);
 370err:
 371        devres_release_group(&pdev->dev, mv64x60_sram_err_probe);
 372        edac_device_free_ctl_info(edac_dev);
 373        return res;
 374}
 375
 376static int mv64x60_sram_err_remove(struct platform_device *pdev)
 377{
 378        struct edac_device_ctl_info *edac_dev = platform_get_drvdata(pdev);
 379
 380        edac_dbg(0, "\n");
 381
 382        edac_device_del_device(&pdev->dev);
 383        edac_device_free_ctl_info(edac_dev);
 384
 385        return 0;
 386}
 387
 388static struct platform_driver mv64x60_sram_err_driver = {
 389        .probe = mv64x60_sram_err_probe,
 390        .remove = mv64x60_sram_err_remove,
 391        .driver = {
 392                   .name = "mv64x60_sram_err",
 393        }
 394};
 395
 396/*********************** CPU err device **********************************/
 397static void mv64x60_cpu_check(struct edac_device_ctl_info *edac_dev)
 398{
 399        struct mv64x60_cpu_pdata *pdata = edac_dev->pvt_info;
 400        u32 cause;
 401
 402        cause = in_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_CAUSE) &
 403            MV64x60_CPU_CAUSE_MASK;
 404        if (!cause)
 405                return;
 406
 407        printk(KERN_ERR "Error on CPU interface\n");
 408        printk(KERN_ERR "Cause register: 0x%08x\n", cause);
 409        printk(KERN_ERR "Address Low: 0x%08x\n",
 410               in_le32(pdata->cpu_vbase[0] + MV64x60_CPU_ERR_ADDR_LO));
 411        printk(KERN_ERR "Address High: 0x%08x\n",
 412               in_le32(pdata->cpu_vbase[0] + MV64x60_CPU_ERR_ADDR_HI));
 413        printk(KERN_ERR "Data Low: 0x%08x\n",
 414               in_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_DATA_LO));
 415        printk(KERN_ERR "Data High: 0x%08x\n",
 416               in_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_DATA_HI));
 417        printk(KERN_ERR "Parity: 0x%08x\n",
 418               in_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_PARITY));
 419        out_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_CAUSE, 0);
 420
 421        edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name);
 422}
 423
 424static irqreturn_t mv64x60_cpu_isr(int irq, void *dev_id)
 425{
 426        struct edac_device_ctl_info *edac_dev = dev_id;
 427        struct mv64x60_cpu_pdata *pdata = edac_dev->pvt_info;
 428        u32 cause;
 429
 430        cause = in_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_CAUSE) &
 431            MV64x60_CPU_CAUSE_MASK;
 432        if (!cause)
 433                return IRQ_NONE;
 434
 435        mv64x60_cpu_check(edac_dev);
 436
 437        return IRQ_HANDLED;
 438}
 439
 440static int mv64x60_cpu_err_probe(struct platform_device *pdev)
 441{
 442        struct edac_device_ctl_info *edac_dev;
 443        struct resource *r;
 444        struct mv64x60_cpu_pdata *pdata;
 445        int res = 0;
 446
 447        if (!devres_open_group(&pdev->dev, mv64x60_cpu_err_probe, GFP_KERNEL))
 448                return -ENOMEM;
 449
 450        edac_dev = edac_device_alloc_ctl_info(sizeof(*pdata),
 451                                              "cpu", 1, NULL, 0, 0, NULL, 0,
 452                                              edac_dev_idx);
 453        if (!edac_dev) {
 454                devres_release_group(&pdev->dev, mv64x60_cpu_err_probe);
 455                return -ENOMEM;
 456        }
 457
 458        pdata = edac_dev->pvt_info;
 459        pdata->name = "mv64x60_cpu_err";
 460        edac_dev->dev = &pdev->dev;
 461        platform_set_drvdata(pdev, edac_dev);
 462        edac_dev->dev_name = dev_name(&pdev->dev);
 463
 464        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 465        if (!r) {
 466                printk(KERN_ERR "%s: Unable to get resource for "
 467                       "CPU err regs\n", __func__);
 468                res = -ENOENT;
 469                goto err;
 470        }
 471
 472        if (!devm_request_mem_region(&pdev->dev,
 473                                     r->start,
 474                                     resource_size(r),
 475                                     pdata->name)) {
 476                printk(KERN_ERR "%s: Error while requesting mem region\n",
 477                       __func__);
 478                res = -EBUSY;
 479                goto err;
 480        }
 481
 482        pdata->cpu_vbase[0] = devm_ioremap(&pdev->dev,
 483                                           r->start,
 484                                           resource_size(r));
 485        if (!pdata->cpu_vbase[0]) {
 486                printk(KERN_ERR "%s: Unable to setup CPU err regs\n", __func__);
 487                res = -ENOMEM;
 488                goto err;
 489        }
 490
 491        r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 492        if (!r) {
 493                printk(KERN_ERR "%s: Unable to get resource for "
 494                       "CPU err regs\n", __func__);
 495                res = -ENOENT;
 496                goto err;
 497        }
 498
 499        if (!devm_request_mem_region(&pdev->dev,
 500                                     r->start,
 501                                     resource_size(r),
 502                                     pdata->name)) {
 503                printk(KERN_ERR "%s: Error while requesting mem region\n",
 504                       __func__);
 505                res = -EBUSY;
 506                goto err;
 507        }
 508
 509        pdata->cpu_vbase[1] = devm_ioremap(&pdev->dev,
 510                                           r->start,
 511                                           resource_size(r));
 512        if (!pdata->cpu_vbase[1]) {
 513                printk(KERN_ERR "%s: Unable to setup CPU err regs\n", __func__);
 514                res = -ENOMEM;
 515                goto err;
 516        }
 517
 518        /* setup CPU err registers */
 519        out_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_CAUSE, 0);
 520        out_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_MASK, 0);
 521        out_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_MASK, 0x000000ff);
 522
 523        edac_dev->mod_name = EDAC_MOD_STR;
 524        edac_dev->ctl_name = pdata->name;
 525        if (edac_op_state == EDAC_OPSTATE_POLL)
 526                edac_dev->edac_check = mv64x60_cpu_check;
 527
 528        pdata->edac_idx = edac_dev_idx++;
 529
 530        if (edac_device_add_device(edac_dev) > 0) {
 531                edac_dbg(3, "failed edac_device_add_device()\n");
 532                goto err;
 533        }
 534
 535        if (edac_op_state == EDAC_OPSTATE_INT) {
 536                pdata->irq = platform_get_irq(pdev, 0);
 537                res = devm_request_irq(&pdev->dev,
 538                                       pdata->irq,
 539                                       mv64x60_cpu_isr,
 540                                       0,
 541                                       "[EDAC] CPU err",
 542                                       edac_dev);
 543                if (res < 0) {
 544                        printk(KERN_ERR
 545                               "%s: Unable to request irq %d for MV64x60 "
 546                               "CPU ERR\n", __func__, pdata->irq);
 547                        res = -ENODEV;
 548                        goto err2;
 549                }
 550
 551                printk(KERN_INFO EDAC_MOD_STR
 552                       " acquired irq %d for CPU Err\n", pdata->irq);
 553        }
 554
 555        devres_remove_group(&pdev->dev, mv64x60_cpu_err_probe);
 556
 557        /* get this far and it's successful */
 558        edac_dbg(3, "success\n");
 559
 560        return 0;
 561
 562err2:
 563        edac_device_del_device(&pdev->dev);
 564err:
 565        devres_release_group(&pdev->dev, mv64x60_cpu_err_probe);
 566        edac_device_free_ctl_info(edac_dev);
 567        return res;
 568}
 569
 570static int mv64x60_cpu_err_remove(struct platform_device *pdev)
 571{
 572        struct edac_device_ctl_info *edac_dev = platform_get_drvdata(pdev);
 573
 574        edac_dbg(0, "\n");
 575
 576        edac_device_del_device(&pdev->dev);
 577        edac_device_free_ctl_info(edac_dev);
 578        return 0;
 579}
 580
 581static struct platform_driver mv64x60_cpu_err_driver = {
 582        .probe = mv64x60_cpu_err_probe,
 583        .remove = mv64x60_cpu_err_remove,
 584        .driver = {
 585                   .name = "mv64x60_cpu_err",
 586        }
 587};
 588
 589/*********************** DRAM err device **********************************/
 590
 591static void mv64x60_mc_check(struct mem_ctl_info *mci)
 592{
 593        struct mv64x60_mc_pdata *pdata = mci->pvt_info;
 594        u32 reg;
 595        u32 err_addr;
 596        u32 sdram_ecc;
 597        u32 comp_ecc;
 598        u32 syndrome;
 599
 600        reg = in_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR);
 601        if (!reg)
 602                return;
 603
 604        err_addr = reg & ~0x3;
 605        sdram_ecc = in_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_RCVD);
 606        comp_ecc = in_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_CALC);
 607        syndrome = sdram_ecc ^ comp_ecc;
 608
 609        /* first bit clear in ECC Err Reg, 1 bit error, correctable by HW */
 610        if (!(reg & 0x1))
 611                edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
 612                                     err_addr >> PAGE_SHIFT,
 613                                     err_addr & PAGE_MASK, syndrome,
 614                                     0, 0, -1,
 615                                     mci->ctl_name, "");
 616        else    /* 2 bit error, UE */
 617                edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
 618                                     err_addr >> PAGE_SHIFT,
 619                                     err_addr & PAGE_MASK, 0,
 620                                     0, 0, -1,
 621                                     mci->ctl_name, "");
 622
 623        /* clear the error */
 624        out_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR, 0);
 625}
 626
 627static irqreturn_t mv64x60_mc_isr(int irq, void *dev_id)
 628{
 629        struct mem_ctl_info *mci = dev_id;
 630        struct mv64x60_mc_pdata *pdata = mci->pvt_info;
 631        u32 reg;
 632
 633        reg = in_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR);
 634        if (!reg)
 635                return IRQ_NONE;
 636
 637        /* writing 0's to the ECC err addr in check function clears irq */
 638        mv64x60_mc_check(mci);
 639
 640        return IRQ_HANDLED;
 641}
 642
 643static void get_total_mem(struct mv64x60_mc_pdata *pdata)
 644{
 645        struct device_node *np = NULL;
 646        const unsigned int *reg;
 647
 648        np = of_find_node_by_type(NULL, "memory");
 649        if (!np)
 650                return;
 651
 652        reg = of_get_property(np, "reg", NULL);
 653
 654        pdata->total_mem = reg[1];
 655}
 656
 657static void mv64x60_init_csrows(struct mem_ctl_info *mci,
 658                                struct mv64x60_mc_pdata *pdata)
 659{
 660        struct csrow_info *csrow;
 661        struct dimm_info *dimm;
 662
 663        u32 devtype;
 664        u32 ctl;
 665
 666        get_total_mem(pdata);
 667
 668        ctl = in_le32(pdata->mc_vbase + MV64X60_SDRAM_CONFIG);
 669
 670        csrow = mci->csrows[0];
 671        dimm = csrow->channels[0]->dimm;
 672
 673        dimm->nr_pages = pdata->total_mem >> PAGE_SHIFT;
 674        dimm->grain = 8;
 675
 676        dimm->mtype = (ctl & MV64X60_SDRAM_REGISTERED) ? MEM_RDDR : MEM_DDR;
 677
 678        devtype = (ctl >> 20) & 0x3;
 679        switch (devtype) {
 680        case 0x0:
 681                dimm->dtype = DEV_X32;
 682                break;
 683        case 0x2:               /* could be X8 too, but no way to tell */
 684                dimm->dtype = DEV_X16;
 685                break;
 686        case 0x3:
 687                dimm->dtype = DEV_X4;
 688                break;
 689        default:
 690                dimm->dtype = DEV_UNKNOWN;
 691                break;
 692        }
 693
 694        dimm->edac_mode = EDAC_SECDED;
 695}
 696
 697static int mv64x60_mc_err_probe(struct platform_device *pdev)
 698{
 699        struct mem_ctl_info *mci;
 700        struct edac_mc_layer layers[2];
 701        struct mv64x60_mc_pdata *pdata;
 702        struct resource *r;
 703        u32 ctl;
 704        int res = 0;
 705
 706        if (!devres_open_group(&pdev->dev, mv64x60_mc_err_probe, GFP_KERNEL))
 707                return -ENOMEM;
 708
 709        layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
 710        layers[0].size = 1;
 711        layers[0].is_virt_csrow = true;
 712        layers[1].type = EDAC_MC_LAYER_CHANNEL;
 713        layers[1].size = 1;
 714        layers[1].is_virt_csrow = false;
 715        mci = edac_mc_alloc(edac_mc_idx, ARRAY_SIZE(layers), layers,
 716                            sizeof(struct mv64x60_mc_pdata));
 717        if (!mci) {
 718                printk(KERN_ERR "%s: No memory for CPU err\n", __func__);
 719                devres_release_group(&pdev->dev, mv64x60_mc_err_probe);
 720                return -ENOMEM;
 721        }
 722
 723        pdata = mci->pvt_info;
 724        mci->pdev = &pdev->dev;
 725        platform_set_drvdata(pdev, mci);
 726        pdata->name = "mv64x60_mc_err";
 727        mci->dev_name = dev_name(&pdev->dev);
 728        pdata->edac_idx = edac_mc_idx++;
 729
 730        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 731        if (!r) {
 732                printk(KERN_ERR "%s: Unable to get resource for "
 733                       "MC err regs\n", __func__);
 734                res = -ENOENT;
 735                goto err;
 736        }
 737
 738        if (!devm_request_mem_region(&pdev->dev,
 739                                     r->start,
 740                                     resource_size(r),
 741                                     pdata->name)) {
 742                printk(KERN_ERR "%s: Error while requesting mem region\n",
 743                       __func__);
 744                res = -EBUSY;
 745                goto err;
 746        }
 747
 748        pdata->mc_vbase = devm_ioremap(&pdev->dev,
 749                                       r->start,
 750                                       resource_size(r));
 751        if (!pdata->mc_vbase) {
 752                printk(KERN_ERR "%s: Unable to setup MC err regs\n", __func__);
 753                res = -ENOMEM;
 754                goto err;
 755        }
 756
 757        ctl = in_le32(pdata->mc_vbase + MV64X60_SDRAM_CONFIG);
 758        if (!(ctl & MV64X60_SDRAM_ECC)) {
 759                /* Non-ECC RAM? */
 760                printk(KERN_WARNING "%s: No ECC DIMMs discovered\n", __func__);
 761                res = -ENODEV;
 762                goto err2;
 763        }
 764
 765        edac_dbg(3, "init mci\n");
 766        mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR;
 767        mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
 768        mci->edac_cap = EDAC_FLAG_SECDED;
 769        mci->mod_name = EDAC_MOD_STR;
 770        mci->mod_ver = MV64x60_REVISION;
 771        mci->ctl_name = mv64x60_ctl_name;
 772
 773        if (edac_op_state == EDAC_OPSTATE_POLL)
 774                mci->edac_check = mv64x60_mc_check;
 775
 776        mci->ctl_page_to_phys = NULL;
 777
 778        mci->scrub_mode = SCRUB_SW_SRC;
 779
 780        mv64x60_init_csrows(mci, pdata);
 781
 782        /* setup MC registers */
 783        out_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR, 0);
 784        ctl = in_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_CNTL);
 785        ctl = (ctl & 0xff00ffff) | 0x10000;
 786        out_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_CNTL, ctl);
 787
 788        res = edac_mc_add_mc(mci);
 789        if (res) {
 790                edac_dbg(3, "failed edac_mc_add_mc()\n");
 791                goto err;
 792        }
 793
 794        if (edac_op_state == EDAC_OPSTATE_INT) {
 795                /* acquire interrupt that reports errors */
 796                pdata->irq = platform_get_irq(pdev, 0);
 797                res = devm_request_irq(&pdev->dev,
 798                                       pdata->irq,
 799                                       mv64x60_mc_isr,
 800                                       0,
 801                                       "[EDAC] MC err",
 802                                       mci);
 803                if (res < 0) {
 804                        printk(KERN_ERR "%s: Unable to request irq %d for "
 805                               "MV64x60 DRAM ERR\n", __func__, pdata->irq);
 806                        res = -ENODEV;
 807                        goto err2;
 808                }
 809
 810                printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for MC Err\n",
 811                       pdata->irq);
 812        }
 813
 814        /* get this far and it's successful */
 815        edac_dbg(3, "success\n");
 816
 817        return 0;
 818
 819err2:
 820        edac_mc_del_mc(&pdev->dev);
 821err:
 822        devres_release_group(&pdev->dev, mv64x60_mc_err_probe);
 823        edac_mc_free(mci);
 824        return res;
 825}
 826
 827static int mv64x60_mc_err_remove(struct platform_device *pdev)
 828{
 829        struct mem_ctl_info *mci = platform_get_drvdata(pdev);
 830
 831        edac_dbg(0, "\n");
 832
 833        edac_mc_del_mc(&pdev->dev);
 834        edac_mc_free(mci);
 835        return 0;
 836}
 837
 838static struct platform_driver mv64x60_mc_err_driver = {
 839        .probe = mv64x60_mc_err_probe,
 840        .remove = mv64x60_mc_err_remove,
 841        .driver = {
 842                   .name = "mv64x60_mc_err",
 843        }
 844};
 845
 846static struct platform_driver * const drivers[] = {
 847        &mv64x60_mc_err_driver,
 848        &mv64x60_cpu_err_driver,
 849        &mv64x60_sram_err_driver,
 850#ifdef CONFIG_PCI
 851        &mv64x60_pci_err_driver,
 852#endif
 853};
 854
 855static int __init mv64x60_edac_init(void)
 856{
 857        int ret = 0;
 858
 859        printk(KERN_INFO "Marvell MV64x60 EDAC driver " MV64x60_REVISION "\n");
 860        printk(KERN_INFO "\t(C) 2006-2007 MontaVista Software\n");
 861        /* make sure error reporting method is sane */
 862        switch (edac_op_state) {
 863        case EDAC_OPSTATE_POLL:
 864        case EDAC_OPSTATE_INT:
 865                break;
 866        default:
 867                edac_op_state = EDAC_OPSTATE_INT;
 868                break;
 869        }
 870
 871        return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
 872}
 873module_init(mv64x60_edac_init);
 874
 875static void __exit mv64x60_edac_exit(void)
 876{
 877        platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
 878}
 879module_exit(mv64x60_edac_exit);
 880
 881MODULE_LICENSE("GPL");
 882MODULE_AUTHOR("Montavista Software, Inc.");
 883module_param(edac_op_state, int, 0444);
 884MODULE_PARM_DESC(edac_op_state,
 885                 "EDAC Error Reporting state: 0=Poll, 2=Interrupt");
 886