diff options
Diffstat (limited to 'arch/i386/kernel/setup.c')
-rw-r--r-- | arch/i386/kernel/setup.c | 594 |
1 files changed, 518 insertions, 76 deletions
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index c0721b482..88ba3feeb 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -14,6 +14,17 @@ * Bart Hartgers <bart@etpmod.phys.tue.nl>, May 1999. * * Intel Mobile Pentium II detection fix. Sean Gilley, June 1999. + * + * IDT Winchip tweaks, misc clean ups. + * Dave Jones <dave@powertweak.com>, August 1999 + * + * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 + * + * Better detection of Centaur/IDT WinChip models. + * Bart Hartgers <bart@etpmod.phys.tue.nl>, August 1999. + * + * Memory region support + * David Parsons <orc@pell.chi.il.us>, July-August 1999 */ /* @@ -35,12 +46,11 @@ #include <linux/delay.h> #include <linux/config.h> #include <linux/init.h> -#ifdef CONFIG_APM #include <linux/apm_bios.h> -#endif #ifdef CONFIG_BLK_DEV_RAM #include <linux/blk.h> #endif +#include <linux/bigmem.h> #include <asm/processor.h> #include <linux/console.h> #include <asm/uaccess.h> @@ -49,6 +59,9 @@ #include <asm/smp.h> #include <asm/cobalt.h> #include <asm/msr.h> +#include <asm/desc.h> +#include <asm/e820.h> +#include <asm/dma.h> /* * Machine setup.. @@ -57,6 +70,8 @@ char ignore_irq13 = 0; /* set if exception 16 works */ struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1, 1, 0, 0, -1 }; +unsigned long mmu_cr4_features __initdata = 0; + /* * Bus types .. */ @@ -74,14 +89,14 @@ unsigned int mca_pentium_flag = 0; */ struct drive_info_struct { char dummy[32]; } drive_info; struct screen_info screen_info; -#ifdef CONFIG_APM struct apm_bios_info apm_bios_info; -#endif struct sys_desc_table_struct { unsigned short length; unsigned char table[0]; }; +struct e820map e820 = { 0 }; + unsigned char aux_device_present; #ifdef CONFIG_BLK_DEV_RAM @@ -91,7 +106,7 @@ extern int rd_image_start; /* starting block # of image */ #endif extern int root_mountflags; -extern int _etext, _edata, _end; +extern int _text, _etext, _edata, _end; extern unsigned long cpu_hz; /* @@ -101,6 +116,8 @@ extern unsigned long cpu_hz; #define SCREEN_INFO (*(struct screen_info *) (PARAM+0)) #define EXT_MEM_K (*(unsigned short *) (PARAM+2)) #define ALT_MEM_K (*(unsigned long *) (PARAM+0x1e0)) +#define E820_MAP_NR (*(char*) (PARAM+E820NR)) +#define E820_MAP ((unsigned long *) (PARAM+E820MAP)) #define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+0x40)) #define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80)) #define SYS_DESC_TABLE (*(struct sys_desc_table_struct*)(PARAM+0xa0)) @@ -249,12 +266,207 @@ visws_get_board_type_and_rev(void) static char command_line[COMMAND_LINE_SIZE] = { 0, }; char saved_command_line[COMMAND_LINE_SIZE]; -__initfunc(void setup_arch(char **cmdline_p, - unsigned long * memory_start_p, unsigned long * memory_end_p)) +struct resource standard_io_resources[] = { + { "dma1", 0x00, 0x1f, IORESOURCE_BUSY }, + { "pic1", 0x20, 0x3f, IORESOURCE_BUSY }, + { "timer", 0x40, 0x5f, IORESOURCE_BUSY }, + { "keyboard", 0x60, 0x6f, IORESOURCE_BUSY }, + { "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY }, + { "pic2", 0xa0, 0xbf, IORESOURCE_BUSY }, + { "dma2", 0xc0, 0xdf, IORESOURCE_BUSY }, + { "fpu", 0xf0, 0xff, IORESOURCE_BUSY } +}; + +#define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource)) + +/* System RAM - interrupted by the 640kB-1M hole */ +#define code_resource (ram_resources[3]) +#define data_resource (ram_resources[4]) +static struct resource ram_resources[] = { + { "System RAM", 0x000000, 0x09ffff, IORESOURCE_BUSY }, + { "System RAM", 0x100000, 0x100000, IORESOURCE_BUSY }, + { "Video RAM area", 0x0a0000, 0x0bffff, IORESOURCE_BUSY }, + { "Kernel code", 0x100000, 0 }, + { "Kernel data", 0, 0 } +}; + +/* System ROM resources */ +#define MAXROMS 6 +static struct resource rom_resources[MAXROMS] = { + { "System ROM", 0xF0000, 0xFFFFF, IORESOURCE_BUSY }, + { "Video ROM", 0xc0000, 0xc7fff, IORESOURCE_BUSY } +}; + +#define romsignature(x) (*(unsigned short *)(x) == 0xaa55) + +static void __init probe_roms(void) +{ + int roms = 1; + unsigned long base; + unsigned char *romstart; + + request_resource(&iomem_resource, rom_resources+0); + + /* Video ROM is standard at C000:0000 - C7FF:0000, check signature */ + for (base = 0xC0000; base < 0xE0000; base += 2048) { + romstart = bus_to_virt(base); + if (!romsignature(romstart)) + continue; + request_resource(&iomem_resource, rom_resources + roms); + roms++; + break; + } + + /* Extension roms at C800:0000 - DFFF:0000 */ + for (base = 0xC8000; base < 0xE0000; base += 2048) { + unsigned long length; + + romstart = bus_to_virt(base); + if (!romsignature(romstart)) + continue; + length = romstart[2] * 512; + if (length) { + unsigned int i; + unsigned char chksum; + + chksum = 0; + for (i = 0; i < length; i++) + chksum += romstart[i]; + + /* Good checksum? */ + if (!chksum) { + rom_resources[roms].start = base; + rom_resources[roms].end = base + length - 1; + rom_resources[roms].name = "Extension ROM"; + rom_resources[roms].flags = IORESOURCE_BUSY; + + request_resource(&iomem_resource, rom_resources + roms); + roms++; + if (roms >= MAXROMS) + return; + } + } + } + + /* Final check for motherboard extension rom at E000:0000 */ + base = 0xE0000; + romstart = bus_to_virt(base); + + if (romsignature(romstart)) { + rom_resources[roms].start = base; + rom_resources[roms].end = base + 65535; + rom_resources[roms].name = "Extension ROM"; + rom_resources[roms].flags = IORESOURCE_BUSY; + + request_resource(&iomem_resource, rom_resources + roms); + } +} + +unsigned long __init memparse(char *ptr, char **retptr) +{ + unsigned long ret; + + ret = simple_strtoul(ptr, retptr, 0); + + if (**retptr == 'K' || **retptr == 'k') { + ret <<= 10; + (*retptr)++; + } + else if (**retptr == 'M' || **retptr == 'm') { + ret <<= 20; + (*retptr)++; + } + return ret; +} /* memparse */ + + +void __init add_memory_region(unsigned long start, + unsigned long size, int type) +{ + int x = e820.nr_map; + + if (x == E820MAX) { + printk("Ooops! Too many entries in the memory map!\n"); + return; + } + + e820.map[x].addr = start; + e820.map[x].size = size; + e820.map[x].type = type; + e820.nr_map++; +} /* add_memory_region */ + + +#define LOWMEMSIZE() ((*(unsigned short *)__va(0x413)) * 1024) + + +void __init setup_memory_region(void) +{ +#define E820_DEBUG 0 +#ifdef E820_DEBUG + int i; +#endif + + /* + * If we're lucky and live on a modern system, the setup code + * will have given us a memory map that we can use to properly + * set up memory. If we aren't, we'll fake a memory map. + * + * We check to see that the memory map contains at least 2 elements + * before we'll use it, because the detection code in setup.S may + * not be perfect and most every PC known to man has two memory + * regions: one from 0 to 640k, and one from 1mb up. (The IBM + * thinkpad 560x, for example, does not cooperate with the memory + * detection code.) + */ + if (E820_MAP_NR > 1) { + /* got a memory map; copy it into a safe place. + */ + e820.nr_map = E820_MAP_NR; + if (e820.nr_map > E820MAX) + e820.nr_map = E820MAX; + memcpy(e820.map, E820_MAP, e820.nr_map * sizeof e820.map[0]); +#ifdef E820_DEBUG + for (i=0; i < e820.nr_map; i++) { + printk("e820: %ld @ %08lx ", + (unsigned long)(e820.map[i].size), + (unsigned long)(e820.map[i].addr)); + switch (e820.map[i].type) { + case E820_RAM: printk("(usable)\n"); + break; + case E820_RESERVED: + printk("(reserved)\n"); + break; + case E820_ACPI: + printk("(ACPI data)\n"); + break; + default: printk("type %lu\n", e820.map[i].type); + break; + } + } +#endif + } + else { + /* otherwise fake a memory map; one section from 0k->640k, + * the next section from 1mb->appropriate_mem_k + */ + unsigned long mem_size; + + mem_size = (ALT_MEM_K < EXT_MEM_K) ? EXT_MEM_K : ALT_MEM_K; + + add_memory_region(0, LOWMEMSIZE(), E820_RAM); + add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM); + } +} /* setup_memory_region */ + + +void __init setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p) { unsigned long memory_start, memory_end; char c = ' ', *to = command_line, *from = COMMAND_LINE; int len = 0; + int i; + int usermem=0; #ifdef CONFIG_VISWS visws_get_board_type_and_rev(); @@ -263,9 +475,7 @@ __initfunc(void setup_arch(char **cmdline_p, ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV); drive_info = DRIVE_INFO; screen_info = SCREEN_INFO; -#ifdef CONFIG_APM apm_bios_info = APM_BIOS_INFO; -#endif if( SYS_DESC_TABLE.length != 0 ) { MCA_bus = SYS_DESC_TABLE.table[3] &0x2; machine_id = SYS_DESC_TABLE.table[0]; @@ -273,29 +483,26 @@ __initfunc(void setup_arch(char **cmdline_p, BIOS_revision = SYS_DESC_TABLE.table[2]; } aux_device_present = AUX_DEVICE_INFO; - memory_end = (1<<20) + (EXT_MEM_K<<10); -#ifndef STANDARD_MEMORY_BIOS_CALL - { - unsigned long memory_alt_end = (1<<20) + (ALT_MEM_K<<10); - /* printk(KERN_DEBUG "Memory sizing: %08x %08x\n", memory_end, memory_alt_end); */ - if (memory_alt_end > memory_end) - memory_end = memory_alt_end; - } -#endif - memory_end &= PAGE_MASK; #ifdef CONFIG_BLK_DEV_RAM rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); #endif + setup_memory_region(); + if (!MOUNT_ROOT_RDONLY) root_mountflags &= ~MS_RDONLY; memory_start = (unsigned long) &_end; - init_task.mm->start_code = PAGE_OFFSET; - init_task.mm->end_code = (unsigned long) &_etext; - init_task.mm->end_data = (unsigned long) &_edata; - init_task.mm->brk = (unsigned long) &_end; + init_mm.start_code = (unsigned long) &_text; + init_mm.end_code = (unsigned long) &_etext; + init_mm.end_data = (unsigned long) &_edata; + init_mm.brk = (unsigned long) &_end; + + code_resource.start = virt_to_bus(&_text); + code_resource.end = virt_to_bus(&_etext)-1; + data_resource.start = virt_to_bus(&_etext); + data_resource.end = virt_to_bus(&_edata)-1; /* Save unparsed command line copy for /proc/cmdline */ memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); @@ -304,8 +511,10 @@ __initfunc(void setup_arch(char **cmdline_p, for (;;) { /* * "mem=nopentium" disables the 4MB page tables. - * "mem=XXX[kKmM]" overrides the BIOS-reported - * memory size + * "mem=XXX[kKmM]" defines a memory region from HIGH_MEM + * to <mem>, overriding the bios size. + * "mem=XXX[KkmM]@XXX[KkmM]" defines a memory region from + * <start> to <start>+<mem>, overriding the bios size. */ if (c == ' ' && *(const unsigned long *)from == *(const unsigned long *)"mem=") { if (to != command_line) to--; @@ -313,14 +522,29 @@ __initfunc(void setup_arch(char **cmdline_p, from += 9+4; boot_cpu_data.x86_capability &= ~X86_FEATURE_PSE; } else { - memory_end = simple_strtoul(from+4, &from, 0); - if ( *from == 'K' || *from == 'k' ) { - memory_end = memory_end << 10; - from++; - } else if ( *from == 'M' || *from == 'm' ) { - memory_end = memory_end << 20; - from++; + /* If the user specifies memory size, we + * blow away any automatically generated + * size + */ + unsigned long start_at, mem_size; + + if (usermem == 0) { + /* first time in: zap the whitelist + * and reinitialize it with the + * standard low-memory region. + */ + e820.nr_map = 0; + usermem = 1; + add_memory_region(0, LOWMEMSIZE(), E820_RAM); + } + mem_size = memparse(from+4, &from); + if (*from == '@') + start_at = memparse(from+1,&from); + else { + start_at = HIGH_MEMORY; + mem_size -= HIGH_MEMORY; } + add_memory_region(start_at, mem_size, E820_RAM); } } c = *(from++); @@ -333,15 +557,47 @@ __initfunc(void setup_arch(char **cmdline_p, *to = '\0'; *cmdline_p = command_line; -#define VMALLOC_RESERVE (64 << 20) /* 64MB for vmalloc */ +#define VMALLOC_RESERVE (128 << 20) /* 128MB for vmalloc and initrd */ #define MAXMEM ((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE)) + memory_end = 0; + for (i=0; i < e820.nr_map; i++) { + /* RAM? */ + if (e820.map[i].type == E820_RAM) { + unsigned long end = e820.map[i].addr + e820.map[i].size; + + if (end > memory_end) + memory_end = end; + } + } + memory_end &= PAGE_MASK; + ram_resources[1].end = memory_end-1; + +#ifdef CONFIG_BIGMEM + bigmem_start = bigmem_end = memory_end; +#endif if (memory_end > MAXMEM) { +#ifdef CONFIG_BIGMEM +#define MAXBIGMEM ((unsigned long)(~(VMALLOC_RESERVE-1))) + bigmem_start = MAXMEM; + bigmem_end = (memory_end < MAXBIGMEM) ? memory_end : MAXBIGMEM; +#endif memory_end = MAXMEM; +#ifdef CONFIG_BIGMEM + printk(KERN_NOTICE "%ldMB BIGMEM available.\n", + (bigmem_end-bigmem_start)>>20); +#else printk(KERN_WARNING "Warning only %ldMB will be used.\n", MAXMEM>>20); +#endif } +#if defined(CONFIG_BIGMEM) && defined(BIGMEM_DEBUG) + else { + memory_end -= memory_end/4; + bigmem_start = memory_end; + } +#endif memory_end += PAGE_OFFSET; *memory_start_p = memory_start; @@ -367,12 +623,20 @@ __initfunc(void setup_arch(char **cmdline_p, } #endif + /* + * Request the standard RAM and ROM resources - + * they eat up PCI memory space + */ + request_resource(&iomem_resource, ram_resources+0); + request_resource(&iomem_resource, ram_resources+1); + request_resource(&iomem_resource, ram_resources+2); + request_resource(ram_resources+1, &code_resource); + request_resource(ram_resources+1, &data_resource); + probe_roms(); + /* request I/O space for devices used on all i[345]86 PCs */ - request_region(0x00,0x20,"dma1"); - request_region(0x40,0x20,"timer"); - request_region(0x80,0x10,"dma page reg"); - request_region(0xc0,0x20,"dma2"); - request_region(0xf0,0x10,"fpu"); + for (i = 0; i < STANDARD_IO_RESOURCES; i++) + request_resource(&ioport_resource, standard_io_resources+i); #ifdef CONFIG_VT #if defined(CONFIG_VGA_CONSOLE) @@ -381,13 +645,9 @@ __initfunc(void setup_arch(char **cmdline_p, conswitchp = &dummy_con; #endif #endif - /* - * Check the bugs that will bite us before we get booting - */ - } -__initfunc(static int get_model_name(struct cpuinfo_x86 *c)) +static int __init get_model_name(struct cpuinfo_x86 *c) { unsigned int n, dummy, *v; @@ -415,7 +675,7 @@ __initfunc(static int get_model_name(struct cpuinfo_x86 *c)) return 1; } -__initfunc(static int amd_model(struct cpuinfo_x86 *c)) +static int __init amd_model(struct cpuinfo_x86 *c) { u32 l, h; unsigned long flags; @@ -480,6 +740,19 @@ __initfunc(static int amd_model(struct cpuinfo_x86 *c)) break; } break; + case 6: /* An Athlon. We can trust the BIOS probably */ + { + + u32 ecx, edx, dummy; + cpuid(0x80000005, &dummy, &dummy, &ecx, &edx); + printk("L1 I Cache: %dK L1 D Cache: %dK\n", + ecx>>24, edx>>24); + cpuid(0x80000006, &dummy, &dummy, &ecx, &edx); + printk("L2 Cache: %dK\n", ecx>>16); + c->x86_cache_size = ecx>>16; + break; + } + } return r; } @@ -544,7 +817,7 @@ static char Cx86_cb[] __initdata = "?.5x Core/Bus Clock"; static char cyrix_model_mult1[] __initdata = "12??43"; static char cyrix_model_mult2[] __initdata = "12233445"; -__initfunc(static void cyrix_model(struct cpuinfo_x86 *c)) +static void __init cyrix_model(struct cpuinfo_x86 *c) { unsigned char dir0, dir0_msn, dir0_lsn, dir1 = 0; char *buf = c->x86_model_id; @@ -615,6 +888,15 @@ __initfunc(static void cyrix_model(struct cpuinfo_x86 *c)) c->x86_model = (dir1 & 0x20) ? 1 : 2; c->x86_capability&=~X86_FEATURE_TSC; } +#ifdef CONFIG_PCI + /* It isnt really a PCI quirk directly, but the cure is the + same. The MediaGX has deep magic SMM stuff that handles the + SB emulation. It thows away the fifo on disable_dma() which + is wrong and ruins the audio. */ + + printk(KERN_INFO "Working around Cyrix MediaGX virtual DMA bug.\n"); + isa_dma_bridge_buggy = 1; +#endif break; case 5: /* 6x86MX/M II */ @@ -640,8 +922,8 @@ __initfunc(static void cyrix_model(struct cpuinfo_x86 *c)) dir0_msn = 0; p = Cx486S_name[0]; break; - break; } + break; default: /* unknown (shouldn't happen, we know everyone ;-) */ dir0_msn = 7; @@ -652,7 +934,99 @@ __initfunc(static void cyrix_model(struct cpuinfo_x86 *c)) return; } -__initfunc(void get_cpu_vendor(struct cpuinfo_x86 *c)) +static void __init centaur_model(struct cpuinfo_x86 *c) +{ + enum { + ECX8=1<<1, + EIERRINT=1<<2, + DPM=1<<3, + DMCE=1<<4, + DSTPCLK=1<<5, + ELINEAR=1<<6, + DSMC=1<<7, + DTLOCK=1<<8, + EDCTLB=1<<8, + EMMX=1<<9, + DPDC=1<<11, + EBRPRED=1<<12, + DIC=1<<13, + DDC=1<<14, + DNA=1<<15, + ERETSTK=1<<16, + E2MMX=1<<19, + EAMD3D=1<<20, + }; + + char *name; + u32 fcr_set=0; + u32 fcr_clr=0; + u32 lo,hi,newlo; + u32 aa,bb,cc,dd; + + switch(c->x86_model) { + case 4: + name="C6"; + fcr_set=ECX8|DSMC|EDCTLB|EMMX|ERETSTK; + fcr_clr=DPDC; + break; + case 8: + switch(c->x86_mask) { + default: + name="2"; + break; + case 7 ... 9: + name="2A"; + break; + case 10 ... 15: + name="2B"; + break; + } + fcr_set=ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|E2MMX|EAMD3D; + fcr_clr=DPDC; + break; + case 9: + name="3"; + fcr_set=ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|E2MMX|EAMD3D; + fcr_clr=DPDC; + break; + case 10: + name="4"; + /* no info on the WC4 yet */ + break; + default: + name="??"; + } + + /* get FCR */ + rdmsr(0x107, lo, hi); + + newlo=(lo|fcr_set) & (~fcr_clr); + + if (newlo!=lo) { + printk("Centaur FCR was 0x%X now 0x%X\n", lo, newlo ); + wrmsr(0x107, newlo, hi ); + } else { + printk("Centaur FCR is 0x%X\n",lo); + } + + /* Emulate MTRRs using Centaur's MCR. */ + c->x86_capability |= X86_FEATURE_MTRR; + /* Report CX8 */ + c->x86_capability |= X86_FEATURE_CX8; + /* Set 3DNow! on Winchip 2 and above. */ + if (c->x86_model >=8) + c->x86_capability |= X86_FEATURE_AMD3D; + /* See if we can find out some more. */ + cpuid(0x80000000,&aa,&bb,&cc,&dd); + if (aa>=0x80000005) { /* Yes, we can. */ + cpuid(0x80000005,&aa,&bb,&cc,&dd); + /* Add L1 data and code cache sizes. */ + c->x86_cache_size = (cc>>24)+(dd>>24); + } + sprintf( c->x86_model_id, "WinChip %s", name ); +} + +void __init get_cpu_vendor(struct cpuinfo_x86 *c) { char *v = c->x86_vendor_id; @@ -701,18 +1075,20 @@ static struct cpu_model_info cpu_models[] __initdata = { "K5", "K5", NULL, NULL, "K6", "K6", "K6-2", "K6-3", NULL, NULL, NULL, NULL, NULL, NULL }}, + { X86_VENDOR_AMD, 6, + { "Athlon", "Athlon", + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, { X86_VENDOR_UMC, 4, { NULL, "U5D", "U5S", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, - { X86_VENDOR_CENTAUR, 5, - { NULL, NULL, NULL, NULL, "C6", NULL, NULL, NULL, "C6-2", NULL, NULL, - NULL, NULL, NULL, NULL, NULL }}, { X86_VENDOR_NEXGEN, 5, { "Nx586", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, }; -__initfunc(void identify_cpu(struct cpuinfo_x86 *c)) +void __init identify_cpu(struct cpuinfo_x86 *c) { int i; char *p = NULL; @@ -733,6 +1109,11 @@ __initfunc(void identify_cpu(struct cpuinfo_x86 *c)) if (c->x86_vendor == X86_VENDOR_AMD && amd_model(c)) return; + + if (c->x86_vendor == X86_VENDOR_CENTAUR) { + centaur_model(c); + return; + } if (c->cpuid_level > 0 && c->x86_vendor == X86_VENDOR_INTEL) { @@ -809,7 +1190,6 @@ __initfunc(void identify_cpu(struct cpuinfo_x86 *c)) p = "Celeron (Dixon)"; } } - } if (p) { @@ -824,7 +1204,7 @@ __initfunc(void identify_cpu(struct cpuinfo_x86 *c)) * Perform early boot up checks for a valid TSC. See arch/i386/kernel/time.c */ -__initfunc(void dodgy_tsc(void)) +void __init dodgy_tsc(void) { get_cpu_vendor(&boot_cpu_data); @@ -841,7 +1221,7 @@ static char *cpu_vendor_names[] __initdata = { "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur" }; -__initfunc(void print_cpu_info(struct cpuinfo_x86 *c)) +void __init print_cpu_info(struct cpuinfo_x86 *c) { char *vendor = NULL; @@ -859,22 +1239,7 @@ __initfunc(void print_cpu_info(struct cpuinfo_x86 *c)) printk("%s", c->x86_model_id); if (c->x86_mask || c->cpuid_level>=0) - printk(" stepping %02x", c->x86_mask); - - if(c->x86_vendor == X86_VENDOR_CENTAUR) - { - u32 hv,lv; - rdmsr(0x107, lv, hv); - printk("\nCentaur FSR was 0x%X ",lv); - lv|=(1<<8); - lv|=(1<<7); - /* lv|=(1<<6); - may help too if the board can cope */ - printk("now 0x%X", lv); - wrmsr(0x107, lv, hv); - /* Emulate MTRRs using Centaur's MCR. */ - c->x86_capability |= X86_FEATURE_MTRR; - } - printk("\n"); + printk(" stepping %02x\n", c->x86_mask); } /* @@ -909,7 +1274,7 @@ int get_cpuinfo(char * buffer) c->x86 + '0', c->x86_model, c->x86_model_id[0] ? c->x86_model_id : "unknown"); - + if (c->x86_mask || c->cpuid_level >= 0) p += sprintf(p, "stepping\t: %d\n", c->x86_mask); else @@ -925,14 +1290,20 @@ int get_cpuinfo(char * buffer) p += sprintf(p, "cache size\t: %d KB\n", c->x86_cache_size); /* Modify the capabilities according to chip type */ - if (c->x86_vendor == X86_VENDOR_CYRIX) { + switch (c->x86_vendor) { + + case X86_VENDOR_CYRIX: x86_cap_flags[24] = "cxmmx"; - } else if (c->x86_vendor == X86_VENDOR_AMD) { - x86_cap_flags[16] = "fcmov"; - x86_cap_flags[31] = "3dnow"; + break; + + case X86_VENDOR_AMD: if (c->x86 == 5 && c->x86_model == 6) x86_cap_flags[10] = "sep"; - } else if (c->x86_vendor == X86_VENDOR_INTEL) { + x86_cap_flags[16] = "fcmov"; + x86_cap_flags[31] = "3dnow"; + break; + + case X86_VENDOR_INTEL: x86_cap_flags[6] = "pae"; x86_cap_flags[9] = "apic"; x86_cap_flags[14] = "mca"; @@ -940,6 +1311,16 @@ int get_cpuinfo(char * buffer) x86_cap_flags[17] = "pse36"; x86_cap_flags[18] = "psn"; x86_cap_flags[24] = "osfxsr"; + break; + + case X86_VENDOR_CENTAUR: + if (c->x86_model >=8) /* Only Winchip2 and above */ + x86_cap_flags[31] = "3dnow"; + break; + + default: + /* Unknown CPU manufacturer. Transmeta ? :-) */ + break; } sep_bug = c->x86_vendor == X86_VENDOR_INTEL && @@ -978,3 +1359,64 @@ int get_cpuinfo(char * buffer) } return p - buffer; } + +int cpus_initialized = 0; +unsigned long cpu_initialized = 0; + +/* + * cpu_init() initializes state that is per-CPU. Some data is already + * initialized (naturally) in the bootstrap process, such as the GDT + * and IDT. We reload them nevertheless, this function acts as a + * 'CPU state barrier', nothing should get across. + */ +void cpu_init (void) +{ + int nr = smp_processor_id(); + struct tss_struct * t = &init_tss[nr]; + + if (test_and_set_bit(nr,&cpu_initialized)) { + printk("CPU#%d already initialized!\n", nr); + for (;;) __sti(); + } + cpus_initialized++; + printk("Initializing CPU#%d\n", nr); + + if (boot_cpu_data.x86_capability & X86_FEATURE_PSE) + clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE); + + __asm__ __volatile__("lgdt %0": "=m" (gdt_descr)); + __asm__ __volatile__("lidt %0": "=m" (idt_descr)); + + /* + * Delete NT + */ + __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl"); + + /* + * set up and load the per-CPU TSS and LDT + */ + atomic_inc(&init_mm.mm_count); + current->active_mm = &init_mm; + t->esp0 = current->thread.esp0; + set_tss_desc(nr,t); + gdt_table[__TSS(nr)].b &= 0xfffffdff; + load_TR(nr); + load_LDT(&init_mm); + + /* + * Clear all 6 debug registers: + */ + +#define CD(register) __asm__("movl %0,%%db" #register ::"r"(0) ); + + CD(0); CD(1); CD(2); CD(3); /* no db4 and db5 */; CD(6); CD(7); + +#undef CD + + /* + * Force FPU initialization: + */ + current->flags &= ~PF_USEDFPU; + current->used_math = 0; + stts(); +} |