e7xxx_edac.c 14.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
/*
 * Intel e7xxx Memory Controller kernel module
 * (C) 2003 Linux Networx (http://lnxi.com)
 * This file may be distributed under the terms of the
 * GNU General Public License.
 *
 * See "enum e7xxx_chips" below for supported chipsets
 *
 * Written by Thayne Harbaugh
 * Based on work by Dan Hollis <goemon at anime dot net> and others.
 *	http://www.anime.net/~goemon/linux-ecc/
 *
 * Contributors:
14
15
16
 *	Eric Biederman (Linux Networx)
 *	Tom Zimmerman (Linux Networx)
 *	Jim Garlick (Lawrence Livermore National Labs)
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 *	Dave Peterson (Lawrence Livermore National Labs)
 *	That One Guy (Some other place)
 *	Wang Zhenyu (intel.com)
 *
 * $Id: edac_e7xxx.c,v 1.5.2.9 2005/10/05 00:43:44 dsp_llnl Exp $
 *
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
#include "edac_mc.h"

32
33
#define	E7XXX_REVISION " Ver: 2.0.1 " __DATE__
#define	EDAC_MOD_STR	"e7xxx_edac"
34

Dave Peterson's avatar
Dave Peterson committed
35
#define e7xxx_printk(level, fmt, arg...) \
36
	edac_printk(level, "e7xxx", fmt, ##arg)
Dave Peterson's avatar
Dave Peterson committed
37
38

#define e7xxx_mc_printk(mci, level, fmt, arg...) \
39
	edac_mc_chipset_printk(mci, level, "e7xxx", fmt, ##arg)
Dave Peterson's avatar
Dave Peterson committed
40

41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#ifndef PCI_DEVICE_ID_INTEL_7205_0
#define PCI_DEVICE_ID_INTEL_7205_0	0x255d
#endif				/* PCI_DEVICE_ID_INTEL_7205_0 */

#ifndef PCI_DEVICE_ID_INTEL_7205_1_ERR
#define PCI_DEVICE_ID_INTEL_7205_1_ERR	0x2551
#endif				/* PCI_DEVICE_ID_INTEL_7205_1_ERR */

#ifndef PCI_DEVICE_ID_INTEL_7500_0
#define PCI_DEVICE_ID_INTEL_7500_0	0x2540
#endif				/* PCI_DEVICE_ID_INTEL_7500_0 */

#ifndef PCI_DEVICE_ID_INTEL_7500_1_ERR
#define PCI_DEVICE_ID_INTEL_7500_1_ERR	0x2541
#endif				/* PCI_DEVICE_ID_INTEL_7500_1_ERR */

#ifndef PCI_DEVICE_ID_INTEL_7501_0
#define PCI_DEVICE_ID_INTEL_7501_0	0x254c
#endif				/* PCI_DEVICE_ID_INTEL_7501_0 */

#ifndef PCI_DEVICE_ID_INTEL_7501_1_ERR
#define PCI_DEVICE_ID_INTEL_7501_1_ERR	0x2541
#endif				/* PCI_DEVICE_ID_INTEL_7501_1_ERR */

#ifndef PCI_DEVICE_ID_INTEL_7505_0
#define PCI_DEVICE_ID_INTEL_7505_0	0x2550
#endif				/* PCI_DEVICE_ID_INTEL_7505_0 */

#ifndef PCI_DEVICE_ID_INTEL_7505_1_ERR
#define PCI_DEVICE_ID_INTEL_7505_1_ERR	0x2551
#endif				/* PCI_DEVICE_ID_INTEL_7505_1_ERR */

#define E7XXX_NR_CSROWS		8	/* number of csrows */
#define E7XXX_NR_DIMMS		8	/* FIXME - is this correct? */

/* E7XXX register addresses - device 0 function 0 */
#define E7XXX_DRB		0x60	/* DRAM row boundary register (8b) */
#define E7XXX_DRA		0x70	/* DRAM row attribute register (8b) */
					/*
					 * 31   Device width row 7 0=x8 1=x4
					 * 27   Device width row 6
					 * 23   Device width row 5
					 * 19   Device width row 4
					 * 15   Device width row 3
					 * 11   Device width row 2
					 *  7   Device width row 1
					 *  3   Device width row 0
					 */
#define E7XXX_DRC		0x7C	/* DRAM controller mode reg (32b) */
					/*
					 * 22    Number channels 0=1,1=2
					 * 19:18 DRB Granularity 32/64MB
					 */
