Import 2.2.0pre6
[davej-history.git] / arch / i386 / kernel / setup.c
blobcfab3ecfc7a026457b26f18a34ffd32694b66eda
1 /*
2 * linux/arch/i386/kernel/setup.c
4 * Copyright (C) 1995 Linus Torvalds
6 * Enhanced CPU type detection by Mike Jagdis, Patrick St. Jean
7 * and Martin Mares, November 1997.
8 */
11 * This file handles the architecture-dependent parts of initialization
14 #include <linux/errno.h>
15 #include <linux/sched.h>
16 #include <linux/kernel.h>
17 #include <linux/mm.h>
18 #include <linux/stddef.h>
19 #include <linux/unistd.h>
20 #include <linux/ptrace.h>
21 #include <linux/malloc.h>
22 #include <linux/user.h>
23 #include <linux/a.out.h>
24 #include <linux/tty.h>
25 #include <linux/ioport.h>
26 #include <linux/delay.h>
27 #include <linux/config.h>
28 #include <linux/init.h>
29 #ifdef CONFIG_APM
30 #include <linux/apm_bios.h>
31 #endif
32 #ifdef CONFIG_BLK_DEV_RAM
33 #include <linux/blk.h>
34 #endif
35 #include <asm/processor.h>
36 #include <linux/console.h>
37 #include <asm/uaccess.h>
38 #include <asm/system.h>
39 #include <asm/io.h>
40 #include <asm/smp.h>
43 * Machine setup..
46 char ignore_irq13 = 0; /* set if exception 16 works */
47 struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
50 * Bus types ..
52 int EISA_bus = 0;
53 int MCA_bus = 0;
55 /* for MCA, but anyone else can use it if they want */
56 unsigned int machine_id = 0;
57 unsigned int machine_submodel_id = 0;
58 unsigned int BIOS_revision = 0;
61 * Setup options
63 struct drive_info_struct { char dummy[32]; } drive_info;
64 struct screen_info screen_info;
65 #ifdef CONFIG_APM
66 struct apm_bios_info apm_bios_info;
67 #endif
68 struct sys_desc_table_struct {
69 unsigned short length;
70 unsigned char table[0];
73 unsigned char aux_device_present;
75 #ifdef CONFIG_BLK_DEV_RAM
76 extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */
77 extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */
78 extern int rd_image_start; /* starting block # of image */
79 #endif
81 extern int root_mountflags;
82 extern int _etext, _edata, _end;
83 extern unsigned long cpu_hz;
86 * This is set up by the setup-routine at boot-time
88 #define PARAM ((unsigned char *)empty_zero_page)
89 #define SCREEN_INFO (*(struct screen_info *) (PARAM+0))
90 #define EXT_MEM_K (*(unsigned short *) (PARAM+2))
91 #define ALT_MEM_K (*(unsigned long *) (PARAM+0x1e0))
92 #define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+0x40))
93 #define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
94 #define SYS_DESC_TABLE (*(struct sys_desc_table_struct*)(PARAM+0xa0))
95 #define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
96 #define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))
97 #define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC))
98 #define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF))
99 #define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))
100 #define KERNEL_START (*(unsigned long *) (PARAM+0x214))
101 #define INITRD_START (*(unsigned long *) (PARAM+0x218))
102 #define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))
103 #define COMMAND_LINE ((char *) (PARAM+2048))
104 #define COMMAND_LINE_SIZE 256
106 #define RAMDISK_IMAGE_START_MASK 0x07FF
107 #define RAMDISK_PROMPT_FLAG 0x8000
108 #define RAMDISK_LOAD_FLAG 0x4000
111 static char command_line[COMMAND_LINE_SIZE] = { 0, };
112 char saved_command_line[COMMAND_LINE_SIZE];
114 __initfunc(void setup_arch(char **cmdline_p,
115 unsigned long * memory_start_p, unsigned long * memory_end_p))
117 unsigned long memory_start, memory_end;
118 char c = ' ', *to = command_line, *from = COMMAND_LINE;
119 int len = 0;
120 static unsigned char smptrap=0;
122 if (smptrap)
123 return;
124 smptrap=1;
126 ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
127 drive_info = DRIVE_INFO;
128 screen_info = SCREEN_INFO;
129 #ifdef CONFIG_APM
130 apm_bios_info = APM_BIOS_INFO;
131 #endif
132 if( SYS_DESC_TABLE.length != 0 ) {
133 MCA_bus = SYS_DESC_TABLE.table[3] &0x2;
134 machine_id = SYS_DESC_TABLE.table[0];
135 machine_submodel_id = SYS_DESC_TABLE.table[1];
136 BIOS_revision = SYS_DESC_TABLE.table[2];
138 aux_device_present = AUX_DEVICE_INFO;
139 memory_end = (1<<20) + (EXT_MEM_K<<10);
140 #ifndef STANDARD_MEMORY_BIOS_CALL
142 unsigned long memory_alt_end = (1<<20) + (ALT_MEM_K<<10);
143 /* printk(KERN_DEBUG "Memory sizing: %08x %08x\n", memory_end, memory_alt_end); */
144 if (memory_alt_end > memory_end)
145 memory_end = memory_alt_end;
147 #endif
149 memory_end &= PAGE_MASK;
150 #ifdef CONFIG_BLK_DEV_RAM
151 rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
152 rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
153 rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
154 #endif
155 if (!MOUNT_ROOT_RDONLY)
156 root_mountflags &= ~MS_RDONLY;
157 memory_start = (unsigned long) &_end;
158 init_task.mm->start_code = PAGE_OFFSET;
159 init_task.mm->end_code = (unsigned long) &_etext;
160 init_task.mm->end_data = (unsigned long) &_edata;
161 init_task.mm->brk = (unsigned long) &_end;
163 /* Save unparsed command line copy for /proc/cmdline */
164 memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
165 saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
167 for (;;) {
169 * "mem=nopentium" disables the 4MB page tables.
170 * "mem=XXX[kKmM]" overrides the BIOS-reported
171 * memory size
173 if (c == ' ' && *(const unsigned long *)from == *(const unsigned long *)"mem=") {
174 if (to != command_line) to--;
175 if (!memcmp(from+4, "nopentium", 9)) {
176 from += 9+4;
177 boot_cpu_data.x86_capability &= ~X86_FEATURE_PSE;
178 } else {
179 memory_end = simple_strtoul(from+4, &from, 0);
180 if ( *from == 'K' || *from == 'k' ) {
181 memory_end = memory_end << 10;
182 from++;
183 } else if ( *from == 'M' || *from == 'm' ) {
184 memory_end = memory_end << 20;
185 from++;
189 c = *(from++);
190 if (!c)
191 break;
192 if (COMMAND_LINE_SIZE <= ++len)
193 break;
194 *(to++) = c;
196 *to = '\0';
197 *cmdline_p = command_line;
199 #define VMALLOC_RESERVE (64 << 20) /* 64MB for vmalloc */
200 #define MAXMEM ((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE))
202 if (memory_end > MAXMEM)
204 memory_end = MAXMEM;
205 printk(KERN_WARNING "Warning only %ldMB will be used.\n",
206 MAXMEM>>20);
209 memory_end += PAGE_OFFSET;
210 *memory_start_p = memory_start;
211 *memory_end_p = memory_end;
213 #ifdef CONFIG_BLK_DEV_INITRD
214 if (LOADER_TYPE) {
215 initrd_start = INITRD_START ? INITRD_START + PAGE_OFFSET : 0;
216 initrd_end = initrd_start+INITRD_SIZE;
217 if (initrd_end > memory_end) {
218 printk("initrd extends beyond end of memory "
219 "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
220 initrd_end,memory_end);
221 initrd_start = 0;
224 #endif
226 /* request I/O space for devices used on all i[345]86 PCs */
227 request_region(0x00,0x20,"dma1");
228 request_region(0x40,0x20,"timer");
229 request_region(0x80,0x10,"dma page reg");
230 request_region(0xc0,0x20,"dma2");
231 request_region(0xf0,0x10,"fpu");
233 #ifdef CONFIG_VT
234 #if defined(CONFIG_VGA_CONSOLE)
235 conswitchp = &vga_con;
236 #elif defined(CONFIG_DUMMY_CONSOLE)
237 conswitchp = &dummy_con;
238 #endif
239 #endif
241 * Check the bugs that will bite us before we get booting
246 __initfunc(static int amd_model(struct cpuinfo_x86 *c))
248 unsigned int n, dummy, *v;
250 /* Actually we must have cpuid or we could never have
251 * figured out that this was AMD from the vendor info :-).
254 cpuid(0x80000000, &n, &dummy, &dummy, &dummy);
255 if (n < 4)
256 return 0;
257 cpuid(0x80000001, &dummy, &dummy, &dummy, &(c->x86_capability));
258 v = (unsigned int *) c->x86_model_id;
259 cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
260 cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
261 cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
262 c->x86_model_id[48] = 0;
263 return 1;
267 * Read Cyrix DEVID registers (DIR) to get more detailed info. about the CPU
269 static inline void do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
271 unsigned char ccr2, ccr3;
273 /* we test for DEVID by checking whether CCR3 is writable */
274 cli();
275 ccr3 = getCx86(CX86_CCR3);
276 setCx86(CX86_CCR3, ccr3 ^ 0x80);
277 getCx86(0xc0); /* dummy to change bus */
279 if (getCx86(CX86_CCR3) == ccr3) { /* no DEVID regs. */
280 ccr2 = getCx86(CX86_CCR2);
281 setCx86(CX86_CCR2, ccr2 ^ 0x04);
282 getCx86(0xc0); /* dummy */
284 if (getCx86(CX86_CCR2) == ccr2) /* old Cx486SLC/DLC */
285 *dir0 = 0xfd;
286 else { /* Cx486S A step */
287 setCx86(CX86_CCR2, ccr2);
288 *dir0 = 0xfe;
291 else {
292 setCx86(CX86_CCR3, ccr3); /* restore CCR3 */
294 /* read DIR0 and DIR1 CPU registers */
295 *dir0 = getCx86(CX86_DIR0);
296 *dir1 = getCx86(CX86_DIR1);
298 sti();
302 * Cx86_dir0_msb is a HACK needed by check_cx686_cpuid/slop in bugs.h in
303 * order to identify the Cyrix CPU model after we're out of setup.c
305 unsigned char Cx86_dir0_msb __initdata = 0;
307 static char Cx86_model[][9] __initdata = {
308 "Cx486", "Cx486", "5x86 ", "6x86", "MediaGX ", "6x86MX ",
309 "M II ", "Unknown"
311 static char Cx486_name[][5] __initdata = {
312 "SLC", "DLC", "SLC2", "DLC2", "SRx", "DRx",
313 "SRx2", "DRx2"
315 static char Cx486S_name[][4] __initdata = {
316 "S", "S2", "Se", "S2e"
318 static char Cx486D_name[][4] __initdata = {
319 "DX", "DX2", "?", "?", "?", "DX4"
321 static char Cx86_cb[] __initdata = "?.5x Core/Bus Clock";
322 static char cyrix_model_mult1[] __initdata = "12??43";
323 static char cyrix_model_mult2[] __initdata = "12233445";
325 __initfunc(static void cyrix_model(struct cpuinfo_x86 *c))
327 unsigned char dir0, dir0_msn, dir0_lsn, dir1 = 0;
328 char *buf = c->x86_model_id;
329 const char *p = NULL;
331 do_cyrix_devid(&dir0, &dir1);
333 Cx86_dir0_msb = dir0_msn = dir0 >> 4; /* identifies CPU "family" */
334 dir0_lsn = dir0 & 0xf; /* model or clock multiplier */
336 /* common case step number/rev -- exceptions handled below */
337 c->x86_model = (dir1 >> 4) + 1;
338 c->x86_mask = dir1 & 0xf;
340 /* Now cook; the original recipe is by Channing Corn, from Cyrix.
341 * We do the same thing for each generation: we work out
342 * the model, multiplier and stepping. Black magic included,
343 * to make the silicon step/rev numbers match the printed ones.
346 switch (dir0_msn) {
347 unsigned char tmp;
349 case 0: /* Cx486SLC/DLC/SRx/DRx */
350 p = Cx486_name[dir0_lsn & 7];
351 break;
353 case 1: /* Cx486S/DX/DX2/DX4 */
354 p = (dir0_lsn & 8) ? Cx486D_name[dir0_lsn & 5]
355 : Cx486S_name[dir0_lsn & 3];
356 break;
358 case 2: /* 5x86 */
359 Cx86_cb[2] = cyrix_model_mult1[dir0_lsn & 5];
360 p = Cx86_cb+2;
361 break;
363 case 3: /* 6x86/6x86L */
364 Cx86_cb[1] = ' ';
365 Cx86_cb[2] = cyrix_model_mult1[dir0_lsn & 5];
366 if (dir1 > 0x21) { /* 686L */
367 Cx86_cb[0] = 'L';
368 p = Cx86_cb;
369 (c->x86_model)++;
370 } else /* 686 */
371 p = Cx86_cb+1;
372 break;
374 case 4: /* MediaGX/GXm */
376 * Life sometimes gets weiiiiiiiird if we use this
377 * on the MediaGX. So we turn it off for now.
380 /* GXm supports extended cpuid levels 'ala' AMD */
381 if (c->cpuid_level == 2) {
382 amd_model(c); /* get CPU marketing name */
383 c->x86_capability&=~X86_FEATURE_TSC;
384 return;
386 else { /* MediaGX */
387 Cx86_cb[2] = (dir0_lsn & 1) ? '3' : '4';
388 p = Cx86_cb+2;
389 c->x86_model = (dir1 & 0x20) ? 1 : 2;
390 c->x86_capability&=~X86_FEATURE_TSC;
392 break;
394 case 5: /* 6x86MX/M II */
395 if (dir1 > 7) dir0_msn++; /* M II */
396 tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0;
397 Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7];
398 p = Cx86_cb+tmp;
399 if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20))
400 (c->x86_model)++;
401 break;
403 case 0xf: /* Cyrix 486 without DEVID registers */
404 switch (dir0_lsn) {
405 case 0xd: /* either a 486SLC or DLC w/o DEVID */
406 dir0_msn = 0;
407 p = Cx486_name[(c->hard_math) ? 1 : 0];
408 break;
410 case 0xe: /* a 486S A step */
411 dir0_msn = 0;
412 p = Cx486S_name[0];
413 break;
414 break;
417 default: /* unknown (shouldn't happen, we know everyone ;-) */
418 dir0_msn = 7;
419 break;
421 strcpy(buf, Cx86_model[dir0_msn & 7]);
422 if (p) strcat(buf, p);
423 return;
426 __initfunc(void get_cpu_vendor(struct cpuinfo_x86 *c))
428 char *v = c->x86_vendor_id;
430 if (!strcmp(v, "GenuineIntel"))
431 c->x86_vendor = X86_VENDOR_INTEL;
432 else if (!strcmp(v, "AuthenticAMD"))
433 c->x86_vendor = X86_VENDOR_AMD;
434 else if (!strcmp(v, "CyrixInstead"))
435 c->x86_vendor = X86_VENDOR_CYRIX;
436 else if (!strcmp(v, "UMC UMC UMC "))
437 c->x86_vendor = X86_VENDOR_UMC;
438 else if (!strcmp(v, "CentaurHauls"))
439 c->x86_vendor = X86_VENDOR_CENTAUR;
440 else if (!strcmp(v, "NexGenDriven"))
441 c->x86_vendor = X86_VENDOR_NEXGEN;
442 else
443 c->x86_vendor = X86_VENDOR_UNKNOWN;
446 struct cpu_model_info {
447 int vendor;
448 int x86;
449 char *model_names[16];
452 static struct cpu_model_info cpu_models[] __initdata = {
453 { X86_VENDOR_INTEL, 4,
454 { "486 DX-25/33", "486 DX-50", "486 SX", "486 DX/2", "486 SL",
455 "486 SX/2", NULL, "486 DX/2-WB", "486 DX/4", "486 DX/4-WB", NULL,
456 NULL, NULL, NULL, NULL, NULL }},
457 { X86_VENDOR_INTEL, 5,
458 { "Pentium 60/66 A-step", "Pentium 60/66", "Pentium 75 - 200",
459 "OverDrive PODP5V83", "Pentium MMX", NULL, NULL,
460 "Mobile Pentium 75 - 200", "Mobile Pentium MMX", NULL, NULL, NULL,
461 NULL, NULL, NULL, NULL }},
462 { X86_VENDOR_INTEL, 6,
463 { "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)",
464 NULL, "Pentium II (Deschutes)", "Celeron (Mendocino)", NULL,
465 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }},
466 { X86_VENDOR_AMD, 4,
467 { NULL, NULL, NULL, "486 DX/2", NULL, NULL, NULL, "486 DX/2-WB",
468 "486 DX/4", "486 DX/4-WB", NULL, NULL, NULL, NULL, "Am5x86-WT",
469 "Am5x86-WB" }},
470 { X86_VENDOR_AMD, 5,
471 { "K5/SSA5", "K5",
472 "K5", "K5", NULL, NULL,
473 "K6", "K6", "K6-2",
474 "K6-3", NULL, NULL, NULL, NULL, NULL, NULL }},
475 { X86_VENDOR_UMC, 4,
476 { NULL, "U5D", "U5S", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
477 NULL, NULL, NULL, NULL, NULL, NULL }},
478 { X86_VENDOR_CENTAUR, 5,
479 { NULL, NULL, NULL, NULL, "C6", NULL, NULL, NULL, "C6-2", NULL, NULL,
480 NULL, NULL, NULL, NULL, NULL }},
481 { X86_VENDOR_NEXGEN, 5,
482 { "Nx586", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
483 NULL, NULL, NULL, NULL, NULL, NULL, NULL }},
486 __initfunc(void identify_cpu(struct cpuinfo_x86 *c))
488 int i;
489 char *p = NULL;
491 c->loops_per_sec = loops_per_sec;
492 c->x86_cache_size = -1;
494 get_cpu_vendor(c);
496 if (c->x86_vendor == X86_VENDOR_UNKNOWN &&
497 c->cpuid_level < 0)
498 return;
500 if (c->x86_vendor == X86_VENDOR_CYRIX) {
501 cyrix_model(c);
502 return;
505 if (c->x86_vendor == X86_VENDOR_AMD && amd_model(c))
506 return;
508 for (i = 0; i < sizeof(cpu_models)/sizeof(struct cpu_model_info); i++) {
509 if (c->cpuid_level > 1) {
510 /* supports eax=2 call */
511 int edx, cache_size, dummy;
513 cpuid(2, &dummy, &dummy, &dummy, &edx);
515 /* We need only the LSB */
516 edx &= 0xff;
518 switch (edx) {
519 case 0x40:
520 cache_size = 0;
521 break;
523 case 0x41:
524 cache_size = 128;
525 break;
527 case 0x42:
528 cache_size = 256;
529 break;
531 case 0x43:
532 cache_size = 512;
533 break;
535 case 0x44:
536 cache_size = 1024;
537 break;
539 case 0x45:
540 cache_size = 2048;
541 break;
543 default:
544 cache_size = 0;
545 break;
548 c->x86_cache_size = cache_size;
551 if (cpu_models[i].vendor == c->x86_vendor &&
552 cpu_models[i].x86 == c->x86) {
553 if (c->x86_model <= 16)
554 p = cpu_models[i].model_names[c->x86_model];
556 /* Names for the Pentium II processors */
557 if ((cpu_models[i].vendor == X86_VENDOR_INTEL)
558 && (cpu_models[i].x86 == 6)
559 && (c->x86_model == 5)
560 && (c->x86_cache_size == 0)) {
561 p = "Celeron (Covington)";
567 if (p) {
568 strcpy(c->x86_model_id, p);
569 return;
572 sprintf(c->x86_model_id, "%02x/%02x", c->x86_vendor, c->x86_model);
576 * Perform early boot up checks for a valid TSC. See arch/i386/kernel/time.c
579 __initfunc(void dodgy_tsc(void))
581 get_cpu_vendor(&boot_cpu_data);
583 if(boot_cpu_data.x86_vendor != X86_VENDOR_CYRIX)
585 return;
587 cyrix_model(&boot_cpu_data);
591 #define rdmsr(msr,val1,val2) \
592 __asm__ __volatile__("rdmsr" \
593 : "=a" (val1), "=d" (val2) \
594 : "c" (msr))
596 #define wrmsr(msr,val1,val2) \
597 __asm__ __volatile__("wrmsr" \
598 : /* no outputs */ \
599 : "c" (msr), "a" (val1), "d" (val2))
601 static char *cpu_vendor_names[] __initdata = {
602 "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur" };
605 __initfunc(void print_cpu_info(struct cpuinfo_x86 *c))
607 char *vendor = NULL;
609 if (c->x86_vendor < sizeof(cpu_vendor_names)/sizeof(char *))
610 vendor = cpu_vendor_names[c->x86_vendor];
611 else if (c->cpuid_level >= 0)
612 vendor = c->x86_vendor_id;
614 if (vendor)
615 printk("%s ", vendor);
617 if (!c->x86_model_id[0])
618 printk("%d86", c->x86);
619 else
620 printk("%s", c->x86_model_id);
622 if (c->x86_mask || c->cpuid_level>=0)
623 printk(" stepping %02x", c->x86_mask);
625 if(c->x86_vendor == X86_VENDOR_CENTAUR)
627 u32 hv,lv;
628 rdmsr(0x107, lv, hv);
629 printk("\nCentaur FSR was 0x%X ",lv);
630 lv|=(1<<8);
631 lv|=(1<<7);
632 /* lv|=(1<<6); - may help too if the board can cope */
633 printk("now 0x%X", lv);
634 wrmsr(0x107, lv, hv);
636 printk("\n");
640 * Get CPU information for use by the procfs.
643 int get_cpuinfo(char * buffer)
645 char *p = buffer;
646 int sep_bug;
647 static char *x86_cap_flags[] = {
648 "fpu", "vme", "de", "pse", "tsc", "msr", "6", "mce",
649 "cx8", "9", "10", "sep", "12", "pge", "14", "cmov",
650 "16", "17", "18", "19", "20", "21", "22", "mmx",
651 "24", "25", "26", "27", "28", "29", "30", "31"
653 struct cpuinfo_x86 *c = cpu_data;
654 int i, n;
656 for(n=0; n<NR_CPUS; n++, c++) {
657 #ifdef __SMP__
658 if (!(cpu_online_map & (1<<n)))
659 continue;
660 #endif
661 p += sprintf(p,"processor\t: %d\n"
662 "vendor_id\t: %s\n"
663 "cpu family\t: %c\n"
664 "model\t\t: %d\n"
665 "model name\t: %s\n",
667 c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown",
668 c->x86 + '0',
669 c->x86_model,
670 c->x86_model_id[0] ? c->x86_model_id : "unknown");
672 if (c->x86_mask)
673 p += sprintf(p, "stepping\t: %d\n", c->x86_mask);
674 else
675 p += sprintf(p, "stepping\t: unknown\n");
677 if (c->x86_capability & X86_FEATURE_TSC) {
678 p += sprintf(p, "cpu MHz\t\t: %lu.%06lu\n",
679 cpu_hz / 1000000, (cpu_hz % 1000000));
682 /* Cache size */
683 if (c->x86_cache_size >= 0)
684 p += sprintf(p, "cache size\t: %d KB\n", c->x86_cache_size);
686 /* Modify the capabilities according to chip type */
687 if (c->x86_vendor == X86_VENDOR_CYRIX) {
688 x86_cap_flags[24] = "cxmmx";
689 } else if (c->x86_vendor == X86_VENDOR_AMD) {
690 x86_cap_flags[16] = "fcmov";
691 x86_cap_flags[31] = "3dnow";
692 if (c->x86 == 5 && c->x86_model == 6)
693 x86_cap_flags[10] = "sep";
694 } else if (c->x86_vendor == X86_VENDOR_INTEL) {
695 x86_cap_flags[6] = "pae";
696 x86_cap_flags[9] = "apic";
697 x86_cap_flags[12] = "mtrr";
698 x86_cap_flags[14] = "mca";
699 x86_cap_flags[16] = "pat";
700 x86_cap_flags[17] = "pse36";
701 x86_cap_flags[24] = "osfxsr";
704 sep_bug = c->x86_vendor == X86_VENDOR_INTEL &&
705 c->x86 == 0x06 &&
706 c->cpuid_level >= 0 &&
707 (c->x86_capability & X86_FEATURE_SEP) &&
708 c->x86_model < 3 &&
709 c->x86_mask < 3;
711 p += sprintf(p, "fdiv_bug\t: %s\n"
712 "hlt_bug\t\t: %s\n"
713 "sep_bug\t\t: %s\n"
714 "f00f_bug\t: %s\n"
715 "fpu\t\t: %s\n"
716 "fpu_exception\t: %s\n"
717 "cpuid level\t: %d\n"
718 "wp\t\t: %s\n"
719 "flags\t\t:",
720 c->fdiv_bug ? "yes" : "no",
721 c->hlt_works_ok ? "no" : "yes",
722 sep_bug ? "yes" : "no",
723 c->f00f_bug ? "yes" : "no",
724 c->hard_math ? "yes" : "no",
725 (c->hard_math && ignore_irq13) ? "yes" : "no",
726 c->cpuid_level,
727 c->wp_works_ok ? "yes" : "no");
729 for ( i = 0 ; i < 32 ; i++ )
730 if ( c->x86_capability & (1 << i) )
731 p += sprintf(p, " %s", x86_cap_flags[i]);
732 p += sprintf(p, "\nbogomips\t: %lu.%02lu\n\n",
733 (c->loops_per_sec+2500)/500000,
734 ((c->loops_per_sec+2500)/5000) % 100);
736 return p - buffer;