blob: 31e3e4b959581f8f44755316c34b91640a3fc43b [file] [log] [blame]
Martin Roth9b1b3352016-02-24 12:27:06 -08001/* error.c - MemTest-86 Version 4.1
2 *
3 * Released under version 2 of the Gnu Public License.
4 * By Chris Brady
5 */
6#include "stddef.h"
7#include "stdint.h"
8#include "test.h"
9#include "config.h"
10#include "cpuid.h"
11#include "smp.h"
12#include "dmi.h"
13#include "controller.h"
14
15extern int dmi_err_cnts[MAX_DMI_MEMDEVS];
16extern int beepmode;
17extern short dmi_initialized;
18extern struct cpu_ident cpu_id;
19extern struct barrier_s *barr;
20extern int test_ticks, nticks;
21extern struct tseq tseq[];
22extern volatile int test;
23void poll_errors();
24extern int num_cpus;
25
26static void update_err_counts(void);
27static void print_err_counts(void);
28static void common_err();
29static int syn, chan, len=1;
30
31/*
32 * Display data error message. Don't display duplicate errors.
33 */
34void error(ulong *adr, ulong good, ulong bad)
35{
Martin Roth4dcd13d2016-02-24 13:53:07 -080036
Martin Roth9b1b3352016-02-24 12:27:06 -080037 ulong xor;
38
39 spin_lock(&barr->mutex);
Martin Roth4dcd13d2016-02-24 13:53:07 -080040
Martin Roth9b1b3352016-02-24 12:27:06 -080041 xor = good ^ bad;
42
43#ifdef USB_WAR
44 /* Skip any errrors that appear to be due to the BIOS using location
45 * 0x4e0 for USB keyboard support. This often happens with Intel
46 * 810, 815 and 820 chipsets. It is possible that we will skip
47 * a real error but the odds are very low.
48 */
49 if ((ulong)adr == 0x4e0 || (ulong)adr == 0x410) {
50 return;
51 }
52#endif
53
54 /* A sporadic bug exists in test #6, with SMP enabled, that
55 * reports false positives on < 65K-0.5MB range. I was
56 * not able to solve this. After investigations, it seems
Martin Roth4dcd13d2016-02-24 13:53:07 -080057 * related to a BIOS issue similiar to the one solved by
Martin Roth9b1b3352016-02-24 12:27:06 -080058 * USB_WAR, but for MP Table.
59 */
Martin Roth4dcd13d2016-02-24 13:53:07 -080060 /* Solved
61 if (test == 6 && (ulong)adr <= 0x07FFFF && num_cpus > 1)
Martin Roth9b1b3352016-02-24 12:27:06 -080062 {
63 cprint(6,78,"-"); // Debug
64 return;
65 }
66 */
Martin Roth4dcd13d2016-02-24 13:53:07 -080067
Martin Roth9b1b3352016-02-24 12:27:06 -080068 common_err(adr, good, bad, xor, 0);
69 spin_unlock(&barr->mutex);
70}
71
72
73
74/*
75 * Display address error message.
76 * Since this is strictly an address test, trying to create BadRAM
77 * patterns does not make sense. Just report the error.
78 */
79void ad_err1(ulong *adr1, ulong *mask, ulong bad, ulong good)
80{
81 spin_lock(&barr->mutex);
82 common_err(adr1, good, bad, (ulong)mask, 1);
83 spin_unlock(&barr->mutex);
84}
85
86/*
87 * Display address error message.
88 * Since this type of address error can also report data errors go
89 * ahead and generate BadRAM patterns.
90 */
91void ad_err2(ulong *adr, ulong bad)
92{
93 spin_lock(&barr->mutex);
94 common_err(adr, (ulong)adr, bad, ((ulong)adr) ^ bad, 0);
95 spin_unlock(&barr->mutex);
96}
97
98static void update_err_counts(void)
99{
100 if (beepmode){
101 beep(600);
102 beep(1000);
103 }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800104
Martin Roth9b1b3352016-02-24 12:27:06 -0800105 if (v->pass && v->ecount == 0) {
106 cprint(LINE_MSG, COL_MSG,
107 " ");
108 }
109 ++(v->ecount);
110 tseq[test].errors++;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800111
Martin Roth9b1b3352016-02-24 12:27:06 -0800112}
113
114static void print_err_counts(void)
115{
116 int i;
117 char *pp;
118
119 if ((v->ecount > 4096) && (v->ecount % 256 != 0)) return;
120
121 dprint(LINE_INFO, 72, v->ecount, 6, 0);
122/*
123 dprint(LINE_INFO, 56, v->ecc_ecount, 6, 0);
124*/
125
126 /* Paint the error messages on the screen red to provide a vivid */
Martin Roth4dcd13d2016-02-24 13:53:07 -0800127 /* indicator that an error has occured */
Martin Roth9b1b3352016-02-24 12:27:06 -0800128 if ((v->printmode == PRINTMODE_ADDRESSES ||
129 v->printmode == PRINTMODE_PATTERNS) &&
130 v->msg_line < 24) {
131 for(i=0, pp=(char *)((SCREEN_ADR+v->msg_line*160+1));
132 i<76; i++, pp+=2) {
133 *pp = 0x47;
134 }
135 }
136}
137
138/*
139 * Print an individual error
140 */
Martin Roth4dcd13d2016-02-24 13:53:07 -0800141void common_err( ulong *adr, ulong good, ulong bad, ulong xor, int type)
Martin Roth9b1b3352016-02-24 12:27:06 -0800142{
143 int i, j, n, x, flag=0;
144 ulong page, offset;
145 int patnchg;
146 ulong mb;
147
148 update_err_counts();
149
150 switch(v->printmode) {
151 case PRINTMODE_SUMMARY:
152 /* Don't do anything for a parity error. */
153 if (type == 3) {
154 return;
155 }
156
157 /* Address error */
158 if (type == 1) {
159 xor = good ^ bad;
160 }
161
162 /* Ecc correctable errors */
163 if (type == 2) {
164 /* the bad value is the corrected flag */
165 if (bad) {
166 v->erri.cor_err++;
167 }
168 page = (ulong)adr;
169 offset = good;
170 } else {
171 page = page_of(adr);
172 offset = (ulong)adr & 0xFFF;
173 }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800174
Martin Roth9b1b3352016-02-24 12:27:06 -0800175 /* Calc upper and lower error addresses */
176 if (v->erri.low_addr.page > page) {
177 v->erri.low_addr.page = page;
178 v->erri.low_addr.offset = offset;
179 flag++;
180 } else if (v->erri.low_addr.page == page &&
181 v->erri.low_addr.offset > offset) {
182 v->erri.low_addr.offset = offset;
183 v->erri.high_addr.offset = offset;
184 flag++;
185 } else if (v->erri.high_addr.page < page) {
186 v->erri.high_addr.page = page;
187 flag++;
188 }
189 if (v->erri.high_addr.page == page &&
190 v->erri.high_addr.offset < offset) {
191 v->erri.high_addr.offset = offset;
192 flag++;
193 }
194
195 /* Calc bits in error */
196 for (i=0, n=0; i<32; i++) {
197 if (xor>>i & 1) {
198 n++;
199 }
200 }
201 v->erri.tbits += n;
202 if (n > v->erri.max_bits) {
203 v->erri.max_bits = n;
204 flag++;
205 }
206 if (n < v->erri.min_bits) {
207 v->erri.min_bits = n;
208 flag++;
209 }
210 if (v->erri.ebits ^ xor) {
211 flag++;
212 }
213 v->erri.ebits |= xor;
214
215 /* Calc max contig errors */
216 len = 1;
217 if ((ulong)adr == (ulong)v->erri.eadr+4 ||
218 (ulong)adr == (ulong)v->erri.eadr-4 ) {
219 len++;
220 }
221 if (len > v->erri.maxl) {
222 v->erri.maxl = len;
223 flag++;
224 }
225 v->erri.eadr = (ulong)adr;
226
227 if (v->erri.hdr_flag == 0) {
228 clear_scroll();
229 cprint(LINE_HEADER+0, 1, "Error Confidence Value:");
230 cprint(LINE_HEADER+1, 1, " Lowest Error Address:");
231 cprint(LINE_HEADER+2, 1, " Highest Error Address:");
232 cprint(LINE_HEADER+3, 1, " Bits in Error Mask:");
233 cprint(LINE_HEADER+4, 1, " Bits in Error - Total:");
234 cprint(LINE_HEADER+4, 29, "Min: Max: Avg:");
235 cprint(LINE_HEADER+5, 1, " Max Contiguous Errors:");
236 x = 24;
237 if (dmi_initialized) {
238 for ( i=0; i < MAX_DMI_MEMDEVS;){
239 n = LINE_HEADER+7;
240 for (j=0; j<4; j++) {
241 if (dmi_err_cnts[i] >= 0) {
242 dprint(n, x, i, 2, 0);
243 cprint(n, x+2, ": 0");
244 }
245 i++;
246 n++;
247 }
248 x += 10;
249 }
250 }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800251
Martin Roth9b1b3352016-02-24 12:27:06 -0800252 cprint(LINE_HEADER+0, 64, "Test Errors");
253 v->erri.hdr_flag++;
254 }
255 if (flag) {
256 /* Calc bits in error */
257 for (i=0, n=0; i<32; i++) {
258 if (v->erri.ebits>>i & 1) {
259 n++;
260 }
261 }
262 page = v->erri.low_addr.page;
263 offset = v->erri.low_addr.offset;
264 mb = page >> 8;
265 hprint(LINE_HEADER+1, 25, page);
266 hprint2(LINE_HEADER+1, 33, offset, 3);
267 cprint(LINE_HEADER+1, 36, " - . MB");
268 dprint(LINE_HEADER+1, 39, mb, 5, 0);
269 dprint(LINE_HEADER+1, 45, ((page & 0xF)*10)/16, 1, 0);
270 page = v->erri.high_addr.page;
271 offset = v->erri.high_addr.offset;
272 mb = page >> 8;
273 hprint(LINE_HEADER+2, 25, page);
274 hprint2(LINE_HEADER+2, 33, offset, 3);
275 cprint(LINE_HEADER+2, 36, " - . MB");
276 dprint(LINE_HEADER+2, 39, mb, 5, 0);
277 dprint(LINE_HEADER+2, 45, ((page & 0xF)*10)/16, 1, 0);
278 hprint(LINE_HEADER+3, 25, v->erri.ebits);
279 dprint(LINE_HEADER+4, 25, n, 2, 1);
280 dprint(LINE_HEADER+4, 34, v->erri.min_bits, 2, 1);
281 dprint(LINE_HEADER+4, 42, v->erri.max_bits, 2, 1);
282 dprint(LINE_HEADER+4, 50, v->erri.tbits/v->ecount, 2, 1);
283 dprint(LINE_HEADER+5, 25, v->erri.maxl, 7, 1);
284 x = 28;
285 for ( i=0; i < MAX_DMI_MEMDEVS;){
286 n = LINE_HEADER+7;
287 for (j=0; j<4; j++) {
288 if (dmi_err_cnts[i] > 0) {
289 dprint (n, x, dmi_err_cnts[i], 7, 1);
290 }
291 i++;
292 n++;
293 }
294 x += 10;
295 }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800296
Martin Roth9b1b3352016-02-24 12:27:06 -0800297 for (i=0; tseq[i].msg != NULL; i++) {
298 dprint(LINE_HEADER+1+i, 66, i, 2, 0);
299 dprint(LINE_HEADER+1+i, 68, tseq[i].errors, 8, 0);
300 }
301 }
302 if (v->erri.cor_err) {
303 dprint(LINE_HEADER+6, 25, v->erri.cor_err, 8, 1);
304 }
305 break;
306
307 case PRINTMODE_ADDRESSES:
308 /* Don't display duplicate errors */
309 if ((ulong)adr == (ulong)v->erri.eadr &&
310 xor == v->erri.exor) {
311 return;
312 }
313 if (v->erri.hdr_flag == 0) {
314 clear_scroll();
315 cprint(LINE_HEADER, 0,
316"Tst Pass Failing Address Good Bad Err-Bits Count CPU");
317 cprint(LINE_HEADER+1, 0,
318"--- ---- ----------------------- -------- -------- -------- ----- ----");
319 v->erri.hdr_flag++;
320 }
321 /* Check for keyboard input */
322 check_input();
323 scroll();
Martin Roth4dcd13d2016-02-24 13:53:07 -0800324
Martin Roth9b1b3352016-02-24 12:27:06 -0800325 if ( type == 2 || type == 3) {
326 page = (ulong)adr;
327 offset = good;
328 } else {
329 page = page_of(adr);
330 offset = ((unsigned long)adr) & 0xFFF;
331 }
332 mb = page >> 8;
333 dprint(v->msg_line, 0, test+1, 3, 0);
334 dprint(v->msg_line, 4, v->pass, 5, 0);
335 hprint(v->msg_line, 11, page);
336 hprint2(v->msg_line, 19, offset, 3);
337 cprint(v->msg_line, 22, " - . MB");
338 dprint(v->msg_line, 25, mb, 5, 0);
339 dprint(v->msg_line, 31, ((page & 0xF)*10)/16, 1, 0);
340
341 if (type == 3) {
342 /* ECC error */
Martin Roth4dcd13d2016-02-24 13:53:07 -0800343 cprint(v->msg_line, 36,
Martin Roth9b1b3352016-02-24 12:27:06 -0800344 bad?"corrected ": "uncorrected ");
345 hprint2(v->msg_line, 60, syn, 4);
Martin Roth4dcd13d2016-02-24 13:53:07 -0800346 cprint(v->msg_line, 68, "ECC");
Martin Roth9b1b3352016-02-24 12:27:06 -0800347 dprint(v->msg_line, 74, chan, 2, 0);
348 } else if (type == 2) {
349 cprint(v->msg_line, 36, "Parity error detected ");
350 } else {
351 hprint(v->msg_line, 36, good);
352 hprint(v->msg_line, 46, bad);
353 hprint(v->msg_line, 56, xor);
354 dprint(v->msg_line, 66, v->ecount, 5, 0);
355 dprint(v->msg_line, 74, smp_my_cpu_num(), 2,1);
356 v->erri.exor = xor;
357 }
358 v->erri.eadr = (ulong)adr;
359 print_err_counts();
360 break;
361
362 case PRINTMODE_PATTERNS:
363 if (v->erri.hdr_flag == 0) {
364 clear_scroll();
365 v->erri.hdr_flag++;
366 }
367 /* Do not do badram patterns from test 0 or 5 */
368 if (test == 0 || test == 5) {
369 return;
370 }
371 /* Only do patterns for data errors */
372 if ( type != 0) {
373 return;
374 }
375 /* Process the address in the pattern administration */
376 patnchg=insertaddress ((ulong) adr);
Martin Roth4dcd13d2016-02-24 13:53:07 -0800377 if (patnchg) {
Martin Roth9b1b3352016-02-24 12:27:06 -0800378 printpatn();
379 }
380 break;
381
382 case PRINTMODE_NONE:
383 if (v->erri.hdr_flag == 0) {
384 clear_scroll();
385 v->erri.hdr_flag++;
386 }
387 break;
388 }
389}
390
391/*
392 * Print an ecc error
393 */
Martin Roth4dcd13d2016-02-24 13:53:07 -0800394void print_ecc_err(unsigned long page, unsigned long offset,
Martin Roth9b1b3352016-02-24 12:27:06 -0800395 int corrected, unsigned short syndrome, int channel)
396{
397 ++(v->ecc_ecount);
398 syn = syndrome;
399 chan = channel;
400 common_err((ulong *)page, offset, corrected, 0, 2);
401}
402
403#ifdef PARITY_MEM
404/*
405 * Print a parity error message
406 */
Martin Roth4dcd13d2016-02-24 13:53:07 -0800407void parity_err( unsigned long edi, unsigned long esi)
Martin Roth9b1b3352016-02-24 12:27:06 -0800408{
409 unsigned long addr;
410
411 if (test == 5) {
412 addr = esi;
413 } else {
414 addr = edi;
415 }
416 common_err((ulong *)addr, addr & 0xFFF, 0, 0, 3);
417}
418#endif
419
420/*
421 * Print the pattern array as a LILO boot option addressing BadRAM support.
422 */
423void printpatn (void)
424{
425 int idx=0;
426 int x;
427
428 /* Check for keyboard input */
429 check_input();
430
431 if (v->numpatn == 0)
432 return;
433
434 scroll();
435
436 cprint (v->msg_line, 0, "badram=");
437 x=7;
438
439 for (idx = 0; idx < v->numpatn; idx++) {
440
441 if (x > 80-22) {
442 scroll();
443 x=7;
444 }
445 cprint (v->msg_line, x, "0x");
446 hprint (v->msg_line, x+2, v->patn[idx].adr );
447 cprint (v->msg_line, x+10, ",0x");
448 hprint (v->msg_line, x+13, v->patn[idx].mask);
449 if (idx+1 < v->numpatn)
450 cprint (v->msg_line, x+21, ",");
451 x+=22;
452 }
453}
Martin Roth4dcd13d2016-02-24 13:53:07 -0800454
Martin Roth9b1b3352016-02-24 12:27:06 -0800455/*
456 * Show progress by displaying elapsed time and update bar graphs
457 */
458short spin_idx[MAX_CPUS];
459char spin[4] = {'|','/','-','\\'};
460
461void do_tick(int me)
462{
463 int i, j, pct;
464 ulong h, l, n, t;
465 extern int mstr_cpu;
466
467 if (++spin_idx[me] > 3) {
468 spin_idx[me] = 0;
469 }
470 cplace(8, me+7, spin[spin_idx[me]]);
Martin Roth4dcd13d2016-02-24 13:53:07 -0800471
472
Martin Roth9b1b3352016-02-24 12:27:06 -0800473 /* Check for keyboard input */
474 if (me == mstr_cpu) {
475 check_input();
476 }
477 /* A barrier here holds the other CPUs until the configuration
478 * changes are done */
479 s_barrier();
480
481 /* Only the first selected CPU does the update */
482 if (me != mstr_cpu) {
483 return;
484 }
485
486 /* FIXME only print serial error messages from the tick handler */
487 if (v->ecount) {
488 print_err_counts();
489 }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800490
Martin Roth9b1b3352016-02-24 12:27:06 -0800491 nticks++;
492 v->total_ticks++;
493
494 if (test_ticks) {
495 pct = 100*nticks/test_ticks;
496 if (pct > 100) {
497 pct = 100;
498 }
499 } else {
500 pct = 0;
501 }
502 dprint(2, COL_MID+4, pct, 3, 0);
503 i = (BAR_SIZE * pct) / 100;
504 while (i > v->tptr) {
505 if (v->tptr >= BAR_SIZE) {
506 break;
507 }
508 cprint(2, COL_MID+9+v->tptr, "#");
509 v->tptr++;
510 }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800511
Martin Roth9b1b3352016-02-24 12:27:06 -0800512 if (v->pass_ticks) {
513 pct = 100*v->total_ticks/v->pass_ticks;
514 if (pct > 100) {
515 pct = 100;
516 }
517 } else {
518 pct = 0;
519 }
520 dprint(1, COL_MID+4, pct, 3, 0);
521 i = (BAR_SIZE * pct) / 100;
522 while (i > v->pptr) {
523 if (v->pptr >= BAR_SIZE) {
524 break;
525 }
526 cprint(1, COL_MID+9+v->pptr, "#");
527 v->pptr++;
528 }
529
530 if (v->ecount && v->printmode == PRINTMODE_SUMMARY) {
531 /* Compute confidence score */
532 pct = 0;
533
534 /* If there are no errors within 1mb of start - end addresses */
535 h = v->pmap[v->msegs - 1].end - 0x100;
536 if (v->erri.low_addr.page > 0x100 &&
537 v->erri.high_addr.page < h) {
538 pct += 8;
539 }
540
541 /* Errors for only some tests */
542 if (v->pass) {
543 for (i=0, n=0; tseq[i].msg != NULL; i++) {
544 if (tseq[i].errors == 0) {
545 n++;
546 }
547 }
548 pct += n*3;
549 } else {
550 for (i=0, n=0; i<test; i++) {
551 if (tseq[i].errors == 0) {
552 n++;
553 }
554 }
555 pct += n*2;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800556
Martin Roth9b1b3352016-02-24 12:27:06 -0800557 }
558
559 /* Only some bits in error */
560 n = 0;
561 if (v->erri.ebits & 0xf) n++;
562 if (v->erri.ebits & 0xf0) n++;
563 if (v->erri.ebits & 0xf00) n++;
564 if (v->erri.ebits & 0xf000) n++;
565 if (v->erri.ebits & 0xf0000) n++;
566 if (v->erri.ebits & 0xf00000) n++;
567 if (v->erri.ebits & 0xf000000) n++;
568 if (v->erri.ebits & 0xf0000000) n++;
569 pct += (8-n)*2;
570
571 /* Adjust the score */
572 pct = pct*100/22;
573/*
574 if (pct > 100) {
575 pct = 100;
576 }
577*/
578 dprint(LINE_HEADER+0, 25, pct, 3, 1);
579 }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800580
Martin Roth9b1b3352016-02-24 12:27:06 -0800581
582 /* We can't do the elapsed time unless the rdtsc instruction
583 * is supported
584 */
585 if (cpu_id.fid.bits.rdtsc) {
586 asm __volatile__(
587 "rdtsc":"=a" (l),"=d" (h));
588 asm __volatile__ (
589 "subl %2,%0\n\t"
590 "sbbl %3,%1"
591 :"=a" (l), "=d" (h)
592 :"g" (v->startl), "g" (v->starth),
593 "0" (l), "1" (h));
594 t = h * ((unsigned)0xffffffff / v->clks_msec) / 1000;
595 t += (l / v->clks_msec) / 1000;
596 i = t % 60;
597 j = i % 10;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800598
Martin Roth9b1b3352016-02-24 12:27:06 -0800599 if(j != v->each_sec)
Martin Roth4dcd13d2016-02-24 13:53:07 -0800600 {
601
Martin Roth9b1b3352016-02-24 12:27:06 -0800602 dprint(LINE_TIME, COL_TIME+9, i % 10, 1, 0);
603 dprint(LINE_TIME, COL_TIME+8, i / 10, 1, 0);
604 t /= 60;
605 i = t % 60;
606 dprint(LINE_TIME, COL_TIME+6, i % 10, 1, 0);
607 dprint(LINE_TIME, COL_TIME+5, i / 10, 1, 0);
608 t /= 60;
609 dprint(LINE_TIME, COL_TIME, t, 4, 0);
Martin Roth4dcd13d2016-02-24 13:53:07 -0800610
Martin Roth9b1b3352016-02-24 12:27:06 -0800611 if(v->check_temp > 0 && !(v->fail_safe & 4))
612 {
Martin Roth4dcd13d2016-02-24 13:53:07 -0800613 coretemp();
614 }
615 v->each_sec = j;
Martin Roth9b1b3352016-02-24 12:27:06 -0800616 }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800617
Martin Roth9b1b3352016-02-24 12:27:06 -0800618 }
Martin Roth4dcd13d2016-02-24 13:53:07 -0800619
Martin Roth9b1b3352016-02-24 12:27:06 -0800620
621
622 /* Poll for ECC errors */
623/*
624 poll_errors();
625*/
626}
627