Root/
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/octeon.h> |
16 | #include <asm/octeon/cvmx-lmcx-defs.h> |
17 | |
18 | #include "edac_core.h" |
19 | #include "edac_module.h" |
20 | |
21 | #define OCTEON_MAX_MC 4 |
22 | |
23 | static void octeon_lmc_edac_poll(struct mem_ctl_info *mci) |
24 | { |
25 | union cvmx_lmcx_mem_cfg0 cfg0; |
26 | bool do_clear = false; |
27 | char msg[64]; |
28 | |
29 | cfg0.u64 = cvmx_read_csr(CVMX_LMCX_MEM_CFG0(mci->mc_idx)); |
30 | if (cfg0.s.sec_err || cfg0.s.ded_err) { |
31 | union cvmx_lmcx_fadr fadr; |
32 | fadr.u64 = cvmx_read_csr(CVMX_LMCX_FADR(mci->mc_idx)); |
33 | snprintf(msg, sizeof(msg), |
34 | "DIMM %d rank %d bank %d row %d col %d", |
35 | fadr.cn30xx.fdimm, fadr.cn30xx.fbunk, |
36 | fadr.cn30xx.fbank, fadr.cn30xx.frow, fadr.cn30xx.fcol); |
37 | } |
38 | |
39 | if (cfg0.s.sec_err) { |
40 | edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 0, 0, 0, |
41 | -1, -1, -1, msg, ""); |
42 | cfg0.s.sec_err = -1; /* Done, re-arm */ |
43 | do_clear = true; |
44 | } |
45 | |
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); |
54 | } |
55 | |
56 | static void octeon_lmc_edac_poll_o2(struct mem_ctl_info *mci) |
57 | { |
58 | union cvmx_lmcx_int int_reg; |
59 | bool do_clear = false; |
60 | char msg[64]; |
61 | |
62 | int_reg.u64 = cvmx_read_csr(CVMX_LMCX_INT(mci->mc_idx)); |
63 | if (int_reg.s.sec_err || int_reg.s.ded_err) { |
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 | } |
71 | |
72 | if (int_reg.s.sec_err) { |
73 | edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 0, 0, 0, |
74 | -1, -1, -1, msg, ""); |
75 | int_reg.s.sec_err = -1; /* Done, re-arm */ |
76 | do_clear = true; |
77 | } |
78 | |
79 | if (int_reg.s.ded_err) { |
80 | edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0, |
81 | -1, -1, -1, msg, ""); |
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 | } |
88 | |
89 | static int 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); |
163 | |
164 | return 0; |
165 | } |
166 | |
167 | static int octeon_lmc_edac_remove(struct platform_device *pdev) |
168 | { |
169 | struct mem_ctl_info *mci = platform_get_drvdata(pdev); |
170 | |
171 | edac_mc_del_mc(&pdev->dev); |
172 | edac_mc_free(mci); |
173 | return 0; |
174 | } |
175 | |
176 | static struct platform_driver octeon_lmc_edac_driver = { |
177 | .probe = octeon_lmc_edac_probe, |
178 | .remove = octeon_lmc_edac_remove, |
179 | .driver = { |
180 | .name = "octeon_lmc_edac", |
181 | } |
182 | }; |
183 | module_platform_driver(octeon_lmc_edac_driver); |
184 | |
185 | MODULE_LICENSE("GPL"); |
186 | MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>"); |
187 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9