blob: 64c4534b930c74bc118cf1530a812401456f3d4e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/arch/x86-64/kernel/setup.c
3 *
4 * Copyright (C) 1995 Linus Torvalds
5 *
6 * Nov 2001 Dave Jones <davej@suse.de>
7 * Forked from i386 setup code.
8 *
9 * $Id$
10 */
11
12/*
13 * This file handles the architecture-dependent parts of initialization
14 */
15
16#include <linux/errno.h>
17#include <linux/sched.h>
18#include <linux/kernel.h>
19#include <linux/mm.h>
20#include <linux/stddef.h>
21#include <linux/unistd.h>
22#include <linux/ptrace.h>
23#include <linux/slab.h>
24#include <linux/user.h>
25#include <linux/a.out.h>
26#include <linux/tty.h>
27#include <linux/ioport.h>
28#include <linux/delay.h>
29#include <linux/config.h>
30#include <linux/init.h>
31#include <linux/initrd.h>
32#include <linux/highmem.h>
33#include <linux/bootmem.h>
34#include <linux/module.h>
35#include <asm/processor.h>
36#include <linux/console.h>
37#include <linux/seq_file.h>
38#include <linux/root_dev.h>
39#include <linux/pci.h>
40#include <linux/acpi.h>
41#include <linux/kallsyms.h>
42#include <linux/edd.h>
Matt Tolentinobbfceef2005-06-23 00:08:07 -070043#include <linux/mmzone.h>
Eric W. Biederman5f5609d2005-06-25 14:58:04 -070044#include <linux/kexec.h>
Venkatesh Pallipadi95235ca2005-12-02 10:43:20 -080045#include <linux/cpufreq.h>
Matt Tolentinobbfceef2005-06-23 00:08:07 -070046
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <asm/mtrr.h>
48#include <asm/uaccess.h>
49#include <asm/system.h>
50#include <asm/io.h>
51#include <asm/smp.h>
52#include <asm/msr.h>
53#include <asm/desc.h>
54#include <video/edid.h>
55#include <asm/e820.h>
56#include <asm/dma.h>
57#include <asm/mpspec.h>
58#include <asm/mmu_context.h>
59#include <asm/bootsetup.h>
60#include <asm/proto.h>
61#include <asm/setup.h>
62#include <asm/mach_apic.h>
63#include <asm/numa.h>
Andi Kleen2bc04142005-11-05 17:25:53 +010064#include <asm/sections.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66/*
67 * Machine setup..
68 */
69
Ravikiran G Thirumalai6c231b72005-09-06 15:17:45 -070070struct cpuinfo_x86 boot_cpu_data __read_mostly;
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
72unsigned long mmu_cr4_features;
73
74int acpi_disabled;
75EXPORT_SYMBOL(acpi_disabled);
Len Brown888ba6c2005-08-24 12:07:20 -040076#ifdef CONFIG_ACPI
Linus Torvalds1da177e2005-04-16 15:20:36 -070077extern int __initdata acpi_ht;
78extern acpi_interrupt_flags acpi_sci_flags;
79int __initdata acpi_force = 0;
80#endif
81
82int acpi_numa __initdata;
83
Linus Torvalds1da177e2005-04-16 15:20:36 -070084/* Boot loader ID as an integer, for the benefit of proc_dointvec */
85int bootloader_type;
86
87unsigned long saved_video_mode;
88
89#ifdef CONFIG_SWIOTLB
90int swiotlb;
91EXPORT_SYMBOL(swiotlb);
92#endif
93
94/*
95 * Setup options
96 */
97struct drive_info_struct { char dummy[32]; } drive_info;
98struct screen_info screen_info;
99struct sys_desc_table_struct {
100 unsigned short length;
101 unsigned char table[0];
102};
103
104struct edid_info edid_info;
105struct e820map e820;
106
107extern int root_mountflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108
109char command_line[COMMAND_LINE_SIZE];
110
111struct resource standard_io_resources[] = {
112 { .name = "dma1", .start = 0x00, .end = 0x1f,
113 .flags = IORESOURCE_BUSY | IORESOURCE_IO },
114 { .name = "pic1", .start = 0x20, .end = 0x21,
115 .flags = IORESOURCE_BUSY | IORESOURCE_IO },
116 { .name = "timer0", .start = 0x40, .end = 0x43,
117 .flags = IORESOURCE_BUSY | IORESOURCE_IO },
118 { .name = "timer1", .start = 0x50, .end = 0x53,
119 .flags = IORESOURCE_BUSY | IORESOURCE_IO },
120 { .name = "keyboard", .start = 0x60, .end = 0x6f,
121 .flags = IORESOURCE_BUSY | IORESOURCE_IO },
122 { .name = "dma page reg", .start = 0x80, .end = 0x8f,
123 .flags = IORESOURCE_BUSY | IORESOURCE_IO },
124 { .name = "pic2", .start = 0xa0, .end = 0xa1,
125 .flags = IORESOURCE_BUSY | IORESOURCE_IO },
126 { .name = "dma2", .start = 0xc0, .end = 0xdf,
127 .flags = IORESOURCE_BUSY | IORESOURCE_IO },
128 { .name = "fpu", .start = 0xf0, .end = 0xff,
129 .flags = IORESOURCE_BUSY | IORESOURCE_IO }
130};
131
132#define STANDARD_IO_RESOURCES \
133 (sizeof standard_io_resources / sizeof standard_io_resources[0])
134
135#define IORESOURCE_RAM (IORESOURCE_BUSY | IORESOURCE_MEM)
136
137struct resource data_resource = {
138 .name = "Kernel data",
139 .start = 0,
140 .end = 0,
141 .flags = IORESOURCE_RAM,
142};
143struct resource code_resource = {
144 .name = "Kernel code",
145 .start = 0,
146 .end = 0,
147 .flags = IORESOURCE_RAM,
148};
149
150#define IORESOURCE_ROM (IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM)
151
152static struct resource system_rom_resource = {
153 .name = "System ROM",
154 .start = 0xf0000,
155 .end = 0xfffff,
156 .flags = IORESOURCE_ROM,
157};
158
159static struct resource extension_rom_resource = {
160 .name = "Extension ROM",
161 .start = 0xe0000,
162 .end = 0xeffff,
163 .flags = IORESOURCE_ROM,
164};
165
166static struct resource adapter_rom_resources[] = {
167 { .name = "Adapter ROM", .start = 0xc8000, .end = 0,
168 .flags = IORESOURCE_ROM },
169 { .name = "Adapter ROM", .start = 0, .end = 0,
170 .flags = IORESOURCE_ROM },
171 { .name = "Adapter ROM", .start = 0, .end = 0,
172 .flags = IORESOURCE_ROM },
173 { .name = "Adapter ROM", .start = 0, .end = 0,
174 .flags = IORESOURCE_ROM },
175 { .name = "Adapter ROM", .start = 0, .end = 0,
176 .flags = IORESOURCE_ROM },
177 { .name = "Adapter ROM", .start = 0, .end = 0,
178 .flags = IORESOURCE_ROM }
179};
180
181#define ADAPTER_ROM_RESOURCES \
182 (sizeof adapter_rom_resources / sizeof adapter_rom_resources[0])
183
184static struct resource video_rom_resource = {
185 .name = "Video ROM",
186 .start = 0xc0000,
187 .end = 0xc7fff,
188 .flags = IORESOURCE_ROM,
189};
190
191static struct resource video_ram_resource = {
192 .name = "Video RAM area",
193 .start = 0xa0000,
194 .end = 0xbffff,
195 .flags = IORESOURCE_RAM,
196};
197
198#define romsignature(x) (*(unsigned short *)(x) == 0xaa55)
199
200static int __init romchecksum(unsigned char *rom, unsigned long length)
201{
202 unsigned char *p, sum = 0;
203
204 for (p = rom; p < rom + length; p++)
205 sum += *p;
206 return sum == 0;
207}
208
209static void __init probe_roms(void)
210{
211 unsigned long start, length, upper;
212 unsigned char *rom;
213 int i;
214
215 /* video rom */
216 upper = adapter_rom_resources[0].start;
217 for (start = video_rom_resource.start; start < upper; start += 2048) {
218 rom = isa_bus_to_virt(start);
219 if (!romsignature(rom))
220 continue;
221
222 video_rom_resource.start = start;
223
224 /* 0 < length <= 0x7f * 512, historically */
225 length = rom[2] * 512;
226
227 /* if checksum okay, trust length byte */
228 if (length && romchecksum(rom, length))
229 video_rom_resource.end = start + length - 1;
230
231 request_resource(&iomem_resource, &video_rom_resource);
232 break;
233 }
234
235 start = (video_rom_resource.end + 1 + 2047) & ~2047UL;
236 if (start < upper)
237 start = upper;
238
239 /* system rom */
240 request_resource(&iomem_resource, &system_rom_resource);
241 upper = system_rom_resource.start;
242
243 /* check for extension rom (ignore length byte!) */
244 rom = isa_bus_to_virt(extension_rom_resource.start);
245 if (romsignature(rom)) {
246 length = extension_rom_resource.end - extension_rom_resource.start + 1;
247 if (romchecksum(rom, length)) {
248 request_resource(&iomem_resource, &extension_rom_resource);
249 upper = extension_rom_resource.start;
250 }
251 }
252
253 /* check for adapter roms on 2k boundaries */
254 for (i = 0; i < ADAPTER_ROM_RESOURCES && start < upper; start += 2048) {
255 rom = isa_bus_to_virt(start);
256 if (!romsignature(rom))
257 continue;
258
259 /* 0 < length <= 0x7f * 512, historically */
260 length = rom[2] * 512;
261
262 /* but accept any length that fits if checksum okay */
263 if (!length || start + length > upper || !romchecksum(rom, length))
264 continue;
265
266 adapter_rom_resources[i].start = start;
267 adapter_rom_resources[i].end = start + length - 1;
268 request_resource(&iomem_resource, &adapter_rom_resources[i]);
269
270 start = adapter_rom_resources[i++].end & ~2047UL;
271 }
272}
273
274static __init void parse_cmdline_early (char ** cmdline_p)
275{
276 char c = ' ', *to = command_line, *from = COMMAND_LINE;
277 int len = 0;
278
279 /* Save unparsed command line copy for /proc/cmdline */
280 memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
281 saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
282
283 for (;;) {
284 if (c != ' ')
285 goto next_char;
286
287#ifdef CONFIG_SMP
288 /*
289 * If the BIOS enumerates physical processors before logical,
290 * maxcpus=N at enumeration-time can be used to disable HT.
291 */
292 else if (!memcmp(from, "maxcpus=", 8)) {
293 extern unsigned int maxcpus;
294
295 maxcpus = simple_strtoul(from + 8, NULL, 0);
296 }
297#endif
Len Brown888ba6c2005-08-24 12:07:20 -0400298#ifdef CONFIG_ACPI
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 /* "acpi=off" disables both ACPI table parsing and interpreter init */
300 if (!memcmp(from, "acpi=off", 8))
301 disable_acpi();
302
303 if (!memcmp(from, "acpi=force", 10)) {
304 /* add later when we do DMI horrors: */
305 acpi_force = 1;
306 acpi_disabled = 0;
307 }
308
309 /* acpi=ht just means: do ACPI MADT parsing
310 at bootup, but don't enable the full ACPI interpreter */
311 if (!memcmp(from, "acpi=ht", 7)) {
312 if (!acpi_force)
313 disable_acpi();
314 acpi_ht = 1;
315 }
316 else if (!memcmp(from, "pci=noacpi", 10))
317 acpi_disable_pci();
318 else if (!memcmp(from, "acpi=noirq", 10))
319 acpi_noirq_set();
320
321 else if (!memcmp(from, "acpi_sci=edge", 13))
322 acpi_sci_flags.trigger = 1;
323 else if (!memcmp(from, "acpi_sci=level", 14))
324 acpi_sci_flags.trigger = 3;
325 else if (!memcmp(from, "acpi_sci=high", 13))
326 acpi_sci_flags.polarity = 1;
327 else if (!memcmp(from, "acpi_sci=low", 12))
328 acpi_sci_flags.polarity = 3;
329
330 /* acpi=strict disables out-of-spec workarounds */
331 else if (!memcmp(from, "acpi=strict", 11)) {
332 acpi_strict = 1;
333 }
Andi Kleen22999242005-04-16 15:25:17 -0700334#ifdef CONFIG_X86_IO_APIC
335 else if (!memcmp(from, "acpi_skip_timer_override", 24))
336 acpi_skip_timer_override = 1;
337#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338#endif
339
Chuck Ebbert66759a02005-09-12 18:49:25 +0200340 if (!memcmp(from, "disable_timer_pin_1", 19))
341 disable_timer_pin_1 = 1;
342 if (!memcmp(from, "enable_timer_pin_1", 18))
343 disable_timer_pin_1 = -1;
344
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 if (!memcmp(from, "nolapic", 7) ||
346 !memcmp(from, "disableapic", 11))
347 disable_apic = 1;
348
349 if (!memcmp(from, "noapic", 6))
350 skip_ioapic_setup = 1;
351
352 if (!memcmp(from, "apic", 4)) {
353 skip_ioapic_setup = 0;
354 ioapic_force = 1;
355 }
356
357 if (!memcmp(from, "mem=", 4))
358 parse_memopt(from+4, &from);
359
Matt Tolentino2b976902005-06-23 00:08:06 -0700360#ifdef CONFIG_NUMA
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 if (!memcmp(from, "numa=", 5))
362 numa_setup(from+5);
363#endif
364
365#ifdef CONFIG_GART_IOMMU
366 if (!memcmp(from,"iommu=",6)) {
367 iommu_setup(from+6);
368 }
369#endif
370
371 if (!memcmp(from,"oops=panic", 10))
372 panic_on_oops = 1;
373
374 if (!memcmp(from, "noexec=", 7))
375 nonx_setup(from + 7);
376
Eric W. Biederman5f5609d2005-06-25 14:58:04 -0700377#ifdef CONFIG_KEXEC
378 /* crashkernel=size@addr specifies the location to reserve for
379 * a crash kernel. By reserving this memory we guarantee
380 * that linux never set's it up as a DMA target.
381 * Useful for holding code to do something appropriate
382 * after a kernel panic.
383 */
384 else if (!memcmp(from, "crashkernel=", 12)) {
385 unsigned long size, base;
386 size = memparse(from+12, &from);
387 if (*from == '@') {
388 base = memparse(from+1, &from);
389 /* FIXME: Do I want a sanity check
390 * to validate the memory range?
391 */
392 crashk_res.start = base;
393 crashk_res.end = base + size - 1;
394 }
395 }
396#endif
397
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 next_char:
399 c = *(from++);
400 if (!c)
401 break;
402 if (COMMAND_LINE_SIZE <= ++len)
403 break;
404 *(to++) = c;
405 }
406 *to = '\0';
407 *cmdline_p = command_line;
408}
409
Matt Tolentino2b976902005-06-23 00:08:06 -0700410#ifndef CONFIG_NUMA
Matt Tolentinobbfceef2005-06-23 00:08:07 -0700411static void __init
412contig_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413{
Matt Tolentinobbfceef2005-06-23 00:08:07 -0700414 unsigned long bootmap_size, bootmap;
415
Matt Tolentinobbfceef2005-06-23 00:08:07 -0700416 bootmap_size = bootmem_bootmap_pages(end_pfn)<<PAGE_SHIFT;
417 bootmap = find_e820_area(0, end_pfn<<PAGE_SHIFT, bootmap_size);
418 if (bootmap == -1L)
419 panic("Cannot find bootmem map of size %ld\n",bootmap_size);
420 bootmap_size = init_bootmem(bootmap >> PAGE_SHIFT, end_pfn);
421 e820_bootmem_free(NODE_DATA(0), 0, end_pfn << PAGE_SHIFT);
422 reserve_bootmem(bootmap, bootmap_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423}
424#endif
425
426/* Use inline assembly to define this because the nops are defined
427 as inline assembly strings in the include files and we cannot
428 get them easily into strings. */
429asm("\t.data\nk8nops: "
430 K8_NOP1 K8_NOP2 K8_NOP3 K8_NOP4 K8_NOP5 K8_NOP6
431 K8_NOP7 K8_NOP8);
432
433extern unsigned char k8nops[];
434static unsigned char *k8_nops[ASM_NOP_MAX+1] = {
435 NULL,
436 k8nops,
437 k8nops + 1,
438 k8nops + 1 + 2,
439 k8nops + 1 + 2 + 3,
440 k8nops + 1 + 2 + 3 + 4,
441 k8nops + 1 + 2 + 3 + 4 + 5,
442 k8nops + 1 + 2 + 3 + 4 + 5 + 6,
443 k8nops + 1 + 2 + 3 + 4 + 5 + 6 + 7,
444};
445
446/* Replace instructions with better alternatives for this CPU type.
447
448 This runs before SMP is initialized to avoid SMP problems with
449 self modifying code. This implies that assymetric systems where
450 APs have less capabilities than the boot processor are not handled.
451 In this case boot with "noreplacement". */
452void apply_alternatives(void *start, void *end)
453{
454 struct alt_instr *a;
455 int diff, i, k;
456 for (a = start; (void *)a < end; a++) {
457 if (!boot_cpu_has(a->cpuid))
458 continue;
459
460 BUG_ON(a->replacementlen > a->instrlen);
461 __inline_memcpy(a->instr, a->replacement, a->replacementlen);
462 diff = a->instrlen - a->replacementlen;
463
464 /* Pad the rest with nops */
465 for (i = a->replacementlen; diff > 0; diff -= k, i += k) {
466 k = diff;
467 if (k > ASM_NOP_MAX)
468 k = ASM_NOP_MAX;
469 __inline_memcpy(a->instr + i, k8_nops[k], k);
470 }
471 }
472}
473
474static int no_replacement __initdata = 0;
475
476void __init alternative_instructions(void)
477{
478 extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
479 if (no_replacement)
480 return;
481 apply_alternatives(__alt_instructions, __alt_instructions_end);
482}
483
484static int __init noreplacement_setup(char *s)
485{
486 no_replacement = 1;
487 return 0;
488}
489
490__setup("noreplacement", noreplacement_setup);
491
492#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
493struct edd edd;
494#ifdef CONFIG_EDD_MODULE
495EXPORT_SYMBOL(edd);
496#endif
497/**
498 * copy_edd() - Copy the BIOS EDD information
499 * from boot_params into a safe place.
500 *
501 */
502static inline void copy_edd(void)
503{
504 memcpy(edd.mbr_signature, EDD_MBR_SIGNATURE, sizeof(edd.mbr_signature));
505 memcpy(edd.edd_info, EDD_BUF, sizeof(edd.edd_info));
506 edd.mbr_signature_nr = EDD_MBR_SIG_NR;
507 edd.edd_info_nr = EDD_NR;
508}
509#else
510static inline void copy_edd(void)
511{
512}
513#endif
514
515#define EBDA_ADDR_POINTER 0x40E
516static void __init reserve_ebda_region(void)
517{
518 unsigned int addr;
519 /**
520 * there is a real-mode segmented pointer pointing to the
521 * 4K EBDA area at 0x40E
522 */
523 addr = *(unsigned short *)phys_to_virt(EBDA_ADDR_POINTER);
524 addr <<= 4;
525 if (addr)
526 reserve_bootmem_generic(addr, PAGE_SIZE);
527}
528
529void __init setup_arch(char **cmdline_p)
530{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 unsigned long kernel_end;
532
533 ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
534 drive_info = DRIVE_INFO;
535 screen_info = SCREEN_INFO;
536 edid_info = EDID_INFO;
537 saved_video_mode = SAVED_VIDEO_MODE;
538 bootloader_type = LOADER_TYPE;
539
540#ifdef CONFIG_BLK_DEV_RAM
541 rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
542 rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
543 rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
544#endif
545 setup_memory_region();
546 copy_edd();
547
548 if (!MOUNT_ROOT_RDONLY)
549 root_mountflags &= ~MS_RDONLY;
550 init_mm.start_code = (unsigned long) &_text;
551 init_mm.end_code = (unsigned long) &_etext;
552 init_mm.end_data = (unsigned long) &_edata;
553 init_mm.brk = (unsigned long) &_end;
554
555 code_resource.start = virt_to_phys(&_text);
556 code_resource.end = virt_to_phys(&_etext)-1;
557 data_resource.start = virt_to_phys(&_etext);
558 data_resource.end = virt_to_phys(&_edata)-1;
559
560 parse_cmdline_early(cmdline_p);
561
562 early_identify_cpu(&boot_cpu_data);
563
564 /*
565 * partially used pages are not usable - thus
566 * we are rounding upwards:
567 */
568 end_pfn = e820_end_of_ram();
569
570 check_efer();
571
572 init_memory_mapping(0, (end_pfn_map << PAGE_SHIFT));
573
Siddha, Suresh Bf6c2e332005-11-05 17:25:53 +0100574 zap_low_mappings(0);
575
Len Brown888ba6c2005-08-24 12:07:20 -0400576#ifdef CONFIG_ACPI
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 /*
578 * Initialize the ACPI boot-time table parser (gets the RSDP and SDT).
579 * Call this early for SRAT node setup.
580 */
581 acpi_boot_table_init();
582#endif
583
584#ifdef CONFIG_ACPI_NUMA
585 /*
586 * Parse SRAT to discover nodes.
587 */
588 acpi_numa_init();
589#endif
590
Matt Tolentino2b976902005-06-23 00:08:06 -0700591#ifdef CONFIG_NUMA
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 numa_initmem_init(0, end_pfn);
593#else
Matt Tolentinobbfceef2005-06-23 00:08:07 -0700594 contig_initmem_init(0, end_pfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595#endif
596
597 /* Reserve direct mapping */
598 reserve_bootmem_generic(table_start << PAGE_SHIFT,
599 (table_end - table_start) << PAGE_SHIFT);
600
601 /* reserve kernel */
602 kernel_end = round_up(__pa_symbol(&_end),PAGE_SIZE);
603 reserve_bootmem_generic(HIGH_MEMORY, kernel_end - HIGH_MEMORY);
604
605 /*
606 * reserve physical page 0 - it's a special BIOS page on many boxes,
607 * enabling clean reboots, SMP operation, laptop functions.
608 */
609 reserve_bootmem_generic(0, PAGE_SIZE);
610
611 /* reserve ebda region */
612 reserve_ebda_region();
613
614#ifdef CONFIG_SMP
615 /*
616 * But first pinch a few for the stack/trampoline stuff
617 * FIXME: Don't need the extra page at 4K, but need to fix
618 * trampoline before removing it. (see the GDT stuff)
619 */
620 reserve_bootmem_generic(PAGE_SIZE, PAGE_SIZE);
621
622 /* Reserve SMP trampoline */
623 reserve_bootmem_generic(SMP_TRAMPOLINE_BASE, PAGE_SIZE);
624#endif
625
626#ifdef CONFIG_ACPI_SLEEP
627 /*
628 * Reserve low memory region for sleep support.
629 */
630 acpi_reserve_bootmem();
631#endif
632#ifdef CONFIG_X86_LOCAL_APIC
633 /*
634 * Find and reserve possible boot-time SMP configuration:
635 */
636 find_smp_config();
637#endif
638#ifdef CONFIG_BLK_DEV_INITRD
639 if (LOADER_TYPE && INITRD_START) {
640 if (INITRD_START + INITRD_SIZE <= (end_pfn << PAGE_SHIFT)) {
641 reserve_bootmem_generic(INITRD_START, INITRD_SIZE);
642 initrd_start =
643 INITRD_START ? INITRD_START + PAGE_OFFSET : 0;
644 initrd_end = initrd_start+INITRD_SIZE;
645 }
646 else {
647 printk(KERN_ERR "initrd extends beyond end of memory "
648 "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
649 (unsigned long)(INITRD_START + INITRD_SIZE),
650 (unsigned long)(end_pfn << PAGE_SHIFT));
651 initrd_start = 0;
652 }
653 }
654#endif
Eric W. Biederman5f5609d2005-06-25 14:58:04 -0700655#ifdef CONFIG_KEXEC
656 if (crashk_res.start != crashk_res.end) {
657 reserve_bootmem(crashk_res.start,
658 crashk_res.end - crashk_res.start + 1);
659 }
660#endif
Eric W. Biederman0d317fb2005-08-06 13:47:36 -0600661
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 paging_init();
663
664 check_ioapic();
665
Len Brown888ba6c2005-08-24 12:07:20 -0400666#ifdef CONFIG_ACPI
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 /*
668 * Read APIC and some other early information from ACPI tables.
669 */
670 acpi_boot_init();
671#endif
672
673#ifdef CONFIG_X86_LOCAL_APIC
674 /*
675 * get boot-time SMP configuration:
676 */
677 if (smp_found_config)
678 get_smp_config();
679 init_apic_mappings();
680#endif
681
682 /*
683 * Request address space for all standard RAM and ROM resources
684 * and also for regions reported as reserved by the e820.
685 */
686 probe_roms();
687 e820_reserve_resources();
688
689 request_resource(&iomem_resource, &video_ram_resource);
690
691 {
692 unsigned i;
693 /* request I/O space for devices used on all i[345]86 PCs */
694 for (i = 0; i < STANDARD_IO_RESOURCES; i++)
695 request_resource(&ioport_resource, &standard_io_resources[i]);
696 }
697
Andi Kleena1e97782005-04-16 15:25:12 -0700698 e820_setup_gap();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699
700#ifdef CONFIG_GART_IOMMU
701 iommu_hole_init();
702#endif
703
704#ifdef CONFIG_VT
705#if defined(CONFIG_VGA_CONSOLE)
706 conswitchp = &vga_con;
707#elif defined(CONFIG_DUMMY_CONSOLE)
708 conswitchp = &dummy_con;
709#endif
710#endif
711}
712
Ashok Raje6982c62005-06-25 14:54:58 -0700713static int __cpuinit get_model_name(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714{
715 unsigned int *v;
716
Andi Kleenebfcaa92005-04-16 15:25:18 -0700717 if (c->extended_cpuid_level < 0x80000004)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 return 0;
719
720 v = (unsigned int *) c->x86_model_id;
721 cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
722 cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
723 cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
724 c->x86_model_id[48] = 0;
725 return 1;
726}
727
728
Ashok Raje6982c62005-06-25 14:54:58 -0700729static void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730{
731 unsigned int n, dummy, eax, ebx, ecx, edx;
732
Andi Kleenebfcaa92005-04-16 15:25:18 -0700733 n = c->extended_cpuid_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
735 if (n >= 0x80000005) {
736 cpuid(0x80000005, &dummy, &ebx, &ecx, &edx);
737 printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), D cache %dK (%d bytes/line)\n",
738 edx>>24, edx&0xFF, ecx>>24, ecx&0xFF);
739 c->x86_cache_size=(ecx>>24)+(edx>>24);
740 /* On K8 L1 TLB is inclusive, so don't count it */
741 c->x86_tlbsize = 0;
742 }
743
744 if (n >= 0x80000006) {
745 cpuid(0x80000006, &dummy, &ebx, &ecx, &edx);
746 ecx = cpuid_ecx(0x80000006);
747 c->x86_cache_size = ecx >> 16;
748 c->x86_tlbsize += ((ebx >> 16) & 0xfff) + (ebx & 0xfff);
749
750 printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n",
751 c->x86_cache_size, ecx & 0xFF);
752 }
753
754 if (n >= 0x80000007)
755 cpuid(0x80000007, &dummy, &dummy, &dummy, &c->x86_power);
756 if (n >= 0x80000008) {
757 cpuid(0x80000008, &eax, &dummy, &dummy, &dummy);
758 c->x86_virt_bits = (eax >> 8) & 0xff;
759 c->x86_phys_bits = eax & 0xff;
760 }
761}
762
Andi Kleen3f098c22005-09-12 18:49:24 +0200763#ifdef CONFIG_NUMA
764static int nearby_node(int apicid)
765{
766 int i;
767 for (i = apicid - 1; i >= 0; i--) {
768 int node = apicid_to_node[i];
769 if (node != NUMA_NO_NODE && node_online(node))
770 return node;
771 }
772 for (i = apicid + 1; i < MAX_LOCAL_APIC; i++) {
773 int node = apicid_to_node[i];
774 if (node != NUMA_NO_NODE && node_online(node))
775 return node;
776 }
777 return first_node(node_online_map); /* Shouldn't happen */
778}
779#endif
780
Andi Kleen63518642005-04-16 15:25:16 -0700781/*
782 * On a AMD dual core setup the lower bits of the APIC id distingush the cores.
783 * Assumes number of cores is a power of two.
784 */
785static void __init amd_detect_cmp(struct cpuinfo_x86 *c)
786{
787#ifdef CONFIG_SMP
Andi Kleen29422832005-05-16 21:53:26 -0700788 int cpu = smp_processor_id();
Andi Kleenb41e2932005-05-20 14:27:55 -0700789 unsigned bits;
Andi Kleen3f098c22005-09-12 18:49:24 +0200790#ifdef CONFIG_NUMA
791 int node = 0;
Andi Kleen0b07e982005-09-12 18:49:24 +0200792 unsigned apicid = phys_proc_id[cpu];
Andi Kleen3f098c22005-09-12 18:49:24 +0200793#endif
Andi Kleenb41e2932005-05-20 14:27:55 -0700794
795 bits = 0;
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100796 while ((1 << bits) < c->x86_max_cores)
Andi Kleenb41e2932005-05-20 14:27:55 -0700797 bits++;
798
799 /* Low order bits define the core id (index of core in socket) */
800 cpu_core_id[cpu] = phys_proc_id[cpu] & ((1 << bits)-1);
801 /* Convert the APIC ID into the socket ID */
802 phys_proc_id[cpu] >>= bits;
Andi Kleen63518642005-04-16 15:25:16 -0700803
804#ifdef CONFIG_NUMA
Andi Kleen3f098c22005-09-12 18:49:24 +0200805 node = phys_proc_id[cpu];
806 if (apicid_to_node[apicid] != NUMA_NO_NODE)
807 node = apicid_to_node[apicid];
808 if (!node_online(node)) {
809 /* Two possibilities here:
810 - The CPU is missing memory and no node was created.
811 In that case try picking one from a nearby CPU
812 - The APIC IDs differ from the HyperTransport node IDs
813 which the K8 northbridge parsing fills in.
814 Assume they are all increased by a constant offset,
815 but in the same order as the HT nodeids.
816 If that doesn't result in a usable node fall back to the
817 path for the previous case. */
818 int ht_nodeid = apicid - (phys_proc_id[0] << bits);
819 if (ht_nodeid >= 0 &&
820 apicid_to_node[ht_nodeid] != NUMA_NO_NODE)
821 node = apicid_to_node[ht_nodeid];
822 /* Pick a nearby node */
823 if (!node_online(node))
824 node = nearby_node(apicid);
825 }
Andi Kleen69d81fc2005-11-05 17:25:53 +0100826 numa_set_node(cpu, node);
Andi Kleena1586082005-05-16 21:53:21 -0700827
Andi Kleen3f098c22005-09-12 18:49:24 +0200828 printk(KERN_INFO "CPU %d(%d) -> Node %d -> Core %d\n",
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100829 cpu, c->x86_max_cores, node, cpu_core_id[cpu]);
Andi Kleen3f098c22005-09-12 18:49:24 +0200830#endif
Andi Kleen63518642005-04-16 15:25:16 -0700831#endif
832}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833
834static int __init init_amd(struct cpuinfo_x86 *c)
835{
836 int r;
837 int level;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838
Linus Torvaldsbc5e8fd2005-09-17 15:41:04 -0700839#ifdef CONFIG_SMP
840 unsigned long value;
841
Andi Kleen7d318d72005-09-29 22:05:55 +0200842 /*
843 * Disable TLB flush filter by setting HWCR.FFDIS on K8
844 * bit 6 of msr C001_0015
845 *
846 * Errata 63 for SH-B3 steppings
847 * Errata 122 for all steppings (F+ have it disabled by default)
848 */
849 if (c->x86 == 15) {
850 rdmsrl(MSR_K8_HWCR, value);
851 value |= 1 << 6;
852 wrmsrl(MSR_K8_HWCR, value);
853 }
Linus Torvaldsbc5e8fd2005-09-17 15:41:04 -0700854#endif
855
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 /* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
857 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
858 clear_bit(0*32+31, &c->x86_capability);
859
860 /* C-stepping K8? */
861 level = cpuid_eax(1);
862 if ((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58)
863 set_bit(X86_FEATURE_K8_C, &c->x86_capability);
864
865 r = get_model_name(c);
866 if (!r) {
867 switch (c->x86) {
868 case 15:
869 /* Should distinguish Models here, but this is only
870 a fallback anyways. */
871 strcpy(c->x86_model_id, "Hammer");
872 break;
873 }
874 }
875 display_cacheinfo(c);
876
Andi Kleenebfcaa92005-04-16 15:25:18 -0700877 if (c->extended_cpuid_level >= 0x80000008) {
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100878 c->x86_max_cores = (cpuid_ecx(0x80000008) & 0xff) + 1;
879 if (c->x86_max_cores & (c->x86_max_cores - 1))
880 c->x86_max_cores = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881
Andi Kleen63518642005-04-16 15:25:16 -0700882 amd_detect_cmp(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 }
884
885 return r;
886}
887
Ashok Raje6982c62005-06-25 14:54:58 -0700888static void __cpuinit detect_ht(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889{
890#ifdef CONFIG_SMP
891 u32 eax, ebx, ecx, edx;
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100892 int index_msb, core_bits;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 int cpu = smp_processor_id();
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100894
895 cpuid(1, &eax, &ebx, &ecx, &edx);
896
897 c->apicid = phys_pkg_id(0);
898
Andi Kleen63518642005-04-16 15:25:16 -0700899 if (!cpu_has(c, X86_FEATURE_HT) || cpu_has(c, X86_FEATURE_CMP_LEGACY))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 return;
901
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 smp_num_siblings = (ebx & 0xff0000) >> 16;
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100903
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 if (smp_num_siblings == 1) {
905 printk(KERN_INFO "CPU: Hyper-Threading is disabled\n");
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100906 } else if (smp_num_siblings > 1 ) {
907
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 if (smp_num_siblings > NR_CPUS) {
909 printk(KERN_WARNING "CPU: Unsupported number of the siblings %d", smp_num_siblings);
910 smp_num_siblings = 1;
911 return;
912 }
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100913
914 index_msb = get_count_order(smp_num_siblings);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 phys_proc_id[cpu] = phys_pkg_id(index_msb);
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100916
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 printk(KERN_INFO "CPU: Physical Processor ID: %d\n",
918 phys_proc_id[cpu]);
Andi Kleen3dd9d512005-04-16 15:25:15 -0700919
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100920 smp_num_siblings = smp_num_siblings / c->x86_max_cores;
Andi Kleen3dd9d512005-04-16 15:25:15 -0700921
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100922 index_msb = get_count_order(smp_num_siblings) ;
Andi Kleen3dd9d512005-04-16 15:25:15 -0700923
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100924 core_bits = get_count_order(c->x86_max_cores);
Andi Kleen3dd9d512005-04-16 15:25:15 -0700925
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100926 cpu_core_id[cpu] = phys_pkg_id(index_msb) &
927 ((1 << core_bits) - 1);
928
929 if (c->x86_max_cores > 1)
Andi Kleen3dd9d512005-04-16 15:25:15 -0700930 printk(KERN_INFO "CPU: Processor Core ID: %d\n",
931 cpu_core_id[cpu]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 }
933#endif
934}
935
Andi Kleen3dd9d512005-04-16 15:25:15 -0700936/*
937 * find out the number of processor cores on the die
938 */
Ashok Raje6982c62005-06-25 14:54:58 -0700939static int __cpuinit intel_num_cpu_cores(struct cpuinfo_x86 *c)
Andi Kleen3dd9d512005-04-16 15:25:15 -0700940{
941 unsigned int eax;
942
943 if (c->cpuid_level < 4)
944 return 1;
945
946 __asm__("cpuid"
947 : "=a" (eax)
948 : "0" (4), "c" (0)
949 : "bx", "dx");
950
951 if (eax & 0x1f)
952 return ((eax >> 26) + 1);
953 else
954 return 1;
955}
956
Andi Kleendf0cc262005-09-12 18:49:24 +0200957static void srat_detect_node(void)
958{
959#ifdef CONFIG_NUMA
Ravikiran G Thirumalaiddea7be2005-10-03 10:36:28 -0700960 unsigned node;
Andi Kleendf0cc262005-09-12 18:49:24 +0200961 int cpu = smp_processor_id();
962
963 /* Don't do the funky fallback heuristics the AMD version employs
964 for now. */
Ravikiran G Thirumalaiddea7be2005-10-03 10:36:28 -0700965 node = apicid_to_node[hard_smp_processor_id()];
Andi Kleendf0cc262005-09-12 18:49:24 +0200966 if (node == NUMA_NO_NODE)
967 node = 0;
Andi Kleen69d81fc2005-11-05 17:25:53 +0100968 numa_set_node(cpu, node);
Andi Kleendf0cc262005-09-12 18:49:24 +0200969
970 if (acpi_numa > 0)
971 printk(KERN_INFO "CPU %d -> Node %d\n", cpu, node);
972#endif
973}
974
Ashok Raje6982c62005-06-25 14:54:58 -0700975static void __cpuinit init_intel(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976{
977 /* Cache sizes */
978 unsigned n;
979
980 init_intel_cacheinfo(c);
Andi Kleenebfcaa92005-04-16 15:25:18 -0700981 n = c->extended_cpuid_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 if (n >= 0x80000008) {
983 unsigned eax = cpuid_eax(0x80000008);
984 c->x86_virt_bits = (eax >> 8) & 0xff;
985 c->x86_phys_bits = eax & 0xff;
Shaohua Liaf9c1422005-11-05 17:25:54 +0100986 /* CPUID workaround for Intel 0F34 CPU */
987 if (c->x86_vendor == X86_VENDOR_INTEL &&
988 c->x86 == 0xF && c->x86_model == 0x3 &&
989 c->x86_mask == 0x4)
990 c->x86_phys_bits = 36;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 }
992
993 if (c->x86 == 15)
994 c->x86_cache_alignment = c->x86_clflush_size * 2;
Andi Kleenc29601e2005-04-16 15:25:05 -0700995 if (c->x86 >= 15)
996 set_bit(X86_FEATURE_CONSTANT_TSC, &c->x86_capability);
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100997 c->x86_max_cores = intel_num_cpu_cores(c);
Andi Kleendf0cc262005-09-12 18:49:24 +0200998
999 srat_detect_node();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000}
1001
Adrian Bunk672289e2005-09-10 00:27:21 -07001002static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003{
1004 char *v = c->x86_vendor_id;
1005
1006 if (!strcmp(v, "AuthenticAMD"))
1007 c->x86_vendor = X86_VENDOR_AMD;
1008 else if (!strcmp(v, "GenuineIntel"))
1009 c->x86_vendor = X86_VENDOR_INTEL;
1010 else
1011 c->x86_vendor = X86_VENDOR_UNKNOWN;
1012}
1013
1014struct cpu_model_info {
1015 int vendor;
1016 int family;
1017 char *model_names[16];
1018};
1019
1020/* Do some early cpuid on the boot CPU to get some parameter that are
1021 needed before check_bugs. Everything advanced is in identify_cpu
1022 below. */
Ashok Raje6982c62005-06-25 14:54:58 -07001023void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024{
1025 u32 tfms;
1026
1027 c->loops_per_jiffy = loops_per_jiffy;
1028 c->x86_cache_size = -1;
1029 c->x86_vendor = X86_VENDOR_UNKNOWN;
1030 c->x86_model = c->x86_mask = 0; /* So far unknown... */
1031 c->x86_vendor_id[0] = '\0'; /* Unset */
1032 c->x86_model_id[0] = '\0'; /* Unset */
1033 c->x86_clflush_size = 64;
1034 c->x86_cache_alignment = c->x86_clflush_size;
Siddha, Suresh B94605ef2005-11-05 17:25:54 +01001035 c->x86_max_cores = 1;
Andi Kleenebfcaa92005-04-16 15:25:18 -07001036 c->extended_cpuid_level = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 memset(&c->x86_capability, 0, sizeof c->x86_capability);
1038
1039 /* Get vendor name */
1040 cpuid(0x00000000, (unsigned int *)&c->cpuid_level,
1041 (unsigned int *)&c->x86_vendor_id[0],
1042 (unsigned int *)&c->x86_vendor_id[8],
1043 (unsigned int *)&c->x86_vendor_id[4]);
1044
1045 get_cpu_vendor(c);
1046
1047 /* Initialize the standard set of capabilities */
1048 /* Note that the vendor-specific code below might override */
1049
1050 /* Intel-defined flags: level 0x00000001 */
1051 if (c->cpuid_level >= 0x00000001) {
1052 __u32 misc;
1053 cpuid(0x00000001, &tfms, &misc, &c->x86_capability[4],
1054 &c->x86_capability[0]);
1055 c->x86 = (tfms >> 8) & 0xf;
1056 c->x86_model = (tfms >> 4) & 0xf;
1057 c->x86_mask = tfms & 0xf;
Suresh Siddhaf5f786d2005-11-05 17:25:53 +01001058 if (c->x86 == 0xf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 c->x86 += (tfms >> 20) & 0xff;
Suresh Siddhaf5f786d2005-11-05 17:25:53 +01001060 if (c->x86 >= 0x6)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 c->x86_model += ((tfms >> 16) & 0xF) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 if (c->x86_capability[0] & (1<<19))
1063 c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 } else {
1065 /* Have CPUID level 0 only - unheard of */
1066 c->x86 = 4;
1067 }
Andi Kleena1586082005-05-16 21:53:21 -07001068
1069#ifdef CONFIG_SMP
Andi Kleenb41e2932005-05-20 14:27:55 -07001070 phys_proc_id[smp_processor_id()] = (cpuid_ebx(1) >> 24) & 0xff;
Andi Kleena1586082005-05-16 21:53:21 -07001071#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072}
1073
1074/*
1075 * This does the hard work of actually picking apart the CPU stuff...
1076 */
Ashok Raje6982c62005-06-25 14:54:58 -07001077void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078{
1079 int i;
1080 u32 xlvl;
1081
1082 early_identify_cpu(c);
1083
1084 /* AMD-defined flags: level 0x80000001 */
1085 xlvl = cpuid_eax(0x80000000);
Andi Kleenebfcaa92005-04-16 15:25:18 -07001086 c->extended_cpuid_level = xlvl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 if ((xlvl & 0xffff0000) == 0x80000000) {
1088 if (xlvl >= 0x80000001) {
1089 c->x86_capability[1] = cpuid_edx(0x80000001);
H. Peter Anvin5b7abc62005-05-01 08:58:49 -07001090 c->x86_capability[6] = cpuid_ecx(0x80000001);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 }
1092 if (xlvl >= 0x80000004)
1093 get_model_name(c); /* Default name */
1094 }
1095
1096 /* Transmeta-defined flags: level 0x80860001 */
1097 xlvl = cpuid_eax(0x80860000);
1098 if ((xlvl & 0xffff0000) == 0x80860000) {
1099 /* Don't set x86_cpuid_level here for now to not confuse. */
1100 if (xlvl >= 0x80860001)
1101 c->x86_capability[2] = cpuid_edx(0x80860001);
1102 }
1103
1104 /*
1105 * Vendor-specific initialization. In this section we
1106 * canonicalize the feature flags, meaning if there are
1107 * features a certain CPU supports which CPUID doesn't
1108 * tell us, CPUID claiming incorrect flags, or other bugs,
1109 * we handle them here.
1110 *
1111 * At the end of this section, c->x86_capability better
1112 * indicate the features this CPU genuinely supports!
1113 */
1114 switch (c->x86_vendor) {
1115 case X86_VENDOR_AMD:
1116 init_amd(c);
1117 break;
1118
1119 case X86_VENDOR_INTEL:
1120 init_intel(c);
1121 break;
1122
1123 case X86_VENDOR_UNKNOWN:
1124 default:
1125 display_cacheinfo(c);
1126 break;
1127 }
1128
1129 select_idle_routine(c);
1130 detect_ht(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131
1132 /*
1133 * On SMP, boot_cpu_data holds the common feature set between
1134 * all CPUs; so make sure that we indicate which features are
1135 * common between the CPUs. The first time this routine gets
1136 * executed, c == &boot_cpu_data.
1137 */
1138 if (c != &boot_cpu_data) {
1139 /* AND the already accumulated flags with these */
1140 for (i = 0 ; i < NCAPINTS ; i++)
1141 boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
1142 }
1143
1144#ifdef CONFIG_X86_MCE
1145 mcheck_init(c);
1146#endif
Shaohua Li3b520b22005-07-07 17:56:38 -07001147 if (c == &boot_cpu_data)
1148 mtrr_bp_init();
1149 else
1150 mtrr_ap_init();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151#ifdef CONFIG_NUMA
Andi Kleen3019e8e2005-07-28 21:15:28 -07001152 numa_add_cpu(smp_processor_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153#endif
1154}
1155
1156
Ashok Raje6982c62005-06-25 14:54:58 -07001157void __cpuinit print_cpu_info(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158{
1159 if (c->x86_model_id[0])
1160 printk("%s", c->x86_model_id);
1161
1162 if (c->x86_mask || c->cpuid_level >= 0)
1163 printk(" stepping %02x\n", c->x86_mask);
1164 else
1165 printk("\n");
1166}
1167
1168/*
1169 * Get CPU information for use by the procfs.
1170 */
1171
1172static int show_cpuinfo(struct seq_file *m, void *v)
1173{
1174 struct cpuinfo_x86 *c = v;
1175
1176 /*
1177 * These flag bits must match the definitions in <asm/cpufeature.h>.
1178 * NULL means this bit is undefined or reserved; either way it doesn't
1179 * have meaning as far as Linux is concerned. Note that it's important
1180 * to realize there is a difference between this table and CPUID -- if
1181 * applications want to get the raw CPUID data, they should access
1182 * /dev/cpu/<cpu_nr>/cpuid instead.
1183 */
1184 static char *x86_cap_flags[] = {
1185 /* Intel-defined */
1186 "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
1187 "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
1188 "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
1189 "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", NULL,
1190
1191 /* AMD-defined */
Zwane Mwaikambo3c3b73b2005-05-01 08:58:51 -07001192 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
1194 NULL, NULL, NULL, NULL, "nx", NULL, "mmxext", NULL,
1195 NULL, "fxsr_opt", NULL, NULL, NULL, "lm", "3dnowext", "3dnow",
1196
1197 /* Transmeta-defined */
1198 "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
1199 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1200 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1201 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1202
1203 /* Other (Linux-defined) */
Andi Kleen622dcaf2005-05-16 21:53:26 -07001204 "cxmmx", NULL, "cyrix_arr", "centaur_mcr", NULL,
Andi Kleenc29601e2005-04-16 15:25:05 -07001205 "constant_tsc", NULL, NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1207 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1208 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1209
1210 /* Intel-defined (#2) */
Kamble, Nitin Adaedb822005-10-30 14:59:43 -08001211 "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", NULL, "est",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 "tm2", NULL, "cid", NULL, NULL, "cx16", "xtpr", NULL,
1213 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1214 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1215
H. Peter Anvin5b7abc62005-05-01 08:58:49 -07001216 /* VIA/Cyrix/Centaur-defined */
1217 NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
1218 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1219 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1220 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1221
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 /* AMD-defined (#2) */
1223 "lahf_lm", "cmp_legacy", NULL, NULL, NULL, NULL, NULL, NULL,
1224 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1225 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
H. Peter Anvin5b7abc62005-05-01 08:58:49 -07001226 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 };
1228 static char *x86_power_flags[] = {
1229 "ts", /* temperature sensor */
1230 "fid", /* frequency id control */
1231 "vid", /* voltage id control */
1232 "ttp", /* thermal trip */
1233 "tm",
1234 "stc"
1235 };
1236
1237
1238#ifdef CONFIG_SMP
1239 if (!cpu_online(c-cpu_data))
1240 return 0;
1241#endif
1242
1243 seq_printf(m,"processor\t: %u\n"
1244 "vendor_id\t: %s\n"
1245 "cpu family\t: %d\n"
1246 "model\t\t: %d\n"
1247 "model name\t: %s\n",
1248 (unsigned)(c-cpu_data),
1249 c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown",
1250 c->x86,
1251 (int)c->x86_model,
1252 c->x86_model_id[0] ? c->x86_model_id : "unknown");
1253
1254 if (c->x86_mask || c->cpuid_level >= 0)
1255 seq_printf(m, "stepping\t: %d\n", c->x86_mask);
1256 else
1257 seq_printf(m, "stepping\t: unknown\n");
1258
1259 if (cpu_has(c,X86_FEATURE_TSC)) {
Venkatesh Pallipadi95235ca2005-12-02 10:43:20 -08001260 unsigned int freq = cpufreq_quick_get((unsigned)(c-cpu_data));
1261 if (!freq)
1262 freq = cpu_khz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 seq_printf(m, "cpu MHz\t\t: %u.%03u\n",
Venkatesh Pallipadi95235ca2005-12-02 10:43:20 -08001264 freq / 1000, (freq % 1000));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 }
1266
1267 /* Cache size */
1268 if (c->x86_cache_size >= 0)
1269 seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size);
1270
1271#ifdef CONFIG_SMP
Siddha, Suresh B94605ef2005-11-05 17:25:54 +01001272 if (smp_num_siblings * c->x86_max_cores > 1) {
Andi Kleendb468682005-04-16 15:24:51 -07001273 int cpu = c - cpu_data;
1274 seq_printf(m, "physical id\t: %d\n", phys_proc_id[cpu]);
Siddha, Suresh B94605ef2005-11-05 17:25:54 +01001275 seq_printf(m, "siblings\t: %d\n", cpus_weight(cpu_core_map[cpu]));
Siddha, Suresh Bd31ddaa2005-04-16 15:25:20 -07001276 seq_printf(m, "core id\t\t: %d\n", cpu_core_id[cpu]);
Siddha, Suresh B94605ef2005-11-05 17:25:54 +01001277 seq_printf(m, "cpu cores\t: %d\n", c->booted_cores);
Andi Kleendb468682005-04-16 15:24:51 -07001278 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279#endif
1280
1281 seq_printf(m,
1282 "fpu\t\t: yes\n"
1283 "fpu_exception\t: yes\n"
1284 "cpuid level\t: %d\n"
1285 "wp\t\t: yes\n"
1286 "flags\t\t:",
1287 c->cpuid_level);
1288
1289 {
1290 int i;
1291 for ( i = 0 ; i < 32*NCAPINTS ; i++ )
1292 if ( test_bit(i, &c->x86_capability) &&
1293 x86_cap_flags[i] != NULL )
1294 seq_printf(m, " %s", x86_cap_flags[i]);
1295 }
1296
1297 seq_printf(m, "\nbogomips\t: %lu.%02lu\n",
1298 c->loops_per_jiffy/(500000/HZ),
1299 (c->loops_per_jiffy/(5000/HZ)) % 100);
1300
1301 if (c->x86_tlbsize > 0)
1302 seq_printf(m, "TLB size\t: %d 4K pages\n", c->x86_tlbsize);
1303 seq_printf(m, "clflush size\t: %d\n", c->x86_clflush_size);
1304 seq_printf(m, "cache_alignment\t: %d\n", c->x86_cache_alignment);
1305
1306 seq_printf(m, "address sizes\t: %u bits physical, %u bits virtual\n",
1307 c->x86_phys_bits, c->x86_virt_bits);
1308
1309 seq_printf(m, "power management:");
1310 {
1311 unsigned i;
1312 for (i = 0; i < 32; i++)
1313 if (c->x86_power & (1 << i)) {
1314 if (i < ARRAY_SIZE(x86_power_flags))
1315 seq_printf(m, " %s", x86_power_flags[i]);
1316 else
1317 seq_printf(m, " [%d]", i);
1318 }
1319 }
Andi Kleen3dd9d512005-04-16 15:25:15 -07001320
Siddha, Suresh Bd31ddaa2005-04-16 15:25:20 -07001321 seq_printf(m, "\n\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 return 0;
1324}
1325
1326static void *c_start(struct seq_file *m, loff_t *pos)
1327{
1328 return *pos < NR_CPUS ? cpu_data + *pos : NULL;
1329}
1330
1331static void *c_next(struct seq_file *m, void *v, loff_t *pos)
1332{
1333 ++*pos;
1334 return c_start(m, pos);
1335}
1336
1337static void c_stop(struct seq_file *m, void *v)
1338{
1339}
1340
1341struct seq_operations cpuinfo_op = {
1342 .start =c_start,
1343 .next = c_next,
1344 .stop = c_stop,
1345 .show = show_cpuinfo,
1346};