#define E7XXX_TOLM		0xC4	/* DRAM top of low memory reg (16b) */
#define E7XXX_REMAPBASE		0xC6	/* DRAM remap base address reg (16b) */
#define E7XXX_REMAPLIMIT	0xC8	/* DRAM remap limit address reg (16b) */

/* E7XXX register addresses - device 0 function 1 */
#define E7XXX_DRAM_FERR		0x80	/* DRAM first error register (8b) */
#define E7XXX_DRAM_NERR		0x82	/* DRAM next error register (8b) */
#define E7XXX_DRAM_CELOG_ADD	0xA0	/* DRAM first correctable memory */
					/*     error address register (32b) */
					/*
					 * 31:28 Reserved
					 * 27:6  CE address (4k block 33:12)
					 *  5:0  Reserved
					 */
#define E7XXX_DRAM_UELOG_ADD	0xB0	/* DRAM first uncorrectable memory */
					/*     error address register (32b) */
					/*
					 * 31:28 Reserved
					 * 27:6  CE address (4k block 33:12)
					 *  5:0  Reserved
					 */
#define E7XXX_DRAM_CELOG_SYNDROME 0xD0	/* DRAM first correctable memory */
					/*     error syndrome register (16b) */

enum e7xxx_chips {
	E7500 = 0,
	E7501,
	E7505,
	E7205,
};

struct e7xxx_pvt {
	struct pci_dev *bridge_ck;
	u32 tolm;
	u32 remapbase;
	u32 remaplimit;
	const struct e7xxx_dev_info *dev_info;
};

struct e7xxx_dev_info {
	u16 err_dev;
	const char *ctl_name;
};

struct e7xxx_error_info {
	u8 dram_ferr;
	u8 dram_nerr;
	u32 dram_celog_add;
	u16 dram_celog_syndrome;
	u32 dram_uelog_add;
};

static const struct e7xxx_dev_info e7xxx_devs[] = {
	[E7500] = {
148
149
150
		.err_dev = PCI_DEVICE_ID_INTEL_7500_1_ERR,
		.ctl_name = "E7500"
	},
151
	[E7501] = {
152
153
154
		.err_dev = PCI_DEVICE_ID_INTEL_7501_1_ERR,
		.ctl_name = "E7501"
	},
155
	[E7505] = {
156
157
158
		.err_dev = PCI_DEVICE_ID_INTEL_7505_1_ERR,
		.ctl_name = "E7505"
	},
159
	[E7205] = {
160
161
162
		.err_dev = PCI_DEVICE_ID_INTEL_7205_1_ERR,
		.ctl_name = "E7205"
	},
163
164
165
166
167
};

/* FIXME - is this valid for both SECDED and S4ECD4ED? */
static inline int e7xxx_find_channel(u16 syndrome)
{
Dave Peterson's avatar
Dave Peterson committed
168
	debugf3("%s()\n", __func__);
169
170
171

	if ((syndrome & 0xff00) == 0)
		return 0;
172

173
174
	if ((syndrome & 0x00ff) == 0)
		return 1;
175

176
177
	if ((syndrome & 0xf000) == 0 || (syndrome & 0x0f00) == 0)
		return 0;
178

179
180
181
	return 1;
}

182
183
static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
		unsigned long page)
184
185
186
187
{
	u32 remap;
	struct e7xxx_pvt *pvt = (struct e7xxx_pvt *) mci->pvt_info;

Dave Peterson's avatar
Dave Peterson committed
188
	debugf3("%s()\n", __func__);
189
190

	if ((page < pvt->tolm) ||
191
			((page >= 0x100000) && (page < pvt->remapbase)))
192
		return page;
193

194
	remap = (page - pvt->tolm) + pvt->remapbase;
195

196
197
	if (remap < pvt->remaplimit)
		return remap;
198

Dave Peterson's avatar
Dave Peterson committed
199
	e7xxx_printk(KERN_ERR, "Invalid page %lx - out of range\n", page);
200
201
202
	return pvt->tolm - 1;
}

203
204
static void process_ce(struct mem_ctl_info *mci,
		struct e7xxx_error_info *info)
205
206
207
208
209
210
{
	u32 error_1b, page;
	u16 syndrome;
	int row;
	int channel;

Dave Peterson's avatar
Dave Peterson committed
211
	debugf3("%s()\n", __func__);
212
213
214
	/* read the error address */
	error_1b = info->dram_celog_add;
	/* FIXME - should use PAGE_SHIFT */
215
	page = error_1b >> 6;  /* convert the address to 4k page */
216
217
218
219
220
221
	/* read the syndrome */
	syndrome = info->dram_celog_syndrome;
	/* FIXME - check for -1 */
	row = edac_mc_find_csrow_by_page(mci, page);
	/* convert syndrome to channel */
	channel = e7xxx_find_channel(syndrome);
222
	edac_mc_handle_ce(mci, page, 0, syndrome, row, channel, "e7xxx CE");
223
224
225
226
}

