~ubuntu-branches/ubuntu/lucid/memtest86+/lucid

1 by Yann Dirson
Import upstream version 1.55.1
1
/* init.c - MemTest-86  Version 3.0
2
 *
3
 * Released under version 2 of the Gnu Public License.
4
 * By Chris Brady, cbrady@sgi.com
5
 * ----------------------------------------------------
1.2.5 by Yann Dirson
Import upstream version 4.00
6
 * MemTest86+ V4.00 Specific code (GPL V2.0)
1 by Yann Dirson
Import upstream version 1.55.1
7
 * By Samuel DEMEULEMEESTER, sdemeule@memtest.org
1.2.4 by Yann Dirson
Import upstream version 2.11
8
 * http://www.canardpc.com - http://www.memtest.org
1 by Yann Dirson
Import upstream version 1.55.1
9
 */
10
11
#include "test.h"
12
#include "defs.h"
13
#include "config.h"
14
#include "controller.h"
15
#include "pci.h"
16
#include "io.h"
1.2.5 by Yann Dirson
Import upstream version 4.00
17
#include "spd.h"
1 by Yann Dirson
Import upstream version 1.55.1
18
1.2.3 by Reinhard Tartler
Import upstream version 2.01
19
#define rdmsr(msr,val1,val2) \
20
	__asm__ __volatile__("rdmsr" \
21
			  : "=a" (val1), "=d" (val2) \
22
			  : "c" (msr))
23
24
extern struct tseq tseq[];
1 by Yann Dirson
Import upstream version 1.55.1
25
extern short memsz_mode;
26
extern short firmware;
1.2.3 by Reinhard Tartler
Import upstream version 2.01
27
extern short dmi_initialized;
28
extern int dmi_err_cnts[MAX_DMI_MEMDEVS];
1 by Yann Dirson
Import upstream version 1.55.1
29
30
struct cpu_ident cpu_id;
31
ulong st_low, st_high;
32
ulong end_low, end_high;
33
ulong cal_low, cal_high;
34
ulong extclock;
1.2.5 by Yann Dirson
Import upstream version 4.00
35
unsigned long imc_type = 0;
1 by Yann Dirson
Import upstream version 1.55.1
36
1.2.4 by Yann Dirson
Import upstream version 2.11
37
int l1_cache, l2_cache, l3_cache;
1.2.3 by Reinhard Tartler
Import upstream version 2.01
38
int tsc_invariable = 0;
39
40
ulong memspeed(ulong src, ulong len, int iter, int type);
1 by Yann Dirson
Import upstream version 1.55.1
41
static void cpu_type(void);
42
static void cacheable(void);
43
static int cpuspeed(void);
1.2.3 by Reinhard Tartler
Import upstream version 2.01
44
int beepmode;
1 by Yann Dirson
Import upstream version 1.55.1
45
46
static void display_init(void)
47
{
48
	int i;
49
	volatile char *pp;
50
51
	serial_echo_init();
52
	serial_echo_print("\x1B[LINE_SCROLL;24r"); /* Set scroll area row 7-23 */
53
	serial_echo_print("\x1B[H\x1B[2J");   /* Clear Screen */
54
	serial_echo_print("\x1B[37m\x1B[44m");
55
	serial_echo_print("\x1B[0m");
56
	serial_echo_print("\x1B[37m\x1B[44m");
57
58
	/* Clear screen & set background to blue */
59
	for(i=0, pp=(char *)(SCREEN_ADR); i<80*24; i++) {
60
		*pp++ = ' ';
61
		*pp++ = 0x17;
62
	}
63
64
	/* Make the name background red */
65
	for(i=0, pp=(char *)(SCREEN_ADR+1); i<TITLE_WIDTH; i++, pp+=2) {
66
		*pp = 0x20;
67
	}
1.2.5 by Yann Dirson
Import upstream version 4.00
68
	cprint(0, 0, "      Memtest86  v4.00      ");
1 by Yann Dirson
Import upstream version 1.55.1
69
70
	for(i=0, pp=(char *)(SCREEN_ADR+1); i<2; i++, pp+=30) {
71
		*pp = 0xA4;
72
	}
73
	cprint(0, 15, "+");
74
75
	/* Do reverse video for the bottom display line */
76
	for(i=0, pp=(char *)(SCREEN_ADR+1+(24 * 160)); i<80; i++, pp+=2) {
77
		*pp = 0x71;
78
	}
79
80
	serial_echo_print("\x1B[0m");
81
}
82
83
/*
84
 * Initialize test, setup screen and find out how much memory there is.
85
 */
