1 diff -urN Linux/drivers/char/Config.in linux/drivers/char/Config.in
2 --- Linux/drivers/char/Config.in Tue May 21 11:16:05 2002
3 +++ linux/drivers/char/Config.in Tue May 21 11:18:53 2002
5 comment 'Character devices'
7 bool 'Virtual terminal' CONFIG_VT
8 +tristate ' ECC memory monitoring' CONFIG_ECC
9 if [ "$CONFIG_VT" = "y" ]; then
10 bool ' Support for console on virtual terminal' CONFIG_VT_CONSOLE
12 diff -urN Linux/drivers/char/Makefile linux/drivers/char/Makefile
13 --- Linux/drivers/char/Makefile Tue May 21 11:16:05 2002
14 +++ linux/drivers/char/Makefile Tue May 21 11:18:53 2002
18 obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o
19 +obj-$(CONFIG_ECC) += ecc.o
20 obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o
21 obj-$(CONFIG_ROCKETPORT) += rocket.o
22 obj-$(CONFIG_MOXA_SMARTIO) += mxser.o
23 diff -urN Linux/drivers/char/ecc.c linux/drivers/char/ecc.c
24 --- Linux/drivers/char/ecc.c Thu Jan 1 01:00:00 1970
25 +++ linux/drivers/char/ecc.c Tue May 21 11:19:17 2002
28 + * ECC kernel module (C) 1998, 1999, 2002 Dan Hollis <goemon at anime dot net>
29 + * Portions thanks to
30 + * Michael O'Reilly <michael at metal dot iinet dot net dot au>
31 + * Osma Ahvenlampi <oa at spray dot fi>
32 + * Martin Maney <maney at pobox dot com>
33 + * Peter Heckert <peter.heckert at arcormail dot de>
34 + * Ishikawa <ishikawa at yk dot rim dot or dot jp>
35 + * Jaakko Hyvti <jaakko dot hyvatti at iki dot fi>
36 + * Various Linux Networx, LLNL & Red Hat staff.
41 +#include <linux/config.h>
42 +#include <linux/version.h>
43 +#include <linux/module.h>
45 +#include <linux/mm.h>
46 +#include <linux/sched.h>
47 +#include <linux/delay.h>
48 +#include <linux/pci.h>
49 +#include <linux/timer.h>
51 +#include <linux/proc_fs.h>
52 +#include <linux/sysctl.h>
53 +#include <linux/kernel.h>
54 +#include <asm/uaccess.h>
56 +#define ECC_VER "0.14 (Oct 10 2001)"
58 +static struct timer_list ecctimer;
59 +static struct pci_dev *bridge = NULL;
60 +static u16 vendor, device;
61 +static int scrub_needed;
62 +static int scrub_row;
64 +/* These are tunable by either module parameter or sysctl */
65 +int panic_on_mbe = 1;
68 +int poll_msec = 1000;
71 +MODULE_PARM(panic_on_mbe, "i");
72 +MODULE_PARM(log_mbe, "i");
73 +MODULE_PARM(log_sbe, "i");
74 +MODULE_PARM(poll_msec, "i");
79 +static ctl_table ecc_table[] = {
81 + &panic_on_mbe, sizeof(int), 0644, NULL, &proc_dointvec},
83 + &log_mbe, sizeof(int), 0644, NULL, &proc_dointvec},
85 + &log_sbe, sizeof(int), 0644, NULL, &proc_dointvec},
87 + &poll_msec, sizeof(int), 0644, NULL, &proc_dointvec},
91 +static ctl_table ecc_root_table[] = {
92 + {CTL_DEBUG, "ecc", NULL, 0, 0555, ecc_table},
96 +static struct ctl_table_header *ecc_sysctl_header = NULL;
100 +#define I860_DUMPCONFIG 0
102 +#define mbe_printk(fmt,args...) do { \
103 + if (panic_on_mbe) panic("ECC: MBE " fmt,##args); \
104 + else if (log_mbe) printk(KERN_EMERG "ECC: MBE " fmt,##args); \
106 +#define sbe_printk(fmt,args...) do { \
107 + if (log_sbe) printk(KERN_WARNING "ECC: SBE " fmt,##args); \
111 +#define assert(EX) do { } while (0)
113 +#define assert(EX) do { \
114 + if (!(EX)) printk("assertion failed: %s, %s::%d\n", \
115 + #EX, __FILE__, __LINE__); \
120 +#define BANK_EMPTY 0 /* Empty bank */
121 +#define BANK_RESERVED 1 /* Reserved bank type */
122 +#define BANK_UNKNOWN 2 /* Unknown bank type */
123 +#define BANK_FPM 3 /* Fast page mode */
124 +#define BANK_EDO 4 /* Extended data out */
125 +#define BANK_BEDO 5 /* Burst Extended data out */
126 +#define BANK_SDR 6 /* Single data rate SDRAM */
127 +#define BANK_DDR 7 /* Double data rate SDRAM */
128 +#define BANK_RDR 8 /* Registered SDRAM */
129 +#define BANK_RMBS 9 /* Rambus DRAM */
131 +/* Memory bank info */
132 +static struct bankstruct
134 + u32 endaddr; /* bank ending address */
135 + u32 mbecount; /* total number of MBE errors */
136 + u32 sbecount; /* total number of SBE errors */
137 + u8 eccmode; /* ECC enabled for this bank? */
138 + u8 mtype; /* memory bank type */
139 +} bank[MAXBANKS]; /* do any chipsets support more? */
141 +/* chipset ECC capabilities and mode */
142 +#define ECC_NONE 0 /* Doesnt support ECC (or is BIOS disabled) */
143 +#define ECC_RESERVED 1 /* Reserved ECC type */
144 +#define ECC_PARITY 2 /* Detects parity errors */
145 +#define ECC_DETECT 3 /* Detects ECC errors */
146 +#define ECC_CORRECT 4 /* Detects ECC errors and corrects SBE */
147 +#define ECC_AUTO 5 /* Detects ECC errors and has hardware scrubber */
149 +static struct ChipsetInfo
151 + int ecc_cap; /* chipset ECC capabilities */
152 + int ecc_mode; /* current ECC mode */
153 + void (*check)(void); /* pointer to ecc checking routine */
154 + void (*clear_err)(void);/* pointer to error clear routine */
157 + * I dont think we care about SERR at the moment.
158 + * We may if/when we hook into an NMI handler.
160 + int SERR; /* SERR enabled? */
161 + int SERR_MBE; /* SERR on multi-bit error? */
162 + int SERR_SBE; /* SERR on single-bit error? */
164 + int MBE_flag_address; /* pci offset for mbe register */
165 + int MBE_flag_shift; /* bits to shift for mbe flag */
166 + int MBE_flag_mask; /* mask for mbe flag */
167 + int MBE_row_shift; /* bits to shift for mbe row flag */
168 + int MBE_row_mask; /* mask for mbe register (shifted) */
169 + int SBE_flag_address; /* pci offset for sbe register */
170 + int SBE_flag_shift; /* bits to shift for sbe flag */
171 + int SBE_flag_mask; /* mask for sbe flag */
172 + int SBE_row_shift; /* bits to shift for sbe row flag */
173 + int SBE_row_mask; /* mask for sbe register (shifted) */
174 + int MBE_err_address1; /* pci offset for mbe address register */
175 + int MBE_err_shift1; /* bits to shift for mbe address register */
176 + int MBE_err_address2; /* pci offset for mbe address register */
177 + int MBE_err_shift2; /* bits to shift for mbe address register */
178 + u32 MBE_err_mask; /* mask for mbe address register */
179 + int MBE_err_flag; /* MBE error flag */
180 + int MBE_err_row; /* MBE row */
181 + u32 MBE_addr; /* address of last MBE */
182 + int SBE_err_address1; /* pci offset for mbe address register */
183 + int SBE_err_shift1; /* bits to shift for mbe address register */
184 + int SBE_err_address2; /* pci offset for mbe address register */
185 + int SBE_err_shift2; /* bits to shift for mbe address register */
186 + u32 SBE_err_mask; /* mask for mbe address register */
187 + int SBE_err_flag; /* SBE error flag */
188 + int SBE_err_row; /* SBE row */
189 + u32 SBE_addr; /* address of last SBE */
192 +static inline unsigned int pci_byte(int offset)
195 + pci_read_config_byte(bridge, offset, &value);
196 + return value & 0xFF;
199 +static inline unsigned int pci_word(int offset)
202 + pci_read_config_word(bridge, offset, &value);
206 +static inline unsigned int pci_dword(int offset)
209 + pci_read_config_dword(bridge, offset, &value);
213 +/* write all or some bits in a byte-register*/
214 +static inline void pci_write_bits8(int offset,u8 value,u8 mask)
218 + pci_read_config_byte(bridge,offset, &buf);
223 + pci_write_config_byte(bridge,offset,value);
226 +static int find_row(unsigned long err_addr)
229 + for(loop=0; loop < MAXBANKS; loop++) {
230 + if (err_addr < bank[loop].endaddr) {
239 + * generic ECC check routine
241 + * This routine assumes that the MBE and SBE error status consist of:
242 + * * one or more bits in a status byte that are non-zero on error
243 + * * zero or more bits in a status byte that encode the row
244 + * It accomodates both the case where both the MBE and SBE data are
245 + * packed into a single byte (all chipsets currently known to me) as
246 + * well as the case where the MBE and SBE information are contained in
247 + * separate locations. The status byte is read only once for the packed
248 + * case in case the status value should be altered by being read.
250 +static void generic_check(void)
252 + int status = pci_byte(cs.MBE_flag_address);
253 + if ((status >> cs.MBE_flag_shift) & cs.MBE_flag_mask)
255 + int row = (status >> cs.MBE_row_shift) & cs.MBE_row_mask;
256 + mbe_printk("detected in DRAM row %d\n", row);
257 + if (cs.MBE_err_address1)
260 + ( pci_word(cs.MBE_err_address1 << cs.MBE_err_shift1) |
261 + pci_word(cs.MBE_err_address2 << cs.MBE_err_shift2) ) &
263 + mbe_printk("at memory address %lx\n", (long unsigned int)cs.MBE_addr);
267 + bank[row].mbecount++;
269 + if (cs.SBE_flag_address != cs.MBE_flag_address)
270 + status = pci_byte(cs.SBE_flag_address);
271 + if ((status >> cs.SBE_flag_shift) & cs.SBE_flag_mask)
273 + int row = (status >> cs.SBE_row_shift) & cs.SBE_row_mask;
274 + sbe_printk("detected in DRAM row %d\n", row);
275 + if (cs.SBE_err_address1)
278 + ( pci_word(cs.SBE_err_address1 << cs.SBE_err_shift1) |
279 + pci_word(cs.SBE_err_address2 << cs.SBE_err_shift2) ) &
281 + sbe_printk("at memory address %lx\n", (long unsigned int)cs.SBE_addr);
285 + bank[row].sbecount++;
289 +/* VIA specific error clearing */
290 +static void clear_via_err(void)
292 + pci_write_bits8(0x6f,0xff,0xff);
293 + /* as scrubbing is unimplemented, we reset it here */
297 +/* unified VIA probe */
298 +static void probe_via(void)
300 + int loop, ecc_ctrl, dimmslots = 3, bankshift = 23;
301 + int m_mem[] = { BANK_FPM, BANK_EDO, BANK_DDR, BANK_SDR };
303 + case 0x0391: /* VIA VT8371 - KX133 */
306 + bank[6].endaddr=(unsigned long)pci_byte(0x56)<<24;
307 + bank[7].endaddr=(unsigned long)pci_byte(0x57)<<24;
308 + case 0x0595: /* VIA VT82C595 - VP2,VP2/97 */
309 + m_mem[2] = BANK_RESERVED;
310 + cs.ecc_cap = ECC_CORRECT;
312 + case 0x0501: /* VIA VT8501 - MVP4 */
313 + case 0x0597: /* VIA VT82C597 - VP3 */
314 + case 0x0598: /* VIA VT82C598 - MVP3 */
315 + cs.ecc_cap = ECC_CORRECT;
317 + case 0x0694: /* VIA VT82C694XDP - Apollo PRO133A smp */
319 + case 0x0691: /* VIA VT82C691 - Apollo PRO */
320 + /* VIA VT82C693A - Apollo Pro133 (rev 40?) */
321 + /* VIA VT82C694X - Apollo Pro133A (rev 8x,Cx)
322 + has 4 dimm slots */
323 + case 0x0693: /* VIA VT82C693 - Apollo PRO-Plus */
325 + cs.ecc_cap = ECC_CORRECT;
327 + case 0x0305: /* VIA VT8363 - KT133 - no ecc!! */
328 + /* VIA VT8363A - KT133A (rev 8) - no ecc!! */
330 + cs.ecc_cap = ECC_NONE;
332 + case 0x0585: /* VIA VT82C585 - VP,VPX,VPX/97 */
334 + cs.ecc_cap = ECC_NONE;
337 + ecc_ctrl = pci_byte(0x6E);
338 + cs.ecc_mode = (ecc_ctrl>>7)&1 ? cs.ecc_cap : ECC_NONE;
340 + cs.check = generic_check;
341 + if (cs.ecc_mode != ECC_NONE) {
342 + cs.clear_err = clear_via_err;
343 + /* clear initial errors */
346 + cs.MBE_flag_address = 0x6F;
347 + cs.MBE_flag_shift = 7;
348 + cs.MBE_flag_mask = 1;
349 + cs.MBE_row_shift = 4;
350 + cs.MBE_row_mask = 7;
351 + cs.SBE_flag_address = 0x6F;
352 + cs.SBE_flag_shift = 3;
353 + cs.SBE_flag_mask = 1;
354 + cs.SBE_row_shift = 0;
355 + cs.SBE_row_mask = 7;
357 + for(loop=0;loop<6;loop++)
358 + bank[loop].endaddr = (unsigned long)pci_byte(0x5a+loop)<<bankshift;
359 + for(loop=0;loop<dimmslots;loop++)
361 + bank[loop*2].mtype = m_mem[(pci_byte(0x60)>>(loop*2))&3];
362 + bank[(loop*2)+1].mtype = m_mem[(pci_byte(0x60)>>(loop*2))&3];
363 + bank[loop*2].eccmode = (ecc_ctrl>>(loop))&1;
364 + bank[(loop*2)+1].eccmode = (ecc_ctrl>>(loop))&1;
368 +static void check_serverworks(void)
370 + unsigned long mesr;
373 + mesr = pci_dword(0x94); /* mesr0 */
374 + row = (int)(mesr>>29)&0x7;
377 + mbe_printk("Detected in DRAM row %d\n", row);
379 + bank[row].mbecount++;
383 + sbe_printk("Detected in DRAM row %d\n", row);
385 + bank[row].sbecount++;
390 + * clear error flag bits that were set by writing 1 to them
391 + * we hope the error was a fluke or something :)
393 + unsigned long value = scrub_needed<<30;
394 + pci_write_config_dword(bridge, 0x94, value);
398 + mesr = pci_dword(0x98); /* mesr1 */
399 + row = (int)(mesr>>29)&0x7;
402 + mbe_printk("Detected in DRAM row %d\n", row);
404 + bank[row].mbecount++;
408 + sbe_printk("Detected in DRAM row %d\n", row);
410 + bank[row].sbecount++;
415 + * clear error flag bits that were set by writing 1 to them
416 + * we hope the error was a fluke or something :)
418 + unsigned long value = scrub_needed<<30;
419 + pci_write_config_dword(bridge, 0x98, value);
424 +static void probe_serverworks(void)
426 + int loop, efcr, mccr;
428 + case 0x0008: /* serverworks iii he */
429 + case 0x0009: /* serverworks iii le */
430 + cs.ecc_cap = ECC_AUTO;
433 + cs.ecc_cap = ECC_NONE;
436 + efcr = pci_byte(0xE0);
437 + mccr = pci_word(0x92);
438 + cs.ecc_mode = (efcr>>2)&1 ? (mccr&1 ? ECC_AUTO : ECC_CORRECT) : ECC_NONE;
440 + cs.check = check_serverworks;
442 + for(loop=0;loop<8;loop++)
444 + bank[loop].mtype = BANK_UNKNOWN;
445 + bank[loop].eccmode = cs.ecc_mode;
446 + bank[loop].endaddr = 0;
451 + * 450gx probing is buggered at the moment. help me obi-wan.
453 +static void probe_450gx(void)
455 + int loop, dramc, merrcmd;
457 + int m_mem[] = { BANK_EDO, BANK_SDR, BANK_RDR, BANK_RESERVED };
458 +/* int ddim[] = { ECC_NONE, ECC_DETECT, ECC_CORRECT, ECC_AUTO }; */
459 + nbxcfg = pci_dword(0x50);
460 + dramc = pci_byte(0x57);
461 + merrcmd = pci_word(0xC0);
462 + for(loop=0;loop<8;loop++)
464 + bank[loop].endaddr=(unsigned long)pci_byte(0x60+loop)<<23;
465 + /* 450gx doesnt allow mixing memory types. bleah. */
466 + bank[loop].mtype = m_mem[(dramc>>3)&3];
467 + /* yes, bit is _zero_ if ecc is _enabled_. */
468 + bank[loop].eccmode = !((nbxcfg>>(loop+24))&1);
470 + cs.ecc_cap = ECC_AUTO;
471 + cs.ecc_mode = (merrcmd>>1)&1 ? ECC_AUTO : ECC_DETECT;
473 + cs.check = generic_check;
474 + cs.MBE_flag_address = 0xC2;
475 + cs.MBE_flag_shift = 0;
476 + cs.MBE_flag_mask = 1;
477 + cs.MBE_row_shift = 5;
478 + cs.MBE_row_mask = 7;
479 + cs.SBE_flag_address = 0xC2;
480 + cs.SBE_flag_shift = 1;
481 + cs.SBE_flag_mask = 1;
482 + cs.SBE_row_shift = 1;
483 + cs.SBE_row_mask = 7;
485 + cs.MBE_err_address1 = 0xA8;
486 + cs.MBE_err_shift1 = 0;
487 + cs.MBE_err_address2 = 0xAA;
488 + cs.MBE_err_shift2 = 16;
489 + cs.MBE_err_mask = 0xFFFFFFFC;
491 + cs.SBE_err_address1 = 0x74;
492 + cs.SBE_err_shift1 = 0;
493 + cs.SBE_err_address2 = 0x76;
494 + cs.SBE_err_shift2 = 16;
495 + cs.SBE_err_mask = 0xFFFFFFFC;
498 +/* there seems to be NO WAY to distinguish 440zx from 440bx!! >B( */
499 +static void probe_440bx(void)
501 + int loop, dramc, errcmd;
503 + int m_mem[] = { BANK_EDO, BANK_SDR, BANK_RDR, BANK_RESERVED };
504 + int ddim[] = { ECC_NONE, ECC_DETECT, ECC_CORRECT, ECC_AUTO };
505 + nbxcfg = pci_dword(0x50);
506 + dramc = pci_byte(0x57);
507 + errcmd = pci_byte(0x90);
508 + cs.ecc_cap = ECC_AUTO;
509 + cs.ecc_mode = ddim[(nbxcfg>>7)&3];
511 + cs.check = generic_check;
512 + cs.MBE_flag_address = 0x91;
513 + cs.MBE_flag_shift = 4;
514 + cs.MBE_flag_mask = 1;
515 + cs.MBE_row_shift = 5;
516 + cs.MBE_row_mask = 7;
517 + cs.SBE_flag_address = 0x91;
518 + cs.SBE_flag_shift = 0;
519 + cs.SBE_flag_mask = 1;
520 + cs.SBE_row_shift = 1;
521 + cs.SBE_row_mask = 7;
523 + cs.MBE_err_address1 = 80;
524 + cs.MBE_err_shift1 = 0;
525 + cs.MBE_err_address2 = 82;
526 + cs.MBE_err_shift2 = 16;
527 + cs.MBE_err_mask = 0xFFFFF000;
529 + cs.SBE_err_address1 = 80;
530 + cs.SBE_err_shift1 = 0;
531 + cs.SBE_err_address2 = 82;
532 + cs.SBE_err_shift2 = 16;
533 + cs.SBE_err_mask = 0xFFFFF000;
535 + for(loop=0;loop<8;loop++)
537 + bank[loop].endaddr=(unsigned long)pci_byte(0x60+loop)<<23;
538 + /* 440bx doesnt allow mixing memory types. bleah. */
539 + bank[loop].mtype = m_mem[(dramc>>3)&3];
540 + /* yes, bit is _zero_ if ecc is _enabled_. */
541 + bank[loop].eccmode = !((nbxcfg>>(loop+24))&1);
545 +/* no way to tell 440ex from 440lx!? grr. */
546 +static void probe_440lx(void)
548 + int loop, drt, paccfg, errcmd;
549 + int m_mem[] = { BANK_EDO, BANK_RESERVED, BANK_SDR, BANK_EMPTY };
550 + int ddim[] = { ECC_NONE, ECC_DETECT, ECC_RESERVED, ECC_CORRECT } ;
551 + paccfg = pci_word(0x50);
552 + drt = pci_byte(0x55) | (pci_byte(0x56)<<8);
553 + errcmd = pci_byte(0x90);
554 + /* 440ex doesnt support ecc, but no way to tell if its 440ex! */
555 + cs.ecc_cap = ECC_CORRECT;
556 + cs.ecc_mode = ddim[(paccfg>>7)&3];
558 + cs.check = generic_check;
559 + cs.MBE_flag_address = 0x91;
560 + cs.MBE_flag_shift = 4;
561 + cs.MBE_flag_mask = 1;
562 + cs.MBE_row_shift = 5;
563 + cs.MBE_row_mask = 7;
564 + cs.SBE_flag_address = 0x91;
565 + cs.SBE_flag_shift = 0;
566 + cs.SBE_flag_mask = 1;
567 + cs.SBE_row_shift = 1;
568 + cs.SBE_row_mask = 7;
570 + for(loop=0;loop<8;loop++)
572 + bank[loop].endaddr = (unsigned long)pci_byte(0x60+loop)<<23;
573 + bank[loop].mtype = m_mem[(drt>>(loop*2))&3];
574 + bank[loop].eccmode = (cs.ecc_mode != 0);
578 +static void probe_440fx(void)
580 + int loop, drt, pmccfg, errcmd;
581 + int m_mem[] = { BANK_FPM, BANK_EDO, BANK_BEDO, BANK_EMPTY };
582 + int ddim[] = { ECC_NONE, ECC_PARITY, ECC_DETECT, ECC_CORRECT };
583 + pmccfg = pci_word(0x50);
584 + drt = pci_byte(0x55) | (pci_byte(0x56)<<8);
585 + errcmd = pci_byte(0x90);
586 + for(loop=0;loop<8;loop++)
588 + bank[loop].endaddr=(unsigned long)pci_byte(0x60+loop)<<23;
589 + bank[loop].mtype = m_mem[(drt>>(loop*2))&3];
591 + cs.ecc_cap = ECC_CORRECT;
592 + cs.ecc_mode = ddim[(pmccfg>>4)&3];
594 + cs.check = generic_check;
595 + cs.MBE_flag_address = 0x91;
596 + cs.MBE_flag_shift = 4;
597 + cs.MBE_flag_mask = 1;
598 + cs.MBE_row_shift = 5;
599 + cs.MBE_row_mask = 7;
600 + cs.SBE_flag_address = 0x91;
601 + cs.SBE_flag_shift = 0;
602 + cs.SBE_flag_mask = 1;
603 + cs.SBE_row_shift = 1;
604 + cs.SBE_row_mask = 7;
607 +static void probe_430hx(void)
609 + int pcicmd, pcon, errcmd, drt, loop;
610 + pcicmd = pci_word(0x4);
611 + pcon = pci_byte(0x50);
612 + drt = pci_byte(0x68);
613 + errcmd = pci_byte(0x90);
614 + cs.ecc_cap = ECC_CORRECT;
615 + cs.ecc_mode = (pcon>>7)&1 ? ECC_CORRECT : ECC_PARITY;
617 + cs.check = generic_check;
618 + cs.MBE_flag_address = 0x91;
619 + cs.MBE_flag_shift = 4;
620 + cs.MBE_flag_mask = 1;
621 + cs.MBE_row_shift = 5;
622 + cs.MBE_row_mask = 7;
623 + cs.SBE_flag_address = 0x91;
624 + cs.SBE_flag_shift = 0;
625 + cs.SBE_flag_mask = 1;
626 + cs.SBE_row_shift = 1;
627 + cs.SBE_row_mask = 7;
629 + for(loop=0;loop<8;loop++)
631 + bank[loop].endaddr=(unsigned long)pci_byte(0x60+loop)<<22;
632 + bank[loop].mtype = (drt>>loop)&1 ? BANK_EDO : BANK_FPM;
633 + bank[loop].eccmode = cs.ecc_mode;
637 +static void check_840(void)
639 + int errsts = pci_word(0xE2);
640 + if ((errsts>>9) & 1)
642 + u32 eap = pci_dword(0xE4) & 0xFFFFF800;
643 + mbe_printk("at memory address %lx\n row %d syndrome %x",
644 + (long unsigned int)eap, find_row(eap), errsts&0xFF);
646 + scrub_row = find_row(eap);
647 + bank[scrub_row].mbecount++;
649 + if ((errsts>>10) & 1)
651 + u32 eap = pci_dword(0xE4) & 0xFFFFF800;
652 + sbe_printk("at memory address %lx row %d syndrome %x\n",
653 + (long unsigned int)eap, find_row(eap), errsts&0xFF);
655 + scrub_row = find_row(eap);
656 + bank[scrub_row].sbecount++;
660 +static void probe_840(void)
663 + int ddim[] = { ECC_NONE, ECC_RESERVED, ECC_CORRECT, ECC_AUTO };
664 + mchcfg = pci_word(0x50);
665 + cs.ecc_cap = ECC_AUTO;
666 + cs.ecc_mode = ddim[(mchcfg>>7)&3];
668 + cs.check = check_840;
670 + for(loop=0;loop<16;loop++)
672 + bank[loop].endaddr=(unsigned long)pci_word(0x60+(loop*2))<<23;
673 + bank[loop].mtype = BANK_RMBS;
674 + bank[loop].eccmode = cs.ecc_mode;
678 +static void check_845(void)
680 + int errsts = pci_word(0xC8);
681 + if ((errsts>>1) & 1)
683 + u32 eap = (pci_dword(0x8C) & 0xFFFFFFFE)<<4;
684 + char derrsyn = pci_byte(0x86);
685 + mbe_printk("at memory address %lx\n row %d syndrome %x",
686 + (long unsigned int)eap, find_row(eap), derrsyn);
688 + scrub_row = find_row(eap);
689 + bank[scrub_row].mbecount++;
693 + u32 eap = (pci_dword(0x8C) & 0xFFFFFFFE)<<4;
694 + char derrsyn = pci_byte(0x86);
695 + sbe_printk("at memory address %lx row %d syndrome %x\n",
696 + (long unsigned int)eap, find_row(eap), derrsyn);
698 + scrub_row = find_row(eap);
699 + bank[scrub_row].sbecount++;
703 +static void probe_845(void)
707 + int ddim[] = { ECC_NONE, ECC_RESERVED, ECC_CORRECT, ECC_RESERVED };
708 + drc = pci_dword(0x7C);
709 + cs.ecc_cap = ECC_CORRECT;
710 + cs.ecc_mode = ddim[(drc>>19)&3];
712 + cs.check = check_845;
714 + for(loop=0;loop<8;loop++)
716 + bank[loop].endaddr=(unsigned long)pci_byte(0x60+loop)<<24;
717 + bank[loop].mtype = BANK_SDR;
718 + bank[loop].eccmode = cs.ecc_mode;
722 +static void check_850(void)
724 + int errsts = pci_word(0xC8);
725 + if ((errsts>>1) & 1)
727 + u32 eap = pci_dword(0xE4) & 0xFFFFE000;
728 + char derrsyn = pci_word(0xE2) & 0x7F;
729 + mbe_printk("at memory address %lx\n row %d syndrome %x",
730 + (long unsigned int)eap, find_row(eap), derrsyn);
732 + scrub_row = find_row(eap);
733 + bank[scrub_row].mbecount++;
737 + u32 eap = pci_dword(0xE4) & 0xFFFFE000;
738 + char derrsyn = pci_byte(0xE2) & 0x7F;
739 + sbe_printk("at memory address %lx row %d syndrome %x\n",
740 + (long unsigned int)eap, find_row(eap), derrsyn);
742 + scrub_row = find_row(eap);
743 + bank[scrub_row].sbecount++;
747 +static void probe_850(void)
751 + int ddim[] = { ECC_NONE, ECC_RESERVED, ECC_CORRECT, ECC_RESERVED };
752 + mchcfg = pci_word(0x50);
753 + cs.ecc_cap = ECC_CORRECT;
754 + cs.ecc_mode = ddim[(mchcfg>>7)&3];
756 + cs.check = check_850;
758 + for(loop=0;loop<16;loop++)
760 + bank[loop].endaddr=(unsigned long)pci_word(0x60+(loop*2))<<23;
761 + bank[loop].mtype = BANK_RMBS;
762 + bank[loop].eccmode = cs.ecc_mode;
766 +/* 860 specific error clearing */
767 +static void clear_860_err(void)
769 + pci_write_bits8(0xc8,0x03,0x03);
770 + /* as scrubbing is unimplemented, we reset it here */
775 +static void check_860(void)
777 + int errsts = pci_word(0xC8);
778 + if ((errsts>>1) & 1)
780 + u32 eap = (pci_dword(0xE4) & 0xFFFFFE00)<<2;
781 + int channel = pci_dword(0xE4) & 1;
782 + unsigned char derrsyn = pci_word(0xE2) & 0xFF;
783 + mbe_printk("at memory address %08lx row %d syndrome %02x channel=%s\n",
784 + (long unsigned int)eap, find_row(eap), derrsyn, channel==0?"A":"B");
786 + scrub_row = find_row(eap);
787 + bank[scrub_row].mbecount++;
788 + cs.clear_err = clear_860_err;
792 + u32 eap = (pci_dword(0xE4) & 0xFFFFFE00)<<2;
793 + int channel = pci_dword(0xE4) & 1;
794 + unsigned char derrsyn = pci_byte(0xE2) & 0xFF;
795 + sbe_printk("at memory address %08lx row %d syndrome %02x channel=%s\n",
796 + (long unsigned int)eap, find_row(eap), derrsyn, channel==0?"A":"B");
798 + scrub_row = find_row(eap);
799 + bank[scrub_row].sbecount++;
800 + cs.clear_err = clear_860_err;
803 + * We should catch other error bits, however we need to add code
804 + * to clear them if we want to continue on (otherwise we will report
805 + * the same error on every poll). Having never seen other bits set
806 + * on our systems, just panic for now. -jg
809 + panic("ECC: MCH ERRSTS register contains 0x%x\n", errsts);
817 + printk("RDRAM Device Group Architecture Registers (16): \n");
818 + for (i = 0; i < 16; i++) {
819 + printk("GAR[%d]=%-2.2x ", i, pci_byte(0x40 + i));
820 + if ((i + 1) % 4 == 0)
823 + printk("MCH Configuration Register: MCHCFG=%-4.4x\n", pci_word(0x50));
824 + printk("Fixed DRAM Hole Control Register: FDHC=%-2.2x\n",
826 + printk("Programmable Attribute Map Registers (7):\n");
827 + for (i = 0; i < 7; i++) {
828 + printk("PAM[%d]=%-2.2x ", i, pci_byte(0x59 + i));
829 + if ((i + 1) % 4 == 0)
833 + printk("RDRAM Device Pool Sizing Register: RDPS=%-2.2x\n",
835 + printk("RDRAM Device Init Control Management Register: RICM=%-8.8x\n",
837 + printk("System Management RAM Control Register: SMRAM=%-2.2x\n",
839 + printk("Extended System Mgmt RAM Control Register: ESMRAMC=%-2.2x\n",
841 + printk("RDRAM Device Timing Register: RDTR=%-2.2x\n", pci_byte(0xBE));
842 + printk("Top of Low Memory Register: TOM=%-4.4x\n", pci_word(0xC4));
843 + printk("Error Command Register: ERRCMD=%-4.4x\n", pci_word(0xCA));
844 + printk("SMI Command Register: SCICMD=%-4.4x\n", pci_word(0xCC));
845 + printk("SCI Command Register: SCICMD=%-4.4x\n", pci_word(0xCE));
846 + printk("RDRAM Device Refresh Control Register: DRAMRC=%-4.4x\n",
848 + printk("Misc. Control Register: MISC_CNTL=%-8.8x\n", pci_dword(0xF4));
849 + printk("PCI Command Register: PCICMD=%-4.4x\n", pci_word(0x04));
854 + printk("ECC: Intel 860 MCH probed successfully\n");
858 +static void probe_860(void)
862 + int ddim[] = { ECC_NONE, ECC_RESERVED, ECC_CORRECT, ECC_RESERVED };
863 + drc = pci_word(0x50);
864 + cs.ecc_cap = ECC_CORRECT;
865 + cs.ecc_mode = ddim[(drc>>7)&3];
867 + cs.check = check_860;
869 + for(loop=0;loop<MAXBANKS;loop++)
871 + bank[loop].endaddr=(unsigned long)pci_word(0x60+(loop*2))<<24;
872 + bank[loop].mtype = BANK_RMBS;
873 + bank[loop].eccmode = cs.ecc_mode;
874 + if (loop > 0) { /* find_bank assumes ascending addresses */
875 + assert(bank[loop].endaddr >= bank[loop-1].endaddr);
878 + clear_860_err(); /* start off with a clean slate */
882 +static void check_amd751(void)
884 + int eccstat = pci_word(0x58);
885 + int csbits = eccstat & 0x3F;
889 + case 1: row = 0; break;
890 + case 2: row = 1; break;
891 + case 4: row = 2; break;
892 + case 8: row = 3; break;
893 + case 16: row = 4; break;
894 + case 32: row = 5; break;
897 + if(((eccstat>>8)&3) == 1)
899 + mbe_printk("Detected in DRAM row %d\n", row);
901 + bank[row].mbecount++;
903 + if(((eccstat>>8)&3) == 2)
905 + sbe_printk("Detected in DRAM row %d\n", row);
907 + bank[row].sbecount++;
909 + if(((eccstat>>8)&3) == 3)
911 + mbe_printk("and SBE Detected in DRAM row %d\n", row);
913 + bank[row].sbecount++;
918 + * clear error flag bits that were set by writing 0 to them
919 + * we hope the error was a fluke or something :)
921 + int value = eccstat & 0xFCFF;
922 + pci_write_config_word(bridge, 0x58, value);
927 +static void probe_amd751(void)
930 + cs.ecc_cap = ECC_CORRECT;
931 + cs.ecc_mode = (pci_byte(0x5a)>>2)&1 ? ECC_CORRECT : ECC_NONE;
932 + cs.check = check_amd751;
933 + for(loop=0;loop<6;loop++)
935 + unsigned flag = pci_byte(0x40+loop*2);
936 + /* bank address mask. */
937 + unsigned mask = (flag&0x7F)>>1;
938 + /* actually starting address */
939 + bank[loop].endaddr=(unsigned long)(pci_word(0x40+loop*2)&0xFF80)<<(23-7);
940 + /* only when bank is populated */
941 + if((flag&1)&&(mask!=0)){
942 + /* mask+1 * 8mb appears to be bank size */
943 + bank[loop].endaddr += (mask + 1) * 8 * (1024 * 1024); /* -1? */
945 + bank[loop].mtype = flag&1 ? BANK_SDR : BANK_EMPTY;
946 + /* no per-bank register, assumed same for all banks? */
947 + bank[loop].eccmode = (pci_byte(0x5a)>>2)&1;
951 +static void check_amd76x(void)
953 + unsigned long eccstat = pci_dword(0x48);
956 + /* bits 7-4 of eccstat indicate the row the MBE occurred. */
957 + int row = (eccstat >> 4) & 0xf;
958 + mbe_printk("Detected in DRAM row %d\n", row);
960 + bank[row].mbecount++;
964 + /* bits 3-0 of eccstat indicate the row the SBE occurred. */
965 + int row = eccstat & 0xf;
966 + sbe_printk("Detected in DRAM row %d\n", row);
968 + bank[row].sbecount++;
973 + * clear error flag bits that were set by writing 0 to them
974 + * we hope the error was a fluke or something :)
976 + unsigned long value = eccstat;
977 + if (scrub_needed & 1)
978 + value &= 0xFFFFFDFF;
979 + if (scrub_needed & 2)
980 + value &= 0xFFFFFEFF;
981 + pci_write_config_dword(bridge, 0x48, value);
986 +static void probe_amd76x(void)
988 + static const int modetab[] = {ECC_NONE, ECC_DETECT, ECC_CORRECT, ECC_AUTO};
990 + unsigned long addr = 0;
991 + cs.ecc_cap = ECC_AUTO;
992 + cs.ecc_mode = modetab [(pci_dword(0x48)>>10)&3];
993 + cs.check = check_amd76x;
995 + /* create fake end addresses, as the chipset is capable of
996 + matching addresses to banks in random order */
997 + for(loop=0;loop<8;loop++)
999 + unsigned long r = pci_dword(0xc0+(loop*4));
1000 + bank[loop].mtype = r & 1 ? BANK_DDR : BANK_EMPTY;
1002 + addr += ((r & 0xff80) << 16) + 0x800000;
1003 + bank[loop].endaddr=addr;
1004 + /* no per-bank register, assumed same for all banks? */
1005 + bank[loop].eccmode = cs.ecc_mode != ECC_NONE;
1010 +void probe_sis(void)
1014 + int m_mem[] = { BANK_FPM, BANK_EDO, BANK_RESERVED, BANK_SDR };
1015 + int dramsize[] = { 256, 1024, 4096, 16384, 1024, 2048, 4096,
1016 + 8192, 512, 1024, 2048, 0, 0, 0, 0, 0 };
1017 + int sdramsize[] = { 1024, 4096, 4096, 8192, 2048, 8192,
1018 + 8192, 16384, 4096, 16384, 16384, 32768, 2048, 0, 0, 0 };
1020 + cs.ecc_cap = ECC_CORRECT;
1022 + cs.check = generic_check;
1024 + cs.MBE_flag_address = 0x64;
1025 + cs.MBE_flag_shift = 4;
1026 + cs.MBE_flag_mask = 1;
1027 + cs.MBE_row_shift = 5;
1028 + cs.MBE_row_mask = 7;
1030 + cs.SBE_flag_address = 0x64;
1031 + cs.SBE_flag_shift = 3;
1032 + cs.SBE_flag_mask = 1;
1033 + cs.SBE_row_shift = 5;
1034 + cs.SBE_row_mask = 7;
1036 + cs.MBE_err_address1 = 0x64;
1037 + cs.MBE_err_shift1 = 0;
1038 + cs.MBE_err_address2 = 0x66;
1039 + cs.MBE_err_shift2 = 16;
1040 + cs.MBE_err_mask = 0xFFFFF000;
1042 + cs.SBE_err_address1 = 0x64;
1043 + cs.SBE_err_shift1 = 0;
1044 + cs.SBE_err_address2 = 0x66;
1045 + cs.SBE_err_shift2 = 16;
1046 + cs.MBE_err_mask = 0xFFFFF000;
1049 + for(loop=0;loop<3;loop++)
1051 + /* populated bank? */
1052 + if ((pci_byte(0x63)>>loop)&1)
1055 + int mtype = pci_byte(0x60+loop);
1057 + bank[loop*2].mtype = m_mem[(mtype>>6)&3];
1058 + if(bank[loop*2].mtype == BANK_SDR)
1060 + banksize = sdramsize[mtype&15]*1024;
1062 + banksize = dramsize[mtype&15]*1024;
1064 + endaddr += banksize;
1065 + bank[loop*2].endaddr = endaddr;
1066 + /* double sided dimm? */
1069 + bank[(loop*2)+1].mtype = bank[loop*2].mtype;
1070 + endaddr += banksize;
1071 + bank[(loop*2)+1].endaddr = endaddr;
1074 + bank[loop*2].mtype = BANK_EMPTY;
1075 + bank[(loop*2)+1].mtype = BANK_EMPTY;
1076 + bank[loop*2].endaddr = endaddr;
1077 + bank[(loop*2)+1].endaddr = endaddr;
1080 + cs.ecc_mode = ECC_NONE;
1081 + for(loop=0;loop<6;loop++)
1083 + int eccmode = (pci_byte(0x74)>>loop)&1;
1084 + bank[loop].eccmode = eccmode;
1086 + cs.ecc_mode = ECC_CORRECT;
1091 +void probe_aladdin4(void)
1094 + int m_mem[] = { BANK_FPM, BANK_EDO, BANK_RESERVED, BANK_SDR };
1095 + cs.ecc_cap = ECC_CORRECT;
1096 + cs.ecc_mode = pci_byte(0x49)&1 ? ECC_CORRECT : ECC_PARITY;
1098 + cs.check = generic_check;
1100 + cs.MBE_flag_address = 0x4a;
1101 + cs.MBE_flag_shift = 4;
1102 + cs.MBE_flag_mask = 1;
1103 + cs.MBE_row_shift = 5;
1104 + cs.MBE_row_mask = 7;
1106 + cs.SBE_flag_address = 0x4a;
1107 + cs.SBE_flag_shift = 0;
1108 + cs.SBE_flag_mask = 1;
1109 + cs.SBE_row_shift = 1;
1110 + cs.SBE_row_mask = 7;
1112 + for(loop=0;loop<8;loop++)
1114 + bank[loop].endaddr = (unsigned long)(pci_byte(0x61+(loop*2))&15)<<27|(pci_byte(0x60+(loop*2))<<20);
1115 + bank[loop].mtype = m_mem[(pci_byte(0x61+(loop*2))>>1)&3];
1116 + if (cs.ecc_mode == ECC_CORRECT) {
1117 + bank[loop].eccmode = 1;
1119 + bank[loop].eccmode = 0;
1124 +void probe_aladdin5(void)
1127 + int m_mem[] = { BANK_FPM, BANK_EDO, BANK_RDR, BANK_SDR };
1128 + cs.ecc_cap = ECC_CORRECT;
1129 + cs.ecc_mode = pci_byte(0x50)&1 ? ECC_CORRECT : ECC_PARITY;
1131 + cs.check = generic_check;
1133 + cs.MBE_flag_address = 0x51;
1134 + cs.MBE_flag_shift = 4;
1135 + cs.MBE_flag_mask = 1;
1136 + cs.MBE_row_shift = 5;
1137 + cs.MBE_row_mask = 7;
1139 + cs.SBE_flag_address = 0x51;
1140 + cs.SBE_flag_shift = 0;
1141 + cs.SBE_flag_mask = 1;
1142 + cs.SBE_row_shift = 1;
1143 + cs.SBE_row_mask = 7;
1145 + for(loop=0;loop<8;loop++)
1147 + /* DBxCII not disabled address mapping? */
1148 + if(pci_byte(0x61+(loop*2))&0xF0)
1150 + /* endaddr always 1 unit low, granularity 1mb */
1151 + bank[loop].endaddr = (unsigned long)((pci_byte(0x61+(loop*2))&15)<<27|(pci_byte(0x60+(loop*2))<<20))+1048576;
1152 + bank[loop].mtype = m_mem[(pci_byte(0x61+(loop*2))>>1)&3];
1153 + if (cs.ecc_mode == ECC_CORRECT) {
1154 + bank[loop].eccmode = 1;
1156 + bank[loop].eccmode = 0;
1164 + * memory scrubber routines, not ready to be used yet...
1166 +/* start at 16mb */
1167 +unsigned long start = 4096;
1168 +unsigned long pages = 1;
1169 +/* other architectures have different page sizes... */
1170 +unsigned long step = 4096;
1172 +char buff[8192] = {0,};
1175 + * Michael's page scrubber routine
1177 +void scrub_page(unsigned long volatile * p)
1182 + q = (unsigned long *) ((((int)buff)+4095) & ~4095);
1184 + if (((int)p) >= 640 * 1024 && ((int)p) < 1024 * 1024)
1187 + cli(); /* kill interrupts */
1188 + err = pci_byte(0x91);
1189 + outb(0x11, PCI_DATA + 1); /* clear the memory error indicator */
1191 + for (i = 0; i < step / 4 ; ++i)
1193 + for (i = 0; i < step / 4 ; ++i)
1195 + err = inb(PCI_DATA + 1);
1198 + printk(KERN_ERR "ECC: Memory error @ %08x (0x%02x)\n", p, err);
1207 + for (i = 0; i < pages; ++i) {
1208 + j = scrub_page(start);
1213 + * Hmm... This is probably a very bad situation.
1215 + printk(KERN_ERR "ECC: Scrubbed, no errors found?!\n");
1219 + if (scrub_needed==2) {
1221 + * TODO: We should determine what process owns the memory
1222 + * and send a SIGBUS to it. We should also printk something
1223 + * along the lines of
1224 + * "ECC: Process (PID) killed with SIGBUS due to uncorrectable memory error at 0xDEADBEEF"
1233 + * Check ECC status every second.
1234 + * SMP safe, doesn't use NMI, and auto-rate-limits.
1236 +void checkecc(void) {
1237 + MOD_INC_USE_COUNT;
1238 + if (!scrub_needed)
1243 + init_timer(&ecctimer);
1244 + ecctimer.expires = jiffies + (HZ * poll_msec) / 1000;
1245 + ecctimer.function = (void *)&checkecc;
1247 + add_timer(&ecctimer);
1248 + MOD_DEC_USE_COUNT;
1251 +#ifdef CONFIG_PROC_FS
1252 +int procfile_read(char *memstat, char **buffer_location, off_t offset,
1253 + int buffer_length, int *eof, void *data)
1255 + char *ecc[] = { "None", "Reserved", "Parity checking", "ECC detection",
1256 + "ECC detection and correction", "ECC with hardware scrubber" };
1257 + char *dram[] = { "Empty", "Reserved", "Unknown", "FPM", "EDO", "BEDO", "SDR",
1258 + "DDR", "RDR", "RMBS" };
1259 + unsigned long mem_end = 0;
1260 + unsigned long last_mem = 0;
1267 + len += sprintf(memstat, "Chipset ECC capability : %s\n", ecc[cs.ecc_cap]);
1268 + len += sprintf(memstat + len, "Current ECC mode : %s\n", ecc[cs.ecc_mode]);
1269 + len += sprintf(memstat + len, "Bank\tSize\tType\tECC\tSBE\tMBE\n");
1270 + for (loop=0;loop<MAXBANKS;loop++){
1271 + last_mem=bank[loop].endaddr;
1272 + if (last_mem>mem_end) {
1273 + len += sprintf(memstat + len, "%d\t", loop);
1274 + len += sprintf(memstat + len, "%dM\t", (int)(last_mem-mem_end)/1048576);
1275 + len += sprintf(memstat + len, "%s\t", dram[bank[loop].mtype]);
1276 + len += sprintf(memstat + len, "%s\t", bank[loop].eccmode ? "Y" : "N");
1277 + len += sprintf(memstat + len, "%ld\t", (unsigned long)bank[loop].sbecount);
1278 + len += sprintf(memstat + len, "%ld\n", (unsigned long)bank[loop].mbecount);
1282 + len += sprintf(memstat + len, "Total\t%dM\n", (int)(mem_end>>20));
1284 + if (len <= buffer_length)
1287 + len = buffer_length;
1292 +struct pci_probe_matrix {
1293 + int vendor; /* pci vendor id */
1294 + int device; /* pci device id */
1295 + void (*check)(void); /* pointer to chipset probing routine */
1298 +static struct pci_probe_matrix probe_matrix[] = {
1300 + { 0x1022, 0x7006, probe_amd751 },
1301 + { 0x1022, 0x700c, probe_amd76x }, /* amd762 2 CPU */
1302 + { 0x1022, 0x700e, probe_amd76x }, /* amd761 1 CPU */
1304 + { 0x1057, 0x4802, 0 }, /* falcon - not yet supported */
1306 + { 0x106b, 0x0001, 0 }, /* bandit - not yet supported */
1308 + { 0x1039, 0x0600, probe_sis }, /* 600 programatically same as 5600 */
1309 + { 0x1039, 0x0620, 0 }, /* 620 doesnt support ecc */
1310 + { 0x1039, 0x5600, probe_sis },
1312 + { 0x10b9, 0x1531, probe_aladdin4 },
1313 + { 0x10b9, 0x1541, probe_aladdin5 },
1315 + { 0x1106, 0x0305, probe_via }, /* vt8363 - kt133/km133 */
1316 + { 0x1106, 0x0391, probe_via }, /* vt8371 - kx133 */
1317 + { 0x1106, 0x0501, probe_via }, /* vt8501 - mvp4 */
1318 + { 0x1106, 0x0585, probe_via }, /* vt82c585 - vp/vpx */
1319 + { 0x1106, 0x0595, probe_via }, /* vt82c595 - vp2 */
1320 + { 0x1106, 0x0597, probe_via }, /* vt82c597 - vp3 */
1321 + { 0x1106, 0x0598, probe_via }, /* vt82c598 - mvp3 */
1322 + { 0x1106, 0x0691, probe_via }, /* vt82c691 - pro133/pro133a */
1323 + { 0x1106, 0x0693, probe_via }, /* vt82c693 - pro+ */
1324 + { 0x1106, 0x0694, probe_via }, /* vt82c694 - pro133a */
1326 + { 0x1166, 0x0008, probe_serverworks }, /* CNB20HE - serverset iii he */
1327 + { 0x1166, 0x0009, probe_serverworks }, /* serverset iii le */
1329 + { 0x8086, 0x1130, 0 }, /* 815 doesnt support ecc */
1330 + { 0x8086, 0x122d, 0 }, /* 430fx doesnt support ecc */
1331 + { 0x8086, 0x1237, probe_440fx },
1332 + { 0x8086, 0x1250, probe_430hx },
1333 + { 0x8086, 0x1A21, probe_840 },
1334 + { 0x8086, 0x1A30, probe_845 },
1335 + { 0x8086, 0x2530, probe_850 },
1336 + { 0x8086, 0x2531, probe_860 },
1337 + { 0x8086, 0x7030, 0 }, /* 430vx doesnt support ecc */
1338 + { 0x8086, 0x7120, 0 }, /* 810 doesnt support ecc */
1339 + { 0x8086, 0x7122, 0 },
1340 + { 0x8086, 0x7124, 0 }, /* 810e doesnt support ecc */
1341 + { 0x8086, 0x7180, probe_440lx }, /* also 440ex */
1342 + { 0x8086, 0x7190, probe_440bx }, /* also 440zx */
1343 + { 0x8086, 0x7192, probe_440bx }, /* also 440zx */
1344 + { 0x8086, 0x71A0, probe_440bx }, /* also 440gx */
1345 + { 0x8086, 0x71A2, probe_440bx }, /* also 440gx */
1346 + { 0x8086, 0x84C5, probe_450gx },
1350 +static int find_chipset(void) {
1352 + if (!pci_present()) {
1353 + printk(KERN_ERR "ECC: No PCI bus.\n");
1357 + while ((bridge = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, bridge)))
1360 + /* Direct reading of the pci config space of these is not
1361 + allowed in linux (eg it leaves no place for fixups and
1362 + other items); so replacing the following two lines with
1363 + those that follow immediately after it is a bugfix added by
1364 + RH. - arjanv@redhat.com 3/26/2002
1365 + pci_read_config_word(bridge, PCI_VENDOR_ID, &vendor);
1366 + pci_read_config_word(bridge, PCI_DEVICE_ID, &device);
1368 + vendor = bridge->vendor;
1369 + device = bridge->device;
1370 + while(probe_matrix[loop].vendor)
1372 + if( (vendor == probe_matrix[loop].vendor) &&
1373 + (device == probe_matrix[loop].device) )
1375 + if(probe_matrix[loop].check)
1377 + probe_matrix[loop].check();
1380 + printk(KERN_WARNING "ECC: Unsupported device %x:%x.\n", vendor, device);
1386 + printk(KERN_DEBUG "ECC: Unknown device %x:%x.\n", vendor, device);
1388 + printk(KERN_ERR "ECC: Can't find host bridge.\n");
1392 +static void ecc_fini(void) {
1395 + del_timer_sync(&ecctimer);
1396 +#ifdef CONFIG_PROC_FS
1397 + remove_proc_entry("ram", 0);
1399 + if (ecc_sysctl_header) {
1400 + unregister_sysctl_table(ecc_sysctl_header);
1401 + ecc_sysctl_header = NULL;
1405 + * If we are expecting to find errors in the logs, we need notification
1406 + * when the module is unloaded.
1408 + if (log_sbe || log_mbe || panic_on_mbe) {
1409 + printk("ECC: Unloaded\n");
1413 +static int ecc_init(void) {
1415 +#ifdef CONFIG_PROC_FS
1416 + struct proc_dir_entry *ent;
1418 + printk(KERN_INFO "ECC: monitor version %s\n", ECC_VER);
1420 + for (loop=0;loop<MAXBANKS;loop++) {
1421 + bank[loop].endaddr = 0;
1422 + bank[loop].sbecount = 0;
1423 + bank[loop].mbecount = 0;
1424 + bank[loop].eccmode = 0;
1425 + bank[loop].mtype = ECC_RESERVED;
1428 + if (!find_chipset()) {
1429 + printk("ECC: failed to find a supported memory controller\n");
1433 +#ifdef CONFIG_PROC_FS
1434 + ent = create_proc_entry("ram", S_IFREG | S_IRUGO, 0);
1437 + ent->read_proc = procfile_read;
1440 + ecc_sysctl_header = register_sysctl_table(ecc_root_table, 1);
1442 + init_timer(&ecctimer);
1443 + ecctimer.expires = jiffies + (HZ * poll_msec) / 1000;
1444 + ecctimer.function = (void *)&checkecc;
1445 + add_timer(&ecctimer);
1451 +int init_module(void) {
1452 + return ecc_init();
1454 +void cleanup_module(void) {
1457 +#ifdef MODULE_LICENSE
1458 +MODULE_LICENSE("GPL");