aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-10-08 17:37:16 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-10-08 17:37:16 -0400
commit8b45bc892e6842115fc87c2b2a3b86a20617606a (patch)
tree636c804eb29bb97070e7d2bc4d5ab9d1dad27cac /drivers/edac
parenteb785bef684f2b7d03b530efc8e6f199e9777e2f (diff)
parentfa637bf0595ee1796d728a0d33b6b7fff12e1f3d (diff)
Merge tag 'drivers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC driver updates from Arnd Bergmann: "These are changes for drivers that are intimately tied to some SoC and for some reason could not get merged through the respective subsystem maintainer tree. Most of the new code is for the Keystone Navigator driver, which is new base support that is going to be needed for their hardware accelerated network driver and other units. Most of the commits are for moving old code around from at91 and omap for things that are done in device drivers nowadays. - at91: move reset, poweroff, memory and clocksource code into drivers directories - socfpga: add edac driver (through arm-soc, as requested by Boris) - omap: move omap-intc code to drivers/irqchip - sunxi: added an RTC driver for sun6i - omap: mailbox driver related changes - keystone: support for the "Navigator" component - versatile: new reboot, led and soc drivers" * tag 'drivers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (92 commits) bus: arm-ccn: Fix spurious warning message leds: add device tree bindings for register bit LEDs soc: add driver for the ARM RealView power: reset: driver for the Versatile syscon reboot leds: add a driver for syscon-based LEDs drivers/soc: ti: fix build break with modules MAINTAINERS: Add Keystone Multicore Navigator drivers entry soc: ti: add Keystone Navigator DMA support Documentation: dt: soc: add Keystone Navigator DMA bindings soc: ti: add Keystone Navigator QMSS driver Documentation: dt: soc: add Keystone Navigator QMSS bindings rtc: sunxi: Depend on platforms sun4i/sun7i that actually have the rtc rtc: sun6i: Add sun6i RTC driver irqchip: omap-intc: remove unnecessary comments irqchip: omap-intc: correct maximum number or MIR registers irqchip: omap-intc: enable TURBO idle mode irqchip: omap-intc: enable IP protection irqchip: omap-intc: remove unnecesary of_address_to_resource() call irqchip: omap-intc: comment style cleanup irqchip: omap-intc: minor improvement to omap_irq_pending() ...
Diffstat (limited to 'drivers/edac')
-rw-r--r--drivers/edac/Kconfig9
-rw-r--r--drivers/edac/Makefile2
-rw-r--r--drivers/edac/altera_edac.c410
3 files changed, 421 insertions, 0 deletions
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index fd89ca982748..7072c2892d63 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -376,4 +376,13 @@ config EDAC_OCTEON_PCI
376 Support for error detection and correction on the 376 Support for error detection and correction on the
377 Cavium Octeon family of SOCs. 377 Cavium Octeon family of SOCs.
378 378
379config EDAC_ALTERA_MC
380 tristate "Altera SDRAM Memory Controller EDAC"
381 depends on EDAC_MM_EDAC && ARCH_SOCFPGA
382 help
383 Support for error detection and correction on the
384 Altera SDRAM memory controller. Note that the
385 preloader must initialize the SDRAM before loading
386 the kernel.
387
379endif # EDAC 388endif # EDAC
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index c479a24d8f77..359aa499b200 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -65,3 +65,5 @@ obj-$(CONFIG_EDAC_OCTEON_PC) += octeon_edac-pc.o
65obj-$(CONFIG_EDAC_OCTEON_L2C) += octeon_edac-l2c.o 65obj-$(CONFIG_EDAC_OCTEON_L2C) += octeon_edac-l2c.o
66obj-$(CONFIG_EDAC_OCTEON_LMC) += octeon_edac-lmc.o 66obj-$(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
69obj-$(CONFIG_EDAC_ALTERA_MC) += altera_edac.o
diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c
new file mode 100644
index 000000000000..3c4929fda9d5
--- /dev/null
+++ b/drivers/edac/altera_edac.c
@@ -0,0 +1,410 @@
1/*
2 * Copyright Altera Corporation (C) 2014. All rights reserved.
3 * Copyright 2011-2012 Calxeda, Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Adapted from the highbank_mc_edac driver.
18 */
19
20#include <linux/ctype.h>
21#include <linux/edac.h>
22#include <linux/interrupt.h>
23#include <linux/kernel.h>
24#include <linux/mfd/syscon.h>
25#include <linux/of_platform.h>
26#include <linux/platform_device.h>
27#include <linux/regmap.h>
28#include <linux/types.h>
29#include <linux/uaccess.h>
30
31#include "edac_core.h"
32#include "edac_module.h"
33
34#define EDAC_MOD_STR "altera_edac"
35#define EDAC_VERSION "1"
36
37/* SDRAM Controller CtrlCfg Register */
38#define CTLCFG_OFST 0x00
39
40/* SDRAM Controller CtrlCfg Register Bit Masks */
41#define CTLCFG_ECC_EN 0x400
42#define CTLCFG_ECC_CORR_EN 0x800
43#define CTLCFG_GEN_SB_ERR 0x2000
44#define CTLCFG_GEN_DB_ERR 0x4000
45
46#define CTLCFG_ECC_AUTO_EN (CTLCFG_ECC_EN | \
47 CTLCFG_ECC_CORR_EN)
48
49/* SDRAM Controller Address Width Register */
50#define DRAMADDRW_OFST 0x2C
51
52/* SDRAM Controller Address Widths Field Register */
53#define DRAMADDRW_COLBIT_MASK 0x001F
54#define DRAMADDRW_COLBIT_SHIFT 0
55#define DRAMADDRW_ROWBIT_MASK 0x03E0
56#define DRAMADDRW_ROWBIT_SHIFT 5
57#define DRAMADDRW_BANKBIT_MASK 0x1C00
58#define DRAMADDRW_BANKBIT_SHIFT 10
59#define DRAMADDRW_CSBIT_MASK 0xE000
60#define DRAMADDRW_CSBIT_SHIFT 13
61
62/* SDRAM Controller Interface Data Width Register */
63#define DRAMIFWIDTH_OFST 0x30
64
65/* SDRAM Controller Interface Data Width Defines */
66#define DRAMIFWIDTH_16B_ECC 24
67#define DRAMIFWIDTH_32B_ECC 40
68
69/* SDRAM Controller DRAM Status Register */
70#define DRAMSTS_OFST 0x38
71
72/* SDRAM Controller DRAM Status Register Bit Masks */
73#define DRAMSTS_SBEERR 0x04
74#define DRAMSTS_DBEERR 0x08
75#define DRAMSTS_CORR_DROP 0x10
76
77/* SDRAM Controller DRAM IRQ Register */
78#define DRAMINTR_OFST 0x3C
79
80/* SDRAM Controller DRAM IRQ Register Bit Masks */
81#define DRAMINTR_INTREN 0x01
82#define DRAMINTR_SBEMASK 0x02
83#define DRAMINTR_DBEMASK 0x04
84#define DRAMINTR_CORRDROPMASK 0x08
85#define DRAMINTR_INTRCLR 0x10
86
87/* SDRAM Controller Single Bit Error Count Register */
88#define SBECOUNT_OFST 0x40
89
90/* SDRAM Controller Single Bit Error Count Register Bit Masks */
91#define SBECOUNT_MASK 0x0F
92
93/* SDRAM Controller Double Bit Error Count Register */
94#define DBECOUNT_OFST 0x44
95
96/* SDRAM Controller Double Bit Error Count Register Bit Masks */
97#define DBECOUNT_MASK 0x0F
98
99/* SDRAM Controller ECC Error Address Register */
100#define ERRADDR_OFST 0x48
101
102/* SDRAM Controller ECC Error Address Register Bit Masks */
103#define ERRADDR_MASK 0xFFFFFFFF
104
105/* Altera SDRAM Memory Controller data */
106struct altr_sdram_mc_data {
107 struct regmap *mc_vbase;
108};
109
110static irqreturn_t altr_sdram_mc_err_handler(int irq, void *dev_id)
111{
112 struct mem_ctl_info *mci = dev_id;
113 struct altr_sdram_mc_data *drvdata = mci->pvt_info;
114 u32 status, err_count, err_addr;
115
116 /* Error Address is shared by both SBE & DBE */
117 regmap_read(drvdata->mc_vbase, ERRADDR_OFST, &err_addr);
118
119 regmap_read(drvdata->mc_vbase, DRAMSTS_OFST, &status);
120
121 if (status & DRAMSTS_DBEERR) {
122 regmap_read(drvdata->mc_vbase, DBECOUNT_OFST, &err_count);
123 panic("\nEDAC: [%d Uncorrectable errors @ 0x%08X]\n",
124 err_count, err_addr);
125 }
126 if (status & DRAMSTS_SBEERR) {
127 regmap_read(drvdata->mc_vbase, SBECOUNT_OFST, &err_count);
128 edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, err_count,
129 err_addr >> PAGE_SHIFT,
130 err_addr & ~PAGE_MASK, 0,
131 0, 0, -1, mci->ctl_name, "");
132 }
133
134 regmap_write(drvdata->mc_vbase, DRAMINTR_OFST,
135 (DRAMINTR_INTRCLR | DRAMINTR_INTREN));
136
137 return IRQ_HANDLED;
138}
139
140#ifdef CONFIG_EDAC_DEBUG
141static ssize_t altr_sdr_mc_err_inject_write(struct file *file,
142 const char __user *data,
143 size_t count, loff_t *ppos)
144{
145 struct mem_ctl_info *mci = file->private_data;
146 struct altr_sdram_mc_data *drvdata = mci->pvt_info;
147 u32 *ptemp;
148 dma_addr_t dma_handle;
149 u32 reg, read_reg;
150
151 ptemp = dma_alloc_coherent(mci->pdev, 16, &dma_handle, GFP_KERNEL);
152 if (!ptemp) {
153 dma_free_coherent(mci->pdev, 16, ptemp, dma_handle);
154 edac_printk(KERN_ERR, EDAC_MC,
155 "Inject: Buffer Allocation error\n");
156 return -ENOMEM;
157 }
158
159 regmap_read(drvdata->mc_vbase, CTLCFG_OFST, &read_reg);
160 read_reg &= ~(CTLCFG_GEN_SB_ERR | CTLCFG_GEN_DB_ERR);
161
162 /* Error are injected by writing a word while the SBE or DBE
163 * bit in the CTLCFG register is set. Reading the word will
164 * trigger the SBE or DBE error and the corresponding IRQ.
165 */
166 if (count == 3) {
167 edac_printk(KERN_ALERT, EDAC_MC,
168 "Inject Double bit error\n");
169 regmap_write(drvdata->mc_vbase, CTLCFG_OFST,
170 (read_reg | CTLCFG_GEN_DB_ERR));
171 } else {
172 edac_printk(KERN_ALERT, EDAC_MC,
173 "Inject Single bit error\n");
174 regmap_write(drvdata->mc_vbase, CTLCFG_OFST,
175 (read_reg | CTLCFG_GEN_SB_ERR));
176 }
177
178 ptemp[0] = 0x5A5A5A5A;
179 ptemp[1] = 0xA5A5A5A5;
180
181 /* Clear the error injection bits */
182 regmap_write(drvdata->mc_vbase, CTLCFG_OFST, read_reg);
183 /* Ensure it has been written out */
184 wmb();
185
186 /*
187 * To trigger the error, we need to read the data back
188 * (the data was written with errors above).
189 * The ACCESS_ONCE macros and printk are used to prevent the
190 * the compiler optimizing these reads out.
191 */
192 reg = ACCESS_ONCE(ptemp[0]);
193 read_reg = ACCESS_ONCE(ptemp[1]);
194 /* Force Read */
195 rmb();
196
197 edac_printk(KERN_ALERT, EDAC_MC, "Read Data [0x%X, 0x%X]\n",
198 reg, read_reg);
199
200 dma_free_coherent(mci->pdev, 16, ptemp, dma_handle);
201
202 return count;
203}
204
205static const struct file_operations altr_sdr_mc_debug_inject_fops = {
206 .open = simple_open,
207 .write = altr_sdr_mc_err_inject_write,
208 .llseek = generic_file_llseek,
209};
210
211static void altr_sdr_mc_create_debugfs_nodes(struct mem_ctl_info *mci)
212{
213 if (mci->debugfs)
214 debugfs_create_file("inject_ctrl", S_IWUSR, mci->debugfs, mci,
215 &altr_sdr_mc_debug_inject_fops);
216}
217#else
218static void altr_sdr_mc_create_debugfs_nodes(struct mem_ctl_info *mci)
219{}
220#endif
221
222/* Get total memory size in bytes */
223static u32 altr_sdram_get_total_mem_size(struct regmap *mc_vbase)
224{
225 u32 size, read_reg, row, bank, col, cs, width;
226
227 if (regmap_read(mc_vbase, DRAMADDRW_OFST, &read_reg) < 0)
228 return 0;
229
230 if (regmap_read(mc_vbase, DRAMIFWIDTH_OFST, &width) < 0)
231 return 0;
232
233 col = (read_reg & DRAMADDRW_COLBIT_MASK) >>
234 DRAMADDRW_COLBIT_SHIFT;
235 row = (read_reg & DRAMADDRW_ROWBIT_MASK) >>
236 DRAMADDRW_ROWBIT_SHIFT;
237 bank = (read_reg & DRAMADDRW_BANKBIT_MASK) >>
238 DRAMADDRW_BANKBIT_SHIFT;
239 cs = (read_reg & DRAMADDRW_CSBIT_MASK) >>
240 DRAMADDRW_CSBIT_SHIFT;
241
242 /* Correct for ECC as its not addressible */
243 if (width == DRAMIFWIDTH_32B_ECC)
244 width = 32;
245 if (width == DRAMIFWIDTH_16B_ECC)
246 width = 16;
247
248 /* calculate the SDRAM size base on this info */
249 size = 1 << (row + bank + col);
250 size = size * cs * (width / 8);
251 return size;
252}
253
254static int altr_sdram_probe(struct platform_device *pdev)
255{
256 struct edac_mc_layer layers[2];
257 struct mem_ctl_info *mci;
258 struct altr_sdram_mc_data *drvdata;
259 struct regmap *mc_vbase;
260 struct dimm_info *dimm;
261 u32 read_reg, mem_size;
262 int irq;
263 int res = 0;
264
265 /* Validate the SDRAM controller has ECC enabled */
266 /* Grab the register range from the sdr controller in device tree */
267 mc_vbase = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
268 "altr,sdr-syscon");
269 if (IS_ERR(mc_vbase)) {
270 edac_printk(KERN_ERR, EDAC_MC,
271 "regmap for altr,sdr-syscon lookup failed.\n");
272 return -ENODEV;
273 }
274
275 if (regmap_read(mc_vbase, CTLCFG_OFST, &read_reg) ||
276 ((read_reg & CTLCFG_ECC_AUTO_EN) != CTLCFG_ECC_AUTO_EN)) {
277 edac_printk(KERN_ERR, EDAC_MC,
278 "No ECC/ECC disabled [0x%08X]\n", read_reg);
279 return -ENODEV;
280 }
281
282 /* Grab memory size from device tree. */
283 mem_size = altr_sdram_get_total_mem_size(mc_vbase);
284 if (!mem_size) {
285 edac_printk(KERN_ERR, EDAC_MC,
286 "Unable to calculate memory size\n");
287 return -ENODEV;
288 }
289
290 /* Ensure the SDRAM Interrupt is disabled and cleared */
291 if (regmap_write(mc_vbase, DRAMINTR_OFST, DRAMINTR_INTRCLR)) {
292 edac_printk(KERN_ERR, EDAC_MC,
293 "Error clearing SDRAM ECC IRQ\n");
294 return -ENODEV;
295 }
296
297 irq = platform_get_irq(pdev, 0);
298 if (irq < 0) {
299 edac_printk(KERN_ERR, EDAC_MC,
300 "No irq %d in DT\n", irq);
301 return -ENODEV;
302 }
303
304 layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
305 layers[0].size = 1;
306 layers[0].is_virt_csrow = true;
307 layers[1].type = EDAC_MC_LAYER_CHANNEL;
308 layers[1].size = 1;
309 layers[1].is_virt_csrow = false;
310 mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers,
311 sizeof(struct altr_sdram_mc_data));
312 if (!mci)
313 return -ENOMEM;
314
315 mci->pdev = &pdev->dev;
316 drvdata = mci->pvt_info;
317 drvdata->mc_vbase = mc_vbase;
318 platform_set_drvdata(pdev, mci);
319
320 if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) {
321 res = -ENOMEM;
322 goto free;
323 }
324
325 mci->mtype_cap = MEM_FLAG_DDR3;
326 mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
327 mci->edac_cap = EDAC_FLAG_SECDED;
328 mci->mod_name = EDAC_MOD_STR;
329 mci->mod_ver = EDAC_VERSION;
330 mci->ctl_name = dev_name(&pdev->dev);
331 mci->scrub_mode = SCRUB_SW_SRC;
332 mci->dev_name = dev_name(&pdev->dev);
333
334 dimm = *mci->dimms;
335 dimm->nr_pages = ((mem_size - 1) >> PAGE_SHIFT) + 1;
336 dimm->grain = 8;
337 dimm->dtype = DEV_X8;
338 dimm->mtype = MEM_DDR3;
339 dimm->edac_mode = EDAC_SECDED;
340
341 res = edac_mc_add_mc(mci);
342 if (res < 0)
343 goto err;
344
345 res = devm_request_irq(&pdev->dev, irq, altr_sdram_mc_err_handler,
346 0, dev_name(&pdev->dev), mci);
347 if (res < 0) {
348 edac_mc_printk(mci, KERN_ERR,
349 "Unable to request irq %d\n", irq);
350 res = -ENODEV;
351 goto err2;
352 }
353
354 if (regmap_write(drvdata->mc_vbase, DRAMINTR_OFST,
355 (DRAMINTR_INTRCLR | DRAMINTR_INTREN))) {
356 edac_mc_printk(mci, KERN_ERR,
357 "Error enabling SDRAM ECC IRQ\n");
358 res = -ENODEV;
359 goto err2;
360 }
361
362 altr_sdr_mc_create_debugfs_nodes(mci);
363
364 devres_close_group(&pdev->dev, NULL);
365
366 return 0;
367
368err2:
369 edac_mc_del_mc(&pdev->dev);
370err:
371 devres_release_group(&pdev->dev, NULL);
372free:
373 edac_mc_free(mci);
374 edac_printk(KERN_ERR, EDAC_MC,
375 "EDAC Probe Failed; Error %d\n", res);
376
377 return res;
378}
379
380static int altr_sdram_remove(struct platform_device *pdev)
381{
382 struct mem_ctl_info *mci = platform_get_drvdata(pdev);
383
384 edac_mc_del_mc(&pdev->dev);
385 edac_mc_free(mci);
386 platform_set_drvdata(pdev, NULL);
387
388 return 0;
389}
390
391static const struct of_device_id altr_sdram_ctrl_of_match[] = {
392 { .compatible = "altr,sdram-edac", },
393 {},
394};
395MODULE_DEVICE_TABLE(of, altr_sdram_ctrl_of_match);
396
397static struct platform_driver altr_sdram_edac_driver = {
398 .probe = altr_sdram_probe,
399 .remove = altr_sdram_remove,
400 .driver = {
401 .name = "altr_sdram_edac",
402 .of_match_table = altr_sdram_ctrl_of_match,
403 },
404};
405
406module_platform_driver(altr_sdram_edac_driver);
407
408MODULE_LICENSE("GPL v2");
409MODULE_AUTHOR("Thor Thayer");
410MODULE_DESCRIPTION("EDAC Driver for Altera SDRAM Controller");