r82600_edac.c 11 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*
 * Radisys 82600 Embedded chipset Memory Controller kernel module
 * (C) 2005 EADS Astrium
 * This file may be distributed under the terms of the
 * GNU General Public License.
 *
 * Written by Tim Small <tim@buttersideup.com>, based on work by Thayne
 * Harbaugh, Dan Hollis <goemon at anime dot net> and others.
 *
 * $Id: edac_r82600.c,v 1.1.2.6 2005/10/05 00:43:44 dsp_llnl Exp $
 *
 * Written with reference to 82600 High Integration Dual PCI System
 * Controller Data Book:
 * http://www.radisys.com/files/support_downloads/007-01277-0002.82600DataBook.pdf
 * references to this document given in []
 */

#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"

25
26
#define R82600_REVISION	" Ver: 2.0.1 " __DATE__
#define EDAC_MOD_STR	"r82600_edac"
27

Dave Peterson's avatar
Dave Peterson committed
28
#define r82600_printk(level, fmt, arg...) \
29
	edac_printk(level, "r82600", fmt, ##arg)
Dave Peterson's avatar
Dave Peterson committed
30
31

#define r82600_mc_printk(mci, level, fmt, arg...) \
32
	edac_mc_chipset_printk(mci, level, "r82600", fmt, ##arg)
Dave Peterson's avatar
Dave Peterson committed
33

34
35
36
37
38
39
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
/* Radisys say "The 82600 integrates a main memory SDRAM controller that
 * supports up to four banks of memory. The four banks can support a mix of
 * sizes of 64 bit wide (72 bits with ECC) Synchronous DRAM (SDRAM) DIMMs,
 * each of which can be any size from 16MB to 512MB. Both registered (control
 * signals buffered) and unbuffered DIMM types are supported. Mixing of
 * registered and unbuffered DIMMs as well as mixing of ECC and non-ECC DIMMs
 * is not allowed. The 82600 SDRAM interface operates at the same frequency as
 * the CPU bus, 66MHz, 100MHz or 133MHz."
 */

#define R82600_NR_CSROWS 4
#define R82600_NR_CHANS  1
#define R82600_NR_DIMMS  4

#define R82600_BRIDGE_ID  0x8200

/* Radisys 82600 register addresses - device 0 function 0 - PCI bridge */
#define R82600_DRAMC	0x57	/* Various SDRAM related control bits
				 * all bits are R/W
				 *
				 * 7    SDRAM ISA Hole Enable
				 * 6    Flash Page Mode Enable
				 * 5    ECC Enable: 1=ECC 0=noECC
				 * 4    DRAM DIMM Type: 1=
				 * 3    BIOS Alias Disable
				 * 2    SDRAM BIOS Flash Write Enable
				 * 1:0  SDRAM Refresh Rate: 00=Disabled
				 *          01=7.8usec (256Mbit SDRAMs)
				 *          10=15.6us 11=125usec
				 */

#define R82600_SDRAMC	0x76	/* "SDRAM Control Register"
				 * More SDRAM related control bits
				 * all bits are R/W
				 *
				 * 15:8 Reserved.
				 *
				 * 7:5  Special SDRAM Mode Select
				 *
				 * 4    Force ECC
				 *
				 *        1=Drive ECC bits to 0 during
				 *          write cycles (i.e. ECC test mode)
				 *
				 *        0=Normal ECC functioning
				 *
				 * 3    Enhanced Paging Enable
				 *
				 * 2    CAS# Latency 0=3clks 1=2clks
				 *
				 * 1    RAS# to CAS# Delay 0=3 1=2
				 *
				 * 0    RAS# Precharge     0=3 1=2
				 */

#define R82600_EAP	0x80	/* ECC Error Address Pointer Register
				 *
				 * 31    Disable Hardware Scrubbing (RW)
				 *        0=Scrub on corrected read
				 *        1=Don't scrub on corrected read
				 *
				 * 30:12 Error Address Pointer (RO)
				 *        Upper 19 bits of error address
				 *
				 * 11:4  Syndrome Bits (RO)
				 *
				 * 3     BSERR# on multibit error (RW)
				 *        1=enable 0=disable
				 *
				 * 2     NMI on Single Bit Eror (RW)
				 *        1=NMI triggered by SBE n.b. other
				 *          prerequeists
				 *        0=NMI not triggered
				 *
				 * 1     MBE (R/WC)
				 *        read 1=MBE at EAP (see above)
				 *        read 0=no MBE, or SBE occurred first
				 *        write 1=Clear MBE status (must also
				 *          clear SBE)
				 *        write 0=NOP
				 *
				 * 1     SBE (R/WC)
				 *        read 1=SBE at EAP (see above)
				 *        read 0=no SBE, or MBE occurred first
				 *        write 1=Clear SBE status (must also
				 *          clear MBE)
				 *        write 0=NOP
				 */

#define R82600_DRBA	0x60	/* + 0x60..0x63 SDRAM Row Boundry Address
				 *  Registers
				 *
				 * 7:0  Address lines 30:24 - upper limit of
				 * each row [p57]
				 */

struct r82600_error_info {
	u32 eapr;
};

static unsigned int disable_hardware_scrub = 0;

static void r82600_get_error_info (struct mem_ctl_info *mci,
		struct r82600_error_info *info)
{
139
140
141
142
	struct pci_dev *pdev;

	pdev = to_pci_dev(mci->dev);
	pci_read_config_dword(pdev, R82600_EAP, &info->eapr);
143
144
145

	if (info->eapr & BIT(0))
		/* Clear error to allow next error to be reported [p.62] */
146
		pci_write_bits32(pdev, R82600_EAP,
147
148
				((u32) BIT(0) & (u32) BIT(1)),
				((u32) BIT(0) & (u32) BIT(1)));
149
150
151

	if (info->eapr & BIT(1))
		/* Clear error to allow next error to be reported [p.62] */
152
		pci_write_bits32(pdev, R82600_EAP,
153
154
				((u32) BIT(0) & (u32) BIT(1)),
				((u32) BIT(0) & (u32) BIT(1)));
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
}

static int r82600_process_error_info (struct mem_ctl_info *mci,
		struct r82600_error_info *info, int handle_errors)
{
	int error_found;
	u32 eapaddr, page;
	u32 syndrome;

	error_found = 0;

	/* bits 30:12 store the upper 19 bits of the 32 bit error address */
	eapaddr = ((info->eapr >> 12) & 0x7FFF) << 13;
	/* Syndrome in bits 11:4 [p.62]       */
	syndrome = (info->eapr >> 4) & 0xFF;

	/* the R82600 reports at less than page *
	 * granularity (upper 19 bits only)     */
	page = eapaddr >> PAGE_SHIFT;

175
	if (info->eapr & BIT(0)) {  /* CE? */
176
177
178
		error_found = 1;

		if (handle_errors)
179
180
181
182
183
			edac_mc_handle_ce(mci, page, 0,  /* not avail */
					syndrome,
					edac_mc_find_csrow_by_page(mci, page),
					0,  /* channel */
					mci->ctl_name);
184
185
	}

186
	if (info->eapr & BIT(1)) {  /* UE? */
187
188
189
190
191
		error_found = 1;

		if (handle_errors)
			/* 82600 doesn't give enough info */
			edac_mc_handle_ue(mci, page, 0,
192
193
				edac_mc_find_csrow_by_page(mci, page),
				mci->ctl_name);
194
195
196
197
198
199
200
201
202
	}

	return error_found;
}

static void r82600_check(struct mem_ctl_info *mci)
{
	struct r82600_error_info info;

Dave Peterson's avatar
Dave Peterson committed
203
	debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
204
205
206
207
	r82600_get_error_info(mci, &info);
	r82600_process_error_info(mci, &info, 1);
}

208
static inline int ecc_enabled(u8 dramcr)
209
{
210
211
212
213
214
215
216
	return dramcr & BIT(5);
}

static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
		u8 dramcr)
{
	struct csrow_info *csrow;
217
	int index;
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
	u8 drbar;  /* SDRAM Row Boundry Address Register */
	u32 row_high_limit, row_high_limit_last;
	u32 reg_sdram, ecc_on, row_base;

	ecc_on = ecc_enabled(dramcr);
	reg_sdram = dramcr & BIT(4);
	row_high_limit_last = 0;

	for (index = 0; index < mci->nr_csrows; index++) {
		csrow = &mci->csrows[index];

		/* find the DRAM Chip Select Base address and mask */
		pci_read_config_byte(pdev, R82600_DRBA + index, &drbar);

		debugf1("%s() Row=%d DRBA = %#0x\n", __func__, index, drbar);

		row_high_limit = ((u32) drbar << 24);
/*		row_high_limit = ((u32)drbar << 24) | 0xffffffUL; */

		debugf1("%s() Row=%d, Boundry Address=%#0x, Last = %#0x\n",
			__func__, index, row_high_limit, row_high_limit_last);

		/* Empty row [p.57] */
		if (row_high_limit == row_high_limit_last)
			continue;

		row_base = row_high_limit_last;

		csrow->first_page = row_base >> PAGE_SHIFT;
		csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1;
		csrow->nr_pages = csrow->last_page - csrow->first_page + 1;
		/* Error address is top 19 bits - so granularity is      *
		 * 14 bits                                               */
		csrow->grain = 1 << 14;
		csrow->mtype = reg_sdram ? MEM_RDDR : MEM_DDR;
		/* FIXME - check that this is unknowable with this chipset */
		csrow->dtype = DEV_UNKNOWN;

		/* Mode is global on 82600 */
		csrow->edac_mode = ecc_on ? EDAC_SECDED : EDAC_NONE;
		row_high_limit_last = row_high_limit;
	}
}

static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
{
	struct mem_ctl_info *mci;
265
266
267
268
	u8 dramcr;
	u32 eapr;
	u32 scrub_disabled;
	u32 sdram_refresh_rate;
269
	struct r82600_error_info discard;
270

Dave Peterson's avatar
Dave Peterson committed
271
	debugf0("%s()\n", __func__);
272
273
274
275
	pci_read_config_byte(pdev, R82600_DRAMC, &dramcr);
	pci_read_config_dword(pdev, R82600_EAP, &eapr);
	scrub_disabled = eapr & BIT(31);
	sdram_refresh_rate = dramcr & (BIT(0) | BIT(1));
Dave Peterson's avatar
Dave Peterson committed
276
277
278
	debugf2("%s(): sdram refresh rate = %#0x\n", __func__,
		sdram_refresh_rate);
	debugf2("%s(): DRAMC register = %#0x\n", __func__, dramcr);
279
280
	mci = edac_mc_alloc(0, R82600_NR_CSROWS, R82600_NR_CHANS);

281
282
	if (mci == NULL)
		return -ENOMEM;
283

Dave Peterson's avatar
Dave Peterson committed
284
	debugf0("%s(): mci = %p\n", __func__, mci);
285
	mci->dev = &pdev->dev;
286
287
	mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR;
	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
288
289
290
	/* FIXME try to work out if the chip leads have been used for COM2
	 * instead on this board? [MA6?] MAYBE:
	 */
291
292
293
294
295
296

	/* On the R82600, the pins for memory bits 72:65 - i.e. the   *
	 * EC bits are shared with the pins for COM2 (!), so if COM2  *
	 * is enabled, we assume COM2 is wired up, and thus no EDAC   *
	 * is possible.                                               */
	mci->edac_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
297

298
	if (ecc_enabled(dramcr)) {
299
		if (scrub_disabled)
Dave Peterson's avatar
Dave Peterson committed
300
301
			debugf3("%s(): mci = %p - Scrubbing disabled! EAP: "
				"%#0x\n", __func__, mci, eapr);
302
303
304
	} else
		mci->edac_cap = EDAC_FLAG_NONE;

Dave Peterson's avatar
Dave Peterson committed
305
	mci->mod_name = EDAC_MOD_STR;
306
	mci->mod_ver = R82600_REVISION;
307
308
309
	mci->ctl_name = "R82600";
	mci->edac_check = r82600_check;
	mci->ctl_page_to_phys = NULL;
310
	r82600_init_csrows(mci, pdev, dramcr);
311
	r82600_get_error_info(mci, &discard);  /* clear counters */
312

313
314
315
316
	/* 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
317
		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
318
319
320
321
322
323
		goto fail;
	}

	/* get this far and it's successful */

	if (disable_hardware_scrub) {
Dave Peterson's avatar
Dave Peterson committed
324
325
		debugf3("%s(): Disabling Hardware Scrub (scrub on error)\n",
			__func__);
326
		pci_write_bits32(pdev, R82600_EAP, BIT(31), BIT(31));
327
328
	}

Dave Peterson's avatar
Dave Peterson committed
329
	debugf3("%s(): success\n", __func__);
330
331
332
	return 0;

fail:
333
334
	edac_mc_free(mci);
	return -ENODEV;
335
336
337
338
}

/* returns count (>= 0), or negative on error */
static int __devinit r82600_init_one(struct pci_dev *pdev,
339
		const struct pci_device_id *ent)
340
{
Dave Peterson's avatar
Dave Peterson committed
341
	debugf0("%s()\n", __func__);
342
343
344
345
346
347
348
349
350

	/* don't need to call pci_device_enable() */
	return r82600_probe1(pdev, ent->driver_data);
}

static void __devexit r82600_remove_one(struct pci_dev *pdev)
{
	struct mem_ctl_info *mci;

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

353
	if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
354
355
356
		return;

	edac_mc_free(mci);
357
358
359
}

static const struct pci_device_id r82600_pci_tbl[] __devinitdata = {
360
361
362
363
364
365
	{
		PCI_DEVICE(PCI_VENDOR_ID_RADISYS, R82600_BRIDGE_ID)
	},
	{
		0,
	}	/* 0 terminated list. */
366
367
368
369
370
};

MODULE_DEVICE_TABLE(pci, r82600_pci_tbl);

static struct pci_driver r82600_driver = {
Dave Peterson's avatar
Dave Peterson committed
371
	.name = EDAC_MOD_STR,
372
373
374
375
376
	.probe = r82600_init_one,
	.remove = __devexit_p(r82600_remove_one),
	.id_table = r82600_pci_tbl,
};

377
static int __init r82600_init(void)
378
379
380
381
382
383
384
385
386
387
388
389
390
391
{
	return pci_register_driver(&r82600_driver);
}

static void __exit r82600_exit(void)
{
	pci_unregister_driver(&r82600_driver);
}

module_init(r82600_init);
module_exit(r82600_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD Ltd. "
392
	"on behalf of EADS Astrium");
393
394
395
396
397
MODULE_DESCRIPTION("MC support for Radisys 82600 memory controllers");

module_param(disable_hardware_scrub, bool, 0644);
MODULE_PARM_DESC(disable_hardware_scrub,
		 "If set, disable the chipset's automatic scrub for CEs");