86
void init(void)
87
{
88
	int i;
89
90
	outb(0x8, 0x3f2);  /* Kill Floppy Motor */
91
92
	/* Turn on cache */
93
	set_cache(1);
94
95
	/* Setup the display */
96
	display_init();
97
98
	/* Determine the memory map */
99
	if ((firmware == FIRMWARE_UNKNOWN) &&
100
		(memsz_mode != SZ_MODE_PROBE)) {
101
		if (query_linuxbios()) {
102
			firmware = FIRMWARE_LINUXBIOS;
103
		}
104
		else if (query_pcbios()) {
105
			firmware = FIRMWARE_PCBIOS;
106
		}
107
	}
108
109
	mem_size();
110
111
	/* setup pci */
112
	pci_init();
113
114
	/* setup beep mode */
115
	beepmode = BEEP_MODE;
116
117
	v->test = 0;
1.2.3 by Reinhard Tartler
Import upstream version 2.01
118
	v->pass = 0;
119
	v->msg_line = 0;
120
	v->ecount = 0;
121
	v->ecc_ecount = 0;
1 by Yann Dirson
Import upstream version 1.55.1
122
	v->testsel = -1;
123
	v->msg_line = LINE_SCROLL-1;
124
	v->scroll_start = v->msg_line * 160;
1.2.3 by Reinhard Tartler
Import upstream version 2.01
125
	v->erri.low_addr.page = 0x7fffffff;
126
	v->erri.low_addr.offset = 0xfff;
127
	v->erri.high_addr.page = 0;
128
	v->erri.high_addr.offset = 0;
129
	v->erri.min_bits = 32;
130
	v->erri.max_bits = 0;
131
	v->erri.min_bits = 32;
132
	v->erri.max_bits = 0;
133
	v->erri.maxl = 0;
134
	v->erri.cor_err = 0;
135
	v->erri.ebits = 0;
136
	v->erri.hdr_flag = 0;
137
	v->erri.tbits = 0;
1.2.5 by Yann Dirson
Import upstream version 4.00
138
	for (i=0; tseq[i].msg != 0; i++) {
1.2.3 by Reinhard Tartler
Import upstream version 2.01
139
		tseq[i].errors = 0;
140
	}
141
	if (dmi_initialized) {
142
		for (i=0; i < MAX_DMI_MEMDEVS; i++){
143
			if (dmi_err_cnts[i] > 0) {
144
				dmi_err_cnts[i] = 0;
145
			}
146
		}
147
	}
1 by Yann Dirson
Import upstream version 1.55.1
148
149
	cprint(LINE_CPU+1, 0, "L1 Cache: Unknown ");
150
	cprint(LINE_CPU+2, 0, "L2 Cache: Unknown ");
1.2.4 by Yann Dirson
Import upstream version 2.11
151
	cprint(LINE_CPU+3, 0, "L3 Cache:       None  ");
152
	cprint(LINE_CPU+4, 0, "Memory  :                   |-------------------------------------------------");
153
	aprint(LINE_CPU+4, 10, v->test_pages);
154
	cprint(LINE_CPU+5, 0, "Chipset : ");
1 by Yann Dirson
Import upstream version 1.55.1
155
156
	cpu_type();
157
1.2.5 by Yann Dirson
Import upstream version 4.00
158
	/* Find the memory controller */
1 by Yann Dirson
Import upstream version 1.55.1
159
	find_controller();
160
1.2.5 by Yann Dirson
Import upstream version 4.00
161
	/* Find Memory Specs */
162
	get_spd_spec();	
163
1 by Yann Dirson
Import upstream version 1.55.1
164
	if (v->rdtsc) {
165
		cacheable();
166
		cprint(LINE_TIME, COL_TIME+4, ":  :");
167
	}
168
	cprint(0, COL_MID,"Pass   %");
169
	cprint(1, COL_MID,"Test   %");
170
	cprint(2, COL_MID,"Test #");
171
	cprint(3, COL_MID,"Testing: ");
172
	cprint(4, COL_MID,"Pattern: ");
173
	cprint(LINE_INFO-2, 0, " WallTime   Cached  RsvdMem   MemMap   Cache  ECC  Test  Pass  Errors ECC Errs");
174
	cprint(LINE_INFO-1, 0, " ---------  ------  -------  --------  -----  ---  ----  ----  ------ --------");
175
	cprint(LINE_INFO, COL_TST, " Std");
176
	cprint(LINE_INFO, COL_PASS, "    0");
177
	cprint(LINE_INFO, COL_ERR, "     0");
178
	cprint(LINE_INFO+1, 0, " -----------------------------------------------------------------------------");
1.2.4 by Yann Dirson
Import upstream version 2.11
179
					
1 by Yann Dirson
Import upstream version 1.55.1
180
181
	for(i=0; i < 5; i++) {
182
		cprint(i, COL_MID-2, "| ");
183
	}
184
	footer();
1.2.3 by Reinhard Tartler
Import upstream version 2.01
185
	// Default Print Mode
186
	// v->printmode=PRINTMODE_SUMMARY;
1 by Yann Dirson
Import upstream version 1.55.1
187
	v->printmode=PRINTMODE_ADDRESSES;
188
	v->numpatn=0;
1.2.4 by Yann Dirson
Import upstream version 2.11
189
1 by Yann Dirson
Import upstream version 1.55.1
190
}
191
192
#define FLAT 0
193
194
static unsigned long mapped_window = 1;
195
void paging_off(void)
196
{
197
	if (!v->pae)
198
		return;
199
	mapped_window = 1;
200
	__asm__ __volatile__ (
201
		/* Disable paging */
202
		"movl %%cr0, %%eax\n\t"
203
		"andl $0x7FFFFFFF, %%eax\n\t"
204
		"movl %%eax, %%cr0\n\t"
205
		/* Disable pae and pse */
206
		"movl %%cr4, %%eax\n\t"
207
		"and $0xCF, %%al\n\t"
208
		"movl %%eax, %%cr4\n\t"
209
		:
210
		:
211
		: "ax"
212
		);
213
}
214
215
static void paging_on(void *pdp)
216
{
217
	if (!v->pae)
218
		return;
219
	__asm__ __volatile__(
220
		/* Load the page table address */
221
		"movl %0, %%cr3\n\t"
222
		/* Enable pae */
223
		"movl %%cr4, %%eax\n\t"
224
		"orl $0x00000020, %%eax\n\t"
225
		"movl %%eax, %%cr4\n\t"
226
		/* Enable paging */
227
		"movl %%cr0, %%eax\n\t"
228
		"orl $0x80000000, %%eax\n\t"
229
		"movl %%eax, %%cr0\n\t"
230
		:
231
		: "r" (pdp)
232
		: "ax"
233
		);
234
}
235
236
int map_page(unsigned long page)
237
{
238
	unsigned long i;
239
	struct pde {
240
		unsigned long addr_lo;
241
		unsigned long addr_hi;
242
	};
243
	extern unsigned char pdp[];
244
	extern struct pde pd2[];
245
	unsigned long window = page >> 19;
246
	if (FLAT || (window == mapped_window)) {
247
		return 0;
248
	}
249
	if (window == 0) {
250
		return 0;
251
	}
252
	if (!v->pae || (window >= 32)) {
253
		/* Fail either we don't have pae support
254
		 * or we want an address that is out of bounds
255
		 * even for pae.
256
		 */
257
		return -1;
258
	}
259
	/* Compute the page table entries... */
260
	for(i = 0; i < 1024; i++) {
261
		/*-----------------10/30/2004 12:37PM---------------
262
		 * 0xE3 --
263
		 * Bit 0 = Present bit.      1 = PDE is present
264
		 * Bit 1 = Read/Write.       1 = memory is writable
265
		 * Bit 2 = Supervisor/User.  0 = Supervisor only (CPL 0-2)
266
		 * Bit 3 = Writethrough.     0 = writeback cache policy
267
		 * Bit 4 = Cache Disable.    0 = page level cache enabled
268
		 * Bit 5 = Accessed.         1 = memory has been accessed.
269
		 * Bit 6 = Dirty.            1 = memory has been written to.
270
		 * Bit 7 = Page Size.        1 = page size is 2 MBytes
271
		 * --------------------------------------------------*/
272
		pd2[i].addr_lo = ((window & 1) << 31) + ((i & 0x3ff) << 21) + 0xE3;
273
		pd2[i].addr_hi = (window >> 1);
274
	}
275
	paging_off();
276
	if (window > 1) {
277
		paging_on(pdp);
278
	}
279
	mapped_window = window;
280
	return 0;
281
}
282
283
void *mapping(unsigned long page_addr)
284
{
285
	void *result;
286
	if (FLAT || (page_addr < 0x80000)) {
287
		/* If the address is less that 1GB directly use the address */
288
		result = (void *)(page_addr << 12);
289
	}
290
	else {
291
		unsigned long alias;
292
		alias = page_addr & 0x7FFFF;
293
		alias += 0x80000;
294
		result = (void *)(alias << 12);
295
	}
296
	return result;
297
}
298
299
void *emapping(unsigned long page_addr)
300
{
301
	void *result;
302
	result = mapping(page_addr -1);
303
	/* The result needs to be 256 byte alinged... */
304
	result = ((unsigned char *)result) + 0xf00;
305
	return result;
306
}
307
308
unsigned long page_of(void *addr)
309
{
310
	unsigned long page;
311
	page = ((unsigned long)addr) >> 12;
312
	if (!FLAT && (page >= 0x80000)) {
313
		page &= 0x7FFFF;
314
		page += mapped_window << 19;
315
	}
316
#if 0
317
	cprint(LINE_SCROLL -2, 0, "page_of(        )->            ");
318
	hprint(LINE_SCROLL -2, 8, ((unsigned long)addr));
319
	hprint(LINE_SCROLL -2, 20, page);
320
#endif
321
	return page;
322
}
323
324
325
/*
326
 * Find CPU type and cache sizes
327
 */
