aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac/octeon_edac-pc.c
diff options
context:
space:
mode:
authorDavid Daney <david.daney@cavium.com>2012-11-15 16:58:59 -0500
committerRalf Baechle <ralf@linux-mips.org>2012-12-13 12:15:26 -0500
commite1ced09797776dfd4a2a7b04b9ee7e97ab1e64be (patch)
tree473934ca424e0e10f235bcd9ae97781349af5495 /drivers/edac/octeon_edac-pc.c
parentabe105a4d8c5ee2aa2acef33c5d163e5d187598f (diff)
MIPS/EDAC: Improve OCTEON EDAC support.
Some initialization errors are reported with the existing OCTEON EDAC support patch. Also some parts have more than one memory controller. Fix the errors and add multiple controllers if present. Signed-off-by: David Daney <david.daney@cavium.com>
Diffstat (limited to 'drivers/edac/octeon_edac-pc.c')
-rw-r--r--drivers/edac/octeon_edac-pc.c137
1 files changed, 70 insertions, 67 deletions
diff --git a/drivers/edac/octeon_edac-pc.c b/drivers/edac/octeon_edac-pc.c
index 9d13061744e4..14a5e57f2b32 100644
--- a/drivers/edac/octeon_edac-pc.c
+++ b/drivers/edac/octeon_edac-pc.c
@@ -3,6 +3,8 @@
3 * License. See the file "COPYING" in the main directory of this archive 3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details. 4 * for more details.
5 * 5 *
6 * Copyright (C) 2012 Cavium, Inc.
7 *
6 * Copyright (C) 2009 Wind River Systems, 8 * Copyright (C) 2009 Wind River Systems,
7 * written by Ralf Baechle <ralf@linux-mips.org> 9 * written by Ralf Baechle <ralf@linux-mips.org>
8 */ 10 */
@@ -19,93 +21,112 @@
19#include <asm/octeon/cvmx.h> 21#include <asm/octeon/cvmx.h>
20#include <asm/mipsregs.h> 22#include <asm/mipsregs.h>
21 23
22#define EDAC_MOD_STR "octeon"
23
24extern int register_co_cache_error_notifier(struct notifier_block *nb); 24extern int register_co_cache_error_notifier(struct notifier_block *nb);
25extern int unregister_co_cache_error_notifier(struct notifier_block *nb); 25extern int unregister_co_cache_error_notifier(struct notifier_block *nb);
26 26
27extern unsigned long long cache_err_dcache[NR_CPUS]; 27extern unsigned long long cache_err_dcache[NR_CPUS];
28 28
29static struct edac_device_ctl_info *ed_cavium; 29struct co_cache_error {
30 struct notifier_block notifier;
31 struct edac_device_ctl_info *ed;
32};
30 33
31/* 34/**
32 * EDAC CPU cache error callback 35 * EDAC CPU cache error callback
33 * 36 *
37 * @event: non-zero if unrecoverable.
34 */ 38 */
35
36static int co_cache_error_event(struct notifier_block *this, 39static int co_cache_error_event(struct notifier_block *this,
37 unsigned long event, void *ptr) 40 unsigned long event, void *ptr)
38{ 41{
42 struct co_cache_error *p = container_of(this, struct co_cache_error,
43 notifier);
44
39 unsigned int core = cvmx_get_core_num(); 45 unsigned int core = cvmx_get_core_num();
40 unsigned int cpu = smp_processor_id(); 46 unsigned int cpu = smp_processor_id();
41 uint64_t icache_err = read_octeon_c0_icacheerr(); 47 u64 icache_err = read_octeon_c0_icacheerr();
42 struct edac_device_ctl_info *ed = ed_cavium; 48 u64 dcache_err;
43 49
44 edac_device_printk(ed, KERN_ERR, 50 if (event) {
45 "Cache error exception on core %d / processor %d:\n", 51 dcache_err = cache_err_dcache[core];
46 core, cpu); 52 cache_err_dcache[core] = 0;
47 edac_device_printk(ed, KERN_ERR, 53 } else {
48 "cp0_errorepc == %lx\n", read_c0_errorepc()); 54 dcache_err = read_octeon_c0_dcacheerr();
55 }
56
49 if (icache_err & 1) { 57 if (icache_err & 1) {
50 edac_device_printk(ed, KERN_ERR, "CacheErr (Icache) == %llx\n", 58 edac_device_printk(p->ed, KERN_ERR,
51 (unsigned long long)icache_err); 59 "CacheErr (Icache):%llx, core %d/cpu %d, cp0_errorepc == %lx\n",
60 (unsigned long long)icache_err, core, cpu,
61 read_c0_errorepc());
52 write_octeon_c0_icacheerr(0); 62 write_octeon_c0_icacheerr(0);
53 edac_device_handle_ce(ed, 0, 0, ed->ctl_name); 63 edac_device_handle_ce(p->ed, cpu, 1, "icache");
54 } 64 }
55 if (cache_err_dcache[core] & 1) { 65 if (dcache_err & 1) {
56 edac_device_printk(ed, KERN_ERR, "CacheErr (Dcache) == %llx\n", 66 edac_device_printk(p->ed, KERN_ERR,
57 (unsigned long long)cache_err_dcache[core]); 67 "CacheErr (Dcache):%llx, core %d/cpu %d, cp0_errorepc == %lx\n",
58 cache_err_dcache[core] = 0; 68 (unsigned long long)dcache_err, core, cpu,
59 edac_device_handle_ue(ed, 0, 0, ed->ctl_name); 69 read_c0_errorepc());
70 if (event)
71 edac_device_handle_ue(p->ed, cpu, 0, "dcache");
72 else
73 edac_device_handle_ce(p->ed, cpu, 0, "dcache");
74
75 /* Clear the error indication */
76 if (OCTEON_IS_MODEL(OCTEON_FAM_2))
77 write_octeon_c0_dcacheerr(1);
78 else
79 write_octeon_c0_dcacheerr(0);
60 } 80 }
61 81
62 return NOTIFY_DONE; 82 return NOTIFY_STOP;
63} 83}
64 84
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) 85static int __devinit co_cache_error_probe(struct platform_device *pdev)
70{ 86{
71 struct edac_device_ctl_info *ed; 87 struct co_cache_error *p = devm_kzalloc(&pdev->dev, sizeof(*p),
72 int res = 0; 88 GFP_KERNEL);
89 if (!p)
90 return -ENOMEM;
91
92 p->notifier.notifier_call = co_cache_error_event;
93 platform_set_drvdata(pdev, p);
94
95 p->ed = edac_device_alloc_ctl_info(0, "cpu", num_possible_cpus(),
96 "cache", 2, 0, NULL, 0,
97 edac_device_alloc_index());
98 if (!p->ed)
99 goto err;
73 100
74 ed = edac_device_alloc_ctl_info(0, "cpu", 1, NULL, 0, 0, NULL, 0, 101 p->ed->dev = &pdev->dev;
75 edac_device_alloc_index());
76 102
77 ed->dev = &pdev->dev; 103 p->ed->dev_name = dev_name(&pdev->dev);
78 platform_set_drvdata(pdev, ed);
79 ed->dev_name = dev_name(&pdev->dev);
80 104
81 ed->mod_name = "octeon-cpu"; 105 p->ed->mod_name = "octeon-cpu";
82 ed->ctl_name = "co_cpu_err"; 106 p->ed->ctl_name = "cache";
83 107
84 if (edac_device_add_device(ed) > 0) { 108 if (edac_device_add_device(p->ed)) {
85 pr_err("%s: edac_device_add_device() failed\n", __func__); 109 pr_err("%s: edac_device_add_device() failed\n", __func__);
86 goto err; 110 goto err1;
87 } 111 }
88 112
89 register_co_cache_error_notifier(&co_cache_error_notifier); 113 register_co_cache_error_notifier(&p->notifier);
90 ed_cavium = ed;
91 114
92 return 0; 115 return 0;
93 116
117err1:
118 edac_device_free_ctl_info(p->ed);
94err: 119err:
95 edac_device_free_ctl_info(ed); 120 return -ENXIO;
96
97 return res;
98} 121}
99 122
100static int co_cache_error_remove(struct platform_device *pdev) 123static int co_cache_error_remove(struct platform_device *pdev)
101{ 124{
102 struct edac_device_ctl_info *ed = platform_get_drvdata(pdev); 125 struct co_cache_error *p = platform_get_drvdata(pdev);
103 126
104 unregister_co_cache_error_notifier(&co_cache_error_notifier); 127 unregister_co_cache_error_notifier(&p->notifier);
105 ed_cavium = NULL;
106 edac_device_del_device(&pdev->dev); 128 edac_device_del_device(&pdev->dev);
107 edac_device_free_ctl_info(ed); 129 edac_device_free_ctl_info(p->ed);
108
109 return 0; 130 return 0;
110} 131}
111 132
@@ -113,28 +134,10 @@ static struct platform_driver co_cache_error_driver = {
113 .probe = co_cache_error_probe, 134 .probe = co_cache_error_probe,
114 .remove = co_cache_error_remove, 135 .remove = co_cache_error_remove,
115 .driver = { 136 .driver = {
116 .name = "co_pc_edac", 137 .name = "octeon_pc_edac",
117 } 138 }
118}; 139};
119 140module_platform_driver(co_cache_error_driver);
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 141
139MODULE_LICENSE("GPL"); 142MODULE_LICENSE("GPL");
140MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>"); 143MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");