aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac
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
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')
-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>");