blob: cdcba69752263678c1d5337c5a8d75a000f30be7 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
62/*
63 * Machine setup..
64 */
65
Ravikiran G Thirumalai6c231b72005-09-06 15:17:45 -070066struct cpuinfo_x86 boot_cpu_data __read_mostly;
Andi Kleen2ee60e172006-06-26 13:59:44 +020067EXPORT_SYMBOL(boot_cpu_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69unsigned long mmu_cr4_features;
70
Linus Torvalds1da177e2005-04-16 15:20:36 -070071/* Boot loader ID as an integer, for the benefit of proc_dointvec */
72int bootloader_type;
73
74unsigned long saved_video_mode;
75
Andi Kleenf039b752007-05-02 19:27:12 +020076int force_mwait __cpuinitdata;
77
Andi Kleenf2d3efe2006-03-25 16:30:22 +010078/*
79 * Early DMI memory
80 */
81int dmi_alloc_index;
82char dmi_alloc_data[DMI_MAX_DATA];
83
Linus Torvalds1da177e2005-04-16 15:20:36 -070084/*
85 * Setup options
86 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070087struct screen_info screen_info;
Andi Kleen2ee60e172006-06-26 13:59:44 +020088EXPORT_SYMBOL(screen_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089struct sys_desc_table_struct {
90 unsigned short length;
91 unsigned char table[0];
92};
93
94struct edid_info edid_info;
Antonino A. Daplasba707102006-06-26 00:26:37 -070095EXPORT_SYMBOL_GPL(edid_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
97extern int root_mountflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
Alon Bar-Levadf48852007-02-12 00:54:25 -080099char __initdata command_line[COMMAND_LINE_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
101struct resource standard_io_resources[] = {
102 { .name = "dma1", .start = 0x00, .end = 0x1f,
103 .flags = IORESOURCE_BUSY | IORESOURCE_IO },
104 { .name = "pic1", .start = 0x20, .end = 0x21,
105 .flags = IORESOURCE_BUSY | IORESOURCE_IO },
106 { .name = "timer0", .start = 0x40, .end = 0x43,
107 .flags = IORESOURCE_BUSY | IORESOURCE_IO },
108 { .name = "timer1", .start = 0x50, .end = 0x53,
109 .flags = IORESOURCE_BUSY | IORESOURCE_IO },
110 { .name = "keyboard", .start = 0x60, .end = 0x6f,
111 .flags = IORESOURCE_BUSY | IORESOURCE_IO },
112 { .name = "dma page reg", .start = 0x80, .end = 0x8f,
113 .flags = IORESOURCE_BUSY | IORESOURCE_IO },
114 { .name = "pic2", .start = 0xa0, .end = 0xa1,
115 .flags = IORESOURCE_BUSY | IORESOURCE_IO },
116 { .name = "dma2", .start = 0xc0, .end = 0xdf,
117 .flags = IORESOURCE_BUSY | IORESOURCE_IO },
118 { .name = "fpu", .start = 0xf0, .end = 0xff,
119 .flags = IORESOURCE_BUSY | IORESOURCE_IO }
120};
121
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122#define IORESOURCE_RAM (IORESOURCE_BUSY | IORESOURCE_MEM)
123
124struct resource data_resource = {
125 .name = "Kernel data",
126 .start = 0,
127 .end = 0,
128 .flags = IORESOURCE_RAM,
129};
130struct resource code_resource = {
131 .name = "Kernel code",
132 .start = 0,
133 .end = 0,
134 .flags = IORESOURCE_RAM,
135};
136
Vivek Goyalaac04b32006-01-09 20:51:47 -0800137#ifdef CONFIG_PROC_VMCORE
Andi Kleen2c8c0e62006-09-26 10:52:32 +0200138/* elfcorehdr= specifies the location of elf core header
139 * stored by the crashed kernel. This option will be passed
140 * by kexec loader to the capture kernel.
141 */
142static int __init setup_elfcorehdr(char *arg)
143{
144 char *end;
145 if (!arg)
146 return -EINVAL;
147 elfcorehdr_addr = memparse(arg, &end);
148 return end > arg ? 0 : -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149}
Andi Kleen2c8c0e62006-09-26 10:52:32 +0200150early_param("elfcorehdr", setup_elfcorehdr);
151#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152
Matt Tolentino2b976902005-06-23 00:08:06 -0700153#ifndef CONFIG_NUMA
Matt Tolentinobbfceef2005-06-23 00:08:07 -0700154static void __init
155contig_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156{
Matt Tolentinobbfceef2005-06-23 00:08:07 -0700157 unsigned long bootmap_size, bootmap;
158
Matt Tolentinobbfceef2005-06-23 00:08:07 -0700159 bootmap_size = bootmem_bootmap_pages(end_pfn)<<PAGE_SHIFT;
160 bootmap = find_e820_area(0, end_pfn<<PAGE_SHIFT, bootmap_size);
161 if (bootmap == -1L)
162 panic("Cannot find bootmem map of size %ld\n",bootmap_size);
163 bootmap_size = init_bootmem(bootmap >> PAGE_SHIFT, end_pfn);
Mel Gorman5cb248a2006-09-27 01:49:52 -0700164 e820_register_active_regions(0, start_pfn, end_pfn);
165 free_bootmem_with_active_regions(0, end_pfn);
Matt Tolentinobbfceef2005-06-23 00:08:07 -0700166 reserve_bootmem(bootmap, bootmap_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167}
168#endif
169
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
171struct edd edd;
172#ifdef CONFIG_EDD_MODULE
173EXPORT_SYMBOL(edd);
174#endif
175/**
176 * copy_edd() - Copy the BIOS EDD information
177 * from boot_params into a safe place.
178 *
179 */
180static inline void copy_edd(void)
181{
H. Peter Anvin30c82642007-10-15 17:13:22 -0700182 memcpy(edd.mbr_signature, boot_params.edd_mbr_sig_buffer,
183 sizeof(edd.mbr_signature));
184 memcpy(edd.edd_info, boot_params.eddbuf, sizeof(edd.edd_info));
185 edd.mbr_signature_nr = boot_params.edd_mbr_sig_buf_entries;
186 edd.edd_info_nr = boot_params.eddbuf_entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187}
188#else
189static inline void copy_edd(void)
190{
191}
192#endif
193
Bernhard Walle5c3391f2007-10-18 23:40:59 -0700194#ifdef CONFIG_KEXEC
195static void __init reserve_crashkernel(void)
196{
197 unsigned long long free_mem;
198 unsigned long long crash_size, crash_base;
199 int ret;
200
201 free_mem = ((unsigned long long)max_low_pfn - min_low_pfn) << PAGE_SHIFT;
202
203 ret = parse_crashkernel(boot_command_line, free_mem,
204 &crash_size, &crash_base);
205 if (ret == 0 && crash_size) {
206 if (crash_base > 0) {
207 printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
208 "for crashkernel (System RAM: %ldMB)\n",
209 (unsigned long)(crash_size >> 20),
210 (unsigned long)(crash_base >> 20),
211 (unsigned long)(free_mem >> 20));
212 crashk_res.start = crash_base;
213 crashk_res.end = crash_base + crash_size - 1;
214 reserve_bootmem(crash_base, crash_size);
215 } else
216 printk(KERN_INFO "crashkernel reservation failed - "
217 "you have to specify a base address\n");
218 }
219}
220#else
221static inline void __init reserve_crashkernel(void)
222{}
223#endif
224
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225#define EBDA_ADDR_POINTER 0x40E
Andi Kleenac71d122006-05-08 15:17:28 +0200226
227unsigned __initdata ebda_addr;
228unsigned __initdata ebda_size;
229
230static void discover_ebda(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231{
Andi Kleenac71d122006-05-08 15:17:28 +0200232 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 * there is a real-mode segmented pointer pointing to the
234 * 4K EBDA area at 0x40E
235 */
Vivek Goyalbdb96a62007-05-02 19:27:07 +0200236 ebda_addr = *(unsigned short *)__va(EBDA_ADDR_POINTER);
Andi Kleenac71d122006-05-08 15:17:28 +0200237 ebda_addr <<= 4;
238
Vivek Goyalbdb96a62007-05-02 19:27:07 +0200239 ebda_size = *(unsigned short *)__va(ebda_addr);
Andi Kleenac71d122006-05-08 15:17:28 +0200240
241 /* Round EBDA up to pages */
242 if (ebda_size == 0)
243 ebda_size = 1;
244 ebda_size <<= 10;
245 ebda_size = round_up(ebda_size + (ebda_addr & ~PAGE_MASK), PAGE_SIZE);
246 if (ebda_size > 64*1024)
247 ebda_size = 64*1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248}
249
250void __init setup_arch(char **cmdline_p)
251{
Alon Bar-Levadf48852007-02-12 00:54:25 -0800252 printk(KERN_INFO "Command line: %s\n", boot_command_line);
Andi Kleen43c85c92006-09-26 10:52:32 +0200253
H. Peter Anvin30c82642007-10-15 17:13:22 -0700254 ROOT_DEV = old_decode_dev(boot_params.hdr.root_dev);
255 screen_info = boot_params.screen_info;
256 edid_info = boot_params.edid_info;
257 saved_video_mode = boot_params.hdr.vid_mode;
258 bootloader_type = boot_params.hdr.type_of_loader;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
260#ifdef CONFIG_BLK_DEV_RAM
H. Peter Anvin30c82642007-10-15 17:13:22 -0700261 rd_image_start = boot_params.hdr.ram_size & RAMDISK_IMAGE_START_MASK;
262 rd_prompt = ((boot_params.hdr.ram_size & RAMDISK_PROMPT_FLAG) != 0);
263 rd_doload = ((boot_params.hdr.ram_size & RAMDISK_LOAD_FLAG) != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264#endif
265 setup_memory_region();
266 copy_edd();
267
H. Peter Anvin30c82642007-10-15 17:13:22 -0700268 if (!boot_params.hdr.root_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 root_mountflags &= ~MS_RDONLY;
270 init_mm.start_code = (unsigned long) &_text;
271 init_mm.end_code = (unsigned long) &_etext;
272 init_mm.end_data = (unsigned long) &_edata;
273 init_mm.brk = (unsigned long) &_end;
274
Linus Torvaldse3ebadd2007-05-07 08:44:24 -0700275 code_resource.start = virt_to_phys(&_text);
276 code_resource.end = virt_to_phys(&_etext)-1;
277 data_resource.start = virt_to_phys(&_etext);
278 data_resource.end = virt_to_phys(&_edata)-1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 early_identify_cpu(&boot_cpu_data);
281
Alon Bar-Levadf48852007-02-12 00:54:25 -0800282 strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
Andi Kleen2c8c0e62006-09-26 10:52:32 +0200283 *cmdline_p = command_line;
284
285 parse_early_param();
286
287 finish_e820_parsing();
Andi Kleen9ca33eb2006-09-26 10:52:32 +0200288
Mel Gorman5cb248a2006-09-27 01:49:52 -0700289 e820_register_active_regions(0, 0, -1UL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 /*
291 * partially used pages are not usable - thus
292 * we are rounding upwards:
293 */
294 end_pfn = e820_end_of_ram();
Jan Beulichcaff0712006-09-26 10:52:31 +0200295 num_physpages = end_pfn;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
297 check_efer();
298
Andi Kleenac71d122006-05-08 15:17:28 +0200299 discover_ebda();
300
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 init_memory_mapping(0, (end_pfn_map << PAGE_SHIFT));
302
Andi Kleenf2d3efe2006-03-25 16:30:22 +0100303 dmi_scan_machine();
304
Len Brown888ba6c2005-08-24 12:07:20 -0400305#ifdef CONFIG_ACPI
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 /*
307 * Initialize the ACPI boot-time table parser (gets the RSDP and SDT).
308 * Call this early for SRAT node setup.
309 */
310 acpi_boot_table_init();
311#endif
312
Jan Beulichcaff0712006-09-26 10:52:31 +0200313 /* How many end-of-memory variables you have, grandma! */
314 max_low_pfn = end_pfn;
315 max_pfn = end_pfn;
316 high_memory = (void *)__va(end_pfn * PAGE_SIZE - 1) + 1;
317
Mel Gorman5cb248a2006-09-27 01:49:52 -0700318 /* Remove active ranges so rediscovery with NUMA-awareness happens */
319 remove_all_active_ranges();
320
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321#ifdef CONFIG_ACPI_NUMA
322 /*
323 * Parse SRAT to discover nodes.
324 */
325 acpi_numa_init();
326#endif
327
Matt Tolentino2b976902005-06-23 00:08:06 -0700328#ifdef CONFIG_NUMA
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 numa_initmem_init(0, end_pfn);
330#else
Matt Tolentinobbfceef2005-06-23 00:08:07 -0700331 contig_initmem_init(0, end_pfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332#endif
333
334 /* Reserve direct mapping */
335 reserve_bootmem_generic(table_start << PAGE_SHIFT,
336 (table_end - table_start) << PAGE_SHIFT);
337
338 /* reserve kernel */
Andi Kleenceee8822006-08-30 19:37:12 +0200339 reserve_bootmem_generic(__pa_symbol(&_text),
340 __pa_symbol(&_end) - __pa_symbol(&_text));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
342 /*
343 * reserve physical page 0 - it's a special BIOS page on many boxes,
344 * enabling clean reboots, SMP operation, laptop functions.
345 */
346 reserve_bootmem_generic(0, PAGE_SIZE);
347
348 /* reserve ebda region */
Andi Kleenac71d122006-05-08 15:17:28 +0200349 if (ebda_addr)
350 reserve_bootmem_generic(ebda_addr, ebda_size);
Amul Shah076422d2007-02-13 13:26:19 +0100351#ifdef CONFIG_NUMA
352 /* reserve nodemap region */
353 if (nodemap_addr)
354 reserve_bootmem_generic(nodemap_addr, nodemap_size);
355#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
357#ifdef CONFIG_SMP
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 /* Reserve SMP trampoline */
Vivek Goyal90b1c202007-05-02 19:27:07 +0200359 reserve_bootmem_generic(SMP_TRAMPOLINE_BASE, 2*PAGE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360#endif
361
Len Brown673d5b42007-07-28 03:33:16 -0400362#ifdef CONFIG_ACPI_SLEEP
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 /*
364 * Reserve low memory region for sleep support.
365 */
366 acpi_reserve_bootmem();
367#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 /*
369 * Find and reserve possible boot-time SMP configuration:
370 */
371 find_smp_config();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372#ifdef CONFIG_BLK_DEV_INITRD
H. Peter Anvin30c82642007-10-15 17:13:22 -0700373 if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) {
374 unsigned long ramdisk_image = boot_params.hdr.ramdisk_image;
375 unsigned long ramdisk_size = boot_params.hdr.ramdisk_size;
376 unsigned long ramdisk_end = ramdisk_image + ramdisk_size;
377 unsigned long end_of_mem = end_pfn << PAGE_SHIFT;
378
379 if (ramdisk_end <= end_of_mem) {
380 reserve_bootmem_generic(ramdisk_image, ramdisk_size);
381 initrd_start = ramdisk_image + PAGE_OFFSET;
382 initrd_end = initrd_start+ramdisk_size;
383 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 printk(KERN_ERR "initrd extends beyond end of memory "
H. Peter Anvin30c82642007-10-15 17:13:22 -0700385 "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
386 ramdisk_end, end_of_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 initrd_start = 0;
388 }
389 }
390#endif
Bernhard Walle5c3391f2007-10-18 23:40:59 -0700391 reserve_crashkernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 paging_init();
393
Andi Kleenf157cbb2006-09-26 10:52:41 +0200394#ifdef CONFIG_PCI
Andi Kleendfa46982006-09-26 10:52:30 +0200395 early_quirks();
Andi Kleenf157cbb2006-09-26 10:52:41 +0200396#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
Ashok Raj51f62e12006-03-25 16:29:28 +0100398 /*
399 * set this early, so we dont allocate cpu0
400 * if MADT list doesnt list BSP first
401 * mpparse.c/MP_processor_info() allocates logical cpu numbers.
402 */
403 cpu_set(0, cpu_present_map);
Len Brown888ba6c2005-08-24 12:07:20 -0400404#ifdef CONFIG_ACPI
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 /*
406 * Read APIC and some other early information from ACPI tables.
407 */
408 acpi_boot_init();
409#endif
410
Ravikiran Thirumalai05b3cbd2006-01-11 22:45:36 +0100411 init_cpu_to_node();
412
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 /*
414 * get boot-time SMP configuration:
415 */
416 if (smp_found_config)
417 get_smp_config();
418 init_apic_mappings();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
420 /*
Andi Kleenfc986db2007-02-13 13:26:24 +0100421 * We trust e820 completely. No explicit ROM probing in memory.
422 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 e820_reserve_resources();
Rafael J. Wysockie8eff5a2006-09-25 23:32:46 -0700424 e820_mark_nosave_regions();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 {
427 unsigned i;
428 /* request I/O space for devices used on all i[345]86 PCs */
Andi Kleen9d0ef4f2006-09-30 01:47:55 +0200429 for (i = 0; i < ARRAY_SIZE(standard_io_resources); i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 request_resource(&ioport_resource, &standard_io_resources[i]);
431 }
432
Andi Kleena1e97782005-04-16 15:25:12 -0700433 e820_setup_gap();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435#ifdef CONFIG_VT
436#if defined(CONFIG_VGA_CONSOLE)
437 conswitchp = &vga_con;
438#elif defined(CONFIG_DUMMY_CONSOLE)
439 conswitchp = &dummy_con;
440#endif
441#endif
442}
443
Ashok Raje6982c62005-06-25 14:54:58 -0700444static int __cpuinit get_model_name(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445{
446 unsigned int *v;
447
Andi Kleenebfcaa92005-04-16 15:25:18 -0700448 if (c->extended_cpuid_level < 0x80000004)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 return 0;
450
451 v = (unsigned int *) c->x86_model_id;
452 cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
453 cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
454 cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
455 c->x86_model_id[48] = 0;
456 return 1;
457}
458
459
Ashok Raje6982c62005-06-25 14:54:58 -0700460static void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461{
462 unsigned int n, dummy, eax, ebx, ecx, edx;
463
Andi Kleenebfcaa92005-04-16 15:25:18 -0700464 n = c->extended_cpuid_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465
466 if (n >= 0x80000005) {
467 cpuid(0x80000005, &dummy, &ebx, &ecx, &edx);
468 printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), D cache %dK (%d bytes/line)\n",
469 edx>>24, edx&0xFF, ecx>>24, ecx&0xFF);
470 c->x86_cache_size=(ecx>>24)+(edx>>24);
471 /* On K8 L1 TLB is inclusive, so don't count it */
472 c->x86_tlbsize = 0;
473 }
474
475 if (n >= 0x80000006) {
476 cpuid(0x80000006, &dummy, &ebx, &ecx, &edx);
477 ecx = cpuid_ecx(0x80000006);
478 c->x86_cache_size = ecx >> 16;
479 c->x86_tlbsize += ((ebx >> 16) & 0xfff) + (ebx & 0xfff);
480
481 printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n",
482 c->x86_cache_size, ecx & 0xFF);
483 }
484
485 if (n >= 0x80000007)
486 cpuid(0x80000007, &dummy, &dummy, &dummy, &c->x86_power);
487 if (n >= 0x80000008) {
488 cpuid(0x80000008, &eax, &dummy, &dummy, &dummy);
489 c->x86_virt_bits = (eax >> 8) & 0xff;
490 c->x86_phys_bits = eax & 0xff;
491 }
492}
493
Andi Kleen3f098c22005-09-12 18:49:24 +0200494#ifdef CONFIG_NUMA
495static int nearby_node(int apicid)
496{
497 int i;
498 for (i = apicid - 1; i >= 0; i--) {
499 int node = apicid_to_node[i];
500 if (node != NUMA_NO_NODE && node_online(node))
501 return node;
502 }
503 for (i = apicid + 1; i < MAX_LOCAL_APIC; i++) {
504 int node = apicid_to_node[i];
505 if (node != NUMA_NO_NODE && node_online(node))
506 return node;
507 }
508 return first_node(node_online_map); /* Shouldn't happen */
509}
510#endif
511
Andi Kleen63518642005-04-16 15:25:16 -0700512/*
513 * On a AMD dual core setup the lower bits of the APIC id distingush the cores.
514 * Assumes number of cores is a power of two.
515 */
516static void __init amd_detect_cmp(struct cpuinfo_x86 *c)
517{
518#ifdef CONFIG_SMP
Andi Kleenb41e2932005-05-20 14:27:55 -0700519 unsigned bits;
Andi Kleen3f098c22005-09-12 18:49:24 +0200520#ifdef CONFIG_NUMA
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200521 int cpu = smp_processor_id();
Andi Kleen3f098c22005-09-12 18:49:24 +0200522 int node = 0;
Ravikiran G Thirumalai60c1bc82006-03-25 16:30:04 +0100523 unsigned apicid = hard_smp_processor_id();
Andi Kleen3f098c22005-09-12 18:49:24 +0200524#endif
Andi Kleenfaee9a52006-06-26 13:56:10 +0200525 unsigned ecx = cpuid_ecx(0x80000008);
Andi Kleenb41e2932005-05-20 14:27:55 -0700526
Andi Kleenfaee9a52006-06-26 13:56:10 +0200527 c->x86_max_cores = (ecx & 0xff) + 1;
528
529 /* CPU telling us the core id bits shift? */
530 bits = (ecx >> 12) & 0xF;
531
532 /* Otherwise recompute */
533 if (bits == 0) {
534 while ((1 << bits) < c->x86_max_cores)
535 bits++;
536 }
Andi Kleenb41e2932005-05-20 14:27:55 -0700537
538 /* Low order bits define the core id (index of core in socket) */
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200539 c->cpu_core_id = c->phys_proc_id & ((1 << bits)-1);
Andi Kleenb41e2932005-05-20 14:27:55 -0700540 /* Convert the APIC ID into the socket ID */
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200541 c->phys_proc_id = phys_pkg_id(bits);
Andi Kleen63518642005-04-16 15:25:16 -0700542
543#ifdef CONFIG_NUMA
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200544 node = c->phys_proc_id;
Andi Kleen3f098c22005-09-12 18:49:24 +0200545 if (apicid_to_node[apicid] != NUMA_NO_NODE)
546 node = apicid_to_node[apicid];
547 if (!node_online(node)) {
548 /* Two possibilities here:
549 - The CPU is missing memory and no node was created.
550 In that case try picking one from a nearby CPU
551 - The APIC IDs differ from the HyperTransport node IDs
552 which the K8 northbridge parsing fills in.
553 Assume they are all increased by a constant offset,
554 but in the same order as the HT nodeids.
555 If that doesn't result in a usable node fall back to the
556 path for the previous case. */
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200557 int ht_nodeid = apicid - (cpu_data[0].phys_proc_id << bits);
Andi Kleen3f098c22005-09-12 18:49:24 +0200558 if (ht_nodeid >= 0 &&
559 apicid_to_node[ht_nodeid] != NUMA_NO_NODE)
560 node = apicid_to_node[ht_nodeid];
561 /* Pick a nearby node */
562 if (!node_online(node))
563 node = nearby_node(apicid);
564 }
Andi Kleen69d81fc2005-11-05 17:25:53 +0100565 numa_set_node(cpu, node);
Andi Kleena1586082005-05-16 21:53:21 -0700566
Rohit Sethe42f9432006-06-26 13:59:14 +0200567 printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
Andi Kleen3f098c22005-09-12 18:49:24 +0200568#endif
Andi Kleen63518642005-04-16 15:25:16 -0700569#endif
570}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571
Thomas Gleixnerfb79d222007-10-12 23:04:07 +0200572#define ENABLE_C1E_MASK 0x18000000
573#define CPUID_PROCESSOR_SIGNATURE 1
574#define CPUID_XFAM 0x0ff00000
575#define CPUID_XFAM_K8 0x00000000
576#define CPUID_XFAM_10H 0x00100000
577#define CPUID_XFAM_11H 0x00200000
578#define CPUID_XMOD 0x000f0000
579#define CPUID_XMOD_REV_F 0x00040000
580
581/* AMD systems with C1E don't have a working lAPIC timer. Check for that. */
582static __cpuinit int amd_apic_timer_broken(void)
583{
584 u32 lo, hi;
585 u32 eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
586 switch (eax & CPUID_XFAM) {
587 case CPUID_XFAM_K8:
588 if ((eax & CPUID_XMOD) < CPUID_XMOD_REV_F)
589 break;
590 case CPUID_XFAM_10H:
591 case CPUID_XFAM_11H:
592 rdmsr(MSR_K8_ENABLE_C1E, lo, hi);
593 if (lo & ENABLE_C1E_MASK)
594 return 1;
595 break;
596 default:
597 /* err on the side of caution */
598 return 1;
599 }
600 return 0;
601}
602
Magnus Dammed775042006-09-26 10:52:36 +0200603static void __cpuinit init_amd(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604{
Andi Kleen7bcd3f32006-02-03 21:51:02 +0100605 unsigned level;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606
Linus Torvaldsbc5e8fd2005-09-17 15:41:04 -0700607#ifdef CONFIG_SMP
608 unsigned long value;
609
Andi Kleen7d318d72005-09-29 22:05:55 +0200610 /*
611 * Disable TLB flush filter by setting HWCR.FFDIS on K8
612 * bit 6 of msr C001_0015
613 *
614 * Errata 63 for SH-B3 steppings
615 * Errata 122 for all steppings (F+ have it disabled by default)
616 */
617 if (c->x86 == 15) {
618 rdmsrl(MSR_K8_HWCR, value);
619 value |= 1 << 6;
620 wrmsrl(MSR_K8_HWCR, value);
621 }
Linus Torvaldsbc5e8fd2005-09-17 15:41:04 -0700622#endif
623
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 /* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
625 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
626 clear_bit(0*32+31, &c->x86_capability);
627
Andi Kleen7bcd3f32006-02-03 21:51:02 +0100628 /* On C+ stepping K8 rep microcode works well for copy/memset */
629 level = cpuid_eax(1);
630 if (c->x86 == 15 && ((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58))
631 set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability);
Andi Kleen99741fa2007-10-17 18:04:41 +0200632 if (c->x86 == 0x10 || c->x86 == 0x11)
Andi Kleen5b74e3a2007-07-21 17:09:57 +0200633 set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability);
Andi Kleen7bcd3f32006-02-03 21:51:02 +0100634
Andi Kleen18bd0572006-04-20 02:36:45 +0200635 /* Enable workaround for FXSAVE leak */
636 if (c->x86 >= 6)
637 set_bit(X86_FEATURE_FXSAVE_LEAK, &c->x86_capability);
638
Rohit Sethe42f9432006-06-26 13:59:14 +0200639 level = get_model_name(c);
640 if (!level) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 switch (c->x86) {
642 case 15:
643 /* Should distinguish Models here, but this is only
644 a fallback anyways. */
645 strcpy(c->x86_model_id, "Hammer");
646 break;
647 }
648 }
649 display_cacheinfo(c);
650
Andi Kleen130951c2006-01-11 22:42:02 +0100651 /* c->x86_power is 8000_0007 edx. Bit 8 is constant TSC */
652 if (c->x86_power & (1<<8))
653 set_bit(X86_FEATURE_CONSTANT_TSC, &c->x86_capability);
654
Andi Kleenfaee9a52006-06-26 13:56:10 +0200655 /* Multi core CPU? */
656 if (c->extended_cpuid_level >= 0x80000008)
Andi Kleen63518642005-04-16 15:25:16 -0700657 amd_detect_cmp(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
Andi Kleen67cddd92007-07-21 17:10:03 +0200659 if (c->extended_cpuid_level >= 0x80000006 &&
660 (cpuid_edx(0x80000006) & 0xf000))
661 num_cache_leaves = 4;
662 else
663 num_cache_leaves = 3;
Andi Kleen20493362006-09-26 10:52:41 +0200664
Andi Kleen0bd8acd2007-07-22 11:12:34 +0200665 if (c->x86 == 0xf || c->x86 == 0x10 || c->x86 == 0x11)
666 set_bit(X86_FEATURE_K8, &c->x86_capability);
667
Andi Kleen61677962006-12-07 02:14:12 +0100668 /* RDTSC can be speculated around */
669 clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
Andi Kleenf039b752007-05-02 19:27:12 +0200670
671 /* Family 10 doesn't support C states in MWAIT so don't use it */
672 if (c->x86 == 0x10 && !force_mwait)
673 clear_bit(X86_FEATURE_MWAIT, &c->x86_capability);
Thomas Gleixnerfb79d222007-10-12 23:04:07 +0200674
675 if (amd_apic_timer_broken())
676 disable_apic_timer = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677}
678
Ashok Raje6982c62005-06-25 14:54:58 -0700679static void __cpuinit detect_ht(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680{
681#ifdef CONFIG_SMP
682 u32 eax, ebx, ecx, edx;
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100683 int index_msb, core_bits;
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100684
685 cpuid(1, &eax, &ebx, &ecx, &edx);
686
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100687
Rohit Sethe42f9432006-06-26 13:59:14 +0200688 if (!cpu_has(c, X86_FEATURE_HT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 return;
Rohit Sethe42f9432006-06-26 13:59:14 +0200690 if (cpu_has(c, X86_FEATURE_CMP_LEGACY))
691 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 smp_num_siblings = (ebx & 0xff0000) >> 16;
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100694
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 if (smp_num_siblings == 1) {
696 printk(KERN_INFO "CPU: Hyper-Threading is disabled\n");
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100697 } else if (smp_num_siblings > 1 ) {
698
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 if (smp_num_siblings > NR_CPUS) {
700 printk(KERN_WARNING "CPU: Unsupported number of the siblings %d", smp_num_siblings);
701 smp_num_siblings = 1;
702 return;
703 }
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100704
705 index_msb = get_count_order(smp_num_siblings);
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200706 c->phys_proc_id = phys_pkg_id(index_msb);
Andi Kleen3dd9d512005-04-16 15:25:15 -0700707
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100708 smp_num_siblings = smp_num_siblings / c->x86_max_cores;
Andi Kleen3dd9d512005-04-16 15:25:15 -0700709
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100710 index_msb = get_count_order(smp_num_siblings) ;
Andi Kleen3dd9d512005-04-16 15:25:15 -0700711
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100712 core_bits = get_count_order(c->x86_max_cores);
Andi Kleen3dd9d512005-04-16 15:25:15 -0700713
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200714 c->cpu_core_id = phys_pkg_id(index_msb) &
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100715 ((1 << core_bits) - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 }
Rohit Sethe42f9432006-06-26 13:59:14 +0200717out:
718 if ((c->x86_max_cores * smp_num_siblings) > 1) {
719 printk(KERN_INFO "CPU: Physical Processor ID: %d\n", c->phys_proc_id);
720 printk(KERN_INFO "CPU: Processor Core ID: %d\n", c->cpu_core_id);
721 }
722
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723#endif
724}
725
Andi Kleen3dd9d512005-04-16 15:25:15 -0700726/*
727 * find out the number of processor cores on the die
728 */
Ashok Raje6982c62005-06-25 14:54:58 -0700729static int __cpuinit intel_num_cpu_cores(struct cpuinfo_x86 *c)
Andi Kleen3dd9d512005-04-16 15:25:15 -0700730{
Rohit Seth2bbc4192006-06-26 13:58:02 +0200731 unsigned int eax, t;
Andi Kleen3dd9d512005-04-16 15:25:15 -0700732
733 if (c->cpuid_level < 4)
734 return 1;
735
Rohit Seth2bbc4192006-06-26 13:58:02 +0200736 cpuid_count(4, 0, &eax, &t, &t, &t);
Andi Kleen3dd9d512005-04-16 15:25:15 -0700737
738 if (eax & 0x1f)
739 return ((eax >> 26) + 1);
740 else
741 return 1;
742}
743
Andi Kleendf0cc262005-09-12 18:49:24 +0200744static void srat_detect_node(void)
745{
746#ifdef CONFIG_NUMA
Ravikiran G Thirumalaiddea7be2005-10-03 10:36:28 -0700747 unsigned node;
Andi Kleendf0cc262005-09-12 18:49:24 +0200748 int cpu = smp_processor_id();
Rohit Sethe42f9432006-06-26 13:59:14 +0200749 int apicid = hard_smp_processor_id();
Andi Kleendf0cc262005-09-12 18:49:24 +0200750
751 /* Don't do the funky fallback heuristics the AMD version employs
752 for now. */
Rohit Sethe42f9432006-06-26 13:59:14 +0200753 node = apicid_to_node[apicid];
Andi Kleendf0cc262005-09-12 18:49:24 +0200754 if (node == NUMA_NO_NODE)
Daniel Yeisley0d015322006-05-30 22:47:57 +0200755 node = first_node(node_online_map);
Andi Kleen69d81fc2005-11-05 17:25:53 +0100756 numa_set_node(cpu, node);
Andi Kleendf0cc262005-09-12 18:49:24 +0200757
Andi Kleenc31fbb12006-09-26 10:52:33 +0200758 printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
Andi Kleendf0cc262005-09-12 18:49:24 +0200759#endif
760}
761
Ashok Raje6982c62005-06-25 14:54:58 -0700762static void __cpuinit init_intel(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763{
764 /* Cache sizes */
765 unsigned n;
766
767 init_intel_cacheinfo(c);
Venkatesh Pallipadi0080e662006-06-26 13:59:59 +0200768 if (c->cpuid_level > 9 ) {
769 unsigned eax = cpuid_eax(10);
770 /* Check for version and the number of counters */
771 if ((eax & 0xff) && (((eax>>8) & 0xff) > 1))
772 set_bit(X86_FEATURE_ARCH_PERFMON, &c->x86_capability);
773 }
774
Stephane Eranian36b2a8d2006-12-07 02:14:01 +0100775 if (cpu_has_ds) {
776 unsigned int l1, l2;
777 rdmsr(MSR_IA32_MISC_ENABLE, l1, l2);
Stephane Eranianee58fad2006-12-07 02:14:11 +0100778 if (!(l1 & (1<<11)))
779 set_bit(X86_FEATURE_BTS, c->x86_capability);
Stephane Eranian36b2a8d2006-12-07 02:14:01 +0100780 if (!(l1 & (1<<12)))
781 set_bit(X86_FEATURE_PEBS, c->x86_capability);
782 }
783
Andi Kleenebfcaa92005-04-16 15:25:18 -0700784 n = c->extended_cpuid_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 if (n >= 0x80000008) {
786 unsigned eax = cpuid_eax(0x80000008);
787 c->x86_virt_bits = (eax >> 8) & 0xff;
788 c->x86_phys_bits = eax & 0xff;
Shaohua Liaf9c1422005-11-05 17:25:54 +0100789 /* CPUID workaround for Intel 0F34 CPU */
790 if (c->x86_vendor == X86_VENDOR_INTEL &&
791 c->x86 == 0xF && c->x86_model == 0x3 &&
792 c->x86_mask == 0x4)
793 c->x86_phys_bits = 36;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 }
795
796 if (c->x86 == 15)
797 c->x86_cache_alignment = c->x86_clflush_size * 2;
Andi Kleen39b3a792006-01-11 22:42:45 +0100798 if ((c->x86 == 0xf && c->x86_model >= 0x03) ||
799 (c->x86 == 0x6 && c->x86_model >= 0x0e))
Andi Kleenc29601e2005-04-16 15:25:05 -0700800 set_bit(X86_FEATURE_CONSTANT_TSC, &c->x86_capability);
Andi Kleen27fbe5b2006-09-26 10:52:41 +0200801 if (c->x86 == 6)
802 set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability);
Arjan van de Venf3d73702006-12-07 02:14:12 +0100803 if (c->x86 == 15)
804 set_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
805 else
806 clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100807 c->x86_max_cores = intel_num_cpu_cores(c);
Andi Kleendf0cc262005-09-12 18:49:24 +0200808
809 srat_detect_node();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810}
811
Adrian Bunk672289e2005-09-10 00:27:21 -0700812static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813{
814 char *v = c->x86_vendor_id;
815
816 if (!strcmp(v, "AuthenticAMD"))
817 c->x86_vendor = X86_VENDOR_AMD;
818 else if (!strcmp(v, "GenuineIntel"))
819 c->x86_vendor = X86_VENDOR_INTEL;
820 else
821 c->x86_vendor = X86_VENDOR_UNKNOWN;
822}
823
824struct cpu_model_info {
825 int vendor;
826 int family;
827 char *model_names[16];
828};
829
830/* Do some early cpuid on the boot CPU to get some parameter that are
831 needed before check_bugs. Everything advanced is in identify_cpu
832 below. */
Ashok Raje6982c62005-06-25 14:54:58 -0700833void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834{
835 u32 tfms;
836
837 c->loops_per_jiffy = loops_per_jiffy;
838 c->x86_cache_size = -1;
839 c->x86_vendor = X86_VENDOR_UNKNOWN;
840 c->x86_model = c->x86_mask = 0; /* So far unknown... */
841 c->x86_vendor_id[0] = '\0'; /* Unset */
842 c->x86_model_id[0] = '\0'; /* Unset */
843 c->x86_clflush_size = 64;
844 c->x86_cache_alignment = c->x86_clflush_size;
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100845 c->x86_max_cores = 1;
Andi Kleenebfcaa92005-04-16 15:25:18 -0700846 c->extended_cpuid_level = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 memset(&c->x86_capability, 0, sizeof c->x86_capability);
848
849 /* Get vendor name */
850 cpuid(0x00000000, (unsigned int *)&c->cpuid_level,
851 (unsigned int *)&c->x86_vendor_id[0],
852 (unsigned int *)&c->x86_vendor_id[8],
853 (unsigned int *)&c->x86_vendor_id[4]);
854
855 get_cpu_vendor(c);
856
857 /* Initialize the standard set of capabilities */
858 /* Note that the vendor-specific code below might override */
859
860 /* Intel-defined flags: level 0x00000001 */
861 if (c->cpuid_level >= 0x00000001) {
862 __u32 misc;
863 cpuid(0x00000001, &tfms, &misc, &c->x86_capability[4],
864 &c->x86_capability[0]);
865 c->x86 = (tfms >> 8) & 0xf;
866 c->x86_model = (tfms >> 4) & 0xf;
867 c->x86_mask = tfms & 0xf;
Suresh Siddhaf5f786d2005-11-05 17:25:53 +0100868 if (c->x86 == 0xf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 c->x86 += (tfms >> 20) & 0xff;
Suresh Siddhaf5f786d2005-11-05 17:25:53 +0100870 if (c->x86 >= 0x6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 c->x86_model += ((tfms >> 16) & 0xF) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 if (c->x86_capability[0] & (1<<19))
873 c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 } else {
875 /* Have CPUID level 0 only - unheard of */
876 c->x86 = 4;
877 }
Andi Kleena1586082005-05-16 21:53:21 -0700878
879#ifdef CONFIG_SMP
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200880 c->phys_proc_id = (cpuid_ebx(1) >> 24) & 0xff;
Andi Kleena1586082005-05-16 21:53:21 -0700881#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882}
883
884/*
885 * This does the hard work of actually picking apart the CPU stuff...
886 */
Ashok Raje6982c62005-06-25 14:54:58 -0700887void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888{
889 int i;
890 u32 xlvl;
891
892 early_identify_cpu(c);
893
894 /* AMD-defined flags: level 0x80000001 */
895 xlvl = cpuid_eax(0x80000000);
Andi Kleenebfcaa92005-04-16 15:25:18 -0700896 c->extended_cpuid_level = xlvl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 if ((xlvl & 0xffff0000) == 0x80000000) {
898 if (xlvl >= 0x80000001) {
899 c->x86_capability[1] = cpuid_edx(0x80000001);
H. Peter Anvin5b7abc62005-05-01 08:58:49 -0700900 c->x86_capability[6] = cpuid_ecx(0x80000001);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 }
902 if (xlvl >= 0x80000004)
903 get_model_name(c); /* Default name */
904 }
905
906 /* Transmeta-defined flags: level 0x80860001 */
907 xlvl = cpuid_eax(0x80860000);
908 if ((xlvl & 0xffff0000) == 0x80860000) {
909 /* Don't set x86_cpuid_level here for now to not confuse. */
910 if (xlvl >= 0x80860001)
911 c->x86_capability[2] = cpuid_edx(0x80860001);
912 }
913
Venki Pallipadi1d679532007-07-11 12:18:32 -0700914 init_scattered_cpuid_features(c);
915
Siddha, Suresh B1e9f28f2006-03-27 01:15:22 -0800916 c->apicid = phys_pkg_id(0);
917
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 /*
919 * Vendor-specific initialization. In this section we
920 * canonicalize the feature flags, meaning if there are
921 * features a certain CPU supports which CPUID doesn't
922 * tell us, CPUID claiming incorrect flags, or other bugs,
923 * we handle them here.
924 *
925 * At the end of this section, c->x86_capability better
926 * indicate the features this CPU genuinely supports!
927 */
928 switch (c->x86_vendor) {
929 case X86_VENDOR_AMD:
930 init_amd(c);
931 break;
932
933 case X86_VENDOR_INTEL:
934 init_intel(c);
935 break;
936
937 case X86_VENDOR_UNKNOWN:
938 default:
939 display_cacheinfo(c);
940 break;
941 }
942
943 select_idle_routine(c);
944 detect_ht(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
946 /*
947 * On SMP, boot_cpu_data holds the common feature set between
948 * all CPUs; so make sure that we indicate which features are
949 * common between the CPUs. The first time this routine gets
950 * executed, c == &boot_cpu_data.
951 */
952 if (c != &boot_cpu_data) {
953 /* AND the already accumulated flags with these */
954 for (i = 0 ; i < NCAPINTS ; i++)
955 boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
956 }
957
958#ifdef CONFIG_X86_MCE
959 mcheck_init(c);
960#endif
Andi Kleen8bd99482007-05-11 11:23:20 +0200961 if (c != &boot_cpu_data)
Shaohua Li3b520b22005-07-07 17:56:38 -0700962 mtrr_ap_init();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963#ifdef CONFIG_NUMA
Andi Kleen3019e8e2005-07-28 21:15:28 -0700964 numa_add_cpu(smp_processor_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965#endif
966}
967
968
Ashok Raje6982c62005-06-25 14:54:58 -0700969void __cpuinit print_cpu_info(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970{
971 if (c->x86_model_id[0])
972 printk("%s", c->x86_model_id);
973
974 if (c->x86_mask || c->cpuid_level >= 0)
975 printk(" stepping %02x\n", c->x86_mask);
976 else
977 printk("\n");
978}
979
980/*
981 * Get CPU information for use by the procfs.
982 */
983
984static int show_cpuinfo(struct seq_file *m, void *v)
985{
986 struct cpuinfo_x86 *c = v;
987
988 /*
989 * These flag bits must match the definitions in <asm/cpufeature.h>.
990 * NULL means this bit is undefined or reserved; either way it doesn't
991 * have meaning as far as Linux is concerned. Note that it's important
992 * to realize there is a difference between this table and CPUID -- if
993 * applications want to get the raw CPUID data, they should access
994 * /dev/cpu/<cpu_nr>/cpuid instead.
995 */
Jan Beulich121d7bf2007-10-17 18:04:37 +0200996 static const char *const x86_cap_flags[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 /* Intel-defined */
998 "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
999 "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
1000 "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
H. Peter Anvinec481532007-07-11 12:18:29 -07001001 "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002
1003 /* AMD-defined */
Zwane Mwaikambo3c3b73b2005-05-01 08:58:51 -07001004 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
1006 NULL, NULL, NULL, NULL, "nx", NULL, "mmxext", NULL,
Andi Kleenf790cd32007-02-13 13:26:25 +01001007 NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm",
1008 "3dnowext", "3dnow",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009
1010 /* Transmeta-defined */
1011 "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
1012 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1013 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1014 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1015
1016 /* Other (Linux-defined) */
H. Peter Anvinec481532007-07-11 12:18:29 -07001017 "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr",
1018 NULL, NULL, NULL, NULL,
1019 "constant_tsc", "up", NULL, "arch_perfmon",
1020 "pebs", "bts", NULL, "sync_rdtsc",
1021 "rep_good", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1023
1024 /* Intel-defined (#2) */
Andi Kleen9d95dd82006-03-25 16:31:22 +01001025 "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est",
Dave Jonesdcf10302006-09-26 10:52:42 +02001026 "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
Andi Kleenf790cd32007-02-13 13:26:25 +01001027 NULL, NULL, "dca", NULL, NULL, NULL, NULL, "popcnt",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1029
H. Peter Anvin5b7abc62005-05-01 08:58:49 -07001030 /* VIA/Cyrix/Centaur-defined */
1031 NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
H. Peter Anvinec481532007-07-11 12:18:29 -07001032 "ace2", "ace2_en", "phe", "phe_en", "pmm", "pmm_en", NULL, NULL,
H. Peter Anvin5b7abc62005-05-01 08:58:49 -07001033 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1034 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1035
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 /* AMD-defined (#2) */
Andi Kleenf790cd32007-02-13 13:26:25 +01001037 "lahf_lm", "cmp_legacy", "svm", "extapic", "cr8_legacy",
1038 "altmovcr8", "abm", "sse4a",
1039 "misalignsse", "3dnowprefetch",
1040 "osvw", "ibs", NULL, NULL, NULL, NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
H. Peter Anvin5b7abc62005-05-01 08:58:49 -07001042 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Venki Pallipadi1d679532007-07-11 12:18:32 -07001043
1044 /* Auxiliary (Linux-defined) */
1045 "ida", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1046 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1047 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1048 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 };
Jan Beulich121d7bf2007-10-17 18:04:37 +02001050 static const char *const x86_power_flags[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 "ts", /* temperature sensor */
1052 "fid", /* frequency id control */
1053 "vid", /* voltage id control */
1054 "ttp", /* thermal trip */
1055 "tm",
Andi Kleen3f98bc42006-01-11 22:42:51 +01001056 "stc",
Andi Kleenf790cd32007-02-13 13:26:25 +01001057 "100mhzsteps",
1058 "hwpstate",
Joerg Roedeld8243952007-05-02 19:27:09 +02001059 "", /* tsc invariant mapped to constant_tsc */
1060 /* nothing */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 };
1062
1063
1064#ifdef CONFIG_SMP
1065 if (!cpu_online(c-cpu_data))
1066 return 0;
1067#endif
1068
1069 seq_printf(m,"processor\t: %u\n"
1070 "vendor_id\t: %s\n"
1071 "cpu family\t: %d\n"
1072 "model\t\t: %d\n"
1073 "model name\t: %s\n",
1074 (unsigned)(c-cpu_data),
1075 c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown",
1076 c->x86,
1077 (int)c->x86_model,
1078 c->x86_model_id[0] ? c->x86_model_id : "unknown");
1079
1080 if (c->x86_mask || c->cpuid_level >= 0)
1081 seq_printf(m, "stepping\t: %d\n", c->x86_mask);
1082 else
1083 seq_printf(m, "stepping\t: unknown\n");
1084
1085 if (cpu_has(c,X86_FEATURE_TSC)) {
Venkatesh Pallipadi95235ca2005-12-02 10:43:20 -08001086 unsigned int freq = cpufreq_quick_get((unsigned)(c-cpu_data));
1087 if (!freq)
1088 freq = cpu_khz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 seq_printf(m, "cpu MHz\t\t: %u.%03u\n",
Venkatesh Pallipadi95235ca2005-12-02 10:43:20 -08001090 freq / 1000, (freq % 1000));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 }
1092
1093 /* Cache size */
1094 if (c->x86_cache_size >= 0)
1095 seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size);
1096
1097#ifdef CONFIG_SMP
Siddha, Suresh B94605ef2005-11-05 17:25:54 +01001098 if (smp_num_siblings * c->x86_max_cores > 1) {
Andi Kleendb468682005-04-16 15:24:51 -07001099 int cpu = c - cpu_data;
Rohit Sethf3fa8eb2006-06-26 13:58:17 +02001100 seq_printf(m, "physical id\t: %d\n", c->phys_proc_id);
Mike Travis08357612007-10-16 01:24:04 -07001101 seq_printf(m, "siblings\t: %d\n",
1102 cpus_weight(per_cpu(cpu_core_map, cpu)));
Rohit Sethf3fa8eb2006-06-26 13:58:17 +02001103 seq_printf(m, "core id\t\t: %d\n", c->cpu_core_id);
Siddha, Suresh B94605ef2005-11-05 17:25:54 +01001104 seq_printf(m, "cpu cores\t: %d\n", c->booted_cores);
Andi Kleendb468682005-04-16 15:24:51 -07001105 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106#endif
1107
1108 seq_printf(m,
1109 "fpu\t\t: yes\n"
1110 "fpu_exception\t: yes\n"
1111 "cpuid level\t: %d\n"
1112 "wp\t\t: yes\n"
1113 "flags\t\t:",
1114 c->cpuid_level);
1115
1116 {
1117 int i;
1118 for ( i = 0 ; i < 32*NCAPINTS ; i++ )
Akinobu Mita3d1712c2006-03-24 03:15:11 -08001119 if (cpu_has(c, i) && x86_cap_flags[i] != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 seq_printf(m, " %s", x86_cap_flags[i]);
1121 }
1122
1123 seq_printf(m, "\nbogomips\t: %lu.%02lu\n",
1124 c->loops_per_jiffy/(500000/HZ),
1125 (c->loops_per_jiffy/(5000/HZ)) % 100);
1126
1127 if (c->x86_tlbsize > 0)
1128 seq_printf(m, "TLB size\t: %d 4K pages\n", c->x86_tlbsize);
1129 seq_printf(m, "clflush size\t: %d\n", c->x86_clflush_size);
1130 seq_printf(m, "cache_alignment\t: %d\n", c->x86_cache_alignment);
1131
1132 seq_printf(m, "address sizes\t: %u bits physical, %u bits virtual\n",
1133 c->x86_phys_bits, c->x86_virt_bits);
1134
1135 seq_printf(m, "power management:");
1136 {
1137 unsigned i;
1138 for (i = 0; i < 32; i++)
1139 if (c->x86_power & (1 << i)) {
Andi Kleen3f98bc42006-01-11 22:42:51 +01001140 if (i < ARRAY_SIZE(x86_power_flags) &&
1141 x86_power_flags[i])
1142 seq_printf(m, "%s%s",
1143 x86_power_flags[i][0]?" ":"",
1144 x86_power_flags[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 else
1146 seq_printf(m, " [%d]", i);
1147 }
1148 }
Andi Kleen3dd9d512005-04-16 15:25:15 -07001149
Siddha, Suresh Bd31ddaa2005-04-16 15:25:20 -07001150 seq_printf(m, "\n\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 return 0;
1153}
1154
1155static void *c_start(struct seq_file *m, loff_t *pos)
1156{
1157 return *pos < NR_CPUS ? cpu_data + *pos : NULL;
1158}
1159
1160static void *c_next(struct seq_file *m, void *v, loff_t *pos)
1161{
1162 ++*pos;
1163 return c_start(m, pos);
1164}
1165
1166static void c_stop(struct seq_file *m, void *v)
1167{
1168}
1169
1170struct seq_operations cpuinfo_op = {
1171 .start =c_start,
1172 .next = c_next,
1173 .stop = c_stop,
1174 .show = show_cpuinfo,
1175};