14f4aeeabc061826376c9a72b4714d062664999eaDave Jiang/* 24f4aeeabc061826376c9a72b4714d062664999eaDave Jiang * Marvell MV64x60 Memory Controller kernel module for PPC platforms 34f4aeeabc061826376c9a72b4714d062664999eaDave Jiang * 44f4aeeabc061826376c9a72b4714d062664999eaDave Jiang * Author: Dave Jiang <djiang@mvista.com> 54f4aeeabc061826376c9a72b4714d062664999eaDave Jiang * 64f4aeeabc061826376c9a72b4714d062664999eaDave Jiang * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under 74f4aeeabc061826376c9a72b4714d062664999eaDave Jiang * the terms of the GNU General Public License version 2. This program 84f4aeeabc061826376c9a72b4714d062664999eaDave Jiang * is licensed "as is" without any warranty of any kind, whether express 94f4aeeabc061826376c9a72b4714d062664999eaDave Jiang * or implied. 104f4aeeabc061826376c9a72b4714d062664999eaDave Jiang * 114f4aeeabc061826376c9a72b4714d062664999eaDave Jiang */ 124f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 134f4aeeabc061826376c9a72b4714d062664999eaDave Jiang#include <linux/module.h> 144f4aeeabc061826376c9a72b4714d062664999eaDave Jiang#include <linux/init.h> 154f4aeeabc061826376c9a72b4714d062664999eaDave Jiang#include <linux/interrupt.h> 164f4aeeabc061826376c9a72b4714d062664999eaDave Jiang#include <linux/io.h> 174f4aeeabc061826376c9a72b4714d062664999eaDave Jiang#include <linux/edac.h> 185a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h> 194f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 204f4aeeabc061826376c9a72b4714d062664999eaDave Jiang#include "edac_core.h" 214f4aeeabc061826376c9a72b4714d062664999eaDave Jiang#include "edac_module.h" 224f4aeeabc061826376c9a72b4714d062664999eaDave Jiang#include "mv64x60_edac.h" 234f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 244f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic const char *mv64x60_ctl_name = "MV64x60"; 254f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic int edac_dev_idx; 264f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic int edac_pci_idx; 274f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic int edac_mc_idx; 284f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 294f4aeeabc061826376c9a72b4714d062664999eaDave Jiang/*********************** PCI err device **********************************/ 304f4aeeabc061826376c9a72b4714d062664999eaDave Jiang#ifdef CONFIG_PCI 314f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic void mv64x60_pci_check(struct edac_pci_ctl_info *pci) 324f4aeeabc061826376c9a72b4714d062664999eaDave Jiang{ 334f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct mv64x60_pci_pdata *pdata = pci->pvt_info; 344f4aeeabc061826376c9a72b4714d062664999eaDave Jiang u32 cause; 354f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 364f4aeeabc061826376c9a72b4714d062664999eaDave Jiang cause = in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_CAUSE); 374f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!cause) 384f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return; 394f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 404f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "Error in PCI %d Interface\n", pdata->pci_hose); 414f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "Cause register: 0x%08x\n", cause); 424f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "Address Low: 0x%08x\n", 434f4aeeabc061826376c9a72b4714d062664999eaDave Jiang in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_ADDR_LO)); 444f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "Address High: 0x%08x\n", 454f4aeeabc061826376c9a72b4714d062664999eaDave Jiang in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_ADDR_HI)); 464f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "Attribute: 0x%08x\n", 474f4aeeabc061826376c9a72b4714d062664999eaDave Jiang in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_ATTR)); 484f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "Command: 0x%08x\n", 494f4aeeabc061826376c9a72b4714d062664999eaDave Jiang in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_CMD)); 504f4aeeabc061826376c9a72b4714d062664999eaDave Jiang out_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_CAUSE, ~cause); 514f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 524f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (cause & MV64X60_PCI_PE_MASK) 534f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_pci_handle_pe(pci, pci->ctl_name); 544f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 554f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!(cause & MV64X60_PCI_PE_MASK)) 564f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_pci_handle_npe(pci, pci->ctl_name); 574f4aeeabc061826376c9a72b4714d062664999eaDave Jiang} 584f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 594f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic irqreturn_t mv64x60_pci_isr(int irq, void *dev_id) 604f4aeeabc061826376c9a72b4714d062664999eaDave Jiang{ 614f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct edac_pci_ctl_info *pci = dev_id; 624f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct mv64x60_pci_pdata *pdata = pci->pvt_info; 634f4aeeabc061826376c9a72b4714d062664999eaDave Jiang u32 val; 644f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 654f4aeeabc061826376c9a72b4714d062664999eaDave Jiang val = in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_CAUSE); 664f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!val) 674f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return IRQ_NONE; 684f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 694f4aeeabc061826376c9a72b4714d062664999eaDave Jiang mv64x60_pci_check(pci); 704f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 714f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return IRQ_HANDLED; 724f4aeeabc061826376c9a72b4714d062664999eaDave Jiang} 734f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 74fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang/* 75fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang * Bit 0 of MV64x60_PCIx_ERR_MASK does not exist on the 64360 and because of 76fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang * errata FEr-#11 and FEr-##16 for the 64460, it should be 0 on that chip as 77fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang * well. IOW, don't set bit 0. 78fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang */ 79fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang 80fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang/* Erratum FEr PCI-#16: clear bit 0 of PCI SERRn Mask reg. */ 81fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiangstatic int __init mv64x60_pci_fixup(struct platform_device *pdev) 82fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang{ 83fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang struct resource *r; 84fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang void __iomem *pci_serr; 85fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang 86fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang r = platform_get_resource(pdev, IORESOURCE_MEM, 1); 87fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang if (!r) { 88fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang printk(KERN_ERR "%s: Unable to get resource for " 89fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang "PCI err regs\n", __func__); 90fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang return -ENOENT; 91fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang } 92fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang 9330a61fff3a2b19506c66ea81fecb6a7747af3d47Julia Lawall pci_serr = ioremap(r->start, resource_size(r)); 94fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang if (!pci_serr) 95fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang return -ENOMEM; 96fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang 97fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang out_le32(pci_serr, in_le32(pci_serr) & ~0x1); 98fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang iounmap(pci_serr); 99fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang 100fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang return 0; 101fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang} 102fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang 1034f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic int __devinit mv64x60_pci_err_probe(struct platform_device *pdev) 1044f4aeeabc061826376c9a72b4714d062664999eaDave Jiang{ 1054f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct edac_pci_ctl_info *pci; 1064f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct mv64x60_pci_pdata *pdata; 1074f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct resource *r; 1084f4aeeabc061826376c9a72b4714d062664999eaDave Jiang int res = 0; 1094f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 1104f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!devres_open_group(&pdev->dev, mv64x60_pci_err_probe, GFP_KERNEL)) 1114f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return -ENOMEM; 1124f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 1134f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pci = edac_pci_alloc_ctl_info(sizeof(*pdata), "mv64x60_pci_err"); 1144f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!pci) 1154f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return -ENOMEM; 1164f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 1174f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata = pci->pvt_info; 1184f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 1194f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->pci_hose = pdev->id; 1204f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->name = "mpc85xx_pci_err"; 1214f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->irq = NO_IRQ; 1224f4aeeabc061826376c9a72b4714d062664999eaDave Jiang platform_set_drvdata(pdev, pci); 1234f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pci->dev = &pdev->dev; 124031d5518591006efd13a33a86909b9477b22917bKay Sievers pci->dev_name = dev_name(&pdev->dev); 1254f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pci->mod_name = EDAC_MOD_STR; 1264f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pci->ctl_name = pdata->name; 1274f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 1284f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (edac_op_state == EDAC_OPSTATE_POLL) 1294f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pci->edac_check = mv64x60_pci_check; 1304f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 1314f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->edac_idx = edac_pci_idx++; 1324f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 1334f4aeeabc061826376c9a72b4714d062664999eaDave Jiang r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1344f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!r) { 1354f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "%s: Unable to get resource for " 1364f4aeeabc061826376c9a72b4714d062664999eaDave Jiang "PCI err regs\n", __func__); 1374f4aeeabc061826376c9a72b4714d062664999eaDave Jiang res = -ENOENT; 1384f4aeeabc061826376c9a72b4714d062664999eaDave Jiang goto err; 1394f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 1404f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 1414f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!devm_request_mem_region(&pdev->dev, 1424f4aeeabc061826376c9a72b4714d062664999eaDave Jiang r->start, 14330a61fff3a2b19506c66ea81fecb6a7747af3d47Julia Lawall resource_size(r), 1444f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->name)) { 1454f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "%s: Error while requesting mem region\n", 1464f4aeeabc061826376c9a72b4714d062664999eaDave Jiang __func__); 1474f4aeeabc061826376c9a72b4714d062664999eaDave Jiang res = -EBUSY; 1484f4aeeabc061826376c9a72b4714d062664999eaDave Jiang goto err; 1494f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 1504f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 1514f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->pci_vbase = devm_ioremap(&pdev->dev, 1524f4aeeabc061826376c9a72b4714d062664999eaDave Jiang r->start, 15330a61fff3a2b19506c66ea81fecb6a7747af3d47Julia Lawall resource_size(r)); 1544f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!pdata->pci_vbase) { 1554f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "%s: Unable to setup PCI err regs\n", __func__); 1564f4aeeabc061826376c9a72b4714d062664999eaDave Jiang res = -ENOMEM; 1574f4aeeabc061826376c9a72b4714d062664999eaDave Jiang goto err; 1584f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 1594f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 160fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang res = mv64x60_pci_fixup(pdev); 161fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang if (res < 0) { 162fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang printk(KERN_ERR "%s: PCI fixup failed\n", __func__); 163fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang goto err; 164fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang } 165fcb19171d196172a4f57e056f7a60e6d1e2e8c85Dave Jiang 1664f4aeeabc061826376c9a72b4714d062664999eaDave Jiang out_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_CAUSE, 0); 1674f4aeeabc061826376c9a72b4714d062664999eaDave Jiang out_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_MASK, 0); 1684f4aeeabc061826376c9a72b4714d062664999eaDave Jiang out_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_MASK, 1694f4aeeabc061826376c9a72b4714d062664999eaDave Jiang MV64X60_PCIx_ERR_MASK_VAL); 1704f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 1714f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (edac_pci_add_device(pci, pdata->edac_idx) > 0) { 1724f4aeeabc061826376c9a72b4714d062664999eaDave Jiang debugf3("%s(): failed edac_pci_add_device()\n", __func__); 1734f4aeeabc061826376c9a72b4714d062664999eaDave Jiang goto err; 1744f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 1754f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 1764f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (edac_op_state == EDAC_OPSTATE_INT) { 1774f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->irq = platform_get_irq(pdev, 0); 1784f4aeeabc061826376c9a72b4714d062664999eaDave Jiang res = devm_request_irq(&pdev->dev, 1794f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->irq, 1804f4aeeabc061826376c9a72b4714d062664999eaDave Jiang mv64x60_pci_isr, 1814f4aeeabc061826376c9a72b4714d062664999eaDave Jiang IRQF_DISABLED, 1824f4aeeabc061826376c9a72b4714d062664999eaDave Jiang "[EDAC] PCI err", 1834f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pci); 1844f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (res < 0) { 1854f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "%s: Unable to request irq %d for " 1864f4aeeabc061826376c9a72b4714d062664999eaDave Jiang "MV64x60 PCI ERR\n", __func__, pdata->irq); 1874f4aeeabc061826376c9a72b4714d062664999eaDave Jiang res = -ENODEV; 1884f4aeeabc061826376c9a72b4714d062664999eaDave Jiang goto err2; 1894f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 1904f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for PCI Err\n", 1914f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->irq); 1924f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 1934f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 1944f4aeeabc061826376c9a72b4714d062664999eaDave Jiang devres_remove_group(&pdev->dev, mv64x60_pci_err_probe); 1954f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 1964f4aeeabc061826376c9a72b4714d062664999eaDave Jiang /* get this far and it's successful */ 1974f4aeeabc061826376c9a72b4714d062664999eaDave Jiang debugf3("%s(): success\n", __func__); 1984f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 1994f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return 0; 2004f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 2014f4aeeabc061826376c9a72b4714d062664999eaDave Jiangerr2: 2024f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_pci_del_device(&pdev->dev); 2034f4aeeabc061826376c9a72b4714d062664999eaDave Jiangerr: 2044f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_pci_free_ctl_info(pci); 2054f4aeeabc061826376c9a72b4714d062664999eaDave Jiang devres_release_group(&pdev->dev, mv64x60_pci_err_probe); 2064f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return res; 2074f4aeeabc061826376c9a72b4714d062664999eaDave Jiang} 2084f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 2094f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic int mv64x60_pci_err_remove(struct platform_device *pdev) 2104f4aeeabc061826376c9a72b4714d062664999eaDave Jiang{ 2114f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct edac_pci_ctl_info *pci = platform_get_drvdata(pdev); 2124f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 2134f4aeeabc061826376c9a72b4714d062664999eaDave Jiang debugf0("%s()\n", __func__); 2144f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 2154f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_pci_del_device(&pdev->dev); 2164f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 2174f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_pci_free_ctl_info(pci); 2184f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 2194f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return 0; 2204f4aeeabc061826376c9a72b4714d062664999eaDave Jiang} 2214f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 2224f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic struct platform_driver mv64x60_pci_err_driver = { 2234f4aeeabc061826376c9a72b4714d062664999eaDave Jiang .probe = mv64x60_pci_err_probe, 2244f4aeeabc061826376c9a72b4714d062664999eaDave Jiang .remove = __devexit_p(mv64x60_pci_err_remove), 2254f4aeeabc061826376c9a72b4714d062664999eaDave Jiang .driver = { 2264f4aeeabc061826376c9a72b4714d062664999eaDave Jiang .name = "mv64x60_pci_err", 2274f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 2284f4aeeabc061826376c9a72b4714d062664999eaDave Jiang}; 2294f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 2304f4aeeabc061826376c9a72b4714d062664999eaDave Jiang#endif /* CONFIG_PCI */ 2314f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 2324f4aeeabc061826376c9a72b4714d062664999eaDave Jiang/*********************** SRAM err device **********************************/ 2334f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic void mv64x60_sram_check(struct edac_device_ctl_info *edac_dev) 2344f4aeeabc061826376c9a72b4714d062664999eaDave Jiang{ 2354f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct mv64x60_sram_pdata *pdata = edac_dev->pvt_info; 2364f4aeeabc061826376c9a72b4714d062664999eaDave Jiang u32 cause; 2374f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 2384f4aeeabc061826376c9a72b4714d062664999eaDave Jiang cause = in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_CAUSE); 2394f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!cause) 2404f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return; 2414f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 2424f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "Error in internal SRAM\n"); 2434f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "Cause register: 0x%08x\n", cause); 2444f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "Address Low: 0x%08x\n", 2454f4aeeabc061826376c9a72b4714d062664999eaDave Jiang in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_ADDR_LO)); 2464f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "Address High: 0x%08x\n", 2474f4aeeabc061826376c9a72b4714d062664999eaDave Jiang in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_ADDR_HI)); 2484f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "Data Low: 0x%08x\n", 2494f4aeeabc061826376c9a72b4714d062664999eaDave Jiang in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_DATA_LO)); 2504f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "Data High: 0x%08x\n", 2514f4aeeabc061826376c9a72b4714d062664999eaDave Jiang in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_DATA_HI)); 2524f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "Parity: 0x%08x\n", 2534f4aeeabc061826376c9a72b4714d062664999eaDave Jiang in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_PARITY)); 2544f4aeeabc061826376c9a72b4714d062664999eaDave Jiang out_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_CAUSE, 0); 2554f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 2564f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name); 2574f4aeeabc061826376c9a72b4714d062664999eaDave Jiang} 2584f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 2594f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic irqreturn_t mv64x60_sram_isr(int irq, void *dev_id) 2604f4aeeabc061826376c9a72b4714d062664999eaDave Jiang{ 2614f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct edac_device_ctl_info *edac_dev = dev_id; 2624f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct mv64x60_sram_pdata *pdata = edac_dev->pvt_info; 2634f4aeeabc061826376c9a72b4714d062664999eaDave Jiang u32 cause; 2644f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 2654f4aeeabc061826376c9a72b4714d062664999eaDave Jiang cause = in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_CAUSE); 2664f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!cause) 2674f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return IRQ_NONE; 2684f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 2694f4aeeabc061826376c9a72b4714d062664999eaDave Jiang mv64x60_sram_check(edac_dev); 2704f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 2714f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return IRQ_HANDLED; 2724f4aeeabc061826376c9a72b4714d062664999eaDave Jiang} 2734f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 2744f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic int __devinit mv64x60_sram_err_probe(struct platform_device *pdev) 2754f4aeeabc061826376c9a72b4714d062664999eaDave Jiang{ 2764f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct edac_device_ctl_info *edac_dev; 2774f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct mv64x60_sram_pdata *pdata; 2784f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct resource *r; 2794f4aeeabc061826376c9a72b4714d062664999eaDave Jiang int res = 0; 2804f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 2814f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!devres_open_group(&pdev->dev, mv64x60_sram_err_probe, GFP_KERNEL)) 2824f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return -ENOMEM; 2834f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 2844f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_dev = edac_device_alloc_ctl_info(sizeof(*pdata), 2854f4aeeabc061826376c9a72b4714d062664999eaDave Jiang "sram", 1, NULL, 0, 0, NULL, 0, 2864f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_dev_idx); 2874f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!edac_dev) { 2884f4aeeabc061826376c9a72b4714d062664999eaDave Jiang devres_release_group(&pdev->dev, mv64x60_sram_err_probe); 2894f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return -ENOMEM; 2904f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 2914f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 2924f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata = edac_dev->pvt_info; 2934f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->name = "mv64x60_sram_err"; 2944f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->irq = NO_IRQ; 2954f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_dev->dev = &pdev->dev; 2964f4aeeabc061826376c9a72b4714d062664999eaDave Jiang platform_set_drvdata(pdev, edac_dev); 297031d5518591006efd13a33a86909b9477b22917bKay Sievers edac_dev->dev_name = dev_name(&pdev->dev); 2984f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 2994f4aeeabc061826376c9a72b4714d062664999eaDave Jiang r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 3004f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!r) { 3014f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "%s: Unable to get resource for " 3024f4aeeabc061826376c9a72b4714d062664999eaDave Jiang "SRAM err regs\n", __func__); 3034f4aeeabc061826376c9a72b4714d062664999eaDave Jiang res = -ENOENT; 3044f4aeeabc061826376c9a72b4714d062664999eaDave Jiang goto err; 3054f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 3064f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 3074f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!devm_request_mem_region(&pdev->dev, 3084f4aeeabc061826376c9a72b4714d062664999eaDave Jiang r->start, 30930a61fff3a2b19506c66ea81fecb6a7747af3d47Julia Lawall resource_size(r), 3104f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->name)) { 3114f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "%s: Error while request mem region\n", 3124f4aeeabc061826376c9a72b4714d062664999eaDave Jiang __func__); 3134f4aeeabc061826376c9a72b4714d062664999eaDave Jiang res = -EBUSY; 3144f4aeeabc061826376c9a72b4714d062664999eaDave Jiang goto err; 3154f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 3164f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 3174f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->sram_vbase = devm_ioremap(&pdev->dev, 3184f4aeeabc061826376c9a72b4714d062664999eaDave Jiang r->start, 31930a61fff3a2b19506c66ea81fecb6a7747af3d47Julia Lawall resource_size(r)); 3204f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!pdata->sram_vbase) { 3214f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "%s: Unable to setup SRAM err regs\n", 3224f4aeeabc061826376c9a72b4714d062664999eaDave Jiang __func__); 3234f4aeeabc061826376c9a72b4714d062664999eaDave Jiang res = -ENOMEM; 3244f4aeeabc061826376c9a72b4714d062664999eaDave Jiang goto err; 3254f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 3264f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 3274f4aeeabc061826376c9a72b4714d062664999eaDave Jiang /* setup SRAM err registers */ 3284f4aeeabc061826376c9a72b4714d062664999eaDave Jiang out_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_CAUSE, 0); 3294f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 3304f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_dev->mod_name = EDAC_MOD_STR; 3314f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_dev->ctl_name = pdata->name; 3324f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 3334f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (edac_op_state == EDAC_OPSTATE_POLL) 3344f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_dev->edac_check = mv64x60_sram_check; 3354f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 3364f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->edac_idx = edac_dev_idx++; 3374f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 3384f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (edac_device_add_device(edac_dev) > 0) { 3394f4aeeabc061826376c9a72b4714d062664999eaDave Jiang debugf3("%s(): failed edac_device_add_device()\n", __func__); 3404f4aeeabc061826376c9a72b4714d062664999eaDave Jiang goto err; 3414f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 3424f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 3434f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (edac_op_state == EDAC_OPSTATE_INT) { 3444f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->irq = platform_get_irq(pdev, 0); 3454f4aeeabc061826376c9a72b4714d062664999eaDave Jiang res = devm_request_irq(&pdev->dev, 3464f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->irq, 3474f4aeeabc061826376c9a72b4714d062664999eaDave Jiang mv64x60_sram_isr, 3484f4aeeabc061826376c9a72b4714d062664999eaDave Jiang IRQF_DISABLED, 3494f4aeeabc061826376c9a72b4714d062664999eaDave Jiang "[EDAC] SRAM err", 3504f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_dev); 3514f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (res < 0) { 3524f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR 3534f4aeeabc061826376c9a72b4714d062664999eaDave Jiang "%s: Unable to request irq %d for " 3544f4aeeabc061826376c9a72b4714d062664999eaDave Jiang "MV64x60 SRAM ERR\n", __func__, pdata->irq); 3554f4aeeabc061826376c9a72b4714d062664999eaDave Jiang res = -ENODEV; 3564f4aeeabc061826376c9a72b4714d062664999eaDave Jiang goto err2; 3574f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 3584f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 3594f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for SRAM Err\n", 3604f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->irq); 3614f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 3624f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 3634f4aeeabc061826376c9a72b4714d062664999eaDave Jiang devres_remove_group(&pdev->dev, mv64x60_sram_err_probe); 3644f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 3654f4aeeabc061826376c9a72b4714d062664999eaDave Jiang /* get this far and it's successful */ 3664f4aeeabc061826376c9a72b4714d062664999eaDave Jiang debugf3("%s(): success\n", __func__); 3674f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 3684f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return 0; 3694f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 3704f4aeeabc061826376c9a72b4714d062664999eaDave Jiangerr2: 3714f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_device_del_device(&pdev->dev); 3724f4aeeabc061826376c9a72b4714d062664999eaDave Jiangerr: 3734f4aeeabc061826376c9a72b4714d062664999eaDave Jiang devres_release_group(&pdev->dev, mv64x60_sram_err_probe); 3744f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_device_free_ctl_info(edac_dev); 3754f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return res; 3764f4aeeabc061826376c9a72b4714d062664999eaDave Jiang} 3774f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 3784f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic int mv64x60_sram_err_remove(struct platform_device *pdev) 3794f4aeeabc061826376c9a72b4714d062664999eaDave Jiang{ 3804f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct edac_device_ctl_info *edac_dev = platform_get_drvdata(pdev); 3814f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 3824f4aeeabc061826376c9a72b4714d062664999eaDave Jiang debugf0("%s()\n", __func__); 3834f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 3844f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_device_del_device(&pdev->dev); 3854f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_device_free_ctl_info(edac_dev); 3864f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 3874f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return 0; 3884f4aeeabc061826376c9a72b4714d062664999eaDave Jiang} 3894f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 3904f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic struct platform_driver mv64x60_sram_err_driver = { 3914f4aeeabc061826376c9a72b4714d062664999eaDave Jiang .probe = mv64x60_sram_err_probe, 3924f4aeeabc061826376c9a72b4714d062664999eaDave Jiang .remove = mv64x60_sram_err_remove, 3934f4aeeabc061826376c9a72b4714d062664999eaDave Jiang .driver = { 3944f4aeeabc061826376c9a72b4714d062664999eaDave Jiang .name = "mv64x60_sram_err", 3954f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 3964f4aeeabc061826376c9a72b4714d062664999eaDave Jiang}; 3974f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 3984f4aeeabc061826376c9a72b4714d062664999eaDave Jiang/*********************** CPU err device **********************************/ 3994f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic void mv64x60_cpu_check(struct edac_device_ctl_info *edac_dev) 4004f4aeeabc061826376c9a72b4714d062664999eaDave Jiang{ 4014f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct mv64x60_cpu_pdata *pdata = edac_dev->pvt_info; 4024f4aeeabc061826376c9a72b4714d062664999eaDave Jiang u32 cause; 4034f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 4044f4aeeabc061826376c9a72b4714d062664999eaDave Jiang cause = in_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_CAUSE) & 4054f4aeeabc061826376c9a72b4714d062664999eaDave Jiang MV64x60_CPU_CAUSE_MASK; 4064f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!cause) 4074f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return; 4084f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 4094f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "Error on CPU interface\n"); 4104f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "Cause register: 0x%08x\n", cause); 4114f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "Address Low: 0x%08x\n", 4124f4aeeabc061826376c9a72b4714d062664999eaDave Jiang in_le32(pdata->cpu_vbase[0] + MV64x60_CPU_ERR_ADDR_LO)); 4134f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "Address High: 0x%08x\n", 4144f4aeeabc061826376c9a72b4714d062664999eaDave Jiang in_le32(pdata->cpu_vbase[0] + MV64x60_CPU_ERR_ADDR_HI)); 4154f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "Data Low: 0x%08x\n", 4164f4aeeabc061826376c9a72b4714d062664999eaDave Jiang in_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_DATA_LO)); 4174f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "Data High: 0x%08x\n", 4184f4aeeabc061826376c9a72b4714d062664999eaDave Jiang in_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_DATA_HI)); 4194f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "Parity: 0x%08x\n", 4204f4aeeabc061826376c9a72b4714d062664999eaDave Jiang in_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_PARITY)); 4214f4aeeabc061826376c9a72b4714d062664999eaDave Jiang out_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_CAUSE, 0); 4224f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 4234f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name); 4244f4aeeabc061826376c9a72b4714d062664999eaDave Jiang} 4254f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 4264f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic irqreturn_t mv64x60_cpu_isr(int irq, void *dev_id) 4274f4aeeabc061826376c9a72b4714d062664999eaDave Jiang{ 4284f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct edac_device_ctl_info *edac_dev = dev_id; 4294f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct mv64x60_cpu_pdata *pdata = edac_dev->pvt_info; 4304f4aeeabc061826376c9a72b4714d062664999eaDave Jiang u32 cause; 4314f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 4324f4aeeabc061826376c9a72b4714d062664999eaDave Jiang cause = in_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_CAUSE) & 4334f4aeeabc061826376c9a72b4714d062664999eaDave Jiang MV64x60_CPU_CAUSE_MASK; 4344f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!cause) 4354f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return IRQ_NONE; 4364f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 4374f4aeeabc061826376c9a72b4714d062664999eaDave Jiang mv64x60_cpu_check(edac_dev); 4384f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 4394f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return IRQ_HANDLED; 4404f4aeeabc061826376c9a72b4714d062664999eaDave Jiang} 4414f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 4424f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic int __devinit mv64x60_cpu_err_probe(struct platform_device *pdev) 4434f4aeeabc061826376c9a72b4714d062664999eaDave Jiang{ 4444f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct edac_device_ctl_info *edac_dev; 4454f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct resource *r; 4464f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct mv64x60_cpu_pdata *pdata; 4474f4aeeabc061826376c9a72b4714d062664999eaDave Jiang int res = 0; 4484f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 4494f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!devres_open_group(&pdev->dev, mv64x60_cpu_err_probe, GFP_KERNEL)) 4504f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return -ENOMEM; 4514f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 4524f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_dev = edac_device_alloc_ctl_info(sizeof(*pdata), 4534f4aeeabc061826376c9a72b4714d062664999eaDave Jiang "cpu", 1, NULL, 0, 0, NULL, 0, 4544f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_dev_idx); 4554f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!edac_dev) { 4564f4aeeabc061826376c9a72b4714d062664999eaDave Jiang devres_release_group(&pdev->dev, mv64x60_cpu_err_probe); 4574f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return -ENOMEM; 4584f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 4594f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 4604f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata = edac_dev->pvt_info; 4614f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->name = "mv64x60_cpu_err"; 4624f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->irq = NO_IRQ; 4634f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_dev->dev = &pdev->dev; 4644f4aeeabc061826376c9a72b4714d062664999eaDave Jiang platform_set_drvdata(pdev, edac_dev); 465031d5518591006efd13a33a86909b9477b22917bKay Sievers edac_dev->dev_name = dev_name(&pdev->dev); 4664f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 4674f4aeeabc061826376c9a72b4714d062664999eaDave Jiang r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 4684f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!r) { 4694f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "%s: Unable to get resource for " 4704f4aeeabc061826376c9a72b4714d062664999eaDave Jiang "CPU err regs\n", __func__); 4714f4aeeabc061826376c9a72b4714d062664999eaDave Jiang res = -ENOENT; 4724f4aeeabc061826376c9a72b4714d062664999eaDave Jiang goto err; 4734f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 4744f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 4754f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!devm_request_mem_region(&pdev->dev, 4764f4aeeabc061826376c9a72b4714d062664999eaDave Jiang r->start, 47730a61fff3a2b19506c66ea81fecb6a7747af3d47Julia Lawall resource_size(r), 4784f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->name)) { 4794f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "%s: Error while requesting mem region\n", 4804f4aeeabc061826376c9a72b4714d062664999eaDave Jiang __func__); 4814f4aeeabc061826376c9a72b4714d062664999eaDave Jiang res = -EBUSY; 4824f4aeeabc061826376c9a72b4714d062664999eaDave Jiang goto err; 4834f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 4844f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 4854f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->cpu_vbase[0] = devm_ioremap(&pdev->dev, 4864f4aeeabc061826376c9a72b4714d062664999eaDave Jiang r->start, 48730a61fff3a2b19506c66ea81fecb6a7747af3d47Julia Lawall resource_size(r)); 4884f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!pdata->cpu_vbase[0]) { 4894f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "%s: Unable to setup CPU err regs\n", __func__); 4904f4aeeabc061826376c9a72b4714d062664999eaDave Jiang res = -ENOMEM; 4914f4aeeabc061826376c9a72b4714d062664999eaDave Jiang goto err; 4924f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 4934f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 4944f4aeeabc061826376c9a72b4714d062664999eaDave Jiang r = platform_get_resource(pdev, IORESOURCE_MEM, 1); 4954f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!r) { 4964f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "%s: Unable to get resource for " 4974f4aeeabc061826376c9a72b4714d062664999eaDave Jiang "CPU err regs\n", __func__); 4984f4aeeabc061826376c9a72b4714d062664999eaDave Jiang res = -ENOENT; 4994f4aeeabc061826376c9a72b4714d062664999eaDave Jiang goto err; 5004f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 5014f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 5024f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!devm_request_mem_region(&pdev->dev, 5034f4aeeabc061826376c9a72b4714d062664999eaDave Jiang r->start, 50430a61fff3a2b19506c66ea81fecb6a7747af3d47Julia Lawall resource_size(r), 5054f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->name)) { 5064f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "%s: Error while requesting mem region\n", 5074f4aeeabc061826376c9a72b4714d062664999eaDave Jiang __func__); 5084f4aeeabc061826376c9a72b4714d062664999eaDave Jiang res = -EBUSY; 5094f4aeeabc061826376c9a72b4714d062664999eaDave Jiang goto err; 5104f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 5114f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 5124f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->cpu_vbase[1] = devm_ioremap(&pdev->dev, 5134f4aeeabc061826376c9a72b4714d062664999eaDave Jiang r->start, 51430a61fff3a2b19506c66ea81fecb6a7747af3d47Julia Lawall resource_size(r)); 5154f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!pdata->cpu_vbase[1]) { 5164f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "%s: Unable to setup CPU err regs\n", __func__); 5174f4aeeabc061826376c9a72b4714d062664999eaDave Jiang res = -ENOMEM; 5184f4aeeabc061826376c9a72b4714d062664999eaDave Jiang goto err; 5194f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 5204f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 5214f4aeeabc061826376c9a72b4714d062664999eaDave Jiang /* setup CPU err registers */ 5224f4aeeabc061826376c9a72b4714d062664999eaDave Jiang out_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_CAUSE, 0); 5234f4aeeabc061826376c9a72b4714d062664999eaDave Jiang out_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_MASK, 0); 5244f4aeeabc061826376c9a72b4714d062664999eaDave Jiang out_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_MASK, 0x000000ff); 5254f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 5264f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_dev->mod_name = EDAC_MOD_STR; 5274f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_dev->ctl_name = pdata->name; 5284f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (edac_op_state == EDAC_OPSTATE_POLL) 5294f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_dev->edac_check = mv64x60_cpu_check; 5304f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 5314f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->edac_idx = edac_dev_idx++; 5324f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 5334f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (edac_device_add_device(edac_dev) > 0) { 5344f4aeeabc061826376c9a72b4714d062664999eaDave Jiang debugf3("%s(): failed edac_device_add_device()\n", __func__); 5354f4aeeabc061826376c9a72b4714d062664999eaDave Jiang goto err; 5364f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 5374f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 5384f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (edac_op_state == EDAC_OPSTATE_INT) { 5394f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->irq = platform_get_irq(pdev, 0); 5404f4aeeabc061826376c9a72b4714d062664999eaDave Jiang res = devm_request_irq(&pdev->dev, 5414f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->irq, 5424f4aeeabc061826376c9a72b4714d062664999eaDave Jiang mv64x60_cpu_isr, 5434f4aeeabc061826376c9a72b4714d062664999eaDave Jiang IRQF_DISABLED, 5444f4aeeabc061826376c9a72b4714d062664999eaDave Jiang "[EDAC] CPU err", 5454f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_dev); 5464f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (res < 0) { 5474f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR 5484f4aeeabc061826376c9a72b4714d062664999eaDave Jiang "%s: Unable to request irq %d for MV64x60 " 5494f4aeeabc061826376c9a72b4714d062664999eaDave Jiang "CPU ERR\n", __func__, pdata->irq); 5504f4aeeabc061826376c9a72b4714d062664999eaDave Jiang res = -ENODEV; 5514f4aeeabc061826376c9a72b4714d062664999eaDave Jiang goto err2; 5524f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 5534f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 5544f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_INFO EDAC_MOD_STR 5554f4aeeabc061826376c9a72b4714d062664999eaDave Jiang " acquired irq %d for CPU Err\n", pdata->irq); 5564f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 5574f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 5584f4aeeabc061826376c9a72b4714d062664999eaDave Jiang devres_remove_group(&pdev->dev, mv64x60_cpu_err_probe); 5594f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 5604f4aeeabc061826376c9a72b4714d062664999eaDave Jiang /* get this far and it's successful */ 5614f4aeeabc061826376c9a72b4714d062664999eaDave Jiang debugf3("%s(): success\n", __func__); 5624f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 5634f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return 0; 5644f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 5654f4aeeabc061826376c9a72b4714d062664999eaDave Jiangerr2: 5664f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_device_del_device(&pdev->dev); 5674f4aeeabc061826376c9a72b4714d062664999eaDave Jiangerr: 5684f4aeeabc061826376c9a72b4714d062664999eaDave Jiang devres_release_group(&pdev->dev, mv64x60_cpu_err_probe); 5694f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_device_free_ctl_info(edac_dev); 5704f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return res; 5714f4aeeabc061826376c9a72b4714d062664999eaDave Jiang} 5724f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 5734f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic int mv64x60_cpu_err_remove(struct platform_device *pdev) 5744f4aeeabc061826376c9a72b4714d062664999eaDave Jiang{ 5754f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct edac_device_ctl_info *edac_dev = platform_get_drvdata(pdev); 5764f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 5774f4aeeabc061826376c9a72b4714d062664999eaDave Jiang debugf0("%s()\n", __func__); 5784f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 5794f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_device_del_device(&pdev->dev); 5804f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_device_free_ctl_info(edac_dev); 5814f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return 0; 5824f4aeeabc061826376c9a72b4714d062664999eaDave Jiang} 5834f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 5844f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic struct platform_driver mv64x60_cpu_err_driver = { 5854f4aeeabc061826376c9a72b4714d062664999eaDave Jiang .probe = mv64x60_cpu_err_probe, 5864f4aeeabc061826376c9a72b4714d062664999eaDave Jiang .remove = mv64x60_cpu_err_remove, 5874f4aeeabc061826376c9a72b4714d062664999eaDave Jiang .driver = { 5884f4aeeabc061826376c9a72b4714d062664999eaDave Jiang .name = "mv64x60_cpu_err", 5894f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 5904f4aeeabc061826376c9a72b4714d062664999eaDave Jiang}; 5914f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 5924f4aeeabc061826376c9a72b4714d062664999eaDave Jiang/*********************** DRAM err device **********************************/ 5934f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 5944f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic void mv64x60_mc_check(struct mem_ctl_info *mci) 5954f4aeeabc061826376c9a72b4714d062664999eaDave Jiang{ 5964f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct mv64x60_mc_pdata *pdata = mci->pvt_info; 5974f4aeeabc061826376c9a72b4714d062664999eaDave Jiang u32 reg; 5984f4aeeabc061826376c9a72b4714d062664999eaDave Jiang u32 err_addr; 5994f4aeeabc061826376c9a72b4714d062664999eaDave Jiang u32 sdram_ecc; 6004f4aeeabc061826376c9a72b4714d062664999eaDave Jiang u32 comp_ecc; 6014f4aeeabc061826376c9a72b4714d062664999eaDave Jiang u32 syndrome; 6024f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 6034f4aeeabc061826376c9a72b4714d062664999eaDave Jiang reg = in_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR); 6044f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!reg) 6054f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return; 6064f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 6074f4aeeabc061826376c9a72b4714d062664999eaDave Jiang err_addr = reg & ~0x3; 6084f4aeeabc061826376c9a72b4714d062664999eaDave Jiang sdram_ecc = in_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_RCVD); 6094f4aeeabc061826376c9a72b4714d062664999eaDave Jiang comp_ecc = in_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_CALC); 6104f4aeeabc061826376c9a72b4714d062664999eaDave Jiang syndrome = sdram_ecc ^ comp_ecc; 6114f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 6124f4aeeabc061826376c9a72b4714d062664999eaDave Jiang /* first bit clear in ECC Err Reg, 1 bit error, correctable by HW */ 6134f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!(reg & 0x1)) 6144f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_mc_handle_ce(mci, err_addr >> PAGE_SHIFT, 6154f4aeeabc061826376c9a72b4714d062664999eaDave Jiang err_addr & PAGE_MASK, syndrome, 0, 0, 6164f4aeeabc061826376c9a72b4714d062664999eaDave Jiang mci->ctl_name); 6174f4aeeabc061826376c9a72b4714d062664999eaDave Jiang else /* 2 bit error, UE */ 6184f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_mc_handle_ue(mci, err_addr >> PAGE_SHIFT, 6194f4aeeabc061826376c9a72b4714d062664999eaDave Jiang err_addr & PAGE_MASK, 0, mci->ctl_name); 6204f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 6214f4aeeabc061826376c9a72b4714d062664999eaDave Jiang /* clear the error */ 6224f4aeeabc061826376c9a72b4714d062664999eaDave Jiang out_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR, 0); 6234f4aeeabc061826376c9a72b4714d062664999eaDave Jiang} 6244f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 6254f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic irqreturn_t mv64x60_mc_isr(int irq, void *dev_id) 6264f4aeeabc061826376c9a72b4714d062664999eaDave Jiang{ 6274f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct mem_ctl_info *mci = dev_id; 6284f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct mv64x60_mc_pdata *pdata = mci->pvt_info; 6294f4aeeabc061826376c9a72b4714d062664999eaDave Jiang u32 reg; 6304f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 6314f4aeeabc061826376c9a72b4714d062664999eaDave Jiang reg = in_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR); 6324f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!reg) 6334f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return IRQ_NONE; 6344f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 6354f4aeeabc061826376c9a72b4714d062664999eaDave Jiang /* writing 0's to the ECC err addr in check function clears irq */ 6364f4aeeabc061826376c9a72b4714d062664999eaDave Jiang mv64x60_mc_check(mci); 6374f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 6384f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return IRQ_HANDLED; 6394f4aeeabc061826376c9a72b4714d062664999eaDave Jiang} 6404f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 6414f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic void get_total_mem(struct mv64x60_mc_pdata *pdata) 6424f4aeeabc061826376c9a72b4714d062664999eaDave Jiang{ 6434f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct device_node *np = NULL; 6444f4aeeabc061826376c9a72b4714d062664999eaDave Jiang const unsigned int *reg; 6454f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 6464f4aeeabc061826376c9a72b4714d062664999eaDave Jiang np = of_find_node_by_type(NULL, "memory"); 6474f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!np) 6484f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return; 6494f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 650596d3941035d4d4b484c820f10f57fd4816c6615Dave Jiang reg = of_get_property(np, "reg", NULL); 6514f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 6524f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->total_mem = reg[1]; 6534f4aeeabc061826376c9a72b4714d062664999eaDave Jiang} 6544f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 6554f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic void mv64x60_init_csrows(struct mem_ctl_info *mci, 6564f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct mv64x60_mc_pdata *pdata) 6574f4aeeabc061826376c9a72b4714d062664999eaDave Jiang{ 6584f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct csrow_info *csrow; 6594f4aeeabc061826376c9a72b4714d062664999eaDave Jiang u32 devtype; 6604f4aeeabc061826376c9a72b4714d062664999eaDave Jiang u32 ctl; 6614f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 6624f4aeeabc061826376c9a72b4714d062664999eaDave Jiang get_total_mem(pdata); 6634f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 6644f4aeeabc061826376c9a72b4714d062664999eaDave Jiang ctl = in_le32(pdata->mc_vbase + MV64X60_SDRAM_CONFIG); 6654f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 6664f4aeeabc061826376c9a72b4714d062664999eaDave Jiang csrow = &mci->csrows[0]; 6674f4aeeabc061826376c9a72b4714d062664999eaDave Jiang csrow->first_page = 0; 6684f4aeeabc061826376c9a72b4714d062664999eaDave Jiang csrow->nr_pages = pdata->total_mem >> PAGE_SHIFT; 6694f4aeeabc061826376c9a72b4714d062664999eaDave Jiang csrow->last_page = csrow->first_page + csrow->nr_pages - 1; 6704f4aeeabc061826376c9a72b4714d062664999eaDave Jiang csrow->grain = 8; 6714f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 6724f4aeeabc061826376c9a72b4714d062664999eaDave Jiang csrow->mtype = (ctl & MV64X60_SDRAM_REGISTERED) ? MEM_RDDR : MEM_DDR; 6734f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 6744f4aeeabc061826376c9a72b4714d062664999eaDave Jiang devtype = (ctl >> 20) & 0x3; 6754f4aeeabc061826376c9a72b4714d062664999eaDave Jiang switch (devtype) { 6764f4aeeabc061826376c9a72b4714d062664999eaDave Jiang case 0x0: 6774f4aeeabc061826376c9a72b4714d062664999eaDave Jiang csrow->dtype = DEV_X32; 6784f4aeeabc061826376c9a72b4714d062664999eaDave Jiang break; 6794f4aeeabc061826376c9a72b4714d062664999eaDave Jiang case 0x2: /* could be X8 too, but no way to tell */ 6804f4aeeabc061826376c9a72b4714d062664999eaDave Jiang csrow->dtype = DEV_X16; 6814f4aeeabc061826376c9a72b4714d062664999eaDave Jiang break; 6824f4aeeabc061826376c9a72b4714d062664999eaDave Jiang case 0x3: 6834f4aeeabc061826376c9a72b4714d062664999eaDave Jiang csrow->dtype = DEV_X4; 6844f4aeeabc061826376c9a72b4714d062664999eaDave Jiang break; 6854f4aeeabc061826376c9a72b4714d062664999eaDave Jiang default: 6864f4aeeabc061826376c9a72b4714d062664999eaDave Jiang csrow->dtype = DEV_UNKNOWN; 6874f4aeeabc061826376c9a72b4714d062664999eaDave Jiang break; 6884f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 6894f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 6904f4aeeabc061826376c9a72b4714d062664999eaDave Jiang csrow->edac_mode = EDAC_SECDED; 6914f4aeeabc061826376c9a72b4714d062664999eaDave Jiang} 6924f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 6934f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic int __devinit mv64x60_mc_err_probe(struct platform_device *pdev) 6944f4aeeabc061826376c9a72b4714d062664999eaDave Jiang{ 6954f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct mem_ctl_info *mci; 6964f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct mv64x60_mc_pdata *pdata; 6974f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct resource *r; 6984f4aeeabc061826376c9a72b4714d062664999eaDave Jiang u32 ctl; 6994f4aeeabc061826376c9a72b4714d062664999eaDave Jiang int res = 0; 7004f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 7014f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!devres_open_group(&pdev->dev, mv64x60_mc_err_probe, GFP_KERNEL)) 7024f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return -ENOMEM; 7034f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 7044f4aeeabc061826376c9a72b4714d062664999eaDave Jiang mci = edac_mc_alloc(sizeof(struct mv64x60_mc_pdata), 1, 1, edac_mc_idx); 7054f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!mci) { 7064f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "%s: No memory for CPU err\n", __func__); 7074f4aeeabc061826376c9a72b4714d062664999eaDave Jiang devres_release_group(&pdev->dev, mv64x60_mc_err_probe); 7084f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return -ENOMEM; 7094f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 7104f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 7114f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata = mci->pvt_info; 7124f4aeeabc061826376c9a72b4714d062664999eaDave Jiang mci->dev = &pdev->dev; 7134f4aeeabc061826376c9a72b4714d062664999eaDave Jiang platform_set_drvdata(pdev, mci); 7144f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->name = "mv64x60_mc_err"; 7154f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->irq = NO_IRQ; 716031d5518591006efd13a33a86909b9477b22917bKay Sievers mci->dev_name = dev_name(&pdev->dev); 7174f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->edac_idx = edac_mc_idx++; 7184f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 7194f4aeeabc061826376c9a72b4714d062664999eaDave Jiang r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 7204f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!r) { 7214f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "%s: Unable to get resource for " 7224f4aeeabc061826376c9a72b4714d062664999eaDave Jiang "MC err regs\n", __func__); 7234f4aeeabc061826376c9a72b4714d062664999eaDave Jiang res = -ENOENT; 7244f4aeeabc061826376c9a72b4714d062664999eaDave Jiang goto err; 7254f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 7264f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 7274f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!devm_request_mem_region(&pdev->dev, 7284f4aeeabc061826376c9a72b4714d062664999eaDave Jiang r->start, 72930a61fff3a2b19506c66ea81fecb6a7747af3d47Julia Lawall resource_size(r), 7304f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->name)) { 7314f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "%s: Error while requesting mem region\n", 7324f4aeeabc061826376c9a72b4714d062664999eaDave Jiang __func__); 7334f4aeeabc061826376c9a72b4714d062664999eaDave Jiang res = -EBUSY; 7344f4aeeabc061826376c9a72b4714d062664999eaDave Jiang goto err; 7354f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 7364f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 7374f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->mc_vbase = devm_ioremap(&pdev->dev, 7384f4aeeabc061826376c9a72b4714d062664999eaDave Jiang r->start, 73930a61fff3a2b19506c66ea81fecb6a7747af3d47Julia Lawall resource_size(r)); 7404f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!pdata->mc_vbase) { 7414f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "%s: Unable to setup MC err regs\n", __func__); 7424f4aeeabc061826376c9a72b4714d062664999eaDave Jiang res = -ENOMEM; 7434f4aeeabc061826376c9a72b4714d062664999eaDave Jiang goto err; 7444f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 7454f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 7464f4aeeabc061826376c9a72b4714d062664999eaDave Jiang ctl = in_le32(pdata->mc_vbase + MV64X60_SDRAM_CONFIG); 7474f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (!(ctl & MV64X60_SDRAM_ECC)) { 7484f4aeeabc061826376c9a72b4714d062664999eaDave Jiang /* Non-ECC RAM? */ 7494f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_WARNING "%s: No ECC DIMMs discovered\n", __func__); 7504f4aeeabc061826376c9a72b4714d062664999eaDave Jiang res = -ENODEV; 7514f4aeeabc061826376c9a72b4714d062664999eaDave Jiang goto err2; 7524f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 7534f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 7544f4aeeabc061826376c9a72b4714d062664999eaDave Jiang debugf3("%s(): init mci\n", __func__); 7554f4aeeabc061826376c9a72b4714d062664999eaDave Jiang mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR; 7564f4aeeabc061826376c9a72b4714d062664999eaDave Jiang mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; 7574f4aeeabc061826376c9a72b4714d062664999eaDave Jiang mci->edac_cap = EDAC_FLAG_SECDED; 7584f4aeeabc061826376c9a72b4714d062664999eaDave Jiang mci->mod_name = EDAC_MOD_STR; 7594f4aeeabc061826376c9a72b4714d062664999eaDave Jiang mci->mod_ver = MV64x60_REVISION; 7604f4aeeabc061826376c9a72b4714d062664999eaDave Jiang mci->ctl_name = mv64x60_ctl_name; 7614f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 7624f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (edac_op_state == EDAC_OPSTATE_POLL) 7634f4aeeabc061826376c9a72b4714d062664999eaDave Jiang mci->edac_check = mv64x60_mc_check; 7644f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 7654f4aeeabc061826376c9a72b4714d062664999eaDave Jiang mci->ctl_page_to_phys = NULL; 7664f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 7674f4aeeabc061826376c9a72b4714d062664999eaDave Jiang mci->scrub_mode = SCRUB_SW_SRC; 7684f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 7694f4aeeabc061826376c9a72b4714d062664999eaDave Jiang mv64x60_init_csrows(mci, pdata); 7704f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 7714f4aeeabc061826376c9a72b4714d062664999eaDave Jiang /* setup MC registers */ 7724f4aeeabc061826376c9a72b4714d062664999eaDave Jiang out_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR, 0); 7734f4aeeabc061826376c9a72b4714d062664999eaDave Jiang ctl = in_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_CNTL); 7744f4aeeabc061826376c9a72b4714d062664999eaDave Jiang ctl = (ctl & 0xff00ffff) | 0x10000; 7754f4aeeabc061826376c9a72b4714d062664999eaDave Jiang out_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_CNTL, ctl); 7764f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 7774f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (edac_mc_add_mc(mci)) { 7784f4aeeabc061826376c9a72b4714d062664999eaDave Jiang debugf3("%s(): failed edac_mc_add_mc()\n", __func__); 7794f4aeeabc061826376c9a72b4714d062664999eaDave Jiang goto err; 7804f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 7814f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 7824f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (edac_op_state == EDAC_OPSTATE_INT) { 7834f4aeeabc061826376c9a72b4714d062664999eaDave Jiang /* acquire interrupt that reports errors */ 7844f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->irq = platform_get_irq(pdev, 0); 7854f4aeeabc061826376c9a72b4714d062664999eaDave Jiang res = devm_request_irq(&pdev->dev, 7864f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->irq, 7874f4aeeabc061826376c9a72b4714d062664999eaDave Jiang mv64x60_mc_isr, 7884f4aeeabc061826376c9a72b4714d062664999eaDave Jiang IRQF_DISABLED, 7894f4aeeabc061826376c9a72b4714d062664999eaDave Jiang "[EDAC] MC err", 7904f4aeeabc061826376c9a72b4714d062664999eaDave Jiang mci); 7914f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (res < 0) { 7924f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_ERR "%s: Unable to request irq %d for " 7934f4aeeabc061826376c9a72b4714d062664999eaDave Jiang "MV64x60 DRAM ERR\n", __func__, pdata->irq); 7944f4aeeabc061826376c9a72b4714d062664999eaDave Jiang res = -ENODEV; 7954f4aeeabc061826376c9a72b4714d062664999eaDave Jiang goto err2; 7964f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 7974f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 7984f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for MC Err\n", 7994f4aeeabc061826376c9a72b4714d062664999eaDave Jiang pdata->irq); 8004f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 8014f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 8024f4aeeabc061826376c9a72b4714d062664999eaDave Jiang /* get this far and it's successful */ 8034f4aeeabc061826376c9a72b4714d062664999eaDave Jiang debugf3("%s(): success\n", __func__); 8044f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 8054f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return 0; 8064f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 8074f4aeeabc061826376c9a72b4714d062664999eaDave Jiangerr2: 8084f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_mc_del_mc(&pdev->dev); 8094f4aeeabc061826376c9a72b4714d062664999eaDave Jiangerr: 8104f4aeeabc061826376c9a72b4714d062664999eaDave Jiang devres_release_group(&pdev->dev, mv64x60_mc_err_probe); 8114f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_mc_free(mci); 8124f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return res; 8134f4aeeabc061826376c9a72b4714d062664999eaDave Jiang} 8144f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 8154f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic int mv64x60_mc_err_remove(struct platform_device *pdev) 8164f4aeeabc061826376c9a72b4714d062664999eaDave Jiang{ 8174f4aeeabc061826376c9a72b4714d062664999eaDave Jiang struct mem_ctl_info *mci = platform_get_drvdata(pdev); 8184f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 8194f4aeeabc061826376c9a72b4714d062664999eaDave Jiang debugf0("%s()\n", __func__); 8204f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 8214f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_mc_del_mc(&pdev->dev); 8224f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_mc_free(mci); 8234f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return 0; 8244f4aeeabc061826376c9a72b4714d062664999eaDave Jiang} 8254f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 8264f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic struct platform_driver mv64x60_mc_err_driver = { 8274f4aeeabc061826376c9a72b4714d062664999eaDave Jiang .probe = mv64x60_mc_err_probe, 8284f4aeeabc061826376c9a72b4714d062664999eaDave Jiang .remove = mv64x60_mc_err_remove, 8294f4aeeabc061826376c9a72b4714d062664999eaDave Jiang .driver = { 8304f4aeeabc061826376c9a72b4714d062664999eaDave Jiang .name = "mv64x60_mc_err", 8314f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 8324f4aeeabc061826376c9a72b4714d062664999eaDave Jiang}; 8334f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 8344f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic int __init mv64x60_edac_init(void) 8354f4aeeabc061826376c9a72b4714d062664999eaDave Jiang{ 8364f4aeeabc061826376c9a72b4714d062664999eaDave Jiang int ret = 0; 8374f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 8384f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_INFO "Marvell MV64x60 EDAC driver " MV64x60_REVISION "\n"); 8394f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_INFO "\t(C) 2006-2007 MontaVista Software\n"); 8404f4aeeabc061826376c9a72b4714d062664999eaDave Jiang /* make sure error reporting method is sane */ 8414f4aeeabc061826376c9a72b4714d062664999eaDave Jiang switch (edac_op_state) { 8424f4aeeabc061826376c9a72b4714d062664999eaDave Jiang case EDAC_OPSTATE_POLL: 8434f4aeeabc061826376c9a72b4714d062664999eaDave Jiang case EDAC_OPSTATE_INT: 8444f4aeeabc061826376c9a72b4714d062664999eaDave Jiang break; 8454f4aeeabc061826376c9a72b4714d062664999eaDave Jiang default: 8464f4aeeabc061826376c9a72b4714d062664999eaDave Jiang edac_op_state = EDAC_OPSTATE_INT; 8474f4aeeabc061826376c9a72b4714d062664999eaDave Jiang break; 8484f4aeeabc061826376c9a72b4714d062664999eaDave Jiang } 8494f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 8504f4aeeabc061826376c9a72b4714d062664999eaDave Jiang ret = platform_driver_register(&mv64x60_mc_err_driver); 8514f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (ret) 8524f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_WARNING EDAC_MOD_STR "MC err failed to register\n"); 8534f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 8544f4aeeabc061826376c9a72b4714d062664999eaDave Jiang ret = platform_driver_register(&mv64x60_cpu_err_driver); 8554f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (ret) 8564f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_WARNING EDAC_MOD_STR 8574f4aeeabc061826376c9a72b4714d062664999eaDave Jiang "CPU err failed to register\n"); 8584f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 8594f4aeeabc061826376c9a72b4714d062664999eaDave Jiang ret = platform_driver_register(&mv64x60_sram_err_driver); 8604f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (ret) 8614f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_WARNING EDAC_MOD_STR 8624f4aeeabc061826376c9a72b4714d062664999eaDave Jiang "SRAM err failed to register\n"); 8634f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 8644f4aeeabc061826376c9a72b4714d062664999eaDave Jiang#ifdef CONFIG_PCI 8654f4aeeabc061826376c9a72b4714d062664999eaDave Jiang ret = platform_driver_register(&mv64x60_pci_err_driver); 8664f4aeeabc061826376c9a72b4714d062664999eaDave Jiang if (ret) 8674f4aeeabc061826376c9a72b4714d062664999eaDave Jiang printk(KERN_WARNING EDAC_MOD_STR 8684f4aeeabc061826376c9a72b4714d062664999eaDave Jiang "PCI err failed to register\n"); 8694f4aeeabc061826376c9a72b4714d062664999eaDave Jiang#endif 8704f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 8714f4aeeabc061826376c9a72b4714d062664999eaDave Jiang return ret; 8724f4aeeabc061826376c9a72b4714d062664999eaDave Jiang} 8734f4aeeabc061826376c9a72b4714d062664999eaDave Jiangmodule_init(mv64x60_edac_init); 8744f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 8754f4aeeabc061826376c9a72b4714d062664999eaDave Jiangstatic void __exit mv64x60_edac_exit(void) 8764f4aeeabc061826376c9a72b4714d062664999eaDave Jiang{ 8774f4aeeabc061826376c9a72b4714d062664999eaDave Jiang#ifdef CONFIG_PCI 8784f4aeeabc061826376c9a72b4714d062664999eaDave Jiang platform_driver_unregister(&mv64x60_pci_err_driver); 8794f4aeeabc061826376c9a72b4714d062664999eaDave Jiang#endif 8804f4aeeabc061826376c9a72b4714d062664999eaDave Jiang platform_driver_unregister(&mv64x60_sram_err_driver); 8814f4aeeabc061826376c9a72b4714d062664999eaDave Jiang platform_driver_unregister(&mv64x60_cpu_err_driver); 8824f4aeeabc061826376c9a72b4714d062664999eaDave Jiang platform_driver_unregister(&mv64x60_mc_err_driver); 8834f4aeeabc061826376c9a72b4714d062664999eaDave Jiang} 8844f4aeeabc061826376c9a72b4714d062664999eaDave Jiangmodule_exit(mv64x60_edac_exit); 8854f4aeeabc061826376c9a72b4714d062664999eaDave Jiang 8864f4aeeabc061826376c9a72b4714d062664999eaDave JiangMODULE_LICENSE("GPL"); 8874f4aeeabc061826376c9a72b4714d062664999eaDave JiangMODULE_AUTHOR("Montavista Software, Inc."); 8884f4aeeabc061826376c9a72b4714d062664999eaDave Jiangmodule_param(edac_op_state, int, 0444); 8894f4aeeabc061826376c9a72b4714d062664999eaDave JiangMODULE_PARM_DESC(edac_op_state, 8904f4aeeabc061826376c9a72b4714d062664999eaDave Jiang "EDAC Error Reporting state: 0=Poll, 2=Interrupt"); 891