diff options
author | York Sun <york.sun@nxp.com> | 2016-08-11 16:15:18 -0400 |
---|---|---|
committer | Borislav Petkov <bp@suse.de> | 2016-09-01 04:28:00 -0400 |
commit | ea2eb9a8b6207ee40fdc346956686d8753aea944 (patch) | |
tree | d9deb6d1f8a3b3741cf6e816fcfd463d8be2c811 | |
parent | 88857ebe7116b0f7702200628fa6b4d1297751a3 (diff) |
EDAC, fsl-ddr: Separate FSL DDR driver from MPC85xx
The mpc85xx-compatible DDR controllers are used on ARM-based SoCs too.
Carve out the DDR part from the mpc85xx EDAC driver in preparation to
support both architectures.
Signed-off-by: York Sun <york.sun@nxp.com>
Cc: Johannes Thumshirn <morbidrsa@gmail.com>
Cc: linux-edac <linux-edac@vger.kernel.org>
Cc: oss@buserror.net
Cc: stuart.yoder@nxp.com
Link: http://lkml.kernel.org/r/1470946525-3410-1-git-send-email-york.sun@nxp.com
Signed-off-by: Borislav Petkov <bp@suse.de>
-rw-r--r-- | drivers/edac/Makefile | 5 | ||||
-rw-r--r-- | drivers/edac/fsl_ddr_edac.c | 592 | ||||
-rw-r--r-- | drivers/edac/fsl_ddr_edac.h | 86 | ||||
-rw-r--r-- | drivers/edac/mpc85xx_edac.c | 556 | ||||
-rw-r--r-- | drivers/edac/mpc85xx_edac.h | 66 |
5 files changed, 683 insertions, 622 deletions
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index f9e4a3e0e6e9..ee047a415722 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile | |||
@@ -50,7 +50,10 @@ amd64_edac_mod-$(CONFIG_EDAC_AMD64_ERROR_INJECTION) += amd64_edac_inj.o | |||
50 | obj-$(CONFIG_EDAC_AMD64) += amd64_edac_mod.o | 50 | obj-$(CONFIG_EDAC_AMD64) += amd64_edac_mod.o |
51 | 51 | ||
52 | obj-$(CONFIG_EDAC_PASEMI) += pasemi_edac.o | 52 | obj-$(CONFIG_EDAC_PASEMI) += pasemi_edac.o |
53 | obj-$(CONFIG_EDAC_MPC85XX) += mpc85xx_edac.o | 53 | |
54 | mpc85xx_edac_mod-y := fsl_ddr_edac.o mpc85xx_edac.o | ||
55 | obj-$(CONFIG_EDAC_MPC85XX) += mpc85xx_edac_mod.o | ||
56 | |||
54 | obj-$(CONFIG_EDAC_MV64X60) += mv64x60_edac.o | 57 | obj-$(CONFIG_EDAC_MV64X60) += mv64x60_edac.o |
55 | obj-$(CONFIG_EDAC_CELL) += cell_edac.o | 58 | obj-$(CONFIG_EDAC_CELL) += cell_edac.o |
56 | obj-$(CONFIG_EDAC_PPC4XX) += ppc4xx_edac.o | 59 | obj-$(CONFIG_EDAC_PPC4XX) += ppc4xx_edac.o |
diff --git a/drivers/edac/fsl_ddr_edac.c b/drivers/edac/fsl_ddr_edac.c new file mode 100644 index 000000000000..ca7636fbc799 --- /dev/null +++ b/drivers/edac/fsl_ddr_edac.c | |||
@@ -0,0 +1,592 @@ | |||
1 | /* | ||
2 | * Freescale Memory Controller kernel module | ||
3 | * | ||
4 | * Support Power-based SoCs including MPC85xx, MPC86xx, MPC83xx and | ||
5 | * ARM-based Layerscape SoCs including LS2xxx. Originally split | ||
6 | * out from mpc85xx_edac EDAC driver. | ||
7 | * | ||
8 | * Parts Copyrighted (c) 2013 by Freescale Semiconductor, Inc. | ||
9 | * | ||
10 | * Author: Dave Jiang <djiang@mvista.com> | ||
11 | * | ||
12 | * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under | ||
13 | * the terms of the GNU General Public License version 2. This program | ||
14 | * is licensed "as is" without any warranty of any kind, whether express | ||
15 | * or implied. | ||
16 | * | ||
17 | */ | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/ctype.h> | ||
22 | #include <linux/io.h> | ||
23 | #include <linux/mod_devicetable.h> | ||
24 | #include <linux/edac.h> | ||
25 | #include <linux/smp.h> | ||
26 | #include <linux/gfp.h> | ||
27 | |||
28 | #include <linux/of_platform.h> | ||
29 | #include <linux/of_device.h> | ||
30 | #include "edac_module.h" | ||
31 | #include "edac_core.h" | ||
32 | #include "fsl_ddr_edac.h" | ||
33 | |||
34 | #define EDAC_MOD_STR "fsl_ddr_edac" | ||
35 | |||
36 | static int edac_mc_idx; | ||
37 | |||
38 | static u32 orig_ddr_err_disable; | ||
39 | static u32 orig_ddr_err_sbe; | ||
40 | |||
41 | /************************ MC SYSFS parts ***********************************/ | ||
42 | |||
43 | #define to_mci(k) container_of(k, struct mem_ctl_info, dev) | ||
44 | |||
45 | static ssize_t mpc85xx_mc_inject_data_hi_show(struct device *dev, | ||
46 | struct device_attribute *mattr, | ||
47 | char *data) | ||
48 | { | ||
49 | struct mem_ctl_info *mci = to_mci(dev); | ||
50 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
51 | return sprintf(data, "0x%08x", | ||
52 | in_be32(pdata->mc_vbase + | ||
53 | MPC85XX_MC_DATA_ERR_INJECT_HI)); | ||
54 | } | ||
55 | |||
56 | static ssize_t mpc85xx_mc_inject_data_lo_show(struct device *dev, | ||
57 | struct device_attribute *mattr, | ||
58 | char *data) | ||
59 | { | ||
60 | struct mem_ctl_info *mci = to_mci(dev); | ||
61 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
62 | return sprintf(data, "0x%08x", | ||
63 | in_be32(pdata->mc_vbase + | ||
64 | MPC85XX_MC_DATA_ERR_INJECT_LO)); | ||
65 | } | ||
66 | |||
67 | static ssize_t mpc85xx_mc_inject_ctrl_show(struct device *dev, | ||
68 | struct device_attribute *mattr, | ||
69 | char *data) | ||
70 | { | ||
71 | struct mem_ctl_info *mci = to_mci(dev); | ||
72 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
73 | return sprintf(data, "0x%08x", | ||
74 | in_be32(pdata->mc_vbase + MPC85XX_MC_ECC_ERR_INJECT)); | ||
75 | } | ||
76 | |||
77 | static ssize_t mpc85xx_mc_inject_data_hi_store(struct device *dev, | ||
78 | struct device_attribute *mattr, | ||
79 | const char *data, size_t count) | ||
80 | { | ||
81 | struct mem_ctl_info *mci = to_mci(dev); | ||
82 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
83 | if (isdigit(*data)) { | ||
84 | out_be32(pdata->mc_vbase + MPC85XX_MC_DATA_ERR_INJECT_HI, | ||
85 | simple_strtoul(data, NULL, 0)); | ||
86 | return count; | ||
87 | } | ||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static ssize_t mpc85xx_mc_inject_data_lo_store(struct device *dev, | ||
92 | struct device_attribute *mattr, | ||
93 | const char *data, size_t count) | ||
94 | { | ||
95 | struct mem_ctl_info *mci = to_mci(dev); | ||
96 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
97 | if (isdigit(*data)) { | ||
98 | out_be32(pdata->mc_vbase + MPC85XX_MC_DATA_ERR_INJECT_LO, | ||
99 | simple_strtoul(data, NULL, 0)); | ||
100 | return count; | ||
101 | } | ||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static ssize_t mpc85xx_mc_inject_ctrl_store(struct device *dev, | ||
106 | struct device_attribute *mattr, | ||
107 | const char *data, size_t count) | ||
108 | { | ||
109 | struct mem_ctl_info *mci = to_mci(dev); | ||
110 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
111 | if (isdigit(*data)) { | ||
112 | out_be32(pdata->mc_vbase + MPC85XX_MC_ECC_ERR_INJECT, | ||
113 | simple_strtoul(data, NULL, 0)); | ||
114 | return count; | ||
115 | } | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | DEVICE_ATTR(inject_data_hi, S_IRUGO | S_IWUSR, | ||
120 | mpc85xx_mc_inject_data_hi_show, mpc85xx_mc_inject_data_hi_store); | ||
121 | DEVICE_ATTR(inject_data_lo, S_IRUGO | S_IWUSR, | ||
122 | mpc85xx_mc_inject_data_lo_show, mpc85xx_mc_inject_data_lo_store); | ||
123 | DEVICE_ATTR(inject_ctrl, S_IRUGO | S_IWUSR, | ||
124 | mpc85xx_mc_inject_ctrl_show, mpc85xx_mc_inject_ctrl_store); | ||
125 | |||
126 | static struct attribute *mpc85xx_dev_attrs[] = { | ||
127 | &dev_attr_inject_data_hi.attr, | ||
128 | &dev_attr_inject_data_lo.attr, | ||
129 | &dev_attr_inject_ctrl.attr, | ||
130 | NULL | ||
131 | }; | ||
132 | |||
133 | ATTRIBUTE_GROUPS(mpc85xx_dev); | ||
134 | |||
135 | /**************************** MC Err device ***************************/ | ||
136 | |||
137 | /* | ||
138 | * Taken from table 8-55 in the MPC8641 User's Manual and/or 9-61 in the | ||
139 | * MPC8572 User's Manual. Each line represents a syndrome bit column as a | ||
140 | * 64-bit value, but split into an upper and lower 32-bit chunk. The labels | ||
141 | * below correspond to Freescale's manuals. | ||
142 | */ | ||
143 | static unsigned int ecc_table[16] = { | ||
144 | /* MSB LSB */ | ||
145 | /* [0:31] [32:63] */ | ||
146 | 0xf00fe11e, 0xc33c0ff7, /* Syndrome bit 7 */ | ||
147 | 0x00ff00ff, 0x00fff0ff, | ||
148 | 0x0f0f0f0f, 0x0f0fff00, | ||
149 | 0x11113333, 0x7777000f, | ||
150 | 0x22224444, 0x8888222f, | ||
151 | 0x44448888, 0xffff4441, | ||
152 | 0x8888ffff, 0x11118882, | ||
153 | 0xffff1111, 0x22221114, /* Syndrome bit 0 */ | ||
154 | }; | ||
155 | |||
156 | /* | ||
157 | * Calculate the correct ECC value for a 64-bit value specified by high:low | ||
158 | */ | ||
159 | static u8 calculate_ecc(u32 high, u32 low) | ||
160 | { | ||
161 | u32 mask_low; | ||
162 | u32 mask_high; | ||
163 | int bit_cnt; | ||
164 | u8 ecc = 0; | ||
165 | int i; | ||
166 | int j; | ||
167 | |||
168 | for (i = 0; i < 8; i++) { | ||
169 | mask_high = ecc_table[i * 2]; | ||
170 | mask_low = ecc_table[i * 2 + 1]; | ||
171 | bit_cnt = 0; | ||
172 | |||
173 | for (j = 0; j < 32; j++) { | ||
174 | if ((mask_high >> j) & 1) | ||
175 | bit_cnt ^= (high >> j) & 1; | ||
176 | if ((mask_low >> j) & 1) | ||
177 | bit_cnt ^= (low >> j) & 1; | ||
178 | } | ||
179 | |||
180 | ecc |= bit_cnt << i; | ||
181 | } | ||
182 | |||
183 | return ecc; | ||
184 | } | ||
185 | |||
186 | /* | ||
187 | * Create the syndrome code which is generated if the data line specified by | ||
188 | * 'bit' failed. Eg generate an 8-bit codes seen in Table 8-55 in the MPC8641 | ||
189 | * User's Manual and 9-61 in the MPC8572 User's Manual. | ||
190 | */ | ||
191 | static u8 syndrome_from_bit(unsigned int bit) { | ||
192 | int i; | ||
193 | u8 syndrome = 0; | ||
194 | |||
195 | /* | ||
196 | * Cycle through the upper or lower 32-bit portion of each value in | ||
197 | * ecc_table depending on if 'bit' is in the upper or lower half of | ||
198 | * 64-bit data. | ||
199 | */ | ||
200 | for (i = bit < 32; i < 16; i += 2) | ||
201 | syndrome |= ((ecc_table[i] >> (bit % 32)) & 1) << (i / 2); | ||
202 | |||
203 | return syndrome; | ||
204 | } | ||
205 | |||
206 | /* | ||
207 | * Decode data and ecc syndrome to determine what went wrong | ||
208 | * Note: This can only decode single-bit errors | ||
209 | */ | ||
210 | static void sbe_ecc_decode(u32 cap_high, u32 cap_low, u32 cap_ecc, | ||
211 | int *bad_data_bit, int *bad_ecc_bit) | ||
212 | { | ||
213 | int i; | ||
214 | u8 syndrome; | ||
215 | |||
216 | *bad_data_bit = -1; | ||
217 | *bad_ecc_bit = -1; | ||
218 | |||
219 | /* | ||
220 | * Calculate the ECC of the captured data and XOR it with the captured | ||
221 | * ECC to find an ECC syndrome value we can search for | ||
222 | */ | ||
223 | syndrome = calculate_ecc(cap_high, cap_low) ^ cap_ecc; | ||
224 | |||
225 | /* Check if a data line is stuck... */ | ||
226 | for (i = 0; i < 64; i++) { | ||
227 | if (syndrome == syndrome_from_bit(i)) { | ||
228 | *bad_data_bit = i; | ||
229 | return; | ||
230 | } | ||
231 | } | ||
232 | |||
233 | /* If data is correct, check ECC bits for errors... */ | ||
234 | for (i = 0; i < 8; i++) { | ||
235 | if ((syndrome >> i) & 0x1) { | ||
236 | *bad_ecc_bit = i; | ||
237 | return; | ||
238 | } | ||
239 | } | ||
240 | } | ||
241 | |||
242 | #define make64(high, low) (((u64)(high) << 32) | (low)) | ||
243 | |||
244 | static void mpc85xx_mc_check(struct mem_ctl_info *mci) | ||
245 | { | ||
246 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
247 | struct csrow_info *csrow; | ||
248 | u32 bus_width; | ||
249 | u32 err_detect; | ||
250 | u32 syndrome; | ||
251 | u64 err_addr; | ||
252 | u32 pfn; | ||
253 | int row_index; | ||
254 | u32 cap_high; | ||
255 | u32 cap_low; | ||
256 | int bad_data_bit; | ||
257 | int bad_ecc_bit; | ||
258 | |||
259 | err_detect = in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT); | ||
260 | if (!err_detect) | ||
261 | return; | ||
262 | |||
263 | mpc85xx_mc_printk(mci, KERN_ERR, "Err Detect Register: %#8.8x\n", | ||
264 | err_detect); | ||
265 | |||
266 | /* no more processing if not ECC bit errors */ | ||
267 | if (!(err_detect & (DDR_EDE_SBE | DDR_EDE_MBE))) { | ||
268 | out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, err_detect); | ||
269 | return; | ||
270 | } | ||
271 | |||
272 | syndrome = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ECC); | ||
273 | |||
274 | /* Mask off appropriate bits of syndrome based on bus width */ | ||
275 | bus_width = (in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG) & | ||
276 | DSC_DBW_MASK) ? 32 : 64; | ||
277 | if (bus_width == 64) | ||
278 | syndrome &= 0xff; | ||
279 | else | ||
280 | syndrome &= 0xffff; | ||
281 | |||
282 | err_addr = make64( | ||
283 | in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_EXT_ADDRESS), | ||
284 | in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ADDRESS)); | ||
285 | pfn = err_addr >> PAGE_SHIFT; | ||
286 | |||
287 | for (row_index = 0; row_index < mci->nr_csrows; row_index++) { | ||
288 | csrow = mci->csrows[row_index]; | ||
289 | if ((pfn >= csrow->first_page) && (pfn <= csrow->last_page)) | ||
290 | break; | ||
291 | } | ||
292 | |||
293 | cap_high = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_DATA_HI); | ||
294 | cap_low = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_DATA_LO); | ||
295 | |||
296 | /* | ||
297 | * Analyze single-bit errors on 64-bit wide buses | ||
298 | * TODO: Add support for 32-bit wide buses | ||
299 | */ | ||
300 | if ((err_detect & DDR_EDE_SBE) && (bus_width == 64)) { | ||
301 | sbe_ecc_decode(cap_high, cap_low, syndrome, | ||
302 | &bad_data_bit, &bad_ecc_bit); | ||
303 | |||
304 | if (bad_data_bit != -1) | ||
305 | mpc85xx_mc_printk(mci, KERN_ERR, | ||
306 | "Faulty Data bit: %d\n", bad_data_bit); | ||
307 | if (bad_ecc_bit != -1) | ||
308 | mpc85xx_mc_printk(mci, KERN_ERR, | ||
309 | "Faulty ECC bit: %d\n", bad_ecc_bit); | ||
310 | |||
311 | mpc85xx_mc_printk(mci, KERN_ERR, | ||
312 | "Expected Data / ECC:\t%#8.8x_%08x / %#2.2x\n", | ||
313 | cap_high ^ (1 << (bad_data_bit - 32)), | ||
314 | cap_low ^ (1 << bad_data_bit), | ||
315 | syndrome ^ (1 << bad_ecc_bit)); | ||
316 | } | ||
317 | |||
318 | mpc85xx_mc_printk(mci, KERN_ERR, | ||
319 | "Captured Data / ECC:\t%#8.8x_%08x / %#2.2x\n", | ||
320 | cap_high, cap_low, syndrome); | ||
321 | mpc85xx_mc_printk(mci, KERN_ERR, "Err addr: %#8.8llx\n", err_addr); | ||
322 | mpc85xx_mc_printk(mci, KERN_ERR, "PFN: %#8.8x\n", pfn); | ||
323 | |||
324 | /* we are out of range */ | ||
325 | if (row_index == mci->nr_csrows) | ||
326 | mpc85xx_mc_printk(mci, KERN_ERR, "PFN out of range!\n"); | ||
327 | |||
328 | if (err_detect & DDR_EDE_SBE) | ||
329 | edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, | ||
330 | pfn, err_addr & ~PAGE_MASK, syndrome, | ||
331 | row_index, 0, -1, | ||
332 | mci->ctl_name, ""); | ||
333 | |||
334 | if (err_detect & DDR_EDE_MBE) | ||
335 | edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, | ||
336 | pfn, err_addr & ~PAGE_MASK, syndrome, | ||
337 | row_index, 0, -1, | ||
338 | mci->ctl_name, ""); | ||
339 | |||
340 | out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, err_detect); | ||
341 | } | ||
342 | |||
343 | static irqreturn_t mpc85xx_mc_isr(int irq, void *dev_id) | ||
344 | { | ||
345 | struct mem_ctl_info *mci = dev_id; | ||
346 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
347 | u32 err_detect; | ||
348 | |||
349 | err_detect = in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT); | ||
350 | if (!err_detect) | ||
351 | return IRQ_NONE; | ||
352 | |||
353 | mpc85xx_mc_check(mci); | ||
354 | |||
355 | return IRQ_HANDLED; | ||
356 | } | ||
357 | |||
358 | static void mpc85xx_init_csrows(struct mem_ctl_info *mci) | ||
359 | { | ||
360 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
361 | struct csrow_info *csrow; | ||
362 | struct dimm_info *dimm; | ||
363 | u32 sdram_ctl; | ||
364 | u32 sdtype; | ||
365 | enum mem_type mtype; | ||
366 | u32 cs_bnds; | ||
367 | int index; | ||
368 | |||
369 | sdram_ctl = in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG); | ||
370 | |||
371 | sdtype = sdram_ctl & DSC_SDTYPE_MASK; | ||
372 | if (sdram_ctl & DSC_RD_EN) { | ||
373 | switch (sdtype) { | ||
374 | case DSC_SDTYPE_DDR: | ||
375 | mtype = MEM_RDDR; | ||
376 | break; | ||
377 | case DSC_SDTYPE_DDR2: | ||
378 | mtype = MEM_RDDR2; | ||
379 | break; | ||
380 | case DSC_SDTYPE_DDR3: | ||
381 | mtype = MEM_RDDR3; | ||
382 | break; | ||
383 | default: | ||
384 | mtype = MEM_UNKNOWN; | ||
385 | break; | ||
386 | } | ||
387 | } else { | ||
388 | switch (sdtype) { | ||
389 | case DSC_SDTYPE_DDR: | ||
390 | mtype = MEM_DDR; | ||
391 | break; | ||
392 | case DSC_SDTYPE_DDR2: | ||
393 | mtype = MEM_DDR2; | ||
394 | break; | ||
395 | case DSC_SDTYPE_DDR3: | ||
396 | mtype = MEM_DDR3; | ||
397 | break; | ||
398 | default: | ||
399 | mtype = MEM_UNKNOWN; | ||
400 | break; | ||
401 | } | ||
402 | } | ||
403 | |||
404 | for (index = 0; index < mci->nr_csrows; index++) { | ||
405 | u32 start; | ||
406 | u32 end; | ||
407 | |||
408 | csrow = mci->csrows[index]; | ||
409 | dimm = csrow->channels[0]->dimm; | ||
410 | |||
411 | cs_bnds = in_be32(pdata->mc_vbase + MPC85XX_MC_CS_BNDS_0 + | ||
412 | (index * MPC85XX_MC_CS_BNDS_OFS)); | ||
413 | |||
414 | start = (cs_bnds & 0xffff0000) >> 16; | ||
415 | end = (cs_bnds & 0x0000ffff); | ||
416 | |||
417 | if (start == end) | ||
418 | continue; /* not populated */ | ||
419 | |||
420 | start <<= (24 - PAGE_SHIFT); | ||
421 | end <<= (24 - PAGE_SHIFT); | ||
422 | end |= (1 << (24 - PAGE_SHIFT)) - 1; | ||
423 | |||
424 | csrow->first_page = start; | ||
425 | csrow->last_page = end; | ||
426 | |||
427 | dimm->nr_pages = end + 1 - start; | ||
428 | dimm->grain = 8; | ||
429 | dimm->mtype = mtype; | ||
430 | dimm->dtype = DEV_UNKNOWN; | ||
431 | if (sdram_ctl & DSC_X32_EN) | ||
432 | dimm->dtype = DEV_X32; | ||
433 | dimm->edac_mode = EDAC_SECDED; | ||
434 | } | ||
435 | } | ||
436 | |||
437 | int mpc85xx_mc_err_probe(struct platform_device *op) | ||
438 | { | ||
439 | struct mem_ctl_info *mci; | ||
440 | struct edac_mc_layer layers[2]; | ||
441 | struct mpc85xx_mc_pdata *pdata; | ||
442 | struct resource r; | ||
443 | u32 sdram_ctl; | ||
444 | int res; | ||
445 | |||
446 | if (!devres_open_group(&op->dev, mpc85xx_mc_err_probe, GFP_KERNEL)) | ||
447 | return -ENOMEM; | ||
448 | |||
449 | layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; | ||
450 | layers[0].size = 4; | ||
451 | layers[0].is_virt_csrow = true; | ||
452 | layers[1].type = EDAC_MC_LAYER_CHANNEL; | ||
453 | layers[1].size = 1; | ||
454 | layers[1].is_virt_csrow = false; | ||
455 | mci = edac_mc_alloc(edac_mc_idx, ARRAY_SIZE(layers), layers, | ||
456 | sizeof(*pdata)); | ||
457 | if (!mci) { | ||
458 | devres_release_group(&op->dev, mpc85xx_mc_err_probe); | ||
459 | return -ENOMEM; | ||
460 | } | ||
461 | |||
462 | pdata = mci->pvt_info; | ||
463 | pdata->name = "mpc85xx_mc_err"; | ||
464 | pdata->irq = NO_IRQ; | ||
465 | mci->pdev = &op->dev; | ||
466 | pdata->edac_idx = edac_mc_idx++; | ||
467 | dev_set_drvdata(mci->pdev, mci); | ||
468 | mci->ctl_name = pdata->name; | ||
469 | mci->dev_name = pdata->name; | ||
470 | |||
471 | res = of_address_to_resource(op->dev.of_node, 0, &r); | ||
472 | if (res) { | ||
473 | pr_err("%s: Unable to get resource for MC err regs\n", | ||
474 | __func__); | ||
475 | goto err; | ||
476 | } | ||
477 | |||
478 | if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r), | ||
479 | pdata->name)) { | ||
480 | pr_err("%s: Error while requesting mem region\n", | ||
481 | __func__); | ||
482 | res = -EBUSY; | ||
483 | goto err; | ||
484 | } | ||
485 | |||
486 | pdata->mc_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r)); | ||
487 | if (!pdata->mc_vbase) { | ||
488 | pr_err("%s: Unable to setup MC err regs\n", __func__); | ||
489 | res = -ENOMEM; | ||
490 | goto err; | ||
491 | } | ||
492 | |||
493 | sdram_ctl = in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG); | ||
494 | if (!(sdram_ctl & DSC_ECC_EN)) { | ||
495 | /* no ECC */ | ||
496 | pr_warn("%s: No ECC DIMMs discovered\n", __func__); | ||
497 | res = -ENODEV; | ||
498 | goto err; | ||
499 | } | ||
500 | |||
501 | edac_dbg(3, "init mci\n"); | ||
502 | mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_RDDR2 | | ||
503 | MEM_FLAG_DDR | MEM_FLAG_DDR2; | ||
504 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; | ||
505 | mci->edac_cap = EDAC_FLAG_SECDED; | ||
506 | mci->mod_name = EDAC_MOD_STR; | ||
507 | |||
508 | if (edac_op_state == EDAC_OPSTATE_POLL) | ||
509 | mci->edac_check = mpc85xx_mc_check; | ||
510 | |||
511 | mci->ctl_page_to_phys = NULL; | ||
512 | |||
513 | mci->scrub_mode = SCRUB_SW_SRC; | ||
514 | |||
515 | mpc85xx_init_csrows(mci); | ||
516 | |||
517 | /* store the original error disable bits */ | ||
518 | orig_ddr_err_disable = | ||
519 | in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE); | ||
520 | out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE, 0); | ||
521 | |||
522 | /* clear all error bits */ | ||
523 | out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, ~0); | ||
524 | |||
525 | if (edac_mc_add_mc_with_groups(mci, mpc85xx_dev_groups)) { | ||
526 | edac_dbg(3, "failed edac_mc_add_mc()\n"); | ||
527 | goto err; | ||
528 | } | ||
529 | |||
530 | if (edac_op_state == EDAC_OPSTATE_INT) { | ||
531 | out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_INT_EN, | ||
532 | DDR_EIE_MBEE | DDR_EIE_SBEE); | ||
533 | |||
534 | /* store the original error management threshold */ | ||
535 | orig_ddr_err_sbe = in_be32(pdata->mc_vbase + | ||
536 | MPC85XX_MC_ERR_SBE) & 0xff0000; | ||
537 | |||
538 | /* set threshold to 1 error per interrupt */ | ||
539 | out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_SBE, 0x10000); | ||
540 | |||
541 | /* register interrupts */ | ||
542 | pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0); | ||
543 | res = devm_request_irq(&op->dev, pdata->irq, | ||
544 | mpc85xx_mc_isr, | ||
545 | IRQF_SHARED, | ||
546 | "[EDAC] MC err", mci); | ||
547 | if (res < 0) { | ||
548 | pr_err("%s: Unable to request irq %d for MPC85xx DRAM ERR\n", | ||
549 | __func__, pdata->irq); | ||
550 | irq_dispose_mapping(pdata->irq); | ||
551 | res = -ENODEV; | ||
552 | goto err2; | ||
553 | } | ||
554 | |||
555 | pr_info(EDAC_MOD_STR " acquired irq %d for MC\n", | ||
556 | pdata->irq); | ||
557 | } | ||
558 | |||
559 | devres_remove_group(&op->dev, mpc85xx_mc_err_probe); | ||
560 | edac_dbg(3, "success\n"); | ||
561 | pr_info(EDAC_MOD_STR " MC err registered\n"); | ||
562 | |||
563 | return 0; | ||
564 | |||
565 | err2: | ||
566 | edac_mc_del_mc(&op->dev); | ||
567 | err: | ||
568 | devres_release_group(&op->dev, mpc85xx_mc_err_probe); | ||
569 | edac_mc_free(mci); | ||
570 | return res; | ||
571 | } | ||
572 | |||
573 | int mpc85xx_mc_err_remove(struct platform_device *op) | ||
574 | { | ||
575 | struct mem_ctl_info *mci = dev_get_drvdata(&op->dev); | ||
576 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
577 | |||
578 | edac_dbg(0, "\n"); | ||
579 | |||
580 | if (edac_op_state == EDAC_OPSTATE_INT) { | ||
581 | out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_INT_EN, 0); | ||
582 | irq_dispose_mapping(pdata->irq); | ||
583 | } | ||
584 | |||
585 | out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE, | ||
586 | orig_ddr_err_disable); | ||
587 | out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_SBE, orig_ddr_err_sbe); | ||
588 | |||
589 | edac_mc_del_mc(&op->dev); | ||
590 | edac_mc_free(mci); | ||
591 | return 0; | ||
592 | } | ||
diff --git a/drivers/edac/fsl_ddr_edac.h b/drivers/edac/fsl_ddr_edac.h new file mode 100644 index 000000000000..2f2c2b1890b9 --- /dev/null +++ b/drivers/edac/fsl_ddr_edac.h | |||
@@ -0,0 +1,86 @@ | |||
1 | /* | ||
2 | * Freescale Memory Controller kernel module | ||
3 | * | ||
4 | * Support Power-based SoCs including MPC85xx, MPC86xx, MPC83xx and | ||
5 | * ARM-based Layerscape SoCs including LS2xxx. Originally split | ||
6 | * out from mpc85xx_edac EDAC driver. | ||
7 | * | ||
8 | * Author: Dave Jiang <djiang@mvista.com> | ||
9 | * | ||
10 | * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under | ||
11 | * the terms of the GNU General Public License version 2. This program | ||
12 | * is licensed "as is" without any warranty of any kind, whether express | ||
13 | * or implied. | ||
14 | * | ||
15 | */ | ||
16 | #ifndef _FSL_DDR_EDAC_H_ | ||
17 | #define _FSL_DDR_EDAC_H_ | ||
18 | |||
19 | #define mpc85xx_mc_printk(mci, level, fmt, arg...) \ | ||
20 | edac_mc_chipset_printk(mci, level, "FSL_DDR", fmt, ##arg) | ||
21 | |||
22 | /* | ||
23 | * DRAM error defines | ||
24 | */ | ||
25 | |||
26 | /* DDR_SDRAM_CFG */ | ||
27 | #define MPC85XX_MC_DDR_SDRAM_CFG 0x0110 | ||
28 | #define MPC85XX_MC_CS_BNDS_0 0x0000 | ||
29 | #define MPC85XX_MC_CS_BNDS_1 0x0008 | ||
30 | #define MPC85XX_MC_CS_BNDS_2 0x0010 | ||
31 | #define MPC85XX_MC_CS_BNDS_3 0x0018 | ||
32 | #define MPC85XX_MC_CS_BNDS_OFS 0x0008 | ||
33 | |||
34 | #define MPC85XX_MC_DATA_ERR_INJECT_HI 0x0e00 | ||
35 | #define MPC85XX_MC_DATA_ERR_INJECT_LO 0x0e04 | ||
36 | #define MPC85XX_MC_ECC_ERR_INJECT 0x0e08 | ||
37 | #define MPC85XX_MC_CAPTURE_DATA_HI 0x0e20 | ||
38 | #define MPC85XX_MC_CAPTURE_DATA_LO 0x0e24 | ||
39 | #define MPC85XX_MC_CAPTURE_ECC 0x0e28 | ||
40 | #define MPC85XX_MC_ERR_DETECT 0x0e40 | ||
41 | #define MPC85XX_MC_ERR_DISABLE 0x0e44 | ||
42 | #define MPC85XX_MC_ERR_INT_EN 0x0e48 | ||
43 | #define MPC85XX_MC_CAPTURE_ATRIBUTES 0x0e4c | ||
44 | #define MPC85XX_MC_CAPTURE_ADDRESS 0x0e50 | ||
45 | #define MPC85XX_MC_CAPTURE_EXT_ADDRESS 0x0e54 | ||
46 | #define MPC85XX_MC_ERR_SBE 0x0e58 | ||
47 | |||
48 | #define DSC_MEM_EN 0x80000000 | ||
49 | #define DSC_ECC_EN 0x20000000 | ||
50 | #define DSC_RD_EN 0x10000000 | ||
51 | #define DSC_DBW_MASK 0x00180000 | ||
52 | #define DSC_DBW_32 0x00080000 | ||
53 | #define DSC_DBW_64 0x00000000 | ||
54 | |||
55 | #define DSC_SDTYPE_MASK 0x07000000 | ||
56 | |||
57 | #define DSC_SDTYPE_DDR 0x02000000 | ||
58 | #define DSC_SDTYPE_DDR2 0x03000000 | ||
59 | #define DSC_SDTYPE_DDR3 0x07000000 | ||
60 | #define DSC_X32_EN 0x00000020 | ||
61 | |||
62 | /* Err_Int_En */ | ||
63 | #define DDR_EIE_MSEE 0x1 /* memory select */ | ||
64 | #define DDR_EIE_SBEE 0x4 /* single-bit ECC error */ | ||
65 | #define DDR_EIE_MBEE 0x8 /* multi-bit ECC error */ | ||
66 | |||
67 | /* Err_Detect */ | ||
68 | #define DDR_EDE_MSE 0x1 /* memory select */ | ||
69 | #define DDR_EDE_SBE 0x4 /* single-bit ECC error */ | ||
70 | #define DDR_EDE_MBE 0x8 /* multi-bit ECC error */ | ||
71 | #define DDR_EDE_MME 0x80000000 /* multiple memory errors */ | ||
72 | |||
73 | /* Err_Disable */ | ||
74 | #define DDR_EDI_MSED 0x1 /* memory select disable */ | ||
75 | #define DDR_EDI_SBED 0x4 /* single-bit ECC error disable */ | ||
76 | #define DDR_EDI_MBED 0x8 /* multi-bit ECC error disable */ | ||
77 | |||
78 | struct mpc85xx_mc_pdata { | ||
79 | char *name; | ||
80 | int edac_idx; | ||
81 | void __iomem *mc_vbase; | ||
82 | int irq; | ||
83 | }; | ||
84 | int mpc85xx_mc_err_probe(struct platform_device *op); | ||
85 | int mpc85xx_mc_err_remove(struct platform_device *op); | ||
86 | #endif | ||
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index 73d809535eb3..c548a80f1823 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c | |||
@@ -27,15 +27,12 @@ | |||
27 | #include "edac_module.h" | 27 | #include "edac_module.h" |
28 | #include "edac_core.h" | 28 | #include "edac_core.h" |
29 | #include "mpc85xx_edac.h" | 29 | #include "mpc85xx_edac.h" |
30 | #include "fsl_ddr_edac.h" | ||
30 | 31 | ||
31 | static int edac_dev_idx; | 32 | static int edac_dev_idx; |
32 | #ifdef CONFIG_PCI | 33 | #ifdef CONFIG_PCI |
33 | static int edac_pci_idx; | 34 | static int edac_pci_idx; |
34 | #endif | 35 | #endif |
35 | static int edac_mc_idx; | ||
36 | |||
37 | static u32 orig_ddr_err_disable; | ||
38 | static u32 orig_ddr_err_sbe; | ||
39 | 36 | ||
40 | /* | 37 | /* |
41 | * PCI Err defines | 38 | * PCI Err defines |
@@ -47,100 +44,6 @@ static u32 orig_pci_err_en; | |||
47 | 44 | ||
48 | static u32 orig_l2_err_disable; | 45 | static u32 orig_l2_err_disable; |
49 | 46 | ||
50 | /************************ MC SYSFS parts ***********************************/ | ||
51 | |||
52 | #define to_mci(k) container_of(k, struct mem_ctl_info, dev) | ||
53 | |||
54 | static ssize_t mpc85xx_mc_inject_data_hi_show(struct device *dev, | ||
55 | struct device_attribute *mattr, | ||
56 | char *data) | ||
57 | { | ||
58 | struct mem_ctl_info *mci = to_mci(dev); | ||
59 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
60 | return sprintf(data, "0x%08x", | ||
61 | in_be32(pdata->mc_vbase + | ||
62 | MPC85XX_MC_DATA_ERR_INJECT_HI)); | ||
63 | } | ||
64 | |||
65 | static ssize_t mpc85xx_mc_inject_data_lo_show(struct device *dev, | ||
66 | struct device_attribute *mattr, | ||
67 | char *data) | ||
68 | { | ||
69 | struct mem_ctl_info *mci = to_mci(dev); | ||
70 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
71 | return sprintf(data, "0x%08x", | ||
72 | in_be32(pdata->mc_vbase + | ||
73 | MPC85XX_MC_DATA_ERR_INJECT_LO)); | ||
74 | } | ||
75 | |||
76 | static ssize_t mpc85xx_mc_inject_ctrl_show(struct device *dev, | ||
77 | struct device_attribute *mattr, | ||
78 | char *data) | ||
79 | { | ||
80 | struct mem_ctl_info *mci = to_mci(dev); | ||
81 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
82 | return sprintf(data, "0x%08x", | ||
83 | in_be32(pdata->mc_vbase + MPC85XX_MC_ECC_ERR_INJECT)); | ||
84 | } | ||
85 | |||
86 | static ssize_t mpc85xx_mc_inject_data_hi_store(struct device *dev, | ||
87 | struct device_attribute *mattr, | ||
88 | const char *data, size_t count) | ||
89 | { | ||
90 | struct mem_ctl_info *mci = to_mci(dev); | ||
91 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
92 | if (isdigit(*data)) { | ||
93 | out_be32(pdata->mc_vbase + MPC85XX_MC_DATA_ERR_INJECT_HI, | ||
94 | simple_strtoul(data, NULL, 0)); | ||
95 | return count; | ||
96 | } | ||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | static ssize_t mpc85xx_mc_inject_data_lo_store(struct device *dev, | ||
101 | struct device_attribute *mattr, | ||
102 | const char *data, size_t count) | ||
103 | { | ||
104 | struct mem_ctl_info *mci = to_mci(dev); | ||
105 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
106 | if (isdigit(*data)) { | ||
107 | out_be32(pdata->mc_vbase + MPC85XX_MC_DATA_ERR_INJECT_LO, | ||
108 | simple_strtoul(data, NULL, 0)); | ||
109 | return count; | ||
110 | } | ||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | static ssize_t mpc85xx_mc_inject_ctrl_store(struct device *dev, | ||
115 | struct device_attribute *mattr, | ||
116 | const char *data, size_t count) | ||
117 | { | ||
118 | struct mem_ctl_info *mci = to_mci(dev); | ||
119 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
120 | if (isdigit(*data)) { | ||
121 | out_be32(pdata->mc_vbase + MPC85XX_MC_ECC_ERR_INJECT, | ||
122 | simple_strtoul(data, NULL, 0)); | ||
123 | return count; | ||
124 | } | ||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | DEVICE_ATTR(inject_data_hi, S_IRUGO | S_IWUSR, | ||
129 | mpc85xx_mc_inject_data_hi_show, mpc85xx_mc_inject_data_hi_store); | ||
130 | DEVICE_ATTR(inject_data_lo, S_IRUGO | S_IWUSR, | ||
131 | mpc85xx_mc_inject_data_lo_show, mpc85xx_mc_inject_data_lo_store); | ||
132 | DEVICE_ATTR(inject_ctrl, S_IRUGO | S_IWUSR, | ||
133 | mpc85xx_mc_inject_ctrl_show, mpc85xx_mc_inject_ctrl_store); | ||
134 | |||
135 | static struct attribute *mpc85xx_dev_attrs[] = { | ||
136 | &dev_attr_inject_data_hi.attr, | ||
137 | &dev_attr_inject_data_lo.attr, | ||
138 | &dev_attr_inject_ctrl.attr, | ||
139 | NULL | ||
140 | }; | ||
141 | |||
142 | ATTRIBUTE_GROUPS(mpc85xx_dev); | ||
143 | |||
144 | /**************************** PCI Err device ***************************/ | 47 | /**************************** PCI Err device ***************************/ |
145 | #ifdef CONFIG_PCI | 48 | #ifdef CONFIG_PCI |
146 | 49 | ||
@@ -725,463 +628,6 @@ static struct platform_driver mpc85xx_l2_err_driver = { | |||
725 | }, | 628 | }, |
726 | }; | 629 | }; |
727 | 630 | ||
728 | /**************************** MC Err device ***************************/ | ||
729 | |||
730 | /* | ||
731 | * Taken from table 8-55 in the MPC8641 User's Manual and/or 9-61 in the | ||
732 | * MPC8572 User's Manual. Each line represents a syndrome bit column as a | ||
733 | * 64-bit value, but split into an upper and lower 32-bit chunk. The labels | ||
734 | * below correspond to Freescale's manuals. | ||
735 | */ | ||
736 | static unsigned int ecc_table[16] = { | ||
737 | /* MSB LSB */ | ||
738 | /* [0:31] [32:63] */ | ||
739 | 0xf00fe11e, 0xc33c0ff7, /* Syndrome bit 7 */ | ||
740 | 0x00ff00ff, 0x00fff0ff, | ||
741 | 0x0f0f0f0f, 0x0f0fff00, | ||
742 | 0x11113333, 0x7777000f, | ||
743 | 0x22224444, 0x8888222f, | ||
744 | 0x44448888, 0xffff4441, | ||
745 | 0x8888ffff, 0x11118882, | ||
746 | 0xffff1111, 0x22221114, /* Syndrome bit 0 */ | ||
747 | }; | ||
748 | |||
749 | /* | ||
750 | * Calculate the correct ECC value for a 64-bit value specified by high:low | ||
751 | */ | ||
752 | static u8 calculate_ecc(u32 high, u32 low) | ||
753 | { | ||
754 | u32 mask_low; | ||
755 | u32 mask_high; | ||
756 | int bit_cnt; | ||
757 | u8 ecc = 0; | ||
758 | int i; | ||
759 | int j; | ||
760 | |||
761 | for (i = 0; i < 8; i++) { | ||
762 | mask_high = ecc_table[i * 2]; | ||
763 | mask_low = ecc_table[i * 2 + 1]; | ||
764 | bit_cnt = 0; | ||
765 | |||
766 | for (j = 0; j < 32; j++) { | ||
767 | if ((mask_high >> j) & 1) | ||
768 | bit_cnt ^= (high >> j) & 1; | ||
769 | if ((mask_low >> j) & 1) | ||
770 | bit_cnt ^= (low >> j) & 1; | ||
771 | } | ||
772 | |||
773 | ecc |= bit_cnt << i; | ||
774 | } | ||
775 | |||
776 | return ecc; | ||
777 | } | ||
778 | |||
779 | /* | ||
780 | * Create the syndrome code which is generated if the data line specified by | ||
781 | * 'bit' failed. Eg generate an 8-bit codes seen in Table 8-55 in the MPC8641 | ||
782 | * User's Manual and 9-61 in the MPC8572 User's Manual. | ||
783 | */ | ||
784 | static u8 syndrome_from_bit(unsigned int bit) { | ||
785 | int i; | ||
786 | u8 syndrome = 0; | ||
787 | |||
788 | /* | ||
789 | * Cycle through the upper or lower 32-bit portion of each value in | ||
790 | * ecc_table depending on if 'bit' is in the upper or lower half of | ||
791 | * 64-bit data. | ||
792 | */ | ||
793 | for (i = bit < 32; i < 16; i += 2) | ||
794 | syndrome |= ((ecc_table[i] >> (bit % 32)) & 1) << (i / 2); | ||
795 | |||
796 | return syndrome; | ||
797 | } | ||
798 | |||
799 | /* | ||
800 | * Decode data and ecc syndrome to determine what went wrong | ||
801 | * Note: This can only decode single-bit errors | ||
802 | */ | ||
803 | static void sbe_ecc_decode(u32 cap_high, u32 cap_low, u32 cap_ecc, | ||
804 | int *bad_data_bit, int *bad_ecc_bit) | ||
805 | { | ||
806 | int i; | ||
807 | u8 syndrome; | ||
808 | |||
809 | *bad_data_bit = -1; | ||
810 | *bad_ecc_bit = -1; | ||
811 | |||
812 | /* | ||
813 | * Calculate the ECC of the captured data and XOR it with the captured | ||
814 | * ECC to find an ECC syndrome value we can search for | ||
815 | */ | ||
816 | syndrome = calculate_ecc(cap_high, cap_low) ^ cap_ecc; | ||
817 | |||
818 | /* Check if a data line is stuck... */ | ||
819 | for (i = 0; i < 64; i++) { | ||
820 | if (syndrome == syndrome_from_bit(i)) { | ||
821 | *bad_data_bit = i; | ||
822 | return; | ||
823 | } | ||
824 | } | ||
825 | |||
826 | /* If data is correct, check ECC bits for errors... */ | ||
827 | for (i = 0; i < 8; i++) { | ||
828 | if ((syndrome >> i) & 0x1) { | ||
829 | *bad_ecc_bit = i; | ||
830 | return; | ||
831 | } | ||
832 | } | ||
833 | } | ||
834 | |||
835 | #define make64(high, low) (((u64)(high) << 32) | (low)) | ||
836 | |||
837 | static void mpc85xx_mc_check(struct mem_ctl_info *mci) | ||
838 | { | ||
839 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
840 | struct csrow_info *csrow; | ||
841 | u32 bus_width; | ||
842 | u32 err_detect; | ||
843 | u32 syndrome; | ||
844 | u64 err_addr; | ||
845 | u32 pfn; | ||
846 | int row_index; | ||
847 | u32 cap_high; | ||
848 | u32 cap_low; | ||
849 | int bad_data_bit; | ||
850 | int bad_ecc_bit; | ||
851 | |||
852 | err_detect = in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT); | ||
853 | if (!err_detect) | ||
854 | return; | ||
855 | |||
856 | mpc85xx_mc_printk(mci, KERN_ERR, "Err Detect Register: %#8.8x\n", | ||
857 | err_detect); | ||
858 | |||
859 | /* no more processing if not ECC bit errors */ | ||
860 | if (!(err_detect & (DDR_EDE_SBE | DDR_EDE_MBE))) { | ||
861 | out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, err_detect); | ||
862 | return; | ||
863 | } | ||
864 | |||
865 | syndrome = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ECC); | ||
866 | |||
867 | /* Mask off appropriate bits of syndrome based on bus width */ | ||
868 | bus_width = (in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG) & | ||
869 | DSC_DBW_MASK) ? 32 : 64; | ||
870 | if (bus_width == 64) | ||
871 | syndrome &= 0xff; | ||
872 | else | ||
873 | syndrome &= 0xffff; | ||
874 | |||
875 | err_addr = make64( | ||
876 | in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_EXT_ADDRESS), | ||
877 | in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ADDRESS)); | ||
878 | pfn = err_addr >> PAGE_SHIFT; | ||
879 | |||
880 | for (row_index = 0; row_index < mci->nr_csrows; row_index++) { | ||
881 | csrow = mci->csrows[row_index]; | ||
882 | if ((pfn >= csrow->first_page) && (pfn <= csrow->last_page)) | ||
883 | break; | ||
884 | } | ||
885 | |||
886 | cap_high = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_DATA_HI); | ||
887 | cap_low = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_DATA_LO); | ||
888 | |||
889 | /* | ||
890 | * Analyze single-bit errors on 64-bit wide buses | ||
891 | * TODO: Add support for 32-bit wide buses | ||
892 | */ | ||
893 | if ((err_detect & DDR_EDE_SBE) && (bus_width == 64)) { | ||
894 | sbe_ecc_decode(cap_high, cap_low, syndrome, | ||
895 | &bad_data_bit, &bad_ecc_bit); | ||
896 | |||
897 | if (bad_data_bit != -1) | ||
898 | mpc85xx_mc_printk(mci, KERN_ERR, | ||
899 | "Faulty Data bit: %d\n", bad_data_bit); | ||
900 | if (bad_ecc_bit != -1) | ||
901 | mpc85xx_mc_printk(mci, KERN_ERR, | ||
902 | "Faulty ECC bit: %d\n", bad_ecc_bit); | ||
903 | |||
904 | mpc85xx_mc_printk(mci, KERN_ERR, | ||
905 | "Expected Data / ECC:\t%#8.8x_%08x / %#2.2x\n", | ||
906 | cap_high ^ (1 << (bad_data_bit - 32)), | ||
907 | cap_low ^ (1 << bad_data_bit), | ||
908 | syndrome ^ (1 << bad_ecc_bit)); | ||
909 | } | ||
910 | |||
911 | mpc85xx_mc_printk(mci, KERN_ERR, | ||
912 | "Captured Data / ECC:\t%#8.8x_%08x / %#2.2x\n", | ||
913 | cap_high, cap_low, syndrome); | ||
914 | mpc85xx_mc_printk(mci, KERN_ERR, "Err addr: %#8.8llx\n", err_addr); | ||
915 | mpc85xx_mc_printk(mci, KERN_ERR, "PFN: %#8.8x\n", pfn); | ||
916 | |||
917 | /* we are out of range */ | ||
918 | if (row_index == mci->nr_csrows) | ||
919 | mpc85xx_mc_printk(mci, KERN_ERR, "PFN out of range!\n"); | ||
920 | |||
921 | if (err_detect & DDR_EDE_SBE) | ||
922 | edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, | ||
923 | pfn, err_addr & ~PAGE_MASK, syndrome, | ||
924 | row_index, 0, -1, | ||
925 | mci->ctl_name, ""); | ||
926 | |||
927 | if (err_detect & DDR_EDE_MBE) | ||
928 | edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, | ||
929 | pfn, err_addr & ~PAGE_MASK, syndrome, | ||
930 | row_index, 0, -1, | ||
931 | mci->ctl_name, ""); | ||
932 | |||
933 | out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, err_detect); | ||
934 | } | ||
935 | |||
936 | static irqreturn_t mpc85xx_mc_isr(int irq, void *dev_id) | ||
937 | { | ||
938 | struct mem_ctl_info *mci = dev_id; | ||
939 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
940 | u32 err_detect; | ||
941 | |||
942 | err_detect = in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT); | ||
943 | if (!err_detect) | ||
944 | return IRQ_NONE; | ||
945 | |||
946 | mpc85xx_mc_check(mci); | ||
947 | |||
948 | return IRQ_HANDLED; | ||
949 | } | ||
950 | |||
951 | static void mpc85xx_init_csrows(struct mem_ctl_info *mci) | ||
952 | { | ||
953 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
954 | struct csrow_info *csrow; | ||
955 | struct dimm_info *dimm; | ||
956 | u32 sdram_ctl; | ||
957 | u32 sdtype; | ||
958 | enum mem_type mtype; | ||
959 | u32 cs_bnds; | ||
960 | int index; | ||
961 | |||
962 | sdram_ctl = in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG); | ||
963 | |||
964 | sdtype = sdram_ctl & DSC_SDTYPE_MASK; | ||
965 | if (sdram_ctl & DSC_RD_EN) { | ||
966 | switch (sdtype) { | ||
967 | case DSC_SDTYPE_DDR: | ||
968 | mtype = MEM_RDDR; | ||
969 | break; | ||
970 | case DSC_SDTYPE_DDR2: | ||
971 | mtype = MEM_RDDR2; | ||
972 | break; | ||
973 | case DSC_SDTYPE_DDR3: | ||
974 | mtype = MEM_RDDR3; | ||
975 | break; | ||
976 | default: | ||
977 | mtype = MEM_UNKNOWN; | ||
978 | break; | ||
979 | } | ||
980 | } else { | ||
981 | switch (sdtype) { | ||
982 | case DSC_SDTYPE_DDR: | ||
983 | mtype = MEM_DDR; | ||
984 | break; | ||
985 | case DSC_SDTYPE_DDR2: | ||
986 | mtype = MEM_DDR2; | ||
987 | break; | ||
988 | case DSC_SDTYPE_DDR3: | ||
989 | mtype = MEM_DDR3; | ||
990 | break; | ||
991 | default: | ||
992 | mtype = MEM_UNKNOWN; | ||
993 | break; | ||
994 | } | ||
995 | } | ||
996 | |||
997 | for (index = 0; index < mci->nr_csrows; index++) { | ||
998 | u32 start; | ||
999 | u32 end; | ||
1000 | |||
1001 | csrow = mci->csrows[index]; | ||
1002 | dimm = csrow->channels[0]->dimm; | ||
1003 | |||
1004 | cs_bnds = in_be32(pdata->mc_vbase + MPC85XX_MC_CS_BNDS_0 + | ||
1005 | (index * MPC85XX_MC_CS_BNDS_OFS)); | ||
1006 | |||
1007 | start = (cs_bnds & 0xffff0000) >> 16; | ||
1008 | end = (cs_bnds & 0x0000ffff); | ||
1009 | |||
1010 | if (start == end) | ||
1011 | continue; /* not populated */ | ||
1012 | |||
1013 | start <<= (24 - PAGE_SHIFT); | ||
1014 | end <<= (24 - PAGE_SHIFT); | ||
1015 | end |= (1 << (24 - PAGE_SHIFT)) - 1; | ||
1016 | |||
1017 | csrow->first_page = start; | ||
1018 | csrow->last_page = end; | ||
1019 | |||
1020 | dimm->nr_pages = end + 1 - start; | ||
1021 | dimm->grain = 8; | ||
1022 | dimm->mtype = mtype; | ||
1023 | dimm->dtype = DEV_UNKNOWN; | ||
1024 | if (sdram_ctl & DSC_X32_EN) | ||
1025 | dimm->dtype = DEV_X32; | ||
1026 | dimm->edac_mode = EDAC_SECDED; | ||
1027 | } | ||
1028 | } | ||
1029 | |||
1030 | static int mpc85xx_mc_err_probe(struct platform_device *op) | ||
1031 | { | ||
1032 | struct mem_ctl_info *mci; | ||
1033 | struct edac_mc_layer layers[2]; | ||
1034 | struct mpc85xx_mc_pdata *pdata; | ||
1035 | struct resource r; | ||
1036 | u32 sdram_ctl; | ||
1037 | int res; | ||
1038 | |||
1039 | if (!devres_open_group(&op->dev, mpc85xx_mc_err_probe, GFP_KERNEL)) | ||
1040 | return -ENOMEM; | ||
1041 | |||
1042 | layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; | ||
1043 | layers[0].size = 4; | ||
1044 | layers[0].is_virt_csrow = true; | ||
1045 | layers[1].type = EDAC_MC_LAYER_CHANNEL; | ||
1046 | layers[1].size = 1; | ||
1047 | layers[1].is_virt_csrow = false; | ||
1048 | mci = edac_mc_alloc(edac_mc_idx, ARRAY_SIZE(layers), layers, | ||
1049 | sizeof(*pdata)); | ||
1050 | if (!mci) { | ||
1051 | devres_release_group(&op->dev, mpc85xx_mc_err_probe); | ||
1052 | return -ENOMEM; | ||
1053 | } | ||
1054 | |||
1055 | pdata = mci->pvt_info; | ||
1056 | pdata->name = "mpc85xx_mc_err"; | ||
1057 | pdata->irq = NO_IRQ; | ||
1058 | mci->pdev = &op->dev; | ||
1059 | pdata->edac_idx = edac_mc_idx++; | ||
1060 | dev_set_drvdata(mci->pdev, mci); | ||
1061 | mci->ctl_name = pdata->name; | ||
1062 | mci->dev_name = pdata->name; | ||
1063 | |||
1064 | res = of_address_to_resource(op->dev.of_node, 0, &r); | ||
1065 | if (res) { | ||
1066 | pr_err("%s: Unable to get resource for MC err regs\n", __func__); | ||
1067 | goto err; | ||
1068 | } | ||
1069 | |||
1070 | if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r), | ||
1071 | pdata->name)) { | ||
1072 | pr_err("%s: Error while requesting mem region\n", __func__); | ||
1073 | res = -EBUSY; | ||
1074 | goto err; | ||
1075 | } | ||
1076 | |||
1077 | pdata->mc_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r)); | ||
1078 | if (!pdata->mc_vbase) { | ||
1079 | pr_err("%s: Unable to setup MC err regs\n", __func__); | ||
1080 | res = -ENOMEM; | ||
1081 | goto err; | ||
1082 | } | ||
1083 | |||
1084 | sdram_ctl = in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG); | ||
1085 | if (!(sdram_ctl & DSC_ECC_EN)) { | ||
1086 | /* no ECC */ | ||
1087 | pr_warn("%s: No ECC DIMMs discovered\n", __func__); | ||
1088 | res = -ENODEV; | ||
1089 | goto err; | ||
1090 | } | ||
1091 | |||
1092 | edac_dbg(3, "init mci\n"); | ||
1093 | mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_RDDR2 | | ||
1094 | MEM_FLAG_DDR | MEM_FLAG_DDR2; | ||
1095 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; | ||
1096 | mci->edac_cap = EDAC_FLAG_SECDED; | ||
1097 | mci->mod_name = EDAC_MOD_STR; | ||
1098 | mci->mod_ver = MPC85XX_REVISION; | ||
1099 | |||
1100 | if (edac_op_state == EDAC_OPSTATE_POLL) | ||
1101 | mci->edac_check = mpc85xx_mc_check; | ||
1102 | |||
1103 | mci->ctl_page_to_phys = NULL; | ||
1104 | |||
1105 | mci->scrub_mode = SCRUB_SW_SRC; | ||
1106 | |||
1107 | mpc85xx_init_csrows(mci); | ||
1108 | |||
1109 | /* store the original error disable bits */ | ||
1110 | orig_ddr_err_disable = | ||
1111 | in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE); | ||
1112 | out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE, 0); | ||
1113 | |||
1114 | /* clear all error bits */ | ||
1115 | out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, ~0); | ||
1116 | |||
1117 | if (edac_mc_add_mc_with_groups(mci, mpc85xx_dev_groups)) { | ||
1118 | edac_dbg(3, "failed edac_mc_add_mc()\n"); | ||
1119 | goto err; | ||
1120 | } | ||
1121 | |||
1122 | if (edac_op_state == EDAC_OPSTATE_INT) { | ||
1123 | out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_INT_EN, | ||
1124 | DDR_EIE_MBEE | DDR_EIE_SBEE); | ||
1125 | |||
1126 | /* store the original error management threshold */ | ||
1127 | orig_ddr_err_sbe = in_be32(pdata->mc_vbase + | ||
1128 | MPC85XX_MC_ERR_SBE) & 0xff0000; | ||
1129 | |||
1130 | /* set threshold to 1 error per interrupt */ | ||
1131 | out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_SBE, 0x10000); | ||
1132 | |||
1133 | /* register interrupts */ | ||
1134 | pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0); | ||
1135 | res = devm_request_irq(&op->dev, pdata->irq, | ||
1136 | mpc85xx_mc_isr, | ||
1137 | IRQF_SHARED, | ||
1138 | "[EDAC] MC err", mci); | ||
1139 | if (res < 0) { | ||
1140 | pr_err("%s: Unable to request irq %d for MPC85xx DRAM ERR\n", | ||
1141 | __func__, pdata->irq); | ||
1142 | irq_dispose_mapping(pdata->irq); | ||
1143 | res = -ENODEV; | ||
1144 | goto err2; | ||
1145 | } | ||
1146 | |||
1147 | pr_info(EDAC_MOD_STR " acquired irq %d for MC\n", pdata->irq); | ||
1148 | } | ||
1149 | |||
1150 | devres_remove_group(&op->dev, mpc85xx_mc_err_probe); | ||
1151 | edac_dbg(3, "success\n"); | ||
1152 | pr_info(EDAC_MOD_STR " MC err registered\n"); | ||
1153 | |||
1154 | return 0; | ||
1155 | |||
1156 | err2: | ||
1157 | edac_mc_del_mc(&op->dev); | ||
1158 | err: | ||
1159 | devres_release_group(&op->dev, mpc85xx_mc_err_probe); | ||
1160 | edac_mc_free(mci); | ||
1161 | return res; | ||
1162 | } | ||
1163 | |||
1164 | static int mpc85xx_mc_err_remove(struct platform_device *op) | ||
1165 | { | ||
1166 | struct mem_ctl_info *mci = dev_get_drvdata(&op->dev); | ||
1167 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
1168 | |||
1169 | edac_dbg(0, "\n"); | ||
1170 | |||
1171 | if (edac_op_state == EDAC_OPSTATE_INT) { | ||
1172 | out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_INT_EN, 0); | ||
1173 | irq_dispose_mapping(pdata->irq); | ||
1174 | } | ||
1175 | |||
1176 | out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE, | ||
1177 | orig_ddr_err_disable); | ||
1178 | out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_SBE, orig_ddr_err_sbe); | ||
1179 | |||
1180 | edac_mc_del_mc(&op->dev); | ||
1181 | edac_mc_free(mci); | ||
1182 | return 0; | ||
1183 | } | ||
1184 | |||
1185 | static const struct of_device_id mpc85xx_mc_err_of_match[] = { | 631 | static const struct of_device_id mpc85xx_mc_err_of_match[] = { |
1186 | /* deprecate the fsl,85.. forms in the future, 2.6.30? */ | 632 | /* deprecate the fsl,85.. forms in the future, 2.6.30? */ |
1187 | { .compatible = "fsl,8540-memory-controller", }, | 633 | { .compatible = "fsl,8540-memory-controller", }, |
diff --git a/drivers/edac/mpc85xx_edac.h b/drivers/edac/mpc85xx_edac.h index 9352e88d53e5..3f6fb16ad34f 100644 --- a/drivers/edac/mpc85xx_edac.h +++ b/drivers/edac/mpc85xx_edac.h | |||
@@ -17,65 +17,6 @@ | |||
17 | #define mpc85xx_printk(level, fmt, arg...) \ | 17 | #define mpc85xx_printk(level, fmt, arg...) \ |
18 | edac_printk(level, "MPC85xx", fmt, ##arg) | 18 | edac_printk(level, "MPC85xx", fmt, ##arg) |
19 | 19 | ||
20 | #define mpc85xx_mc_printk(mci, level, fmt, arg...) \ | ||
21 | edac_mc_chipset_printk(mci, level, "MPC85xx", fmt, ##arg) | ||
22 | |||
23 | /* | ||
24 | * DRAM error defines | ||
25 | */ | ||
26 | |||
27 | /* DDR_SDRAM_CFG */ | ||
28 | #define MPC85XX_MC_DDR_SDRAM_CFG 0x0110 | ||
29 | #define MPC85XX_MC_CS_BNDS_0 0x0000 | ||
30 | #define MPC85XX_MC_CS_BNDS_1 0x0008 | ||
31 | #define MPC85XX_MC_CS_BNDS_2 0x0010 | ||
32 | #define MPC85XX_MC_CS_BNDS_3 0x0018 | ||
33 | #define MPC85XX_MC_CS_BNDS_OFS 0x0008 | ||
34 | |||
35 | #define MPC85XX_MC_DATA_ERR_INJECT_HI 0x0e00 | ||
36 | #define MPC85XX_MC_DATA_ERR_INJECT_LO 0x0e04 | ||
37 | #define MPC85XX_MC_ECC_ERR_INJECT 0x0e08 | ||
38 | #define MPC85XX_MC_CAPTURE_DATA_HI 0x0e20 | ||
39 | #define MPC85XX_MC_CAPTURE_DATA_LO 0x0e24 | ||
40 | #define MPC85XX_MC_CAPTURE_ECC 0x0e28 | ||
41 | #define MPC85XX_MC_ERR_DETECT 0x0e40 | ||
42 | #define MPC85XX_MC_ERR_DISABLE 0x0e44 | ||
43 | #define MPC85XX_MC_ERR_INT_EN 0x0e48 | ||
44 | #define MPC85XX_MC_CAPTURE_ATRIBUTES 0x0e4c | ||
45 | #define MPC85XX_MC_CAPTURE_ADDRESS 0x0e50 | ||
46 | #define MPC85XX_MC_CAPTURE_EXT_ADDRESS 0x0e54 | ||
47 | #define MPC85XX_MC_ERR_SBE 0x0e58 | ||
48 | |||
49 | #define DSC_MEM_EN 0x80000000 | ||
50 | #define DSC_ECC_EN 0x20000000 | ||
51 | #define DSC_RD_EN 0x10000000 | ||
52 | #define DSC_DBW_MASK 0x00180000 | ||
53 | #define DSC_DBW_32 0x00080000 | ||
54 | #define DSC_DBW_64 0x00000000 | ||
55 | |||
56 | #define DSC_SDTYPE_MASK 0x07000000 | ||
57 | |||
58 | #define DSC_SDTYPE_DDR 0x02000000 | ||
59 | #define DSC_SDTYPE_DDR2 0x03000000 | ||
60 | #define DSC_SDTYPE_DDR3 0x07000000 | ||
61 | #define DSC_X32_EN 0x00000020 | ||
62 | |||
63 | /* Err_Int_En */ | ||
64 | #define DDR_EIE_MSEE 0x1 /* memory select */ | ||
65 | #define DDR_EIE_SBEE 0x4 /* single-bit ECC error */ | ||
66 | #define DDR_EIE_MBEE 0x8 /* multi-bit ECC error */ | ||
67 | |||
68 | /* Err_Detect */ | ||
69 | #define DDR_EDE_MSE 0x1 /* memory select */ | ||
70 | #define DDR_EDE_SBE 0x4 /* single-bit ECC error */ | ||
71 | #define DDR_EDE_MBE 0x8 /* multi-bit ECC error */ | ||
72 | #define DDR_EDE_MME 0x80000000 /* multiple memory errors */ | ||
73 | |||
74 | /* Err_Disable */ | ||
75 | #define DDR_EDI_MSED 0x1 /* memory select disable */ | ||
76 | #define DDR_EDI_SBED 0x4 /* single-bit ECC error disable */ | ||
77 | #define DDR_EDI_MBED 0x8 /* multi-bit ECC error disable */ | ||
78 | |||
79 | /* | 20 | /* |
80 | * L2 Err defines | 21 | * L2 Err defines |
81 | */ | 22 | */ |
@@ -149,13 +90,6 @@ | |||
149 | #define MPC85XX_PCIE_ERR_CAP_R2 0x0030 | 90 | #define MPC85XX_PCIE_ERR_CAP_R2 0x0030 |
150 | #define MPC85XX_PCIE_ERR_CAP_R3 0x0034 | 91 | #define MPC85XX_PCIE_ERR_CAP_R3 0x0034 |
151 | 92 | ||
152 | struct mpc85xx_mc_pdata { | ||
153 | char *name; | ||
154 | int edac_idx; | ||
155 | void __iomem *mc_vbase; | ||
156 | int irq; | ||
157 | }; | ||
158 | |||
159 | struct mpc85xx_l2_pdata { | 93 | struct mpc85xx_l2_pdata { |
160 | char *name; | 94 | char *name; |
161 | int edac_idx; | 95 | int edac_idx; |