blob: 238633d3d09a7ac1d8a6427d2e26c3ce773291e8 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * Copyright (C) 1995 Linus Torvalds
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 */
4
5/*
6 * This file handles the architecture-dependent parts of initialization
7 */
8
9#include <linux/errno.h>
10#include <linux/sched.h>
11#include <linux/kernel.h>
12#include <linux/mm.h>
13#include <linux/stddef.h>
14#include <linux/unistd.h>
15#include <linux/ptrace.h>
16#include <linux/slab.h>
17#include <linux/user.h>
18#include <linux/a.out.h>
Jon Smirl894673e2006-07-10 04:44:13 -070019#include <linux/screen_info.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include <linux/ioport.h>
21#include <linux/delay.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <linux/init.h>
23#include <linux/initrd.h>
24#include <linux/highmem.h>
25#include <linux/bootmem.h>
26#include <linux/module.h>
27#include <asm/processor.h>
28#include <linux/console.h>
29#include <linux/seq_file.h>
Vivek Goyalaac04b32006-01-09 20:51:47 -080030#include <linux/crash_dump.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/root_dev.h>
32#include <linux/pci.h>
33#include <linux/acpi.h>
34#include <linux/kallsyms.h>
35#include <linux/edd.h>
Matt Tolentinobbfceef2005-06-23 00:08:07 -070036#include <linux/mmzone.h>
Eric W. Biederman5f5609d2005-06-25 14:58:04 -070037#include <linux/kexec.h>
Venkatesh Pallipadi95235ca2005-12-02 10:43:20 -080038#include <linux/cpufreq.h>
Andi Kleene9928672006-01-11 22:43:33 +010039#include <linux/dmi.h>
Muli Ben-Yehuda17a941d2006-01-11 22:44:42 +010040#include <linux/dma-mapping.h>
Andi Kleen681558f2006-03-25 16:29:46 +010041#include <linux/ctype.h>
Matt Tolentinobbfceef2005-06-23 00:08:07 -070042
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <asm/mtrr.h>
44#include <asm/uaccess.h>
45#include <asm/system.h>
46#include <asm/io.h>
47#include <asm/smp.h>
48#include <asm/msr.h>
49#include <asm/desc.h>
50#include <video/edid.h>
51#include <asm/e820.h>
52#include <asm/dma.h>
53#include <asm/mpspec.h>
54#include <asm/mmu_context.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070055#include <asm/proto.h>
56#include <asm/setup.h>
57#include <asm/mach_apic.h>
58#include <asm/numa.h>
Andi Kleen2bc04142005-11-05 17:25:53 +010059#include <asm/sections.h>
Andi Kleenf2d3efe2006-03-25 16:30:22 +010060#include <asm/dmi.h>
Bernhard Walle00bf4092007-10-21 16:42:01 -070061#include <asm/cacheflush.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
63/*
64 * Machine setup..
65 */
66
Ravikiran G Thirumalai6c231b72005-09-06 15:17:45 -070067struct cpuinfo_x86 boot_cpu_data __read_mostly;
Andi Kleen2ee60e172006-06-26 13:59:44 +020068EXPORT_SYMBOL(boot_cpu_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
70unsigned long mmu_cr4_features;
71
Linus Torvalds1da177e2005-04-16 15:20:36 -070072/* Boot loader ID as an integer, for the benefit of proc_dointvec */
73int bootloader_type;
74
75unsigned long saved_video_mode;
76
Andi Kleenf039b752007-05-02 19:27:12 +020077int force_mwait __cpuinitdata;
78
Andi Kleenf2d3efe2006-03-25 16:30:22 +010079/*
80 * Early DMI memory
81 */
82int dmi_alloc_index;
83char dmi_alloc_data[DMI_MAX_DATA];
84
Linus Torvalds1da177e2005-04-16 15:20:36 -070085/*
86 * Setup options
87 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070088struct screen_info screen_info;
Andi Kleen2ee60e172006-06-26 13:59:44 +020089EXPORT_SYMBOL(screen_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -070090struct sys_desc_table_struct {
91 unsigned short length;
92 unsigned char table[0];
93};
94
95struct edid_info edid_info;
Antonino A. Daplasba707102006-06-26 00:26:37 -070096EXPORT_SYMBOL_GPL(edid_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
98extern int root_mountflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Alon Bar-Levadf48852007-02-12 00:54:25 -0800100char __initdata command_line[COMMAND_LINE_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
102struct resource standard_io_resources[] = {
103 { .name = "dma1", .start = 0x00, .end = 0x1f,
104 .flags = IORESOURCE_BUSY | IORESOURCE_IO },
105 { .name = "pic1", .start = 0x20, .end = 0x21,
106 .flags = IORESOURCE_BUSY | IORESOURCE_IO },
107 { .name = "timer0", .start = 0x40, .end = 0x43,
108 .flags = IORESOURCE_BUSY | IORESOURCE_IO },
109 { .name = "timer1", .start = 0x50, .end = 0x53,
110 .flags = IORESOURCE_BUSY | IORESOURCE_IO },
111 { .name = "keyboard", .start = 0x60, .end = 0x6f,
112 .flags = IORESOURCE_BUSY | IORESOURCE_IO },
113 { .name = "dma page reg", .start = 0x80, .end = 0x8f,
114 .flags = IORESOURCE_BUSY | IORESOURCE_IO },
115 { .name = "pic2", .start = 0xa0, .end = 0xa1,
116 .flags = IORESOURCE_BUSY | IORESOURCE_IO },
117 { .name = "dma2", .start = 0xc0, .end = 0xdf,
118 .flags = IORESOURCE_BUSY | IORESOURCE_IO },
119 { .name = "fpu", .start = 0xf0, .end = 0xff,
120 .flags = IORESOURCE_BUSY | IORESOURCE_IO }
121};
122
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123#define IORESOURCE_RAM (IORESOURCE_BUSY | IORESOURCE_MEM)
124
125struct resource data_resource = {
126 .name = "Kernel data",
127 .start = 0,
128 .end = 0,
129 .flags = IORESOURCE_RAM,
130};
131struct resource code_resource = {
132 .name = "Kernel code",
133 .start = 0,
134 .end = 0,
135 .flags = IORESOURCE_RAM,
136};
Bernhard Walle00bf4092007-10-21 16:42:01 -0700137struct resource bss_resource = {
138 .name = "Kernel bss",
139 .start = 0,
140 .end = 0,
141 .flags = IORESOURCE_RAM,
142};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
Vivek Goyalaac04b32006-01-09 20:51:47 -0800144#ifdef CONFIG_PROC_VMCORE
Andi Kleen2c8c0e62006-09-26 10:52:32 +0200145/* elfcorehdr= specifies the location of elf core header
146 * stored by the crashed kernel. This option will be passed
147 * by kexec loader to the capture kernel.
148 */
149static int __init setup_elfcorehdr(char *arg)
150{
151 char *end;
152 if (!arg)
153 return -EINVAL;
154 elfcorehdr_addr = memparse(arg, &end);
155 return end > arg ? 0 : -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156}
Andi Kleen2c8c0e62006-09-26 10:52:32 +0200157early_param("elfcorehdr", setup_elfcorehdr);
158#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159
Matt Tolentino2b976902005-06-23 00:08:06 -0700160#ifndef CONFIG_NUMA
Matt Tolentinobbfceef2005-06-23 00:08:07 -0700161static void __init
162contig_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163{
Matt Tolentinobbfceef2005-06-23 00:08:07 -0700164 unsigned long bootmap_size, bootmap;
165
Matt Tolentinobbfceef2005-06-23 00:08:07 -0700166 bootmap_size = bootmem_bootmap_pages(end_pfn)<<PAGE_SHIFT;
167 bootmap = find_e820_area(0, end_pfn<<PAGE_SHIFT, bootmap_size);
168 if (bootmap == -1L)
169 panic("Cannot find bootmem map of size %ld\n",bootmap_size);
170 bootmap_size = init_bootmem(bootmap >> PAGE_SHIFT, end_pfn);
Mel Gorman5cb248a2006-09-27 01:49:52 -0700171 e820_register_active_regions(0, start_pfn, end_pfn);
172 free_bootmem_with_active_regions(0, end_pfn);
Matt Tolentinobbfceef2005-06-23 00:08:07 -0700173 reserve_bootmem(bootmap, bootmap_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174}
175#endif
176
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
178struct edd edd;
179#ifdef CONFIG_EDD_MODULE
180EXPORT_SYMBOL(edd);
181#endif
182/**
183 * copy_edd() - Copy the BIOS EDD information
184 * from boot_params into a safe place.
185 *
186 */
187static inline void copy_edd(void)
188{
H. Peter Anvin30c82642007-10-15 17:13:22 -0700189 memcpy(edd.mbr_signature, boot_params.edd_mbr_sig_buffer,
190 sizeof(edd.mbr_signature));
191 memcpy(edd.edd_info, boot_params.eddbuf, sizeof(edd.edd_info));
192 edd.mbr_signature_nr = boot_params.edd_mbr_sig_buf_entries;
193 edd.edd_info_nr = boot_params.eddbuf_entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194}
195#else
196static inline void copy_edd(void)
197{
198}
199#endif
200
Bernhard Walle5c3391f2007-10-18 23:40:59 -0700201#ifdef CONFIG_KEXEC
202static void __init reserve_crashkernel(void)
203{
204 unsigned long long free_mem;
205 unsigned long long crash_size, crash_base;
206 int ret;
207
208 free_mem = ((unsigned long long)max_low_pfn - min_low_pfn) << PAGE_SHIFT;
209
210 ret = parse_crashkernel(boot_command_line, free_mem,
211 &crash_size, &crash_base);
212 if (ret == 0 && crash_size) {
213 if (crash_base > 0) {
214 printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
215 "for crashkernel (System RAM: %ldMB)\n",
216 (unsigned long)(crash_size >> 20),
217 (unsigned long)(crash_base >> 20),
218 (unsigned long)(free_mem >> 20));
219 crashk_res.start = crash_base;
220 crashk_res.end = crash_base + crash_size - 1;
221 reserve_bootmem(crash_base, crash_size);
222 } else
223 printk(KERN_INFO "crashkernel reservation failed - "
224 "you have to specify a base address\n");
225 }
226}
227#else
228static inline void __init reserve_crashkernel(void)
229{}
230#endif
231
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232#define EBDA_ADDR_POINTER 0x40E
Andi Kleenac71d122006-05-08 15:17:28 +0200233
234unsigned __initdata ebda_addr;
235unsigned __initdata ebda_size;
236
237static void discover_ebda(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238{
Andi Kleenac71d122006-05-08 15:17:28 +0200239 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 * there is a real-mode segmented pointer pointing to the
241 * 4K EBDA area at 0x40E
242 */
Vivek Goyalbdb96a62007-05-02 19:27:07 +0200243 ebda_addr = *(unsigned short *)__va(EBDA_ADDR_POINTER);
Andi Kleenac71d122006-05-08 15:17:28 +0200244 ebda_addr <<= 4;
245
Vivek Goyalbdb96a62007-05-02 19:27:07 +0200246 ebda_size = *(unsigned short *)__va(ebda_addr);
Andi Kleenac71d122006-05-08 15:17:28 +0200247
248 /* Round EBDA up to pages */
249 if (ebda_size == 0)
250 ebda_size = 1;
251 ebda_size <<= 10;
252 ebda_size = round_up(ebda_size + (ebda_addr & ~PAGE_MASK), PAGE_SIZE);
253 if (ebda_size > 64*1024)
254 ebda_size = 64*1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255}
256
257void __init setup_arch(char **cmdline_p)
258{
Alon Bar-Levadf48852007-02-12 00:54:25 -0800259 printk(KERN_INFO "Command line: %s\n", boot_command_line);
Andi Kleen43c85c92006-09-26 10:52:32 +0200260
H. Peter Anvin30c82642007-10-15 17:13:22 -0700261 ROOT_DEV = old_decode_dev(boot_params.hdr.root_dev);
262 screen_info = boot_params.screen_info;
263 edid_info = boot_params.edid_info;
264 saved_video_mode = boot_params.hdr.vid_mode;
265 bootloader_type = boot_params.hdr.type_of_loader;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
267#ifdef CONFIG_BLK_DEV_RAM
H. Peter Anvin30c82642007-10-15 17:13:22 -0700268 rd_image_start = boot_params.hdr.ram_size & RAMDISK_IMAGE_START_MASK;
269 rd_prompt = ((boot_params.hdr.ram_size & RAMDISK_PROMPT_FLAG) != 0);
270 rd_doload = ((boot_params.hdr.ram_size & RAMDISK_LOAD_FLAG) != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271#endif
272 setup_memory_region();
273 copy_edd();
274
H. Peter Anvin30c82642007-10-15 17:13:22 -0700275 if (!boot_params.hdr.root_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 root_mountflags &= ~MS_RDONLY;
277 init_mm.start_code = (unsigned long) &_text;
278 init_mm.end_code = (unsigned long) &_etext;
279 init_mm.end_data = (unsigned long) &_edata;
280 init_mm.brk = (unsigned long) &_end;
281
Linus Torvaldse3ebadd2007-05-07 08:44:24 -0700282 code_resource.start = virt_to_phys(&_text);
283 code_resource.end = virt_to_phys(&_etext)-1;
284 data_resource.start = virt_to_phys(&_etext);
285 data_resource.end = virt_to_phys(&_edata)-1;
Bernhard Walle00bf4092007-10-21 16:42:01 -0700286 bss_resource.start = virt_to_phys(&__bss_start);
287 bss_resource.end = virt_to_phys(&__bss_stop)-1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 early_identify_cpu(&boot_cpu_data);
290
Alon Bar-Levadf48852007-02-12 00:54:25 -0800291 strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
Andi Kleen2c8c0e62006-09-26 10:52:32 +0200292 *cmdline_p = command_line;
293
294 parse_early_param();
295
296 finish_e820_parsing();
Andi Kleen9ca33eb2006-09-26 10:52:32 +0200297
Mel Gorman5cb248a2006-09-27 01:49:52 -0700298 e820_register_active_regions(0, 0, -1UL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 /*
300 * partially used pages are not usable - thus
301 * we are rounding upwards:
302 */
303 end_pfn = e820_end_of_ram();
Jan Beulichcaff0712006-09-26 10:52:31 +0200304 num_physpages = end_pfn;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
306 check_efer();
307
Andi Kleenac71d122006-05-08 15:17:28 +0200308 discover_ebda();
309
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 init_memory_mapping(0, (end_pfn_map << PAGE_SHIFT));
311
Andi Kleenf2d3efe2006-03-25 16:30:22 +0100312 dmi_scan_machine();
313
Mike Travis71fff5e2007-10-19 20:35:03 +0200314#ifdef CONFIG_SMP
315 /* setup to use the static apicid table during kernel startup */
316 x86_cpu_to_apicid_ptr = (void *)&x86_cpu_to_apicid_init;
317#endif
318
Len Brown888ba6c2005-08-24 12:07:20 -0400319#ifdef CONFIG_ACPI
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 /*
321 * Initialize the ACPI boot-time table parser (gets the RSDP and SDT).
322 * Call this early for SRAT node setup.
323 */
324 acpi_boot_table_init();
325#endif
326
Jan Beulichcaff0712006-09-26 10:52:31 +0200327 /* How many end-of-memory variables you have, grandma! */
328 max_low_pfn = end_pfn;
329 max_pfn = end_pfn;
330 high_memory = (void *)__va(end_pfn * PAGE_SIZE - 1) + 1;
331
Mel Gorman5cb248a2006-09-27 01:49:52 -0700332 /* Remove active ranges so rediscovery with NUMA-awareness happens */
333 remove_all_active_ranges();
334
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335#ifdef CONFIG_ACPI_NUMA
336 /*
337 * Parse SRAT to discover nodes.
338 */
339 acpi_numa_init();
340#endif
341
Matt Tolentino2b976902005-06-23 00:08:06 -0700342#ifdef CONFIG_NUMA
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 numa_initmem_init(0, end_pfn);
344#else
Matt Tolentinobbfceef2005-06-23 00:08:07 -0700345 contig_initmem_init(0, end_pfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346#endif
347
348 /* Reserve direct mapping */
349 reserve_bootmem_generic(table_start << PAGE_SHIFT,
350 (table_end - table_start) << PAGE_SHIFT);
351
352 /* reserve kernel */
Andi Kleenceee8822006-08-30 19:37:12 +0200353 reserve_bootmem_generic(__pa_symbol(&_text),
354 __pa_symbol(&_end) - __pa_symbol(&_text));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355
356 /*
357 * reserve physical page 0 - it's a special BIOS page on many boxes,
358 * enabling clean reboots, SMP operation, laptop functions.
359 */
360 reserve_bootmem_generic(0, PAGE_SIZE);
361
362 /* reserve ebda region */
Andi Kleenac71d122006-05-08 15:17:28 +0200363 if (ebda_addr)
364 reserve_bootmem_generic(ebda_addr, ebda_size);
Amul Shah076422d2007-02-13 13:26:19 +0100365#ifdef CONFIG_NUMA
366 /* reserve nodemap region */
367 if (nodemap_addr)
368 reserve_bootmem_generic(nodemap_addr, nodemap_size);
369#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
371#ifdef CONFIG_SMP
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 /* Reserve SMP trampoline */
Vivek Goyal90b1c202007-05-02 19:27:07 +0200373 reserve_bootmem_generic(SMP_TRAMPOLINE_BASE, 2*PAGE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374#endif
375
Len Brown673d5b42007-07-28 03:33:16 -0400376#ifdef CONFIG_ACPI_SLEEP
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 /*
378 * Reserve low memory region for sleep support.
379 */
380 acpi_reserve_bootmem();
381#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 /*
383 * Find and reserve possible boot-time SMP configuration:
384 */
385 find_smp_config();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386#ifdef CONFIG_BLK_DEV_INITRD
H. Peter Anvin30c82642007-10-15 17:13:22 -0700387 if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) {
388 unsigned long ramdisk_image = boot_params.hdr.ramdisk_image;
389 unsigned long ramdisk_size = boot_params.hdr.ramdisk_size;
390 unsigned long ramdisk_end = ramdisk_image + ramdisk_size;
391 unsigned long end_of_mem = end_pfn << PAGE_SHIFT;
392
393 if (ramdisk_end <= end_of_mem) {
394 reserve_bootmem_generic(ramdisk_image, ramdisk_size);
395 initrd_start = ramdisk_image + PAGE_OFFSET;
396 initrd_end = initrd_start+ramdisk_size;
397 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 printk(KERN_ERR "initrd extends beyond end of memory "
H. Peter Anvin30c82642007-10-15 17:13:22 -0700399 "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
400 ramdisk_end, end_of_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 initrd_start = 0;
402 }
403 }
404#endif
Bernhard Walle5c3391f2007-10-18 23:40:59 -0700405 reserve_crashkernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 paging_init();
407
Andi Kleenf157cbb2006-09-26 10:52:41 +0200408#ifdef CONFIG_PCI
Andi Kleendfa46982006-09-26 10:52:30 +0200409 early_quirks();
Andi Kleenf157cbb2006-09-26 10:52:41 +0200410#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411
Ashok Raj51f62e12006-03-25 16:29:28 +0100412 /*
413 * set this early, so we dont allocate cpu0
414 * if MADT list doesnt list BSP first
415 * mpparse.c/MP_processor_info() allocates logical cpu numbers.
416 */
417 cpu_set(0, cpu_present_map);
Len Brown888ba6c2005-08-24 12:07:20 -0400418#ifdef CONFIG_ACPI
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 /*
420 * Read APIC and some other early information from ACPI tables.
421 */
422 acpi_boot_init();
423#endif
424
Ravikiran Thirumalai05b3cbd2006-01-11 22:45:36 +0100425 init_cpu_to_node();
426
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 /*
428 * get boot-time SMP configuration:
429 */
430 if (smp_found_config)
431 get_smp_config();
432 init_apic_mappings();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433
434 /*
Andi Kleenfc986db2007-02-13 13:26:24 +0100435 * We trust e820 completely. No explicit ROM probing in memory.
436 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 e820_reserve_resources();
Rafael J. Wysockie8eff5a2006-09-25 23:32:46 -0700438 e820_mark_nosave_regions();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 {
441 unsigned i;
442 /* request I/O space for devices used on all i[345]86 PCs */
Andi Kleen9d0ef4f2006-09-30 01:47:55 +0200443 for (i = 0; i < ARRAY_SIZE(standard_io_resources); i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 request_resource(&ioport_resource, &standard_io_resources[i]);
445 }
446
Andi Kleena1e97782005-04-16 15:25:12 -0700447 e820_setup_gap();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449#ifdef CONFIG_VT
450#if defined(CONFIG_VGA_CONSOLE)
451 conswitchp = &vga_con;
452#elif defined(CONFIG_DUMMY_CONSOLE)
453 conswitchp = &dummy_con;
454#endif
455#endif
456}
457
Ashok Raje6982c62005-06-25 14:54:58 -0700458static int __cpuinit get_model_name(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459{
460 unsigned int *v;
461
Andi Kleenebfcaa92005-04-16 15:25:18 -0700462 if (c->extended_cpuid_level < 0x80000004)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 return 0;
464
465 v = (unsigned int *) c->x86_model_id;
466 cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
467 cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
468 cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
469 c->x86_model_id[48] = 0;
470 return 1;
471}
472
473
Ashok Raje6982c62005-06-25 14:54:58 -0700474static void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475{
476 unsigned int n, dummy, eax, ebx, ecx, edx;
477
Andi Kleenebfcaa92005-04-16 15:25:18 -0700478 n = c->extended_cpuid_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479
480 if (n >= 0x80000005) {
481 cpuid(0x80000005, &dummy, &ebx, &ecx, &edx);
482 printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), D cache %dK (%d bytes/line)\n",
483 edx>>24, edx&0xFF, ecx>>24, ecx&0xFF);
484 c->x86_cache_size=(ecx>>24)+(edx>>24);
485 /* On K8 L1 TLB is inclusive, so don't count it */
486 c->x86_tlbsize = 0;
487 }
488
489 if (n >= 0x80000006) {
490 cpuid(0x80000006, &dummy, &ebx, &ecx, &edx);
491 ecx = cpuid_ecx(0x80000006);
492 c->x86_cache_size = ecx >> 16;
493 c->x86_tlbsize += ((ebx >> 16) & 0xfff) + (ebx & 0xfff);
494
495 printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n",
496 c->x86_cache_size, ecx & 0xFF);
497 }
498
499 if (n >= 0x80000007)
500 cpuid(0x80000007, &dummy, &dummy, &dummy, &c->x86_power);
501 if (n >= 0x80000008) {
502 cpuid(0x80000008, &eax, &dummy, &dummy, &dummy);
503 c->x86_virt_bits = (eax >> 8) & 0xff;
504 c->x86_phys_bits = eax & 0xff;
505 }
506}
507
Andi Kleen3f098c22005-09-12 18:49:24 +0200508#ifdef CONFIG_NUMA
509static int nearby_node(int apicid)
510{
511 int i;
512 for (i = apicid - 1; i >= 0; i--) {
513 int node = apicid_to_node[i];
514 if (node != NUMA_NO_NODE && node_online(node))
515 return node;
516 }
517 for (i = apicid + 1; i < MAX_LOCAL_APIC; i++) {
518 int node = apicid_to_node[i];
519 if (node != NUMA_NO_NODE && node_online(node))
520 return node;
521 }
522 return first_node(node_online_map); /* Shouldn't happen */
523}
524#endif
525
Andi Kleen63518642005-04-16 15:25:16 -0700526/*
527 * On a AMD dual core setup the lower bits of the APIC id distingush the cores.
528 * Assumes number of cores is a power of two.
529 */
530static void __init amd_detect_cmp(struct cpuinfo_x86 *c)
531{
532#ifdef CONFIG_SMP
Andi Kleenb41e2932005-05-20 14:27:55 -0700533 unsigned bits;
Andi Kleen3f098c22005-09-12 18:49:24 +0200534#ifdef CONFIG_NUMA
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200535 int cpu = smp_processor_id();
Andi Kleen3f098c22005-09-12 18:49:24 +0200536 int node = 0;
Ravikiran G Thirumalai60c1bc82006-03-25 16:30:04 +0100537 unsigned apicid = hard_smp_processor_id();
Andi Kleen3f098c22005-09-12 18:49:24 +0200538#endif
Andi Kleenfaee9a52006-06-26 13:56:10 +0200539 unsigned ecx = cpuid_ecx(0x80000008);
Andi Kleenb41e2932005-05-20 14:27:55 -0700540
Andi Kleenfaee9a52006-06-26 13:56:10 +0200541 c->x86_max_cores = (ecx & 0xff) + 1;
542
543 /* CPU telling us the core id bits shift? */
544 bits = (ecx >> 12) & 0xF;
545
546 /* Otherwise recompute */
547 if (bits == 0) {
548 while ((1 << bits) < c->x86_max_cores)
549 bits++;
550 }
Andi Kleenb41e2932005-05-20 14:27:55 -0700551
552 /* Low order bits define the core id (index of core in socket) */
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200553 c->cpu_core_id = c->phys_proc_id & ((1 << bits)-1);
Andi Kleenb41e2932005-05-20 14:27:55 -0700554 /* Convert the APIC ID into the socket ID */
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200555 c->phys_proc_id = phys_pkg_id(bits);
Andi Kleen63518642005-04-16 15:25:16 -0700556
557#ifdef CONFIG_NUMA
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200558 node = c->phys_proc_id;
Andi Kleen3f098c22005-09-12 18:49:24 +0200559 if (apicid_to_node[apicid] != NUMA_NO_NODE)
560 node = apicid_to_node[apicid];
561 if (!node_online(node)) {
562 /* Two possibilities here:
563 - The CPU is missing memory and no node was created.
564 In that case try picking one from a nearby CPU
565 - The APIC IDs differ from the HyperTransport node IDs
566 which the K8 northbridge parsing fills in.
567 Assume they are all increased by a constant offset,
568 but in the same order as the HT nodeids.
569 If that doesn't result in a usable node fall back to the
570 path for the previous case. */
Mike Travis92cb7612007-10-19 20:35:04 +0200571 int ht_nodeid = apicid - (cpu_data(0).phys_proc_id << bits);
Andi Kleen3f098c22005-09-12 18:49:24 +0200572 if (ht_nodeid >= 0 &&
573 apicid_to_node[ht_nodeid] != NUMA_NO_NODE)
574 node = apicid_to_node[ht_nodeid];
575 /* Pick a nearby node */
576 if (!node_online(node))
577 node = nearby_node(apicid);
578 }
Andi Kleen69d81fc2005-11-05 17:25:53 +0100579 numa_set_node(cpu, node);
Andi Kleena1586082005-05-16 21:53:21 -0700580
Rohit Sethe42f9432006-06-26 13:59:14 +0200581 printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
Andi Kleen3f098c22005-09-12 18:49:24 +0200582#endif
Andi Kleen63518642005-04-16 15:25:16 -0700583#endif
584}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585
Thomas Gleixnerfb79d222007-10-12 23:04:07 +0200586#define ENABLE_C1E_MASK 0x18000000
587#define CPUID_PROCESSOR_SIGNATURE 1
588#define CPUID_XFAM 0x0ff00000
589#define CPUID_XFAM_K8 0x00000000
590#define CPUID_XFAM_10H 0x00100000
591#define CPUID_XFAM_11H 0x00200000
592#define CPUID_XMOD 0x000f0000
593#define CPUID_XMOD_REV_F 0x00040000
594
595/* AMD systems with C1E don't have a working lAPIC timer. Check for that. */
596static __cpuinit int amd_apic_timer_broken(void)
597{
598 u32 lo, hi;
599 u32 eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
600 switch (eax & CPUID_XFAM) {
601 case CPUID_XFAM_K8:
602 if ((eax & CPUID_XMOD) < CPUID_XMOD_REV_F)
603 break;
604 case CPUID_XFAM_10H:
605 case CPUID_XFAM_11H:
606 rdmsr(MSR_K8_ENABLE_C1E, lo, hi);
607 if (lo & ENABLE_C1E_MASK)
608 return 1;
609 break;
610 default:
611 /* err on the side of caution */
612 return 1;
613 }
614 return 0;
615}
616
Magnus Dammed775042006-09-26 10:52:36 +0200617static void __cpuinit init_amd(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618{
Andi Kleen7bcd3f32006-02-03 21:51:02 +0100619 unsigned level;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620
Linus Torvaldsbc5e8fd2005-09-17 15:41:04 -0700621#ifdef CONFIG_SMP
622 unsigned long value;
623
Andi Kleen7d318d72005-09-29 22:05:55 +0200624 /*
625 * Disable TLB flush filter by setting HWCR.FFDIS on K8
626 * bit 6 of msr C001_0015
627 *
628 * Errata 63 for SH-B3 steppings
629 * Errata 122 for all steppings (F+ have it disabled by default)
630 */
631 if (c->x86 == 15) {
632 rdmsrl(MSR_K8_HWCR, value);
633 value |= 1 << 6;
634 wrmsrl(MSR_K8_HWCR, value);
635 }
Linus Torvaldsbc5e8fd2005-09-17 15:41:04 -0700636#endif
637
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 /* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
639 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
640 clear_bit(0*32+31, &c->x86_capability);
641
Andi Kleen7bcd3f32006-02-03 21:51:02 +0100642 /* On C+ stepping K8 rep microcode works well for copy/memset */
643 level = cpuid_eax(1);
644 if (c->x86 == 15 && ((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58))
645 set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability);
Andi Kleen99741fa2007-10-17 18:04:41 +0200646 if (c->x86 == 0x10 || c->x86 == 0x11)
Andi Kleen5b74e3a2007-07-21 17:09:57 +0200647 set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability);
Andi Kleen7bcd3f32006-02-03 21:51:02 +0100648
Andi Kleen18bd0572006-04-20 02:36:45 +0200649 /* Enable workaround for FXSAVE leak */
650 if (c->x86 >= 6)
651 set_bit(X86_FEATURE_FXSAVE_LEAK, &c->x86_capability);
652
Rohit Sethe42f9432006-06-26 13:59:14 +0200653 level = get_model_name(c);
654 if (!level) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 switch (c->x86) {
656 case 15:
657 /* Should distinguish Models here, but this is only
658 a fallback anyways. */
659 strcpy(c->x86_model_id, "Hammer");
660 break;
661 }
662 }
663 display_cacheinfo(c);
664
Andi Kleen130951c2006-01-11 22:42:02 +0100665 /* c->x86_power is 8000_0007 edx. Bit 8 is constant TSC */
666 if (c->x86_power & (1<<8))
667 set_bit(X86_FEATURE_CONSTANT_TSC, &c->x86_capability);
668
Andi Kleenfaee9a52006-06-26 13:56:10 +0200669 /* Multi core CPU? */
670 if (c->extended_cpuid_level >= 0x80000008)
Andi Kleen63518642005-04-16 15:25:16 -0700671 amd_detect_cmp(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672
Andi Kleen67cddd92007-07-21 17:10:03 +0200673 if (c->extended_cpuid_level >= 0x80000006 &&
674 (cpuid_edx(0x80000006) & 0xf000))
675 num_cache_leaves = 4;
676 else
677 num_cache_leaves = 3;
Andi Kleen20493362006-09-26 10:52:41 +0200678
Andi Kleen0bd8acd2007-07-22 11:12:34 +0200679 if (c->x86 == 0xf || c->x86 == 0x10 || c->x86 == 0x11)
680 set_bit(X86_FEATURE_K8, &c->x86_capability);
681
Andi Kleen61677962006-12-07 02:14:12 +0100682 /* RDTSC can be speculated around */
683 clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
Andi Kleenf039b752007-05-02 19:27:12 +0200684
685 /* Family 10 doesn't support C states in MWAIT so don't use it */
686 if (c->x86 == 0x10 && !force_mwait)
687 clear_bit(X86_FEATURE_MWAIT, &c->x86_capability);
Thomas Gleixnerfb79d222007-10-12 23:04:07 +0200688
689 if (amd_apic_timer_broken())
690 disable_apic_timer = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691}
692
Ashok Raje6982c62005-06-25 14:54:58 -0700693static void __cpuinit detect_ht(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694{
695#ifdef CONFIG_SMP
696 u32 eax, ebx, ecx, edx;
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100697 int index_msb, core_bits;
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100698
699 cpuid(1, &eax, &ebx, &ecx, &edx);
700
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100701
Rohit Sethe42f9432006-06-26 13:59:14 +0200702 if (!cpu_has(c, X86_FEATURE_HT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 return;
Rohit Sethe42f9432006-06-26 13:59:14 +0200704 if (cpu_has(c, X86_FEATURE_CMP_LEGACY))
705 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 smp_num_siblings = (ebx & 0xff0000) >> 16;
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100708
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 if (smp_num_siblings == 1) {
710 printk(KERN_INFO "CPU: Hyper-Threading is disabled\n");
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100711 } else if (smp_num_siblings > 1 ) {
712
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 if (smp_num_siblings > NR_CPUS) {
714 printk(KERN_WARNING "CPU: Unsupported number of the siblings %d", smp_num_siblings);
715 smp_num_siblings = 1;
716 return;
717 }
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100718
719 index_msb = get_count_order(smp_num_siblings);
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200720 c->phys_proc_id = phys_pkg_id(index_msb);
Andi Kleen3dd9d512005-04-16 15:25:15 -0700721
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100722 smp_num_siblings = smp_num_siblings / c->x86_max_cores;
Andi Kleen3dd9d512005-04-16 15:25:15 -0700723
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100724 index_msb = get_count_order(smp_num_siblings) ;
Andi Kleen3dd9d512005-04-16 15:25:15 -0700725
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100726 core_bits = get_count_order(c->x86_max_cores);
Andi Kleen3dd9d512005-04-16 15:25:15 -0700727
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200728 c->cpu_core_id = phys_pkg_id(index_msb) &
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100729 ((1 << core_bits) - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 }
Rohit Sethe42f9432006-06-26 13:59:14 +0200731out:
732 if ((c->x86_max_cores * smp_num_siblings) > 1) {
733 printk(KERN_INFO "CPU: Physical Processor ID: %d\n", c->phys_proc_id);
734 printk(KERN_INFO "CPU: Processor Core ID: %d\n", c->cpu_core_id);
735 }
736
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737#endif
738}
739
Andi Kleen3dd9d512005-04-16 15:25:15 -0700740/*
741 * find out the number of processor cores on the die
742 */
Ashok Raje6982c62005-06-25 14:54:58 -0700743static int __cpuinit intel_num_cpu_cores(struct cpuinfo_x86 *c)
Andi Kleen3dd9d512005-04-16 15:25:15 -0700744{
Rohit Seth2bbc4192006-06-26 13:58:02 +0200745 unsigned int eax, t;
Andi Kleen3dd9d512005-04-16 15:25:15 -0700746
747 if (c->cpuid_level < 4)
748 return 1;
749
Rohit Seth2bbc4192006-06-26 13:58:02 +0200750 cpuid_count(4, 0, &eax, &t, &t, &t);
Andi Kleen3dd9d512005-04-16 15:25:15 -0700751
752 if (eax & 0x1f)
753 return ((eax >> 26) + 1);
754 else
755 return 1;
756}
757
Andi Kleendf0cc262005-09-12 18:49:24 +0200758static void srat_detect_node(void)
759{
760#ifdef CONFIG_NUMA
Ravikiran G Thirumalaiddea7be2005-10-03 10:36:28 -0700761 unsigned node;
Andi Kleendf0cc262005-09-12 18:49:24 +0200762 int cpu = smp_processor_id();
Rohit Sethe42f9432006-06-26 13:59:14 +0200763 int apicid = hard_smp_processor_id();
Andi Kleendf0cc262005-09-12 18:49:24 +0200764
765 /* Don't do the funky fallback heuristics the AMD version employs
766 for now. */
Rohit Sethe42f9432006-06-26 13:59:14 +0200767 node = apicid_to_node[apicid];
Andi Kleendf0cc262005-09-12 18:49:24 +0200768 if (node == NUMA_NO_NODE)
Daniel Yeisley0d015322006-05-30 22:47:57 +0200769 node = first_node(node_online_map);
Andi Kleen69d81fc2005-11-05 17:25:53 +0100770 numa_set_node(cpu, node);
Andi Kleendf0cc262005-09-12 18:49:24 +0200771
Andi Kleenc31fbb12006-09-26 10:52:33 +0200772 printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
Andi Kleendf0cc262005-09-12 18:49:24 +0200773#endif
774}
775
Ashok Raje6982c62005-06-25 14:54:58 -0700776static void __cpuinit init_intel(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777{
778 /* Cache sizes */
779 unsigned n;
780
781 init_intel_cacheinfo(c);
Venkatesh Pallipadi0080e662006-06-26 13:59:59 +0200782 if (c->cpuid_level > 9 ) {
783 unsigned eax = cpuid_eax(10);
784 /* Check for version and the number of counters */
785 if ((eax & 0xff) && (((eax>>8) & 0xff) > 1))
786 set_bit(X86_FEATURE_ARCH_PERFMON, &c->x86_capability);
787 }
788
Stephane Eranian36b2a8d2006-12-07 02:14:01 +0100789 if (cpu_has_ds) {
790 unsigned int l1, l2;
791 rdmsr(MSR_IA32_MISC_ENABLE, l1, l2);
Stephane Eranianee58fad2006-12-07 02:14:11 +0100792 if (!(l1 & (1<<11)))
793 set_bit(X86_FEATURE_BTS, c->x86_capability);
Stephane Eranian36b2a8d2006-12-07 02:14:01 +0100794 if (!(l1 & (1<<12)))
795 set_bit(X86_FEATURE_PEBS, c->x86_capability);
796 }
797
Andi Kleenebfcaa92005-04-16 15:25:18 -0700798 n = c->extended_cpuid_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 if (n >= 0x80000008) {
800 unsigned eax = cpuid_eax(0x80000008);
801 c->x86_virt_bits = (eax >> 8) & 0xff;
802 c->x86_phys_bits = eax & 0xff;
Shaohua Liaf9c1422005-11-05 17:25:54 +0100803 /* CPUID workaround for Intel 0F34 CPU */
804 if (c->x86_vendor == X86_VENDOR_INTEL &&
805 c->x86 == 0xF && c->x86_model == 0x3 &&
806 c->x86_mask == 0x4)
807 c->x86_phys_bits = 36;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 }
809
810 if (c->x86 == 15)
811 c->x86_cache_alignment = c->x86_clflush_size * 2;
Andi Kleen39b3a792006-01-11 22:42:45 +0100812 if ((c->x86 == 0xf && c->x86_model >= 0x03) ||
813 (c->x86 == 0x6 && c->x86_model >= 0x0e))
Andi Kleenc29601e2005-04-16 15:25:05 -0700814 set_bit(X86_FEATURE_CONSTANT_TSC, &c->x86_capability);
Andi Kleen27fbe5b2006-09-26 10:52:41 +0200815 if (c->x86 == 6)
816 set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability);
Arjan van de Venf3d73702006-12-07 02:14:12 +0100817 if (c->x86 == 15)
818 set_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
819 else
820 clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100821 c->x86_max_cores = intel_num_cpu_cores(c);
Andi Kleendf0cc262005-09-12 18:49:24 +0200822
823 srat_detect_node();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824}
825
Adrian Bunk672289e2005-09-10 00:27:21 -0700826static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827{
828 char *v = c->x86_vendor_id;
829
830 if (!strcmp(v, "AuthenticAMD"))
831 c->x86_vendor = X86_VENDOR_AMD;
832 else if (!strcmp(v, "GenuineIntel"))
833 c->x86_vendor = X86_VENDOR_INTEL;
834 else
835 c->x86_vendor = X86_VENDOR_UNKNOWN;
836}
837
838struct cpu_model_info {
839 int vendor;
840 int family;
841 char *model_names[16];
842};
843
844/* Do some early cpuid on the boot CPU to get some parameter that are
845 needed before check_bugs. Everything advanced is in identify_cpu
846 below. */
Ashok Raje6982c62005-06-25 14:54:58 -0700847void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848{
849 u32 tfms;
850
851 c->loops_per_jiffy = loops_per_jiffy;
852 c->x86_cache_size = -1;
853 c->x86_vendor = X86_VENDOR_UNKNOWN;
854 c->x86_model = c->x86_mask = 0; /* So far unknown... */
855 c->x86_vendor_id[0] = '\0'; /* Unset */
856 c->x86_model_id[0] = '\0'; /* Unset */
857 c->x86_clflush_size = 64;
858 c->x86_cache_alignment = c->x86_clflush_size;
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100859 c->x86_max_cores = 1;
Andi Kleenebfcaa92005-04-16 15:25:18 -0700860 c->extended_cpuid_level = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 memset(&c->x86_capability, 0, sizeof c->x86_capability);
862
863 /* Get vendor name */
864 cpuid(0x00000000, (unsigned int *)&c->cpuid_level,
865 (unsigned int *)&c->x86_vendor_id[0],
866 (unsigned int *)&c->x86_vendor_id[8],
867 (unsigned int *)&c->x86_vendor_id[4]);
868
869 get_cpu_vendor(c);
870
871 /* Initialize the standard set of capabilities */
872 /* Note that the vendor-specific code below might override */
873
874 /* Intel-defined flags: level 0x00000001 */
875 if (c->cpuid_level >= 0x00000001) {
876 __u32 misc;
877 cpuid(0x00000001, &tfms, &misc, &c->x86_capability[4],
878 &c->x86_capability[0]);
879 c->x86 = (tfms >> 8) & 0xf;
880 c->x86_model = (tfms >> 4) & 0xf;
881 c->x86_mask = tfms & 0xf;
Suresh Siddhaf5f786d2005-11-05 17:25:53 +0100882 if (c->x86 == 0xf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 c->x86 += (tfms >> 20) & 0xff;
Suresh Siddhaf5f786d2005-11-05 17:25:53 +0100884 if (c->x86 >= 0x6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 c->x86_model += ((tfms >> 16) & 0xF) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 if (c->x86_capability[0] & (1<<19))
887 c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 } else {
889 /* Have CPUID level 0 only - unheard of */
890 c->x86 = 4;
891 }
Andi Kleena1586082005-05-16 21:53:21 -0700892
893#ifdef CONFIG_SMP
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200894 c->phys_proc_id = (cpuid_ebx(1) >> 24) & 0xff;
Mike Travis92cb7612007-10-19 20:35:04 +0200895 c->cpu_index = 0;
Andi Kleena1586082005-05-16 21:53:21 -0700896#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897}
898
899/*
900 * This does the hard work of actually picking apart the CPU stuff...
901 */
Ashok Raje6982c62005-06-25 14:54:58 -0700902void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903{
904 int i;
905 u32 xlvl;
906
907 early_identify_cpu(c);
908
909 /* AMD-defined flags: level 0x80000001 */
910 xlvl = cpuid_eax(0x80000000);
Andi Kleenebfcaa92005-04-16 15:25:18 -0700911 c->extended_cpuid_level = xlvl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 if ((xlvl & 0xffff0000) == 0x80000000) {
913 if (xlvl >= 0x80000001) {
914 c->x86_capability[1] = cpuid_edx(0x80000001);
H. Peter Anvin5b7abc62005-05-01 08:58:49 -0700915 c->x86_capability[6] = cpuid_ecx(0x80000001);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 }
917 if (xlvl >= 0x80000004)
918 get_model_name(c); /* Default name */
919 }
920
921 /* Transmeta-defined flags: level 0x80860001 */
922 xlvl = cpuid_eax(0x80860000);
923 if ((xlvl & 0xffff0000) == 0x80860000) {
924 /* Don't set x86_cpuid_level here for now to not confuse. */
925 if (xlvl >= 0x80860001)
926 c->x86_capability[2] = cpuid_edx(0x80860001);
927 }
928
Venki Pallipadi1d679532007-07-11 12:18:32 -0700929 init_scattered_cpuid_features(c);
930
Siddha, Suresh B1e9f28f2006-03-27 01:15:22 -0800931 c->apicid = phys_pkg_id(0);
932
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 /*
934 * Vendor-specific initialization. In this section we
935 * canonicalize the feature flags, meaning if there are
936 * features a certain CPU supports which CPUID doesn't
937 * tell us, CPUID claiming incorrect flags, or other bugs,
938 * we handle them here.
939 *
940 * At the end of this section, c->x86_capability better
941 * indicate the features this CPU genuinely supports!
942 */
943 switch (c->x86_vendor) {
944 case X86_VENDOR_AMD:
945 init_amd(c);
946 break;
947
948 case X86_VENDOR_INTEL:
949 init_intel(c);
950 break;
951
952 case X86_VENDOR_UNKNOWN:
953 default:
954 display_cacheinfo(c);
955 break;
956 }
957
958 select_idle_routine(c);
959 detect_ht(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
961 /*
962 * On SMP, boot_cpu_data holds the common feature set between
963 * all CPUs; so make sure that we indicate which features are
964 * common between the CPUs. The first time this routine gets
965 * executed, c == &boot_cpu_data.
966 */
967 if (c != &boot_cpu_data) {
968 /* AND the already accumulated flags with these */
969 for (i = 0 ; i < NCAPINTS ; i++)
970 boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
971 }
972
973#ifdef CONFIG_X86_MCE
974 mcheck_init(c);
975#endif
Andi Kleen8bd99482007-05-11 11:23:20 +0200976 if (c != &boot_cpu_data)
Shaohua Li3b520b22005-07-07 17:56:38 -0700977 mtrr_ap_init();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978#ifdef CONFIG_NUMA
Andi Kleen3019e8e2005-07-28 21:15:28 -0700979 numa_add_cpu(smp_processor_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980#endif
981}
982
983
Ashok Raje6982c62005-06-25 14:54:58 -0700984void __cpuinit print_cpu_info(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985{
986 if (c->x86_model_id[0])
987 printk("%s", c->x86_model_id);
988
989 if (c->x86_mask || c->cpuid_level >= 0)
990 printk(" stepping %02x\n", c->x86_mask);
991 else
992 printk("\n");
993}
994
995/*
996 * Get CPU information for use by the procfs.
997 */
998
999static int show_cpuinfo(struct seq_file *m, void *v)
1000{
1001 struct cpuinfo_x86 *c = v;
Mike Travis92cb7612007-10-19 20:35:04 +02001002 int cpu = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003
1004 /*
1005 * These flag bits must match the definitions in <asm/cpufeature.h>.
1006 * NULL means this bit is undefined or reserved; either way it doesn't
1007 * have meaning as far as Linux is concerned. Note that it's important
1008 * to realize there is a difference between this table and CPUID -- if
1009 * applications want to get the raw CPUID data, they should access
1010 * /dev/cpu/<cpu_nr>/cpuid instead.
1011 */
Jan Beulich121d7bf2007-10-17 18:04:37 +02001012 static const char *const x86_cap_flags[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 /* Intel-defined */
1014 "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
1015 "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
1016 "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
H. Peter Anvinec481532007-07-11 12:18:29 -07001017 "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018
1019 /* AMD-defined */
Zwane Mwaikambo3c3b73b2005-05-01 08:58:51 -07001020 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
1022 NULL, NULL, NULL, NULL, "nx", NULL, "mmxext", NULL,
Andi Kleenf790cd32007-02-13 13:26:25 +01001023 NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm",
1024 "3dnowext", "3dnow",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025
1026 /* Transmeta-defined */
1027 "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
1028 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1029 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1030 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1031
1032 /* Other (Linux-defined) */
H. Peter Anvinec481532007-07-11 12:18:29 -07001033 "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr",
1034 NULL, NULL, NULL, NULL,
1035 "constant_tsc", "up", NULL, "arch_perfmon",
1036 "pebs", "bts", NULL, "sync_rdtsc",
1037 "rep_good", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1039
1040 /* Intel-defined (#2) */
Andi Kleen9d95dd82006-03-25 16:31:22 +01001041 "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est",
Dave Jonesdcf10302006-09-26 10:52:42 +02001042 "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
H. Peter Anvine1054b32007-10-26 14:09:09 -07001043 NULL, NULL, "dca", "sse4_1", "sse4_2", NULL, NULL, "popcnt",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1045
H. Peter Anvin5b7abc62005-05-01 08:58:49 -07001046 /* VIA/Cyrix/Centaur-defined */
1047 NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
H. Peter Anvinec481532007-07-11 12:18:29 -07001048 "ace2", "ace2_en", "phe", "phe_en", "pmm", "pmm_en", NULL, NULL,
H. Peter Anvin5b7abc62005-05-01 08:58:49 -07001049 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1050 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1051
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 /* AMD-defined (#2) */
H. Peter Anvine1054b32007-10-26 14:09:09 -07001053 "lahf_lm", "cmp_legacy", "svm", "extapic",
1054 "cr8_legacy", "abm", "sse4a", "misalignsse",
1055 "3dnowprefetch", "osvw", "ibs", "sse5",
1056 "skinit", "wdt", NULL, NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
H. Peter Anvin5b7abc62005-05-01 08:58:49 -07001058 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Venki Pallipadi1d679532007-07-11 12:18:32 -07001059
1060 /* Auxiliary (Linux-defined) */
1061 "ida", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1062 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1063 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1064 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 };
Jan Beulich121d7bf2007-10-17 18:04:37 +02001066 static const char *const x86_power_flags[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 "ts", /* temperature sensor */
1068 "fid", /* frequency id control */
1069 "vid", /* voltage id control */
1070 "ttp", /* thermal trip */
1071 "tm",
Andi Kleen3f98bc42006-01-11 22:42:51 +01001072 "stc",
Andi Kleenf790cd32007-02-13 13:26:25 +01001073 "100mhzsteps",
1074 "hwpstate",
Joerg Roedeld8243952007-05-02 19:27:09 +02001075 "", /* tsc invariant mapped to constant_tsc */
1076 /* nothing */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 };
1078
1079
1080#ifdef CONFIG_SMP
Mike Travis92cb7612007-10-19 20:35:04 +02001081 if (!cpu_online(c->cpu_index))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 return 0;
Mike Travis92cb7612007-10-19 20:35:04 +02001083 cpu = c->cpu_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084#endif
1085
1086 seq_printf(m,"processor\t: %u\n"
1087 "vendor_id\t: %s\n"
1088 "cpu family\t: %d\n"
1089 "model\t\t: %d\n"
1090 "model name\t: %s\n",
Mike Travis92cb7612007-10-19 20:35:04 +02001091 (unsigned)cpu,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown",
1093 c->x86,
1094 (int)c->x86_model,
1095 c->x86_model_id[0] ? c->x86_model_id : "unknown");
1096
1097 if (c->x86_mask || c->cpuid_level >= 0)
1098 seq_printf(m, "stepping\t: %d\n", c->x86_mask);
1099 else
1100 seq_printf(m, "stepping\t: unknown\n");
1101
1102 if (cpu_has(c,X86_FEATURE_TSC)) {
Mike Travis92cb7612007-10-19 20:35:04 +02001103 unsigned int freq = cpufreq_quick_get((unsigned)cpu);
Venkatesh Pallipadi95235ca2005-12-02 10:43:20 -08001104 if (!freq)
1105 freq = cpu_khz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 seq_printf(m, "cpu MHz\t\t: %u.%03u\n",
Venkatesh Pallipadi95235ca2005-12-02 10:43:20 -08001107 freq / 1000, (freq % 1000));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 }
1109
1110 /* Cache size */
1111 if (c->x86_cache_size >= 0)
1112 seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size);
1113
1114#ifdef CONFIG_SMP
Siddha, Suresh B94605ef2005-11-05 17:25:54 +01001115 if (smp_num_siblings * c->x86_max_cores > 1) {
Rohit Sethf3fa8eb2006-06-26 13:58:17 +02001116 seq_printf(m, "physical id\t: %d\n", c->phys_proc_id);
Mike Travis08357612007-10-16 01:24:04 -07001117 seq_printf(m, "siblings\t: %d\n",
1118 cpus_weight(per_cpu(cpu_core_map, cpu)));
Rohit Sethf3fa8eb2006-06-26 13:58:17 +02001119 seq_printf(m, "core id\t\t: %d\n", c->cpu_core_id);
Siddha, Suresh B94605ef2005-11-05 17:25:54 +01001120 seq_printf(m, "cpu cores\t: %d\n", c->booted_cores);
Andi Kleendb468682005-04-16 15:24:51 -07001121 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122#endif
1123
1124 seq_printf(m,
1125 "fpu\t\t: yes\n"
1126 "fpu_exception\t: yes\n"
1127 "cpuid level\t: %d\n"
1128 "wp\t\t: yes\n"
1129 "flags\t\t:",
1130 c->cpuid_level);
1131
1132 {
1133 int i;
1134 for ( i = 0 ; i < 32*NCAPINTS ; i++ )
Akinobu Mita3d1712c2006-03-24 03:15:11 -08001135 if (cpu_has(c, i) && x86_cap_flags[i] != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 seq_printf(m, " %s", x86_cap_flags[i]);
1137 }
1138
1139 seq_printf(m, "\nbogomips\t: %lu.%02lu\n",
1140 c->loops_per_jiffy/(500000/HZ),
1141 (c->loops_per_jiffy/(5000/HZ)) % 100);
1142
1143 if (c->x86_tlbsize > 0)
1144 seq_printf(m, "TLB size\t: %d 4K pages\n", c->x86_tlbsize);
1145 seq_printf(m, "clflush size\t: %d\n", c->x86_clflush_size);
1146 seq_printf(m, "cache_alignment\t: %d\n", c->x86_cache_alignment);
1147
1148 seq_printf(m, "address sizes\t: %u bits physical, %u bits virtual\n",
1149 c->x86_phys_bits, c->x86_virt_bits);
1150
1151 seq_printf(m, "power management:");
1152 {
1153 unsigned i;
1154 for (i = 0; i < 32; i++)
1155 if (c->x86_power & (1 << i)) {
Andi Kleen3f98bc42006-01-11 22:42:51 +01001156 if (i < ARRAY_SIZE(x86_power_flags) &&
1157 x86_power_flags[i])
1158 seq_printf(m, "%s%s",
1159 x86_power_flags[i][0]?" ":"",
1160 x86_power_flags[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 else
1162 seq_printf(m, " [%d]", i);
1163 }
1164 }
Andi Kleen3dd9d512005-04-16 15:25:15 -07001165
Siddha, Suresh Bd31ddaa2005-04-16 15:25:20 -07001166 seq_printf(m, "\n\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 return 0;
1169}
1170
1171static void *c_start(struct seq_file *m, loff_t *pos)
1172{
Mike Travis92cb7612007-10-19 20:35:04 +02001173 if (*pos == 0) /* just in case, cpu 0 is not the first */
1174 *pos = first_cpu(cpu_possible_map);
1175 if ((*pos) < NR_CPUS && cpu_possible(*pos))
1176 return &cpu_data(*pos);
1177 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178}
1179
1180static void *c_next(struct seq_file *m, void *v, loff_t *pos)
1181{
Mike Travis92cb7612007-10-19 20:35:04 +02001182 *pos = next_cpu(*pos, cpu_possible_map);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 return c_start(m, pos);
1184}
1185
1186static void c_stop(struct seq_file *m, void *v)
1187{
1188}
1189
1190struct seq_operations cpuinfo_op = {
1191 .start =c_start,
1192 .next = c_next,
1193 .stop = c_stop,
1194 .show = show_cpuinfo,
1195};