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