blob: 94630c66470e963f83716e571aa097c1c45e774b [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
194#define EBDA_ADDR_POINTER 0x40E
Andi Kleenac71d122006-05-08 15:17:28 +0200195
196unsigned __initdata ebda_addr;
197unsigned __initdata ebda_size;
198
199static void discover_ebda(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200{
Andi Kleenac71d122006-05-08 15:17:28 +0200201 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 * there is a real-mode segmented pointer pointing to the
203 * 4K EBDA area at 0x40E
204 */
Vivek Goyalbdb96a62007-05-02 19:27:07 +0200205 ebda_addr = *(unsigned short *)__va(EBDA_ADDR_POINTER);
Andi Kleenac71d122006-05-08 15:17:28 +0200206 ebda_addr <<= 4;
207
Vivek Goyalbdb96a62007-05-02 19:27:07 +0200208 ebda_size = *(unsigned short *)__va(ebda_addr);
Andi Kleenac71d122006-05-08 15:17:28 +0200209
210 /* Round EBDA up to pages */
211 if (ebda_size == 0)
212 ebda_size = 1;
213 ebda_size <<= 10;
214 ebda_size = round_up(ebda_size + (ebda_addr & ~PAGE_MASK), PAGE_SIZE);
215 if (ebda_size > 64*1024)
216 ebda_size = 64*1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217}
218
219void __init setup_arch(char **cmdline_p)
220{
Alon Bar-Levadf48852007-02-12 00:54:25 -0800221 printk(KERN_INFO "Command line: %s\n", boot_command_line);
Andi Kleen43c85c92006-09-26 10:52:32 +0200222
H. Peter Anvin30c82642007-10-15 17:13:22 -0700223 ROOT_DEV = old_decode_dev(boot_params.hdr.root_dev);
224 screen_info = boot_params.screen_info;
225 edid_info = boot_params.edid_info;
226 saved_video_mode = boot_params.hdr.vid_mode;
227 bootloader_type = boot_params.hdr.type_of_loader;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228
229#ifdef CONFIG_BLK_DEV_RAM
H. Peter Anvin30c82642007-10-15 17:13:22 -0700230 rd_image_start = boot_params.hdr.ram_size & RAMDISK_IMAGE_START_MASK;
231 rd_prompt = ((boot_params.hdr.ram_size & RAMDISK_PROMPT_FLAG) != 0);
232 rd_doload = ((boot_params.hdr.ram_size & RAMDISK_LOAD_FLAG) != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233#endif
234 setup_memory_region();
235 copy_edd();
236
H. Peter Anvin30c82642007-10-15 17:13:22 -0700237 if (!boot_params.hdr.root_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 root_mountflags &= ~MS_RDONLY;
239 init_mm.start_code = (unsigned long) &_text;
240 init_mm.end_code = (unsigned long) &_etext;
241 init_mm.end_data = (unsigned long) &_edata;
242 init_mm.brk = (unsigned long) &_end;
243
Linus Torvaldse3ebadd2007-05-07 08:44:24 -0700244 code_resource.start = virt_to_phys(&_text);
245 code_resource.end = virt_to_phys(&_etext)-1;
246 data_resource.start = virt_to_phys(&_etext);
247 data_resource.end = virt_to_phys(&_edata)-1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 early_identify_cpu(&boot_cpu_data);
250
Alon Bar-Levadf48852007-02-12 00:54:25 -0800251 strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
Andi Kleen2c8c0e62006-09-26 10:52:32 +0200252 *cmdline_p = command_line;
253
254 parse_early_param();
255
256 finish_e820_parsing();
Andi Kleen9ca33eb2006-09-26 10:52:32 +0200257
Mel Gorman5cb248a2006-09-27 01:49:52 -0700258 e820_register_active_regions(0, 0, -1UL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 /*
260 * partially used pages are not usable - thus
261 * we are rounding upwards:
262 */
263 end_pfn = e820_end_of_ram();
Jan Beulichcaff0712006-09-26 10:52:31 +0200264 num_physpages = end_pfn;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265
266 check_efer();
267
Andi Kleenac71d122006-05-08 15:17:28 +0200268 discover_ebda();
269
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 init_memory_mapping(0, (end_pfn_map << PAGE_SHIFT));
271
Andi Kleenf2d3efe2006-03-25 16:30:22 +0100272 dmi_scan_machine();
273
Mike Travis71fff5e2007-10-19 20:35:03 +0200274#ifdef CONFIG_SMP
275 /* setup to use the static apicid table during kernel startup */
276 x86_cpu_to_apicid_ptr = (void *)&x86_cpu_to_apicid_init;
277#endif
278
Len Brown888ba6c2005-08-24 12:07:20 -0400279#ifdef CONFIG_ACPI
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 /*
281 * Initialize the ACPI boot-time table parser (gets the RSDP and SDT).
282 * Call this early for SRAT node setup.
283 */
284 acpi_boot_table_init();
285#endif
286
Jan Beulichcaff0712006-09-26 10:52:31 +0200287 /* How many end-of-memory variables you have, grandma! */
288 max_low_pfn = end_pfn;
289 max_pfn = end_pfn;
290 high_memory = (void *)__va(end_pfn * PAGE_SIZE - 1) + 1;
291
Mel Gorman5cb248a2006-09-27 01:49:52 -0700292 /* Remove active ranges so rediscovery with NUMA-awareness happens */
293 remove_all_active_ranges();
294
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295#ifdef CONFIG_ACPI_NUMA
296 /*
297 * Parse SRAT to discover nodes.
298 */
299 acpi_numa_init();
300#endif
301
Matt Tolentino2b976902005-06-23 00:08:06 -0700302#ifdef CONFIG_NUMA
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 numa_initmem_init(0, end_pfn);
304#else
Matt Tolentinobbfceef2005-06-23 00:08:07 -0700305 contig_initmem_init(0, end_pfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306#endif
307
308 /* Reserve direct mapping */
309 reserve_bootmem_generic(table_start << PAGE_SHIFT,
310 (table_end - table_start) << PAGE_SHIFT);
311
312 /* reserve kernel */
Andi Kleenceee8822006-08-30 19:37:12 +0200313 reserve_bootmem_generic(__pa_symbol(&_text),
314 __pa_symbol(&_end) - __pa_symbol(&_text));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
316 /*
317 * reserve physical page 0 - it's a special BIOS page on many boxes,
318 * enabling clean reboots, SMP operation, laptop functions.
319 */
320 reserve_bootmem_generic(0, PAGE_SIZE);
321
322 /* reserve ebda region */
Andi Kleenac71d122006-05-08 15:17:28 +0200323 if (ebda_addr)
324 reserve_bootmem_generic(ebda_addr, ebda_size);
Amul Shah076422d2007-02-13 13:26:19 +0100325#ifdef CONFIG_NUMA
326 /* reserve nodemap region */
327 if (nodemap_addr)
328 reserve_bootmem_generic(nodemap_addr, nodemap_size);
329#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
331#ifdef CONFIG_SMP
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 /* Reserve SMP trampoline */
Vivek Goyal90b1c202007-05-02 19:27:07 +0200333 reserve_bootmem_generic(SMP_TRAMPOLINE_BASE, 2*PAGE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334#endif
335
Len Brown673d5b42007-07-28 03:33:16 -0400336#ifdef CONFIG_ACPI_SLEEP
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 /*
338 * Reserve low memory region for sleep support.
339 */
340 acpi_reserve_bootmem();
341#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 /*
343 * Find and reserve possible boot-time SMP configuration:
344 */
345 find_smp_config();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346#ifdef CONFIG_BLK_DEV_INITRD
H. Peter Anvin30c82642007-10-15 17:13:22 -0700347 if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) {
348 unsigned long ramdisk_image = boot_params.hdr.ramdisk_image;
349 unsigned long ramdisk_size = boot_params.hdr.ramdisk_size;
350 unsigned long ramdisk_end = ramdisk_image + ramdisk_size;
351 unsigned long end_of_mem = end_pfn << PAGE_SHIFT;
352
353 if (ramdisk_end <= end_of_mem) {
354 reserve_bootmem_generic(ramdisk_image, ramdisk_size);
355 initrd_start = ramdisk_image + PAGE_OFFSET;
356 initrd_end = initrd_start+ramdisk_size;
357 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 printk(KERN_ERR "initrd extends beyond end of memory "
H. Peter Anvin30c82642007-10-15 17:13:22 -0700359 "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
360 ramdisk_end, end_of_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 initrd_start = 0;
362 }
363 }
364#endif
Eric W. Biederman5f5609d2005-06-25 14:58:04 -0700365#ifdef CONFIG_KEXEC
366 if (crashk_res.start != crashk_res.end) {
Amul Shah00212fe2006-06-25 05:49:31 -0700367 reserve_bootmem_generic(crashk_res.start,
Eric W. Biederman5f5609d2005-06-25 14:58:04 -0700368 crashk_res.end - crashk_res.start + 1);
369 }
370#endif
Eric W. Biederman0d317fb2005-08-06 13:47:36 -0600371
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 paging_init();
373
Andi Kleenf157cbb2006-09-26 10:52:41 +0200374#ifdef CONFIG_PCI
Andi Kleendfa46982006-09-26 10:52:30 +0200375 early_quirks();
Andi Kleenf157cbb2006-09-26 10:52:41 +0200376#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
Ashok Raj51f62e12006-03-25 16:29:28 +0100378 /*
379 * set this early, so we dont allocate cpu0
380 * if MADT list doesnt list BSP first
381 * mpparse.c/MP_processor_info() allocates logical cpu numbers.
382 */
383 cpu_set(0, cpu_present_map);
Len Brown888ba6c2005-08-24 12:07:20 -0400384#ifdef CONFIG_ACPI
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 /*
386 * Read APIC and some other early information from ACPI tables.
387 */
388 acpi_boot_init();
389#endif
390
Ravikiran Thirumalai05b3cbd2006-01-11 22:45:36 +0100391 init_cpu_to_node();
392
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 /*
394 * get boot-time SMP configuration:
395 */
396 if (smp_found_config)
397 get_smp_config();
398 init_apic_mappings();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399
400 /*
Andi Kleenfc986db2007-02-13 13:26:24 +0100401 * We trust e820 completely. No explicit ROM probing in memory.
402 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 e820_reserve_resources();
Rafael J. Wysockie8eff5a2006-09-25 23:32:46 -0700404 e820_mark_nosave_regions();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 {
407 unsigned i;
408 /* request I/O space for devices used on all i[345]86 PCs */
Andi Kleen9d0ef4f2006-09-30 01:47:55 +0200409 for (i = 0; i < ARRAY_SIZE(standard_io_resources); i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 request_resource(&ioport_resource, &standard_io_resources[i]);
411 }
412
Andi Kleena1e97782005-04-16 15:25:12 -0700413 e820_setup_gap();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415#ifdef CONFIG_VT
416#if defined(CONFIG_VGA_CONSOLE)
417 conswitchp = &vga_con;
418#elif defined(CONFIG_DUMMY_CONSOLE)
419 conswitchp = &dummy_con;
420#endif
421#endif
422}
423
Ashok Raje6982c62005-06-25 14:54:58 -0700424static int __cpuinit get_model_name(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425{
426 unsigned int *v;
427
Andi Kleenebfcaa92005-04-16 15:25:18 -0700428 if (c->extended_cpuid_level < 0x80000004)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 return 0;
430
431 v = (unsigned int *) c->x86_model_id;
432 cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
433 cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
434 cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
435 c->x86_model_id[48] = 0;
436 return 1;
437}
438
439
Ashok Raje6982c62005-06-25 14:54:58 -0700440static void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441{
442 unsigned int n, dummy, eax, ebx, ecx, edx;
443
Andi Kleenebfcaa92005-04-16 15:25:18 -0700444 n = c->extended_cpuid_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
446 if (n >= 0x80000005) {
447 cpuid(0x80000005, &dummy, &ebx, &ecx, &edx);
448 printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), D cache %dK (%d bytes/line)\n",
449 edx>>24, edx&0xFF, ecx>>24, ecx&0xFF);
450 c->x86_cache_size=(ecx>>24)+(edx>>24);
451 /* On K8 L1 TLB is inclusive, so don't count it */
452 c->x86_tlbsize = 0;
453 }
454
455 if (n >= 0x80000006) {
456 cpuid(0x80000006, &dummy, &ebx, &ecx, &edx);
457 ecx = cpuid_ecx(0x80000006);
458 c->x86_cache_size = ecx >> 16;
459 c->x86_tlbsize += ((ebx >> 16) & 0xfff) + (ebx & 0xfff);
460
461 printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n",
462 c->x86_cache_size, ecx & 0xFF);
463 }
464
465 if (n >= 0x80000007)
466 cpuid(0x80000007, &dummy, &dummy, &dummy, &c->x86_power);
467 if (n >= 0x80000008) {
468 cpuid(0x80000008, &eax, &dummy, &dummy, &dummy);
469 c->x86_virt_bits = (eax >> 8) & 0xff;
470 c->x86_phys_bits = eax & 0xff;
471 }
472}
473
Andi Kleen3f098c22005-09-12 18:49:24 +0200474#ifdef CONFIG_NUMA
475static int nearby_node(int apicid)
476{
477 int i;
478 for (i = apicid - 1; i >= 0; i--) {
479 int node = apicid_to_node[i];
480 if (node != NUMA_NO_NODE && node_online(node))
481 return node;
482 }
483 for (i = apicid + 1; i < MAX_LOCAL_APIC; i++) {
484 int node = apicid_to_node[i];
485 if (node != NUMA_NO_NODE && node_online(node))
486 return node;
487 }
488 return first_node(node_online_map); /* Shouldn't happen */
489}
490#endif
491
Andi Kleen63518642005-04-16 15:25:16 -0700492/*
493 * On a AMD dual core setup the lower bits of the APIC id distingush the cores.
494 * Assumes number of cores is a power of two.
495 */
496static void __init amd_detect_cmp(struct cpuinfo_x86 *c)
497{
498#ifdef CONFIG_SMP
Andi Kleenb41e2932005-05-20 14:27:55 -0700499 unsigned bits;
Andi Kleen3f098c22005-09-12 18:49:24 +0200500#ifdef CONFIG_NUMA
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200501 int cpu = smp_processor_id();
Andi Kleen3f098c22005-09-12 18:49:24 +0200502 int node = 0;
Ravikiran G Thirumalai60c1bc82006-03-25 16:30:04 +0100503 unsigned apicid = hard_smp_processor_id();
Andi Kleen3f098c22005-09-12 18:49:24 +0200504#endif
Andi Kleenfaee9a52006-06-26 13:56:10 +0200505 unsigned ecx = cpuid_ecx(0x80000008);
Andi Kleenb41e2932005-05-20 14:27:55 -0700506
Andi Kleenfaee9a52006-06-26 13:56:10 +0200507 c->x86_max_cores = (ecx & 0xff) + 1;
508
509 /* CPU telling us the core id bits shift? */
510 bits = (ecx >> 12) & 0xF;
511
512 /* Otherwise recompute */
513 if (bits == 0) {
514 while ((1 << bits) < c->x86_max_cores)
515 bits++;
516 }
Andi Kleenb41e2932005-05-20 14:27:55 -0700517
518 /* Low order bits define the core id (index of core in socket) */
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200519 c->cpu_core_id = c->phys_proc_id & ((1 << bits)-1);
Andi Kleenb41e2932005-05-20 14:27:55 -0700520 /* Convert the APIC ID into the socket ID */
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200521 c->phys_proc_id = phys_pkg_id(bits);
Andi Kleen63518642005-04-16 15:25:16 -0700522
523#ifdef CONFIG_NUMA
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200524 node = c->phys_proc_id;
Andi Kleen3f098c22005-09-12 18:49:24 +0200525 if (apicid_to_node[apicid] != NUMA_NO_NODE)
526 node = apicid_to_node[apicid];
527 if (!node_online(node)) {
528 /* Two possibilities here:
529 - The CPU is missing memory and no node was created.
530 In that case try picking one from a nearby CPU
531 - The APIC IDs differ from the HyperTransport node IDs
532 which the K8 northbridge parsing fills in.
533 Assume they are all increased by a constant offset,
534 but in the same order as the HT nodeids.
535 If that doesn't result in a usable node fall back to the
536 path for the previous case. */
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200537 int ht_nodeid = apicid - (cpu_data[0].phys_proc_id << bits);
Andi Kleen3f098c22005-09-12 18:49:24 +0200538 if (ht_nodeid >= 0 &&
539 apicid_to_node[ht_nodeid] != NUMA_NO_NODE)
540 node = apicid_to_node[ht_nodeid];
541 /* Pick a nearby node */
542 if (!node_online(node))
543 node = nearby_node(apicid);
544 }
Andi Kleen69d81fc2005-11-05 17:25:53 +0100545 numa_set_node(cpu, node);
Andi Kleena1586082005-05-16 21:53:21 -0700546
Rohit Sethe42f9432006-06-26 13:59:14 +0200547 printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
Andi Kleen3f098c22005-09-12 18:49:24 +0200548#endif
Andi Kleen63518642005-04-16 15:25:16 -0700549#endif
550}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551
Thomas Gleixnerfb79d222007-10-12 23:04:07 +0200552#define ENABLE_C1E_MASK 0x18000000
553#define CPUID_PROCESSOR_SIGNATURE 1
554#define CPUID_XFAM 0x0ff00000
555#define CPUID_XFAM_K8 0x00000000
556#define CPUID_XFAM_10H 0x00100000
557#define CPUID_XFAM_11H 0x00200000
558#define CPUID_XMOD 0x000f0000
559#define CPUID_XMOD_REV_F 0x00040000
560
561/* AMD systems with C1E don't have a working lAPIC timer. Check for that. */
562static __cpuinit int amd_apic_timer_broken(void)
563{
564 u32 lo, hi;
565 u32 eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
566 switch (eax & CPUID_XFAM) {
567 case CPUID_XFAM_K8:
568 if ((eax & CPUID_XMOD) < CPUID_XMOD_REV_F)
569 break;
570 case CPUID_XFAM_10H:
571 case CPUID_XFAM_11H:
572 rdmsr(MSR_K8_ENABLE_C1E, lo, hi);
573 if (lo & ENABLE_C1E_MASK)
574 return 1;
575 break;
576 default:
577 /* err on the side of caution */
578 return 1;
579 }
580 return 0;
581}
582
Magnus Dammed775042006-09-26 10:52:36 +0200583static void __cpuinit init_amd(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584{
Andi Kleen7bcd3f32006-02-03 21:51:02 +0100585 unsigned level;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586
Linus Torvaldsbc5e8fd2005-09-17 15:41:04 -0700587#ifdef CONFIG_SMP
588 unsigned long value;
589
Andi Kleen7d318d72005-09-29 22:05:55 +0200590 /*
591 * Disable TLB flush filter by setting HWCR.FFDIS on K8
592 * bit 6 of msr C001_0015
593 *
594 * Errata 63 for SH-B3 steppings
595 * Errata 122 for all steppings (F+ have it disabled by default)
596 */
597 if (c->x86 == 15) {
598 rdmsrl(MSR_K8_HWCR, value);
599 value |= 1 << 6;
600 wrmsrl(MSR_K8_HWCR, value);
601 }
Linus Torvaldsbc5e8fd2005-09-17 15:41:04 -0700602#endif
603
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 /* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
605 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
606 clear_bit(0*32+31, &c->x86_capability);
607
Andi Kleen7bcd3f32006-02-03 21:51:02 +0100608 /* On C+ stepping K8 rep microcode works well for copy/memset */
609 level = cpuid_eax(1);
610 if (c->x86 == 15 && ((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58))
611 set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability);
Andi Kleen99741fa2007-10-17 18:04:41 +0200612 if (c->x86 == 0x10 || c->x86 == 0x11)
Andi Kleen5b74e3a2007-07-21 17:09:57 +0200613 set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability);
Andi Kleen7bcd3f32006-02-03 21:51:02 +0100614
Andi Kleen18bd0572006-04-20 02:36:45 +0200615 /* Enable workaround for FXSAVE leak */
616 if (c->x86 >= 6)
617 set_bit(X86_FEATURE_FXSAVE_LEAK, &c->x86_capability);
618
Rohit Sethe42f9432006-06-26 13:59:14 +0200619 level = get_model_name(c);
620 if (!level) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 switch (c->x86) {
622 case 15:
623 /* Should distinguish Models here, but this is only
624 a fallback anyways. */
625 strcpy(c->x86_model_id, "Hammer");
626 break;
627 }
628 }
629 display_cacheinfo(c);
630
Andi Kleen130951c2006-01-11 22:42:02 +0100631 /* c->x86_power is 8000_0007 edx. Bit 8 is constant TSC */
632 if (c->x86_power & (1<<8))
633 set_bit(X86_FEATURE_CONSTANT_TSC, &c->x86_capability);
634
Andi Kleenfaee9a52006-06-26 13:56:10 +0200635 /* Multi core CPU? */
636 if (c->extended_cpuid_level >= 0x80000008)
Andi Kleen63518642005-04-16 15:25:16 -0700637 amd_detect_cmp(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
Andi Kleen67cddd92007-07-21 17:10:03 +0200639 if (c->extended_cpuid_level >= 0x80000006 &&
640 (cpuid_edx(0x80000006) & 0xf000))
641 num_cache_leaves = 4;
642 else
643 num_cache_leaves = 3;
Andi Kleen20493362006-09-26 10:52:41 +0200644
Andi Kleen0bd8acd2007-07-22 11:12:34 +0200645 if (c->x86 == 0xf || c->x86 == 0x10 || c->x86 == 0x11)
646 set_bit(X86_FEATURE_K8, &c->x86_capability);
647
Andi Kleen61677962006-12-07 02:14:12 +0100648 /* RDTSC can be speculated around */
649 clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
Andi Kleenf039b752007-05-02 19:27:12 +0200650
651 /* Family 10 doesn't support C states in MWAIT so don't use it */
652 if (c->x86 == 0x10 && !force_mwait)
653 clear_bit(X86_FEATURE_MWAIT, &c->x86_capability);
Thomas Gleixnerfb79d222007-10-12 23:04:07 +0200654
655 if (amd_apic_timer_broken())
656 disable_apic_timer = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657}
658
Ashok Raje6982c62005-06-25 14:54:58 -0700659static void __cpuinit detect_ht(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660{
661#ifdef CONFIG_SMP
662 u32 eax, ebx, ecx, edx;
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100663 int index_msb, core_bits;
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100664
665 cpuid(1, &eax, &ebx, &ecx, &edx);
666
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100667
Rohit Sethe42f9432006-06-26 13:59:14 +0200668 if (!cpu_has(c, X86_FEATURE_HT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 return;
Rohit Sethe42f9432006-06-26 13:59:14 +0200670 if (cpu_has(c, X86_FEATURE_CMP_LEGACY))
671 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 smp_num_siblings = (ebx & 0xff0000) >> 16;
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100674
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 if (smp_num_siblings == 1) {
676 printk(KERN_INFO "CPU: Hyper-Threading is disabled\n");
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100677 } else if (smp_num_siblings > 1 ) {
678
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 if (smp_num_siblings > NR_CPUS) {
680 printk(KERN_WARNING "CPU: Unsupported number of the siblings %d", smp_num_siblings);
681 smp_num_siblings = 1;
682 return;
683 }
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100684
685 index_msb = get_count_order(smp_num_siblings);
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200686 c->phys_proc_id = phys_pkg_id(index_msb);
Andi Kleen3dd9d512005-04-16 15:25:15 -0700687
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100688 smp_num_siblings = smp_num_siblings / c->x86_max_cores;
Andi Kleen3dd9d512005-04-16 15:25:15 -0700689
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100690 index_msb = get_count_order(smp_num_siblings) ;
Andi Kleen3dd9d512005-04-16 15:25:15 -0700691
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100692 core_bits = get_count_order(c->x86_max_cores);
Andi Kleen3dd9d512005-04-16 15:25:15 -0700693
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200694 c->cpu_core_id = phys_pkg_id(index_msb) &
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100695 ((1 << core_bits) - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 }
Rohit Sethe42f9432006-06-26 13:59:14 +0200697out:
698 if ((c->x86_max_cores * smp_num_siblings) > 1) {
699 printk(KERN_INFO "CPU: Physical Processor ID: %d\n", c->phys_proc_id);
700 printk(KERN_INFO "CPU: Processor Core ID: %d\n", c->cpu_core_id);
701 }
702
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703#endif
704}
705
Andi Kleen3dd9d512005-04-16 15:25:15 -0700706/*
707 * find out the number of processor cores on the die
708 */
Ashok Raje6982c62005-06-25 14:54:58 -0700709static int __cpuinit intel_num_cpu_cores(struct cpuinfo_x86 *c)
Andi Kleen3dd9d512005-04-16 15:25:15 -0700710{
Rohit Seth2bbc4192006-06-26 13:58:02 +0200711 unsigned int eax, t;
Andi Kleen3dd9d512005-04-16 15:25:15 -0700712
713 if (c->cpuid_level < 4)
714 return 1;
715
Rohit Seth2bbc4192006-06-26 13:58:02 +0200716 cpuid_count(4, 0, &eax, &t, &t, &t);
Andi Kleen3dd9d512005-04-16 15:25:15 -0700717
718 if (eax & 0x1f)
719 return ((eax >> 26) + 1);
720 else
721 return 1;
722}
723
Andi Kleendf0cc262005-09-12 18:49:24 +0200724static void srat_detect_node(void)
725{
726#ifdef CONFIG_NUMA
Ravikiran G Thirumalaiddea7be2005-10-03 10:36:28 -0700727 unsigned node;
Andi Kleendf0cc262005-09-12 18:49:24 +0200728 int cpu = smp_processor_id();
Rohit Sethe42f9432006-06-26 13:59:14 +0200729 int apicid = hard_smp_processor_id();
Andi Kleendf0cc262005-09-12 18:49:24 +0200730
731 /* Don't do the funky fallback heuristics the AMD version employs
732 for now. */
Rohit Sethe42f9432006-06-26 13:59:14 +0200733 node = apicid_to_node[apicid];
Andi Kleendf0cc262005-09-12 18:49:24 +0200734 if (node == NUMA_NO_NODE)
Daniel Yeisley0d015322006-05-30 22:47:57 +0200735 node = first_node(node_online_map);
Andi Kleen69d81fc2005-11-05 17:25:53 +0100736 numa_set_node(cpu, node);
Andi Kleendf0cc262005-09-12 18:49:24 +0200737
Andi Kleenc31fbb12006-09-26 10:52:33 +0200738 printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
Andi Kleendf0cc262005-09-12 18:49:24 +0200739#endif
740}
741
Ashok Raje6982c62005-06-25 14:54:58 -0700742static void __cpuinit init_intel(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743{
744 /* Cache sizes */
745 unsigned n;
746
747 init_intel_cacheinfo(c);
Venkatesh Pallipadi0080e662006-06-26 13:59:59 +0200748 if (c->cpuid_level > 9 ) {
749 unsigned eax = cpuid_eax(10);
750 /* Check for version and the number of counters */
751 if ((eax & 0xff) && (((eax>>8) & 0xff) > 1))
752 set_bit(X86_FEATURE_ARCH_PERFMON, &c->x86_capability);
753 }
754
Stephane Eranian36b2a8d2006-12-07 02:14:01 +0100755 if (cpu_has_ds) {
756 unsigned int l1, l2;
757 rdmsr(MSR_IA32_MISC_ENABLE, l1, l2);
Stephane Eranianee58fad2006-12-07 02:14:11 +0100758 if (!(l1 & (1<<11)))
759 set_bit(X86_FEATURE_BTS, c->x86_capability);
Stephane Eranian36b2a8d2006-12-07 02:14:01 +0100760 if (!(l1 & (1<<12)))
761 set_bit(X86_FEATURE_PEBS, c->x86_capability);
762 }
763
Andi Kleenebfcaa92005-04-16 15:25:18 -0700764 n = c->extended_cpuid_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 if (n >= 0x80000008) {
766 unsigned eax = cpuid_eax(0x80000008);
767 c->x86_virt_bits = (eax >> 8) & 0xff;
768 c->x86_phys_bits = eax & 0xff;
Shaohua Liaf9c1422005-11-05 17:25:54 +0100769 /* CPUID workaround for Intel 0F34 CPU */
770 if (c->x86_vendor == X86_VENDOR_INTEL &&
771 c->x86 == 0xF && c->x86_model == 0x3 &&
772 c->x86_mask == 0x4)
773 c->x86_phys_bits = 36;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 }
775
776 if (c->x86 == 15)
777 c->x86_cache_alignment = c->x86_clflush_size * 2;
Andi Kleen39b3a792006-01-11 22:42:45 +0100778 if ((c->x86 == 0xf && c->x86_model >= 0x03) ||
779 (c->x86 == 0x6 && c->x86_model >= 0x0e))
Andi Kleenc29601e2005-04-16 15:25:05 -0700780 set_bit(X86_FEATURE_CONSTANT_TSC, &c->x86_capability);
Andi Kleen27fbe5b2006-09-26 10:52:41 +0200781 if (c->x86 == 6)
782 set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability);
Arjan van de Venf3d73702006-12-07 02:14:12 +0100783 if (c->x86 == 15)
784 set_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
785 else
786 clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100787 c->x86_max_cores = intel_num_cpu_cores(c);
Andi Kleendf0cc262005-09-12 18:49:24 +0200788
789 srat_detect_node();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790}
791
Adrian Bunk672289e2005-09-10 00:27:21 -0700792static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793{
794 char *v = c->x86_vendor_id;
795
796 if (!strcmp(v, "AuthenticAMD"))
797 c->x86_vendor = X86_VENDOR_AMD;
798 else if (!strcmp(v, "GenuineIntel"))
799 c->x86_vendor = X86_VENDOR_INTEL;
800 else
801 c->x86_vendor = X86_VENDOR_UNKNOWN;
802}
803
804struct cpu_model_info {
805 int vendor;
806 int family;
807 char *model_names[16];
808};
809
810/* Do some early cpuid on the boot CPU to get some parameter that are
811 needed before check_bugs. Everything advanced is in identify_cpu
812 below. */
Ashok Raje6982c62005-06-25 14:54:58 -0700813void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814{
815 u32 tfms;
816
817 c->loops_per_jiffy = loops_per_jiffy;
818 c->x86_cache_size = -1;
819 c->x86_vendor = X86_VENDOR_UNKNOWN;
820 c->x86_model = c->x86_mask = 0; /* So far unknown... */
821 c->x86_vendor_id[0] = '\0'; /* Unset */
822 c->x86_model_id[0] = '\0'; /* Unset */
823 c->x86_clflush_size = 64;
824 c->x86_cache_alignment = c->x86_clflush_size;
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100825 c->x86_max_cores = 1;
Andi Kleenebfcaa92005-04-16 15:25:18 -0700826 c->extended_cpuid_level = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 memset(&c->x86_capability, 0, sizeof c->x86_capability);
828
829 /* Get vendor name */
830 cpuid(0x00000000, (unsigned int *)&c->cpuid_level,
831 (unsigned int *)&c->x86_vendor_id[0],
832 (unsigned int *)&c->x86_vendor_id[8],
833 (unsigned int *)&c->x86_vendor_id[4]);
834
835 get_cpu_vendor(c);
836
837 /* Initialize the standard set of capabilities */
838 /* Note that the vendor-specific code below might override */
839
840 /* Intel-defined flags: level 0x00000001 */
841 if (c->cpuid_level >= 0x00000001) {
842 __u32 misc;
843 cpuid(0x00000001, &tfms, &misc, &c->x86_capability[4],
844 &c->x86_capability[0]);
845 c->x86 = (tfms >> 8) & 0xf;
846 c->x86_model = (tfms >> 4) & 0xf;
847 c->x86_mask = tfms & 0xf;
Suresh Siddhaf5f786d2005-11-05 17:25:53 +0100848 if (c->x86 == 0xf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 c->x86 += (tfms >> 20) & 0xff;
Suresh Siddhaf5f786d2005-11-05 17:25:53 +0100850 if (c->x86 >= 0x6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 c->x86_model += ((tfms >> 16) & 0xF) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 if (c->x86_capability[0] & (1<<19))
853 c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 } else {
855 /* Have CPUID level 0 only - unheard of */
856 c->x86 = 4;
857 }
Andi Kleena1586082005-05-16 21:53:21 -0700858
859#ifdef CONFIG_SMP
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200860 c->phys_proc_id = (cpuid_ebx(1) >> 24) & 0xff;
Andi Kleena1586082005-05-16 21:53:21 -0700861#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862}
863
864/*
865 * This does the hard work of actually picking apart the CPU stuff...
866 */
Ashok Raje6982c62005-06-25 14:54:58 -0700867void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868{
869 int i;
870 u32 xlvl;
871
872 early_identify_cpu(c);
873
874 /* AMD-defined flags: level 0x80000001 */
875 xlvl = cpuid_eax(0x80000000);
Andi Kleenebfcaa92005-04-16 15:25:18 -0700876 c->extended_cpuid_level = xlvl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 if ((xlvl & 0xffff0000) == 0x80000000) {
878 if (xlvl >= 0x80000001) {
879 c->x86_capability[1] = cpuid_edx(0x80000001);
H. Peter Anvin5b7abc62005-05-01 08:58:49 -0700880 c->x86_capability[6] = cpuid_ecx(0x80000001);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 }
882 if (xlvl >= 0x80000004)
883 get_model_name(c); /* Default name */
884 }
885
886 /* Transmeta-defined flags: level 0x80860001 */
887 xlvl = cpuid_eax(0x80860000);
888 if ((xlvl & 0xffff0000) == 0x80860000) {
889 /* Don't set x86_cpuid_level here for now to not confuse. */
890 if (xlvl >= 0x80860001)
891 c->x86_capability[2] = cpuid_edx(0x80860001);
892 }
893
Venki Pallipadi1d679532007-07-11 12:18:32 -0700894 init_scattered_cpuid_features(c);
895
Siddha, Suresh B1e9f28f2006-03-27 01:15:22 -0800896 c->apicid = phys_pkg_id(0);
897
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 /*
899 * Vendor-specific initialization. In this section we
900 * canonicalize the feature flags, meaning if there are
901 * features a certain CPU supports which CPUID doesn't
902 * tell us, CPUID claiming incorrect flags, or other bugs,
903 * we handle them here.
904 *
905 * At the end of this section, c->x86_capability better
906 * indicate the features this CPU genuinely supports!
907 */
908 switch (c->x86_vendor) {
909 case X86_VENDOR_AMD:
910 init_amd(c);
911 break;
912
913 case X86_VENDOR_INTEL:
914 init_intel(c);
915 break;
916
917 case X86_VENDOR_UNKNOWN:
918 default:
919 display_cacheinfo(c);
920 break;
921 }
922
923 select_idle_routine(c);
924 detect_ht(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925
926 /*
927 * On SMP, boot_cpu_data holds the common feature set between
928 * all CPUs; so make sure that we indicate which features are
929 * common between the CPUs. The first time this routine gets
930 * executed, c == &boot_cpu_data.
931 */
932 if (c != &boot_cpu_data) {
933 /* AND the already accumulated flags with these */
934 for (i = 0 ; i < NCAPINTS ; i++)
935 boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
936 }
937
938#ifdef CONFIG_X86_MCE
939 mcheck_init(c);
940#endif
Andi Kleen8bd99482007-05-11 11:23:20 +0200941 if (c != &boot_cpu_data)
Shaohua Li3b520b22005-07-07 17:56:38 -0700942 mtrr_ap_init();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943#ifdef CONFIG_NUMA
Andi Kleen3019e8e2005-07-28 21:15:28 -0700944 numa_add_cpu(smp_processor_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945#endif
946}
947
948
Ashok Raje6982c62005-06-25 14:54:58 -0700949void __cpuinit print_cpu_info(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950{
951 if (c->x86_model_id[0])
952 printk("%s", c->x86_model_id);
953
954 if (c->x86_mask || c->cpuid_level >= 0)
955 printk(" stepping %02x\n", c->x86_mask);
956 else
957 printk("\n");
958}
959
960/*
961 * Get CPU information for use by the procfs.
962 */
963
964static int show_cpuinfo(struct seq_file *m, void *v)
965{
966 struct cpuinfo_x86 *c = v;
967
968 /*
969 * These flag bits must match the definitions in <asm/cpufeature.h>.
970 * NULL means this bit is undefined or reserved; either way it doesn't
971 * have meaning as far as Linux is concerned. Note that it's important
972 * to realize there is a difference between this table and CPUID -- if
973 * applications want to get the raw CPUID data, they should access
974 * /dev/cpu/<cpu_nr>/cpuid instead.
975 */
Jan Beulich121d7bf2007-10-17 18:04:37 +0200976 static const char *const x86_cap_flags[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 /* Intel-defined */
978 "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
979 "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
980 "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
H. Peter Anvinec481532007-07-11 12:18:29 -0700981 "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
983 /* AMD-defined */
Zwane Mwaikambo3c3b73b2005-05-01 08:58:51 -0700984 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
986 NULL, NULL, NULL, NULL, "nx", NULL, "mmxext", NULL,
Andi Kleenf790cd32007-02-13 13:26:25 +0100987 NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm",
988 "3dnowext", "3dnow",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989
990 /* Transmeta-defined */
991 "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
992 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
993 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
994 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
995
996 /* Other (Linux-defined) */
H. Peter Anvinec481532007-07-11 12:18:29 -0700997 "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr",
998 NULL, NULL, NULL, NULL,
999 "constant_tsc", "up", NULL, "arch_perfmon",
1000 "pebs", "bts", NULL, "sync_rdtsc",
1001 "rep_good", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1003
1004 /* Intel-defined (#2) */
Andi Kleen9d95dd82006-03-25 16:31:22 +01001005 "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est",
Dave Jonesdcf10302006-09-26 10:52:42 +02001006 "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
Andi Kleenf790cd32007-02-13 13:26:25 +01001007 NULL, NULL, "dca", NULL, NULL, NULL, NULL, "popcnt",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1009
H. Peter Anvin5b7abc62005-05-01 08:58:49 -07001010 /* VIA/Cyrix/Centaur-defined */
1011 NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
H. Peter Anvinec481532007-07-11 12:18:29 -07001012 "ace2", "ace2_en", "phe", "phe_en", "pmm", "pmm_en", NULL, NULL,
H. Peter Anvin5b7abc62005-05-01 08:58:49 -07001013 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1014 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1015
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 /* AMD-defined (#2) */
Andi Kleenf790cd32007-02-13 13:26:25 +01001017 "lahf_lm", "cmp_legacy", "svm", "extapic", "cr8_legacy",
1018 "altmovcr8", "abm", "sse4a",
1019 "misalignsse", "3dnowprefetch",
1020 "osvw", "ibs", NULL, NULL, NULL, NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
H. Peter Anvin5b7abc62005-05-01 08:58:49 -07001022 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Venki Pallipadi1d679532007-07-11 12:18:32 -07001023
1024 /* Auxiliary (Linux-defined) */
1025 "ida", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1026 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1027 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1028 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 };
Jan Beulich121d7bf2007-10-17 18:04:37 +02001030 static const char *const x86_power_flags[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 "ts", /* temperature sensor */
1032 "fid", /* frequency id control */
1033 "vid", /* voltage id control */
1034 "ttp", /* thermal trip */
1035 "tm",
Andi Kleen3f98bc42006-01-11 22:42:51 +01001036 "stc",
Andi Kleenf790cd32007-02-13 13:26:25 +01001037 "100mhzsteps",
1038 "hwpstate",
Joerg Roedeld8243952007-05-02 19:27:09 +02001039 "", /* tsc invariant mapped to constant_tsc */
1040 /* nothing */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 };
1042
1043
1044#ifdef CONFIG_SMP
1045 if (!cpu_online(c-cpu_data))
1046 return 0;
1047#endif
1048
1049 seq_printf(m,"processor\t: %u\n"
1050 "vendor_id\t: %s\n"
1051 "cpu family\t: %d\n"
1052 "model\t\t: %d\n"
1053 "model name\t: %s\n",
1054 (unsigned)(c-cpu_data),
1055 c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown",
1056 c->x86,
1057 (int)c->x86_model,
1058 c->x86_model_id[0] ? c->x86_model_id : "unknown");
1059
1060 if (c->x86_mask || c->cpuid_level >= 0)
1061 seq_printf(m, "stepping\t: %d\n", c->x86_mask);
1062 else
1063 seq_printf(m, "stepping\t: unknown\n");
1064
1065 if (cpu_has(c,X86_FEATURE_TSC)) {
Venkatesh Pallipadi95235ca2005-12-02 10:43:20 -08001066 unsigned int freq = cpufreq_quick_get((unsigned)(c-cpu_data));
1067 if (!freq)
1068 freq = cpu_khz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 seq_printf(m, "cpu MHz\t\t: %u.%03u\n",
Venkatesh Pallipadi95235ca2005-12-02 10:43:20 -08001070 freq / 1000, (freq % 1000));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 }
1072
1073 /* Cache size */
1074 if (c->x86_cache_size >= 0)
1075 seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size);
1076
1077#ifdef CONFIG_SMP
Siddha, Suresh B94605ef2005-11-05 17:25:54 +01001078 if (smp_num_siblings * c->x86_max_cores > 1) {
Andi Kleendb468682005-04-16 15:24:51 -07001079 int cpu = c - cpu_data;
Rohit Sethf3fa8eb2006-06-26 13:58:17 +02001080 seq_printf(m, "physical id\t: %d\n", c->phys_proc_id);
Mike Travis08357612007-10-16 01:24:04 -07001081 seq_printf(m, "siblings\t: %d\n",
1082 cpus_weight(per_cpu(cpu_core_map, cpu)));
Rohit Sethf3fa8eb2006-06-26 13:58:17 +02001083 seq_printf(m, "core id\t\t: %d\n", c->cpu_core_id);
Siddha, Suresh B94605ef2005-11-05 17:25:54 +01001084 seq_printf(m, "cpu cores\t: %d\n", c->booted_cores);
Andi Kleendb468682005-04-16 15:24:51 -07001085 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086#endif
1087
1088 seq_printf(m,
1089 "fpu\t\t: yes\n"
1090 "fpu_exception\t: yes\n"
1091 "cpuid level\t: %d\n"
1092 "wp\t\t: yes\n"
1093 "flags\t\t:",
1094 c->cpuid_level);
1095
1096 {
1097 int i;
1098 for ( i = 0 ; i < 32*NCAPINTS ; i++ )
Akinobu Mita3d1712c2006-03-24 03:15:11 -08001099 if (cpu_has(c, i) && x86_cap_flags[i] != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 seq_printf(m, " %s", x86_cap_flags[i]);
1101 }
1102
1103 seq_printf(m, "\nbogomips\t: %lu.%02lu\n",
1104 c->loops_per_jiffy/(500000/HZ),
1105 (c->loops_per_jiffy/(5000/HZ)) % 100);
1106
1107 if (c->x86_tlbsize > 0)
1108 seq_printf(m, "TLB size\t: %d 4K pages\n", c->x86_tlbsize);
1109 seq_printf(m, "clflush size\t: %d\n", c->x86_clflush_size);
1110 seq_printf(m, "cache_alignment\t: %d\n", c->x86_cache_alignment);
1111
1112 seq_printf(m, "address sizes\t: %u bits physical, %u bits virtual\n",
1113 c->x86_phys_bits, c->x86_virt_bits);
1114
1115 seq_printf(m, "power management:");
1116 {
1117 unsigned i;
1118 for (i = 0; i < 32; i++)
1119 if (c->x86_power & (1 << i)) {
Andi Kleen3f98bc42006-01-11 22:42:51 +01001120 if (i < ARRAY_SIZE(x86_power_flags) &&
1121 x86_power_flags[i])
1122 seq_printf(m, "%s%s",
1123 x86_power_flags[i][0]?" ":"",
1124 x86_power_flags[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 else
1126 seq_printf(m, " [%d]", i);
1127 }
1128 }
Andi Kleen3dd9d512005-04-16 15:25:15 -07001129
Siddha, Suresh Bd31ddaa2005-04-16 15:25:20 -07001130 seq_printf(m, "\n\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 return 0;
1133}
1134
1135static void *c_start(struct seq_file *m, loff_t *pos)
1136{
1137 return *pos < NR_CPUS ? cpu_data + *pos : NULL;
1138}
1139
1140static void *c_next(struct seq_file *m, void *v, loff_t *pos)
1141{
1142 ++*pos;
1143 return c_start(m, pos);
1144}
1145
1146static void c_stop(struct seq_file *m, void *v)
1147{
1148}
1149
1150struct seq_operations cpuinfo_op = {
1151 .start =c_start,
1152 .next = c_next,
1153 .stop = c_stop,
1154 .show = show_cpuinfo,
1155};