static void process_ce_no_info(struct mem_ctl_info *mci)
{
Dave Peterson's avatar
Dave Peterson committed
227
	debugf3("%s()\n", __func__);
228
229
230
	edac_mc_handle_ce_no_info(mci, "e7xxx CE log register overflow");
}

231
232
static void process_ue(struct mem_ctl_info *mci,
		struct e7xxx_error_info *info)
233
234
235
236
{
	u32 error_2b, block_page;
	int row;

Dave Peterson's avatar
Dave Peterson committed
237
	debugf3("%s()\n", __func__);
238
239
240
	/* read the error address */
	error_2b = info->dram_uelog_add;
	/* FIXME - should use PAGE_SHIFT */
241
	block_page = error_2b >> 6;  /* convert to 4k address */
242
243
244
245
246
247
	row = edac_mc_find_csrow_by_page(mci, block_page);
	edac_mc_handle_ue(mci, block_page, 0, row, "e7xxx UE");
}

static void process_ue_no_info(struct mem_ctl_info *mci)
{
Dave Peterson's avatar
Dave Peterson committed
248
	debugf3("%s()\n", __func__);
249
250
251
252
253
254
255
256
257
258
	edac_mc_handle_ue_no_info(mci, "e7xxx UE log register overflow");
}

static void e7xxx_get_error_info (struct mem_ctl_info *mci,
		struct e7xxx_error_info *info)
{
	struct e7xxx_pvt *pvt;

	pvt = (struct e7xxx_pvt *) mci->pvt_info;
	pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_FERR,
259
			&info->dram_ferr);
260
	pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_NERR,
261
			&info->dram_nerr);
262
263
264

	if ((info->dram_ferr & 1) || (info->dram_nerr & 1)) {
		pci_read_config_dword(pvt->bridge_ck, E7XXX_DRAM_CELOG_ADD,
265
				&info->dram_celog_add);
266
		pci_read_config_word(pvt->bridge_ck,
267
268
				E7XXX_DRAM_CELOG_SYNDROME,
				&info->dram_celog_syndrome);
269
270
271
272
	}

	if ((info->dram_ferr & 2) || (info->dram_nerr & 2))
		pci_read_config_dword(pvt->bridge_ck, E7XXX_DRAM_UELOG_ADD,
273
				&info->dram_uelog_add);
274
275

	if (info->dram_ferr & 3)
276
		pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_FERR, 0x03, 0x03);
277
278

	if (info->dram_nerr & 3)
279
		pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_NERR, 0x03, 0x03);
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
}

static int e7xxx_process_error_info (struct mem_ctl_info *mci,
		struct e7xxx_error_info *info, int handle_errors)
{
	int error_found;

	error_found = 0;

	/* decode and report errors */
	if (info->dram_ferr & 1) {	/* check first error correctable */
		error_found = 1;

		if (handle_errors)
			process_ce(mci, info);
	}

	if (info->dram_ferr & 2) {	/* check first error uncorrectable */
		error_found = 1;

		if (handle_errors)
			process_ue(mci, info);
	}

	if (info->dram_nerr & 1) {	/* check next error correctable */
		error_found = 1;

		if (handle_errors) {
			if (info->dram_ferr & 1)
				process_ce_no_info(mci);
			else
				process_ce(mci, info);
		}
	}

	if (info->dram_nerr & 2) {	/* check next error uncorrectable */
		error_found = 1;

		if (handle_errors) {
			if (info->dram_ferr & 2)
				process_ue_no_info(mci);
			else
				process_ue(mci, info);
		}
	}

	return error_found;
}

static void e7xxx_check(struct mem_ctl_info *mci)
{
	struct e7xxx_error_info info;

Dave Peterson's avatar
Dave Peterson committed
333
	debugf3("%s()\n", __func__);
334
335
336
337
	e7xxx_get_error_info(mci, &info);
	e7xxx_process_error_info(mci, &info, 1);
}

338
339
/* Return 1 if dual channel mode is active.  Else return 0. */
static inline int dual_channel_active(u32 drc, int dev_idx)
340
{
341
342
	return (dev_idx == E7501) ? ((drc >> 22) & 0x1) : 1;
}
343

