aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac
diff options
context:
space:
mode:
authorPunnaiah Choudary Kalluri <punnaiah.choudary.kalluri@xilinx.com>2015-01-06 12:43:47 -0500
committerBorislav Petkov <bp@suse.de>2015-01-07 05:42:05 -0500
commitae9b56e3996dadbb59c727018f45486c06844261 (patch)
tree5f279f73e994d47823ad244a71383d13d5ed61ad /drivers/edac
parent775c503f65679c46647c9414b218738b7062b215 (diff)
EDAC, synps: Add EDAC support for zynq ddr ecc controller
Add EDAC support for ecc errors reporting on the synopsys ddr controller. The ddr ecc controller corrects single bit errors and detects double bit errors. Selected important-ish notes from the changelog: - I have not taken care of spliting synps_edac_geterror_info function as it adds additional indentation levels and moreover the existing changes were made as part of the v2 review comments - Removed dt binding info as already there is a binding info available under memorycontroller. so, updated ecc info there. - Shortened the prefix "sysnopsys" to "synps" Signed-off-by: Punnaiah Choudary Kalluri <punnaia@xilinx.com> Link: http://lkml.kernel.org/r/a728a8d4678f4dbf9de189a480297c3d@BY2FFO11FD034.protection.gbl [ Boris: massage commit message. ] Signed-off-by: Borislav Petkov <bp@suse.de>
Diffstat (limited to 'drivers/edac')
-rw-r--r--drivers/edac/Kconfig7
-rw-r--r--drivers/edac/Makefile1
-rw-r--r--drivers/edac/synopsys_edac.c535
3 files changed, 543 insertions, 0 deletions
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 49c265255a07..cb59619df23f 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -385,4 +385,11 @@ config EDAC_ALTERA_MC
385 preloader must initialize the SDRAM before loading 385 preloader must initialize the SDRAM before loading
386 the kernel. 386 the kernel.
387 387
388config EDAC_SYNOPSYS
389 tristate "Synopsys DDR Memory Controller"
390 depends on EDAC_MM_EDAC && ARCH_ZYNQ
391 help
392 Support for error detection and correction on the Synopsys DDR
393 memory controller.
394
388endif # EDAC 395endif # EDAC
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index d40c69a04df7..b255f362b1db 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -67,3 +67,4 @@ obj-$(CONFIG_EDAC_OCTEON_LMC) += octeon_edac-lmc.o
67obj-$(CONFIG_EDAC_OCTEON_PCI) += octeon_edac-pci.o 67obj-$(CONFIG_EDAC_OCTEON_PCI) += octeon_edac-pci.o
68 68
69obj-$(CONFIG_EDAC_ALTERA_MC) += altera_edac.o 69obj-$(CONFIG_EDAC_ALTERA_MC) += altera_edac.o
70obj-$(CONFIG_EDAC_SYNOPSYS) += synopsys_edac.o
diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c
new file mode 100644
index 000000000000..1c9691535e13
--- /dev/null
+++ b/drivers/edac/synopsys_edac.c
@@ -0,0 +1,535 @@
1/*
2 * Synopsys DDR ECC Driver
3 * This driver is based on ppc4xx_edac.c drivers
4 *
5 * Copyright (C) 2012 - 2014 Xilinx, Inc.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * This file is subject to the terms and conditions of the GNU General Public
18 * License. See the file "COPYING" in the main directory of this archive
19 * for more details
20 */
21
22#include <linux/edac.h>
23#include <linux/module.h>
24#include <linux/platform_device.h>
25
26#include "edac_core.h"
27
28/* Number of cs_rows needed per memory controller */
29#define SYNPS_EDAC_NR_CSROWS 1
30
31/* Number of channels per memory controller */
32#define SYNPS_EDAC_NR_CHANS 1
33
34/* Granularity of reported error in bytes */
35#define SYNPS_EDAC_ERR_GRAIN 1
36
37#define SYNPS_EDAC_MSG_SIZE 256
38
39#define SYNPS_EDAC_MOD_STRING "synps_edac"
40#define SYNPS_EDAC_MOD_VER "1"
41
42/* Synopsys DDR memory controller registers that are relevant to ECC */
43#define CTRL_OFST 0x0
44#define T_ZQ_OFST 0xA4
45
46/* ECC control register */
47#define ECC_CTRL_OFST 0xC4
48/* ECC log register */
49#define CE_LOG_OFST 0xC8
50/* ECC address register */
51#define CE_ADDR_OFST 0xCC
52/* ECC data[31:0] register */
53#define CE_DATA_31_0_OFST 0xD0
54
55/* Uncorrectable error info registers */
56#define UE_LOG_OFST 0xDC
57#define UE_ADDR_OFST 0xE0
58#define UE_DATA_31_0_OFST 0xE4
59
60#define STAT_OFST 0xF0
61#define SCRUB_OFST 0xF4
62
63/* Control register bit field definitions */
64#define CTRL_BW_MASK 0xC
65#define CTRL_BW_SHIFT 2
66
67#define DDRCTL_WDTH_16 1
68#define DDRCTL_WDTH_32 0
69
70/* ZQ register bit field definitions */
71#define T_ZQ_DDRMODE_MASK 0x2
72
73/* ECC control register bit field definitions */
74#define ECC_CTRL_CLR_CE_ERR 0x2
75#define ECC_CTRL_CLR_UE_ERR 0x1
76
77/* ECC correctable/uncorrectable error log register definitions */
78#define LOG_VALID 0x1
79#define CE_LOG_BITPOS_MASK 0xFE
80#define CE_LOG_BITPOS_SHIFT 1
81
82/* ECC correctable/uncorrectable error address register definitions */
83#define ADDR_COL_MASK 0xFFF
84#define ADDR_ROW_MASK 0xFFFF000
85#define ADDR_ROW_SHIFT 12
86#define ADDR_BANK_MASK 0x70000000
87#define ADDR_BANK_SHIFT 28
88
89/* ECC statistic register definitions */
90#define STAT_UECNT_MASK 0xFF
91#define STAT_CECNT_MASK 0xFF00
92#define STAT_CECNT_SHIFT 8
93
94/* ECC scrub register definitions */
95#define SCRUB_MODE_MASK 0x7
96#define SCRUB_MODE_SECDED 0x4
97
98/**
99 * struct ecc_error_info - ECC error log information
100 * @row: Row number
101 * @col: Column number
102 * @bank: Bank number
103 * @bitpos: Bit position
104 * @data: Data causing the error
105 */
106struct ecc_error_info {
107 u32 row;
108 u32 col;
109 u32 bank;
110 u32 bitpos;
111 u32 data;
112};
113
114/**
115 * struct synps_ecc_status - ECC status information to report
116 * @ce_cnt: Correctable error count
117 * @ue_cnt: Uncorrectable error count
118 * @ceinfo: Correctable error log information
119 * @ueinfo: Uncorrectable error log information
120 */
121struct synps_ecc_status {
122 u32 ce_cnt;
123 u32 ue_cnt;
124 struct ecc_error_info ceinfo;
125 struct ecc_error_info ueinfo;
126};
127
128/**
129 * struct synps_edac_priv - DDR memory controller private instance data
130 * @baseaddr: Base address of the DDR controller
131 * @message: Buffer for framing the event specific info
132 * @stat: ECC status information
133 * @ce_cnt: Correctable Error count
134 * @ue_cnt: Uncorrectable Error count
135 */
136struct synps_edac_priv {
137 void __iomem *baseaddr;
138 char message[SYNPS_EDAC_MSG_SIZE];
139 struct synps_ecc_status stat;
140 u32 ce_cnt;
141 u32 ue_cnt;
142};
143
144/**
145 * synps_edac_geterror_info - Get the current ecc error info
146 * @base: Pointer to the base address of the ddr memory controller
147 * @p: Pointer to the synopsys ecc status structure
148 *
149 * Determines there is any ecc error or not
150 *
151 * Return: one if there is no error otherwise returns zero
152 */
153static int synps_edac_geterror_info(void __iomem *base,
154 struct synps_ecc_status *p)
155{
156 u32 regval, clearval = 0;
157
158 regval = readl(base + STAT_OFST);
159 if (!regval)
160 return 1;
161
162 p->ce_cnt = (regval & STAT_CECNT_MASK) >> STAT_CECNT_SHIFT;
163 p->ue_cnt = regval & STAT_UECNT_MASK;
164
165 regval = readl(base + CE_LOG_OFST);
166 if (!(p->ce_cnt && (regval & LOG_VALID)))
167 goto ue_err;
168
169 p->ceinfo.bitpos = (regval & CE_LOG_BITPOS_MASK) >> CE_LOG_BITPOS_SHIFT;
170 regval = readl(base + CE_ADDR_OFST);
171 p->ceinfo.row = (regval & ADDR_ROW_MASK) >> ADDR_ROW_SHIFT;
172 p->ceinfo.col = regval & ADDR_COL_MASK;
173 p->ceinfo.bank = (regval & ADDR_BANK_MASK) >> ADDR_BANK_SHIFT;
174 p->ceinfo.data = readl(base + CE_DATA_31_0_OFST);
175 edac_dbg(3, "ce bit position: %d data: %d\n", p->ceinfo.bitpos,
176 p->ceinfo.data);
177 clearval = ECC_CTRL_CLR_CE_ERR;
178
179ue_err:
180 regval = readl(base + UE_LOG_OFST);
181 if (!(p->ue_cnt && (regval & LOG_VALID)))
182 goto out;
183
184 regval = readl(base + UE_ADDR_OFST);
185 p->ueinfo.row = (regval & ADDR_ROW_MASK) >> ADDR_ROW_SHIFT;
186 p->ueinfo.col = regval & ADDR_COL_MASK;
187 p->ueinfo.bank = (regval & ADDR_BANK_MASK) >> ADDR_BANK_SHIFT;
188 p->ueinfo.data = readl(base + UE_DATA_31_0_OFST);
189 clearval |= ECC_CTRL_CLR_UE_ERR;
190
191out:
192 writel(clearval, base + ECC_CTRL_OFST);
193 writel(0x0, base + ECC_CTRL_OFST);
194
195 return 0;
196}
197
198/**
199 * synps_edac_handle_error - Handle controller error types CE and UE
200 * @mci: Pointer to the edac memory controller instance
201 * @p: Pointer to the synopsys ecc status structure
202 *
203 * Handles the controller ECC correctable and un correctable error.
204 */
205static void synps_edac_handle_error(struct mem_ctl_info *mci,
206 struct synps_ecc_status *p)
207{
208 struct synps_edac_priv *priv = mci->pvt_info;
209 struct ecc_error_info *pinf;
210
211 if (p->ce_cnt) {
212 pinf = &p->ceinfo;
213 snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
214 "DDR ECC error type :%s Row %d Bank %d Col %d ",
215 "CE", pinf->row, pinf->bank, pinf->col);
216 edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
217 p->ce_cnt, 0, 0, 0, 0, 0, -1,
218 priv->message, "");
219 }
220
221 if (p->ue_cnt) {
222 pinf = &p->ueinfo;
223 snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
224 "DDR ECC error type :%s Row %d Bank %d Col %d ",
225 "UE", pinf->row, pinf->bank, pinf->col);
226 edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
227 p->ue_cnt, 0, 0, 0, 0, 0, -1,
228 priv->message, "");
229 }
230
231 memset(p, 0, sizeof(*p));
232}
233
234/**
235 * synps_edac_check - Check controller for ECC errors
236 * @mci: Pointer to the edac memory controller instance
237 *
238 * Used to check and post ECC errors. Called by the polling thread
239 */
240static void synps_edac_check(struct mem_ctl_info *mci)
241{
242 struct synps_edac_priv *priv = mci->pvt_info;
243 int status;
244
245 status = synps_edac_geterror_info(priv->baseaddr, &priv->stat);
246 if (status)
247 return;
248
249 priv->ce_cnt += priv->stat.ce_cnt;
250 priv->ue_cnt += priv->stat.ue_cnt;
251 synps_edac_handle_error(mci, &priv->stat);
252
253 edac_dbg(3, "Total error count ce %d ue %d\n",
254 priv->ce_cnt, priv->ue_cnt);
255}
256
257/**
258 * synps_edac_get_dtype - Return the controller memory width
259 * @base: Pointer to the ddr memory controller base address
260 *
261 * Get the EDAC device type width appropriate for the current controller
262 * configuration.
263 *
264 * Return: a device type width enumeration.
265 */
266static enum dev_type synps_edac_get_dtype(const void __iomem *base)
267{
268 enum dev_type dt;
269 u32 width;
270
271 width = readl(base + CTRL_OFST);
272 width = (width & CTRL_BW_MASK) >> CTRL_BW_SHIFT;
273
274 switch (width) {
275 case DDRCTL_WDTH_16:
276 dt = DEV_X2;
277 break;
278 case DDRCTL_WDTH_32:
279 dt = DEV_X4;
280 break;
281 default:
282 dt = DEV_UNKNOWN;
283 }
284
285 return dt;
286}
287
288/**
289 * synps_edac_get_eccstate - Return the controller ecc enable/disable status
290 * @base: Pointer to the ddr memory controller base address
291 *
292 * Get the ECC enable/disable status for the controller
293 *
294 * Return: a ecc status boolean i.e true/false - enabled/disabled.
295 */
296static bool synps_edac_get_eccstate(void __iomem *base)
297{
298 enum dev_type dt;
299 u32 ecctype;
300 bool state = false;
301
302 dt = synps_edac_get_dtype(base);
303 if (dt == DEV_UNKNOWN)
304 return state;
305
306 ecctype = readl(base + SCRUB_OFST) & SCRUB_MODE_MASK;
307 if ((ecctype == SCRUB_MODE_SECDED) && (dt == DEV_X2))
308 state = true;
309
310 return state;
311}
312
313/**
314 * synps_edac_get_memsize - reads the size of the attached memory device
315 *
316 * Return: the memory size in bytes
317 */
318static u32 synps_edac_get_memsize(void)
319{
320 struct sysinfo inf;
321
322 si_meminfo(&inf);
323
324 return inf.totalram * inf.mem_unit;
325}
326
327/**
328 * synps_edac_get_mtype - Returns controller memory type
329 * @base: pointer to the synopsys ecc status structure
330 *
331 * Get the EDAC memory type appropriate for the current controller
332 * configuration.
333 *
334 * Return: a memory type enumeration.
335 */
336static enum mem_type synps_edac_get_mtype(const void __iomem *base)
337{
338 enum mem_type mt;
339 u32 memtype;
340
341 memtype = readl(base + T_ZQ_OFST);
342
343 if (memtype & T_ZQ_DDRMODE_MASK)
344 mt = MEM_DDR3;
345 else
346 mt = MEM_DDR2;
347
348 return mt;
349}
350
351/**
352 * synps_edac_init_csrows - Initialize the cs row data
353 * @mci: Pointer to the edac memory controller instance
354 *
355 * Initializes the chip select rows associated with the EDAC memory
356 * controller instance
357 *
358 * Return: Unconditionally 0.
359 */
360static int synps_edac_init_csrows(struct mem_ctl_info *mci)
361{
362 struct csrow_info *csi;
363 struct dimm_info *dimm;
364 struct synps_edac_priv *priv = mci->pvt_info;
365 u32 size;
366 int row, j;
367
368 for (row = 0; row < mci->nr_csrows; row++) {
369 csi = mci->csrows[row];
370 size = synps_edac_get_memsize();
371
372 for (j = 0; j < csi->nr_channels; j++) {
373 dimm = csi->channels[j]->dimm;
374 dimm->edac_mode = EDAC_FLAG_SECDED;
375 dimm->mtype = synps_edac_get_mtype(priv->baseaddr);
376 dimm->nr_pages = (size >> PAGE_SHIFT) / csi->nr_channels;
377 dimm->grain = SYNPS_EDAC_ERR_GRAIN;
378 dimm->dtype = synps_edac_get_dtype(priv->baseaddr);
379 }
380 }
381
382 return 0;
383}
384
385/**
386 * synps_edac_mc_init - Initialize driver instance
387 * @mci: Pointer to the edac memory controller instance
388 * @pdev: Pointer to the platform_device struct
389 *
390 * Performs initialization of the EDAC memory controller instance and
391 * related driver-private data associated with the memory controller the
392 * instance is bound to.
393 *
394 * Return: Always zero.
395 */
396static int synps_edac_mc_init(struct mem_ctl_info *mci,
397 struct platform_device *pdev)
398{
399 int status;
400 struct synps_edac_priv *priv;
401
402 mci->pdev = &pdev->dev;
403 priv = mci->pvt_info;
404 platform_set_drvdata(pdev, mci);
405
406 /* Initialize controller capabilities and configuration */
407 mci->mtype_cap = MEM_FLAG_DDR3 | MEM_FLAG_DDR2;
408 mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
409 mci->scrub_cap = SCRUB_HW_SRC;
410 mci->scrub_mode = SCRUB_NONE;
411
412 mci->edac_cap = EDAC_FLAG_SECDED;
413 mci->ctl_name = "synps_ddr_controller";
414 mci->dev_name = SYNPS_EDAC_MOD_STRING;
415 mci->mod_name = SYNPS_EDAC_MOD_VER;
416 mci->mod_ver = "1";
417
418 edac_op_state = EDAC_OPSTATE_POLL;
419 mci->edac_check = synps_edac_check;
420 mci->ctl_page_to_phys = NULL;
421
422 status = synps_edac_init_csrows(mci);
423
424 return status;
425}
426
427/**
428 * synps_edac_mc_probe - Check controller and bind driver
429 * @pdev: Pointer to the platform_device struct
430 *
431 * Probes a specific controller instance for binding with the driver.
432 *
433 * Return: 0 if the controller instance was successfully bound to the
434 * driver; otherwise, < 0 on error.
435 */
436static int synps_edac_mc_probe(struct platform_device *pdev)
437{
438 struct mem_ctl_info *mci;
439 struct edac_mc_layer layers[2];
440 struct synps_edac_priv *priv;
441 int rc;
442 struct resource *res;
443 void __iomem *baseaddr;
444
445 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
446 baseaddr = devm_ioremap_resource(&pdev->dev, res);
447 if (IS_ERR(baseaddr))
448 return PTR_ERR(baseaddr);
449
450 if (!synps_edac_get_eccstate(baseaddr)) {
451 edac_printk(KERN_INFO, EDAC_MC, "ECC not enabled\n");
452 return -ENXIO;
453 }
454
455 layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
456 layers[0].size = SYNPS_EDAC_NR_CSROWS;
457 layers[0].is_virt_csrow = true;
458 layers[1].type = EDAC_MC_LAYER_CHANNEL;
459 layers[1].size = SYNPS_EDAC_NR_CHANS;
460 layers[1].is_virt_csrow = false;
461
462 mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers,
463 sizeof(struct synps_edac_priv));
464 if (!mci) {
465 edac_printk(KERN_ERR, EDAC_MC,
466 "Failed memory allocation for mc instance\n");
467 return -ENOMEM;
468 }
469
470 priv = mci->pvt_info;
471 priv->baseaddr = baseaddr;
472 rc = synps_edac_mc_init(mci, pdev);
473 if (rc) {
474 edac_printk(KERN_ERR, EDAC_MC,
475 "Failed to initialize instance\n");
476 goto free_edac_mc;
477 }
478
479 rc = edac_mc_add_mc(mci);
480 if (rc) {
481 edac_printk(KERN_ERR, EDAC_MC,
482 "Failed to register with EDAC core\n");
483 goto free_edac_mc;
484 }
485
486 /*
487 * Start capturing the correctable and uncorrectable errors. A write of
488 * 0 starts the counters.
489 */
490 writel(0x0, baseaddr + ECC_CTRL_OFST);
491 return rc;
492
493free_edac_mc:
494 edac_mc_free(mci);
495
496 return rc;
497}
498
499/**
500 * synps_edac_mc_remove - Unbind driver from controller
501 * @pdev: Pointer to the platform_device struct
502 *
503 * Return: Unconditionally 0
504 */
505static int synps_edac_mc_remove(struct platform_device *pdev)
506{
507 struct mem_ctl_info *mci = platform_get_drvdata(pdev);
508
509 edac_mc_del_mc(&pdev->dev);
510 edac_mc_free(mci);
511
512 return 0;
513}
514
515static struct of_device_id synps_edac_match[] = {
516 { .compatible = "xlnx,zynq-ddrc-a05", },
517 { /* end of table */ }
518};
519
520MODULE_DEVICE_TABLE(of, synps_edac_match);
521
522static struct platform_driver synps_edac_mc_driver = {
523 .driver = {
524 .name = "synopsys-edac",
525 .of_match_table = synps_edac_match,
526 },
527 .probe = synps_edac_mc_probe,
528 .remove = synps_edac_mc_remove,
529};
530
531module_platform_driver(synps_edac_mc_driver);
532
533MODULE_AUTHOR("Xilinx Inc");
534MODULE_DESCRIPTION("Synopsys DDR ECC driver");
535MODULE_LICENSE("GPL v2");