--- ecc-0.12/Makefile Wed Sep 13 01:19:07 2000 +++ ecc-0.12-jh/Makefile Thu Apr 12 07:39:39 2001 @@ -1,11 +1,16 @@ # ecc -CC= gcc -CFLAGS= -O2 -Wall -LINK_FLAGS= ecc.c +# Change this to gcc if you do not have kgcc defined. kgcc is the +# default to remind RedHat users not to use the shipped compiler for +# kernel compilation, though this module probably would work with it. +CC= kgcc -ecc.o: ecc.c - $(CC) $(CFLAGS) -c -o $@ $^ +# Kernel headers should not be linked to /usr/include any more. +# Therefore we must explicitly include the current kernel source in +# include file path. +CFLAGS= -O2 -Wall -I/usr/src/linux/include + +ecc.o: ecc.c clean: - rm -f *.o ecc + rm -f ecc.o --- ecc-0.12/README.chipsets Tue Oct 26 02:49:05 1999 +++ ecc-0.12-jh/README.chipsets Thu Apr 12 02:49:49 2001 @@ -18,6 +18,8 @@ --- 751 (Athlon) ECC is all-or-none, only SDRAM is supported. +761 (Athlon) +ECC is all-or-none, only DDR-SDRAM is supported. Intel ----- --- ecc-0.12/ecc.c Wed Sep 13 02:32:48 2000 +++ ecc-0.12-jh/ecc.c Thu Apr 12 08:35:33 2001 @@ -19,7 +19,7 @@ #include #include -#define ECC_VER "0.12 (Apr 11 2000)" +#define ECC_VER "0.12-jh (Apr 12 2001)" static struct timer_list ecctimer; static struct pci_dev *bridge = NULL; @@ -97,6 +97,9 @@ int SBE_err_flag; /* SBE error flag */ int SBE_err_row; /* SBE row */ u32 SBE_addr; /* address of last SBE */ + int clear_errors; /* should we clear the error bits? */ + int MBE_clear_value; /* value to write to MBE flag to clear it */ + int SBE_clear_value; /* value to write to SBE flag to clear it */ } cs; unsigned int pci_byte(int offset) @@ -134,10 +137,13 @@ */ void generic_check() { - int status = pci_byte(cs.MBE_flag_address); - if ((status >> cs.MBE_flag_shift) & cs.MBE_flag_mask) + int MBE_status = pci_byte(cs.MBE_flag_address); + int SBE_status; + int MBE_set = 0; + int SBE_set = 0; + if ((MBE_status >> cs.MBE_flag_shift) & cs.MBE_flag_mask) { - int row = (status >> cs.MBE_row_shift) & cs.MBE_row_mask; + int row = (MBE_status >> cs.MBE_row_shift) & cs.MBE_row_mask; printk("<1>ECC: MBE detected in DRAM row %d\n", row); if (cs.MBE_err_address1) { @@ -147,15 +153,18 @@ cs.MBE_err_mask; printk("<1>ECC: MBE at memory address %lx\n", (long unsigned int)cs.MBE_addr); } + MBE_set = 1; scrub_needed = 2; scrub_row = row; bank[row].mbecount++; } if (cs.SBE_flag_address != cs.MBE_flag_address) - status = pci_byte(cs.SBE_flag_address); - if ((status >> cs.SBE_flag_shift) & cs.SBE_flag_mask) + SBE_status = pci_byte(cs.SBE_flag_address); + else + SBE_status = MBE_status; + if ((SBE_status >> cs.SBE_flag_shift) & cs.SBE_flag_mask) { - int row = (status >> cs.SBE_row_shift) & cs.SBE_row_mask; + int row = (SBE_status >> cs.SBE_row_shift) & cs.SBE_row_mask; printk("<1>ECC: SBE detected in DRAM row %d\n", row); if (cs.SBE_err_address1) { @@ -165,10 +174,24 @@ cs.SBE_err_mask; printk("<1>ECC: SBE at memory address %lx\n", (long unsigned int)cs.SBE_addr); } + SBE_set = 1; scrub_needed = 1; scrub_row = row; bank[row].sbecount++; } + if (cs.clear_errors) { + if (MBE_set) { + MBE_status = (MBE_status & ~(cs.MBE_flag_mask << cs.MBE_flag_shift)) | (cs.MBE_clear_value << cs.MBE_flag_shift); + if (cs.SBE_flag_address != cs.MBE_flag_address || !SBE_set) + pci_write_config_byte (bridge, cs.MBE_flag_address, MBE_status); + } + if (SBE_set) { + if (cs.SBE_flag_address == cs.MBE_flag_address) + SBE_status = MBE_status; + SBE_status = (SBE_status & ~(cs.SBE_flag_mask << cs.SBE_flag_shift)) | (cs.SBE_clear_value << cs.SBE_flag_shift); + pci_write_config_byte (bridge, cs.SBE_flag_address, SBE_status); + } + } } /* unified VIA probe */ @@ -214,6 +237,8 @@ cs.SBE_row_shift = 0; cs.SBE_row_mask = 7; + cs.clear_errors = 0; /* until we know what to do */ + for(loop=0;loop<6;loop++) bank[loop].endaddr = (unsigned long)pci_byte(0x5a+loop)<B( */ @@ -312,6 +339,10 @@ cs.SBE_err_shift2 = 16; cs.SBE_err_mask = 0xFFFFF000; + cs.clear_errors = 1; + cs.MBE_clear_value = 1; + cs.SBE_clear_value = 1; + for(loop=0;loop<8;loop++) { bank[loop].endaddr=(unsigned long)pci_byte(0x60+loop)<<23; @@ -347,6 +378,8 @@ cs.SBE_row_shift = 1; cs.SBE_row_mask = 7; + cs.clear_errors = 0; /* until we know what to do */ + for(loop=0;loop<8;loop++) { bank[loop].endaddr = (unsigned long)pci_byte(0x60+loop)<<23; @@ -382,6 +415,8 @@ cs.SBE_flag_mask = 1; cs.SBE_row_shift = 1; cs.SBE_row_mask = 7; + + cs.clear_errors = 0; /* until we know what to do */ } void probe_430hx() @@ -406,6 +441,10 @@ cs.SBE_row_shift = 1; cs.SBE_row_mask = 7; + cs.clear_errors = 1; + cs.MBE_clear_value = 1; + cs.SBE_clear_value = 1; + for(loop=0;loop<8;loop++) { bank[loop].endaddr=(unsigned long)pci_byte(0x60+loop)<<22; @@ -448,7 +487,42 @@ */ int value = eccstat & 0xFCFF; pci_write_config_word(bridge, 0x58, value); - scrub_needed = 0; + } +} + +void check_amd761() +{ + unsigned long eccstat = pci_dword(0x48); + int MBE_set = 0; + int SBE_set = 0; + if(eccstat & 0x10) + { + /* bits 7-4 of eccstat indicate the row the MBE occurred. */ + int row = (eccstat >> 4) & 0xf; + printk("<1>ECC: MBE Detected in DRAM row %d\n", row); + MBE_set = 1; + scrub_needed = 2; + bank[row].mbecount++; + } + if(eccstat & 0x20) + { + /* bits 3-0 of eccstat indicate the row the SBE occurred. */ + int row = eccstat & 0xf; + printk("<1>ECC: SBE Detected in DRAM row %d\n", row); + SBE_set = 1; + scrub_needed = 1; + bank[row].sbecount++; + } + if (MBE_set || SBE_set) + { + /* + * clear error flag bits that were set by writing 0 to them + */ + if (MBE_set) + eccstat &= ~0x10; + if (SBE_set) + eccstat &= ~0x20; + pci_write_config_dword(bridge, 0x48, eccstat); } } @@ -462,6 +536,7 @@ cs.ecc_cap = ECC_CORRECT; cs.ecc_mode = (pci_byte(0x5a)>>2)&1 ? ECC_CORRECT : ECC_NONE; cs.check = check_amd751; + cs.clear_errors = 1; for(loop=0;loop<6;loop++) { bank[loop].endaddr=(unsigned long)pci_byte(0x41+(loop*2))<<23; @@ -472,6 +547,31 @@ } } +void probe_amd761() +{ + static const int modetab[] = {ECC_NONE, ECC_DETECT, ECC_CORRECT, ECC_AUTO}; + int loop; + unsigned long addr = 0; + cs.ecc_cap = ECC_AUTO; + cs.ecc_mode = modetab [(pci_dword(0x48)>>10)&3]; + cs.check = check_amd761; + cs.clear_errors = 1; + + /* create fake end addresses, as the chipset is capable of + matching addresses to banks in random order */ + + for(loop=0;loop<8;loop++) + { + unsigned long r = pci_dword(0xc0+(loop*4)); + bank[loop].mtype = r & 1 ? BANK_DDR : BANK_EMPTY; + if (r & 1) + addr += ((r & 0xff80) << 16) + 0x800000; + bank[loop].endaddr=addr; + /* no per-bank register, assumed same for all banks? */ + bank[loop].eccmode = cs.ecc_mode != ECC_NONE; + } +} + /* SiS */ void probe_sis() { @@ -511,6 +611,8 @@ cs.SBE_err_shift2 = 16; cs.MBE_err_mask = 0xFFFFF000; + cs.clear_errors = 0; /* until we know what to do */ + endaddr = 0; for(loop=0;loop<3;loop++) { @@ -575,6 +677,8 @@ cs.SBE_row_shift = 1; cs.SBE_row_mask = 7; + cs.clear_errors = 0; /* until we know what to do */ + for(loop=0;loop<8;loop++) { bank[loop].endaddr = (unsigned long)(pci_byte(0x61+(loop*2))&15)<<27|(pci_byte(0x60+(loop*2))<<20); @@ -608,6 +712,8 @@ cs.SBE_row_shift = 1; cs.SBE_row_mask = 7; + cs.clear_errors = 0; /* until we know what to do */ + for(loop=0;loop<8;loop++) { /* DBxCII not disabled address mapping? */ @@ -702,6 +808,24 @@ if (!scrub_needed) if (cs.check) cs.check(); + /* + * With parity or just error checking, it is no use to try + * scrubbing. With auto mode, it is not needed. + */ + if (scrub_needed + && cs.clear_errors + && (ECC_PARITY == cs.ecc_mode + || ECC_DETECT == cs.ecc_mode + || ECC_AUTO == cs.ecc_mode)) + scrub_needed = 0; + if (scrub_needed) + /* + * Replace this with the scrubbing routines. For now, + * if clearing errors has been done in the checking + * routine, we can enable detecing further errors. + */ + if (cs.clear_errors) + scrub_needed = 0; init_timer(&ecctimer); ecctimer.expires = jiffies + HZ; ecctimer.function = (void *)&checkecc; @@ -760,6 +884,7 @@ static struct pci_probe_matrix probe_matrix[] = { /* AMD */ { 0x1022, 0x7006, probe_amd751 }, + { 0x1022, 0x700e, probe_amd761 }, /* Motorola */ { 0x1057, 0x4802, 0 }, /* falcon - not yet supported */ /* Apple */