1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include <linux/module.h>
25#include <linux/init.h>
26
27#include <linux/pci.h>
28#include <linux/pci_ids.h>
29
30
31#include <linux/edac.h>
32#include "edac_core.h"
33
34#define I82443_REVISION "0.1"
35
36#define EDAC_MOD_STR "i82443bxgx_edac"
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59#define I82443BXGX_NR_CSROWS 8
60#define I82443BXGX_NR_CHANS 1
61#define I82443BXGX_NR_DIMMS 4
62
63
64#define I82443BXGX_NBXCFG 0x50
65
66#define I82443BXGX_NBXCFG_OFFSET_NON_ECCROW 24
67
68#define I82443BXGX_NBXCFG_OFFSET_DRAM_FREQ 12
69
70#define I82443BXGX_NBXCFG_OFFSET_DRAM_INTEGRITY 7
71#define I82443BXGX_NBXCFG_INTEGRITY_NONE 0x0
72#define I82443BXGX_NBXCFG_INTEGRITY_EC 0x1
73#define I82443BXGX_NBXCFG_INTEGRITY_ECC 0x2
74#define I82443BXGX_NBXCFG_INTEGRITY_SCRUB 0x3
75
76#define I82443BXGX_NBXCFG_OFFSET_ECC_DIAG_ENABLE 6
77
78
79#define I82443BXGX_EAP 0x80
80
81
82#define I82443BXGX_EAP_OFFSET_EAP 12
83#define I82443BXGX_EAP_OFFSET_MBE BIT(1)
84#define I82443BXGX_EAP_OFFSET_SBE BIT(0)
85
86#define I82443BXGX_ERRCMD 0x90
87
88#define I82443BXGX_ERRCMD_OFFSET_SERR_ON_MBE BIT(1)
89#define I82443BXGX_ERRCMD_OFFSET_SERR_ON_SBE BIT(0)
90
91#define I82443BXGX_ERRSTS 0x91
92
93#define I82443BXGX_ERRSTS_OFFSET_MBFRE 5
94#define I82443BXGX_ERRSTS_OFFSET_MEF BIT(4)
95#define I82443BXGX_ERRSTS_OFFSET_SBFRE 1
96#define I82443BXGX_ERRSTS_OFFSET_SEF BIT(0)
97
98#define I82443BXGX_DRAMC 0x57
99
100#define I82443BXGX_DRAMC_OFFSET_DT 3
101#define I82443BXGX_DRAMC_DRAM_IS_EDO 0
102#define I82443BXGX_DRAMC_DRAM_IS_SDRAM 1
103#define I82443BXGX_DRAMC_DRAM_IS_RSDRAM 2
104
105#define I82443BXGX_DRB 0x60
106
107
108
109
110struct i82443bxgx_edacmc_error_info {
111 u32 eap;
112};
113
114static struct edac_pci_ctl_info *i82443bxgx_pci;
115
116static struct pci_dev *mci_pdev;
117
118
119
120static int i82443bxgx_registered = 1;
121
122static void i82443bxgx_edacmc_get_error_info(struct mem_ctl_info *mci,
123 struct i82443bxgx_edacmc_error_info
124 *info)
125{
126 struct pci_dev *pdev;
127 pdev = to_pci_dev(mci->pdev);
128 pci_read_config_dword(pdev, I82443BXGX_EAP, &info->eap);
129 if (info->eap & I82443BXGX_EAP_OFFSET_SBE)
130
131 pci_write_bits32(pdev, I82443BXGX_EAP,
132 I82443BXGX_EAP_OFFSET_SBE,
133 I82443BXGX_EAP_OFFSET_SBE);
134
135 if (info->eap & I82443BXGX_EAP_OFFSET_MBE)
136
137 pci_write_bits32(pdev, I82443BXGX_EAP,
138 I82443BXGX_EAP_OFFSET_MBE,
139 I82443BXGX_EAP_OFFSET_MBE);
140}
141
142static int i82443bxgx_edacmc_process_error_info(struct mem_ctl_info *mci,
143 struct
144 i82443bxgx_edacmc_error_info
145 *info, int handle_errors)
146{
147 int error_found = 0;
148 u32 eapaddr, page, pageoffset;
149
150
151
152 eapaddr = (info->eap & 0xfffff000);
153 page = eapaddr >> PAGE_SHIFT;
154 pageoffset = eapaddr - (page << PAGE_SHIFT);
155
156 if (info->eap & I82443BXGX_EAP_OFFSET_SBE) {
157 error_found = 1;
158 if (handle_errors)
159 edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
160 page, pageoffset, 0,
161 edac_mc_find_csrow_by_page(mci, page),
162 0, -1, mci->ctl_name, "");
163 }
164
165 if (info->eap & I82443BXGX_EAP_OFFSET_MBE) {
166 error_found = 1;
167 if (handle_errors)
168 edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
169 page, pageoffset, 0,
170 edac_mc_find_csrow_by_page(mci, page),
171 0, -1, mci->ctl_name, "");
172 }
173
174 return error_found;
175}
176
177static void i82443bxgx_edacmc_check(struct mem_ctl_info *mci)
178{
179 struct i82443bxgx_edacmc_error_info info;
180
181 edac_dbg(1, "MC%d\n", mci->mc_idx);
182 i82443bxgx_edacmc_get_error_info(mci, &info);
183 i82443bxgx_edacmc_process_error_info(mci, &info, 1);
184}
185
186static void i82443bxgx_init_csrows(struct mem_ctl_info *mci,
187 struct pci_dev *pdev,
188 enum edac_type edac_mode,
189 enum mem_type mtype)
190{
191 struct csrow_info *csrow;
192 struct dimm_info *dimm;
193 int index;
194 u8 drbar, dramc;
195 u32 row_base, row_high_limit, row_high_limit_last;
196
197 pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc);
198 row_high_limit_last = 0;
199 for (index = 0; index < mci->nr_csrows; index++) {
200 csrow = mci->csrows[index];
201 dimm = csrow->channels[0]->dimm;
202
203 pci_read_config_byte(pdev, I82443BXGX_DRB + index, &drbar);
204 edac_dbg(1, "MC%d: Row=%d DRB = %#0x\n",
205 mci->mc_idx, index, drbar);
206 row_high_limit = ((u32) drbar << 23);
207
208 edac_dbg(1, "MC%d: Row=%d, Boundary Address=%#0x, Last = %#0x\n",
209 mci->mc_idx, index, row_high_limit,
210 row_high_limit_last);
211
212
213 if (row_high_limit_last && !row_high_limit)
214 row_high_limit = 1UL << 31;
215
216
217 if (row_high_limit == row_high_limit_last)
218 continue;
219 row_base = row_high_limit_last;
220 csrow->first_page = row_base >> PAGE_SHIFT;
221 csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1;
222 dimm->nr_pages = csrow->last_page - csrow->first_page + 1;
223
224 dimm->grain = 1 << 12;
225 dimm->mtype = mtype;
226
227 dimm->dtype = DEV_UNKNOWN;
228
229 dimm->edac_mode = edac_mode;
230 row_high_limit_last = row_high_limit;
231 }
232}
233
234static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
235{
236 struct mem_ctl_info *mci;
237 struct edac_mc_layer layers[2];
238 u8 dramc;
239 u32 nbxcfg, ecc_mode;
240 enum mem_type mtype;
241 enum edac_type edac_mode;
242
243 edac_dbg(0, "MC:\n");
244
245
246
247
248 if (pci_read_config_dword(pdev, I82443BXGX_NBXCFG, &nbxcfg))
249 return -EIO;
250
251 layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
252 layers[0].size = I82443BXGX_NR_CSROWS;
253 layers[0].is_virt_csrow = true;
254 layers[1].type = EDAC_MC_LAYER_CHANNEL;
255 layers[1].size = I82443BXGX_NR_CHANS;
256 layers[1].is_virt_csrow = false;
257 mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, 0);
258 if (mci == NULL)
259 return -ENOMEM;
260
261 edac_dbg(0, "MC: mci = %p\n", mci);
262 mci->pdev = &pdev->dev;
263 mci->mtype_cap = MEM_FLAG_EDO | MEM_FLAG_SDR | MEM_FLAG_RDR;
264 mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
265 pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc);
266 switch ((dramc >> I82443BXGX_DRAMC_OFFSET_DT) & (BIT(0) | BIT(1))) {
267 case I82443BXGX_DRAMC_DRAM_IS_EDO:
268 mtype = MEM_EDO;
269 break;
270 case I82443BXGX_DRAMC_DRAM_IS_SDRAM:
271 mtype = MEM_SDR;
272 break;
273 case I82443BXGX_DRAMC_DRAM_IS_RSDRAM:
274 mtype = MEM_RDR;
275 break;
276 default:
277 edac_dbg(0, "Unknown/reserved DRAM type value in DRAMC register!\n");
278 mtype = -MEM_UNKNOWN;
279 }
280
281 if ((mtype == MEM_SDR) || (mtype == MEM_RDR))
282 mci->edac_cap = mci->edac_ctl_cap;
283 else
284 mci->edac_cap = EDAC_FLAG_NONE;
285
286 mci->scrub_cap = SCRUB_FLAG_HW_SRC;
287 pci_read_config_dword(pdev, I82443BXGX_NBXCFG, &nbxcfg);
288 ecc_mode = ((nbxcfg >> I82443BXGX_NBXCFG_OFFSET_DRAM_INTEGRITY) &
289 (BIT(0) | BIT(1)));
290
291 mci->scrub_mode = (ecc_mode == I82443BXGX_NBXCFG_INTEGRITY_SCRUB)
292 ? SCRUB_HW_SRC : SCRUB_NONE;
293
294 switch (ecc_mode) {
295 case I82443BXGX_NBXCFG_INTEGRITY_NONE:
296 edac_mode = EDAC_NONE;
297 break;
298 case I82443BXGX_NBXCFG_INTEGRITY_EC:
299 edac_mode = EDAC_EC;
300 break;
301 case I82443BXGX_NBXCFG_INTEGRITY_ECC:
302 case I82443BXGX_NBXCFG_INTEGRITY_SCRUB:
303 edac_mode = EDAC_SECDED;
304 break;
305 default:
306 edac_dbg(0, "Unknown/reserved ECC state in NBXCFG register!\n");
307 edac_mode = EDAC_UNKNOWN;
308 break;
309 }
310
311 i82443bxgx_init_csrows(mci, pdev, edac_mode, mtype);
312
313
314
315
316 pci_write_bits32(pdev, I82443BXGX_EAP,
317 (I82443BXGX_EAP_OFFSET_SBE |
318 I82443BXGX_EAP_OFFSET_MBE),
319 (I82443BXGX_EAP_OFFSET_SBE |
320 I82443BXGX_EAP_OFFSET_MBE));
321
322 mci->mod_name = EDAC_MOD_STR;
323 mci->mod_ver = I82443_REVISION;
324 mci->ctl_name = "I82443BXGX";
325 mci->dev_name = pci_name(pdev);
326 mci->edac_check = i82443bxgx_edacmc_check;
327 mci->ctl_page_to_phys = NULL;
328
329 if (edac_mc_add_mc(mci)) {
330 edac_dbg(3, "failed edac_mc_add_mc()\n");
331 goto fail;
332 }
333
334
335 i82443bxgx_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
336 if (!i82443bxgx_pci) {
337 printk(KERN_WARNING
338 "%s(): Unable to create PCI control\n",
339 __func__);
340 printk(KERN_WARNING
341 "%s(): PCI error report via EDAC not setup\n",
342 __func__);
343 }
344
345 edac_dbg(3, "MC: success\n");
346 return 0;
347
348fail:
349 edac_mc_free(mci);
350 return -ENODEV;
351}
352
353EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_probe1);
354
355
356static int i82443bxgx_edacmc_init_one(struct pci_dev *pdev,
357 const struct pci_device_id *ent)
358{
359 int rc;
360
361 edac_dbg(0, "MC:\n");
362
363
364 rc = i82443bxgx_edacmc_probe1(pdev, ent->driver_data);
365
366 if (mci_pdev == NULL)
367 mci_pdev = pci_dev_get(pdev);
368
369 return rc;
370}
371
372static void i82443bxgx_edacmc_remove_one(struct pci_dev *pdev)
373{
374 struct mem_ctl_info *mci;
375
376 edac_dbg(0, "\n");
377
378 if (i82443bxgx_pci)
379 edac_pci_release_generic_ctl(i82443bxgx_pci);
380
381 if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
382 return;
383
384 edac_mc_free(mci);
385}
386
387EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_remove_one);
388
389static const struct pci_device_id i82443bxgx_pci_tbl[] = {
390 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0)},
391 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2)},
392 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_0)},
393 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_2)},
394 {0,}
395};
396
397MODULE_DEVICE_TABLE(pci, i82443bxgx_pci_tbl);
398
399static struct pci_driver i82443bxgx_edacmc_driver = {
400 .name = EDAC_MOD_STR,
401 .probe = i82443bxgx_edacmc_init_one,
402 .remove = i82443bxgx_edacmc_remove_one,
403 .id_table = i82443bxgx_pci_tbl,
404};
405
406static int __init i82443bxgx_edacmc_init(void)
407{
408 int pci_rc;
409
410 opstate_init();
411
412 pci_rc = pci_register_driver(&i82443bxgx_edacmc_driver);
413 if (pci_rc < 0)
414 goto fail0;
415
416 if (mci_pdev == NULL) {
417 const struct pci_device_id *id = &i82443bxgx_pci_tbl[0];
418 int i = 0;
419 i82443bxgx_registered = 0;
420
421 while (mci_pdev == NULL && id->vendor != 0) {
422 mci_pdev = pci_get_device(id->vendor,
423 id->device, NULL);
424 i++;
425 id = &i82443bxgx_pci_tbl[i];
426 }
427 if (!mci_pdev) {
428 edac_dbg(0, "i82443bxgx pci_get_device fail\n");
429 pci_rc = -ENODEV;
430 goto fail1;
431 }
432
433 pci_rc = i82443bxgx_edacmc_init_one(mci_pdev, i82443bxgx_pci_tbl);
434
435 if (pci_rc < 0) {
436 edac_dbg(0, "i82443bxgx init fail\n");
437 pci_rc = -ENODEV;
438 goto fail1;
439 }
440 }
441
442 return 0;
443
444fail1:
445 pci_unregister_driver(&i82443bxgx_edacmc_driver);
446
447fail0:
448 if (mci_pdev != NULL)
449 pci_dev_put(mci_pdev);
450
451 return pci_rc;
452}
453
454static void __exit i82443bxgx_edacmc_exit(void)
455{
456 pci_unregister_driver(&i82443bxgx_edacmc_driver);
457
458 if (!i82443bxgx_registered)
459 i82443bxgx_edacmc_remove_one(mci_pdev);
460
461 pci_dev_put(mci_pdev);
462}
463
464module_init(i82443bxgx_edacmc_init);
465module_exit(i82443bxgx_edacmc_exit);
466
467MODULE_LICENSE("GPL");
468MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD");
469MODULE_DESCRIPTION("EDAC MC support for Intel 82443BX/GX memory controllers");
470
471module_param(edac_op_state, int, 0444);
472MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
473