]> git.pld-linux.org Git - packages/kernel.git/blob - linux-2.4.20-ecc.patch
- added description of djurban's branch
[packages/kernel.git] / linux-2.4.20-ecc.patch
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
4 @@ -5,6 +5,7 @@
5  comment 'Character devices'
6  
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
11  fi
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
15 @@ -144,6 +144,7 @@
16  endif
17  
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
26 @@ -0,0 +1,1434 @@
27 +/*
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.
37 + */
38 +
39 +#define DEBUG  0
40 +
41 +#include <linux/config.h>
42 +#include <linux/version.h>
43 +#include <linux/module.h>
44 +
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>
50 +#include <asm/io.h>
51 +#include <linux/proc_fs.h>
52 +#include <linux/sysctl.h>
53 +#include <linux/kernel.h>
54 +#include <asm/uaccess.h>
55 +
56 +#define        ECC_VER "0.14 (Oct 10 2001)"
57 +
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;
63 +
64 +/* These are tunable by either module parameter or sysctl */
65 +int panic_on_mbe = 1;
66 +int log_mbe = 1;
67 +int log_sbe = 1;
68 +int poll_msec = 1000;
69 +
70 +#ifdef MODULE
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");
75 +#endif
76 +
77 +#define CTL_ECC 2740
78 +
79 +static ctl_table ecc_table[] = {
80 +       {1, "panic_on_mbe",
81 +               &panic_on_mbe, sizeof(int), 0644, NULL, &proc_dointvec},
82 +       {2, "log_mbe",
83 +               &log_mbe, sizeof(int), 0644, NULL, &proc_dointvec},
84 +       {3, "log_sbe",
85 +               &log_sbe, sizeof(int), 0644, NULL, &proc_dointvec},
86 +       {4, "poll_msec",
87 +               &poll_msec, sizeof(int), 0644, NULL, &proc_dointvec},
88 +       {0}
89 +};
90 +
91 +static ctl_table ecc_root_table[] = {
92 +       {CTL_DEBUG, "ecc", NULL, 0, 0555, ecc_table},
93 +       {0}
94 +};
95 +
96 +static struct ctl_table_header *ecc_sysctl_header = NULL;
97 +
98 +#define MAXBANKS 16
99 +
100 +#define I860_DUMPCONFIG 0
101 +
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); \
105 +} while(0)
106 +#define sbe_printk(fmt,args...) do { \
107 +    if (log_sbe) printk(KERN_WARNING "ECC: SBE " fmt,##args); \
108 +} while(0)
109 +
110 +#if     defined(NDEBUG)
111 +#define assert(EX) do { } while (0)
112 +#else
113 +#define assert(EX) do { \
114 +       if (!(EX)) printk("assertion failed: %s, %s::%d\n", \
115 +                       #EX, __FILE__, __LINE__); \
116 +       } while (0)
117 +#endif
118 +
119 +/* memory types */
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 */
130 +
131 +/* Memory bank info */
132 +static struct bankstruct
133 +{
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? */
140 +
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 */
148 +
149 +static struct ChipsetInfo
150 +{
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 */
155 +#if 0
156 +/*
157 + * I dont think we care about SERR at the moment.
158 + * We may if/when we hook into an NMI handler.
159 + */
160 +       int SERR;               /* SERR enabled? */
161 +       int SERR_MBE;           /* SERR on multi-bit error? */
162 +       int SERR_SBE;           /* SERR on single-bit error? */
163 +#endif
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 */
190 +} cs;
191 +
192 +static inline unsigned int pci_byte(int offset)
193 +{
194 +       u8 value;
195 +       pci_read_config_byte(bridge, offset, &value);
196 +       return value & 0xFF;
197 +}
198 +
199 +static inline unsigned int pci_word(int offset)
200 +{
201 +       u16 value;
202 +       pci_read_config_word(bridge, offset, &value);
203 +       return value;
204 +}
205 +
206 +static inline unsigned int pci_dword(int offset)
207 +{
208 +       u32 value;
209 +       pci_read_config_dword(bridge, offset, &value);
210 +       return value;
211 +}
212 +
213 +/* write all or some bits in a byte-register*/
214 +static inline void pci_write_bits8(int offset,u8 value,u8 mask)
215 +{ 
216 +        if (mask != 0xff){
217 +                u8 buf;
218 +                pci_read_config_byte(bridge,offset, &buf);
219 +                value &=mask;
220 +                buf &= ~mask;
221 +                value |= buf;
222 +        }
223 +        pci_write_config_byte(bridge,offset,value);
224 +}  
225 +
226 +static int find_row(unsigned long err_addr)
227 +{
228 +       int row = 0, loop;
229 +       for(loop=0; loop < MAXBANKS; loop++) {
230 +               if (err_addr < bank[loop].endaddr) {
231 +               row=loop;
232 +                       break;
233 +               }
234 +       }
235 +       return row;
236 +}
237 +
238 +/*
239 + *     generic ECC check routine
240 + *
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.
249 + */
250 +static void generic_check(void)
251 +{
252 +       int status = pci_byte(cs.MBE_flag_address);
253 +       if ((status >> cs.MBE_flag_shift) & cs.MBE_flag_mask)
254 +       {
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)
258 +               {
259 +                       cs.MBE_addr =
260 +                       ( pci_word(cs.MBE_err_address1 << cs.MBE_err_shift1) |
261 +                         pci_word(cs.MBE_err_address2 << cs.MBE_err_shift2) ) &
262 +                         cs.MBE_err_mask;
263 +                       mbe_printk("at memory address %lx\n", (long unsigned int)cs.MBE_addr);
264 +               }
265 +               scrub_needed = 2;
266 +               scrub_row = row;
267 +               bank[row].mbecount++;
268 +       }
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)
272 +       {
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)
276 +               {
277 +                       cs.SBE_addr =
278 +                       ( pci_word(cs.SBE_err_address1 << cs.SBE_err_shift1) |
279 +                         pci_word(cs.SBE_err_address2 << cs.SBE_err_shift2) ) &
280 +                         cs.SBE_err_mask;
281 +                       sbe_printk("at memory address %lx\n", (long unsigned int)cs.SBE_addr);
282 +               }
283 +               scrub_needed = 1;
284 +               scrub_row = row;
285 +               bank[row].sbecount++;
286 +       }
287 +}
288 +
289 +/* VIA specific error clearing */
290 +static void clear_via_err(void)
291 +{
292 +       pci_write_bits8(0x6f,0xff,0xff);
293 +       /* as scrubbing is unimplemented, we reset it here */
294 +       scrub_needed = 0;
295 +}
296 +
297 +/* unified VIA probe */
298 +static void probe_via(void)
299 +{
300 +       int loop, ecc_ctrl, dimmslots = 3, bankshift = 23;
301 +       int m_mem[] = { BANK_FPM, BANK_EDO, BANK_DDR, BANK_SDR };
302 +       switch (device) {
303 +               case 0x0391: /* VIA VT8371   - KX133            */
304 +                       dimmslots = 4;
305 +                       bankshift = 24;
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;
311 +                       break;
312 +               case 0x0501: /* VIA VT8501   - MVP4             */
313 +               case 0x0597: /* VIA VT82C597 - VP3              */
314 +               case 0x0598: /* VIA VT82C598 - MVP3             */
315 +                       cs.ecc_cap = ECC_CORRECT;
316 +                       break;
317 +               case 0x0694: /* VIA VT82C694XDP - Apollo PRO133A smp */
318 +                       dimmslots = 4;
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  */
324 +                       bankshift = 24;
325 +                       cs.ecc_cap = ECC_CORRECT;
326 +                       break;
327 +               case 0x0305: /* VIA VT8363   - KT133 - no ecc!! */
328 +                            /* VIA VT8363A  - KT133A (rev 8) - no ecc!! */
329 +                       bankshift = 24;
330 +                       cs.ecc_cap = ECC_NONE;
331 +                       break;
332 +               case 0x0585: /* VIA VT82C585 - VP,VPX,VPX/97    */
333 +               default:
334 +                       cs.ecc_cap = ECC_NONE;
335 +                       return;
336 +       }
337 +       ecc_ctrl = pci_byte(0x6E);
338 +       cs.ecc_mode = (ecc_ctrl>>7)&1 ? cs.ecc_cap : ECC_NONE;
339 +
340 +       cs.check = generic_check;
341 +       if (cs.ecc_mode != ECC_NONE) {
342 +               cs.clear_err = clear_via_err;
343 +               /* clear initial errors */
344 +               cs.clear_err();
345 +       }
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;
356 +
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++)
360 +       {
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;
365 +       }
366 +}
367 +
368 +static void check_serverworks(void)
369 +{
370 +       unsigned long mesr;
371 +       int row;
372 +
373 +       mesr = pci_dword(0x94); /* mesr0 */
374 +       row = (int)(mesr>>29)&0x7;
375 +       if((mesr>>31)&1)
376 +       {
377 +               mbe_printk("Detected in DRAM row %d\n", row);
378 +               scrub_needed |= 2;
379 +               bank[row].mbecount++;
380 +       }
381 +       if((mesr>>30)&1)
382 +       {
383 +               sbe_printk("Detected in DRAM row %d\n", row);
384 +               scrub_needed |= 1;
385 +               bank[row].sbecount++;
386 +       }
387 +       if (scrub_needed)
388 +       {
389 +               /*
390 +                * clear error flag bits that were set by writing 1 to them
391 +                * we hope the error was a fluke or something :)
392 +                */
393 +               unsigned long value = scrub_needed<<30;
394 +               pci_write_config_dword(bridge, 0x94, value);
395 +               scrub_needed = 0;
396 +       }
397 +
398 +       mesr = pci_dword(0x98); /* mesr1 */
399 +       row = (int)(mesr>>29)&0x7;
400 +       if((mesr>>31)&1)
401 +       {
402 +               mbe_printk("Detected in DRAM row %d\n", row);
403 +               scrub_needed |= 2;
404 +               bank[row].mbecount++;
405 +       }
406 +       if((mesr>>30)&1)
407 +       {
408 +               sbe_printk("Detected in DRAM row %d\n", row);
409 +               scrub_needed |= 1;
410 +               bank[row].sbecount++;
411 +       }
412 +       if (scrub_needed)
413 +       {
414 +               /*
415 +                * clear error flag bits that were set by writing 1 to them
416 +                * we hope the error was a fluke or something :)
417 +                */
418 +               unsigned long value = scrub_needed<<30;
419 +               pci_write_config_dword(bridge, 0x98, value);
420 +               scrub_needed = 0;
421 +        }
422 +}
423 +
424 +static void probe_serverworks(void)
425 +{
426 +       int loop, efcr, mccr;
427 +       switch (device) {
428 +               case 0x0008: /* serverworks iii he */
429 +               case 0x0009: /* serverworks iii le */
430 +                       cs.ecc_cap = ECC_AUTO;
431 +                       break;
432 +               default:
433 +                       cs.ecc_cap = ECC_NONE;
434 +                       return;
435 +       }
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;
439 +
440 +       cs.check = check_serverworks;
441 +
442 +       for(loop=0;loop<8;loop++)
443 +       {
444 +               bank[loop].mtype = BANK_UNKNOWN;
445 +               bank[loop].eccmode = cs.ecc_mode;
446 +                bank[loop].endaddr = 0;
447 +       }
448 +}
449 +
450 +/*
451 + * 450gx probing is buggered at the moment. help me obi-wan.
452 + */
453 +static void probe_450gx(void)
454 +{
455 +       int loop, dramc, merrcmd;
456 +       u32 nbxcfg;
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++)
463 +       {
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);
469 +       }
470 +       cs.ecc_cap = ECC_AUTO;
471 +       cs.ecc_mode = (merrcmd>>1)&1 ? ECC_AUTO : ECC_DETECT;
472 +
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;
484 +
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;
490 +
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;
496 +}
497 +
498 +/* there seems to be NO WAY to distinguish 440zx from 440bx!! >B( */
499 +static void probe_440bx(void)
500 +{
501 +       int loop, dramc, errcmd;
502 +       u32 nbxcfg;
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];
510 +
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;
522 +
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;
528 +
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;
534 +
535 +       for(loop=0;loop<8;loop++)
536 +       {
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);
542 +       }
543 +}
544 +
545 +/* no way to tell 440ex from 440lx!? grr. */
546 +static void probe_440lx(void)
547 +{
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];
557 +
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;
569 +
570 +       for(loop=0;loop<8;loop++)
571 +       {
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);
575 +       }
576 +}
577 +
578 +static void probe_440fx(void)
579 +{
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++)
587 +       {
588 +               bank[loop].endaddr=(unsigned long)pci_byte(0x60+loop)<<23;
589 +               bank[loop].mtype = m_mem[(drt>>(loop*2))&3];
590 +       }
591 +       cs.ecc_cap = ECC_CORRECT;
592 +       cs.ecc_mode = ddim[(pmccfg>>4)&3];
593 +
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;
605 +}
606 +
607 +static void probe_430hx(void)
608 +{
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;
616 +
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;
628 +
629 +       for(loop=0;loop<8;loop++)
630 +       {
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;
634 +       }
635 +}
636 +
637 +static void check_840(void)
638 +{
639 +       int errsts = pci_word(0xE2);
640 +       if ((errsts>>9) & 1)
641 +       {
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);
645 +               scrub_needed = 2;
646 +               scrub_row = find_row(eap);
647 +               bank[scrub_row].mbecount++;
648 +       }
649 +       if ((errsts>>10) & 1)
650 +       {
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);
654 +               scrub_needed = 1;
655 +               scrub_row = find_row(eap);
656 +               bank[scrub_row].sbecount++;
657 +       }
658 +}
659 +
660 +static void probe_840(void)
661 +{
662 +       int loop, mchcfg;
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];
667 +
668 +       cs.check = check_840;
669 +
670 +       for(loop=0;loop<16;loop++)
671 +       {
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;
675 +       }
676 +}
677 +
678 +static void check_845(void)
679 +{
680 +       int errsts = pci_word(0xC8);
681 +       if ((errsts>>1) & 1)
682 +       {
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);
687 +               scrub_needed = 2;
688 +               scrub_row = find_row(eap);
689 +               bank[scrub_row].mbecount++;
690 +       }
691 +       if (errsts & 1)
692 +       {
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);
697 +               scrub_needed = 1;
698 +               scrub_row = find_row(eap);
699 +               bank[scrub_row].sbecount++;
700 +       }
701 +}
702 +
703 +static void probe_845(void)
704 +{
705 +       int loop;
706 +       u32 drc;
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];
711 +
712 +       cs.check = check_845;
713 +
714 +       for(loop=0;loop<8;loop++)
715 +       {
716 +               bank[loop].endaddr=(unsigned long)pci_byte(0x60+loop)<<24;
717 +               bank[loop].mtype = BANK_SDR;
718 +               bank[loop].eccmode = cs.ecc_mode;
719 +       }
720 +}
721 +
722 +static void check_850(void)
723 +{
724 +       int errsts = pci_word(0xC8);
725 +       if ((errsts>>1) & 1)
726 +       {
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);
731 +               scrub_needed = 2;
732 +               scrub_row = find_row(eap);
733 +               bank[scrub_row].mbecount++;
734 +       }
735 +       if (errsts & 1)
736 +       {
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);
741 +               scrub_needed = 1;
742 +               scrub_row = find_row(eap);
743 +               bank[scrub_row].sbecount++;
744 +       }
745 +}
746 +
747 +static void probe_850(void)
748 +{
749 +       int loop;
750 +       int mchcfg;
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];
755 +
756 +       cs.check = check_850;
757 +
758 +       for(loop=0;loop<16;loop++)
759 +       {
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;
763 +       }
764 +}
765 +
766 +/* 860 specific error clearing */
767 +static void clear_860_err(void)
768 +{
769 +       pci_write_bits8(0xc8,0x03,0x03);
770 +       /* as scrubbing is unimplemented, we reset it here */
771 +       scrub_needed = 0;
772 +       cs.clear_err = 0;
773 +}
774 +
775 +static void check_860(void)
776 +{
777 +       int errsts = pci_word(0xC8);
778 +       if ((errsts>>1) & 1)
779 +       {
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");
785 +               scrub_needed = 2;
786 +               scrub_row = find_row(eap);
787 +               bank[scrub_row].mbecount++;
788 +               cs.clear_err = clear_860_err;
789 +       }
790 +       if (errsts & 1)
791 +       {
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");
797 +               scrub_needed = 1;
798 +               scrub_row = find_row(eap);
799 +               bank[scrub_row].sbecount++;
800 +               cs.clear_err = clear_860_err;
801 +       }
802 +       /* 
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
807 +        */
808 +       if (errsts & 0xfc)
809 +               panic("ECC: MCH ERRSTS register contains 0x%x\n", errsts);
810 +}
811 +
812 +#if    I860_DUMPCONFIG
813 +void info_860(void)
814 +{
815 +       int i;
816 +
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)
821 +                       printk("\n");
822 +       }
823 +       printk("MCH Configuration Register: MCHCFG=%-4.4x\n", pci_word(0x50));
824 +       printk("Fixed DRAM Hole Control Register: FDHC=%-2.2x\n", 
825 +                       pci_byte(0x58));
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)
830 +                       printk("\n");
831 +       }
832 +       printk("\n");
833 +       printk("RDRAM Device Pool Sizing Register: RDPS=%-2.2x\n", 
834 +                       pci_byte(0x88));
835 +       printk("RDRAM Device Init Control Management Register: RICM=%-8.8x\n", 
836 +                       pci_dword(0x94));
837 +       printk("System Management RAM Control Register: SMRAM=%-2.2x\n",
838 +                       pci_byte(0x9D));
839 +       printk("Extended System Mgmt RAM Control Register: ESMRAMC=%-2.2x\n",
840 +                       pci_byte(0x9E));
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",
847 +                       pci_word(0xDC));
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));
850 +}
851 +#else
852 +void info_860(void)
853 +{
854 +       printk("ECC: Intel 860 MCH probed successfully\n");
855 +}
856 +#endif
857 +
858 +static void probe_860(void)
859 +{
860 +       int loop;
861 +       u32 drc;
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];
866 +
867 +       cs.check = check_860;
868 +
869 +       for(loop=0;loop<MAXBANKS;loop++)
870 +       {
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);
876 +       }
877 +       }
878 +       clear_860_err(); /* start off with a clean slate */
879 +       info_860();
880 +}
881 +
882 +static void check_amd751(void)
883 +{
884 +       int eccstat = pci_word(0x58);
885 +        int csbits = eccstat & 0x3F;
886 +        int row;
887 +        switch (csbits)
888 +       {
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;
895 +               default: row = 6;
896 +       }
897 +       if(((eccstat>>8)&3) == 1)
898 +       {
899 +               mbe_printk("Detected in DRAM row %d\n", row);
900 +               scrub_needed=2;
901 +               bank[row].mbecount++;
902 +       }
903 +       if(((eccstat>>8)&3) == 2)
904 +       {
905 +               sbe_printk("Detected in DRAM row %d\n", row);
906 +               scrub_needed=1;
907 +               bank[row].sbecount++;
908 +       }
909 +       if(((eccstat>>8)&3) == 3)
910 +       {
911 +               mbe_printk("and SBE Detected in DRAM row %d\n", row);
912 +               scrub_needed=1;
913 +               bank[row].sbecount++;
914 +       }
915 +       if (scrub_needed)
916 +       {
917 +               /*
918 +                * clear error flag bits that were set by writing 0 to them
919 +                * we hope the error was a fluke or something :)
920 +                */
921 +               int value = eccstat & 0xFCFF;
922 +               pci_write_config_word(bridge, 0x58, value);
923 +               scrub_needed = 0;
924 +        }
925 +}
926 +
927 +static void probe_amd751(void)
928 +{
929 +       int loop;
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++)
934 +       {
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? */
944 +               }
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;
948 +       }
949 +}
950 +
951 +static void check_amd76x(void)
952 +{
953 +       unsigned long eccstat = pci_dword(0x48);
954 +       if(eccstat & 0x10)
955 +       {
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);
959 +               scrub_needed |= 2;
960 +               bank[row].mbecount++;
961 +       }
962 +       if(eccstat & 0x20)
963 +       {
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);
967 +               scrub_needed |= 1;
968 +               bank[row].sbecount++;
969 +       }
970 +       if (scrub_needed)
971 +       {
972 +               /*
973 +                * clear error flag bits that were set by writing 0 to them
974 +                * we hope the error was a fluke or something :)
975 +                */
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);
982 +               scrub_needed = 0;
983 +        }
984 +}
985 +
986 +static void probe_amd76x(void)
987 +{
988 +       static const int modetab[] = {ECC_NONE, ECC_DETECT, ECC_CORRECT, ECC_AUTO};
989 +       int loop;
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;
994 +
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++)
998 +       {
999 +               unsigned long r = pci_dword(0xc0+(loop*4));
1000 +               bank[loop].mtype = r & 1 ? BANK_DDR : BANK_EMPTY;
1001 +               if (r & 1)
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;
1006 +       }
1007 +}
1008 +
1009 +/* SiS */
1010 +void probe_sis(void)
1011 +{
1012 +       int loop;
1013 +       u32 endaddr;
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 };
1019 +
1020 +       cs.ecc_cap = ECC_CORRECT;
1021 +
1022 +        cs.check = generic_check;
1023 +
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;
1029 +
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;
1035 +
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;
1041 +
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;
1047 +
1048 +       endaddr = 0;
1049 +       for(loop=0;loop<3;loop++)
1050 +       {
1051 +               /* populated bank? */
1052 +               if ((pci_byte(0x63)>>loop)&1)
1053 +               {
1054 +                       u32 banksize;
1055 +                       int mtype = pci_byte(0x60+loop);
1056 +
1057 +                       bank[loop*2].mtype = m_mem[(mtype>>6)&3];
1058 +                       if(bank[loop*2].mtype == BANK_SDR)
1059 +                       {
1060 +                               banksize = sdramsize[mtype&15]*1024;
1061 +                       } else {
1062 +                               banksize = dramsize[mtype&15]*1024;
1063 +                       }
1064 +                       endaddr += banksize;
1065 +                       bank[loop*2].endaddr = endaddr;
1066 +                       /* double sided dimm? */
1067 +                       if ((mtype>>5)&1)
1068 +                       {
1069 +                               bank[(loop*2)+1].mtype = bank[loop*2].mtype;
1070 +                               endaddr += banksize;
1071 +                               bank[(loop*2)+1].endaddr = endaddr;
1072 +                       }
1073 +               } else {
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;
1078 +               }
1079 +       }
1080 +       cs.ecc_mode = ECC_NONE;
1081 +       for(loop=0;loop<6;loop++)
1082 +       {
1083 +               int eccmode = (pci_byte(0x74)>>loop)&1;
1084 +               bank[loop].eccmode = eccmode;
1085 +               if(eccmode)
1086 +                       cs.ecc_mode = ECC_CORRECT;
1087 +       }
1088 +}
1089 +
1090 +/* ALi */
1091 +void probe_aladdin4(void)
1092 +{
1093 +       int loop;
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;
1097 +
1098 +        cs.check = generic_check;
1099 +
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;
1105 +
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;
1111 +
1112 +       for(loop=0;loop<8;loop++)
1113 +       {
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;
1118 +               } else {
1119 +                       bank[loop].eccmode = 0;
1120 +               }
1121 +       }
1122 +}
1123 +
1124 +void probe_aladdin5(void)
1125 +{
1126 +       int loop;
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;
1130 +
1131 +        cs.check = generic_check;
1132 +
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;
1138 +
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;
1144 +
1145 +       for(loop=0;loop<8;loop++)
1146 +       {
1147 +               /* DBxCII not disabled address mapping? */
1148 +               if(pci_byte(0x61+(loop*2))&0xF0)
1149 +               {
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;
1155 +                       } else {
1156 +                               bank[loop].eccmode = 0;
1157 +                       }
1158 +               }
1159 +       }
1160 +}
1161 +
1162 +#if 0
1163 +/*
1164 + * memory scrubber routines, not ready to be used yet...
1165 + */
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;
1171 +
1172 +char buff[8192] = {0,};
1173 +
1174 +/*
1175 + * Michael's page scrubber routine
1176 + */
1177 +void scrub_page(unsigned long volatile * p)
1178 +{
1179 +       int i;
1180 +       int len, err = 0;
1181 +       unsigned long *q;
1182 +       q = (unsigned long *) ((((int)buff)+4095) & ~4095);
1183 +
1184 +       if (((int)p) >= 640 * 1024 && ((int)p) < 1024 * 1024)
1185 +               return;
1186 +
1187 +       cli();  /* kill interrupts */
1188 +       err = pci_byte(0x91);
1189 +       outb(0x11, PCI_DATA + 1); /* clear the memory error indicator */
1190 +       
1191 +       for (i = 0; i < step / 4 ; ++i)
1192 +               q[i] = p[i];
1193 +       for (i = 0; i < step / 4 ; ++i)
1194 +               p[i] = q[i];
1195 +       err = inb(PCI_DATA + 1);
1196 +       sti();
1197 +       if (err & 0x11) {
1198 +               printk(KERN_ERR "ECC: Memory error @ %08x (0x%02x)\n", p, err);
1199 +               return 1;
1200 +       }
1201 +       return 0;
1202 +}
1203 +
1204 +void scrub(void)
1205 +{
1206 +       int i,j = 0;
1207 +       for (i = 0; i < pages; ++i) {
1208 +               j = scrub_page(start);
1209 +               start += step;
1210 +       }
1211 +       if (!j) {
1212 +               /*
1213 +                * Hmm... This is probably a very bad situation.
1214 +                */
1215 +               printk(KERN_ERR "ECC: Scrubbed, no errors found?!\n");
1216 +               scrub_needed=0;
1217 +               return;
1218 +       }
1219 +       if (scrub_needed==2) {
1220 +               /*
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"
1225 +                */
1226 +               scrub_needed=0;
1227 +       }
1228 +}
1229 +#endif
1230 +
1231 +int unload = 0;
1232 +/*
1233 + * Check ECC status every second.
1234 + * SMP safe, doesn't use NMI, and auto-rate-limits.
1235 + */
1236 +void checkecc(void) {
1237 +        MOD_INC_USE_COUNT;
1238 +       if (!scrub_needed)
1239 +               if (cs.check)
1240 +                       cs.check();
1241 +       if (cs.clear_err)
1242 +               cs.clear_err();
1243 +       init_timer(&ecctimer);
1244 +       ecctimer.expires = jiffies + (HZ * poll_msec) / 1000;
1245 +       ecctimer.function = (void *)&checkecc;
1246 +       if (!unload)
1247 +               add_timer(&ecctimer);
1248 +       MOD_DEC_USE_COUNT;
1249 +}
1250 +
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)
1254 +{
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;
1261 +       int loop;
1262 +       int len = 0;
1263 +
1264 +       if (offset)
1265 +               return 0;
1266 +
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);
1279 +                       mem_end=last_mem;
1280 +               }
1281 +       }
1282 +       len += sprintf(memstat + len, "Total\t%dM\n", (int)(mem_end>>20));
1283 +
1284 +       if (len <= buffer_length)
1285 +               *eof = 1;
1286 +       else
1287 +               len = buffer_length;
1288 +       return len;
1289 +}
1290 +#endif
1291 +
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 */
1296 +};
1297 +
1298 +static struct pci_probe_matrix probe_matrix[] = {
1299 +       /* AMD */
1300 +       { 0x1022, 0x7006, probe_amd751 },
1301 +       { 0x1022, 0x700c, probe_amd76x }, /* amd762 2 CPU */
1302 +       { 0x1022, 0x700e, probe_amd76x }, /* amd761 1 CPU */
1303 +       /* Motorola */
1304 +       { 0x1057, 0x4802, 0 }, /* falcon - not yet supported */
1305 +       /* Apple */
1306 +       { 0x106b, 0x0001, 0 }, /* bandit - not yet supported */
1307 +       /* SiS */
1308 +       { 0x1039, 0x0600, probe_sis }, /* 600 programatically same as 5600 */
1309 +       { 0x1039, 0x0620, 0 }, /* 620 doesnt support ecc */
1310 +       { 0x1039, 0x5600, probe_sis },
1311 +       /* ALi */
1312 +       { 0x10b9, 0x1531, probe_aladdin4 },
1313 +       { 0x10b9, 0x1541, probe_aladdin5 },
1314 +       /* VIA */
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 */
1325 +       /* Serverworks */
1326 +       { 0x1166, 0x0008, probe_serverworks }, /* CNB20HE - serverset iii he */
1327 +       { 0x1166, 0x0009, probe_serverworks }, /* serverset iii le */
1328 +       /* Intel */
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 },
1347 +       { 0, 0, 0 }
1348 +};
1349 +
1350 +static int find_chipset(void) {
1351 +
1352 +       if (!pci_present()) {
1353 +               printk(KERN_ERR "ECC: No PCI bus.\n");
1354 +               return 0;
1355 +       }
1356 +
1357 +       while ((bridge = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, bridge)))
1358 +       {
1359 +               int loop = 0;
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);
1367 +               */
1368 +               vendor = bridge->vendor;
1369 +               device = bridge->device;
1370 +               while(probe_matrix[loop].vendor)
1371 +               {
1372 +                       if( (vendor == probe_matrix[loop].vendor) &&
1373 +                           (device == probe_matrix[loop].device) )
1374 +                       {
1375 +                               if(probe_matrix[loop].check)
1376 +                               {
1377 +                                       probe_matrix[loop].check();
1378 +                                       return 1;
1379 +                               } else {
1380 +                                       printk(KERN_WARNING "ECC: Unsupported device %x:%x.\n", vendor, device);
1381 +                                       return 0;
1382 +                               }
1383 +                       }
1384 +                       loop++;
1385 +               }
1386 +               printk(KERN_DEBUG "ECC: Unknown device %x:%x.\n", vendor, device);
1387 +       }
1388 +       printk(KERN_ERR "ECC: Can't find host bridge.\n");
1389 +       return 0;
1390 +}
1391 +
1392 +static void ecc_fini(void) {
1393 +        unload = 1;
1394 +        wmb();
1395 +        del_timer_sync(&ecctimer);
1396 +#ifdef CONFIG_PROC_FS
1397 +       remove_proc_entry("ram", 0);
1398 +#endif
1399 +       if (ecc_sysctl_header) {
1400 +               unregister_sysctl_table(ecc_sysctl_header);
1401 +               ecc_sysctl_header = NULL;
1402 +       }
1403 +
1404 +       /* 
1405 +        * If we are expecting to find errors in the logs, we need notification
1406 +        * when the module is unloaded.
1407 +        */
1408 +       if (log_sbe || log_mbe || panic_on_mbe) {
1409 +               printk("ECC: Unloaded\n");
1410 +       }
1411 +}
1412 +
1413 +static int ecc_init(void) {
1414 +       int loop;
1415 +#ifdef CONFIG_PROC_FS
1416 +       struct proc_dir_entry *ent;
1417 +#endif
1418 +       printk(KERN_INFO "ECC: monitor version %s\n", ECC_VER);
1419 +
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;
1426 +       }
1427 +
1428 +       if (!find_chipset()) {
1429 +               printk("ECC: failed to find a supported memory controller\n");
1430 +               return -ENODEV;
1431 +       }
1432 +
1433 +#ifdef CONFIG_PROC_FS
1434 +       ent = create_proc_entry("ram", S_IFREG | S_IRUGO, 0);
1435 +       if (ent) {
1436 +               ent->nlink = 1;
1437 +               ent->read_proc = procfile_read;
1438 +       }
1439 +#endif
1440 +        ecc_sysctl_header = register_sysctl_table(ecc_root_table, 1);
1441 +
1442 +       init_timer(&ecctimer);
1443 +       ecctimer.expires = jiffies + (HZ * poll_msec) / 1000;
1444 +       ecctimer.function = (void *)&checkecc;
1445 +       add_timer(&ecctimer);
1446 +
1447 +       return 0; 
1448 +}
1449 +
1450 +#ifdef MODULE
1451 +int init_module(void) {
1452 +       return ecc_init();
1453 +}
1454 +void cleanup_module(void) {
1455 +       ecc_fini();
1456 +}
1457 +#ifdef MODULE_LICENSE
1458 +MODULE_LICENSE("GPL");
1459 +#endif
1460 +#endif
This page took 0.190131 seconds and 3 git commands to generate.