diff options
Diffstat (limited to 'drivers/edac/octeon_edac-pci.c')
-rw-r--r-- | drivers/edac/octeon_edac-pci.c | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/drivers/edac/octeon_edac-pci.c b/drivers/edac/octeon_edac-pci.c new file mode 100644 index 000000000000..e72b96e3e4e0 --- /dev/null +++ b/drivers/edac/octeon_edac-pci.c | |||
@@ -0,0 +1,135 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2009 Wind River Systems, | ||
7 | * written by Ralf Baechle <ralf@linux-mips.org> | ||
8 | */ | ||
9 | #include <linux/module.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/slab.h> | ||
12 | #include <linux/io.h> | ||
13 | #include <linux/edac.h> | ||
14 | |||
15 | #include <asm/octeon/cvmx.h> | ||
16 | #include <asm/octeon/cvmx-npi-defs.h> | ||
17 | #include <asm/octeon/cvmx-pci-defs.h> | ||
18 | #include <asm/octeon/octeon.h> | ||
19 | |||
20 | #include "edac_core.h" | ||
21 | #include "edac_module.h" | ||
22 | |||
23 | #define EDAC_MOD_STR "octeon" | ||
24 | |||
25 | static void co_pci_poll(struct edac_pci_ctl_info *pci) | ||
26 | { | ||
27 | union cvmx_pci_cfg01 cfg01; | ||
28 | |||
29 | cfg01.u32 = octeon_npi_read32(CVMX_NPI_PCI_CFG01); | ||
30 | if (cfg01.s.dpe) { /* Detected parity error */ | ||
31 | edac_pci_handle_pe(pci, pci->ctl_name); | ||
32 | cfg01.s.dpe = 1; /* Reset */ | ||
33 | octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32); | ||
34 | } | ||
35 | if (cfg01.s.sse) { | ||
36 | edac_pci_handle_npe(pci, "Signaled System Error"); | ||
37 | cfg01.s.sse = 1; /* Reset */ | ||
38 | octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32); | ||
39 | } | ||
40 | if (cfg01.s.rma) { | ||
41 | edac_pci_handle_npe(pci, "Received Master Abort"); | ||
42 | cfg01.s.rma = 1; /* Reset */ | ||
43 | octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32); | ||
44 | } | ||
45 | if (cfg01.s.rta) { | ||
46 | edac_pci_handle_npe(pci, "Received Target Abort"); | ||
47 | cfg01.s.rta = 1; /* Reset */ | ||
48 | octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32); | ||
49 | } | ||
50 | if (cfg01.s.sta) { | ||
51 | edac_pci_handle_npe(pci, "Signaled Target Abort"); | ||
52 | cfg01.s.sta = 1; /* Reset */ | ||
53 | octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32); | ||
54 | } | ||
55 | if (cfg01.s.mdpe) { | ||
56 | edac_pci_handle_npe(pci, "Master Data Parity Error"); | ||
57 | cfg01.s.mdpe = 1; /* Reset */ | ||
58 | octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32); | ||
59 | } | ||
60 | if (cfg01.s.mdpe) { | ||
61 | edac_pci_handle_npe(pci, "Master Data Parity Error"); | ||
62 | cfg01.s.mdpe = 1; /* Reset */ | ||
63 | octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32); | ||
64 | } | ||
65 | } | ||
66 | |||
67 | static int __devinit co_pci_probe(struct platform_device *pdev) | ||
68 | { | ||
69 | struct edac_pci_ctl_info *pci; | ||
70 | int res = 0; | ||
71 | |||
72 | pci = edac_pci_alloc_ctl_info(0, "octeon_pci_err"); | ||
73 | if (!pci) | ||
74 | return -ENOMEM; | ||
75 | |||
76 | pci->dev = &pdev->dev; | ||
77 | platform_set_drvdata(pdev, pci); | ||
78 | pci->dev_name = dev_name(&pdev->dev); | ||
79 | |||
80 | pci->mod_name = "octeon-pci"; | ||
81 | pci->ctl_name = "octeon_pci_err"; | ||
82 | pci->edac_check = co_pci_poll; | ||
83 | |||
84 | if (edac_pci_add_device(pci, 0) > 0) { | ||
85 | pr_err("%s: edac_pci_add_device() failed\n", __func__); | ||
86 | goto err; | ||
87 | } | ||
88 | |||
89 | return 0; | ||
90 | |||
91 | err: | ||
92 | edac_pci_free_ctl_info(pci); | ||
93 | |||
94 | return res; | ||
95 | } | ||
96 | |||
97 | static int co_pci_remove(struct platform_device *pdev) | ||
98 | { | ||
99 | struct edac_pci_ctl_info *pci = platform_get_drvdata(pdev); | ||
100 | |||
101 | edac_pci_del_device(&pdev->dev); | ||
102 | edac_pci_free_ctl_info(pci); | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static struct platform_driver co_pci_driver = { | ||
108 | .probe = co_pci_probe, | ||
109 | .remove = co_pci_remove, | ||
110 | .driver = { | ||
111 | .name = "co_pci_edac", | ||
112 | } | ||
113 | }; | ||
114 | |||
115 | static int __init co_edac_init(void) | ||
116 | { | ||
117 | int ret; | ||
118 | |||
119 | ret = platform_driver_register(&co_pci_driver); | ||
120 | if (ret) | ||
121 | pr_warning(EDAC_MOD_STR " PCI EDAC failed to register\n"); | ||
122 | |||
123 | return ret; | ||
124 | } | ||
125 | |||
126 | static void __exit co_edac_exit(void) | ||
127 | { | ||
128 | platform_driver_unregister(&co_pci_driver); | ||
129 | } | ||
130 | |||
131 | module_init(co_edac_init); | ||
132 | module_exit(co_edac_exit); | ||
133 | |||
134 | MODULE_LICENSE("GPL"); | ||
135 | MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>"); | ||