1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/module.h>
19#include <linux/init.h>
20#include <linux/pci.h>
21#include <linux/pci_ids.h>
22#include <linux/slab.h>
23#include "edac_core.h"
24
25#define R82600_REVISION " Ver: 2.0.2 " __DATE__
26#define EDAC_MOD_STR "r82600_edac"
27
28#define r82600_printk(level, fmt, arg...) \
29 edac_printk(level, "r82600", fmt, ##arg)
30
31#define r82600_mc_printk(mci, level, fmt, arg...) \
32 edac_mc_chipset_printk(mci, level, "r82600", fmt, ##arg)
33
34
35
36
37
38
39
40
41
42
43
44#define R82600_NR_CSROWS 4
45#define R82600_NR_CHANS 1
46#define R82600_NR_DIMMS 4
47
48#define R82600_BRIDGE_ID 0x8200
49
50
51#define R82600_DRAMC 0x57
52
53
54
55
56
57
58
59
60
61
62
63
64
65#define R82600_SDRAMC 0x76
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89#define R82600_EAP 0x80
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123#define R82600_DRBA 0x60
124
125
126
127
128
129
130struct r82600_error_info {
131 u32 eapr;
132};
133
134static unsigned int disable_hardware_scrub;
135
136static struct edac_pci_ctl_info *r82600_pci;
137
138static void r82600_get_error_info(struct mem_ctl_info *mci,
139 struct r82600_error_info *info)
140{
141 struct pci_dev *pdev;
142
143 pdev = to_pci_dev(mci->dev);
144 pci_read_config_dword(pdev, R82600_EAP, &info->eapr);
145
146 if (info->eapr & BIT(0))
147
148 pci_write_bits32(pdev, R82600_EAP,
149 ((u32) BIT(0) & (u32) BIT(1)),
150 ((u32) BIT(0) & (u32) BIT(1)));
151
152 if (info->eapr & BIT(1))
153
154 pci_write_bits32(pdev, R82600_EAP,
155 ((u32) BIT(0) & (u32) BIT(1)),
156 ((u32) BIT(0) & (u32) BIT(1)));
157}
158
159static int r82600_process_error_info(struct mem_ctl_info *mci,
160 struct r82600_error_info *info,
161 int handle_errors)
162{
163 int error_found;
164 u32 eapaddr, page;
165 u32 syndrome;
166
167 error_found = 0;
168
169
170 eapaddr = ((info->eapr >> 12) & 0x7FFF) << 13;
171
172 syndrome = (info->eapr >> 4) & 0xFF;
173
174
175
176 page = eapaddr >> PAGE_SHIFT;
177
178 if (info->eapr & BIT(0)) {
179 error_found = 1;
180
181 if (handle_errors)
182 edac_mc_handle_ce(mci, page, 0,
183 syndrome,
184 edac_mc_find_csrow_by_page(mci, page),
185 0, mci->ctl_name);
186 }
187
188 if (info->eapr & BIT(1)) {
189 error_found = 1;
190
191 if (handle_errors)
192
193 edac_mc_handle_ue(mci, page, 0,
194 edac_mc_find_csrow_by_page(mci, page),
195 mci->ctl_name);
196 }
197
198 return error_found;
199}
200
201static void r82600_check(struct mem_ctl_info *mci)
202{
203 struct r82600_error_info info;
204
205 debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
206 r82600_get_error_info(mci, &info);
207 r82600_process_error_info(mci, &info, 1);
208}
209
210static inline int ecc_enabled(u8 dramcr)
211{
212 return dramcr & BIT(5);
213}
214
215static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
216 u8 dramcr)
217{
218 struct csrow_info *csrow;
219 int index;
220 u8 drbar;
221 u32 row_high_limit, row_high_limit_last;
222 u32 reg_sdram, ecc_on, row_base;
223
224 ecc_on = ecc_enabled(dramcr);
225 reg_sdram = dramcr & BIT(4);
226 row_high_limit_last = 0;
227
228 for (index = 0; index < mci->nr_csrows; index++) {
229 csrow = &mci->csrows[index];
230
231
232 pci_read_config_byte(pdev, R82600_DRBA + index, &drbar);
233
234 debugf1("%s() Row=%d DRBA = %#0x\n", __func__, index, drbar);
235
236 row_high_limit = ((u32) drbar << 24);
237
238
239 debugf1("%s() Row=%d, Boundry Address=%#0x, Last = %#0x\n",
240 __func__, index, row_high_limit, row_high_limit_last);
241
242
243 if (row_high_limit == row_high_limit_last)
244 continue;
245
246 row_base = row_high_limit_last;
247
248 csrow->first_page = row_base >> PAGE_SHIFT;
249 csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1;
250 csrow->nr_pages = csrow->last_page - csrow->first_page + 1;
251
252
253 csrow->grain = 1 << 14;
254 csrow->mtype = reg_sdram ? MEM_RDDR : MEM_DDR;
255
256 csrow->dtype = DEV_UNKNOWN;
257
258
259 csrow->edac_mode = ecc_on ? EDAC_SECDED : EDAC_NONE;
260 row_high_limit_last = row_high_limit;
261 }
262}
263
264static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
265{
266 struct mem_ctl_info *mci;
267 u8 dramcr;
268 u32 eapr;
269 u32 scrub_disabled;
270 u32 sdram_refresh_rate;
271 struct r82600_error_info discard;
272
273 debugf0("%s()\n", __func__);
274 pci_read_config_byte(pdev, R82600_DRAMC, &dramcr);
275 pci_read_config_dword(pdev, R82600_EAP, &eapr);
276 scrub_disabled = eapr & BIT(31);
277 sdram_refresh_rate = dramcr & (BIT(0) | BIT(1));
278 debugf2("%s(): sdram refresh rate = %#0x\n", __func__,
279 sdram_refresh_rate);
280 debugf2("%s(): DRAMC register = %#0x\n", __func__, dramcr);
281 mci = edac_mc_alloc(0, R82600_NR_CSROWS, R82600_NR_CHANS, 0);
282
283 if (mci == NULL)
284 return -ENOMEM;
285
286 debugf0("%s(): mci = %p\n", __func__, mci);
287 mci->dev = &pdev->dev;
288 mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR;
289 mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
290
291
292
293
294
295
296
297
298 mci->edac_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
299
300 if (ecc_enabled(dramcr)) {
301 if (scrub_disabled)
302 debugf3("%s(): mci = %p - Scrubbing disabled! EAP: "
303 "%#0x\n", __func__, mci, eapr);
304 } else
305 mci->edac_cap = EDAC_FLAG_NONE;
306
307 mci->mod_name = EDAC_MOD_STR;
308 mci->mod_ver = R82600_REVISION;
309 mci->ctl_name = "R82600";
310 mci->dev_name = pci_name(pdev);
311 mci->edac_check = r82600_check;
312 mci->ctl_page_to_phys = NULL;
313 r82600_init_csrows(mci, pdev, dramcr);
314 r82600_get_error_info(mci, &discard);
315
316
317
318
319 if (edac_mc_add_mc(mci)) {
320 debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
321 goto fail;
322 }
323
324
325
326 if (disable_hardware_scrub) {
327 debugf3("%s(): Disabling Hardware Scrub (scrub on error)\n",
328 __func__);
329 pci_write_bits32(pdev, R82600_EAP, BIT(31), BIT(31));
330 }
331
332
333 r82600_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
334 if (!r82600_pci) {
335 printk(KERN_WARNING
336 "%s(): Unable to create PCI control\n",
337 __func__);
338 printk(KERN_WARNING
339 "%s(): PCI error report via EDAC not setup\n",
340 __func__);
341 }
342
343 debugf3("%s(): success\n", __func__);
344 return 0;
345
346fail:
347 edac_mc_free(mci);
348 return -ENODEV;
349}
350
351
352static int __devinit r82600_init_one(struct pci_dev *pdev,
353 const struct pci_device_id *ent)
354{
355 debugf0("%s()\n", __func__);
356
357
358 return r82600_probe1(pdev, ent->driver_data);
359}
360
361static void __devexit r82600_remove_one(struct pci_dev *pdev)
362{
363 struct mem_ctl_info *mci;
364
365 debugf0("%s()\n", __func__);
366
367 if (r82600_pci)
368 edac_pci_release_generic_ctl(r82600_pci);
369
370 if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
371 return;
372
373 edac_mc_free(mci);
374}
375
376static const struct pci_device_id r82600_pci_tbl[] __devinitdata = {
377 {
378 PCI_DEVICE(PCI_VENDOR_ID_RADISYS, R82600_BRIDGE_ID)
379 },
380 {
381 0,
382 }
383};
384
385MODULE_DEVICE_TABLE(pci, r82600_pci_tbl);
386
387static struct pci_driver r82600_driver = {
388 .name = EDAC_MOD_STR,
389 .probe = r82600_init_one,
390 .remove = __devexit_p(r82600_remove_one),
391 .id_table = r82600_pci_tbl,
392};
393
394static int __init r82600_init(void)
395{
396 return pci_register_driver(&r82600_driver);
397}
398
399static void __exit r82600_exit(void)
400{
401 pci_unregister_driver(&r82600_driver);
402}
403
404module_init(r82600_init);
405module_exit(r82600_exit);
406
407MODULE_LICENSE("GPL");
408MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD Ltd. "
409 "on behalf of EADS Astrium");
410MODULE_DESCRIPTION("MC support for Radisys 82600 memory controllers");
411
412module_param(disable_hardware_scrub, bool, 0644);
413MODULE_PARM_DESC(disable_hardware_scrub,
414 "If set, disable the chipset's automatic scrub for CEs");
415