blob: 30d94d1d5f5f38e222b8ac7e4a869a6e0ee91b01 [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;
Andi Kleena1586082005-05-16 21:53:21 -0700895#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896}
897
898/*
899 * This does the hard work of actually picking apart the CPU stuff...
900 */
Ashok Raje6982c62005-06-25 14:54:58 -0700901void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902{
903 int i;
904 u32 xlvl;
905
906 early_identify_cpu(c);
907
908 /* AMD-defined flags: level 0x80000001 */
909 xlvl = cpuid_eax(0x80000000);
Andi Kleenebfcaa92005-04-16 15:25:18 -0700910 c->extended_cpuid_level = xlvl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 if ((xlvl & 0xffff0000) == 0x80000000) {
912 if (xlvl >= 0x80000001) {
913 c->x86_capability[1] = cpuid_edx(0x80000001);
H. Peter Anvin5b7abc62005-05-01 08:58:49 -0700914 c->x86_capability[6] = cpuid_ecx(0x80000001);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 }
916 if (xlvl >= 0x80000004)
917 get_model_name(c); /* Default name */
918 }
919
920 /* Transmeta-defined flags: level 0x80860001 */
921 xlvl = cpuid_eax(0x80860000);
922 if ((xlvl & 0xffff0000) == 0x80860000) {
923 /* Don't set x86_cpuid_level here for now to not confuse. */
924 if (xlvl >= 0x80860001)
925 c->x86_capability[2] = cpuid_edx(0x80860001);
926 }
927
Venki Pallipadi1d679532007-07-11 12:18:32 -0700928 init_scattered_cpuid_features(c);
929
Siddha, Suresh B1e9f28f2006-03-27 01:15:22 -0800930 c->apicid = phys_pkg_id(0);
931
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 /*
933 * Vendor-specific initialization. In this section we
934 * canonicalize the feature flags, meaning if there are
935 * features a certain CPU supports which CPUID doesn't
936 * tell us, CPUID claiming incorrect flags, or other bugs,
937 * we handle them here.
938 *
939 * At the end of this section, c->x86_capability better
940 * indicate the features this CPU genuinely supports!
941 */
942 switch (c->x86_vendor) {
943 case X86_VENDOR_AMD:
944 init_amd(c);
945 break;
946
947 case X86_VENDOR_INTEL:
948 init_intel(c);
949 break;
950
951 case X86_VENDOR_UNKNOWN:
952 default:
953 display_cacheinfo(c);
954 break;
955 }
956
957 select_idle_routine(c);
958 detect_ht(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
960 /*
961 * On SMP, boot_cpu_data holds the common feature set between
962 * all CPUs; so make sure that we indicate which features are
963 * common between the CPUs. The first time this routine gets
964 * executed, c == &boot_cpu_data.
965 */
966 if (c != &boot_cpu_data) {
967 /* AND the already accumulated flags with these */
968 for (i = 0 ; i < NCAPINTS ; i++)
969 boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
970 }
971
972#ifdef CONFIG_X86_MCE
973 mcheck_init(c);
974#endif
Andi Kleen8bd99482007-05-11 11:23:20 +0200975 if (c != &boot_cpu_data)
Shaohua Li3b520b22005-07-07 17:56:38 -0700976 mtrr_ap_init();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977#ifdef CONFIG_NUMA
Andi Kleen3019e8e2005-07-28 21:15:28 -0700978 numa_add_cpu(smp_processor_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979#endif
980}
981
982
Ashok Raje6982c62005-06-25 14:54:58 -0700983void __cpuinit print_cpu_info(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984{
985 if (c->x86_model_id[0])
986 printk("%s", c->x86_model_id);
987
988 if (c->x86_mask || c->cpuid_level >= 0)
989 printk(" stepping %02x\n", c->x86_mask);
990 else
991 printk("\n");
992}
993
994/*
995 * Get CPU information for use by the procfs.
996 */
997
998static int show_cpuinfo(struct seq_file *m, void *v)
999{
1000 struct cpuinfo_x86 *c = v;
Mike Travis92cb7612007-10-19 20:35:04 +02001001 int cpu = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002
1003 /*
1004 * These flag bits must match the definitions in <asm/cpufeature.h>.
1005 * NULL means this bit is undefined or reserved; either way it doesn't
1006 * have meaning as far as Linux is concerned. Note that it's important
1007 * to realize there is a difference between this table and CPUID -- if
1008 * applications want to get the raw CPUID data, they should access
1009 * /dev/cpu/<cpu_nr>/cpuid instead.
1010 */
Jan Beulich121d7bf2007-10-17 18:04:37 +02001011 static const char *const x86_cap_flags[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 /* Intel-defined */
1013 "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
1014 "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
1015 "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
H. Peter Anvinec481532007-07-11 12:18:29 -07001016 "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017
1018 /* AMD-defined */
Zwane Mwaikambo3c3b73b2005-05-01 08:58:51 -07001019 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
1021 NULL, NULL, NULL, NULL, "nx", NULL, "mmxext", NULL,
Andi Kleenf790cd32007-02-13 13:26:25 +01001022 NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm",
1023 "3dnowext", "3dnow",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024
1025 /* Transmeta-defined */
1026 "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
1027 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1028 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1029 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1030
1031 /* Other (Linux-defined) */
H. Peter Anvinec481532007-07-11 12:18:29 -07001032 "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr",
1033 NULL, NULL, NULL, NULL,
1034 "constant_tsc", "up", NULL, "arch_perfmon",
1035 "pebs", "bts", NULL, "sync_rdtsc",
1036 "rep_good", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1038
1039 /* Intel-defined (#2) */
Andi Kleen9d95dd82006-03-25 16:31:22 +01001040 "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est",
Dave Jonesdcf10302006-09-26 10:52:42 +02001041 "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
H. Peter Anvine1054b32007-10-26 14:09:09 -07001042 NULL, NULL, "dca", "sse4_1", "sse4_2", NULL, NULL, "popcnt",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1044
H. Peter Anvin5b7abc62005-05-01 08:58:49 -07001045 /* VIA/Cyrix/Centaur-defined */
1046 NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
H. Peter Anvinec481532007-07-11 12:18:29 -07001047 "ace2", "ace2_en", "phe", "phe_en", "pmm", "pmm_en", NULL, NULL,
H. Peter Anvin5b7abc62005-05-01 08:58:49 -07001048 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1049 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1050
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 /* AMD-defined (#2) */
H. Peter Anvine1054b32007-10-26 14:09:09 -07001052 "lahf_lm", "cmp_legacy", "svm", "extapic",
1053 "cr8_legacy", "abm", "sse4a", "misalignsse",
1054 "3dnowprefetch", "osvw", "ibs", "sse5",
1055 "skinit", "wdt", NULL, NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
H. Peter Anvin5b7abc62005-05-01 08:58:49 -07001057 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Venki Pallipadi1d679532007-07-11 12:18:32 -07001058
1059 /* Auxiliary (Linux-defined) */
1060 "ida", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1061 NULL, 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,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 };
Jan Beulich121d7bf2007-10-17 18:04:37 +02001065 static const char *const x86_power_flags[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 "ts", /* temperature sensor */
1067 "fid", /* frequency id control */
1068 "vid", /* voltage id control */
1069 "ttp", /* thermal trip */
1070 "tm",
Andi Kleen3f98bc42006-01-11 22:42:51 +01001071 "stc",
Andi Kleenf790cd32007-02-13 13:26:25 +01001072 "100mhzsteps",
1073 "hwpstate",
Joerg Roedeld8243952007-05-02 19:27:09 +02001074 "", /* tsc invariant mapped to constant_tsc */
1075 /* nothing */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 };
1077
1078
1079#ifdef CONFIG_SMP
Mike Travis92cb7612007-10-19 20:35:04 +02001080 cpu = c->cpu_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081#endif
1082
1083 seq_printf(m,"processor\t: %u\n"
1084 "vendor_id\t: %s\n"
1085 "cpu family\t: %d\n"
1086 "model\t\t: %d\n"
1087 "model name\t: %s\n",
Mike Travis92cb7612007-10-19 20:35:04 +02001088 (unsigned)cpu,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown",
1090 c->x86,
1091 (int)c->x86_model,
1092 c->x86_model_id[0] ? c->x86_model_id : "unknown");
1093
1094 if (c->x86_mask || c->cpuid_level >= 0)
1095 seq_printf(m, "stepping\t: %d\n", c->x86_mask);
1096 else
1097 seq_printf(m, "stepping\t: unknown\n");
1098
1099 if (cpu_has(c,X86_FEATURE_TSC)) {
Mike Travis92cb7612007-10-19 20:35:04 +02001100 unsigned int freq = cpufreq_quick_get((unsigned)cpu);
Venkatesh Pallipadi95235ca2005-12-02 10:43:20 -08001101 if (!freq)
1102 freq = cpu_khz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 seq_printf(m, "cpu MHz\t\t: %u.%03u\n",
Venkatesh Pallipadi95235ca2005-12-02 10:43:20 -08001104 freq / 1000, (freq % 1000));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 }
1106
1107 /* Cache size */
1108 if (c->x86_cache_size >= 0)
1109 seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size);
1110
1111#ifdef CONFIG_SMP
Siddha, Suresh B94605ef2005-11-05 17:25:54 +01001112 if (smp_num_siblings * c->x86_max_cores > 1) {
Rohit Sethf3fa8eb2006-06-26 13:58:17 +02001113 seq_printf(m, "physical id\t: %d\n", c->phys_proc_id);
Mike Travis08357612007-10-16 01:24:04 -07001114 seq_printf(m, "siblings\t: %d\n",
1115 cpus_weight(per_cpu(cpu_core_map, cpu)));
Rohit Sethf3fa8eb2006-06-26 13:58:17 +02001116 seq_printf(m, "core id\t\t: %d\n", c->cpu_core_id);
Siddha, Suresh B94605ef2005-11-05 17:25:54 +01001117 seq_printf(m, "cpu cores\t: %d\n", c->booted_cores);
Andi Kleendb468682005-04-16 15:24:51 -07001118 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119#endif
1120
1121 seq_printf(m,
1122 "fpu\t\t: yes\n"
1123 "fpu_exception\t: yes\n"
1124 "cpuid level\t: %d\n"
1125 "wp\t\t: yes\n"
1126 "flags\t\t:",
1127 c->cpuid_level);
1128
1129 {
1130 int i;
1131 for ( i = 0 ; i < 32*NCAPINTS ; i++ )
Akinobu Mita3d1712c2006-03-24 03:15:11 -08001132 if (cpu_has(c, i) && x86_cap_flags[i] != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 seq_printf(m, " %s", x86_cap_flags[i]);
1134 }
1135
1136 seq_printf(m, "\nbogomips\t: %lu.%02lu\n",
1137 c->loops_per_jiffy/(500000/HZ),
1138 (c->loops_per_jiffy/(5000/HZ)) % 100);
1139
1140 if (c->x86_tlbsize > 0)
1141 seq_printf(m, "TLB size\t: %d 4K pages\n", c->x86_tlbsize);
1142 seq_printf(m, "clflush size\t: %d\n", c->x86_clflush_size);
1143 seq_printf(m, "cache_alignment\t: %d\n", c->x86_cache_alignment);
1144
1145 seq_printf(m, "address sizes\t: %u bits physical, %u bits virtual\n",
1146 c->x86_phys_bits, c->x86_virt_bits);
1147
1148 seq_printf(m, "power management:");
1149 {
1150 unsigned i;
1151 for (i = 0; i < 32; i++)
1152 if (c->x86_power & (1 << i)) {
Andi Kleen3f98bc42006-01-11 22:42:51 +01001153 if (i < ARRAY_SIZE(x86_power_flags) &&
1154 x86_power_flags[i])
1155 seq_printf(m, "%s%s",
1156 x86_power_flags[i][0]?" ":"",
1157 x86_power_flags[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 else
1159 seq_printf(m, " [%d]", i);
1160 }
1161 }
Andi Kleen3dd9d512005-04-16 15:25:15 -07001162
Siddha, Suresh Bd31ddaa2005-04-16 15:25:20 -07001163 seq_printf(m, "\n\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 return 0;
1166}
1167
1168static void *c_start(struct seq_file *m, loff_t *pos)
1169{
Mike Travis92cb7612007-10-19 20:35:04 +02001170 if (*pos == 0) /* just in case, cpu 0 is not the first */
Andreas Herrmannc0c52d22007-11-01 19:32:17 +01001171 *pos = first_cpu(cpu_online_map);
1172 if ((*pos) < NR_CPUS && cpu_online(*pos))
Mike Travis92cb7612007-10-19 20:35:04 +02001173 return &cpu_data(*pos);
1174 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175}
1176
1177static void *c_next(struct seq_file *m, void *v, loff_t *pos)
1178{
Andreas Herrmannc0c52d22007-11-01 19:32:17 +01001179 *pos = next_cpu(*pos, cpu_online_map);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 return c_start(m, pos);
1181}
1182
1183static void c_stop(struct seq_file *m, void *v)
1184{
1185}
1186
1187struct seq_operations cpuinfo_op = {
1188 .start =c_start,
1189 .next = c_next,
1190 .stop = c_stop,
1191 .show = show_cpuinfo,
1192};