blob: 8159bf0be17aa61bed4b91bd1aa09c84f2814a96 [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
Len Brown888ba6c2005-08-24 12:07:20 -0400274#ifdef CONFIG_ACPI
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 /*
276 * Initialize the ACPI boot-time table parser (gets the RSDP and SDT).
277 * Call this early for SRAT node setup.
278 */
279 acpi_boot_table_init();
280#endif
281
Jan Beulichcaff0712006-09-26 10:52:31 +0200282 /* How many end-of-memory variables you have, grandma! */
283 max_low_pfn = end_pfn;
284 max_pfn = end_pfn;
285 high_memory = (void *)__va(end_pfn * PAGE_SIZE - 1) + 1;
286
Mel Gorman5cb248a2006-09-27 01:49:52 -0700287 /* Remove active ranges so rediscovery with NUMA-awareness happens */
288 remove_all_active_ranges();
289
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290#ifdef CONFIG_ACPI_NUMA
291 /*
292 * Parse SRAT to discover nodes.
293 */
294 acpi_numa_init();
295#endif
296
Matt Tolentino2b976902005-06-23 00:08:06 -0700297#ifdef CONFIG_NUMA
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 numa_initmem_init(0, end_pfn);
299#else
Matt Tolentinobbfceef2005-06-23 00:08:07 -0700300 contig_initmem_init(0, end_pfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301#endif
302
303 /* Reserve direct mapping */
304 reserve_bootmem_generic(table_start << PAGE_SHIFT,
305 (table_end - table_start) << PAGE_SHIFT);
306
307 /* reserve kernel */
Andi Kleenceee8822006-08-30 19:37:12 +0200308 reserve_bootmem_generic(__pa_symbol(&_text),
309 __pa_symbol(&_end) - __pa_symbol(&_text));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
311 /*
312 * reserve physical page 0 - it's a special BIOS page on many boxes,
313 * enabling clean reboots, SMP operation, laptop functions.
314 */
315 reserve_bootmem_generic(0, PAGE_SIZE);
316
317 /* reserve ebda region */
Andi Kleenac71d122006-05-08 15:17:28 +0200318 if (ebda_addr)
319 reserve_bootmem_generic(ebda_addr, ebda_size);
Amul Shah076422d2007-02-13 13:26:19 +0100320#ifdef CONFIG_NUMA
321 /* reserve nodemap region */
322 if (nodemap_addr)
323 reserve_bootmem_generic(nodemap_addr, nodemap_size);
324#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
326#ifdef CONFIG_SMP
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 /* Reserve SMP trampoline */
Vivek Goyal90b1c202007-05-02 19:27:07 +0200328 reserve_bootmem_generic(SMP_TRAMPOLINE_BASE, 2*PAGE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329#endif
330
Len Brown673d5b42007-07-28 03:33:16 -0400331#ifdef CONFIG_ACPI_SLEEP
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 /*
333 * Reserve low memory region for sleep support.
334 */
335 acpi_reserve_bootmem();
336#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 /*
338 * Find and reserve possible boot-time SMP configuration:
339 */
340 find_smp_config();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341#ifdef CONFIG_BLK_DEV_INITRD
H. Peter Anvin30c82642007-10-15 17:13:22 -0700342 if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) {
343 unsigned long ramdisk_image = boot_params.hdr.ramdisk_image;
344 unsigned long ramdisk_size = boot_params.hdr.ramdisk_size;
345 unsigned long ramdisk_end = ramdisk_image + ramdisk_size;
346 unsigned long end_of_mem = end_pfn << PAGE_SHIFT;
347
348 if (ramdisk_end <= end_of_mem) {
349 reserve_bootmem_generic(ramdisk_image, ramdisk_size);
350 initrd_start = ramdisk_image + PAGE_OFFSET;
351 initrd_end = initrd_start+ramdisk_size;
352 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 printk(KERN_ERR "initrd extends beyond end of memory "
H. Peter Anvin30c82642007-10-15 17:13:22 -0700354 "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
355 ramdisk_end, end_of_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 initrd_start = 0;
357 }
358 }
359#endif
Eric W. Biederman5f5609d2005-06-25 14:58:04 -0700360#ifdef CONFIG_KEXEC
361 if (crashk_res.start != crashk_res.end) {
Amul Shah00212fe2006-06-25 05:49:31 -0700362 reserve_bootmem_generic(crashk_res.start,
Eric W. Biederman5f5609d2005-06-25 14:58:04 -0700363 crashk_res.end - crashk_res.start + 1);
364 }
365#endif
Eric W. Biederman0d317fb2005-08-06 13:47:36 -0600366
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 paging_init();
368
Andi Kleenf157cbb2006-09-26 10:52:41 +0200369#ifdef CONFIG_PCI
Andi Kleendfa46982006-09-26 10:52:30 +0200370 early_quirks();
Andi Kleenf157cbb2006-09-26 10:52:41 +0200371#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
Ashok Raj51f62e12006-03-25 16:29:28 +0100373 /*
374 * set this early, so we dont allocate cpu0
375 * if MADT list doesnt list BSP first
376 * mpparse.c/MP_processor_info() allocates logical cpu numbers.
377 */
378 cpu_set(0, cpu_present_map);
Len Brown888ba6c2005-08-24 12:07:20 -0400379#ifdef CONFIG_ACPI
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 /*
381 * Read APIC and some other early information from ACPI tables.
382 */
383 acpi_boot_init();
384#endif
385
Ravikiran Thirumalai05b3cbd2006-01-11 22:45:36 +0100386 init_cpu_to_node();
387
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 /*
389 * get boot-time SMP configuration:
390 */
391 if (smp_found_config)
392 get_smp_config();
393 init_apic_mappings();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394
395 /*
Andi Kleenfc986db2007-02-13 13:26:24 +0100396 * We trust e820 completely. No explicit ROM probing in memory.
397 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 e820_reserve_resources();
Rafael J. Wysockie8eff5a2006-09-25 23:32:46 -0700399 e820_mark_nosave_regions();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 {
402 unsigned i;
403 /* request I/O space for devices used on all i[345]86 PCs */
Andi Kleen9d0ef4f2006-09-30 01:47:55 +0200404 for (i = 0; i < ARRAY_SIZE(standard_io_resources); i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 request_resource(&ioport_resource, &standard_io_resources[i]);
406 }
407
Andi Kleena1e97782005-04-16 15:25:12 -0700408 e820_setup_gap();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410#ifdef CONFIG_VT
411#if defined(CONFIG_VGA_CONSOLE)
412 conswitchp = &vga_con;
413#elif defined(CONFIG_DUMMY_CONSOLE)
414 conswitchp = &dummy_con;
415#endif
416#endif
417}
418
Ashok Raje6982c62005-06-25 14:54:58 -0700419static int __cpuinit get_model_name(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420{
421 unsigned int *v;
422
Andi Kleenebfcaa92005-04-16 15:25:18 -0700423 if (c->extended_cpuid_level < 0x80000004)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 return 0;
425
426 v = (unsigned int *) c->x86_model_id;
427 cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
428 cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
429 cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
430 c->x86_model_id[48] = 0;
431 return 1;
432}
433
434
Ashok Raje6982c62005-06-25 14:54:58 -0700435static void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436{
437 unsigned int n, dummy, eax, ebx, ecx, edx;
438
Andi Kleenebfcaa92005-04-16 15:25:18 -0700439 n = c->extended_cpuid_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440
441 if (n >= 0x80000005) {
442 cpuid(0x80000005, &dummy, &ebx, &ecx, &edx);
443 printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), D cache %dK (%d bytes/line)\n",
444 edx>>24, edx&0xFF, ecx>>24, ecx&0xFF);
445 c->x86_cache_size=(ecx>>24)+(edx>>24);
446 /* On K8 L1 TLB is inclusive, so don't count it */
447 c->x86_tlbsize = 0;
448 }
449
450 if (n >= 0x80000006) {
451 cpuid(0x80000006, &dummy, &ebx, &ecx, &edx);
452 ecx = cpuid_ecx(0x80000006);
453 c->x86_cache_size = ecx >> 16;
454 c->x86_tlbsize += ((ebx >> 16) & 0xfff) + (ebx & 0xfff);
455
456 printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n",
457 c->x86_cache_size, ecx & 0xFF);
458 }
459
460 if (n >= 0x80000007)
461 cpuid(0x80000007, &dummy, &dummy, &dummy, &c->x86_power);
462 if (n >= 0x80000008) {
463 cpuid(0x80000008, &eax, &dummy, &dummy, &dummy);
464 c->x86_virt_bits = (eax >> 8) & 0xff;
465 c->x86_phys_bits = eax & 0xff;
466 }
467}
468
Andi Kleen3f098c22005-09-12 18:49:24 +0200469#ifdef CONFIG_NUMA
470static int nearby_node(int apicid)
471{
472 int i;
473 for (i = apicid - 1; i >= 0; i--) {
474 int node = apicid_to_node[i];
475 if (node != NUMA_NO_NODE && node_online(node))
476 return node;
477 }
478 for (i = apicid + 1; i < MAX_LOCAL_APIC; i++) {
479 int node = apicid_to_node[i];
480 if (node != NUMA_NO_NODE && node_online(node))
481 return node;
482 }
483 return first_node(node_online_map); /* Shouldn't happen */
484}
485#endif
486
Andi Kleen63518642005-04-16 15:25:16 -0700487/*
488 * On a AMD dual core setup the lower bits of the APIC id distingush the cores.
489 * Assumes number of cores is a power of two.
490 */
491static void __init amd_detect_cmp(struct cpuinfo_x86 *c)
492{
493#ifdef CONFIG_SMP
Andi Kleenb41e2932005-05-20 14:27:55 -0700494 unsigned bits;
Andi Kleen3f098c22005-09-12 18:49:24 +0200495#ifdef CONFIG_NUMA
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200496 int cpu = smp_processor_id();
Andi Kleen3f098c22005-09-12 18:49:24 +0200497 int node = 0;
Ravikiran G Thirumalai60c1bc82006-03-25 16:30:04 +0100498 unsigned apicid = hard_smp_processor_id();
Andi Kleen3f098c22005-09-12 18:49:24 +0200499#endif
Andi Kleenfaee9a52006-06-26 13:56:10 +0200500 unsigned ecx = cpuid_ecx(0x80000008);
Andi Kleenb41e2932005-05-20 14:27:55 -0700501
Andi Kleenfaee9a52006-06-26 13:56:10 +0200502 c->x86_max_cores = (ecx & 0xff) + 1;
503
504 /* CPU telling us the core id bits shift? */
505 bits = (ecx >> 12) & 0xF;
506
507 /* Otherwise recompute */
508 if (bits == 0) {
509 while ((1 << bits) < c->x86_max_cores)
510 bits++;
511 }
Andi Kleenb41e2932005-05-20 14:27:55 -0700512
513 /* Low order bits define the core id (index of core in socket) */
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200514 c->cpu_core_id = c->phys_proc_id & ((1 << bits)-1);
Andi Kleenb41e2932005-05-20 14:27:55 -0700515 /* Convert the APIC ID into the socket ID */
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200516 c->phys_proc_id = phys_pkg_id(bits);
Andi Kleen63518642005-04-16 15:25:16 -0700517
518#ifdef CONFIG_NUMA
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200519 node = c->phys_proc_id;
Andi Kleen3f098c22005-09-12 18:49:24 +0200520 if (apicid_to_node[apicid] != NUMA_NO_NODE)
521 node = apicid_to_node[apicid];
522 if (!node_online(node)) {
523 /* Two possibilities here:
524 - The CPU is missing memory and no node was created.
525 In that case try picking one from a nearby CPU
526 - The APIC IDs differ from the HyperTransport node IDs
527 which the K8 northbridge parsing fills in.
528 Assume they are all increased by a constant offset,
529 but in the same order as the HT nodeids.
530 If that doesn't result in a usable node fall back to the
531 path for the previous case. */
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200532 int ht_nodeid = apicid - (cpu_data[0].phys_proc_id << bits);
Andi Kleen3f098c22005-09-12 18:49:24 +0200533 if (ht_nodeid >= 0 &&
534 apicid_to_node[ht_nodeid] != NUMA_NO_NODE)
535 node = apicid_to_node[ht_nodeid];
536 /* Pick a nearby node */
537 if (!node_online(node))
538 node = nearby_node(apicid);
539 }
Andi Kleen69d81fc2005-11-05 17:25:53 +0100540 numa_set_node(cpu, node);
Andi Kleena1586082005-05-16 21:53:21 -0700541
Rohit Sethe42f9432006-06-26 13:59:14 +0200542 printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
Andi Kleen3f098c22005-09-12 18:49:24 +0200543#endif
Andi Kleen63518642005-04-16 15:25:16 -0700544#endif
545}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546
Thomas Gleixnerfb79d222007-10-12 23:04:07 +0200547#define ENABLE_C1E_MASK 0x18000000
548#define CPUID_PROCESSOR_SIGNATURE 1
549#define CPUID_XFAM 0x0ff00000
550#define CPUID_XFAM_K8 0x00000000
551#define CPUID_XFAM_10H 0x00100000
552#define CPUID_XFAM_11H 0x00200000
553#define CPUID_XMOD 0x000f0000
554#define CPUID_XMOD_REV_F 0x00040000
555
556/* AMD systems with C1E don't have a working lAPIC timer. Check for that. */
557static __cpuinit int amd_apic_timer_broken(void)
558{
559 u32 lo, hi;
560 u32 eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
561 switch (eax & CPUID_XFAM) {
562 case CPUID_XFAM_K8:
563 if ((eax & CPUID_XMOD) < CPUID_XMOD_REV_F)
564 break;
565 case CPUID_XFAM_10H:
566 case CPUID_XFAM_11H:
567 rdmsr(MSR_K8_ENABLE_C1E, lo, hi);
568 if (lo & ENABLE_C1E_MASK)
569 return 1;
570 break;
571 default:
572 /* err on the side of caution */
573 return 1;
574 }
575 return 0;
576}
577
Magnus Dammed775042006-09-26 10:52:36 +0200578static void __cpuinit init_amd(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579{
Andi Kleen7bcd3f32006-02-03 21:51:02 +0100580 unsigned level;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581
Linus Torvaldsbc5e8fd2005-09-17 15:41:04 -0700582#ifdef CONFIG_SMP
583 unsigned long value;
584
Andi Kleen7d318d72005-09-29 22:05:55 +0200585 /*
586 * Disable TLB flush filter by setting HWCR.FFDIS on K8
587 * bit 6 of msr C001_0015
588 *
589 * Errata 63 for SH-B3 steppings
590 * Errata 122 for all steppings (F+ have it disabled by default)
591 */
592 if (c->x86 == 15) {
593 rdmsrl(MSR_K8_HWCR, value);
594 value |= 1 << 6;
595 wrmsrl(MSR_K8_HWCR, value);
596 }
Linus Torvaldsbc5e8fd2005-09-17 15:41:04 -0700597#endif
598
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 /* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
600 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
601 clear_bit(0*32+31, &c->x86_capability);
602
Andi Kleen7bcd3f32006-02-03 21:51:02 +0100603 /* On C+ stepping K8 rep microcode works well for copy/memset */
604 level = cpuid_eax(1);
605 if (c->x86 == 15 && ((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58))
606 set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability);
Andi Kleen5b74e3a2007-07-21 17:09:57 +0200607 if (c->x86 == 0x10)
608 set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability);
Andi Kleen7bcd3f32006-02-03 21:51:02 +0100609
Andi Kleen18bd0572006-04-20 02:36:45 +0200610 /* Enable workaround for FXSAVE leak */
611 if (c->x86 >= 6)
612 set_bit(X86_FEATURE_FXSAVE_LEAK, &c->x86_capability);
613
Rohit Sethe42f9432006-06-26 13:59:14 +0200614 level = get_model_name(c);
615 if (!level) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 switch (c->x86) {
617 case 15:
618 /* Should distinguish Models here, but this is only
619 a fallback anyways. */
620 strcpy(c->x86_model_id, "Hammer");
621 break;
622 }
623 }
624 display_cacheinfo(c);
625
Andi Kleen130951c2006-01-11 22:42:02 +0100626 /* c->x86_power is 8000_0007 edx. Bit 8 is constant TSC */
627 if (c->x86_power & (1<<8))
628 set_bit(X86_FEATURE_CONSTANT_TSC, &c->x86_capability);
629
Andi Kleenfaee9a52006-06-26 13:56:10 +0200630 /* Multi core CPU? */
631 if (c->extended_cpuid_level >= 0x80000008)
Andi Kleen63518642005-04-16 15:25:16 -0700632 amd_detect_cmp(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633
Andi Kleen67cddd92007-07-21 17:10:03 +0200634 if (c->extended_cpuid_level >= 0x80000006 &&
635 (cpuid_edx(0x80000006) & 0xf000))
636 num_cache_leaves = 4;
637 else
638 num_cache_leaves = 3;
Andi Kleen20493362006-09-26 10:52:41 +0200639
Andi Kleen0bd8acd2007-07-22 11:12:34 +0200640 if (c->x86 == 0xf || c->x86 == 0x10 || c->x86 == 0x11)
641 set_bit(X86_FEATURE_K8, &c->x86_capability);
642
Andi Kleen61677962006-12-07 02:14:12 +0100643 /* RDTSC can be speculated around */
644 clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
Andi Kleenf039b752007-05-02 19:27:12 +0200645
646 /* Family 10 doesn't support C states in MWAIT so don't use it */
647 if (c->x86 == 0x10 && !force_mwait)
648 clear_bit(X86_FEATURE_MWAIT, &c->x86_capability);
Thomas Gleixnerfb79d222007-10-12 23:04:07 +0200649
650 if (amd_apic_timer_broken())
651 disable_apic_timer = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652}
653
Ashok Raje6982c62005-06-25 14:54:58 -0700654static void __cpuinit detect_ht(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655{
656#ifdef CONFIG_SMP
657 u32 eax, ebx, ecx, edx;
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100658 int index_msb, core_bits;
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100659
660 cpuid(1, &eax, &ebx, &ecx, &edx);
661
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100662
Rohit Sethe42f9432006-06-26 13:59:14 +0200663 if (!cpu_has(c, X86_FEATURE_HT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 return;
Rohit Sethe42f9432006-06-26 13:59:14 +0200665 if (cpu_has(c, X86_FEATURE_CMP_LEGACY))
666 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 smp_num_siblings = (ebx & 0xff0000) >> 16;
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100669
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 if (smp_num_siblings == 1) {
671 printk(KERN_INFO "CPU: Hyper-Threading is disabled\n");
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100672 } else if (smp_num_siblings > 1 ) {
673
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 if (smp_num_siblings > NR_CPUS) {
675 printk(KERN_WARNING "CPU: Unsupported number of the siblings %d", smp_num_siblings);
676 smp_num_siblings = 1;
677 return;
678 }
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100679
680 index_msb = get_count_order(smp_num_siblings);
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200681 c->phys_proc_id = phys_pkg_id(index_msb);
Andi Kleen3dd9d512005-04-16 15:25:15 -0700682
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100683 smp_num_siblings = smp_num_siblings / c->x86_max_cores;
Andi Kleen3dd9d512005-04-16 15:25:15 -0700684
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100685 index_msb = get_count_order(smp_num_siblings) ;
Andi Kleen3dd9d512005-04-16 15:25:15 -0700686
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100687 core_bits = get_count_order(c->x86_max_cores);
Andi Kleen3dd9d512005-04-16 15:25:15 -0700688
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200689 c->cpu_core_id = phys_pkg_id(index_msb) &
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100690 ((1 << core_bits) - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 }
Rohit Sethe42f9432006-06-26 13:59:14 +0200692out:
693 if ((c->x86_max_cores * smp_num_siblings) > 1) {
694 printk(KERN_INFO "CPU: Physical Processor ID: %d\n", c->phys_proc_id);
695 printk(KERN_INFO "CPU: Processor Core ID: %d\n", c->cpu_core_id);
696 }
697
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698#endif
699}
700
Andi Kleen3dd9d512005-04-16 15:25:15 -0700701/*
702 * find out the number of processor cores on the die
703 */
Ashok Raje6982c62005-06-25 14:54:58 -0700704static int __cpuinit intel_num_cpu_cores(struct cpuinfo_x86 *c)
Andi Kleen3dd9d512005-04-16 15:25:15 -0700705{
Rohit Seth2bbc4192006-06-26 13:58:02 +0200706 unsigned int eax, t;
Andi Kleen3dd9d512005-04-16 15:25:15 -0700707
708 if (c->cpuid_level < 4)
709 return 1;
710
Rohit Seth2bbc4192006-06-26 13:58:02 +0200711 cpuid_count(4, 0, &eax, &t, &t, &t);
Andi Kleen3dd9d512005-04-16 15:25:15 -0700712
713 if (eax & 0x1f)
714 return ((eax >> 26) + 1);
715 else
716 return 1;
717}
718
Andi Kleendf0cc262005-09-12 18:49:24 +0200719static void srat_detect_node(void)
720{
721#ifdef CONFIG_NUMA
Ravikiran G Thirumalaiddea7be2005-10-03 10:36:28 -0700722 unsigned node;
Andi Kleendf0cc262005-09-12 18:49:24 +0200723 int cpu = smp_processor_id();
Rohit Sethe42f9432006-06-26 13:59:14 +0200724 int apicid = hard_smp_processor_id();
Andi Kleendf0cc262005-09-12 18:49:24 +0200725
726 /* Don't do the funky fallback heuristics the AMD version employs
727 for now. */
Rohit Sethe42f9432006-06-26 13:59:14 +0200728 node = apicid_to_node[apicid];
Andi Kleendf0cc262005-09-12 18:49:24 +0200729 if (node == NUMA_NO_NODE)
Daniel Yeisley0d015322006-05-30 22:47:57 +0200730 node = first_node(node_online_map);
Andi Kleen69d81fc2005-11-05 17:25:53 +0100731 numa_set_node(cpu, node);
Andi Kleendf0cc262005-09-12 18:49:24 +0200732
Andi Kleenc31fbb12006-09-26 10:52:33 +0200733 printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
Andi Kleendf0cc262005-09-12 18:49:24 +0200734#endif
735}
736
Ashok Raje6982c62005-06-25 14:54:58 -0700737static void __cpuinit init_intel(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738{
739 /* Cache sizes */
740 unsigned n;
741
742 init_intel_cacheinfo(c);
Venkatesh Pallipadi0080e662006-06-26 13:59:59 +0200743 if (c->cpuid_level > 9 ) {
744 unsigned eax = cpuid_eax(10);
745 /* Check for version and the number of counters */
746 if ((eax & 0xff) && (((eax>>8) & 0xff) > 1))
747 set_bit(X86_FEATURE_ARCH_PERFMON, &c->x86_capability);
748 }
749
Stephane Eranian36b2a8d2006-12-07 02:14:01 +0100750 if (cpu_has_ds) {
751 unsigned int l1, l2;
752 rdmsr(MSR_IA32_MISC_ENABLE, l1, l2);
Stephane Eranianee58fad2006-12-07 02:14:11 +0100753 if (!(l1 & (1<<11)))
754 set_bit(X86_FEATURE_BTS, c->x86_capability);
Stephane Eranian36b2a8d2006-12-07 02:14:01 +0100755 if (!(l1 & (1<<12)))
756 set_bit(X86_FEATURE_PEBS, c->x86_capability);
757 }
758
Andi Kleenebfcaa92005-04-16 15:25:18 -0700759 n = c->extended_cpuid_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 if (n >= 0x80000008) {
761 unsigned eax = cpuid_eax(0x80000008);
762 c->x86_virt_bits = (eax >> 8) & 0xff;
763 c->x86_phys_bits = eax & 0xff;
Shaohua Liaf9c1422005-11-05 17:25:54 +0100764 /* CPUID workaround for Intel 0F34 CPU */
765 if (c->x86_vendor == X86_VENDOR_INTEL &&
766 c->x86 == 0xF && c->x86_model == 0x3 &&
767 c->x86_mask == 0x4)
768 c->x86_phys_bits = 36;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 }
770
771 if (c->x86 == 15)
772 c->x86_cache_alignment = c->x86_clflush_size * 2;
Andi Kleen39b3a792006-01-11 22:42:45 +0100773 if ((c->x86 == 0xf && c->x86_model >= 0x03) ||
774 (c->x86 == 0x6 && c->x86_model >= 0x0e))
Andi Kleenc29601e2005-04-16 15:25:05 -0700775 set_bit(X86_FEATURE_CONSTANT_TSC, &c->x86_capability);
Andi Kleen27fbe5b2006-09-26 10:52:41 +0200776 if (c->x86 == 6)
777 set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability);
Arjan van de Venf3d73702006-12-07 02:14:12 +0100778 if (c->x86 == 15)
779 set_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
780 else
781 clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100782 c->x86_max_cores = intel_num_cpu_cores(c);
Andi Kleendf0cc262005-09-12 18:49:24 +0200783
784 srat_detect_node();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785}
786
Adrian Bunk672289e2005-09-10 00:27:21 -0700787static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788{
789 char *v = c->x86_vendor_id;
790
791 if (!strcmp(v, "AuthenticAMD"))
792 c->x86_vendor = X86_VENDOR_AMD;
793 else if (!strcmp(v, "GenuineIntel"))
794 c->x86_vendor = X86_VENDOR_INTEL;
795 else
796 c->x86_vendor = X86_VENDOR_UNKNOWN;
797}
798
799struct cpu_model_info {
800 int vendor;
801 int family;
802 char *model_names[16];
803};
804
805/* Do some early cpuid on the boot CPU to get some parameter that are
806 needed before check_bugs. Everything advanced is in identify_cpu
807 below. */
Ashok Raje6982c62005-06-25 14:54:58 -0700808void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809{
810 u32 tfms;
811
812 c->loops_per_jiffy = loops_per_jiffy;
813 c->x86_cache_size = -1;
814 c->x86_vendor = X86_VENDOR_UNKNOWN;
815 c->x86_model = c->x86_mask = 0; /* So far unknown... */
816 c->x86_vendor_id[0] = '\0'; /* Unset */
817 c->x86_model_id[0] = '\0'; /* Unset */
818 c->x86_clflush_size = 64;
819 c->x86_cache_alignment = c->x86_clflush_size;
Siddha, Suresh B94605ef2005-11-05 17:25:54 +0100820 c->x86_max_cores = 1;
Andi Kleenebfcaa92005-04-16 15:25:18 -0700821 c->extended_cpuid_level = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 memset(&c->x86_capability, 0, sizeof c->x86_capability);
823
824 /* Get vendor name */
825 cpuid(0x00000000, (unsigned int *)&c->cpuid_level,
826 (unsigned int *)&c->x86_vendor_id[0],
827 (unsigned int *)&c->x86_vendor_id[8],
828 (unsigned int *)&c->x86_vendor_id[4]);
829
830 get_cpu_vendor(c);
831
832 /* Initialize the standard set of capabilities */
833 /* Note that the vendor-specific code below might override */
834
835 /* Intel-defined flags: level 0x00000001 */
836 if (c->cpuid_level >= 0x00000001) {
837 __u32 misc;
838 cpuid(0x00000001, &tfms, &misc, &c->x86_capability[4],
839 &c->x86_capability[0]);
840 c->x86 = (tfms >> 8) & 0xf;
841 c->x86_model = (tfms >> 4) & 0xf;
842 c->x86_mask = tfms & 0xf;
Suresh Siddhaf5f786d2005-11-05 17:25:53 +0100843 if (c->x86 == 0xf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 c->x86 += (tfms >> 20) & 0xff;
Suresh Siddhaf5f786d2005-11-05 17:25:53 +0100845 if (c->x86 >= 0x6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 c->x86_model += ((tfms >> 16) & 0xF) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 if (c->x86_capability[0] & (1<<19))
848 c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 } else {
850 /* Have CPUID level 0 only - unheard of */
851 c->x86 = 4;
852 }
Andi Kleena1586082005-05-16 21:53:21 -0700853
854#ifdef CONFIG_SMP
Rohit Sethf3fa8eb2006-06-26 13:58:17 +0200855 c->phys_proc_id = (cpuid_ebx(1) >> 24) & 0xff;
Andi Kleena1586082005-05-16 21:53:21 -0700856#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857}
858
859/*
860 * This does the hard work of actually picking apart the CPU stuff...
861 */
Ashok Raje6982c62005-06-25 14:54:58 -0700862void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863{
864 int i;
865 u32 xlvl;
866
867 early_identify_cpu(c);
868
869 /* AMD-defined flags: level 0x80000001 */
870 xlvl = cpuid_eax(0x80000000);
Andi Kleenebfcaa92005-04-16 15:25:18 -0700871 c->extended_cpuid_level = xlvl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 if ((xlvl & 0xffff0000) == 0x80000000) {
873 if (xlvl >= 0x80000001) {
874 c->x86_capability[1] = cpuid_edx(0x80000001);
H. Peter Anvin5b7abc62005-05-01 08:58:49 -0700875 c->x86_capability[6] = cpuid_ecx(0x80000001);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 }
877 if (xlvl >= 0x80000004)
878 get_model_name(c); /* Default name */
879 }
880
881 /* Transmeta-defined flags: level 0x80860001 */
882 xlvl = cpuid_eax(0x80860000);
883 if ((xlvl & 0xffff0000) == 0x80860000) {
884 /* Don't set x86_cpuid_level here for now to not confuse. */
885 if (xlvl >= 0x80860001)
886 c->x86_capability[2] = cpuid_edx(0x80860001);
887 }
888
Venki Pallipadi1d679532007-07-11 12:18:32 -0700889 init_scattered_cpuid_features(c);
890
Siddha, Suresh B1e9f28f2006-03-27 01:15:22 -0800891 c->apicid = phys_pkg_id(0);
892
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 /*
894 * Vendor-specific initialization. In this section we
895 * canonicalize the feature flags, meaning if there are
896 * features a certain CPU supports which CPUID doesn't
897 * tell us, CPUID claiming incorrect flags, or other bugs,
898 * we handle them here.
899 *
900 * At the end of this section, c->x86_capability better
901 * indicate the features this CPU genuinely supports!
902 */
903 switch (c->x86_vendor) {
904 case X86_VENDOR_AMD:
905 init_amd(c);
906 break;
907
908 case X86_VENDOR_INTEL:
909 init_intel(c);
910 break;
911
912 case X86_VENDOR_UNKNOWN:
913 default:
914 display_cacheinfo(c);
915 break;
916 }
917
918 select_idle_routine(c);
919 detect_ht(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
921 /*
922 * On SMP, boot_cpu_data holds the common feature set between
923 * all CPUs; so make sure that we indicate which features are
924 * common between the CPUs. The first time this routine gets
925 * executed, c == &boot_cpu_data.
926 */
927 if (c != &boot_cpu_data) {
928 /* AND the already accumulated flags with these */
929 for (i = 0 ; i < NCAPINTS ; i++)
930 boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
931 }
932
933#ifdef CONFIG_X86_MCE
934 mcheck_init(c);
935#endif
Andi Kleen8bd99482007-05-11 11:23:20 +0200936 if (c != &boot_cpu_data)
Shaohua Li3b520b22005-07-07 17:56:38 -0700937 mtrr_ap_init();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938#ifdef CONFIG_NUMA
Andi Kleen3019e8e2005-07-28 21:15:28 -0700939 numa_add_cpu(smp_processor_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940#endif
941}
942
943
Ashok Raje6982c62005-06-25 14:54:58 -0700944void __cpuinit print_cpu_info(struct cpuinfo_x86 *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945{
946 if (c->x86_model_id[0])
947 printk("%s", c->x86_model_id);
948
949 if (c->x86_mask || c->cpuid_level >= 0)
950 printk(" stepping %02x\n", c->x86_mask);
951 else
952 printk("\n");
953}
954
955/*
956 * Get CPU information for use by the procfs.
957 */
958
959static int show_cpuinfo(struct seq_file *m, void *v)
960{
961 struct cpuinfo_x86 *c = v;
962
963 /*
964 * These flag bits must match the definitions in <asm/cpufeature.h>.
965 * NULL means this bit is undefined or reserved; either way it doesn't
966 * have meaning as far as Linux is concerned. Note that it's important
967 * to realize there is a difference between this table and CPUID -- if
968 * applications want to get the raw CPUID data, they should access
969 * /dev/cpu/<cpu_nr>/cpuid instead.
970 */
971 static char *x86_cap_flags[] = {
972 /* Intel-defined */
973 "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
974 "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
975 "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
H. Peter Anvinec481532007-07-11 12:18:29 -0700976 "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
978 /* AMD-defined */
Zwane Mwaikambo3c3b73b2005-05-01 08:58:51 -0700979 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
981 NULL, NULL, NULL, NULL, "nx", NULL, "mmxext", NULL,
Andi Kleenf790cd32007-02-13 13:26:25 +0100982 NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm",
983 "3dnowext", "3dnow",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
985 /* Transmeta-defined */
986 "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
987 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
988 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
989 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
990
991 /* Other (Linux-defined) */
H. Peter Anvinec481532007-07-11 12:18:29 -0700992 "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr",
993 NULL, NULL, NULL, NULL,
994 "constant_tsc", "up", NULL, "arch_perfmon",
995 "pebs", "bts", NULL, "sync_rdtsc",
996 "rep_good", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
998
999 /* Intel-defined (#2) */
Andi Kleen9d95dd82006-03-25 16:31:22 +01001000 "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est",
Dave Jonesdcf10302006-09-26 10:52:42 +02001001 "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
Andi Kleenf790cd32007-02-13 13:26:25 +01001002 NULL, NULL, "dca", NULL, NULL, NULL, NULL, "popcnt",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1004
H. Peter Anvin5b7abc62005-05-01 08:58:49 -07001005 /* VIA/Cyrix/Centaur-defined */
1006 NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
H. Peter Anvinec481532007-07-11 12:18:29 -07001007 "ace2", "ace2_en", "phe", "phe_en", "pmm", "pmm_en", NULL, NULL,
H. Peter Anvin5b7abc62005-05-01 08:58:49 -07001008 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1009 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1010
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 /* AMD-defined (#2) */
Andi Kleenf790cd32007-02-13 13:26:25 +01001012 "lahf_lm", "cmp_legacy", "svm", "extapic", "cr8_legacy",
1013 "altmovcr8", "abm", "sse4a",
1014 "misalignsse", "3dnowprefetch",
1015 "osvw", "ibs", NULL, NULL, NULL, NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
H. Peter Anvin5b7abc62005-05-01 08:58:49 -07001017 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Venki Pallipadi1d679532007-07-11 12:18:32 -07001018
1019 /* Auxiliary (Linux-defined) */
1020 "ida", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1021 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1022 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1023 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 };
1025 static char *x86_power_flags[] = {
1026 "ts", /* temperature sensor */
1027 "fid", /* frequency id control */
1028 "vid", /* voltage id control */
1029 "ttp", /* thermal trip */
1030 "tm",
Andi Kleen3f98bc42006-01-11 22:42:51 +01001031 "stc",
Andi Kleenf790cd32007-02-13 13:26:25 +01001032 "100mhzsteps",
1033 "hwpstate",
Joerg Roedeld8243952007-05-02 19:27:09 +02001034 "", /* tsc invariant mapped to constant_tsc */
1035 /* nothing */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 };
1037
1038
1039#ifdef CONFIG_SMP
1040 if (!cpu_online(c-cpu_data))
1041 return 0;
1042#endif
1043
1044 seq_printf(m,"processor\t: %u\n"
1045 "vendor_id\t: %s\n"
1046 "cpu family\t: %d\n"
1047 "model\t\t: %d\n"
1048 "model name\t: %s\n",
1049 (unsigned)(c-cpu_data),
1050 c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown",
1051 c->x86,
1052 (int)c->x86_model,
1053 c->x86_model_id[0] ? c->x86_model_id : "unknown");
1054
1055 if (c->x86_mask || c->cpuid_level >= 0)
1056 seq_printf(m, "stepping\t: %d\n", c->x86_mask);
1057 else
1058 seq_printf(m, "stepping\t: unknown\n");
1059
1060 if (cpu_has(c,X86_FEATURE_TSC)) {
Venkatesh Pallipadi95235ca2005-12-02 10:43:20 -08001061 unsigned int freq = cpufreq_quick_get((unsigned)(c-cpu_data));
1062 if (!freq)
1063 freq = cpu_khz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 seq_printf(m, "cpu MHz\t\t: %u.%03u\n",
Venkatesh Pallipadi95235ca2005-12-02 10:43:20 -08001065 freq / 1000, (freq % 1000));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 }
1067
1068 /* Cache size */
1069 if (c->x86_cache_size >= 0)
1070 seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size);
1071
1072#ifdef CONFIG_SMP
Siddha, Suresh B94605ef2005-11-05 17:25:54 +01001073 if (smp_num_siblings * c->x86_max_cores > 1) {
Andi Kleendb468682005-04-16 15:24:51 -07001074 int cpu = c - cpu_data;
Rohit Sethf3fa8eb2006-06-26 13:58:17 +02001075 seq_printf(m, "physical id\t: %d\n", c->phys_proc_id);
Mike Travis08357612007-10-16 01:24:04 -07001076 seq_printf(m, "siblings\t: %d\n",
1077 cpus_weight(per_cpu(cpu_core_map, cpu)));
Rohit Sethf3fa8eb2006-06-26 13:58:17 +02001078 seq_printf(m, "core id\t\t: %d\n", c->cpu_core_id);
Siddha, Suresh B94605ef2005-11-05 17:25:54 +01001079 seq_printf(m, "cpu cores\t: %d\n", c->booted_cores);
Andi Kleendb468682005-04-16 15:24:51 -07001080 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081#endif
1082
1083 seq_printf(m,
1084 "fpu\t\t: yes\n"
1085 "fpu_exception\t: yes\n"
1086 "cpuid level\t: %d\n"
1087 "wp\t\t: yes\n"
1088 "flags\t\t:",
1089 c->cpuid_level);
1090
1091 {
1092 int i;
1093 for ( i = 0 ; i < 32*NCAPINTS ; i++ )
Akinobu Mita3d1712c2006-03-24 03:15:11 -08001094 if (cpu_has(c, i) && x86_cap_flags[i] != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 seq_printf(m, " %s", x86_cap_flags[i]);
1096 }
1097
1098 seq_printf(m, "\nbogomips\t: %lu.%02lu\n",
1099 c->loops_per_jiffy/(500000/HZ),
1100 (c->loops_per_jiffy/(5000/HZ)) % 100);
1101
1102 if (c->x86_tlbsize > 0)
1103 seq_printf(m, "TLB size\t: %d 4K pages\n", c->x86_tlbsize);
1104 seq_printf(m, "clflush size\t: %d\n", c->x86_clflush_size);
1105 seq_printf(m, "cache_alignment\t: %d\n", c->x86_cache_alignment);
1106
1107 seq_printf(m, "address sizes\t: %u bits physical, %u bits virtual\n",
1108 c->x86_phys_bits, c->x86_virt_bits);
1109
1110 seq_printf(m, "power management:");
1111 {
1112 unsigned i;
1113 for (i = 0; i < 32; i++)
1114 if (c->x86_power & (1 << i)) {
Andi Kleen3f98bc42006-01-11 22:42:51 +01001115 if (i < ARRAY_SIZE(x86_power_flags) &&
1116 x86_power_flags[i])
1117 seq_printf(m, "%s%s",
1118 x86_power_flags[i][0]?" ":"",
1119 x86_power_flags[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 else
1121 seq_printf(m, " [%d]", i);
1122 }
1123 }
Andi Kleen3dd9d512005-04-16 15:25:15 -07001124
Siddha, Suresh Bd31ddaa2005-04-16 15:25:20 -07001125 seq_printf(m, "\n\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 return 0;
1128}
1129
1130static void *c_start(struct seq_file *m, loff_t *pos)
1131{
1132 return *pos < NR_CPUS ? cpu_data + *pos : NULL;
1133}
1134
1135static void *c_next(struct seq_file *m, void *v, loff_t *pos)
1136{
1137 ++*pos;
1138 return c_start(m, pos);
1139}
1140
1141static void c_stop(struct seq_file *m, void *v)
1142{
1143}
1144
1145struct seq_operations cpuinfo_op = {
1146 .start =c_start,
1147 .next = c_next,
1148 .stop = c_stop,
1149 .show = show_cpuinfo,
1150};