0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/module.h>
0011 #include <linux/init.h>
0012 #include <linux/slab.h>
0013 #include <linux/io.h>
0014 #include <linux/edac.h>
0015
0016 #include <asm/octeon/cvmx.h>
0017 #include <asm/octeon/cvmx-npi-defs.h>
0018 #include <asm/octeon/cvmx-pci-defs.h>
0019 #include <asm/octeon/octeon.h>
0020
0021 #include "edac_module.h"
0022
0023 static void octeon_pci_poll(struct edac_pci_ctl_info *pci)
0024 {
0025 union cvmx_pci_cfg01 cfg01;
0026
0027 cfg01.u32 = octeon_npi_read32(CVMX_NPI_PCI_CFG01);
0028 if (cfg01.s.dpe) {
0029 edac_pci_handle_pe(pci, pci->ctl_name);
0030 cfg01.s.dpe = 1;
0031 octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32);
0032 }
0033 if (cfg01.s.sse) {
0034 edac_pci_handle_npe(pci, "Signaled System Error");
0035 cfg01.s.sse = 1;
0036 octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32);
0037 }
0038 if (cfg01.s.rma) {
0039 edac_pci_handle_npe(pci, "Received Master Abort");
0040 cfg01.s.rma = 1;
0041 octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32);
0042 }
0043 if (cfg01.s.rta) {
0044 edac_pci_handle_npe(pci, "Received Target Abort");
0045 cfg01.s.rta = 1;
0046 octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32);
0047 }
0048 if (cfg01.s.sta) {
0049 edac_pci_handle_npe(pci, "Signaled Target Abort");
0050 cfg01.s.sta = 1;
0051 octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32);
0052 }
0053 if (cfg01.s.mdpe) {
0054 edac_pci_handle_npe(pci, "Master Data Parity Error");
0055 cfg01.s.mdpe = 1;
0056 octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32);
0057 }
0058 }
0059
0060 static int octeon_pci_probe(struct platform_device *pdev)
0061 {
0062 struct edac_pci_ctl_info *pci;
0063 int res = 0;
0064
0065 pci = edac_pci_alloc_ctl_info(0, "octeon_pci_err");
0066 if (!pci)
0067 return -ENOMEM;
0068
0069 pci->dev = &pdev->dev;
0070 platform_set_drvdata(pdev, pci);
0071 pci->dev_name = dev_name(&pdev->dev);
0072
0073 pci->mod_name = "octeon-pci";
0074 pci->ctl_name = "octeon_pci_err";
0075 pci->edac_check = octeon_pci_poll;
0076
0077 if (edac_pci_add_device(pci, 0) > 0) {
0078 pr_err("%s: edac_pci_add_device() failed\n", __func__);
0079 goto err;
0080 }
0081
0082 return 0;
0083
0084 err:
0085 edac_pci_free_ctl_info(pci);
0086
0087 return res;
0088 }
0089
0090 static int octeon_pci_remove(struct platform_device *pdev)
0091 {
0092 struct edac_pci_ctl_info *pci = platform_get_drvdata(pdev);
0093
0094 edac_pci_del_device(&pdev->dev);
0095 edac_pci_free_ctl_info(pci);
0096
0097 return 0;
0098 }
0099
0100 static struct platform_driver octeon_pci_driver = {
0101 .probe = octeon_pci_probe,
0102 .remove = octeon_pci_remove,
0103 .driver = {
0104 .name = "octeon_pci_edac",
0105 }
0106 };
0107 module_platform_driver(octeon_pci_driver);
0108
0109 MODULE_LICENSE("GPL");
0110 MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");