diff options
-rw-r--r-- | drivers/edac/Kconfig | 9 | ||||
-rw-r--r-- | drivers/edac/Makefile | 1 | ||||
-rw-r--r-- | drivers/edac/cpc925_edac.c | 1017 |
3 files changed, 1027 insertions, 0 deletions
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index ab4f3592a11c..ea3a75ee3fa3 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig | |||
@@ -232,4 +232,13 @@ config EDAC_AMD8111 | |||
232 | Note, add more Kconfig dependency if it's adopted | 232 | Note, add more Kconfig dependency if it's adopted |
233 | on some machine other than Maple. | 233 | on some machine other than Maple. |
234 | 234 | ||
235 | config EDAC_CPC925 | ||
236 | tristate "IBM CPC925 Memory Controller (PPC970FX)" | ||
237 | depends on EDAC_MM_EDAC && PPC64 | ||
238 | help | ||
239 | Support for error detection and correction on the | ||
240 | IBM CPC925 Bridge and Memory Controller, which is | ||
241 | a companion chip to the PowerPC 970 family of | ||
242 | processors. | ||
243 | |||
235 | endif # EDAC | 244 | endif # EDAC |
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index 633dc5604ee3..98aa4a7db412 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile | |||
@@ -18,6 +18,7 @@ edac_core-objs += edac_pci.o edac_pci_sysfs.o | |||
18 | endif | 18 | endif |
19 | 19 | ||
20 | obj-$(CONFIG_EDAC_AMD76X) += amd76x_edac.o | 20 | obj-$(CONFIG_EDAC_AMD76X) += amd76x_edac.o |
21 | obj-$(CONFIG_EDAC_CPC925) += cpc925_edac.o | ||
21 | obj-$(CONFIG_EDAC_I5000) += i5000_edac.o | 22 | obj-$(CONFIG_EDAC_I5000) += i5000_edac.o |
22 | obj-$(CONFIG_EDAC_I5100) += i5100_edac.o | 23 | obj-$(CONFIG_EDAC_I5100) += i5100_edac.o |
23 | obj-$(CONFIG_EDAC_I5400) += i5400_edac.o | 24 | obj-$(CONFIG_EDAC_I5400) += i5400_edac.o |
diff --git a/drivers/edac/cpc925_edac.c b/drivers/edac/cpc925_edac.c new file mode 100644 index 000000000000..8c54196b5aba --- /dev/null +++ b/drivers/edac/cpc925_edac.c | |||
@@ -0,0 +1,1017 @@ | |||
1 | /* | ||
2 | * cpc925_edac.c, EDAC driver for IBM CPC925 Bridge and Memory Controller. | ||
3 | * | ||
4 | * Copyright (c) 2008 Wind River Systems, Inc. | ||
5 | * | ||
6 | * Authors: Cao Qingtao <qingtao.cao@windriver.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
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. | ||
15 | * See the GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/io.h> | ||
25 | #include <linux/edac.h> | ||
26 | #include <linux/of.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | |||
29 | #include "edac_core.h" | ||
30 | #include "edac_module.h" | ||
31 | |||
32 | #define CPC925_EDAC_REVISION " Ver: 1.0.0 " __DATE__ | ||
33 | #define CPC925_EDAC_MOD_STR "cpc925_edac" | ||
34 | |||
35 | #define cpc925_printk(level, fmt, arg...) \ | ||
36 | edac_printk(level, "CPC925", fmt, ##arg) | ||
37 | |||
38 | #define cpc925_mc_printk(mci, level, fmt, arg...) \ | ||
39 | edac_mc_chipset_printk(mci, level, "CPC925", fmt, ##arg) | ||
40 | |||
41 | /* | ||
42 | * CPC925 registers are of 32 bits with bit0 defined at the | ||
43 | * most significant bit and bit31 at that of least significant. | ||
44 | */ | ||
45 | #define CPC925_BITS_PER_REG 32 | ||
46 | #define CPC925_BIT(nr) (1UL << (CPC925_BITS_PER_REG - 1 - nr)) | ||
47 | |||
48 | /* | ||
49 | * EDAC device names for the error detections of | ||
50 | * CPU Interface and Hypertransport Link. | ||
51 | */ | ||
52 | #define CPC925_CPU_ERR_DEV "cpu" | ||
53 | #define CPC925_HT_LINK_DEV "htlink" | ||
54 | |||
55 | /* Suppose DDR Refresh cycle is 15.6 microsecond */ | ||
56 | #define CPC925_REF_FREQ 0xFA69 | ||
57 | #define CPC925_SCRUB_BLOCK_SIZE 64 /* bytes */ | ||
58 | #define CPC925_NR_CSROWS 8 | ||
59 | |||
60 | /* | ||
61 | * All registers and bits definitions are taken from | ||
62 | * "CPC925 Bridge and Memory Controller User Manual, SA14-2761-02". | ||
63 | */ | ||
64 | |||
65 | /* | ||
66 | * CPU and Memory Controller Registers | ||
67 | */ | ||
68 | /************************************************************ | ||
69 | * Processor Interface Exception Mask Register (APIMASK) | ||
70 | ************************************************************/ | ||
71 | #define REG_APIMASK_OFFSET 0x30070 | ||
72 | enum apimask_bits { | ||
73 | APIMASK_DART = CPC925_BIT(0), /* DART Exception */ | ||
74 | APIMASK_ADI0 = CPC925_BIT(1), /* Handshake Error on PI0_ADI */ | ||
75 | APIMASK_ADI1 = CPC925_BIT(2), /* Handshake Error on PI1_ADI */ | ||
76 | APIMASK_STAT = CPC925_BIT(3), /* Status Exception */ | ||
77 | APIMASK_DERR = CPC925_BIT(4), /* Data Error Exception */ | ||
78 | APIMASK_ADRS0 = CPC925_BIT(5), /* Addressing Exception on PI0 */ | ||
79 | APIMASK_ADRS1 = CPC925_BIT(6), /* Addressing Exception on PI1 */ | ||
80 | /* BIT(7) Reserved */ | ||
81 | APIMASK_ECC_UE_H = CPC925_BIT(8), /* UECC upper */ | ||
82 | APIMASK_ECC_CE_H = CPC925_BIT(9), /* CECC upper */ | ||
83 | APIMASK_ECC_UE_L = CPC925_BIT(10), /* UECC lower */ | ||
84 | APIMASK_ECC_CE_L = CPC925_BIT(11), /* CECC lower */ | ||
85 | |||
86 | CPU_MASK_ENABLE = (APIMASK_DART | APIMASK_ADI0 | APIMASK_ADI1 | | ||
87 | APIMASK_STAT | APIMASK_DERR | APIMASK_ADRS0 | | ||
88 | APIMASK_ADRS1), | ||
89 | ECC_MASK_ENABLE = (APIMASK_ECC_UE_H | APIMASK_ECC_CE_H | | ||
90 | APIMASK_ECC_UE_L | APIMASK_ECC_CE_L), | ||
91 | }; | ||
92 | |||
93 | /************************************************************ | ||
94 | * Processor Interface Exception Register (APIEXCP) | ||
95 | ************************************************************/ | ||
96 | #define REG_APIEXCP_OFFSET 0x30060 | ||
97 | enum apiexcp_bits { | ||
98 | APIEXCP_DART = CPC925_BIT(0), /* DART Exception */ | ||
99 | APIEXCP_ADI0 = CPC925_BIT(1), /* Handshake Error on PI0_ADI */ | ||
100 | APIEXCP_ADI1 = CPC925_BIT(2), /* Handshake Error on PI1_ADI */ | ||
101 | APIEXCP_STAT = CPC925_BIT(3), /* Status Exception */ | ||
102 | APIEXCP_DERR = CPC925_BIT(4), /* Data Error Exception */ | ||
103 | APIEXCP_ADRS0 = CPC925_BIT(5), /* Addressing Exception on PI0 */ | ||
104 | APIEXCP_ADRS1 = CPC925_BIT(6), /* Addressing Exception on PI1 */ | ||
105 | /* BIT(7) Reserved */ | ||
106 | APIEXCP_ECC_UE_H = CPC925_BIT(8), /* UECC upper */ | ||
107 | APIEXCP_ECC_CE_H = CPC925_BIT(9), /* CECC upper */ | ||
108 | APIEXCP_ECC_UE_L = CPC925_BIT(10), /* UECC lower */ | ||
109 | APIEXCP_ECC_CE_L = CPC925_BIT(11), /* CECC lower */ | ||
110 | |||
111 | CPU_EXCP_DETECTED = (APIEXCP_DART | APIEXCP_ADI0 | APIEXCP_ADI1 | | ||
112 | APIEXCP_STAT | APIEXCP_DERR | APIEXCP_ADRS0 | | ||
113 | APIEXCP_ADRS1), | ||
114 | UECC_EXCP_DETECTED = (APIEXCP_ECC_UE_H | APIEXCP_ECC_UE_L), | ||
115 | CECC_EXCP_DETECTED = (APIEXCP_ECC_CE_H | APIEXCP_ECC_CE_L), | ||
116 | ECC_EXCP_DETECTED = (UECC_EXCP_DETECTED | CECC_EXCP_DETECTED), | ||
117 | }; | ||
118 | |||
119 | /************************************************************ | ||
120 | * Memory Bus Configuration Register (MBCR) | ||
121 | ************************************************************/ | ||
122 | #define REG_MBCR_OFFSET 0x2190 | ||
123 | #define MBCR_64BITCFG_SHIFT 23 | ||
124 | #define MBCR_64BITCFG_MASK (1UL << MBCR_64BITCFG_SHIFT) | ||
125 | #define MBCR_64BITBUS_SHIFT 22 | ||
126 | #define MBCR_64BITBUS_MASK (1UL << MBCR_64BITBUS_SHIFT) | ||
127 | |||
128 | /************************************************************ | ||
129 | * Memory Bank Mode Register (MBMR) | ||
130 | ************************************************************/ | ||
131 | #define REG_MBMR_OFFSET 0x21C0 | ||
132 | #define MBMR_MODE_MAX_VALUE 0xF | ||
133 | #define MBMR_MODE_SHIFT 25 | ||
134 | #define MBMR_MODE_MASK (MBMR_MODE_MAX_VALUE << MBMR_MODE_SHIFT) | ||
135 | #define MBMR_BBA_SHIFT 24 | ||
136 | #define MBMR_BBA_MASK (1UL << MBMR_BBA_SHIFT) | ||
137 | |||
138 | /************************************************************ | ||
139 | * Memory Bank Boundary Address Register (MBBAR) | ||
140 | ************************************************************/ | ||
141 | #define REG_MBBAR_OFFSET 0x21D0 | ||
142 | #define MBBAR_BBA_MAX_VALUE 0xFF | ||
143 | #define MBBAR_BBA_SHIFT 24 | ||
144 | #define MBBAR_BBA_MASK (MBBAR_BBA_MAX_VALUE << MBBAR_BBA_SHIFT) | ||
145 | |||
146 | /************************************************************ | ||
147 | * Memory Scrub Control Register (MSCR) | ||
148 | ************************************************************/ | ||
149 | #define REG_MSCR_OFFSET 0x2400 | ||
150 | #define MSCR_SCRUB_MOD_MASK 0xC0000000 /* scrub_mod - bit0:1*/ | ||
151 | #define MSCR_BACKGR_SCRUB 0x40000000 /* 01 */ | ||
152 | #define MSCR_SI_SHIFT 16 /* si - bit8:15*/ | ||
153 | #define MSCR_SI_MAX_VALUE 0xFF | ||
154 | #define MSCR_SI_MASK (MSCR_SI_MAX_VALUE << MSCR_SI_SHIFT) | ||
155 | |||
156 | /************************************************************ | ||
157 | * Memory Scrub Range Start Register (MSRSR) | ||
158 | ************************************************************/ | ||
159 | #define REG_MSRSR_OFFSET 0x2410 | ||
160 | |||
161 | /************************************************************ | ||
162 | * Memory Scrub Range End Register (MSRER) | ||
163 | ************************************************************/ | ||
164 | #define REG_MSRER_OFFSET 0x2420 | ||
165 | |||
166 | /************************************************************ | ||
167 | * Memory Scrub Pattern Register (MSPR) | ||
168 | ************************************************************/ | ||
169 | #define REG_MSPR_OFFSET 0x2430 | ||
170 | |||
171 | /************************************************************ | ||
172 | * Memory Check Control Register (MCCR) | ||
173 | ************************************************************/ | ||
174 | #define REG_MCCR_OFFSET 0x2440 | ||
175 | enum mccr_bits { | ||
176 | MCCR_ECC_EN = CPC925_BIT(0), /* ECC high and low check */ | ||
177 | }; | ||
178 | |||
179 | /************************************************************ | ||
180 | * Memory Check Range End Register (MCRER) | ||
181 | ************************************************************/ | ||
182 | #define REG_MCRER_OFFSET 0x2450 | ||
183 | |||
184 | /************************************************************ | ||
185 | * Memory Error Address Register (MEAR) | ||
186 | ************************************************************/ | ||
187 | #define REG_MEAR_OFFSET 0x2460 | ||
188 | #define MEAR_BCNT_MAX_VALUE 0x3 | ||
189 | #define MEAR_BCNT_SHIFT 30 | ||
190 | #define MEAR_BCNT_MASK (MEAR_BCNT_MAX_VALUE << MEAR_BCNT_SHIFT) | ||
191 | #define MEAR_RANK_MAX_VALUE 0x7 | ||
192 | #define MEAR_RANK_SHIFT 27 | ||
193 | #define MEAR_RANK_MASK (MEAR_RANK_MAX_VALUE << MEAR_RANK_SHIFT) | ||
194 | #define MEAR_COL_MAX_VALUE 0x7FF | ||
195 | #define MEAR_COL_SHIFT 16 | ||
196 | #define MEAR_COL_MASK (MEAR_COL_MAX_VALUE << MEAR_COL_SHIFT) | ||
197 | #define MEAR_BANK_MAX_VALUE 0x3 | ||
198 | #define MEAR_BANK_SHIFT 14 | ||
199 | #define MEAR_BANK_MASK (MEAR_BANK_MAX_VALUE << MEAR_BANK_SHIFT) | ||
200 | #define MEAR_ROW_MASK 0x00003FFF | ||
201 | |||
202 | /************************************************************ | ||
203 | * Memory Error Syndrome Register (MESR) | ||
204 | ************************************************************/ | ||
205 | #define REG_MESR_OFFSET 0x2470 | ||
206 | #define MESR_ECC_SYN_H_MASK 0xFF00 | ||
207 | #define MESR_ECC_SYN_L_MASK 0x00FF | ||
208 | |||
209 | /************************************************************ | ||
210 | * Memory Mode Control Register (MMCR) | ||
211 | ************************************************************/ | ||
212 | #define REG_MMCR_OFFSET 0x2500 | ||
213 | enum mmcr_bits { | ||
214 | MMCR_REG_DIMM_MODE = CPC925_BIT(3), | ||
215 | }; | ||
216 | |||
217 | /* | ||
218 | * HyperTransport Link Registers | ||
219 | */ | ||
220 | /************************************************************ | ||
221 | * Error Handling/Enumeration Scratch Pad Register (ERRCTRL) | ||
222 | ************************************************************/ | ||
223 | #define REG_ERRCTRL_OFFSET 0x70140 | ||
224 | enum errctrl_bits { /* nonfatal interrupts for */ | ||
225 | ERRCTRL_SERR_NF = CPC925_BIT(0), /* system error */ | ||
226 | ERRCTRL_CRC_NF = CPC925_BIT(1), /* CRC error */ | ||
227 | ERRCTRL_RSP_NF = CPC925_BIT(2), /* Response error */ | ||
228 | ERRCTRL_EOC_NF = CPC925_BIT(3), /* End-Of-Chain error */ | ||
229 | ERRCTRL_OVF_NF = CPC925_BIT(4), /* Overflow error */ | ||
230 | ERRCTRL_PROT_NF = CPC925_BIT(5), /* Protocol error */ | ||
231 | |||
232 | ERRCTRL_RSP_ERR = CPC925_BIT(6), /* Response error received */ | ||
233 | ERRCTRL_CHN_FAL = CPC925_BIT(7), /* Sync flooding detected */ | ||
234 | |||
235 | HT_ERRCTRL_ENABLE = (ERRCTRL_SERR_NF | ERRCTRL_CRC_NF | | ||
236 | ERRCTRL_RSP_NF | ERRCTRL_EOC_NF | | ||
237 | ERRCTRL_OVF_NF | ERRCTRL_PROT_NF), | ||
238 | HT_ERRCTRL_DETECTED = (ERRCTRL_RSP_ERR | ERRCTRL_CHN_FAL), | ||
239 | }; | ||
240 | |||
241 | /************************************************************ | ||
242 | * Link Configuration and Link Control Register (LINKCTRL) | ||
243 | ************************************************************/ | ||
244 | #define REG_LINKCTRL_OFFSET 0x70110 | ||
245 | enum linkctrl_bits { | ||
246 | LINKCTRL_CRC_ERR = (CPC925_BIT(22) | CPC925_BIT(23)), | ||
247 | LINKCTRL_LINK_FAIL = CPC925_BIT(27), | ||
248 | |||
249 | HT_LINKCTRL_DETECTED = (LINKCTRL_CRC_ERR | LINKCTRL_LINK_FAIL), | ||
250 | }; | ||
251 | |||
252 | /************************************************************ | ||
253 | * Link FreqCap/Error/Freq/Revision ID Register (LINKERR) | ||
254 | ************************************************************/ | ||
255 | #define REG_LINKERR_OFFSET 0x70120 | ||
256 | enum linkerr_bits { | ||
257 | LINKERR_EOC_ERR = CPC925_BIT(17), /* End-Of-Chain error */ | ||
258 | LINKERR_OVF_ERR = CPC925_BIT(18), /* Receive Buffer Overflow */ | ||
259 | LINKERR_PROT_ERR = CPC925_BIT(19), /* Protocol error */ | ||
260 | |||
261 | HT_LINKERR_DETECTED = (LINKERR_EOC_ERR | LINKERR_OVF_ERR | | ||
262 | LINKERR_PROT_ERR), | ||
263 | }; | ||
264 | |||
265 | /************************************************************ | ||
266 | * Bridge Control Register (BRGCTRL) | ||
267 | ************************************************************/ | ||
268 | #define REG_BRGCTRL_OFFSET 0x70300 | ||
269 | enum brgctrl_bits { | ||
270 | BRGCTRL_DETSERR = CPC925_BIT(0), /* SERR on Secondary Bus */ | ||
271 | BRGCTRL_SECBUSRESET = CPC925_BIT(9), /* Secondary Bus Reset */ | ||
272 | }; | ||
273 | |||
274 | /* Private structure for edac memory controller */ | ||
275 | struct cpc925_mc_pdata { | ||
276 | void __iomem *vbase; | ||
277 | unsigned long total_mem; | ||
278 | const char *name; | ||
279 | int edac_idx; | ||
280 | }; | ||
281 | |||
282 | /* Private structure for common edac device */ | ||
283 | struct cpc925_dev_info { | ||
284 | void __iomem *vbase; | ||
285 | struct platform_device *pdev; | ||
286 | char *ctl_name; | ||
287 | int edac_idx; | ||
288 | struct edac_device_ctl_info *edac_dev; | ||
289 | void (*init)(struct cpc925_dev_info *dev_info); | ||
290 | void (*exit)(struct cpc925_dev_info *dev_info); | ||
291 | void (*check)(struct edac_device_ctl_info *edac_dev); | ||
292 | }; | ||
293 | |||
294 | /* Get total memory size from Open Firmware DTB */ | ||
295 | static void get_total_mem(struct cpc925_mc_pdata *pdata) | ||
296 | { | ||
297 | struct device_node *np = NULL; | ||
298 | const unsigned int *reg, *reg_end; | ||
299 | int len, sw, aw; | ||
300 | unsigned long start, size; | ||
301 | |||
302 | np = of_find_node_by_type(NULL, "memory"); | ||
303 | if (!np) | ||
304 | return; | ||
305 | |||
306 | aw = of_n_addr_cells(np); | ||
307 | sw = of_n_size_cells(np); | ||
308 | reg = (const unsigned int *)of_get_property(np, "reg", &len); | ||
309 | reg_end = reg + len/4; | ||
310 | |||
311 | pdata->total_mem = 0; | ||
312 | do { | ||
313 | start = of_read_number(reg, aw); | ||
314 | reg += aw; | ||
315 | size = of_read_number(reg, sw); | ||
316 | reg += sw; | ||
317 | debugf1("%s: start 0x%lx, size 0x%lx\n", __func__, | ||
318 | start, size); | ||
319 | pdata->total_mem += size; | ||
320 | } while (reg < reg_end); | ||
321 | |||
322 | of_node_put(np); | ||
323 | debugf0("%s: total_mem 0x%lx\n", __func__, pdata->total_mem); | ||
324 | } | ||
325 | |||
326 | static void cpc925_init_csrows(struct mem_ctl_info *mci) | ||
327 | { | ||
328 | struct cpc925_mc_pdata *pdata = mci->pvt_info; | ||
329 | struct csrow_info *csrow; | ||
330 | int index; | ||
331 | u32 mbmr, mbbar, bba; | ||
332 | unsigned long row_size, last_nr_pages = 0; | ||
333 | |||
334 | get_total_mem(pdata); | ||
335 | |||
336 | for (index = 0; index < mci->nr_csrows; index++) { | ||
337 | mbmr = __raw_readl(pdata->vbase + REG_MBMR_OFFSET + | ||
338 | 0x20 * index); | ||
339 | mbbar = __raw_readl(pdata->vbase + REG_MBBAR_OFFSET + | ||
340 | 0x20 + index); | ||
341 | bba = (((mbmr & MBMR_BBA_MASK) >> MBMR_BBA_SHIFT) << 8) | | ||
342 | ((mbbar & MBBAR_BBA_MASK) >> MBBAR_BBA_SHIFT); | ||
343 | |||
344 | if (bba == 0) | ||
345 | continue; /* not populated */ | ||
346 | |||
347 | csrow = &mci->csrows[index]; | ||
348 | |||
349 | row_size = bba * (1UL << 28); /* 256M */ | ||
350 | csrow->first_page = last_nr_pages; | ||
351 | csrow->nr_pages = row_size >> PAGE_SHIFT; | ||
352 | csrow->last_page = csrow->first_page + csrow->nr_pages - 1; | ||
353 | last_nr_pages = csrow->last_page + 1; | ||
354 | |||
355 | csrow->mtype = MEM_RDDR; | ||
356 | csrow->edac_mode = EDAC_SECDED; | ||
357 | |||
358 | switch (csrow->nr_channels) { | ||
359 | case 1: /* Single channel */ | ||
360 | csrow->grain = 32; /* four-beat burst of 32 bytes */ | ||
361 | break; | ||
362 | case 2: /* Dual channel */ | ||
363 | default: | ||
364 | csrow->grain = 64; /* four-beat burst of 64 bytes */ | ||
365 | break; | ||
366 | } | ||
367 | |||
368 | switch ((mbmr & MBMR_MODE_MASK) >> MBMR_MODE_SHIFT) { | ||
369 | case 6: /* 0110, no way to differentiate X8 VS X16 */ | ||
370 | case 5: /* 0101 */ | ||
371 | case 8: /* 1000 */ | ||
372 | csrow->dtype = DEV_X16; | ||
373 | break; | ||
374 | case 7: /* 0111 */ | ||
375 | case 9: /* 1001 */ | ||
376 | csrow->dtype = DEV_X8; | ||
377 | break; | ||
378 | default: | ||
379 | csrow->dtype = DEV_UNKNOWN; | ||
380 | break; | ||
381 | } | ||
382 | } | ||
383 | } | ||
384 | |||
385 | /* Enable memory controller ECC detection */ | ||
386 | static void cpc925_mc_init(struct mem_ctl_info *mci) | ||
387 | { | ||
388 | struct cpc925_mc_pdata *pdata = mci->pvt_info; | ||
389 | u32 apimask; | ||
390 | u32 mccr; | ||
391 | |||
392 | /* Enable various ECC error exceptions */ | ||
393 | apimask = __raw_readl(pdata->vbase + REG_APIMASK_OFFSET); | ||
394 | if ((apimask & ECC_MASK_ENABLE) == 0) { | ||
395 | apimask |= ECC_MASK_ENABLE; | ||
396 | __raw_writel(apimask, pdata->vbase + REG_APIMASK_OFFSET); | ||
397 | } | ||
398 | |||
399 | /* Enable ECC detection */ | ||
400 | mccr = __raw_readl(pdata->vbase + REG_MCCR_OFFSET); | ||
401 | if ((mccr & MCCR_ECC_EN) == 0) { | ||
402 | mccr |= MCCR_ECC_EN; | ||
403 | __raw_writel(mccr, pdata->vbase + REG_MCCR_OFFSET); | ||
404 | } | ||
405 | } | ||
406 | |||
407 | /* Disable memory controller ECC detection */ | ||
408 | static void cpc925_mc_exit(struct mem_ctl_info *mci) | ||
409 | { | ||
410 | /* | ||
411 | * WARNING: | ||
412 | * We are supposed to clear the ECC error detection bits, | ||
413 | * and it will be no problem to do so. However, once they | ||
414 | * are cleared here if we want to re-install CPC925 EDAC | ||
415 | * module later, setting them up in cpc925_mc_init() will | ||
416 | * trigger machine check exception. | ||
417 | * Also, it's ok to leave ECC error detection bits enabled, | ||
418 | * since they are reset to 1 by default or by boot loader. | ||
419 | */ | ||
420 | |||
421 | return; | ||
422 | } | ||
423 | |||
424 | /* | ||
425 | * Revert DDR column/row/bank addresses into page frame number and | ||
426 | * offset in page. | ||
427 | * | ||
428 | * Suppose memory mode is 0x0111(128-bit mode, identical DIMM pairs), | ||
429 | * physical address(PA) bits to column address(CA) bits mappings are: | ||
430 | * CA 0 1 2 3 4 5 6 7 8 9 10 | ||
431 | * PA 59 58 57 56 55 54 53 52 51 50 49 | ||
432 | * | ||
433 | * physical address(PA) bits to bank address(BA) bits mappings are: | ||
434 | * BA 0 1 | ||
435 | * PA 43 44 | ||
436 | * | ||
437 | * physical address(PA) bits to row address(RA) bits mappings are: | ||
438 | * RA 0 1 2 3 4 5 6 7 8 9 10 11 12 | ||
439 | * PA 36 35 34 48 47 46 45 40 41 42 39 38 37 | ||
440 | */ | ||
441 | static void cpc925_mc_get_pfn(struct mem_ctl_info *mci, u32 mear, | ||
442 | unsigned long *pfn, unsigned long *offset, int *csrow) | ||
443 | { | ||
444 | u32 bcnt, rank, col, bank, row; | ||
445 | u32 c; | ||
446 | unsigned long pa; | ||
447 | int i; | ||
448 | |||
449 | bcnt = (mear & MEAR_BCNT_MASK) >> MEAR_BCNT_SHIFT; | ||
450 | rank = (mear & MEAR_RANK_MASK) >> MEAR_RANK_SHIFT; | ||
451 | col = (mear & MEAR_COL_MASK) >> MEAR_COL_SHIFT; | ||
452 | bank = (mear & MEAR_BANK_MASK) >> MEAR_BANK_SHIFT; | ||
453 | row = mear & MEAR_ROW_MASK; | ||
454 | |||
455 | *csrow = rank; | ||
456 | |||
457 | #ifdef CONFIG_EDAC_DEBUG | ||
458 | if (mci->csrows[rank].first_page == 0) { | ||
459 | cpc925_mc_printk(mci, KERN_ERR, "ECC occurs in a " | ||
460 | "non-populated csrow, broken hardware?\n"); | ||
461 | return; | ||
462 | } | ||
463 | #endif | ||
464 | |||
465 | /* Revert csrow number */ | ||
466 | pa = mci->csrows[rank].first_page << PAGE_SHIFT; | ||
467 | |||
468 | /* Revert column address */ | ||
469 | col += bcnt; | ||
470 | for (i = 0; i < 11; i++) { | ||
471 | c = col & 0x1; | ||
472 | col >>= 1; | ||
473 | pa |= c << (14 - i); | ||
474 | } | ||
475 | |||
476 | /* Revert bank address */ | ||
477 | pa |= bank << 19; | ||
478 | |||
479 | /* Revert row address, in 4 steps */ | ||
480 | for (i = 0; i < 3; i++) { | ||
481 | c = row & 0x1; | ||
482 | row >>= 1; | ||
483 | pa |= c << (26 - i); | ||
484 | } | ||
485 | |||
486 | for (i = 0; i < 3; i++) { | ||
487 | c = row & 0x1; | ||
488 | row >>= 1; | ||
489 | pa |= c << (21 + i); | ||
490 | } | ||
491 | |||
492 | for (i = 0; i < 4; i++) { | ||
493 | c = row & 0x1; | ||
494 | row >>= 1; | ||
495 | pa |= c << (18 - i); | ||
496 | } | ||
497 | |||
498 | for (i = 0; i < 3; i++) { | ||
499 | c = row & 0x1; | ||
500 | row >>= 1; | ||
501 | pa |= c << (29 - i); | ||
502 | } | ||
503 | |||
504 | *offset = pa & (PAGE_SIZE - 1); | ||
505 | *pfn = pa >> PAGE_SHIFT; | ||
506 | |||
507 | debugf0("%s: ECC physical address 0x%lx\n", __func__, pa); | ||
508 | } | ||
509 | |||
510 | static int cpc925_mc_find_channel(struct mem_ctl_info *mci, u16 syndrome) | ||
511 | { | ||
512 | if ((syndrome & MESR_ECC_SYN_H_MASK) == 0) | ||
513 | return 0; | ||
514 | |||
515 | if ((syndrome & MESR_ECC_SYN_L_MASK) == 0) | ||
516 | return 1; | ||
517 | |||
518 | cpc925_mc_printk(mci, KERN_INFO, "Unexpected syndrome value: 0x%x\n", | ||
519 | syndrome); | ||
520 | return 1; | ||
521 | } | ||
522 | |||
523 | /* Check memory controller registers for ECC errors */ | ||
524 | static void cpc925_mc_check(struct mem_ctl_info *mci) | ||
525 | { | ||
526 | struct cpc925_mc_pdata *pdata = mci->pvt_info; | ||
527 | u32 apiexcp; | ||
528 | u32 mear; | ||
529 | u32 mesr; | ||
530 | u16 syndrome; | ||
531 | unsigned long pfn = 0, offset = 0; | ||
532 | int csrow = 0, channel = 0; | ||
533 | |||
534 | /* APIEXCP is cleared when read */ | ||
535 | apiexcp = __raw_readl(pdata->vbase + REG_APIEXCP_OFFSET); | ||
536 | if ((apiexcp & ECC_EXCP_DETECTED) == 0) | ||
537 | return; | ||
538 | |||
539 | mesr = __raw_readl(pdata->vbase + REG_MESR_OFFSET); | ||
540 | syndrome = mesr | (MESR_ECC_SYN_H_MASK | MESR_ECC_SYN_L_MASK); | ||
541 | |||
542 | mear = __raw_readl(pdata->vbase + REG_MEAR_OFFSET); | ||
543 | |||
544 | /* Revert column/row addresses into page frame number, etc */ | ||
545 | cpc925_mc_get_pfn(mci, mear, &pfn, &offset, &csrow); | ||
546 | |||
547 | if (apiexcp & CECC_EXCP_DETECTED) { | ||
548 | cpc925_mc_printk(mci, KERN_INFO, "DRAM CECC Fault\n"); | ||
549 | channel = cpc925_mc_find_channel(mci, syndrome); | ||
550 | edac_mc_handle_ce(mci, pfn, offset, syndrome, | ||
551 | csrow, channel, mci->ctl_name); | ||
552 | } | ||
553 | |||
554 | if (apiexcp & UECC_EXCP_DETECTED) { | ||
555 | cpc925_mc_printk(mci, KERN_INFO, "DRAM UECC Fault\n"); | ||
556 | edac_mc_handle_ue(mci, pfn, offset, csrow, mci->ctl_name); | ||
557 | } | ||
558 | |||
559 | cpc925_mc_printk(mci, KERN_INFO, "Dump registers:\n"); | ||
560 | cpc925_mc_printk(mci, KERN_INFO, "APIMASK 0x%08x\n", | ||
561 | __raw_readl(pdata->vbase + REG_APIMASK_OFFSET)); | ||
562 | cpc925_mc_printk(mci, KERN_INFO, "APIEXCP 0x%08x\n", | ||
563 | apiexcp); | ||
564 | cpc925_mc_printk(mci, KERN_INFO, "Mem Scrub Ctrl 0x%08x\n", | ||
565 | __raw_readl(pdata->vbase + REG_MSCR_OFFSET)); | ||
566 | cpc925_mc_printk(mci, KERN_INFO, "Mem Scrub Rge Start 0x%08x\n", | ||
567 | __raw_readl(pdata->vbase + REG_MSRSR_OFFSET)); | ||
568 | cpc925_mc_printk(mci, KERN_INFO, "Mem Scrub Rge End 0x%08x\n", | ||
569 | __raw_readl(pdata->vbase + REG_MSRER_OFFSET)); | ||
570 | cpc925_mc_printk(mci, KERN_INFO, "Mem Scrub Pattern 0x%08x\n", | ||
571 | __raw_readl(pdata->vbase + REG_MSPR_OFFSET)); | ||
572 | cpc925_mc_printk(mci, KERN_INFO, "Mem Chk Ctrl 0x%08x\n", | ||
573 | __raw_readl(pdata->vbase + REG_MCCR_OFFSET)); | ||
574 | cpc925_mc_printk(mci, KERN_INFO, "Mem Chk Rge End 0x%08x\n", | ||
575 | __raw_readl(pdata->vbase + REG_MCRER_OFFSET)); | ||
576 | cpc925_mc_printk(mci, KERN_INFO, "Mem Err Address 0x%08x\n", | ||
577 | mesr); | ||
578 | cpc925_mc_printk(mci, KERN_INFO, "Mem Err Syndrome 0x%08x\n", | ||
579 | syndrome); | ||
580 | } | ||
581 | |||
582 | /******************** CPU err device********************************/ | ||
583 | /* Enable CPU Errors detection */ | ||
584 | static void cpc925_cpu_init(struct cpc925_dev_info *dev_info) | ||
585 | { | ||
586 | u32 apimask; | ||
587 | |||
588 | apimask = __raw_readl(dev_info->vbase + REG_APIMASK_OFFSET); | ||
589 | if ((apimask & CPU_MASK_ENABLE) == 0) { | ||
590 | apimask |= CPU_MASK_ENABLE; | ||
591 | __raw_writel(apimask, dev_info->vbase + REG_APIMASK_OFFSET); | ||
592 | } | ||
593 | } | ||
594 | |||
595 | /* Disable CPU Errors detection */ | ||
596 | static void cpc925_cpu_exit(struct cpc925_dev_info *dev_info) | ||
597 | { | ||
598 | /* | ||
599 | * WARNING: | ||
600 | * We are supposed to clear the CPU error detection bits, | ||
601 | * and it will be no problem to do so. However, once they | ||
602 | * are cleared here if we want to re-install CPC925 EDAC | ||
603 | * module later, setting them up in cpc925_cpu_init() will | ||
604 | * trigger machine check exception. | ||
605 | * Also, it's ok to leave CPU error detection bits enabled, | ||
606 | * since they are reset to 1 by default. | ||
607 | */ | ||
608 | |||
609 | return; | ||
610 | } | ||
611 | |||
612 | /* Check for CPU Errors */ | ||
613 | static void cpc925_cpu_check(struct edac_device_ctl_info *edac_dev) | ||
614 | { | ||
615 | struct cpc925_dev_info *dev_info = edac_dev->pvt_info; | ||
616 | u32 apiexcp; | ||
617 | u32 apimask; | ||
618 | |||
619 | /* APIEXCP is cleared when read */ | ||
620 | apiexcp = __raw_readl(dev_info->vbase + REG_APIEXCP_OFFSET); | ||
621 | if ((apiexcp & CPU_EXCP_DETECTED) == 0) | ||
622 | return; | ||
623 | |||
624 | apimask = __raw_readl(dev_info->vbase + REG_APIMASK_OFFSET); | ||
625 | cpc925_printk(KERN_INFO, "Processor Interface Fault\n" | ||
626 | "Processor Interface register dump:\n"); | ||
627 | cpc925_printk(KERN_INFO, "APIMASK 0x%08x\n", apimask); | ||
628 | cpc925_printk(KERN_INFO, "APIEXCP 0x%08x\n", apiexcp); | ||
629 | |||
630 | edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name); | ||
631 | } | ||
632 | |||
633 | /******************** HT Link err device****************************/ | ||
634 | /* Enable HyperTransport Link Error detection */ | ||
635 | static void cpc925_htlink_init(struct cpc925_dev_info *dev_info) | ||
636 | { | ||
637 | u32 ht_errctrl; | ||
638 | |||
639 | ht_errctrl = __raw_readl(dev_info->vbase + REG_ERRCTRL_OFFSET); | ||
640 | if ((ht_errctrl & HT_ERRCTRL_ENABLE) == 0) { | ||
641 | ht_errctrl |= HT_ERRCTRL_ENABLE; | ||
642 | __raw_writel(ht_errctrl, dev_info->vbase + REG_ERRCTRL_OFFSET); | ||
643 | } | ||
644 | } | ||
645 | |||
646 | /* Disable HyperTransport Link Error detection */ | ||
647 | static void cpc925_htlink_exit(struct cpc925_dev_info *dev_info) | ||
648 | { | ||
649 | u32 ht_errctrl; | ||
650 | |||
651 | ht_errctrl = __raw_readl(dev_info->vbase + REG_ERRCTRL_OFFSET); | ||
652 | ht_errctrl &= ~HT_ERRCTRL_ENABLE; | ||
653 | __raw_writel(ht_errctrl, dev_info->vbase + REG_ERRCTRL_OFFSET); | ||
654 | } | ||
655 | |||
656 | /* Check for HyperTransport Link errors */ | ||
657 | static void cpc925_htlink_check(struct edac_device_ctl_info *edac_dev) | ||
658 | { | ||
659 | struct cpc925_dev_info *dev_info = edac_dev->pvt_info; | ||
660 | u32 brgctrl = __raw_readl(dev_info->vbase + REG_BRGCTRL_OFFSET); | ||
661 | u32 linkctrl = __raw_readl(dev_info->vbase + REG_LINKCTRL_OFFSET); | ||
662 | u32 errctrl = __raw_readl(dev_info->vbase + REG_ERRCTRL_OFFSET); | ||
663 | u32 linkerr = __raw_readl(dev_info->vbase + REG_LINKERR_OFFSET); | ||
664 | |||
665 | if (!((brgctrl & BRGCTRL_DETSERR) || | ||
666 | (linkctrl & HT_LINKCTRL_DETECTED) || | ||
667 | (errctrl & HT_ERRCTRL_DETECTED) || | ||
668 | (linkerr & HT_LINKERR_DETECTED))) | ||
669 | return; | ||
670 | |||
671 | cpc925_printk(KERN_INFO, "HT Link Fault\n" | ||
672 | "HT register dump:\n"); | ||
673 | cpc925_printk(KERN_INFO, "Bridge Ctrl 0x%08x\n", | ||
674 | brgctrl); | ||
675 | cpc925_printk(KERN_INFO, "Link Config Ctrl 0x%08x\n", | ||
676 | linkctrl); | ||
677 | cpc925_printk(KERN_INFO, "Error Enum and Ctrl 0x%08x\n", | ||
678 | errctrl); | ||
679 | cpc925_printk(KERN_INFO, "Link Error 0x%08x\n", | ||
680 | linkerr); | ||
681 | |||
682 | /* Clear by write 1 */ | ||
683 | if (brgctrl & BRGCTRL_DETSERR) | ||
684 | __raw_writel(BRGCTRL_DETSERR, | ||
685 | dev_info->vbase + REG_BRGCTRL_OFFSET); | ||
686 | |||
687 | if (linkctrl & HT_LINKCTRL_DETECTED) | ||
688 | __raw_writel(HT_LINKCTRL_DETECTED, | ||
689 | dev_info->vbase + REG_LINKCTRL_OFFSET); | ||
690 | |||
691 | /* Initiate Secondary Bus Reset to clear the chain failure */ | ||
692 | if (errctrl & ERRCTRL_CHN_FAL) | ||
693 | __raw_writel(BRGCTRL_SECBUSRESET, | ||
694 | dev_info->vbase + REG_BRGCTRL_OFFSET); | ||
695 | |||
696 | if (errctrl & ERRCTRL_RSP_ERR) | ||
697 | __raw_writel(ERRCTRL_RSP_ERR, | ||
698 | dev_info->vbase + REG_ERRCTRL_OFFSET); | ||
699 | |||
700 | if (linkerr & HT_LINKERR_DETECTED) | ||
701 | __raw_writel(HT_LINKERR_DETECTED, | ||
702 | dev_info->vbase + REG_LINKERR_OFFSET); | ||
703 | |||
704 | edac_device_handle_ce(edac_dev, 0, 0, edac_dev->ctl_name); | ||
705 | } | ||
706 | |||
707 | static struct cpc925_dev_info cpc925_devs[] = { | ||
708 | { | ||
709 | .ctl_name = CPC925_CPU_ERR_DEV, | ||
710 | .init = cpc925_cpu_init, | ||
711 | .exit = cpc925_cpu_exit, | ||
712 | .check = cpc925_cpu_check, | ||
713 | }, | ||
714 | { | ||
715 | .ctl_name = CPC925_HT_LINK_DEV, | ||
716 | .init = cpc925_htlink_init, | ||
717 | .exit = cpc925_htlink_exit, | ||
718 | .check = cpc925_htlink_check, | ||
719 | }, | ||
720 | {0}, /* Terminated by NULL */ | ||
721 | }; | ||
722 | |||
723 | /* | ||
724 | * Add CPU Err detection and HyperTransport Link Err detection | ||
725 | * as common "edac_device", they have no corresponding device | ||
726 | * nodes in the Open Firmware DTB and we have to add platform | ||
727 | * devices for them. Also, they will share the MMIO with that | ||
728 | * of memory controller. | ||
729 | */ | ||
730 | static void cpc925_add_edac_devices(void __iomem *vbase) | ||
731 | { | ||
732 | struct cpc925_dev_info *dev_info; | ||
733 | |||
734 | if (!vbase) { | ||
735 | cpc925_printk(KERN_ERR, "MMIO not established yet\n"); | ||
736 | return; | ||
737 | } | ||
738 | |||
739 | for (dev_info = &cpc925_devs[0]; dev_info->init; dev_info++) { | ||
740 | dev_info->vbase = vbase; | ||
741 | dev_info->pdev = platform_device_register_simple( | ||
742 | dev_info->ctl_name, 0, NULL, 0); | ||
743 | if (IS_ERR(dev_info->pdev)) { | ||
744 | cpc925_printk(KERN_ERR, | ||
745 | "Can't register platform device for %s\n", | ||
746 | dev_info->ctl_name); | ||
747 | continue; | ||
748 | } | ||
749 | |||
750 | /* | ||
751 | * Don't have to allocate private structure but | ||
752 | * make use of cpc925_devs[] instead. | ||
753 | */ | ||
754 | dev_info->edac_idx = edac_device_alloc_index(); | ||
755 | dev_info->edac_dev = | ||
756 | edac_device_alloc_ctl_info(0, dev_info->ctl_name, | ||
757 | 1, NULL, 0, 0, NULL, 0, dev_info->edac_idx); | ||
758 | if (!dev_info->edac_dev) { | ||
759 | cpc925_printk(KERN_ERR, "No memory for edac device\n"); | ||
760 | goto err1; | ||
761 | } | ||
762 | |||
763 | dev_info->edac_dev->pvt_info = dev_info; | ||
764 | dev_info->edac_dev->dev = &dev_info->pdev->dev; | ||
765 | dev_info->edac_dev->ctl_name = dev_info->ctl_name; | ||
766 | dev_info->edac_dev->mod_name = CPC925_EDAC_MOD_STR; | ||
767 | dev_info->edac_dev->dev_name = dev_name(&dev_info->pdev->dev); | ||
768 | |||
769 | if (edac_op_state == EDAC_OPSTATE_POLL) | ||
770 | dev_info->edac_dev->edac_check = dev_info->check; | ||
771 | |||
772 | if (dev_info->init) | ||
773 | dev_info->init(dev_info); | ||
774 | |||
775 | if (edac_device_add_device(dev_info->edac_dev) > 0) { | ||
776 | cpc925_printk(KERN_ERR, | ||
777 | "Unable to add edac device for %s\n", | ||
778 | dev_info->ctl_name); | ||
779 | goto err2; | ||
780 | } | ||
781 | |||
782 | debugf0("%s: Successfully added edac device for %s\n", | ||
783 | __func__, dev_info->ctl_name); | ||
784 | |||
785 | continue; | ||
786 | |||
787 | err2: | ||
788 | if (dev_info->exit) | ||
789 | dev_info->exit(dev_info); | ||
790 | edac_device_free_ctl_info(dev_info->edac_dev); | ||
791 | err1: | ||
792 | platform_device_unregister(dev_info->pdev); | ||
793 | } | ||
794 | } | ||
795 | |||
796 | /* | ||
797 | * Delete the common "edac_device" for CPU Err Detection | ||
798 | * and HyperTransport Link Err Detection | ||
799 | */ | ||
800 | static void cpc925_del_edac_devices(void) | ||
801 | { | ||
802 | struct cpc925_dev_info *dev_info; | ||
803 | |||
804 | for (dev_info = &cpc925_devs[0]; dev_info->init; dev_info++) { | ||
805 | if (dev_info->edac_dev) { | ||
806 | edac_device_del_device(dev_info->edac_dev->dev); | ||
807 | edac_device_free_ctl_info(dev_info->edac_dev); | ||
808 | platform_device_unregister(dev_info->pdev); | ||
809 | } | ||
810 | |||
811 | if (dev_info->exit) | ||
812 | dev_info->exit(dev_info); | ||
813 | |||
814 | debugf0("%s: Successfully deleted edac device for %s\n", | ||
815 | __func__, dev_info->ctl_name); | ||
816 | } | ||
817 | } | ||
818 | |||
819 | /* Convert current back-ground scrub rate into byte/sec bandwith */ | ||
820 | static int cpc925_get_sdram_scrub_rate(struct mem_ctl_info *mci, u32 *bw) | ||
821 | { | ||
822 | struct cpc925_mc_pdata *pdata = mci->pvt_info; | ||
823 | u32 mscr; | ||
824 | u8 si; | ||
825 | |||
826 | mscr = __raw_readl(pdata->vbase + REG_MSCR_OFFSET); | ||
827 | si = (mscr & MSCR_SI_MASK) >> MSCR_SI_SHIFT; | ||
828 | |||
829 | debugf0("%s, Mem Scrub Ctrl Register 0x%x\n", __func__, mscr); | ||
830 | |||
831 | if (((mscr & MSCR_SCRUB_MOD_MASK) != MSCR_BACKGR_SCRUB) || | ||
832 | (si == 0)) { | ||
833 | cpc925_mc_printk(mci, KERN_INFO, "Scrub mode not enabled\n"); | ||
834 | *bw = 0; | ||
835 | } else | ||
836 | *bw = CPC925_SCRUB_BLOCK_SIZE * 0xFA67 / si; | ||
837 | |||
838 | return 0; | ||
839 | } | ||
840 | |||
841 | /* Return 0 for single channel; 1 for dual channel */ | ||
842 | static int cpc925_mc_get_channels(void __iomem *vbase) | ||
843 | { | ||
844 | int dual = 0; | ||
845 | u32 mbcr; | ||
846 | |||
847 | mbcr = __raw_readl(vbase + REG_MBCR_OFFSET); | ||
848 | |||
849 | /* | ||
850 | * Dual channel only when 128-bit wide physical bus | ||
851 | * and 128-bit configuration. | ||
852 | */ | ||
853 | if (((mbcr & MBCR_64BITCFG_MASK) == 0) && | ||
854 | ((mbcr & MBCR_64BITBUS_MASK) == 0)) | ||
855 | dual = 1; | ||
856 | |||
857 | debugf0("%s: %s channel\n", __func__, | ||
858 | (dual > 0) ? "Dual" : "Single"); | ||
859 | |||
860 | return dual; | ||
861 | } | ||
862 | |||
863 | static int __devinit cpc925_probe(struct platform_device *pdev) | ||
864 | { | ||
865 | static int edac_mc_idx; | ||
866 | struct mem_ctl_info *mci; | ||
867 | void __iomem *vbase; | ||
868 | struct cpc925_mc_pdata *pdata; | ||
869 | struct resource *r; | ||
870 | int res = 0, nr_channels; | ||
871 | |||
872 | debugf0("%s: %s platform device found!\n", __func__, pdev->name); | ||
873 | |||
874 | if (!devres_open_group(&pdev->dev, cpc925_probe, GFP_KERNEL)) { | ||
875 | res = -ENOMEM; | ||
876 | goto out; | ||
877 | } | ||
878 | |||
879 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
880 | if (!r) { | ||
881 | cpc925_printk(KERN_ERR, "Unable to get resource\n"); | ||
882 | res = -ENOENT; | ||
883 | goto err1; | ||
884 | } | ||
885 | |||
886 | if (!devm_request_mem_region(&pdev->dev, | ||
887 | r->start, | ||
888 | r->end - r->start + 1, | ||
889 | pdev->name)) { | ||
890 | cpc925_printk(KERN_ERR, "Unable to request mem region\n"); | ||
891 | res = -EBUSY; | ||
892 | goto err1; | ||
893 | } | ||
894 | |||
895 | vbase = devm_ioremap(&pdev->dev, r->start, r->end - r->start + 1); | ||
896 | if (!vbase) { | ||
897 | cpc925_printk(KERN_ERR, "Unable to ioremap device\n"); | ||
898 | res = -ENOMEM; | ||
899 | goto err2; | ||
900 | } | ||
901 | |||
902 | nr_channels = cpc925_mc_get_channels(vbase); | ||
903 | mci = edac_mc_alloc(sizeof(struct cpc925_mc_pdata), | ||
904 | CPC925_NR_CSROWS, nr_channels + 1, edac_mc_idx); | ||
905 | if (!mci) { | ||
906 | cpc925_printk(KERN_ERR, "No memory for mem_ctl_info\n"); | ||
907 | res = -ENOMEM; | ||
908 | goto err2; | ||
909 | } | ||
910 | |||
911 | pdata = mci->pvt_info; | ||
912 | pdata->vbase = vbase; | ||
913 | pdata->edac_idx = edac_mc_idx++; | ||
914 | pdata->name = pdev->name; | ||
915 | |||
916 | mci->dev = &pdev->dev; | ||
917 | platform_set_drvdata(pdev, mci); | ||
918 | mci->dev_name = dev_name(&pdev->dev); | ||
919 | mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR; | ||
920 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; | ||
921 | mci->edac_cap = EDAC_FLAG_SECDED; | ||
922 | mci->mod_name = CPC925_EDAC_MOD_STR; | ||
923 | mci->mod_ver = CPC925_EDAC_REVISION; | ||
924 | mci->ctl_name = pdev->name; | ||
925 | |||
926 | if (edac_op_state == EDAC_OPSTATE_POLL) | ||
927 | mci->edac_check = cpc925_mc_check; | ||
928 | |||
929 | mci->ctl_page_to_phys = NULL; | ||
930 | mci->scrub_mode = SCRUB_SW_SRC; | ||
931 | mci->set_sdram_scrub_rate = NULL; | ||
932 | mci->get_sdram_scrub_rate = cpc925_get_sdram_scrub_rate; | ||
933 | |||
934 | cpc925_init_csrows(mci); | ||
935 | |||
936 | /* Setup memory controller registers */ | ||
937 | cpc925_mc_init(mci); | ||
938 | |||
939 | if (edac_mc_add_mc(mci) > 0) { | ||
940 | cpc925_mc_printk(mci, KERN_ERR, "Failed edac_mc_add_mc()\n"); | ||
941 | goto err3; | ||
942 | } | ||
943 | |||
944 | cpc925_add_edac_devices(vbase); | ||
945 | |||
946 | /* get this far and it's successful */ | ||
947 | debugf0("%s: success\n", __func__); | ||
948 | |||
949 | res = 0; | ||
950 | goto out; | ||
951 | |||
952 | err3: | ||
953 | cpc925_mc_exit(mci); | ||
954 | edac_mc_free(mci); | ||
955 | err2: | ||
956 | devm_release_mem_region(&pdev->dev, r->start, r->end-r->start+1); | ||
957 | err1: | ||
958 | devres_release_group(&pdev->dev, cpc925_probe); | ||
959 | out: | ||
960 | return res; | ||
961 | } | ||
962 | |||
963 | static int cpc925_remove(struct platform_device *pdev) | ||
964 | { | ||
965 | struct mem_ctl_info *mci = platform_get_drvdata(pdev); | ||
966 | |||
967 | /* | ||
968 | * Delete common edac devices before edac mc, because | ||
969 | * the former share the MMIO of the latter. | ||
970 | */ | ||
971 | cpc925_del_edac_devices(); | ||
972 | cpc925_mc_exit(mci); | ||
973 | |||
974 | edac_mc_del_mc(&pdev->dev); | ||
975 | edac_mc_free(mci); | ||
976 | |||
977 | return 0; | ||
978 | } | ||
979 | |||
980 | static struct platform_driver cpc925_edac_driver = { | ||
981 | .probe = cpc925_probe, | ||
982 | .remove = cpc925_remove, | ||
983 | .driver = { | ||
984 | .name = "cpc925_edac", | ||
985 | } | ||
986 | }; | ||
987 | |||
988 | static int __init cpc925_edac_init(void) | ||
989 | { | ||
990 | int ret = 0; | ||
991 | |||
992 | printk(KERN_INFO "IBM CPC925 EDAC driver " CPC925_EDAC_REVISION "\n"); | ||
993 | printk(KERN_INFO "\t(c) 2008 Wind River Systems, Inc\n"); | ||
994 | |||
995 | /* Only support POLL mode so far */ | ||
996 | edac_op_state = EDAC_OPSTATE_POLL; | ||
997 | |||
998 | ret = platform_driver_register(&cpc925_edac_driver); | ||
999 | if (ret) { | ||
1000 | printk(KERN_WARNING "Failed to register %s\n", | ||
1001 | CPC925_EDAC_MOD_STR); | ||
1002 | } | ||
1003 | |||
1004 | return ret; | ||
1005 | } | ||
1006 | |||
1007 | static void __exit cpc925_edac_exit(void) | ||
1008 | { | ||
1009 | platform_driver_unregister(&cpc925_edac_driver); | ||
1010 | } | ||
1011 | |||
1012 | module_init(cpc925_edac_init); | ||
1013 | module_exit(cpc925_edac_exit); | ||
1014 | |||
1015 | MODULE_LICENSE("GPL"); | ||
1016 | MODULE_AUTHOR("Cao Qingtao <qingtao.cao@windriver.com>"); | ||
1017 | MODULE_DESCRIPTION("IBM CPC925 Bridge and MC EDAC kernel module"); | ||