18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 38c2ecf20Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 48c2ecf20Sopenharmony_ci * for more details. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2012 Cavium, Inc. 78c2ecf20Sopenharmony_ci * Copyright (C) 2009 Wind River Systems, 88c2ecf20Sopenharmony_ci * written by Ralf Baechle <ralf@linux-mips.org> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/io.h> 148c2ecf20Sopenharmony_ci#include <linux/edac.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <asm/octeon/cvmx.h> 178c2ecf20Sopenharmony_ci#include <asm/octeon/cvmx-npi-defs.h> 188c2ecf20Sopenharmony_ci#include <asm/octeon/cvmx-pci-defs.h> 198c2ecf20Sopenharmony_ci#include <asm/octeon/octeon.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "edac_module.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic void octeon_pci_poll(struct edac_pci_ctl_info *pci) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci union cvmx_pci_cfg01 cfg01; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci cfg01.u32 = octeon_npi_read32(CVMX_NPI_PCI_CFG01); 288c2ecf20Sopenharmony_ci if (cfg01.s.dpe) { /* Detected parity error */ 298c2ecf20Sopenharmony_ci edac_pci_handle_pe(pci, pci->ctl_name); 308c2ecf20Sopenharmony_ci cfg01.s.dpe = 1; /* Reset */ 318c2ecf20Sopenharmony_ci octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32); 328c2ecf20Sopenharmony_ci } 338c2ecf20Sopenharmony_ci if (cfg01.s.sse) { 348c2ecf20Sopenharmony_ci edac_pci_handle_npe(pci, "Signaled System Error"); 358c2ecf20Sopenharmony_ci cfg01.s.sse = 1; /* Reset */ 368c2ecf20Sopenharmony_ci octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32); 378c2ecf20Sopenharmony_ci } 388c2ecf20Sopenharmony_ci if (cfg01.s.rma) { 398c2ecf20Sopenharmony_ci edac_pci_handle_npe(pci, "Received Master Abort"); 408c2ecf20Sopenharmony_ci cfg01.s.rma = 1; /* Reset */ 418c2ecf20Sopenharmony_ci octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32); 428c2ecf20Sopenharmony_ci } 438c2ecf20Sopenharmony_ci if (cfg01.s.rta) { 448c2ecf20Sopenharmony_ci edac_pci_handle_npe(pci, "Received Target Abort"); 458c2ecf20Sopenharmony_ci cfg01.s.rta = 1; /* Reset */ 468c2ecf20Sopenharmony_ci octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32); 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci if (cfg01.s.sta) { 498c2ecf20Sopenharmony_ci edac_pci_handle_npe(pci, "Signaled Target Abort"); 508c2ecf20Sopenharmony_ci cfg01.s.sta = 1; /* Reset */ 518c2ecf20Sopenharmony_ci octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32); 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci if (cfg01.s.mdpe) { 548c2ecf20Sopenharmony_ci edac_pci_handle_npe(pci, "Master Data Parity Error"); 558c2ecf20Sopenharmony_ci cfg01.s.mdpe = 1; /* Reset */ 568c2ecf20Sopenharmony_ci octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32); 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic int octeon_pci_probe(struct platform_device *pdev) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci struct edac_pci_ctl_info *pci; 638c2ecf20Sopenharmony_ci int res = 0; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci pci = edac_pci_alloc_ctl_info(0, "octeon_pci_err"); 668c2ecf20Sopenharmony_ci if (!pci) 678c2ecf20Sopenharmony_ci return -ENOMEM; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci pci->dev = &pdev->dev; 708c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, pci); 718c2ecf20Sopenharmony_ci pci->dev_name = dev_name(&pdev->dev); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci pci->mod_name = "octeon-pci"; 748c2ecf20Sopenharmony_ci pci->ctl_name = "octeon_pci_err"; 758c2ecf20Sopenharmony_ci pci->edac_check = octeon_pci_poll; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (edac_pci_add_device(pci, 0) > 0) { 788c2ecf20Sopenharmony_ci pr_err("%s: edac_pci_add_device() failed\n", __func__); 798c2ecf20Sopenharmony_ci goto err; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci return 0; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cierr: 858c2ecf20Sopenharmony_ci edac_pci_free_ctl_info(pci); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci return res; 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic int octeon_pci_remove(struct platform_device *pdev) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci struct edac_pci_ctl_info *pci = platform_get_drvdata(pdev); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci edac_pci_del_device(&pdev->dev); 958c2ecf20Sopenharmony_ci edac_pci_free_ctl_info(pci); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci return 0; 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic struct platform_driver octeon_pci_driver = { 1018c2ecf20Sopenharmony_ci .probe = octeon_pci_probe, 1028c2ecf20Sopenharmony_ci .remove = octeon_pci_remove, 1038c2ecf20Sopenharmony_ci .driver = { 1048c2ecf20Sopenharmony_ci .name = "octeon_pci_edac", 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci}; 1078c2ecf20Sopenharmony_cimodule_platform_driver(octeon_pci_driver); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1108c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>"); 111