2 * Cell MIC driver for ECC counting
4 * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
5 * <benh@kernel.crashing.org>
7 * This file may be distributed under the terms of the
8 * GNU General Public License.
12 #include <linux/module.h>
13 #include <linux/init.h>
14 #include <linux/platform_device.h>
15 #include <linux/stop_machine.h>
17 #include <asm/machdep.h>
18 #include <asm/cell-regs.h>
20 #include "edac_core.h"
24 struct cbe_mic_tm_regs __iomem
*regs
;
32 static void cell_edac_count_ce(struct mem_ctl_info
*mci
, int chan
, u64 ar
)
34 struct cell_edac_priv
*priv
= mci
->pvt_info
;
35 struct csrow_info
*csrow
= &mci
->csrows
[0];
36 unsigned long address
, pfn
, offset
;
38 dev_dbg(mci
->dev
, "ECC CE err on node %d, channel %d, ar = 0x%016lx\n",
39 priv
->node
, chan
, ar
);
41 /* Address decoding is likely a bit bogus, to dbl check */
42 address
= (ar
& 0xffffffffe0000000ul
) >> 29;
43 if (priv
->chanmask
== 0x3)
44 address
= (address
<< 1) | chan
;
45 pfn
= address
>> PAGE_SHIFT
;
46 offset
= address
& ~PAGE_MASK
;
48 /* TODO: Decoding of the error addresss */
49 edac_mc_handle_ce(mci
, csrow
->first_page
+ pfn
, offset
,
53 static void cell_edac_count_ue(struct mem_ctl_info
*mci
, int chan
, u64 ar
)
55 struct cell_edac_priv
*priv
= mci
->pvt_info
;
56 struct csrow_info
*csrow
= &mci
->csrows
[0];
57 unsigned long address
, pfn
, offset
;
59 dev_dbg(mci
->dev
, "ECC UE err on node %d, channel %d, ar = 0x%016lx\n",
60 priv
->node
, chan
, ar
);
62 /* Address decoding is likely a bit bogus, to dbl check */
63 address
= (ar
& 0xffffffffe0000000ul
) >> 29;
64 if (priv
->chanmask
== 0x3)
65 address
= (address
<< 1) | chan
;
66 pfn
= address
>> PAGE_SHIFT
;
67 offset
= address
& ~PAGE_MASK
;
69 /* TODO: Decoding of the error addresss */
70 edac_mc_handle_ue(mci
, csrow
->first_page
+ pfn
, offset
, 0, "");
73 static void cell_edac_check(struct mem_ctl_info
*mci
)
75 struct cell_edac_priv
*priv
= mci
->pvt_info
;
76 u64 fir
, addreg
, clear
= 0;
78 fir
= in_be64(&priv
->regs
->mic_fir
);
80 if (fir
!= priv
->prev_fir
) {
81 dev_dbg(mci
->dev
, "fir change : 0x%016lx\n", fir
);
85 if ((priv
->chanmask
& 0x1) && (fir
& CBE_MIC_FIR_ECC_SINGLE_0_ERR
)) {
86 addreg
= in_be64(&priv
->regs
->mic_df_ecc_address_0
);
87 clear
|= CBE_MIC_FIR_ECC_SINGLE_0_RESET
;
88 cell_edac_count_ce(mci
, 0, addreg
);
90 if ((priv
->chanmask
& 0x2) && (fir
& CBE_MIC_FIR_ECC_SINGLE_1_ERR
)) {
91 addreg
= in_be64(&priv
->regs
->mic_df_ecc_address_1
);
92 clear
|= CBE_MIC_FIR_ECC_SINGLE_1_RESET
;
93 cell_edac_count_ce(mci
, 1, addreg
);
95 if ((priv
->chanmask
& 0x1) && (fir
& CBE_MIC_FIR_ECC_MULTI_0_ERR
)) {
96 addreg
= in_be64(&priv
->regs
->mic_df_ecc_address_0
);
97 clear
|= CBE_MIC_FIR_ECC_MULTI_0_RESET
;
98 cell_edac_count_ue(mci
, 0, addreg
);
100 if ((priv
->chanmask
& 0x2) && (fir
& CBE_MIC_FIR_ECC_MULTI_1_ERR
)) {
101 addreg
= in_be64(&priv
->regs
->mic_df_ecc_address_1
);
102 clear
|= CBE_MIC_FIR_ECC_MULTI_1_RESET
;
103 cell_edac_count_ue(mci
, 1, addreg
);
106 /* The procedure for clearing FIR bits is a bit ... weird */
108 fir
&= ~(CBE_MIC_FIR_ECC_ERR_MASK
| CBE_MIC_FIR_ECC_SET_MASK
);
109 fir
|= CBE_MIC_FIR_ECC_RESET_MASK
;
111 out_be64(&priv
->regs
->mic_fir
, fir
);
112 (void)in_be64(&priv
->regs
->mic_fir
);
116 fir
= in_be64(&priv
->regs
->mic_fir
);
117 dev_dbg(mci
->dev
, "fir clear : 0x%016lx\n", fir
);
122 static void __devinit
cell_edac_init_csrows(struct mem_ctl_info
*mci
)
124 struct csrow_info
*csrow
= &mci
->csrows
[0];
125 struct cell_edac_priv
*priv
= mci
->pvt_info
;
126 struct device_node
*np
;
129 (np
= of_find_node_by_name(np
, "memory")) != NULL
;) {
132 /* We "know" that the Cell firmware only creates one entry
133 * in the "memory" nodes. If that changes, this code will
134 * need to be adapted.
136 if (of_address_to_resource(np
, 0, &r
))
138 if (of_node_to_nid(np
) != priv
->node
)
140 csrow
->first_page
= r
.start
>> PAGE_SHIFT
;
141 csrow
->nr_pages
= (r
.end
- r
.start
+ 1) >> PAGE_SHIFT
;
142 csrow
->last_page
= csrow
->first_page
+ csrow
->nr_pages
- 1;
143 csrow
->mtype
= MEM_XDR
;
144 csrow
->edac_mode
= EDAC_FLAG_EC
| EDAC_FLAG_SECDED
;
146 "Initialized on node %d, chanmask=0x%x,"
147 " first_page=0x%lx, nr_pages=0x%x\n",
148 priv
->node
, priv
->chanmask
,
149 csrow
->first_page
, csrow
->nr_pages
);
154 static int __devinit
cell_edac_probe(struct platform_device
*pdev
)
156 struct cbe_mic_tm_regs __iomem
*regs
;
157 struct mem_ctl_info
*mci
;
158 struct cell_edac_priv
*priv
;
162 regs
= cbe_get_cpu_mic_tm_regs(cbe_node_to_cpu(pdev
->id
));
166 /* Get channel population */
167 reg
= in_be64(®s
->mic_mnt_cfg
);
168 dev_dbg(&pdev
->dev
, "MIC_MNT_CFG = 0x%016lx\n", reg
);
170 if (reg
& CBE_MIC_MNT_CFG_CHAN_0_POP
)
172 if (reg
& CBE_MIC_MNT_CFG_CHAN_1_POP
)
176 "Yuck ! No channel populated ? Aborting !\n");
179 dev_dbg(&pdev
->dev
, "Initial FIR = 0x%016lx\n",
180 in_be64(®s
->mic_fir
));
182 /* Allocate & init EDAC MC data structure */
183 mci
= edac_mc_alloc(sizeof(struct cell_edac_priv
), 1,
184 chanmask
== 3 ? 2 : 1, pdev
->id
);
187 priv
= mci
->pvt_info
;
189 priv
->node
= pdev
->id
;
190 priv
->chanmask
= chanmask
;
191 mci
->dev
= &pdev
->dev
;
192 mci
->mtype_cap
= MEM_FLAG_XDR
;
193 mci
->edac_ctl_cap
= EDAC_FLAG_NONE
| EDAC_FLAG_EC
| EDAC_FLAG_SECDED
;
194 mci
->edac_cap
= EDAC_FLAG_EC
| EDAC_FLAG_SECDED
;
195 mci
->mod_name
= "cell_edac";
196 mci
->ctl_name
= "MIC";
197 mci
->dev_name
= pdev
->dev
.bus_id
;
198 mci
->edac_check
= cell_edac_check
;
199 cell_edac_init_csrows(mci
);
201 /* Register with EDAC core */
202 rc
= edac_mc_add_mc(mci
);
204 dev_err(&pdev
->dev
, "failed to register with EDAC core\n");
212 static int __devexit
cell_edac_remove(struct platform_device
*pdev
)
214 struct mem_ctl_info
*mci
= edac_mc_del_mc(&pdev
->dev
);
220 static struct platform_driver cell_edac_driver
= {
223 .owner
= THIS_MODULE
,
225 .probe
= cell_edac_probe
,
226 .remove
= cell_edac_remove
,
229 static int __init
cell_edac_init(void)
231 /* Sanity check registers data structure */
232 BUILD_BUG_ON(offsetof(struct cbe_mic_tm_regs
,
233 mic_df_ecc_address_0
) != 0xf8);
234 BUILD_BUG_ON(offsetof(struct cbe_mic_tm_regs
,
235 mic_df_ecc_address_1
) != 0x1b8);
236 BUILD_BUG_ON(offsetof(struct cbe_mic_tm_regs
,
237 mic_df_config
) != 0x218);
238 BUILD_BUG_ON(offsetof(struct cbe_mic_tm_regs
,
240 BUILD_BUG_ON(offsetof(struct cbe_mic_tm_regs
,
241 mic_mnt_cfg
) != 0x210);
242 BUILD_BUG_ON(offsetof(struct cbe_mic_tm_regs
,
245 return platform_driver_register(&cell_edac_driver
);
248 static void __exit
cell_edac_exit(void)
250 platform_driver_unregister(&cell_edac_driver
);
253 module_init(cell_edac_init
);
254 module_exit(cell_edac_exit
);
256 MODULE_LICENSE("GPL");
257 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
258 MODULE_DESCRIPTION("ECC counting for Cell MIC");