aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/edac')
-rw-r--r--drivers/edac/octeon_edac-l2c.c178
-rw-r--r--drivers/edac/octeon_edac-lmc.c232
-rw-r--r--drivers/edac/octeon_edac-lmc.h78
-rw-r--r--drivers/edac/octeon_edac-pc.c137
-rw-r--r--drivers/edac/octeon_edac-pci.c44
5 files changed, 348 insertions, 321 deletions
diff --git a/drivers/edac/octeon_edac-l2c.c b/drivers/edac/octeon_edac-l2c.c
index 5f459aa451bf..40fde6a51ed6 100644
--- a/drivers/edac/octeon_edac-l2c.c
+++ b/drivers/edac/octeon_edac-l2c.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,32 +21,124 @@
19 21
20#define EDAC_MOD_STR "octeon-l2c" 22#define EDAC_MOD_STR "octeon-l2c"
21 23
22static void co_l2c_poll(struct edac_device_ctl_info *l2c) 24static void octeon_l2c_poll_oct1(struct edac_device_ctl_info *l2c)
23{ 25{
24 union cvmx_l2t_err l2t_err; 26 union cvmx_l2t_err l2t_err, l2t_err_reset;
27 union cvmx_l2d_err l2d_err, l2d_err_reset;
25 28
29 l2t_err_reset.u64 = 0;
26 l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR); 30 l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR);
27 if (l2t_err.s.sec_err) { 31 if (l2t_err.s.sec_err) {
28 edac_device_handle_ce(l2c, 0, 0, 32 edac_device_handle_ce(l2c, 0, 0,
29 "Single bit error (corrected)"); 33 "Tag Single bit error (corrected)");
30 l2t_err.s.sec_err = 1; /* Reset */ 34 l2t_err_reset.s.sec_err = 1;
31 cvmx_write_csr(CVMX_L2T_ERR, l2t_err.u64);
32 } 35 }
33 if (l2t_err.s.ded_err) { 36 if (l2t_err.s.ded_err) {
34 edac_device_handle_ue(l2c, 0, 0, 37 edac_device_handle_ue(l2c, 0, 0,
35 "Double bit error (corrected)"); 38 "Tag Double bit error (detected)");
36 l2t_err.s.ded_err = 1; /* Reset */ 39 l2t_err_reset.s.ded_err = 1;
37 cvmx_write_csr(CVMX_L2T_ERR, l2t_err.u64); 40 }
41 if (l2t_err_reset.u64)
42 cvmx_write_csr(CVMX_L2T_ERR, l2t_err_reset.u64);
43
44 l2d_err_reset.u64 = 0;
45 l2d_err.u64 = cvmx_read_csr(CVMX_L2D_ERR);
46 if (l2d_err.s.sec_err) {
47 edac_device_handle_ce(l2c, 0, 1,
48 "Data Single bit error (corrected)");
49 l2d_err_reset.s.sec_err = 1;
50 }
51 if (l2d_err.s.ded_err) {
52 edac_device_handle_ue(l2c, 0, 1,
53 "Data Double bit error (detected)");
54 l2d_err_reset.s.ded_err = 1;
55 }
56 if (l2d_err_reset.u64)
57 cvmx_write_csr(CVMX_L2D_ERR, l2d_err_reset.u64);
58
59}
60
61static void _octeon_l2c_poll_oct2(struct edac_device_ctl_info *l2c, int tad)
62{
63 union cvmx_l2c_err_tdtx err_tdtx, err_tdtx_reset;
64 union cvmx_l2c_err_ttgx err_ttgx, err_ttgx_reset;
65 char buf1[64];
66 char buf2[80];
67
68 err_tdtx_reset.u64 = 0;
69 err_tdtx.u64 = cvmx_read_csr(CVMX_L2C_ERR_TDTX(tad));
70 if (err_tdtx.s.dbe || err_tdtx.s.sbe ||
71 err_tdtx.s.vdbe || err_tdtx.s.vsbe)
72 snprintf(buf1, sizeof(buf1),
73 "type:%d, syn:0x%x, way:%d",
74 err_tdtx.s.type, err_tdtx.s.syn, err_tdtx.s.wayidx);
75
76 if (err_tdtx.s.dbe) {
77 snprintf(buf2, sizeof(buf2),
78 "L2D Double bit error (detected):%s", buf1);
79 err_tdtx_reset.s.dbe = 1;
80 edac_device_handle_ue(l2c, tad, 1, buf2);
81 }
82 if (err_tdtx.s.sbe) {
83 snprintf(buf2, sizeof(buf2),
84 "L2D Single bit error (corrected):%s", buf1);
85 err_tdtx_reset.s.sbe = 1;
86 edac_device_handle_ce(l2c, tad, 1, buf2);
87 }
88 if (err_tdtx.s.vdbe) {
89 snprintf(buf2, sizeof(buf2),
90 "VBF Double bit error (detected):%s", buf1);
91 err_tdtx_reset.s.vdbe = 1;
92 edac_device_handle_ue(l2c, tad, 1, buf2);
93 }
94 if (err_tdtx.s.vsbe) {
95 snprintf(buf2, sizeof(buf2),
96 "VBF Single bit error (corrected):%s", buf1);
97 err_tdtx_reset.s.vsbe = 1;
98 edac_device_handle_ce(l2c, tad, 1, buf2);
99 }
100 if (err_tdtx_reset.u64)
101 cvmx_write_csr(CVMX_L2C_ERR_TDTX(tad), err_tdtx_reset.u64);
102
103 err_ttgx_reset.u64 = 0;
104 err_ttgx.u64 = cvmx_read_csr(CVMX_L2C_ERR_TTGX(tad));
105
106 if (err_ttgx.s.dbe || err_ttgx.s.sbe)
107 snprintf(buf1, sizeof(buf1),
108 "type:%d, syn:0x%x, way:%d",
109 err_ttgx.s.type, err_ttgx.s.syn, err_ttgx.s.wayidx);
110
111 if (err_ttgx.s.dbe) {
112 snprintf(buf2, sizeof(buf2),
113 "Tag Double bit error (detected):%s", buf1);
114 err_ttgx_reset.s.dbe = 1;
115 edac_device_handle_ue(l2c, tad, 0, buf2);
38 } 116 }
117 if (err_ttgx.s.sbe) {
118 snprintf(buf2, sizeof(buf2),
119 "Tag Single bit error (corrected):%s", buf1);
120 err_ttgx_reset.s.sbe = 1;
121 edac_device_handle_ce(l2c, tad, 0, buf2);
122 }
123 if (err_ttgx_reset.u64)
124 cvmx_write_csr(CVMX_L2C_ERR_TTGX(tad), err_ttgx_reset.u64);
125}
126
127static void octeon_l2c_poll_oct2(struct edac_device_ctl_info *l2c)
128{
129 int i;
130 for (i = 0; i < l2c->nr_instances; i++)
131 _octeon_l2c_poll_oct2(l2c, i);
39} 132}
40 133
41static int __devinit co_l2c_probe(struct platform_device *pdev) 134static int __devinit octeon_l2c_probe(struct platform_device *pdev)
42{ 135{
43 struct edac_device_ctl_info *l2c; 136 struct edac_device_ctl_info *l2c;
44 union cvmx_l2t_err l2t_err;
45 int res = 0;
46 137
47 l2c = edac_device_alloc_ctl_info(0, "l2c", 1, NULL, 0, 0, 138 int num_tads = OCTEON_IS_MODEL(OCTEON_CN68XX) ? 4 : 1;
139
140 /* 'Tags' are block 0, 'Data' is block 1*/
141 l2c = edac_device_alloc_ctl_info(0, "l2c", num_tads, "l2c", 2, 0,
48 NULL, 0, edac_device_alloc_index()); 142 NULL, 0, edac_device_alloc_index());
49 if (!l2c) 143 if (!l2c)
50 return -ENOMEM; 144 return -ENOMEM;
@@ -55,29 +149,43 @@ static int __devinit co_l2c_probe(struct platform_device *pdev)
55 149
56 l2c->mod_name = "octeon-l2c"; 150 l2c->mod_name = "octeon-l2c";
57 l2c->ctl_name = "octeon_l2c_err"; 151 l2c->ctl_name = "octeon_l2c_err";
58 l2c->edac_check = co_l2c_poll; 152
153
154 if (OCTEON_IS_MODEL(OCTEON_FAM_1_PLUS)) {
155 union cvmx_l2t_err l2t_err;
156 union cvmx_l2d_err l2d_err;
157
158 l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR);
159 l2t_err.s.sec_intena = 0; /* We poll */
160 l2t_err.s.ded_intena = 0;
161 cvmx_write_csr(CVMX_L2T_ERR, l2t_err.u64);
162
163 l2d_err.u64 = cvmx_read_csr(CVMX_L2D_ERR);
164 l2d_err.s.sec_intena = 0; /* We poll */
165 l2d_err.s.ded_intena = 0;
166 cvmx_write_csr(CVMX_L2T_ERR, l2d_err.u64);
167
168 l2c->edac_check = octeon_l2c_poll_oct1;
169 } else {
170 /* OCTEON II */
171 l2c->edac_check = octeon_l2c_poll_oct2;
172 }
59 173
60 if (edac_device_add_device(l2c) > 0) { 174 if (edac_device_add_device(l2c) > 0) {
61 pr_err("%s: edac_device_add_device() failed\n", __func__); 175 pr_err("%s: edac_device_add_device() failed\n", __func__);
62 goto err; 176 goto err;
63 } 177 }
64 178
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 179
72 return 0; 180 return 0;
73 181
74err: 182err:
75 edac_device_free_ctl_info(l2c); 183 edac_device_free_ctl_info(l2c);
76 184
77 return res; 185 return -ENXIO;
78} 186}
79 187
80static int co_l2c_remove(struct platform_device *pdev) 188static int octeon_l2c_remove(struct platform_device *pdev)
81{ 189{
82 struct edac_device_ctl_info *l2c = platform_get_drvdata(pdev); 190 struct edac_device_ctl_info *l2c = platform_get_drvdata(pdev);
83 191
@@ -87,32 +195,14 @@ static int co_l2c_remove(struct platform_device *pdev)
87 return 0; 195 return 0;
88} 196}
89 197
90static struct platform_driver co_l2c_driver = { 198static struct platform_driver octeon_l2c_driver = {
91 .probe = co_l2c_probe, 199 .probe = octeon_l2c_probe,
92 .remove = co_l2c_remove, 200 .remove = octeon_l2c_remove,
93 .driver = { 201 .driver = {
94 .name = "co_l2c_edac", 202 .name = "octeon_l2c_edac",
95 } 203 }
96}; 204};
97 205module_platform_driver(octeon_l2c_driver);
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 206
117MODULE_LICENSE("GPL"); 207MODULE_LICENSE("GPL");
118MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>"); 208MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
diff --git a/drivers/edac/octeon_edac-lmc.c b/drivers/edac/octeon_edac-lmc.c
index e0c1e44187bc..33bca766e37d 100644
--- a/drivers/edac/octeon_edac-lmc.c
+++ b/drivers/edac/octeon_edac-lmc.c
@@ -12,139 +12,175 @@
12#include <linux/io.h> 12#include <linux/io.h>
13#include <linux/edac.h> 13#include <linux/edac.h>
14 14
15#include <asm/octeon/cvmx.h> 15#include <asm/octeon/octeon.h>
16#include <asm/octeon/cvmx-lmcx-defs.h>
16 17
17#include "edac_core.h" 18#include "edac_core.h"
18#include "edac_module.h" 19#include "edac_module.h"
19#include "octeon_edac-lmc.h"
20 20
21#define EDAC_MOD_STR "octeon" 21#define OCTEON_MAX_MC 4
22 22
23static struct mem_ctl_info *mc_cavium; 23static void octeon_lmc_edac_poll(struct mem_ctl_info *mci)
24static void *lmc_base;
25
26static void co_lmc_poll(struct mem_ctl_info *mci)
27{ 24{
28 union lmc_mem_cfg0 cfg0; 25 union cvmx_lmcx_mem_cfg0 cfg0;
29 union lmc_fadr fadr; 26 bool do_clear = false;
30 char msg[64]; 27 char msg[64];
31 28
32 fadr.u64 = readq(lmc_base + LMC_FADR); 29 cfg0.u64 = cvmx_read_csr(CVMX_LMCX_MEM_CFG0(mci->mc_idx));
33 cfg0.u64 = readq(lmc_base + LMC_MEM_CFG0); 30 if (cfg0.s.sec_err || cfg0.s.ded_err) {
34 snprintf(msg, sizeof(msg), "DIMM %d rank %d bank %d row %d col %d", 31 union cvmx_lmcx_fadr fadr;
35 fadr.fdimm, fadr.fbunk, fadr.fbank, fadr.frow, fadr.fcol); 32 fadr.u64 = cvmx_read_csr(CVMX_LMCX_FADR(mci->mc_idx));
36 33 snprintf(msg, sizeof(msg),
37 if (cfg0.sec_err) { 34 "DIMM %d rank %d bank %d row %d col %d",
38 edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 0, 0, 0, -1, -1, -1, 35 fadr.cn30xx.fdimm, fadr.cn30xx.fbunk,
39 msg, ""); 36 fadr.cn30xx.fbank, fadr.cn30xx.frow, fadr.cn30xx.fcol);
40
41 cfg0.intr_sec_ena = -1; /* Done, re-arm */
42 } 37 }
43 38
44 if (cfg0.ded_err) { 39 if (cfg0.s.sec_err) {
45 edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0, -1, -1, -1, 40 edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 0, 0, 0,
46 msg, ""); 41 -1, -1, -1, msg, "");
47 cfg0.intr_ded_ena = -1; /* Done, re-arm */ 42 cfg0.s.sec_err = -1; /* Done, re-arm */
43 do_clear = true;
48 } 44 }
49 45
50 writeq(cfg0.u64, lmc_base + LMC_MEM_CFG0); 46 if (cfg0.s.ded_err) {
47 edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0,
48 -1, -1, -1, msg, "");
49 cfg0.s.ded_err = -1; /* Done, re-arm */
50 do_clear = true;
51 }
52 if (do_clear)
53 cvmx_write_csr(CVMX_LMCX_MEM_CFG0(mci->mc_idx), cfg0.u64);
51} 54}
52 55
53static int __devinit co_lmc_probe(struct platform_device *pdev) 56static void octeon_lmc_edac_poll_o2(struct mem_ctl_info *mci)
54{ 57{
55 struct mem_ctl_info *mci; 58 union cvmx_lmcx_int int_reg;
56 union lmc_mem_cfg0 cfg0; 59 bool do_clear = false;
57 int res = 0; 60 char msg[64];
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 61
67 mci->mod_name = "octeon-lmc"; 62 int_reg.u64 = cvmx_read_csr(CVMX_LMCX_INT(mci->mc_idx));
68 mci->ctl_name = "co_lmc_err"; 63 if (int_reg.s.sec_err || int_reg.s.ded_err) {
69 mci->edac_check = co_lmc_poll; 64 union cvmx_lmcx_fadr fadr;
65 fadr.u64 = cvmx_read_csr(CVMX_LMCX_FADR(mci->mc_idx));
66 snprintf(msg, sizeof(msg),
67 "DIMM %d rank %d bank %d row %d col %d",
68 fadr.cn61xx.fdimm, fadr.cn61xx.fbunk,
69 fadr.cn61xx.fbank, fadr.cn61xx.frow, fadr.cn61xx.fcol);
70 }
70 71
71 if (edac_mc_add_mc(mci) > 0) { 72 if (int_reg.s.sec_err) {
72 pr_err("%s: edac_mc_add_mc() failed\n", __func__); 73 edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 0, 0, 0,
73 goto err; 74 -1, -1, -1, msg, "");
75 int_reg.s.sec_err = -1; /* Done, re-arm */
76 do_clear = true;
74 } 77 }
75 78
76 cfg0.u64 = readq(lmc_base + LMC_MEM_CFG0); /* We poll */ 79 if (int_reg.s.ded_err) {
77 cfg0.intr_ded_ena = 0; 80 edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0,
78 cfg0.intr_sec_ena = 0; 81 -1, -1, -1, msg, "");
79 writeq(cfg0.u64, lmc_base + LMC_MEM_CFG0); 82 int_reg.s.ded_err = -1; /* Done, re-arm */
83 do_clear = true;
84 }
85 if (do_clear)
86 cvmx_write_csr(CVMX_LMCX_INT(mci->mc_idx), int_reg.u64);
87}
80 88
81 mc_cavium = mci; 89static int __devinit octeon_lmc_edac_probe(struct platform_device *pdev)
90{
91 struct mem_ctl_info *mci;
92 struct edac_mc_layer layers[1];
93 int mc = pdev->id;
94
95 layers[0].type = EDAC_MC_LAYER_CHANNEL;
96 layers[0].size = 1;
97 layers[0].is_virt_csrow = false;
98
99 if (OCTEON_IS_MODEL(OCTEON_FAM_1_PLUS)) {
100 union cvmx_lmcx_mem_cfg0 cfg0;
101
102 cfg0.u64 = cvmx_read_csr(CVMX_LMCX_MEM_CFG0(0));
103 if (!cfg0.s.ecc_ena) {
104 dev_info(&pdev->dev, "Disabled (ECC not enabled)\n");
105 return 0;
106 }
107
108 mci = edac_mc_alloc(mc, ARRAY_SIZE(layers), layers, 0);
109 if (!mci)
110 return -ENXIO;
111
112 mci->pdev = &pdev->dev;
113 mci->dev_name = dev_name(&pdev->dev);
114
115 mci->mod_name = "octeon-lmc";
116 mci->ctl_name = "octeon-lmc-err";
117 mci->edac_check = octeon_lmc_edac_poll;
118
119 if (edac_mc_add_mc(mci)) {
120 dev_err(&pdev->dev, "edac_mc_add_mc() failed\n");
121 edac_mc_free(mci);
122 return -ENXIO;
123 }
124
125 cfg0.u64 = cvmx_read_csr(CVMX_LMCX_MEM_CFG0(mc));
126 cfg0.s.intr_ded_ena = 0; /* We poll */
127 cfg0.s.intr_sec_ena = 0;
128 cvmx_write_csr(CVMX_LMCX_MEM_CFG0(mc), cfg0.u64);
129 } else {
130 /* OCTEON II */
131 union cvmx_lmcx_int_en en;
132 union cvmx_lmcx_config config;
133
134 config.u64 = cvmx_read_csr(CVMX_LMCX_CONFIG(0));
135 if (!config.s.ecc_ena) {
136 dev_info(&pdev->dev, "Disabled (ECC not enabled)\n");
137 return 0;
138 }
139
140 mci = edac_mc_alloc(mc, ARRAY_SIZE(layers), layers, 0);
141 if (!mci)
142 return -ENXIO;
143
144 mci->pdev = &pdev->dev;
145 mci->dev_name = dev_name(&pdev->dev);
146
147 mci->mod_name = "octeon-lmc";
148 mci->ctl_name = "co_lmc_err";
149 mci->edac_check = octeon_lmc_edac_poll_o2;
150
151 if (edac_mc_add_mc(mci)) {
152 dev_err(&pdev->dev, "edac_mc_add_mc() failed\n");
153 edac_mc_free(mci);
154 return -ENXIO;
155 }
156
157 en.u64 = cvmx_read_csr(CVMX_LMCX_MEM_CFG0(mc));
158 en.s.intr_ded_ena = 0; /* We poll */
159 en.s.intr_sec_ena = 0;
160 cvmx_write_csr(CVMX_LMCX_MEM_CFG0(mc), en.u64);
161 }
162 platform_set_drvdata(pdev, mci);
82 163
83 return 0; 164 return 0;
84
85err:
86 edac_mc_free(mci);
87
88 return res;
89} 165}
90 166
91static int co_lmc_remove(struct platform_device *pdev) 167static int octeon_lmc_edac_remove(struct platform_device *pdev)
92{ 168{
93 struct mem_ctl_info *mci = platform_get_drvdata(pdev); 169 struct mem_ctl_info *mci = platform_get_drvdata(pdev);
94 170
95 mc_cavium = NULL;
96 edac_mc_del_mc(&pdev->dev); 171 edac_mc_del_mc(&pdev->dev);
97 edac_mc_free(mci); 172 edac_mc_free(mci);
98
99 return 0; 173 return 0;
100} 174}
101 175
102static struct platform_driver co_lmc_driver = { 176static struct platform_driver octeon_lmc_edac_driver = {
103 .probe = co_lmc_probe, 177 .probe = octeon_lmc_edac_probe,
104 .remove = co_lmc_remove, 178 .remove = octeon_lmc_edac_remove,
105 .driver = { 179 .driver = {
106 .name = "co_lmc_edac", 180 .name = "octeon_lmc_edac",
107 } 181 }
108}; 182};
109 183module_platform_driver(octeon_lmc_edac_driver);
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 184
149MODULE_LICENSE("GPL"); 185MODULE_LICENSE("GPL");
150MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>"); 186MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
diff --git a/drivers/edac/octeon_edac-lmc.h b/drivers/edac/octeon_edac-lmc.h
deleted file mode 100644
index 246dc525bc10..000000000000
--- a/drivers/edac/octeon_edac-lmc.h
+++ /dev/null
@@ -1,78 +0,0 @@
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
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>");
diff --git a/drivers/edac/octeon_edac-pci.c b/drivers/edac/octeon_edac-pci.c
index e72b96e3e4e0..758c1ef5fc9e 100644
--- a/drivers/edac/octeon_edac-pci.c
+++ b/drivers/edac/octeon_edac-pci.c
@@ -3,6 +3,7 @@
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.
6 * Copyright (C) 2009 Wind River Systems, 7 * Copyright (C) 2009 Wind River Systems,
7 * written by Ralf Baechle <ralf@linux-mips.org> 8 * written by Ralf Baechle <ralf@linux-mips.org>
8 */ 9 */
@@ -20,9 +21,7 @@
20#include "edac_core.h" 21#include "edac_core.h"
21#include "edac_module.h" 22#include "edac_module.h"
22 23
23#define EDAC_MOD_STR "octeon" 24static void octeon_pci_poll(struct edac_pci_ctl_info *pci)
24
25static void co_pci_poll(struct edac_pci_ctl_info *pci)
26{ 25{
27 union cvmx_pci_cfg01 cfg01; 26 union cvmx_pci_cfg01 cfg01;
28 27
@@ -57,14 +56,9 @@ static void co_pci_poll(struct edac_pci_ctl_info *pci)
57 cfg01.s.mdpe = 1; /* Reset */ 56 cfg01.s.mdpe = 1; /* Reset */
58 octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32); 57 octeon_npi_write32(CVMX_NPI_PCI_CFG01, cfg01.u32);
59 } 58 }
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} 59}
66 60
67static int __devinit co_pci_probe(struct platform_device *pdev) 61static int __devinit octeon_pci_probe(struct platform_device *pdev)
68{ 62{
69 struct edac_pci_ctl_info *pci; 63 struct edac_pci_ctl_info *pci;
70 int res = 0; 64 int res = 0;
@@ -79,7 +73,7 @@ static int __devinit co_pci_probe(struct platform_device *pdev)
79 73
80 pci->mod_name = "octeon-pci"; 74 pci->mod_name = "octeon-pci";
81 pci->ctl_name = "octeon_pci_err"; 75 pci->ctl_name = "octeon_pci_err";
82 pci->edac_check = co_pci_poll; 76 pci->edac_check = octeon_pci_poll;
83 77
84 if (edac_pci_add_device(pci, 0) > 0) { 78 if (edac_pci_add_device(pci, 0) > 0) {
85 pr_err("%s: edac_pci_add_device() failed\n", __func__); 79 pr_err("%s: edac_pci_add_device() failed\n", __func__);
@@ -94,7 +88,7 @@ err:
94 return res; 88 return res;
95} 89}
96 90
97static int co_pci_remove(struct platform_device *pdev) 91static int octeon_pci_remove(struct platform_device *pdev)
98{ 92{
99 struct edac_pci_ctl_info *pci = platform_get_drvdata(pdev); 93 struct edac_pci_ctl_info *pci = platform_get_drvdata(pdev);
100 94
@@ -104,32 +98,14 @@ static int co_pci_remove(struct platform_device *pdev)
104 return 0; 98 return 0;
105} 99}
106 100
107static struct platform_driver co_pci_driver = { 101static struct platform_driver octeon_pci_driver = {
108 .probe = co_pci_probe, 102 .probe = octeon_pci_probe,
109 .remove = co_pci_remove, 103 .remove = octeon_pci_remove,
110 .driver = { 104 .driver = {
111 .name = "co_pci_edac", 105 .name = "octeon_pci_edac",
112 } 106 }
113}; 107};
114 108module_platform_driver(octeon_pci_driver);
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 109
134MODULE_LICENSE("GPL"); 110MODULE_LICENSE("GPL");
135MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>"); 111MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");