344

345
346
347
/* Return DRB granularity (0=32mb, 1=64mb). */
static inline int drb_granularity(u32 drc, int dev_idx)
{
348
	/* only e7501 can be single channel */
349
350
	return (dev_idx == E7501) ? ((drc >> 18) & 0x3) : 1;
}
351

352

353
354
355
356
357
358
359
360
361
static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
		int dev_idx, u32 drc)
{
	unsigned long last_cumul_size;
	int index;
	u8 value;
	u32 dra, cumul_size;
	int drc_chan, drc_drbg, drc_ddim, mem_dev;
	struct csrow_info *csrow;
362
363

	pci_read_config_dword(pdev, E7XXX_DRA, &dra);
364
365
366
367
	drc_chan = dual_channel_active(drc, dev_idx);
	drc_drbg = drb_granularity(drc, dev_idx);
	drc_ddim = (drc >> 20) & 0x3;
	last_cumul_size = 0;
368

369
	/* The dram row boundary (DRB) reg values are boundary address
370
371
372
373
	 * for each DRAM row with a granularity of 32 or 64MB (single/dual
	 * channel operation).  DRB regs are cumulative; therefore DRB7 will
	 * contain the total memory contained in all eight rows.
	 */
374
	for (index = 0; index < mci->nr_csrows; index++) {
375
		/* mem_dev 0=x8, 1=x4 */
376
377
		mem_dev = (dra >> (index * 4 + 3)) & 0x1;
		csrow = &mci->csrows[index];
378

379
		pci_read_config_byte(pdev, E7XXX_DRB + index, &value);
380
381
		/* convert a 64 or 32 MiB DRB to a page size. */
		cumul_size = value << (25 + drc_drbg - PAGE_SHIFT);
Dave Peterson's avatar
Dave Peterson committed
382
383
		debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
			cumul_size);
384
		if (cumul_size == last_cumul_size)
385
			continue;	/* not populated */
386
387
388
389
390

		csrow->first_page = last_cumul_size;
		csrow->last_page = cumul_size - 1;
		csrow->nr_pages = cumul_size - last_cumul_size;
		last_cumul_size = cumul_size;
391
392
		csrow->grain = 1 << 12;	/* 4KiB - resolution of CELOG */
		csrow->mtype = MEM_RDDR;	/* only one type supported */
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
		csrow->dtype = mem_dev ? DEV_X4 : DEV_X8;

		/*
		 * if single channel or x8 devices then SECDED
		 * if dual channel and x4 then S4ECD4ED
		 */
		if (drc_ddim) {
			if (drc_chan && mem_dev) {
				csrow->edac_mode = EDAC_S4ECD4ED;
				mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
			} else {
				csrow->edac_mode = EDAC_SECDED;
				mci->edac_cap |= EDAC_FLAG_SECDED;
			}
		} else
			csrow->edac_mode = EDAC_NONE;
	}
410
}
411

412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
{
	u16 pci_data;
	struct mem_ctl_info *mci = NULL;
	struct e7xxx_pvt *pvt = NULL;
	u32 drc;
	int drc_chan;
	struct e7xxx_error_info discard;

	debugf0("%s(): mci\n", __func__);
	pci_read_config_dword(pdev, E7XXX_DRC, &drc);

	drc_chan = dual_channel_active(drc, dev_idx);
	mci = edac_mc_alloc(sizeof(*pvt), E7XXX_NR_CSROWS, drc_chan + 1);

	if (mci == NULL)
		return -ENOMEM;
429

430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
	debugf3("%s(): init mci\n", __func__);
	mci->mtype_cap = MEM_FLAG_RDDR;
	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED |
			EDAC_FLAG_S4ECD4ED;
	/* FIXME - what if different memory types are in different csrows? */
	mci->mod_name = EDAC_MOD_STR;
	mci->mod_ver = E7XXX_REVISION;
	mci->dev = &pdev->dev;
	debugf3("%s(): init pvt\n", __func__);
	pvt = (struct e7xxx_pvt *) mci->pvt_info;
	pvt->dev_info = &e7xxx_devs[dev_idx];
	pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL,
					pvt->dev_info->err_dev,
					pvt->bridge_ck);

	if (!pvt->bridge_ck) {
		e7xxx_printk(KERN_ERR, "error reporting device not found:"
			"vendor %x device 0x%x (broken BIOS?)\n",
			PCI_VENDOR_ID_INTEL, e7xxx_devs[dev_idx].err_dev);
		goto fail0;
	}

	debugf3("%s(): more mci init\n", __func__);
	mci->ctl_name = pvt->dev_info->ctl_name;
	mci->edac_check = e7xxx_check;
	mci->ctl_page_to_phys = ctl_page_to_phys;
	e7xxx_init_csrows(mci, pdev, dev_idx, drc);
	mci->edac_cap |= EDAC_FLAG_NONE;
