aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS9
-rw-r--r--arch/mips/Kconfig1
-rw-r--r--arch/mips/cavium-octeon/setup.c30
-rw-r--r--arch/mips/mm/c-octeon.c46
-rw-r--r--arch/mips/pci/pci-octeon.c4
-rw-r--r--drivers/edac/Kconfig33
-rw-r--r--drivers/edac/Makefile5
-rw-r--r--drivers/edac/octeon_edac-l2c.c118
-rw-r--r--drivers/edac/octeon_edac-lmc.c150
-rw-r--r--drivers/edac/octeon_edac-lmc.h78
-rw-r--r--drivers/edac/octeon_edac-pc.c140
-rw-r--r--drivers/edac/octeon_edac-pci.c135
12 files changed, 725 insertions, 24 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 9386a63ea8f6..5c97541eb24c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2722,6 +2722,15 @@ W: bluesmoke.sourceforge.net
2722S: Maintained 2722S: Maintained
2723F: drivers/edac/amd64_edac* 2723F: drivers/edac/amd64_edac*
2724 2724
2725EDAC-CAVIUM
2726M: Ralf Baechle <ralf@linux-mips.org>
2727M: David Daney <david.daney@cavium.com>
2728L: linux-edac@vger.kernel.org
2729L: linux-mips@linux-mips.org
2730W: bluesmoke.sourceforge.net
2731S: Supported
2732F: drivers/edac/octeon_edac*
2733
2725EDAC-E752X 2734EDAC-E752X
2726M: Mark Gross <mark.gross@intel.com> 2735M: Mark Gross <mark.gross@intel.com>
2727M: Doug Thompson <dougthompson@xmission.com> 2736M: Doug Thompson <dougthompson@xmission.com>
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 397194a263ce..b47d591c03dd 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -774,6 +774,7 @@ config CAVIUM_OCTEON_REFERENCE_BOARD
774 select DMA_COHERENT 774 select DMA_COHERENT
775 select SYS_SUPPORTS_64BIT_KERNEL 775 select SYS_SUPPORTS_64BIT_KERNEL
776 select SYS_SUPPORTS_BIG_ENDIAN 776 select SYS_SUPPORTS_BIG_ENDIAN
777 select EDAC_SUPPORT
777 select SYS_SUPPORTS_HOTPLUG_CPU 778 select SYS_SUPPORTS_HOTPLUG_CPU
778 select SYS_HAS_EARLY_PRINTK 779 select SYS_HAS_EARLY_PRINTK
779 select SYS_HAS_CPU_CAVIUM_OCTEON 780 select SYS_HAS_CPU_CAVIUM_OCTEON
diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c
index 04dd8ff0e0d8..60ed700a956d 100644
--- a/arch/mips/cavium-octeon/setup.c
+++ b/arch/mips/cavium-octeon/setup.c
@@ -4,9 +4,11 @@
4 * for more details. 4 * for more details.
5 * 5 *
6 * Copyright (C) 2004-2007 Cavium Networks 6 * Copyright (C) 2004-2007 Cavium Networks
7 * Copyright (C) 2008 Wind River Systems 7 * Copyright (C) 2008, 2009 Wind River Systems
8 * written by Ralf Baechle <ralf@linux-mips.org>
8 */ 9 */
9#include <linux/init.h> 10#include <linux/init.h>
11#include <linux/kernel.h>
10#include <linux/console.h> 12#include <linux/console.h>
11#include <linux/delay.h> 13#include <linux/delay.h>
12#include <linux/export.h> 14#include <linux/export.h>
@@ -821,3 +823,29 @@ void __init device_tree_init(void)
821 } 823 }
822 unflatten_device_tree(); 824 unflatten_device_tree();
823} 825}
826
827static char *edac_device_names[] = {
828 "co_l2c_edac",
829 "co_lmc_edac",
830 "co_pc_edac",
831};
832
833static int __init edac_devinit(void)
834{
835 struct platform_device *dev;
836 int i, err = 0;
837 char *name;
838
839 for (i = 0; i < ARRAY_SIZE(edac_device_names); i++) {
840 name = edac_device_names[i];
841 dev = platform_device_register_simple(name, -1, NULL, 0);
842 if (IS_ERR(dev)) {
843 pr_err("Registation of %s failed!\n", name);
844 err = PTR_ERR(dev);
845 }
846 }
847
848 return err;
849}
850
851device_initcall(edac_devinit);
diff --git a/arch/mips/mm/c-octeon.c b/arch/mips/mm/c-octeon.c
index 44e69e7a4519..9f67553762d5 100644
--- a/arch/mips/mm/c-octeon.c
+++ b/arch/mips/mm/c-octeon.c
@@ -5,6 +5,7 @@
5 * 5 *
6 * Copyright (C) 2005-2007 Cavium Networks 6 * Copyright (C) 2005-2007 Cavium Networks
7 */ 7 */
8#include <linux/export.h>
8#include <linux/init.h> 9#include <linux/init.h>
9#include <linux/kernel.h> 10#include <linux/kernel.h>
10#include <linux/sched.h> 11#include <linux/sched.h>
@@ -28,6 +29,7 @@
28#include <asm/octeon/octeon.h> 29#include <asm/octeon/octeon.h>
29 30
30unsigned long long cache_err_dcache[NR_CPUS]; 31unsigned long long cache_err_dcache[NR_CPUS];
32EXPORT_SYMBOL_GPL(cache_err_dcache);
31 33
32/** 34/**
33 * Octeon automatically flushes the dcache on tlb changes, so 35 * Octeon automatically flushes the dcache on tlb changes, so
@@ -288,42 +290,42 @@ void __cpuinit octeon_cache_init(void)
288 * Handle a cache error exception 290 * Handle a cache error exception
289 */ 291 */
290 292
291static void cache_parity_error_octeon(int non_recoverable) 293static RAW_NOTIFIER_HEAD(co_cache_error_chain);
294
295int register_co_cache_error_notifier(struct notifier_block *nb)
292{ 296{
293 unsigned long coreid = cvmx_get_core_num(); 297 return raw_notifier_chain_register(&co_cache_error_chain, nb);
294 uint64_t icache_err = read_octeon_c0_icacheerr(); 298}
295 299EXPORT_SYMBOL_GPL(register_co_cache_error_notifier);
296 pr_err("Cache error exception:\n");
297 pr_err("cp0_errorepc == %lx\n", read_c0_errorepc());
298 if (icache_err & 1) {
299 pr_err("CacheErr (Icache) == %llx\n",
300 (unsigned long long)icache_err);
301 write_octeon_c0_icacheerr(0);
302 }
303 if (cache_err_dcache[coreid] & 1) {
304 pr_err("CacheErr (Dcache) == %llx\n",
305 (unsigned long long)cache_err_dcache[coreid]);
306 cache_err_dcache[coreid] = 0;
307 }
308 300
309 if (non_recoverable) 301int unregister_co_cache_error_notifier(struct notifier_block *nb)
310 panic("Can't handle cache error: nested exception"); 302{
303 return raw_notifier_chain_unregister(&co_cache_error_chain, nb);
304}
305EXPORT_SYMBOL_GPL(unregister_co_cache_error_notifier);
306
307static inline int co_cache_error_call_notifiers(unsigned long val)
308{
309 return raw_notifier_call_chain(&co_cache_error_chain, val, NULL);
311} 310}
312 311
313/** 312/**
314 * Called when the the exception is recoverable 313 * Called when the the exception is recoverable
315 */ 314 */
316
317asmlinkage void cache_parity_error_octeon_recoverable(void) 315asmlinkage void cache_parity_error_octeon_recoverable(void)
318{ 316{
319 cache_parity_error_octeon(0); 317 co_cache_error_call_notifiers(0);
320} 318}
321 319
322/** 320/**
323 * Called when the the exception is not recoverable 321 * Called when the the exception is not recoverable
322 *
323 * The issue not that the cache error exception itself was non-recoverable
324 * but that due to nesting of exception may have lost some state so can't
325 * continue.
324 */ 326 */
325
326asmlinkage void cache_parity_error_octeon_non_recoverable(void) 327asmlinkage void cache_parity_error_octeon_non_recoverable(void)
327{ 328{
328 cache_parity_error_octeon(1); 329 co_cache_error_call_notifiers(1);
330 panic("Can't handle cache error: nested exception");
329} 331}
diff --git a/arch/mips/pci/pci-octeon.c b/arch/mips/pci/pci-octeon.c
index 4b0c347d7a82..8eb2ee345d03 100644
--- a/arch/mips/pci/pci-octeon.c
+++ b/arch/mips/pci/pci-octeon.c
@@ -11,6 +11,7 @@
11#include <linux/interrupt.h> 11#include <linux/interrupt.h>
12#include <linux/time.h> 12#include <linux/time.h>
13#include <linux/delay.h> 13#include <linux/delay.h>
14#include <linux/platform_device.h>
14#include <linux/swiotlb.h> 15#include <linux/swiotlb.h>
15 16
16#include <asm/time.h> 17#include <asm/time.h>
@@ -704,6 +705,9 @@ static int __init octeon_pci_setup(void)
704 */ 705 */
705 cvmx_write_csr(CVMX_NPI_PCI_INT_SUM2, -1); 706 cvmx_write_csr(CVMX_NPI_PCI_INT_SUM2, -1);
706 707
708 if (IS_ERR(platform_device_register_simple("co_pci_edac", 0, NULL, 0)))
709 pr_err("Registation of co_pci_edac failed!\n");
710
707 octeon_pci_dma_init(); 711 octeon_pci_dma_init();
708 712
709 return 0; 713 return 0;
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 409b92b8d346..a9db20815a39 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -7,7 +7,7 @@
7menuconfig EDAC 7menuconfig EDAC
8 bool "EDAC (Error Detection And Correction) reporting" 8 bool "EDAC (Error Detection And Correction) reporting"
9 depends on HAS_IOMEM 9 depends on HAS_IOMEM
10 depends on X86 || PPC || TILE || ARM 10 depends on X86 || PPC || TILE || ARM || EDAC_SUPPORT
11 help 11 help
12 EDAC is designed to report errors in the core system. 12 EDAC is designed to report errors in the core system.
13 These are low-level errors that are reported in the CPU or 13 These are low-level errors that are reported in the CPU or
@@ -27,6 +27,9 @@ menuconfig EDAC
27 There is also a mailing list for the EDAC project, which can 27 There is also a mailing list for the EDAC project, which can
28 be found via the sourceforge page. 28 be found via the sourceforge page.
29 29
30config EDAC_SUPPORT
31 bool
32
30if EDAC 33if EDAC
31 34
32comment "Reporting subsystems" 35comment "Reporting subsystems"
@@ -316,4 +319,32 @@ config EDAC_HIGHBANK_L2
316 Support for error detection and correction on the 319 Support for error detection and correction on the
317 Calxeda Highbank memory controller. 320 Calxeda Highbank memory controller.
318 321
322config EDAC_OCTEON_PC
323 tristate "Cavium Octeon Primary Caches"
324 depends on EDAC_MM_EDAC && CPU_CAVIUM_OCTEON
325 help
326 Support for error detection and correction on the primary caches of
327 the cnMIPS cores of Cavium Octeon family SOCs.
328
329config EDAC_OCTEON_L2C
330 tristate "Cavium Octeon Secondary Caches (L2C)"
331 depends on EDAC_MM_EDAC && CPU_CAVIUM_OCTEON
332 help
333 Support for error detection and correction on the
334 Cavium Octeon family of SOCs.
335
336config EDAC_OCTEON_LMC
337 tristate "Cavium Octeon DRAM Memory Controller (LMC)"
338 depends on EDAC_MM_EDAC && CPU_CAVIUM_OCTEON
339 help
340 Support for error detection and correction on the
341 Cavium Octeon family of SOCs.
342
343config EDAC_OCTEON_PCI
344 tristate "Cavium Octeon PCI Controller"
345 depends on EDAC_MM_EDAC && PCI && CPU_CAVIUM_OCTEON
346 help
347 Support for error detection and correction on the
348 Cavium Octeon family of SOCs.
349
319endif # EDAC 350endif # EDAC
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index 7e5129a733f8..5608a9ba61b7 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -58,3 +58,8 @@ obj-$(CONFIG_EDAC_TILE) += tile_edac.o
58 58
59obj-$(CONFIG_EDAC_HIGHBANK_MC) += highbank_mc_edac.o 59obj-$(CONFIG_EDAC_HIGHBANK_MC) += highbank_mc_edac.o
60obj-$(CONFIG_EDAC_HIGHBANK_L2) += highbank_l2_edac.o 60obj-$(CONFIG_EDAC_HIGHBANK_L2) += highbank_l2_edac.o
61
62obj-$(CONFIG_EDAC_OCTEON_PC) += octeon_edac-pc.o
63obj-$(CONFIG_EDAC_OCTEON_L2C) += octeon_edac-l2c.o
64obj-$(CONFIG_EDAC_OCTEON_LMC) += octeon_edac-lmc.o
65obj-$(CONFIG_EDAC_OCTEON_PCI) += octeon_edac-pci.o
diff --git a/drivers/edac/octeon_edac-l2c.c b/drivers/edac/octeon_edac-l2c.c
new file mode 100644
index 000000000000..5f459aa451bf
--- /dev/null
+++ b/drivers/edac/octeon_edac-l2c.c
@@ -0,0 +1,118 @@
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
17#include "edac_core.h"
18#include "edac_module.h"
19
20#define EDAC_MOD_STR "octeon-l2c"
21
22static void co_l2c_poll(struct edac_device_ctl_info *l2c)
23{
24 union cvmx_l2t_err l2t_err;
25
26 l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR);
27 if (l2t_err.s.sec_err) {
28 edac_device_handle_ce(l2c, 0, 0,
29 "Single bit error (corrected)");
30 l2t_err.s.sec_err = 1; /* Reset */
31 cvmx_write_csr(CVMX_L2T_ERR, l2t_err.u64);
32 }
33 if (l2t_err.s.ded_err) {
34 edac_device_handle_ue(l2c, 0, 0,
35 "Double bit error (corrected)");
36 l2t_err.s.ded_err = 1; /* Reset */
37 cvmx_write_csr(CVMX_L2T_ERR, l2t_err.u64);
38 }
39}
40
41static int __devinit co_l2c_probe(struct platform_device *pdev)
42{
43 struct edac_device_ctl_info *l2c;
44 union cvmx_l2t_err l2t_err;
45 int res = 0;
46
47 l2c = edac_device_alloc_ctl_info(0, "l2c", 1, NULL, 0, 0,
48 NULL, 0, edac_device_alloc_index());
49 if (!l2c)
50 return -ENOMEM;
51
52 l2c->dev = &pdev->dev;
53 platform_set_drvdata(pdev, l2c);
54 l2c->dev_name = dev_name(&pdev->dev);
55
56 l2c->mod_name = "octeon-l2c";
57 l2c->ctl_name = "octeon_l2c_err";
58 l2c->edac_check = co_l2c_poll;
59
60 if (edac_device_add_device(l2c) > 0) {
61 pr_err("%s: edac_device_add_device() failed\n", __func__);
62 goto err;
63 }
64
65 l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR);
66 l2t_err.s.sec_intena = 0; /* We poll */
67 l2t_err.s.ded_intena = 0;
68 l2t_err.s.sec_err = 1; /* Clear, just in case */
69 l2t_err.s.ded_err = 1;
70 cvmx_write_csr(CVMX_L2T_ERR, l2t_err.u64);
71
72 return 0;
73
74err:
75 edac_device_free_ctl_info(l2c);
76
77 return res;
78}
79
80static int co_l2c_remove(struct platform_device *pdev)
81{
82 struct edac_device_ctl_info *l2c = platform_get_drvdata(pdev);
83
84 edac_device_del_device(&pdev->dev);
85 edac_device_free_ctl_info(l2c);
86
87 return 0;
88}
89
90static struct platform_driver co_l2c_driver = {
91 .probe = co_l2c_probe,
92 .remove = co_l2c_remove,
93 .driver = {
94 .name = "co_l2c_edac",
95 }
96};
97
98static int __init co_edac_init(void)
99{
100 int ret;
101
102 ret = platform_driver_register(&co_l2c_driver);
103 if (ret)
104 pr_warning(EDAC_MOD_STR " EDAC failed to register\n");
105
106 return ret;
107}
108
109static void __exit co_edac_exit(void)
110{
111 platform_driver_unregister(&co_l2c_driver);
112}
113
114module_init(co_edac_init);
115module_exit(co_edac_exit);
116
117MODULE_LICENSE("GPL");
118MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
diff --git a/drivers/edac/octeon_edac-lmc.c b/drivers/edac/octeon_edac-lmc.c
new file mode 100644
index 000000000000..e0c1e44187bc
--- /dev/null
+++ b/drivers/edac/octeon_edac-lmc.c
@@ -0,0 +1,150 @@
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
17#include "edac_core.h"
18#include "edac_module.h"
19#include "octeon_edac-lmc.h"
20
21#define EDAC_MOD_STR "octeon"
22
23static struct mem_ctl_info *mc_cavium;
24static void *lmc_base;
25
26static void co_lmc_poll(struct mem_ctl_info *mci)
27{
28 union lmc_mem_cfg0 cfg0;
29 union lmc_fadr fadr;
30 char msg[64];
31
32 fadr.u64 = readq(lmc_base + LMC_FADR);
33 cfg0.u64 = readq(lmc_base + LMC_MEM_CFG0);
34 snprintf(msg, sizeof(msg), "DIMM %d rank %d bank %d row %d col %d",
35 fadr.fdimm, fadr.fbunk, fadr.fbank, fadr.frow, fadr.fcol);
36
37 if (cfg0.sec_err) {
38 edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 0, 0, 0, -1, -1, -1,
39 msg, "");
40
41 cfg0.intr_sec_ena = -1; /* Done, re-arm */
42 }
43
44 if (cfg0.ded_err) {
45 edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0, -1, -1, -1,
46 msg, "");
47 cfg0.intr_ded_ena = -1; /* Done, re-arm */
48 }
49
50 writeq(cfg0.u64, lmc_base + LMC_MEM_CFG0);
51}
52
53static int __devinit co_lmc_probe(struct platform_device *pdev)
54{
55 struct mem_ctl_info *mci;
56 union lmc_mem_cfg0 cfg0;
57 int res = 0;
58
59 mci = edac_mc_alloc(0, 0, 0, 0);
60 if (!mci)
61 return -ENOMEM;
62
63 mci->pdev = &pdev->dev;
64 platform_set_drvdata(pdev, mci);
65 mci->dev_name = dev_name(&pdev->dev);
66
67 mci->mod_name = "octeon-lmc";
68 mci->ctl_name = "co_lmc_err";
69 mci->edac_check = co_lmc_poll;
70
71 if (edac_mc_add_mc(mci) > 0) {
72 pr_err("%s: edac_mc_add_mc() failed\n", __func__);
73 goto err;
74 }
75
76 cfg0.u64 = readq(lmc_base + LMC_MEM_CFG0); /* We poll */
77 cfg0.intr_ded_ena = 0;
78 cfg0.intr_sec_ena = 0;
79 writeq(cfg0.u64, lmc_base + LMC_MEM_CFG0);
80
81 mc_cavium = mci;
82
83 return 0;
84
85err:
86 edac_mc_free(mci);
87
88 return res;
89}
90
91static int co_lmc_remove(struct platform_device *pdev)
92{
93 struct mem_ctl_info *mci = platform_get_drvdata(pdev);
94
95 mc_cavium = NULL;
96 edac_mc_del_mc(&pdev->dev);
97 edac_mc_free(mci);
98
99 return 0;
100}
101
102static struct platform_driver co_lmc_driver = {
103 .probe = co_lmc_probe,
104 .remove = co_lmc_remove,
105 .driver = {
106 .name = "co_lmc_edac",
107 }
108};
109
110static int __init co_edac_init(void)
111{
112 union lmc_mem_cfg0 cfg0;
113 int ret;
114
115 lmc_base = ioremap_nocache(LMC_BASE, LMC_SIZE);
116 if (!lmc_base)
117 return -ENOMEM;
118
119 cfg0.u64 = readq(lmc_base + LMC_MEM_CFG0);
120 if (!cfg0.ecc_ena) {
121 pr_info(EDAC_MOD_STR " LMC EDAC: ECC disabled, good bye\n");
122 ret = -ENODEV;
123 goto out;
124 }
125
126 ret = platform_driver_register(&co_lmc_driver);
127 if (ret) {
128 pr_warning(EDAC_MOD_STR " LMC EDAC failed to register\n");
129 goto out;
130 }
131
132 return ret;
133
134out:
135 iounmap(lmc_base);
136
137 return ret;
138}
139
140static void __exit co_edac_exit(void)
141{
142 platform_driver_unregister(&co_lmc_driver);
143 iounmap(lmc_base);
144}
145
146module_init(co_edac_init);
147module_exit(co_edac_exit);
148
149MODULE_LICENSE("GPL");
150MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
diff --git a/drivers/edac/octeon_edac-lmc.h b/drivers/edac/octeon_edac-lmc.h
new file mode 100644
index 000000000000..246dc525bc10
--- /dev/null
+++ b/drivers/edac/octeon_edac-lmc.h
@@ -0,0 +1,78 @@
1/*
2 * LMC Registers, see chapter 2.5
3 *
4 * These are RSL Type registers and are accessed indirectly across the
5 * I/O bus, so accesses are slowish. Not that it matters. Any size load is
6 * ok but stores must be 64-bit.
7 */
8#define LMC_BASE 0x0001180088000000
9#define LMC_SIZE 0xb8
10
11#define LMC_MEM_CFG0 0x0000000000000000
12#define LMC_MEM_CFG1 0x0000000000000008
13#define LMC_CTL 0x0000000000000010
14#define LMC_DDR2_CTL 0x0000000000000018
15#define LMC_FADR 0x0000000000000020
16#define LMC_FADR_FDIMM
17#define LMC_FADR_FBUNK
18#define LMC_FADR_FBANK
19#define LMC_FADR_FROW
20#define LMC_FADR_FCOL
21#define LMC_COMP_CTL 0x0000000000000028
22#define LMC_WODT_CTL 0x0000000000000030
23#define LMC_ECC_SYND 0x0000000000000038
24#define LMC_IFB_CNT_LO 0x0000000000000048
25#define LMC_IFB_CNT_HI 0x0000000000000050
26#define LMC_OPS_CNT_LO 0x0000000000000058
27#define LMC_OPS_CNT_HI 0x0000000000000060
28#define LMC_DCLK_CNT_LO 0x0000000000000068
29#define LMC_DCLK_CNT_HI 0x0000000000000070
30#define LMC_DELAY_CFG 0x0000000000000088
31#define LMC_CTL1 0x0000000000000090
32#define LMC_DUAL_MEM_CONFIG 0x0000000000000098
33#define LMC_RODT_COMP_CTL 0x00000000000000A0
34#define LMC_PLL_CTL 0x00000000000000A8
35#define LMC_PLL_STATUS 0x00000000000000B0
36
37union lmc_mem_cfg0 {
38 uint64_t u64;
39 struct {
40 uint64_t reserved_32_63:32;
41 uint64_t reset:1;
42 uint64_t silo_qc:1;
43 uint64_t bunk_ena:1;
44 uint64_t ded_err:4;
45 uint64_t sec_err:4;
46 uint64_t intr_ded_ena:1;
47 uint64_t intr_sec_ena:1;
48 uint64_t reserved_15_18:4;
49 uint64_t ref_int:5;
50 uint64_t pbank_lsb:4;
51 uint64_t row_lsb:3;
52 uint64_t ecc_ena:1;
53 uint64_t init_start:1;
54 };
55};
56
57union lmc_fadr {
58 uint64_t u64;
59 struct {
60 uint64_t reserved_32_63:32;
61 uint64_t fdimm:2;
62 uint64_t fbunk:1;
63 uint64_t fbank:3;
64 uint64_t frow:14;
65 uint64_t fcol:12;
66 };
67};
68
69union lmc_ecc_synd {
70 uint64_t u64;
71 struct {
72 uint64_t reserved_32_63:32;
73 uint64_t mrdsyn3:8;
74 uint64_t mrdsyn2:8;
75 uint64_t mrdsyn1:8;
76 uint64_t mrdsyn0:8;
77 };
78};
diff --git a/drivers/edac/octeon_edac-pc.c b/drivers/edac/octeon_edac-pc.c
new file mode 100644
index 000000000000..9d13061744e4
--- /dev/null
+++ b/drivers/edac/octeon_edac-pc.c
@@ -0,0 +1,140 @@
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/interrupt.h>
13#include <linux/io.h>
14#include <linux/edac.h>
15
16#include "edac_core.h"
17#include "edac_module.h"
18
19#include <asm/octeon/cvmx.h>
20#include <asm/mipsregs.h>
21
22#define EDAC_MOD_STR "octeon"
23
24extern int register_co_cache_error_notifier(struct notifier_block *nb);
25extern int unregister_co_cache_error_notifier(struct notifier_block *nb);
26
27extern unsigned long long cache_err_dcache[NR_CPUS];
28
29static struct edac_device_ctl_info *ed_cavium;
30
31/*
32 * EDAC CPU cache error callback
33 *
34 */
35
36static int co_cache_error_event(struct notifier_block *this,
37 unsigned long event, void *ptr)
38{
39 unsigned int core = cvmx_get_core_num();
40 unsigned int cpu = smp_processor_id();
41 uint64_t icache_err = read_octeon_c0_icacheerr();
42 struct edac_device_ctl_info *ed = ed_cavium;
43
44 edac_device_printk(ed, KERN_ERR,
45 "Cache error exception on core %d / processor %d:\n",
46 core, cpu);
47 edac_device_printk(ed, KERN_ERR,
48 "cp0_errorepc == %lx\n", read_c0_errorepc());
49 if (icache_err & 1) {
50 edac_device_printk(ed, KERN_ERR, "CacheErr (Icache) == %llx\n",
51 (unsigned long long)icache_err);
52 write_octeon_c0_icacheerr(0);
53 edac_device_handle_ce(ed, 0, 0, ed->ctl_name);
54 }
55 if (cache_err_dcache[core] & 1) {
56 edac_device_printk(ed, KERN_ERR, "CacheErr (Dcache) == %llx\n",
57 (unsigned long long)cache_err_dcache[core]);
58 cache_err_dcache[core] = 0;
59 edac_device_handle_ue(ed, 0, 0, ed->ctl_name);
60 }
61
62 return NOTIFY_DONE;
63}
64
65static struct notifier_block co_cache_error_notifier = {
66 .notifier_call = co_cache_error_event,
67};
68
69static int __devinit co_cache_error_probe(struct platform_device *pdev)
70{
71 struct edac_device_ctl_info *ed;
72 int res = 0;
73
74 ed = edac_device_alloc_ctl_info(0, "cpu", 1, NULL, 0, 0, NULL, 0,
75 edac_device_alloc_index());
76
77 ed->dev = &pdev->dev;
78 platform_set_drvdata(pdev, ed);
79 ed->dev_name = dev_name(&pdev->dev);
80
81 ed->mod_name = "octeon-cpu";
82 ed->ctl_name = "co_cpu_err";
83
84 if (edac_device_add_device(ed) > 0) {
85 pr_err("%s: edac_device_add_device() failed\n", __func__);
86 goto err;
87 }
88
89 register_co_cache_error_notifier(&co_cache_error_notifier);
90 ed_cavium = ed;
91
92 return 0;
93
94err:
95 edac_device_free_ctl_info(ed);
96
97 return res;
98}
99
100static int co_cache_error_remove(struct platform_device *pdev)
101{
102 struct edac_device_ctl_info *ed = platform_get_drvdata(pdev);
103
104 unregister_co_cache_error_notifier(&co_cache_error_notifier);
105 ed_cavium = NULL;
106 edac_device_del_device(&pdev->dev);
107 edac_device_free_ctl_info(ed);
108
109 return 0;
110}
111
112static struct platform_driver co_cache_error_driver = {
113 .probe = co_cache_error_probe,
114 .remove = co_cache_error_remove,
115 .driver = {
116 .name = "co_pc_edac",
117 }
118};
119
120static int __init co_edac_init(void)
121{
122 int ret;
123
124 ret = platform_driver_register(&co_cache_error_driver);
125 if (ret)
126 pr_warning(EDAC_MOD_STR "CPU err failed to register\n");
127
128 return ret;
129}
130
131static void __exit co_edac_exit(void)
132{
133 platform_driver_unregister(&co_cache_error_driver);
134}
135
136module_init(co_edac_init);
137module_exit(co_edac_exit);
138
139MODULE_LICENSE("GPL");
140MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
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
25static 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
67static 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
91err:
92 edac_pci_free_ctl_info(pci);
93
94 return res;
95}
96
97static 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
107static 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
115static 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
126static void __exit co_edac_exit(void)
127{
128 platform_driver_unregister(&co_pci_driver);
129}
130
131module_init(co_edac_init);
132module_exit(co_edac_exit);
133
134MODULE_LICENSE("GPL");
135MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");