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/edac.h>
23#include "edac_core.h"
24
25#define R82600_REVISION " Ver: 2.0.2"
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 bool 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->pdev);
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_error(HW_EVENT_ERR_CORRECTED, mci, 1,
183 page, 0, syndrome,
184 edac_mc_find_csrow_by_page(mci, page),
185 0, -1,
186 mci->ctl_name, "");
187 }
188
189 if (info->eapr & BIT(1)) {
190 error_found = 1;
191
192 if (handle_errors)
193
194 edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
195 page, 0, 0,
196 edac_mc_find_csrow_by_page(mci, page),
197 0, -1,
198 mci->ctl_name, "");
199 }
200
201 return error_found;
202}
203
204static void r82600_check(struct mem_ctl_info *mci)
205{
206 struct r82600_error_info info;
207
208 edac_dbg(1, "MC%d\n", mci->mc_idx);
209 r82600_get_error_info(mci, &info);
210 r82600_process_error_info(mci, &info, 1);
211}
212
213static inline int ecc_enabled(u8 dramcr)
214{
215 return dramcr & BIT(5);
216}
217
218static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
219 u8 dramcr)
220{
221 struct csrow_info *csrow;
222 struct dimm_info *dimm;
223 int index;
224 u8 drbar;
225 u32 row_high_limit, row_high_limit_last;
226 u32 reg_sdram, ecc_on, row_base;
227
228 ecc_on = ecc_enabled(dramcr);
229 reg_sdram = dramcr & BIT(4);
230 row_high_limit_last = 0;
231
232 for (index = 0; index < mci->nr_csrows; index++) {
233 csrow = mci->csrows[index];
234 dimm = csrow->channels[0]->dimm;
235
236
237 pci_read_config_byte(pdev, R82600_DRBA + index, &drbar);
238
239 edac_dbg(1, "Row=%d DRBA = %#0x\n", index, drbar);
240
241 row_high_limit = ((u32) drbar << 24);
242
243
244 edac_dbg(1, "Row=%d, Boundary Address=%#0x, Last = %#0x\n",
245 index, row_high_limit, row_high_limit_last);
246
247
248 if (row_high_limit == row_high_limit_last)
249 continue;
250
251 row_base = row_high_limit_last;
252
253 csrow->first_page = row_base >> PAGE_SHIFT;
254 csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1;
255
256 dimm->nr_pages = csrow->last_page - csrow->first_page + 1;
257
258
259 dimm->grain = 1 << 14;
260 dimm->mtype = reg_sdram ? MEM_RDDR : MEM_DDR;
261
262 dimm->dtype = DEV_UNKNOWN;
263
264
265 dimm->edac_mode = ecc_on ? EDAC_SECDED : EDAC_NONE;
266 row_high_limit_last = row_high_limit;
267 }
268}
269
270static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
271{
272 struct mem_ctl_info *mci;
273 struct edac_mc_layer layers[2];
274 u8 dramcr;
275 u32 eapr;
276 u32 scrub_disabled;
277 u32 sdram_refresh_rate;
278 struct r82600_error_info discard;
279
280 edac_dbg(0, "\n");
281 pci_read_config_byte(pdev, R82600_DRAMC, &dramcr);
282 pci_read_config_dword(pdev, R82600_EAP, &eapr);
283 scrub_disabled = eapr & BIT(31);
284 sdram_refresh_rate = dramcr & (BIT(0) | BIT(1));
285 edac_dbg(2, "sdram refresh rate = %#0x\n", sdram_refresh_rate);
286 edac_dbg(2, "DRAMC register = %#0x\n", dramcr);
287 layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
288 layers[0].size = R82600_NR_CSROWS;
289 layers[0].is_virt_csrow = true;
290 layers[1].type = EDAC_MC_LAYER_CHANNEL;
291 layers[1].size = R82600_NR_CHANS;
292 layers[1].is_virt_csrow = false;
293 mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, 0);
294 if (mci == NULL)
295 return -ENOMEM;
296
297 edac_dbg(0, "mci = %p\n", mci);
298 mci->pdev = &pdev->dev;
299 mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR;
300 mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
301
302
303
304
305
306
307
308
309 mci->edac_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
310
311 if (ecc_enabled(dramcr)) {
312 if (scrub_disabled)
313 edac_dbg(3, "mci = %p - Scrubbing disabled! EAP: %#0x\n",
314 mci, eapr);
315 } else
316 mci->edac_cap = EDAC_FLAG_NONE;
317
318 mci->mod_name = EDAC_MOD_STR;
319 mci->mod_ver = R82600_REVISION;
320 mci->ctl_name = "R82600";
321 mci->dev_name = pci_name(pdev);
322 mci->edac_check = r82600_check;
323 mci->ctl_page_to_phys = NULL;
324 r82600_init_csrows(mci, pdev, dramcr);
325 r82600_get_error_info(mci, &discard);
326
327
328
329
330 if (edac_mc_add_mc(mci)) {
331 edac_dbg(3, "failed edac_mc_add_mc()\n");
332 goto fail;
333 }
334
335
336
337 if (disable_hardware_scrub) {
338 edac_dbg(3, "Disabling Hardware Scrub (scrub on error)\n");
339 pci_write_bits32(pdev, R82600_EAP, BIT(31), BIT(31));
340 }
341
342
343 r82600_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
344 if (!r82600_pci) {
345 printk(KERN_WARNING
346 "%s(): Unable to create PCI control\n",
347 __func__);
348 printk(KERN_WARNING
349 "%s(): PCI error report via EDAC not setup\n",
350 __func__);
351 }
352
353 edac_dbg(3, "success\n");
354 return 0;
355
356fail:
357 edac_mc_free(mci);
358 return -ENODEV;
359}
360
361
362static int r82600_init_one(struct pci_dev *pdev,
363 const struct pci_device_id *ent)
364{
365 edac_dbg(0, "\n");
366
367
368 return r82600_probe1(pdev, ent->driver_data);
369}
370
371static void r82600_remove_one(struct pci_dev *pdev)
372{
373 struct mem_ctl_info *mci;
374
375 edac_dbg(0, "\n");
376
377 if (r82600_pci)
378 edac_pci_release_generic_ctl(r82600_pci);
379
380 if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
381 return;
382
383 edac_mc_free(mci);
384}
385
386static const struct pci_device_id r82600_pci_tbl[] = {
387 {
388 PCI_DEVICE(PCI_VENDOR_ID_RADISYS, R82600_BRIDGE_ID)
389 },
390 {
391 0,
392 }
393};
394
395MODULE_DEVICE_TABLE(pci, r82600_pci_tbl);
396
397static struct pci_driver r82600_driver = {
398 .name = EDAC_MOD_STR,
399 .probe = r82600_init_one,
400 .remove = r82600_remove_one,
401 .id_table = r82600_pci_tbl,
402};
403
404static int __init r82600_init(void)
405{
406
407 opstate_init();
408
409 return pci_register_driver(&r82600_driver);
410}
411
412static void __exit r82600_exit(void)
413{
414 pci_unregister_driver(&r82600_driver);
415}
416
417module_init(r82600_init);
418module_exit(r82600_exit);
419
420MODULE_LICENSE("GPL");
421MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD Ltd. "
422 "on behalf of EADS Astrium");
423MODULE_DESCRIPTION("MC support for Radisys 82600 memory controllers");
424
425module_param(disable_hardware_scrub, bool, 0644);
426MODULE_PARM_DESC(disable_hardware_scrub,
427 "If set, disable the chipset's automatic scrub for CEs");
428
429module_param(edac_op_state, int, 0444);
430MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
431