Dave Peterson's avatar
Dave Peterson committed
458
	debugf3("%s(): tolm, remapbase, remaplimit\n", __func__);
459
	/* load the top of low memory, remap base, and remap limit vars */
460
	pci_read_config_word(pdev, E7XXX_TOLM, &pci_data);
461
	pvt->tolm = ((u32) pci_data) << 4;
462
	pci_read_config_word(pdev, E7XXX_REMAPBASE, &pci_data);
463
	pvt->remapbase = ((u32) pci_data) << 14;
464
	pci_read_config_word(pdev, E7XXX_REMAPLIMIT, &pci_data);
465
	pvt->remaplimit = ((u32) pci_data) << 14;
Dave Peterson's avatar
Dave Peterson committed
466
	e7xxx_printk(KERN_INFO,
467
468
		"tolm = %x, remapbase = %x, remaplimit = %x\n", pvt->tolm,
		pvt->remapbase, pvt->remaplimit);
469
470

	/* clear any pending errors, or initial state bits */
471
	e7xxx_get_error_info(mci, &discard);
472

473
474
475
476
	/* Here we assume that we will never see multiple instances of this
	 * type of memory controller.  The ID is therefore hardcoded to 0.
	 */
	if (edac_mc_add_mc(mci,0)) {
Dave Peterson's avatar
Dave Peterson committed
477
		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
478
		goto fail1;
479
480
481
	}

	/* get this far and it's successful */
Dave Peterson's avatar
Dave Peterson committed
482
	debugf3("%s(): success\n", __func__);
483
484
	return 0;

485
486
487
488
489
fail1:
	pci_dev_put(pvt->bridge_ck);

fail0:
	edac_mc_free(mci);
490

491
	return -ENODEV;
492
493
494
}

/* returns count (>= 0), or negative on error */
495
496
static int __devinit e7xxx_init_one(struct pci_dev *pdev,
		const struct pci_device_id *ent)
497
{
Dave Peterson's avatar
Dave Peterson committed
498
	debugf0("%s()\n", __func__);
499
500
501

	/* wake up and enable device */
	return pci_enable_device(pdev) ?
502
		-EIO : e7xxx_probe1(pdev, ent->driver_data);
503
504
505
506
507
508
509
}

static void __devexit e7xxx_remove_one(struct pci_dev *pdev)
{
	struct mem_ctl_info *mci;
	struct e7xxx_pvt *pvt;

Dave Peterson's avatar
Dave Peterson committed
510
	debugf0("%s()\n", __func__);
511

512
	if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
513
514
515
516
517
		return;

	pvt = (struct e7xxx_pvt *) mci->pvt_info;
	pci_dev_put(pvt->bridge_ck);
	edac_mc_free(mci);
518
519
520
}

static const struct pci_device_id e7xxx_pci_tbl[] __devinitdata = {
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
	{
		PCI_VEND_DEV(INTEL, 7205_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
		E7205
	},
	{
		PCI_VEND_DEV(INTEL, 7500_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
		E7500
	},
	{
		PCI_VEND_DEV(INTEL, 7501_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
		E7501
	},
	{
		PCI_VEND_DEV(INTEL, 7505_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
		E7505
	},
	{
		0,
	}	/* 0 terminated list. */
540
541
542
543
544
};

MODULE_DEVICE_TABLE(pci, e7xxx_pci_tbl);

static struct pci_driver e7xxx_driver = {
Dave Peterson's avatar
Dave Peterson committed
545
	.name = EDAC_MOD_STR,
546
547
548
549
550
	.probe = e7xxx_init_one,
	.remove = __devexit_p(e7xxx_remove_one),
	.id_table = e7xxx_pci_tbl,
};

551
static int __init e7xxx_init(void)
552
553
554
555
556
557
558
559
560
561
562
563
564
565
{
	return pci_register_driver(&e7xxx_driver);
}

static void __exit e7xxx_exit(void)
{
	pci_unregister_driver(&e7xxx_driver);
}

module_init(e7xxx_init);
module_exit(e7xxx_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al\n"
566
	"Based on.work by Dan Hollis et al");
567
MODULE_DESCRIPTION("MC support for Intel e7xxx memory controllers");