Root/drivers/edac/mv64x60_edac.c

1/*
2 * Marvell MV64x60 Memory Controller kernel module for PPC platforms
3 *
4 * Author: Dave Jiang <djiang@mvista.com>
5 *
6 * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under
7 * the terms of the GNU General Public License version 2. This program
8 * is licensed "as is" without any warranty of any kind, whether express
9 * or implied.
10 *
11 */
12
13#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/interrupt.h>
16#include <linux/io.h>
17#include <linux/edac.h>
18#include <linux/gfp.h>
19
20#include "edac_core.h"
21#include "edac_module.h"
22#include "mv64x60_edac.h"
23
24static const char *mv64x60_ctl_name = "MV64x60";
25static int edac_dev_idx;
26static int edac_pci_idx;
27static int edac_mc_idx;
28
29/*********************** PCI err device **********************************/
30#ifdef CONFIG_PCI
31static void mv64x60_pci_check(struct edac_pci_ctl_info *pci)
32{
33    struct mv64x60_pci_pdata *pdata = pci->pvt_info;
34    u32 cause;
35
36    cause = in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_CAUSE);
37    if (!cause)
38        return;
39
40    printk(KERN_ERR "Error in PCI %d Interface\n", pdata->pci_hose);
41    printk(KERN_ERR "Cause register: 0x%08x\n", cause);
42    printk(KERN_ERR "Address Low: 0x%08x\n",
43           in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_ADDR_LO));
44    printk(KERN_ERR "Address High: 0x%08x\n",
45           in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_ADDR_HI));
46    printk(KERN_ERR "Attribute: 0x%08x\n",
47           in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_ATTR));
48    printk(KERN_ERR "Command: 0x%08x\n",
49           in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_CMD));
50    out_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_CAUSE, ~cause);
51
52    if (cause & MV64X60_PCI_PE_MASK)
53        edac_pci_handle_pe(pci, pci->ctl_name);
54
55    if (!(cause & MV64X60_PCI_PE_MASK))
56        edac_pci_handle_npe(pci, pci->ctl_name);
57}
58
59static irqreturn_t mv64x60_pci_isr(int irq, void *dev_id)
60{
61    struct edac_pci_ctl_info *pci = dev_id;
62    struct mv64x60_pci_pdata *pdata = pci->pvt_info;
63    u32 val;
64
65    val = in_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_CAUSE);
66    if (!val)
67        return IRQ_NONE;
68
69    mv64x60_pci_check(pci);
70
71    return IRQ_HANDLED;
72}
73
74/*
75 * Bit 0 of MV64x60_PCIx_ERR_MASK does not exist on the 64360 and because of
76 * errata FEr-#11 and FEr-##16 for the 64460, it should be 0 on that chip as
77 * well. IOW, don't set bit 0.
78 */
79
80/* Erratum FEr PCI-#16: clear bit 0 of PCI SERRn Mask reg. */
81static int __init mv64x60_pci_fixup(struct platform_device *pdev)
82{
83    struct resource *r;
84    void __iomem *pci_serr;
85
86    r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
87    if (!r) {
88        printk(KERN_ERR "%s: Unable to get resource for "
89               "PCI err regs\n", __func__);
90        return -ENOENT;
91    }
92
93    pci_serr = ioremap(r->start, resource_size(r));
94    if (!pci_serr)
95        return -ENOMEM;
96
97    out_le32(pci_serr, in_le32(pci_serr) & ~0x1);
98    iounmap(pci_serr);
99
100    return 0;
101}
102
103static int __devinit mv64x60_pci_err_probe(struct platform_device *pdev)
104{
105    struct edac_pci_ctl_info *pci;
106    struct mv64x60_pci_pdata *pdata;
107    struct resource *r;
108    int res = 0;
109
110    if (!devres_open_group(&pdev->dev, mv64x60_pci_err_probe, GFP_KERNEL))
111        return -ENOMEM;
112
113    pci = edac_pci_alloc_ctl_info(sizeof(*pdata), "mv64x60_pci_err");
114    if (!pci)
115        return -ENOMEM;
116
117    pdata = pci->pvt_info;
118
119    pdata->pci_hose = pdev->id;
120    pdata->name = "mpc85xx_pci_err";
121    pdata->irq = NO_IRQ;
122    platform_set_drvdata(pdev, pci);
123    pci->dev = &pdev->dev;
124    pci->dev_name = dev_name(&pdev->dev);
125    pci->mod_name = EDAC_MOD_STR;
126    pci->ctl_name = pdata->name;
127
128    if (edac_op_state == EDAC_OPSTATE_POLL)
129        pci->edac_check = mv64x60_pci_check;
130
131    pdata->edac_idx = edac_pci_idx++;
132
133    r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
134    if (!r) {
135        printk(KERN_ERR "%s: Unable to get resource for "
136               "PCI err regs\n", __func__);
137        res = -ENOENT;
138        goto err;
139    }
140
141    if (!devm_request_mem_region(&pdev->dev,
142                     r->start,
143                     resource_size(r),
144                     pdata->name)) {
145        printk(KERN_ERR "%s: Error while requesting mem region\n",
146               __func__);
147        res = -EBUSY;
148        goto err;
149    }
150
151    pdata->pci_vbase = devm_ioremap(&pdev->dev,
152                    r->start,
153                    resource_size(r));
154    if (!pdata->pci_vbase) {
155        printk(KERN_ERR "%s: Unable to setup PCI err regs\n", __func__);
156        res = -ENOMEM;
157        goto err;
158    }
159
160    res = mv64x60_pci_fixup(pdev);
161    if (res < 0) {
162        printk(KERN_ERR "%s: PCI fixup failed\n", __func__);
163        goto err;
164    }
165
166    out_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_CAUSE, 0);
167    out_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_MASK, 0);
168    out_le32(pdata->pci_vbase + MV64X60_PCI_ERROR_MASK,
169         MV64X60_PCIx_ERR_MASK_VAL);
170
171    if (edac_pci_add_device(pci, pdata->edac_idx) > 0) {
172        edac_dbg(3, "failed edac_pci_add_device()\n");
173        goto err;
174    }
175
176    if (edac_op_state == EDAC_OPSTATE_INT) {
177        pdata->irq = platform_get_irq(pdev, 0);
178        res = devm_request_irq(&pdev->dev,
179                       pdata->irq,
180                       mv64x60_pci_isr,
181                       IRQF_DISABLED,
182                       "[EDAC] PCI err",
183                       pci);
184        if (res < 0) {
185            printk(KERN_ERR "%s: Unable to request irq %d for "
186                   "MV64x60 PCI ERR\n", __func__, pdata->irq);
187            res = -ENODEV;
188            goto err2;
189        }
190        printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for PCI Err\n",
191               pdata->irq);
192    }
193
194    devres_remove_group(&pdev->dev, mv64x60_pci_err_probe);
195
196    /* get this far and it's successful */
197    edac_dbg(3, "success\n");
198
199    return 0;
200
201err2:
202    edac_pci_del_device(&pdev->dev);
203err:
204    edac_pci_free_ctl_info(pci);
205    devres_release_group(&pdev->dev, mv64x60_pci_err_probe);
206    return res;
207}
208
209static int mv64x60_pci_err_remove(struct platform_device *pdev)
210{
211    struct edac_pci_ctl_info *pci = platform_get_drvdata(pdev);
212
213    edac_dbg(0, "\n");
214
215    edac_pci_del_device(&pdev->dev);
216
217    edac_pci_free_ctl_info(pci);
218
219    return 0;
220}
221
222static struct platform_driver mv64x60_pci_err_driver = {
223    .probe = mv64x60_pci_err_probe,
224    .remove = __devexit_p(mv64x60_pci_err_remove),
225    .driver = {
226           .name = "mv64x60_pci_err",
227    }
228};
229
230#endif /* CONFIG_PCI */
231
232/*********************** SRAM err device **********************************/
233static void mv64x60_sram_check(struct edac_device_ctl_info *edac_dev)
234{
235    struct mv64x60_sram_pdata *pdata = edac_dev->pvt_info;
236    u32 cause;
237
238    cause = in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_CAUSE);
239    if (!cause)
240        return;
241
242    printk(KERN_ERR "Error in internal SRAM\n");
243    printk(KERN_ERR "Cause register: 0x%08x\n", cause);
244    printk(KERN_ERR "Address Low: 0x%08x\n",
245           in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_ADDR_LO));
246    printk(KERN_ERR "Address High: 0x%08x\n",
247           in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_ADDR_HI));
248    printk(KERN_ERR "Data Low: 0x%08x\n",
249           in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_DATA_LO));
250    printk(KERN_ERR "Data High: 0x%08x\n",
251           in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_DATA_HI));
252    printk(KERN_ERR "Parity: 0x%08x\n",
253           in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_PARITY));
254    out_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_CAUSE, 0);
255
256    edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name);
257}
258
259static irqreturn_t mv64x60_sram_isr(int irq, void *dev_id)
260{
261    struct edac_device_ctl_info *edac_dev = dev_id;
262    struct mv64x60_sram_pdata *pdata = edac_dev->pvt_info;
263    u32 cause;
264
265    cause = in_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_CAUSE);
266    if (!cause)
267        return IRQ_NONE;
268
269    mv64x60_sram_check(edac_dev);
270
271    return IRQ_HANDLED;
272}
273
274static int __devinit mv64x60_sram_err_probe(struct platform_device *pdev)
275{
276    struct edac_device_ctl_info *edac_dev;
277    struct mv64x60_sram_pdata *pdata;
278    struct resource *r;
279    int res = 0;
280
281    if (!devres_open_group(&pdev->dev, mv64x60_sram_err_probe, GFP_KERNEL))
282        return -ENOMEM;
283
284    edac_dev = edac_device_alloc_ctl_info(sizeof(*pdata),
285                          "sram", 1, NULL, 0, 0, NULL, 0,
286                          edac_dev_idx);
287    if (!edac_dev) {
288        devres_release_group(&pdev->dev, mv64x60_sram_err_probe);
289        return -ENOMEM;
290    }
291
292    pdata = edac_dev->pvt_info;
293    pdata->name = "mv64x60_sram_err";
294    pdata->irq = NO_IRQ;
295    edac_dev->dev = &pdev->dev;
296    platform_set_drvdata(pdev, edac_dev);
297    edac_dev->dev_name = dev_name(&pdev->dev);
298
299    r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
300    if (!r) {
301        printk(KERN_ERR "%s: Unable to get resource for "
302               "SRAM err regs\n", __func__);
303        res = -ENOENT;
304        goto err;
305    }
306
307    if (!devm_request_mem_region(&pdev->dev,
308                     r->start,
309                     resource_size(r),
310                     pdata->name)) {
311        printk(KERN_ERR "%s: Error while request mem region\n",
312               __func__);
313        res = -EBUSY;
314        goto err;
315    }
316
317    pdata->sram_vbase = devm_ioremap(&pdev->dev,
318                     r->start,
319                     resource_size(r));
320    if (!pdata->sram_vbase) {
321        printk(KERN_ERR "%s: Unable to setup SRAM err regs\n",
322               __func__);
323        res = -ENOMEM;
324        goto err;
325    }
326
327    /* setup SRAM err registers */
328    out_le32(pdata->sram_vbase + MV64X60_SRAM_ERR_CAUSE, 0);
329
330    edac_dev->mod_name = EDAC_MOD_STR;
331    edac_dev->ctl_name = pdata->name;
332
333    if (edac_op_state == EDAC_OPSTATE_POLL)
334        edac_dev->edac_check = mv64x60_sram_check;
335
336    pdata->edac_idx = edac_dev_idx++;
337
338    if (edac_device_add_device(edac_dev) > 0) {
339        edac_dbg(3, "failed edac_device_add_device()\n");
340        goto err;
341    }
342
343    if (edac_op_state == EDAC_OPSTATE_INT) {
344        pdata->irq = platform_get_irq(pdev, 0);
345        res = devm_request_irq(&pdev->dev,
346                       pdata->irq,
347                       mv64x60_sram_isr,
348                       IRQF_DISABLED,
349                       "[EDAC] SRAM err",
350                       edac_dev);
351        if (res < 0) {
352            printk(KERN_ERR
353                   "%s: Unable to request irq %d for "
354                   "MV64x60 SRAM ERR\n", __func__, pdata->irq);
355            res = -ENODEV;
356            goto err2;
357        }
358
359        printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for SRAM Err\n",
360               pdata->irq);
361    }
362
363    devres_remove_group(&pdev->dev, mv64x60_sram_err_probe);
364
365    /* get this far and it's successful */
366    edac_dbg(3, "success\n");
367
368    return 0;
369
370err2:
371    edac_device_del_device(&pdev->dev);
372err:
373    devres_release_group(&pdev->dev, mv64x60_sram_err_probe);
374    edac_device_free_ctl_info(edac_dev);
375    return res;
376}
377
378static int mv64x60_sram_err_remove(struct platform_device *pdev)
379{
380    struct edac_device_ctl_info *edac_dev = platform_get_drvdata(pdev);
381
382    edac_dbg(0, "\n");
383
384    edac_device_del_device(&pdev->dev);
385    edac_device_free_ctl_info(edac_dev);
386
387    return 0;
388}
389
390static struct platform_driver mv64x60_sram_err_driver = {
391    .probe = mv64x60_sram_err_probe,
392    .remove = mv64x60_sram_err_remove,
393    .driver = {
394           .name = "mv64x60_sram_err",
395    }
396};
397
398/*********************** CPU err device **********************************/
399static void mv64x60_cpu_check(struct edac_device_ctl_info *edac_dev)
400{
401    struct mv64x60_cpu_pdata *pdata = edac_dev->pvt_info;
402    u32 cause;
403
404    cause = in_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_CAUSE) &
405        MV64x60_CPU_CAUSE_MASK;
406    if (!cause)
407        return;
408
409    printk(KERN_ERR "Error on CPU interface\n");
410    printk(KERN_ERR "Cause register: 0x%08x\n", cause);
411    printk(KERN_ERR "Address Low: 0x%08x\n",
412           in_le32(pdata->cpu_vbase[0] + MV64x60_CPU_ERR_ADDR_LO));
413    printk(KERN_ERR "Address High: 0x%08x\n",
414           in_le32(pdata->cpu_vbase[0] + MV64x60_CPU_ERR_ADDR_HI));
415    printk(KERN_ERR "Data Low: 0x%08x\n",
416           in_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_DATA_LO));
417    printk(KERN_ERR "Data High: 0x%08x\n",
418           in_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_DATA_HI));
419    printk(KERN_ERR "Parity: 0x%08x\n",
420           in_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_PARITY));
421    out_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_CAUSE, 0);
422
423    edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name);
424}
425
426static irqreturn_t mv64x60_cpu_isr(int irq, void *dev_id)
427{
428    struct edac_device_ctl_info *edac_dev = dev_id;
429    struct mv64x60_cpu_pdata *pdata = edac_dev->pvt_info;
430    u32 cause;
431
432    cause = in_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_CAUSE) &
433        MV64x60_CPU_CAUSE_MASK;
434    if (!cause)
435        return IRQ_NONE;
436
437    mv64x60_cpu_check(edac_dev);
438
439    return IRQ_HANDLED;
440}
441
442static int __devinit mv64x60_cpu_err_probe(struct platform_device *pdev)
443{
444    struct edac_device_ctl_info *edac_dev;
445    struct resource *r;
446    struct mv64x60_cpu_pdata *pdata;
447    int res = 0;
448
449    if (!devres_open_group(&pdev->dev, mv64x60_cpu_err_probe, GFP_KERNEL))
450        return -ENOMEM;
451
452    edac_dev = edac_device_alloc_ctl_info(sizeof(*pdata),
453                          "cpu", 1, NULL, 0, 0, NULL, 0,
454                          edac_dev_idx);
455    if (!edac_dev) {
456        devres_release_group(&pdev->dev, mv64x60_cpu_err_probe);
457        return -ENOMEM;
458    }
459
460    pdata = edac_dev->pvt_info;
461    pdata->name = "mv64x60_cpu_err";
462    pdata->irq = NO_IRQ;
463    edac_dev->dev = &pdev->dev;
464    platform_set_drvdata(pdev, edac_dev);
465    edac_dev->dev_name = dev_name(&pdev->dev);
466
467    r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
468    if (!r) {
469        printk(KERN_ERR "%s: Unable to get resource for "
470               "CPU err regs\n", __func__);
471        res = -ENOENT;
472        goto err;
473    }
474
475    if (!devm_request_mem_region(&pdev->dev,
476                     r->start,
477                     resource_size(r),
478                     pdata->name)) {
479        printk(KERN_ERR "%s: Error while requesting mem region\n",
480               __func__);
481        res = -EBUSY;
482        goto err;
483    }
484
485    pdata->cpu_vbase[0] = devm_ioremap(&pdev->dev,
486                       r->start,
487                       resource_size(r));
488    if (!pdata->cpu_vbase[0]) {
489        printk(KERN_ERR "%s: Unable to setup CPU err regs\n", __func__);
490        res = -ENOMEM;
491        goto err;
492    }
493
494    r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
495    if (!r) {
496        printk(KERN_ERR "%s: Unable to get resource for "
497               "CPU err regs\n", __func__);
498        res = -ENOENT;
499        goto err;
500    }
501
502    if (!devm_request_mem_region(&pdev->dev,
503                     r->start,
504                     resource_size(r),
505                     pdata->name)) {
506        printk(KERN_ERR "%s: Error while requesting mem region\n",
507               __func__);
508        res = -EBUSY;
509        goto err;
510    }
511
512    pdata->cpu_vbase[1] = devm_ioremap(&pdev->dev,
513                       r->start,
514                       resource_size(r));
515    if (!pdata->cpu_vbase[1]) {
516        printk(KERN_ERR "%s: Unable to setup CPU err regs\n", __func__);
517        res = -ENOMEM;
518        goto err;
519    }
520
521    /* setup CPU err registers */
522    out_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_CAUSE, 0);
523    out_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_MASK, 0);
524    out_le32(pdata->cpu_vbase[1] + MV64x60_CPU_ERR_MASK, 0x000000ff);
525
526    edac_dev->mod_name = EDAC_MOD_STR;
527    edac_dev->ctl_name = pdata->name;
528    if (edac_op_state == EDAC_OPSTATE_POLL)
529        edac_dev->edac_check = mv64x60_cpu_check;
530
531    pdata->edac_idx = edac_dev_idx++;
532
533    if (edac_device_add_device(edac_dev) > 0) {
534        edac_dbg(3, "failed edac_device_add_device()\n");
535        goto err;
536    }
537
538    if (edac_op_state == EDAC_OPSTATE_INT) {
539        pdata->irq = platform_get_irq(pdev, 0);
540        res = devm_request_irq(&pdev->dev,
541                       pdata->irq,
542                       mv64x60_cpu_isr,
543                       IRQF_DISABLED,
544                       "[EDAC] CPU err",
545                       edac_dev);
546        if (res < 0) {
547            printk(KERN_ERR
548                   "%s: Unable to request irq %d for MV64x60 "
549                   "CPU ERR\n", __func__, pdata->irq);
550            res = -ENODEV;
551            goto err2;
552        }
553
554        printk(KERN_INFO EDAC_MOD_STR
555               " acquired irq %d for CPU Err\n", pdata->irq);
556    }
557
558    devres_remove_group(&pdev->dev, mv64x60_cpu_err_probe);
559
560    /* get this far and it's successful */
561    edac_dbg(3, "success\n");
562
563    return 0;
564
565err2:
566    edac_device_del_device(&pdev->dev);
567err:
568    devres_release_group(&pdev->dev, mv64x60_cpu_err_probe);
569    edac_device_free_ctl_info(edac_dev);
570    return res;
571}
572
573static int mv64x60_cpu_err_remove(struct platform_device *pdev)
574{
575    struct edac_device_ctl_info *edac_dev = platform_get_drvdata(pdev);
576
577    edac_dbg(0, "\n");
578
579    edac_device_del_device(&pdev->dev);
580    edac_device_free_ctl_info(edac_dev);
581    return 0;
582}
583
584static struct platform_driver mv64x60_cpu_err_driver = {
585    .probe = mv64x60_cpu_err_probe,
586    .remove = mv64x60_cpu_err_remove,
587    .driver = {
588           .name = "mv64x60_cpu_err",
589    }
590};
591
592/*********************** DRAM err device **********************************/
593
594static void mv64x60_mc_check(struct mem_ctl_info *mci)
595{
596    struct mv64x60_mc_pdata *pdata = mci->pvt_info;
597    u32 reg;
598    u32 err_addr;
599    u32 sdram_ecc;
600    u32 comp_ecc;
601    u32 syndrome;
602
603    reg = in_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR);
604    if (!reg)
605        return;
606
607    err_addr = reg & ~0x3;
608    sdram_ecc = in_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_RCVD);
609    comp_ecc = in_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_CALC);
610    syndrome = sdram_ecc ^ comp_ecc;
611
612    /* first bit clear in ECC Err Reg, 1 bit error, correctable by HW */
613    if (!(reg & 0x1))
614        edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
615                     err_addr >> PAGE_SHIFT,
616                     err_addr & PAGE_MASK, syndrome,
617                     0, 0, -1,
618                     mci->ctl_name, "");
619    else /* 2 bit error, UE */
620        edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
621                     err_addr >> PAGE_SHIFT,
622                     err_addr & PAGE_MASK, 0,
623                     0, 0, -1,
624                     mci->ctl_name, "");
625
626    /* clear the error */
627    out_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR, 0);
628}
629
630static irqreturn_t mv64x60_mc_isr(int irq, void *dev_id)
631{
632    struct mem_ctl_info *mci = dev_id;
633    struct mv64x60_mc_pdata *pdata = mci->pvt_info;
634    u32 reg;
635
636    reg = in_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR);
637    if (!reg)
638        return IRQ_NONE;
639
640    /* writing 0's to the ECC err addr in check function clears irq */
641    mv64x60_mc_check(mci);
642
643    return IRQ_HANDLED;
644}
645
646static void get_total_mem(struct mv64x60_mc_pdata *pdata)
647{
648    struct device_node *np = NULL;
649    const unsigned int *reg;
650
651    np = of_find_node_by_type(NULL, "memory");
652    if (!np)
653        return;
654
655    reg = of_get_property(np, "reg", NULL);
656
657    pdata->total_mem = reg[1];
658}
659
660static void mv64x60_init_csrows(struct mem_ctl_info *mci,
661                struct mv64x60_mc_pdata *pdata)
662{
663    struct csrow_info *csrow;
664    struct dimm_info *dimm;
665
666    u32 devtype;
667    u32 ctl;
668
669    get_total_mem(pdata);
670
671    ctl = in_le32(pdata->mc_vbase + MV64X60_SDRAM_CONFIG);
672
673    csrow = mci->csrows[0];
674    dimm = csrow->channels[0]->dimm;
675
676    dimm->nr_pages = pdata->total_mem >> PAGE_SHIFT;
677    dimm->grain = 8;
678
679    dimm->mtype = (ctl & MV64X60_SDRAM_REGISTERED) ? MEM_RDDR : MEM_DDR;
680
681    devtype = (ctl >> 20) & 0x3;
682    switch (devtype) {
683    case 0x0:
684        dimm->dtype = DEV_X32;
685        break;
686    case 0x2: /* could be X8 too, but no way to tell */
687        dimm->dtype = DEV_X16;
688        break;
689    case 0x3:
690        dimm->dtype = DEV_X4;
691        break;
692    default:
693        dimm->dtype = DEV_UNKNOWN;
694        break;
695    }
696
697    dimm->edac_mode = EDAC_SECDED;
698}
699
700static int __devinit mv64x60_mc_err_probe(struct platform_device *pdev)
701{
702    struct mem_ctl_info *mci;
703    struct edac_mc_layer layers[2];
704    struct mv64x60_mc_pdata *pdata;
705    struct resource *r;
706    u32 ctl;
707    int res = 0;
708
709    if (!devres_open_group(&pdev->dev, mv64x60_mc_err_probe, GFP_KERNEL))
710        return -ENOMEM;
711
712    layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
713    layers[0].size = 1;
714    layers[0].is_virt_csrow = true;
715    layers[1].type = EDAC_MC_LAYER_CHANNEL;
716    layers[1].size = 1;
717    layers[1].is_virt_csrow = false;
718    mci = edac_mc_alloc(edac_mc_idx, ARRAY_SIZE(layers), layers,
719                sizeof(struct mv64x60_mc_pdata));
720    if (!mci) {
721        printk(KERN_ERR "%s: No memory for CPU err\n", __func__);
722        devres_release_group(&pdev->dev, mv64x60_mc_err_probe);
723        return -ENOMEM;
724    }
725
726    pdata = mci->pvt_info;
727    mci->pdev = &pdev->dev;
728    platform_set_drvdata(pdev, mci);
729    pdata->name = "mv64x60_mc_err";
730    pdata->irq = NO_IRQ;
731    mci->dev_name = dev_name(&pdev->dev);
732    pdata->edac_idx = edac_mc_idx++;
733
734    r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
735    if (!r) {
736        printk(KERN_ERR "%s: Unable to get resource for "
737               "MC err regs\n", __func__);
738        res = -ENOENT;
739        goto err;
740    }
741
742    if (!devm_request_mem_region(&pdev->dev,
743                     r->start,
744                     resource_size(r),
745                     pdata->name)) {
746        printk(KERN_ERR "%s: Error while requesting mem region\n",
747               __func__);
748        res = -EBUSY;
749        goto err;
750    }
751
752    pdata->mc_vbase = devm_ioremap(&pdev->dev,
753                       r->start,
754                       resource_size(r));
755    if (!pdata->mc_vbase) {
756        printk(KERN_ERR "%s: Unable to setup MC err regs\n", __func__);
757        res = -ENOMEM;
758        goto err;
759    }
760
761    ctl = in_le32(pdata->mc_vbase + MV64X60_SDRAM_CONFIG);
762    if (!(ctl & MV64X60_SDRAM_ECC)) {
763        /* Non-ECC RAM? */
764        printk(KERN_WARNING "%s: No ECC DIMMs discovered\n", __func__);
765        res = -ENODEV;
766        goto err2;
767    }
768
769    edac_dbg(3, "init mci\n");
770    mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR;
771    mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
772    mci->edac_cap = EDAC_FLAG_SECDED;
773    mci->mod_name = EDAC_MOD_STR;
774    mci->mod_ver = MV64x60_REVISION;
775    mci->ctl_name = mv64x60_ctl_name;
776
777    if (edac_op_state == EDAC_OPSTATE_POLL)
778        mci->edac_check = mv64x60_mc_check;
779
780    mci->ctl_page_to_phys = NULL;
781
782    mci->scrub_mode = SCRUB_SW_SRC;
783
784    mv64x60_init_csrows(mci, pdata);
785
786    /* setup MC registers */
787    out_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR, 0);
788    ctl = in_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_CNTL);
789    ctl = (ctl & 0xff00ffff) | 0x10000;
790    out_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_CNTL, ctl);
791
792    if (edac_mc_add_mc(mci)) {
793        edac_dbg(3, "failed edac_mc_add_mc()\n");
794        goto err;
795    }
796
797    if (edac_op_state == EDAC_OPSTATE_INT) {
798        /* acquire interrupt that reports errors */
799        pdata->irq = platform_get_irq(pdev, 0);
800        res = devm_request_irq(&pdev->dev,
801                       pdata->irq,
802                       mv64x60_mc_isr,
803                       IRQF_DISABLED,
804                       "[EDAC] MC err",
805                       mci);
806        if (res < 0) {
807            printk(KERN_ERR "%s: Unable to request irq %d for "
808                   "MV64x60 DRAM ERR\n", __func__, pdata->irq);
809            res = -ENODEV;
810            goto err2;
811        }
812
813        printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for MC Err\n",
814               pdata->irq);
815    }
816
817    /* get this far and it's successful */
818    edac_dbg(3, "success\n");
819
820    return 0;
821
822err2:
823    edac_mc_del_mc(&pdev->dev);
824err:
825    devres_release_group(&pdev->dev, mv64x60_mc_err_probe);
826    edac_mc_free(mci);
827    return res;
828}
829
830static int mv64x60_mc_err_remove(struct platform_device *pdev)
831{
832    struct mem_ctl_info *mci = platform_get_drvdata(pdev);
833
834    edac_dbg(0, "\n");
835
836    edac_mc_del_mc(&pdev->dev);
837    edac_mc_free(mci);
838    return 0;
839}
840
841static struct platform_driver mv64x60_mc_err_driver = {
842    .probe = mv64x60_mc_err_probe,
843    .remove = mv64x60_mc_err_remove,
844    .driver = {
845           .name = "mv64x60_mc_err",
846    }
847};
848
849static int __init mv64x60_edac_init(void)
850{
851    int ret = 0;
852
853    printk(KERN_INFO "Marvell MV64x60 EDAC driver " MV64x60_REVISION "\n");
854    printk(KERN_INFO "\t(C) 2006-2007 MontaVista Software\n");
855    /* make sure error reporting method is sane */
856    switch (edac_op_state) {
857    case EDAC_OPSTATE_POLL:
858    case EDAC_OPSTATE_INT:
859        break;
860    default:
861        edac_op_state = EDAC_OPSTATE_INT;
862        break;
863    }
864
865    ret = platform_driver_register(&mv64x60_mc_err_driver);
866    if (ret)
867        printk(KERN_WARNING EDAC_MOD_STR "MC err failed to register\n");
868
869    ret = platform_driver_register(&mv64x60_cpu_err_driver);
870    if (ret)
871        printk(KERN_WARNING EDAC_MOD_STR
872            "CPU err failed to register\n");
873
874    ret = platform_driver_register(&mv64x60_sram_err_driver);
875    if (ret)
876        printk(KERN_WARNING EDAC_MOD_STR
877            "SRAM err failed to register\n");
878
879#ifdef CONFIG_PCI
880    ret = platform_driver_register(&mv64x60_pci_err_driver);
881    if (ret)
882        printk(KERN_WARNING EDAC_MOD_STR
883            "PCI err failed to register\n");
884#endif
885
886    return ret;
887}
888module_init(mv64x60_edac_init);
889
890static void __exit mv64x60_edac_exit(void)
891{
892#ifdef CONFIG_PCI
893    platform_driver_unregister(&mv64x60_pci_err_driver);
894#endif
895    platform_driver_unregister(&mv64x60_sram_err_driver);
896    platform_driver_unregister(&mv64x60_cpu_err_driver);
897    platform_driver_unregister(&mv64x60_mc_err_driver);
898}
899module_exit(mv64x60_edac_exit);
900
901MODULE_LICENSE("GPL");
902MODULE_AUTHOR("Montavista Software, Inc.");
903module_param(edac_op_state, int, 0444);
904MODULE_PARM_DESC(edac_op_state,
905         "EDAC Error Reporting state: 0=Poll, 2=Interrupt");
906

Archive Download this file



interactive