328
329
330
void cpu_type(void)
331
{
332
	int i, off=0;
1.2.4 by Yann Dirson
Import upstream version 2.11
333
	int l1_cache=0, l2_cache=0, l3_cache=0;
1 by Yann Dirson
Import upstream version 1.55.1
334
	ulong speed;
335
336
	v->rdtsc = 0;
337
	v->pae = 0;
338
339
#ifdef CPUID_DEBUG
340
	dprint(9,0,cpu_id.type,3,1);
341
	dprint(10,0,cpu_id.model,3,1);
342
	dprint(11,0,cpu_id.cpuid,3,1);
343
#endif
344
345
	/* If the CPUID instruction is not supported then this is */
346
	/* a 386, 486 or one of the early Cyrix CPU's */
347
	if (cpu_id.cpuid < 1) {
348
		switch (cpu_id.type) {
349
		case 2:
350
			/* This is a Cyrix CPU without CPUID */
351
			i = getCx86(0xfe);
352
			i &= 0xf0;
353
			i >>= 4;
354
			switch(i) {
355
			case 0:
356
			case 1:
357
				cprint(LINE_CPU, 0, "Cyrix Cx486");
358
				break;
359
			case 2:
360
				cprint(LINE_CPU, 0,"Cyrix 5x86");
361
				break;
362
			case 3:
363
				cprint(LINE_CPU, 0,"Cyrix 6x86");
364
				break;
365
			case 4:
366
				cprint(LINE_CPU, 0,"Cyrix MediaGX");
367
				break;
368
			case 5:
369
				cprint(LINE_CPU, 0,"Cyrix 6x86MX");
370
				break;
371
			case 6:
372
				cprint(LINE_CPU, 0,"Cyrix MII");
373
				break;
374
			default:
375
				cprint(LINE_CPU, 0,"Cyrix ???");
376
				break;
377
			}
378
			break;
379
		case 3:
380
			cprint(LINE_CPU, 0, "386");
381
			break;
382
383
		case 4:
384
			cprint(LINE_CPU, 0, "486");
385
			l1_cache = 8;
386
			break;
387
		}
388
		return;
389
	}
390
391
	/* We have cpuid so we can see if we have pae support */
392
	if (cpu_id.capability & (1 << X86_FEATURE_PAE)) {
393
		v->pae = 1;
394
	}
395
	switch(cpu_id.vend_id[0]) {
396
	/* AMD Processors */
397
	case 'A':
398
		switch(cpu_id.type) {
399
		case 4:
400
			switch(cpu_id.model) {
401
			case 3:
402
				cprint(LINE_CPU, 0, "AMD 486DX2");
403
				break;
404
			case 7:
405
				cprint(LINE_CPU, 0, "AMD 486DX2-WB");
406
				break;
407
			case 8:
408
				cprint(LINE_CPU, 0, "AMD 486DX4");
409
				break;
410
			case 9:
411
				cprint(LINE_CPU, 0, "AMD 486DX4-WB");
412
				break;
413
			case 14:
414
				cprint(LINE_CPU, 0, "AMD 5x86-WT");
415
				break;
416
			}
417
			/* Since we can't get CPU speed or cache info return */
418
			return;
419
		case 5:
420
			switch(cpu_id.model) {
421
			case 0:
422
			case 1:
423
			case 2:
424
			case 3:
425
				cprint(LINE_CPU, 0, "AMD K5");
1.2.1 by Yann Dirson
Import upstream version 1.65
426
				l1_cache = 8;
1 by Yann Dirson
Import upstream version 1.55.1
427
				off = 6;
428
				break;
429
			case 6:
430
			case 7:
431
				cprint(LINE_CPU, 0, "AMD K6");
432
				off = 6;
433
				l1_cache = cpu_id.cache_info[3];
434
				l1_cache += cpu_id.cache_info[7];
435
				break;
436
			case 8:
437
				cprint(LINE_CPU, 0, "AMD K6-2");
438
				off = 8;
439
				l1_cache = cpu_id.cache_info[3];
440
				l1_cache += cpu_id.cache_info[7];
441
				break;
442
			case 9:
443
				cprint(LINE_CPU, 0, "AMD K6-III");
444
				off = 10;
445
				l1_cache = cpu_id.cache_info[3];
446
				l1_cache += cpu_id.cache_info[7];
447
				l2_cache = (cpu_id.cache_info[11] << 8);
448
				l2_cache += cpu_id.cache_info[10];
449
				break;
1.2.5 by Yann Dirson
Import upstream version 4.00
450
			case 10:
451
				cprint(LINE_CPU, 0, "AMD Geode LX");
452
				off = 12;
453
				l1_cache = cpu_id.cache_info[3];
454
				l1_cache += cpu_id.cache_info[7];
455
				l2_cache = (cpu_id.cache_info[11] << 8);
456
				l2_cache += cpu_id.cache_info[10];
457
				break;
1 by Yann Dirson
Import upstream version 1.55.1
458
			case 13:
459
				cprint(LINE_CPU, 0, "AMD K6-III+");
460
				off = 11;
461
				l1_cache = cpu_id.cache_info[3];
462
				l1_cache += cpu_id.cache_info[7];
463
				l2_cache = (cpu_id.cache_info[11] << 8);
464
				l2_cache += cpu_id.cache_info[10];
465
				break;
466
			}
467
			break;
468
		case 6:
469
			switch(cpu_id.model) {
470
			case 1:
471
				cprint(LINE_CPU, 0, "AMD Athlon (0.25)");
472
				off = 17;
473
				l2_cache = (cpu_id.cache_info[11] << 8);
474
				l2_cache += cpu_id.cache_info[10];
475
				break;
476
			case 2:
477
			case 4:
478
				cprint(LINE_CPU, 0, "AMD Athlon (0.18)");
479
				off = 17;
480
				l2_cache = (cpu_id.cache_info[11] << 8);
481
				l2_cache += cpu_id.cache_info[10];
482
				break;
483
			case 6:
484
				l2_cache = (cpu_id.cache_info[11] << 8);
485
				l2_cache += cpu_id.cache_info[10];
486
				if (l2_cache == 64) {
487
					cprint(LINE_CPU, 0, "AMD Duron (0.18)");
488
				} else {
489
					cprint(LINE_CPU, 0, "Athlon XP (0.18)");
490
				}
491
				off = 16;
492
				break;
493
			case 8:
494
			case 10:
495
				l2_cache = (cpu_id.cache_info[11] << 8);
496
				l2_cache += cpu_id.cache_info[10];
497
				if (l2_cache == 64) {
498
					cprint(LINE_CPU, 0, "AMD Duron (0.13)");
499
				} else {
500
					cprint(LINE_CPU, 0, "Athlon XP (0.13)");
501
				}
502
				off = 16;
503
				break;
504
			case 3:
505
			case 7:
506
				cprint(LINE_CPU, 0, "AMD Duron");
507
				off = 9;
508
				/* Duron stepping 0 CPUID for L2 is broken */
509
				/* (AMD errata T13)*/
510
				if (cpu_id.step == 0) { /* stepping 0 */
511
					/* Hard code the right size*/
512
					l2_cache = 64;
513
				} else {
514
					l2_cache = (cpu_id.cache_info[11] << 8);
515
					l2_cache += cpu_id.cache_info[10];
516
				}
517
				break;
518
			}
519
			l1_cache = cpu_id.cache_info[3];
520
			l1_cache += cpu_id.cache_info[7];
521
			break;
522
		case 15:
523
			l1_cache = cpu_id.cache_info[3];
524
			l2_cache = (cpu_id.cache_info[11] << 8);
525
			l2_cache += cpu_id.cache_info[10];
1.2.5 by Yann Dirson
Import upstream version 4.00
526
			imc_type = 0x0100;
527
			if(((cpu_id.ext >> 16) & 0xFF) < 0x10) {
528
			// Here if CPUID.EXT < 0x10h	(old K8/K10)
529
				switch(cpu_id.model) {
530
				default:
531
					cprint(LINE_CPU, 0, "AMD K8");
532
					off = 6;
533
					break;
534
				case 1:
535
				case 5:
536
					if (((cpu_id.ext >> 16) & 0xF) != 0) {
537
						cprint(LINE_CPU, 0, "AMD Opteron (0.09)");				
538
					} else {
539
						cprint(LINE_CPU, 0, "AMD Opteron (0.13)");
540
					}
541
					off = 18;
542
					break;
543
				case 3:
544
				case 11:
545
					cprint(LINE_CPU, 0, "Athlon 64 X2");
546
					off = 12;				
547
					break;			
548
				case 8:
549
					cprint(LINE_CPU, 0, "Turion 64 X2");
550
					off = 12;						
551
					break;
552
				case 4:
553
				case 7:
554
				case 12:
555
				case 14:
556
				case 15:
557
					if (((cpu_id.ext >> 16) & 0xF) != 0) {
558
						if (l2_cache > 256) {
559
							cprint(LINE_CPU, 0, "Athlon 64 (0.09)");
560
						} else {
561
							cprint(LINE_CPU, 0, "Sempron (0.09)");						
562
						}
563
					} else {
564
						if (l2_cache > 256) {
565
							cprint(LINE_CPU, 0, "Athlon 64 (0.13)");
566
						} else {
567
							cprint(LINE_CPU, 0, "Sempron (0.13)");						
568
						}		
569
					}
570
					off = 16;
571
					break;			
572
				}
573
				break;
574
			} else {
575
			 // Here if CPUID.EXT >= 0x10h	(new K10)
1.2.4 by Yann Dirson
Import upstream version 2.11
576
				l3_cache = (cpu_id.cache_info[15] << 8);
577
				l3_cache += (cpu_id.cache_info[14] >> 2);
578
				l3_cache *= 512;
1.2.5 by Yann Dirson
Import upstream version 4.00
579
				imc_type = 0x0101;
580
				switch(cpu_id.model) {
581
				default:			 
582
				case 2:
583
					cprint(LINE_CPU, 0, "AMD K10 (65nm) @");
584
					off = 16;				
585
					break;	
586
				case 4:
587
					cprint(LINE_CPU, 0, "AMD K10 (45nm) @");
588
					off = 16;				
589
					break;				
590
				case 9:
591
					cprint(LINE_CPU, 0, "AMD Magny-Cours");
592
					off = 15;				
593
					break;			
594
				}
595
				break;		  
1 by Yann Dirson
Import upstream version 1.55.1
596
			}
597
		}
598
		break;
599
600
	/* Intel or Transmeta Processors */
601
	case 'G':
602
		if ( cpu_id.vend_id[7] == 'T' ) {	/* GenuineTMx86 */
603
			if (cpu_id.type == 5) {
604
				cprint(LINE_CPU, 0, "TM 5x00");
605
				off = 7;
606
			} else if (cpu_id.type == 15) {
607
				cprint(LINE_CPU, 0, "TM 8x00");
608
				off = 7;
609
			}
610
			l1_cache = cpu_id.cache_info[3] + cpu_id.cache_info[7];
611
			l2_cache = (cpu_id.cache_info[11]*256) + cpu_id.cache_info[10];
612
		} else {				/* GenuineIntel */
613
			if (cpu_id.type == 4) {
614
				switch(cpu_id.model) {
615
				case 0:
616
				case 1:
617
					cprint(LINE_CPU, 0, "Intel 486DX");
618
					off = 11;
619
					break;
620
				case 2:
621
					cprint(LINE_CPU, 0, "Intel 486SX");
622
					off = 11;
623
					break;
624
				case 3:
625
					cprint(LINE_CPU, 0, "Intel 486DX2");
626
					off = 12;
627
					break;
628
				case 4:
629
					cprint(LINE_CPU, 0, "Intel 486SL");
630
					off = 11;
631
					break;
632
				case 5:
633
					cprint(LINE_CPU, 0, "Intel 486SX2");
634
					off = 12;
635
					break;
636
				case 7:
637
					cprint(LINE_CPU, 0, "Intel 486DX2-WB");
638
					off = 15;
639
					break;
640
				case 8:
641
					cprint(LINE_CPU, 0, "Intel 486DX4");
642
					off = 12;
643
					break;
644
				case 9:
645
					cprint(LINE_CPU, 0, "Intel 486DX4-WB");
646
					off = 15;
647
					break;
648
				}
649
				/* Since we can't get CPU speed or cache info return */
650
				return;
651
			}
652
653
			/* Get the cache info */
654
			for (i=0; i<16; i++) {
655
#ifdef CPUID_DEBUG
656
				dprint(12,i*3,cpu_id.cache_info[i],2,1);
657
#endif
658
				switch(cpu_id.cache_info[i]) {
659
				case 0x6:
660
				case 0xa:
661
				case 0x66:
1.2.4 by Yann Dirson
Import upstream version 2.11
662
					l1_cache = 8;
1 by Yann Dirson
Import upstream version 1.55.1
663
					break;
664
				case 0x8:
665
				case 0xc:
666
				case 0x67:
667
				case 0x60:
1.2.4 by Yann Dirson
Import upstream version 2.11
668
					l1_cache = 16;
1 by Yann Dirson
Import upstream version 1.55.1
669
					break;
1.2.4 by Yann Dirson
Import upstream version 2.11
670
				case 0x9:
671
				case 0xd:
1 by Yann Dirson
Import upstream version 1.55.1
672
				case 0x68:
673
				case 0x2c:
674
				case 0x30:
1.2.4 by Yann Dirson
Import upstream version 2.11
675
					l1_cache = 32;
1 by Yann Dirson
Import upstream version 1.55.1
676
					break;
677
				case 0x40:
678
					l2_cache = 0;
679
					break;
680
				case 0x41:
681
				case 0x79:
682
				case 0x39:
683
				case 0x3b:
684
					l2_cache = 128;
685
					break;
1.2.2 by Martin Pitt
Import upstream version 1.70
686
				case 0x3a:
687
					l2_cache = 192;
688
					break;
1.2.4 by Yann Dirson
Import upstream version 2.11
689
				case 0x21:
1 by Yann Dirson
Import upstream version 1.55.1
690
				case 0x42:
691
				case 0x7a:
692
				case 0x82:
693
				case 0x3c:
1.2.4 by Yann Dirson
Import upstream version 2.11
694
				case 0x3f:
1 by Yann Dirson
Import upstream version 1.55.1
695
					l2_cache = 256;
696
					break;
1.2.2 by Martin Pitt
Import upstream version 1.70
697
				case 0x3d:
698
					l2_cache = 384;
699
					break;				
1 by Yann Dirson
Import upstream version 1.55.1
700
				case 0x43:
701
				case 0x7b:
702
				case 0x83:
703
				case 0x86:
1.2.2 by Martin Pitt
Import upstream version 1.70
704
				case 0x3e:
705
				case 0x7f:
1.2.4 by Yann Dirson
Import upstream version 2.11
706
				case 0x80:
1 by Yann Dirson
Import upstream version 1.55.1
707
					l2_cache = 512;
708
					break;
709
				case 0x44:
710
				case 0x7c:
711
				case 0x84:
712
				case 0x87:
1.2.2 by Martin Pitt
Import upstream version 1.70
713
				case 0x78:
1 by Yann Dirson
Import upstream version 1.55.1
714
					l2_cache = 1024;
715
					break;
716
				case 0x45:
717
				case 0x7d:
718
				case 0x85:
719
					l2_cache = 2048;
720
					break;
1.2.3 by Reinhard Tartler
Import upstream version 2.01
721
				case 0x48:
722
					l2_cache = 3072;
723
					break;
1.2.2 by Martin Pitt
Import upstream version 1.70
724
				case 0x49:
725
					l2_cache = 4096;
726
					break;
1.2.3 by Reinhard Tartler
Import upstream version 2.01
727
				case 0x4e:
728
					l2_cache = 6144;
729
					break;
1.2.5 by Yann Dirson
Import upstream version 4.00
730
				case 0x22:
731
				case 0xd0:
732
					l3_cache = 512;
733
				case 0x23:
1.2.4 by Yann Dirson
Import upstream version 2.11
734
				case 0xd1:
735
				case 0xd6:
736
					l3_cache = 1024;
737
					break;
1.2.5 by Yann Dirson
Import upstream version 4.00
738
				case 0xdc:
739
					l3_cache = 1536;
740
					break;
741
				case 0x25:
1.2.4 by Yann Dirson
Import upstream version 2.11
742
				case 0xd2:
743
				case 0xd7:
744
				case 0xe2:
745
					l3_cache = 2048;
746
					break;
1.2.5 by Yann Dirson
Import upstream version 4.00
747
				case 0xdd:
748
					l3_cache = 3072;
749
					break;				
750
				case 0x29:
751
				case 0x46:
1.2.4 by Yann Dirson
Import upstream version 2.11
752
				case 0xd8:
753
				case 0xe3:
754
					l3_cache = 4096;
755
					break;
1.2.5 by Yann Dirson
Import upstream version 4.00
756
				case 0x4a:
1.2.4 by Yann Dirson
Import upstream version 2.11
757
				case 0xde:
1.2.5 by Yann Dirson
Import upstream version 4.00
758
					l3_cache = 6144;
759
					break;
760
				case 0x47:
761
				case 0x4b:
1.2.4 by Yann Dirson
Import upstream version 2.11
762
				case 0xe4:
763
					l3_cache = 8192;
764
					break;				
1.2.5 by Yann Dirson
Import upstream version 4.00
765
				case 0x4c:
766
				case 0xea:
767
					l3_cache = 12288;
768
					break;	
769
				case 0x4d:
770
					l3_cache = 16374;
771
					break;						
772
				case 0xeb:
773
					l3_cache = 18432;
774
					break;
775
				case 0xec:
776
					l3_cache = 24576;
777
					break;		
1 by Yann Dirson
Import upstream version 1.55.1
778
				}
779
			}
780
781
			switch(cpu_id.type) {
782
			case 5:
783
				switch(cpu_id.model) {
784
				case 0:
785
				case 1:
786
				case 2:
787
				case 3:
788
				case 7:
789
					cprint(LINE_CPU, 0, "Pentium");
790
					if (l1_cache == 0) {
791
						l1_cache = 8;
792
					}
793
					off = 7;
794
					break;
795
				case 4:
796
				case 8:
797
					cprint(LINE_CPU, 0, "Pentium-MMX");
798
					if (l1_cache == 0) {
799
						l1_cache = 16;
800
					}
801
					off = 11;
802
					break;
803
				}
804
				break;
805
			case 6:
806
				switch(cpu_id.model) {
807
				case 0:
808
				case 1:
809
					cprint(LINE_CPU, 0, "Pentium Pro");
810
					off = 11;
811
					break;
812
				case 3:
813
					cprint(LINE_CPU, 0, "Pentium II");
814
					off = 10;
815
					break;
816
				case 5:
1.2.5 by Yann Dirson
Import upstream version 4.00
817
				if ((cpu_id.ext >> 16) & 0xF) {
818
					if(((cpu_id.ext >> 16) & 0xF) > 1) {
819
						cprint(LINE_CPU, 0, "Intel Core i3/i5");
820
						tsc_invariable = 1;
821
						imc_type = 0x0002;
822
						off = 16;
823
					} else {
824
						cprint(LINE_CPU, 0, "Intel EP80579");
825
						if (l2_cache == 0) { l2_cache = 256; }
826
						off = 13;						
827
					}
1.2.4 by Yann Dirson
Import upstream version 2.11
828
				} else {
1 by Yann Dirson
Import upstream version 1.55.1
829
					if (l2_cache == 0) {
830
						cprint(LINE_CPU, 0, "Celeron");
831
						off = 7;
832
					} else {
833
						cprint(LINE_CPU, 0, "Pentium II");
834
						off = 10;
835
					}
1.2.4 by Yann Dirson
Import upstream version 2.11
836
				 }
1 by Yann Dirson
Import upstream version 1.55.1
837
					break;
838
				case 6:
1.2.3 by Reinhard Tartler
Import upstream version 2.01
839
						if (l2_cache == 128) {
840
							cprint(LINE_CPU, 0, "Celeron");
841
							off = 7;
842
						} else {
843
							cprint(LINE_CPU, 0, "Pentium II");
844
							off = 10;
845
						}
1 by Yann Dirson
Import upstream version 1.55.1
846
					break;
847
				case 7:
848
				case 8:
849
				case 11:
1.2.3 by Reinhard Tartler
Import upstream version 2.01
850
					if (((cpu_id.ext >> 16) & 0xF) != 0) {
851
						tsc_invariable = 1;
852
						if (l2_cache < 1024) {
853
							cprint(LINE_CPU, 0, "Celeron");
854
							off = 7;
855
						} else {
856
							cprint(LINE_CPU, 0, "Intel Core 2");
857
							off = 12;
858
						}					
1 by Yann Dirson
Import upstream version 1.55.1
859
					} else {
1.2.3 by Reinhard Tartler
Import upstream version 2.01
860
						if (l2_cache == 128) {
861
							cprint(LINE_CPU, 0, "Celeron");
862
							off = 7;
863
						} else {
864
							cprint(LINE_CPU, 0, "Pentium III");
865
							off = 11;
866
						}
1 by Yann Dirson
Import upstream version 1.55.1
867
					}
868
					break;
869
				case 9:
870
					if (l2_cache == 512) {
871
						cprint(LINE_CPU, 0, "Celeron M (0.13)");
872
					} else {
873
						cprint(LINE_CPU, 0, "Pentium M (0.13)");
874
					}
875
					off = 16;
876
					break;
1.2.4 by Yann Dirson
Import upstream version 2.11
877
				case 10:
878
					if (((cpu_id.ext >> 16) & 0xF) != 0) {
879
						  tsc_invariable = 1;
1.2.5 by Yann Dirson
Import upstream version 4.00
880
						  imc_type = 0x0001;
1.2.4 by Yann Dirson
Import upstream version 2.11
881
							cprint(LINE_CPU, 0, "Intel Core i7");
882
							off = 13;
883
						} else {
884
							cprint(LINE_CPU, 0, "Pentium III Xeon");
885
							off = 16;
886
						}					
887
					break;
888
				case 12:
1.2.5 by Yann Dirson
Import upstream version 4.00
889
					if (((cpu_id.ext >> 16) & 0xF) > 1) {					
890
						cprint(LINE_CPU, 0, "Intel Core i9");
891
						tsc_invariable = 1;
892
						imc_type = 0x0002;
893
						off = 13;
894
					} else {
895
						l1_cache = 24;
896
						cprint(LINE_CPU, 0, "Atom (0.045)");
897
						off = 12;						
898
					}
1.2.4 by Yann Dirson
Import upstream version 2.11
899
					break;					
1 by Yann Dirson
Import upstream version 1.55.1
900
				case 13:
901
					if (l2_cache == 1024) {
902
						cprint(LINE_CPU, 0, "Celeron M (0.09)");
903
					} else {
904
						cprint(LINE_CPU, 0, "Pentium M (0.09)");
905
					}
906
					off = 16;
907
					break;
1.2.1 by Yann Dirson
Import upstream version 1.65
908
				case 14:
1.2.4 by Yann Dirson
Import upstream version 2.11
909
					if (((cpu_id.ext >> 16) & 0xF) != 0) {
910
						tsc_invariable = 1;
1.2.5 by Yann Dirson
Import upstream version 4.00
911
						imc_type = 0x0001;
912
						cprint(LINE_CPU, 0, "Intel Core i5/i7");
913
						off = 16;
1.2.4 by Yann Dirson
Import upstream version 2.11
914
					} else {
915
						cprint(LINE_CPU, 0, "Intel Core");
916
						off = 10;
917
					}
1.2.1 by Yann Dirson
Import upstream version 1.65
918
					break;				
919
				case 15:
1.2.3 by Reinhard Tartler
Import upstream version 2.01
920
					if (l2_cache == 1024) {
921
						cprint(LINE_CPU, 0, "Pentium E");
922
						off = 9;
923
					} else {
924
						cprint(LINE_CPU, 0, "Intel Core 2");
925
						off = 12;	
926
					}				
927
					tsc_invariable = 1;
1.2.1 by Yann Dirson
Import upstream version 1.65
928
					break;
1 by Yann Dirson
Import upstream version 1.55.1
929
				}
930
				break;
931
			case 15:
932
				switch(cpu_id.model) {
933
				case 0:
934
				case 1:
935
					if (l2_cache == 128) {
936
						cprint(LINE_CPU, 0, "Celeron (0.18)");
937
						off = 14;
938
					} else if (cpu_id.pwrcap == 0x0B) {
939
						cprint(LINE_CPU, 0, "Xeon DP (0.18)");
940
						off = 14;
941
					} else if (cpu_id.pwrcap == 0x0C) {
942
						cprint(LINE_CPU, 0, "Xeon MP (0.18)");
943
						off = 14;
944
					} else {
945
						cprint(LINE_CPU, 0, "Pentium 4 (0.18)");
946
						off = 16;
947
					}
948
					break;
949
				case 2:
950
					if (l2_cache == 128) {
951
						cprint(LINE_CPU, 0, "Celeron (0.13)");
952
						off = 14;
953
					} else if (cpu_id.pwrcap == 0x0B) {
954
						cprint(LINE_CPU, 0, "Xeon DP (0.13)");
955
						off = 14;
956
					} else if (cpu_id.pwrcap == 0x0C) {
957
						cprint(LINE_CPU, 0, "Xeon MP (0.13)");
958
						off = 14;
959
					} else {
960
						cprint(LINE_CPU, 0, "Pentium 4 (0.13)");
961
						off = 16;
962
					}
963
					break;
964
				case 3:
965
				case 4:
966
					if (l2_cache == 256) {
967
						cprint(LINE_CPU, 0, "Celeron (0.09)");
968
						off = 14;
969
					} else if (cpu_id.pwrcap == 0x0B) {
970
						cprint(LINE_CPU, 0, "Xeon DP (0.09)");
971
						off = 14;
972
					} else if (cpu_id.pwrcap == 0x0C) {
973
						cprint(LINE_CPU, 0, "Xeon MP (0.09)");
974
						off = 14;
1.2.1 by Yann Dirson
Import upstream version 1.65
975
					} else if ((cpu_id.step == 0x4 || cpu_id.step == 0x7) && cpu_id.model == 0x4) {
976
						cprint(LINE_CPU, 0, "Pentium D (0.09)");
977
						off = 16;
1 by Yann Dirson
Import upstream version 1.55.1
978
					} else {
979
						cprint(LINE_CPU, 0, "Pentium 4 (0.09)");
980
						off = 16;
981
					}
982
					break;
1.2.1 by Yann Dirson
Import upstream version 1.65
983
				case 6:
984
					cprint(LINE_CPU, 0, "Pentium D (65nm)");
1.1.1 by Yann Dirson
Import upstream version 1.60
985
					off = 16;		
986
					break;
987
				default:
988
					cprint(LINE_CPU, 0, "Unknown Intel");
989
					off = 13;		
990
					break;													
1 by Yann Dirson
Import upstream version 1.55.1
991
				}
992
				break;
993
			}
994
		}
995
		break;
996
997
	/* VIA/Cyrix/Centaur Processors with CPUID */
998
	case 'C':
999
		if ( cpu_id.vend_id[1] == 'e' ) {	/* CentaurHauls */
1.2.4 by Yann Dirson
Import upstream version 2.11
1000
			l1_cache = cpu_id.cache_info[3] + cpu_id.cache_info[7];
1001
			l2_cache = cpu_id.cache_info[11];
1 by Yann Dirson
Import upstream version 1.55.1
1002
			switch(cpu_id.type){
1003
			case 5:
1004
				cprint(LINE_CPU, 0, "Centaur 5x86");
1005
				off = 12;
1006
				break;
1007
			case 6: // VIA C3
1.2.3 by Reinhard Tartler
Import upstream version 2.01
1008
				switch(cpu_id.model){
1009
					default:
1010
						if (cpu_id.step < 8) {
1011
							cprint(LINE_CPU, 0, "VIA C3 Samuel2");
1012
							off = 14;
1013
						} else {
1014
							cprint(LINE_CPU, 0, "VIA C3 Eden");
1015
							off = 11;
1016
						}
1017
						break;
1018
					case 10:
1.2.4 by Yann Dirson
Import upstream version 2.11
1019
						cprint(LINE_CPU, 0, "VIA C7 (C5J)");
1020
						l1_cache = 64;
1021
						l2_cache = 128;
1.2.3 by Reinhard Tartler
Import upstream version 2.01
1022
						off = 16;
1023
						break;
1024
					case 13:
1025
						cprint(LINE_CPU, 0, "VIA C7 (C5R)");
1.2.4 by Yann Dirson
Import upstream version 2.11
1026
						l1_cache = 64;
1027
						l2_cache = 128;
1.2.3 by Reinhard Tartler
Import upstream version 2.01
1028
						off = 12;
1029
						break;
1030
					case 15:
1031
						cprint(LINE_CPU, 0, "VIA Isaiah (CN)");
1.2.4 by Yann Dirson
Import upstream version 2.11
1032
						l1_cache = 64;
1033
						l2_cache = 1024;
1.2.3 by Reinhard Tartler
Import upstream version 2.01
1034
						off = 15;
1035
						break;
1 by Yann Dirson
Import upstream version 1.55.1
1036
				}
1037
			}
1038
		} else {				/* CyrixInstead */
1039
			switch(cpu_id.type) {
1040
			case 5:
1041
				switch(cpu_id.model) {
1042
				case 0:
1043
					cprint(LINE_CPU, 0, "Cyrix 6x86MX/MII");
1044
					off = 16;
1045
					break;
1046
				case 4:
1047
					cprint(LINE_CPU, 0, "Cyrix GXm");
1048
					off = 9;
1049
					break;
1050
				}
1051
				return;
1052
1053
			case 6: // VIA C3
1054
				switch(cpu_id.model) {
1055
				case 6:
1056
					cprint(LINE_CPU, 0, "Cyrix III");
1057
					off = 9;
1058
					break;
1059
				case 7:
1060
					if (cpu_id.step < 8) {
1061
						cprint(LINE_CPU, 0, "VIA C3 Samuel2");
1062
						off = 14;
1063
					} else {
1064
						cprint(LINE_CPU, 0, "VIA C3 Ezra-T");
1065
						off = 13;
1066
					}
1067
					break;
1068
				case 8:
1069
					cprint(LINE_CPU, 0, "VIA C3 Ezra-T");
1070
					off = 13;
1071
					break;
1072
				case 9:
1073
					cprint(LINE_CPU, 0, "VIA C3 Nehemiah");
1074
					off = 15;
1075
					break;
1076
				}
1077
				// L1 = L2 = 64 KB from Cyrix III to Nehemiah
1078
				l1_cache = 64;
1079
				l2_cache = 64;
1080
				break;
1081
			}
1082
		}
1083
		break;
1084
1085
	/* Unknown processor */
1086
	default:
1087
		off = 3;
1088
		/* Make a guess at the family */
1089
		switch(cpu_id.type) {
1090
		case 5:
1091
			cprint(LINE_CPU, 0, "586");
1092
			return;
1093
		case 6:
1094
			cprint(LINE_CPU, 0, "686");
1095
			return;
1096
		}
1097
	}
1098
1099
	/* We are here only if the CPU type supports the rdtsc instruction */
1100
1101
	/* Print CPU speed */
1102
	if ((speed = cpuspeed()) > 0) {
1103
		if (speed < 1000000-50) {
1104
			speed += 50; /* for rounding */
1105
			cprint(LINE_CPU, off, "    . MHz");
1106
			dprint(LINE_CPU, off+1, speed/1000, 3, 1);
1107
			dprint(LINE_CPU, off+5, (speed/100)%10, 1, 0);
1108
		} else {
1109
			speed += 500; /* for rounding */
1.2.1 by Yann Dirson
Import upstream version 1.65
1110
			cprint(LINE_CPU, off, "      MHz");
1 by Yann Dirson
Import upstream version 1.55.1
1111
			dprint(LINE_CPU, off, speed/1000, 5, 0);
1112
		}
1113
		extclock = speed;
1114
	}
1115
1116
	/* Print out L1 cache info */
1117
	/* To measure L1 cache speed we use a block size that is 1/4th */
1118
	/* of the total L1 cache size since half of it is for instructions */
1119
	if (l1_cache) {
1.2.3 by Reinhard Tartler
Import upstream version 2.01
1120
		cprint(LINE_CPU+1, 0, "L1 Cache:     K  ");
1 by Yann Dirson
Import upstream version 1.55.1
1121
		dprint(LINE_CPU+1, 11, l1_cache, 3, 0);
1.2.4 by Yann Dirson
Import upstream version 2.11
1122
		if ((speed=memspeed((ulong)mapping(0x100), (l1_cache / 4) * 1024, 200, MS_COPY))) {
1.2.3 by Reinhard Tartler
Import upstream version 2.01
1123
			cprint(LINE_CPU+1, 16, "       MB/s");
1124
			dprint(LINE_CPU+1, 16, speed, 6, 0);
1 by Yann Dirson
Import upstream version 1.55.1
1125
		}
1126
	}
1127
1128
	/* Print out L2 cache info */
1129
	/* We measure the L2 cache speed by using a block size that is */
1130
	/* the size of the L1 cache.  We have to fudge if the L1 */
1131
	/* cache is bigger than the L2 */
1132
	if (l2_cache) {
1.2.3 by Reinhard Tartler
Import upstream version 2.01
1133
		cprint(LINE_CPU+2, 0, "L2 Cache:     K  ");
1134
		dprint(LINE_CPU+2, 10, l2_cache, 4, 0);
1 by Yann Dirson
Import upstream version 1.55.1
1135
		dprint(LINE_CPU+2, 10, l2_cache, 4, 0);
1136
1137
		if (l2_cache < l1_cache) {
1138
			i = l1_cache / 4 + l2_cache / 4;
1139
		} else {
1140
			i = l1_cache;
1141
		}
1.2.4 by Yann Dirson
Import upstream version 2.11
1142
		if ((speed=memspeed((ulong)mapping(0x100), i*1024, 200, MS_COPY))) {
1.2.3 by Reinhard Tartler
Import upstream version 2.01
1143
			cprint(LINE_CPU+2, 16, "       MB/s");
1144
			dprint(LINE_CPU+2, 16, speed, 6, 0);
1 by Yann Dirson
Import upstream version 1.55.1
1145
		}
1146
	}
1147
1.2.4 by Yann Dirson
Import upstream version 2.11
1148
	/* Print out L3 cache info */
1149
	/* We measure the L3 cache speed by using a block size that is */
1150
	/* the size of the L2 cache. */
1151
1152
	if (l3_cache) {
1153
		cprint(LINE_CPU+3, 0, "L3 Cache:     K  ");
1154
		dprint(LINE_CPU+3, 10, l3_cache, 4, 0);
1155
		dprint(LINE_CPU+3, 10, l3_cache, 4, 0);
1156
1157
		i = l2_cache*2;
1158
1159
		if ((speed=memspeed((ulong)mapping(0x100), i*1024, 150, MS_COPY))) {
1160
			cprint(LINE_CPU+3, 16, "       MB/s");
1161
			dprint(LINE_CPU+3, 16, speed, 6, 0);
1162
		}
1163
	}
1164
1165
1166
	/* Determine memory speed.  To find the memory speed we use */
1167
	/* A block size that is 5x the sum of the L1, L2 & L3 caches */
1168
	i = (l3_cache + l2_cache + l1_cache) * 5;
1169
		
1 by Yann Dirson
Import upstream version 1.55.1
1170
	/* Make sure that we have enough memory to do the test */
1171
	if ((1 + (i * 2)) > (v->plim_upper << 2)) {
1172
		i = ((v->plim_upper <<2) - 1) / 2;
1173
	}
1.2.4 by Yann Dirson
Import upstream version 2.11
1174
	if((speed = memspeed((ulong)mapping(0x100), i*1024, 50, MS_COPY))) {
1175
		cprint(LINE_CPU+4, 16, "       MB/s");
1176
		dprint(LINE_CPU+4, 16, speed, 6, 0);
1 by Yann Dirson
Import upstream version 1.55.1
1177
	}
1178
1179
	/* Record the starting time */
1180
	asm __volatile__ ("rdtsc":"=a" (v->startl),"=d" (v->starth));
1181
	v->snapl = v->startl;
1182
	v->snaph = v->starth;
1183
	v->rdtsc = 1;
1184
	if (l1_cache == 0) { l1_cache = 66; }
1185
	if (l2_cache == 0) { l1_cache = 666; }
1186
}
1187
1188
/* Find cache-able memory size */
1189
static void cacheable(void)
1190
{
1191
	ulong speed, pspeed;
1192
	ulong paddr, mem_top, cached;
1193
1194
	mem_top = v->pmap[v->msegs - 1].end;
1195
	cached = v->test_pages;
1196
	pspeed = 0;
1197
	for (paddr=0x200; paddr <= mem_top - 64; paddr+=0x400) {
1198
		int i;
1199
		int found;
1200
		/* See if the paddr is at a testable location */
1201
		found = 0;
1202
		for(i = 0; i < v->msegs; i++) {
1203
			if ((v->pmap[i].start >= paddr)  &&
1204
				(v->pmap[i].end <= (paddr + 32))) {
1205
				found = 1;
1206
				break;
1207
			}
1208
		}
1209
		if (!found) {
1210
			continue;
1211
		}
1212
		/* Map the range and perform the test */
1213
		map_page(paddr);
1.2.4 by Yann Dirson
Import upstream version 2.11
1214
		speed = memspeed((ulong)mapping(paddr), 32*4096, 1, MS_READ);
1 by Yann Dirson
Import upstream version 1.55.1
1215
		if (pspeed) {
1216
			if (speed < pspeed) {
1217
				cached -= 32;
1218
			}
1219
			pspeed = (ulong)((float)speed * 0.7);
1220
		}
1221
	}
1222
	aprint(LINE_INFO, COL_CACHE_TOP, cached);
1223
	/* Ensure the default set of pages are mapped */
1224
	map_page(0);
1225
	map_page(0x80000);
1226
}
1227
1228
1229
/* #define TICKS 5 * 11832 (count = 6376)*/
1230
/* #define TICKS (65536 - 12752) */
1231
/* #define TICKS (65536 - 8271) */
1232
#define TICKS	59659			/* Program counter to 50 ms = 59659 clks */
1233
1234
/* Returns CPU clock in khz */
1235
static int cpuspeed(void)
1236
{
1237
	int loops;
1238
1239
	/* Setup timer */
1240
	outb((inb(0x61) & ~0x02) | 0x01, 0x61);
1241
	outb(0xb0, 0x43);
1242
	outb(TICKS & 0xff, 0x42);
1243
	outb(TICKS >> 8, 0x42);
1244
1245
	asm __volatile__ ("rdtsc":"=a" (st_low),"=d" (st_high));
1246
1247
	loops = 0;
1248
	do {
1249
		loops++;
1250
	} while ((inb(0x61) & 0x20) == 0);
1251
1252
	asm __volatile__ (
1253
		"rdtsc\n\t" \
1254
		"subl st_low,%%eax\n\t" \
1255
		"sbbl st_high,%%edx\n\t" \
1256
		:"=a" (end_low), "=d" (end_high)
1257
	);
1258
1259
	/* Make sure we have a credible result */
1260
	if (loops < 4 || end_low < 50000) {
1261
		return(-1);
1262
	}
1.2.3 by Reinhard Tartler
Import upstream version 2.01
1263
1264
	if(tsc_invariable){ end_low = correct_tsc(end_low);	}
1265
1266
	v->clks_msec = end_low/50;	
1 by Yann Dirson
Import upstream version 1.55.1
1267
	return(v->clks_msec);
1268
}
1269
1270
/* Measure cache/memory speed by copying a block of memory. */
1271
/* Returned value is kbytes/second */
1.2.3 by Reinhard Tartler
Import upstream version 2.01
1272
ulong memspeed(ulong src, ulong len, int iter, int type)
1 by Yann Dirson
Import upstream version 1.55.1
1273
{
1274
	ulong dst;
1275
	ulong wlen;
1276
	int i;
1277
1278
	dst = src + len;
1279
	wlen = len / 4;  /* Length is bytes */
1280
1281
	/* Calibrate the overhead with a zero word copy */
1282
	asm __volatile__ ("rdtsc":"=a" (st_low),"=d" (st_high));
1283
	for (i=0; i<iter; i++) {
1284
		asm __volatile__ (
1285
			"movl %0,%%esi\n\t" \
1.2.3 by Reinhard Tartler
Import upstream version 2.01
1286
       		 	"movl %1,%%edi\n\t" \
1287
       		 	"movl %2,%%ecx\n\t" \
1288
       		 	"cld\n\t" \
1289
       		 	"rep\n\t" \
1290
       		 	"movsl\n\t" \
1 by Yann Dirson
Import upstream version 1.55.1
1291
				:: "g" (src), "g" (dst), "g" (0)
1292
			: "esi", "edi", "ecx"
1293
		);
1294
	}
1295
	asm __volatile__ ("rdtsc":"=a" (cal_low),"=d" (cal_high));
1296
1297
	/* Compute the overhead time */
1298
	asm __volatile__ (
1299
		"subl %2,%0\n\t"
1300
		"sbbl %3,%1"
1301
		:"=a" (cal_low), "=d" (cal_high)
1302
		:"g" (st_low), "g" (st_high),
1303
		"0" (cal_low), "1" (cal_high)
1304
	);
1305
1.2.3 by Reinhard Tartler
Import upstream version 2.01
1306
1307
	/* Now measure the speed */
1308
	switch (type) {
1309
	case MS_COPY:
1310
		/* Do the first copy to prime the cache */
1311
		asm __volatile__ (
1312
			"movl %0,%%esi\n\t" \
1313
			"movl %1,%%edi\n\t" \
1314
       		 	"movl %2,%%ecx\n\t" \
1315
       		 	"cld\n\t" \
1316
       		 	"rep\n\t" \
1317
       		 	"movsl\n\t" \
1 by Yann Dirson
Import upstream version 1.55.1
1318
			:: "g" (src), "g" (dst), "g" (wlen)
1.2.3 by Reinhard Tartler
Import upstream version 2.01
1319
			: "esi", "edi", "ecx"
1320
		);
1321
		asm __volatile__ ("rdtsc":"=a" (st_low),"=d" (st_high));
1322
		for (i=0; i<iter; i++) {
1323
		        asm __volatile__ (
1324
				"movl %0,%%esi\n\t" \
1325
				"movl %1,%%edi\n\t" \
1326
       			 	"movl %2,%%ecx\n\t" \
1327
       			 	"cld\n\t" \
1328
       			 	"rep\n\t" \
1329
       			 	"movsl\n\t" \
1 by Yann Dirson
Import upstream version 1.55.1
1330
				:: "g" (src), "g" (dst), "g" (wlen)
1.2.3 by Reinhard Tartler
Import upstream version 2.01
1331
				: "esi", "edi", "ecx"
1332
			);
1333
		}
1334
		asm __volatile__ ("rdtsc":"=a" (end_low),"=d" (end_high));
1335
		break;
1336
	case MS_WRITE:
1337
		asm __volatile__ ("rdtsc":"=a" (st_low),"=d" (st_high));
1338
		for (i=0; i<iter; i++) {
1339
			asm __volatile__ (
1340
       			 	"movl %0,%%ecx\n\t" \
1341
				"movl %1,%%edi\n\t" \
1342
       			 	"movl %2,%%eax\n\t" \
1343
                                "rep\n\t" \
1344
                                "stosl\n\t"
1345
                                :: "g" (wlen), "g" (dst), "g" (0)
1346
				: "edi", "ecx", "eax"
1347
                        );
1348
		}
1349
		asm __volatile__ ("rdtsc":"=a" (end_low),"=d" (end_high));
1350
		break;
1351
	case MS_READ:
1352
		asm __volatile__ (
1353
			"movl %0,%%esi\n\t" \
1354
			"movl %1,%%ecx\n\t" \
1355
       	 		"cld\n\t" \
1356
       	 		"L1:\n\t" \
1357
			"lodsl\n\t" \
1358
       	 		"loop L1\n\t" \
1359
			:: "g" (src), "g" (wlen)
1360
			: "esi", "ecx"
1 by Yann Dirson
Import upstream version 1.55.1
1361
		);
1.2.3 by Reinhard Tartler
Import upstream version 2.01
1362
		asm __volatile__ ("rdtsc":"=a" (st_low),"=d" (st_high));
1363
		for (i=0; i<iter; i++) {
1364
		        asm __volatile__ (
1365
				"movl %0,%%esi\n\t" \
1366
				"movl %1,%%ecx\n\t" \
1367
       		 		"cld\n\t" \
1368
       		 		"L2:\n\t" \
1369
				"lodsl\n\t" \
1370
       		 		"loop L2\n\t" \
1371
				:: "g" (src), "g" (wlen)
1372
				: "esi", "ecx"
1373
			);
1374
		}
1375
		asm __volatile__ ("rdtsc":"=a" (end_low),"=d" (end_high));
1376
		break;
1 by Yann Dirson
Import upstream version 1.55.1
1377
	}
1378
1379
	/* Compute the elapsed time */
1380
	asm __volatile__ (
1381
		"subl %2,%0\n\t"
1382
		"sbbl %3,%1"
1383
		:"=a" (end_low), "=d" (end_high)
1384
		:"g" (st_low), "g" (st_high),
1385
		"0" (end_low), "1" (end_high)
1386
	);
1387
	/* Subtract the overhead time */
1388
	asm __volatile__ (
1389
		"subl %2,%0\n\t"
1390
		"sbbl %3,%1"
1391
		:"=a" (end_low), "=d" (end_high)
1392
		:"g" (cal_low), "g" (cal_high),
1393
		"0" (end_low), "1" (end_high)
1394
	);
1395
1396
	/* Make sure that the result fits in 32 bits */
1397
	if (end_high) {
1398
		return(0);
1399
	}
1400
1.2.3 by Reinhard Tartler
Import upstream version 2.01
1401
	/* If this was a copy adjust the time */
1402
	if (type == MS_COPY) {
1403
		end_low /= 2;
1404
	}
1 by Yann Dirson
Import upstream version 1.55.1
1405
1406
	/* Convert to clocks/KB */
1407
	end_low /= len;
1408
	end_low *= 1024;
1409
	end_low /= iter;
1410
	if (end_low == 0) {
1411
		return(0);
1412
	}
1413
1.2.3 by Reinhard Tartler
Import upstream version 2.01
1414
	if(tsc_invariable){ end_low = correct_tsc(end_low);	}
1415
		
1 by Yann Dirson
Import upstream version 1.55.1
1416
	/* Convert to kbytes/sec */
1417
	return((v->clks_msec)/end_low);
1418
}
1.2.3 by Reinhard Tartler
Import upstream version 2.01
1419
1420
ulong correct_tsc(ulong el_org)
1421
{
1422
	
1423
	float coef_now, coef_max;
1424
	int msr_lo, msr_hi, is_xe;
1425
	
1426
	rdmsr(0x198, msr_lo, msr_hi);
1427
	is_xe = (msr_lo >> 31) & 0x1;		
1428
	
1429
	if(is_xe){
1430
		rdmsr(0x198, msr_lo, msr_hi);
1431
		coef_max = ((msr_hi >> 8) & 0x1F);	
1432
		if ((msr_hi >> 14) & 0x1) { coef_max = coef_max + 0.5f; }
1433
	} else {
1434
		rdmsr(0x17, msr_lo, msr_hi);
1435
		coef_max = ((msr_lo >> 8) & 0x1F);
1436
		if ((msr_lo >> 14) & 0x1) { coef_max = coef_max + 0.5f; }
1437
	}
1438
	
1439
	if((cpu_id.feature_flag >> 7) & 1) {
1440
		rdmsr(0x198, msr_lo, msr_hi);
1441
		coef_now = ((msr_lo >> 8) & 0x1F);
1442
		if ((msr_lo >> 14) & 0x1) { coef_now = coef_now + 0.5f; }
1443
	} else {
1444
		rdmsr(0x2A, msr_lo, msr_hi);
1445
		coef_now = (msr_lo >> 22) & 0x1F;
1446
	}
1447
		
1448
	if(coef_max && coef_now) { el_org = (ulong)(el_org * coef_now / coef_max); }
1449
	
1450
	return el_org;
1451
1452
}