diff -uNr linux-2.4.2.sym/arch/i386/kernel/head.S linux-2.4.2.amp/arch/i386/kernel/head.S --- linux-2.4.2.sym/arch/i386/kernel/head.S Sat Feb 17 00:53:08 2001 +++ linux-2.4.2.amp/arch/i386/kernel/head.S Wed Mar 21 03:22:49 2001 @@ -229,6 +229,12 @@ movb %al,X86_MODEL andb $0x0f,%cl # mask mask revision movb %cl,X86_MASK + /* prevent overwriting of corrected cpu_boot_data.x86_capabilty[0] */ +#ifdef CONFIG_SMP + movb ready,%cl + cmpb $0,%cl + jne is486 +#endif movl %edx,X86_CAPABILITY is486: diff -uNr linux-2.4.2.sym/arch/i386/kernel/i387.c linux-2.4.2.amp/arch/i386/kernel/i387.c --- linux-2.4.2.sym/arch/i386/kernel/i387.c Sat Feb 3 21:09:34 2001 +++ linux-2.4.2.amp/arch/i386/kernel/i387.c Wed Mar 21 02:54:27 2001 @@ -28,7 +28,7 @@ * The _current_ task is using the FPU for the first time * so initialize it and set the mxcsr to its default * value at reset if we support XMM instructions and then - * remeber the current task has used the FPU. + * remember the current task has used the FPU. */ void init_fpu(void) { diff -uNr linux-2.4.2.sym/arch/i386/kernel/mpparse.c linux-2.4.2.amp/arch/i386/kernel/mpparse.c --- linux-2.4.2.sym/arch/i386/kernel/mpparse.c Wed Nov 15 06:25:34 2000 +++ linux-2.4.2.amp/arch/i386/kernel/mpparse.c Wed Mar 21 14:51:17 2001 @@ -106,6 +106,8 @@ return n; } +unsigned long mp_max_features = 0xffffffff; + static void __init MP_processor_info (struct mpc_config_processor *m) { int ver; @@ -171,6 +173,9 @@ boot_cpu_id = m->mpc_apicid; } num_processors++; + + /* Clear features that are not present on all CPUs */ + mp_max_features &= m->mpc_featureflag; if (m->mpc_apicid > MAX_APICS) { printk("Processor #%d INVALID. (Max ID: %d).\n", diff -uNr linux-2.4.2.sym/arch/i386/kernel/setup.c linux-2.4.2.amp/arch/i386/kernel/setup.c --- linux-2.4.2.sym/arch/i386/kernel/setup.c Sat Feb 17 01:02:37 2001 +++ linux-2.4.2.amp/arch/i386/kernel/setup.c Wed Mar 21 14:52:58 2001 @@ -106,6 +106,9 @@ struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1, 1, 0, 0, -1 }; unsigned long mmu_cr4_features; +#ifdef CONFIG_SMP +extern unsigned long mp_max_features; +#endif /* * Bus types .. @@ -144,10 +147,11 @@ extern int root_mountflags; extern char _text, _etext, _edata, _end; -extern unsigned long cpu_khz; +//extern unsigned long cpu_khz; static int disable_x86_serial_nr __initdata = 1; static int disable_x86_fxsr __initdata = 0; +static int disable_x86_xmm __initdata = 0; /* * This is set up by the setup-routine at boot-time @@ -1805,6 +1809,11 @@ } __setup("nofxsr", x86_fxsr_setup); +int __init x86_xmm_setup(char* s) +{ disable_x86_xmm = 1; + return 1; +} +__setup("noxmm", x86_xmm_setup); /* Standard macro to see if a specific flag is changeable */ static inline int flag_is_changeable_p(u32 flag) @@ -1912,6 +1921,8 @@ return have_cpuid_p(); /* Check to see if CPUID now enabled? */ } + +extern void time_init_cpu(struct cpuinfo_x86 *); /* * This does the hard work of actually picking apart the CPU stuff... */ @@ -2046,6 +2057,10 @@ clear_bit(X86_FEATURE_XMM, &c->x86_capability); } + /* XMM/SSE disabled? */ + if (disable_x86_xmm) + clear_bit(X86_FEATURE_XMM, &c->x86_capability); + /* Disable the PN if appropriate */ squash_the_stupid_serial_number(c); @@ -2079,7 +2094,12 @@ /* AND the already accumulated flags with these */ for ( i = 0 ; i < NCAPINTS ; i++ ) boot_cpu_data.x86_capability[i] &= c->x86_capability[i]; + time_init_cpu (c); } +#if 0 //def CONFIG_SMP + else + c->x86_capability[0] &= mp_max_features; +#endif printk("CPU: Common caps: %08x %08x %08x %08x\n", boot_cpu_data.x86_capability[0], @@ -2196,7 +2216,7 @@ if ( test_bit(X86_FEATURE_TSC, &c->x86_capability) ) { p += sprintf(p, "cpu MHz\t\t: %lu.%03lu\n", - cpu_khz / 1000, (cpu_khz % 1000)); + c->cpu_khz / 1000, (c->cpu_khz % 1000)); } /* Cache size */ diff -uNr linux-2.4.2.sym/arch/i386/kernel/smpboot.c linux-2.4.2.amp/arch/i386/kernel/smpboot.c --- linux-2.4.2.sym/arch/i386/kernel/smpboot.c Tue Feb 13 23:13:43 2001 +++ linux-2.4.2.amp/arch/i386/kernel/smpboot.c Wed Mar 21 15:04:03 2001 @@ -29,6 +29,7 @@ * Ingo Molnar : various cleanups and rewrites * Tigran Aivazian : fixed "0.00 in /proc/uptime on SMP" bug. * Maciej W. Rozycki : Bits for genuine 82489DX APICs + * Kurt Garloff : Support for SMP with non-identical CPUs */ #include @@ -44,6 +45,7 @@ #include #include #include +#include /* Set if we find a B stepping CPU */ static int smp_b_stepping; @@ -198,7 +200,7 @@ #define NR_LOOPS 5 -extern unsigned long fast_gettimeoffset_quotient; +//extern unsigned long fast_gettimeoffset_quotient; /* * accurate 64-bit/32-bit division, expanded to 32-bit divisions and 64-bit @@ -239,7 +241,7 @@ printk("checking TSC synchronization across CPUs: "); - one_usec = ((1<<30)/fast_gettimeoffset_quotient)*(1<<2); + one_usec = ((1<<30)/current_cpu_data.fast_gettimeoffset_quotient)*(1<<2); atomic_set(&tsc_start_flag, 1); wmb(); @@ -342,6 +344,38 @@ } #undef NR_LOOPS +/* Note: cpu_boot_data caps on SMP machines is filled in as follows: + * (1) Initialized with the boot CPU's caps (head.S) + * (2) AND with the common caps from the MP table (identify_cpu()) + * (3) AND with the caps from the started CPUs (identify_cpu()) + * (4) Finally calculated and overwritten here (smp_make_common_caps()) + * Step 2 is actually disabled, as the info is not very reliable. + * Step 4 should not be needed then, actually. + * KG , 2001-03-21 + */ + +/* Store common subset of capabilities in boot_cpu_data */ +void smp_make_common_caps(void) +{ + int cpu, c; + unsigned long x86cap[NCAPINTS]; + for (c = 0; c < NCAPINTS; c++) + x86cap[c] = 0xffffffff; + for (cpu = 0; cpu < NR_CPUS; cpu++) { + if (!(cpu_online_map & (1< -unsigned long cpu_khz; /* Detected as we calibrate the TSC */ +//unsigned long cpu_khz; /* Detected as we calibrate the TSC */ /* Number of usecs that the last interrupt was delayed */ static int delay_at_last_interrupt; -static unsigned long last_tsc_low; /* lsb 32 bits of Time Stamp Counter */ +//static unsigned long last_tsc_low; /* lsb 32 bits of Time Stamp Counter */ /* Cached *multiplier* to convert TSC counts to microseconds. * (see the equation below). * Equal to 2^32 * (1 / (clocks per usec) ). * Initialized in time_init. */ -unsigned long fast_gettimeoffset_quotient; +//unsigned long fast_gettimeoffset_quotient; extern rwlock_t xtime_lock; extern unsigned long wall_jiffies; @@ -92,7 +92,7 @@ rdtsc(eax,edx); /* .. relative to previous jiffy (32 bits is enough) */ - eax -= last_tsc_low; /* tsc_low delta */ + eax -= current_cpu_data.last_tsc_low; /* tsc_low delta */ /* * Time offset = (tsc_low delta) * fast_gettimeoffset_quotient @@ -105,7 +105,7 @@ __asm__("mull %2" :"=a" (eax), "=d" (edx) - :"rm" (fast_gettimeoffset_quotient), + :"rm" (current_cpu_data.fast_gettimeoffset_quotient), "0" (eax)); /* our adjusted time offset in microseconds */ @@ -266,8 +266,8 @@ if (lost) usec += lost * (1000000 / HZ); } - sec = xtime.tv_sec; - usec += xtime.tv_usec; + sec = current_cpu_data.xtime.tv_sec; + usec += current_cpu_data.xtime.tv_usec; read_unlock_irqrestore(&xtime_lock, flags); while (usec >= 1000000) { @@ -431,6 +431,7 @@ else last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ } + current_cpu_data.xtime = xtime; #ifdef CONFIG_MCA if( MCA_bus ) { @@ -485,7 +486,7 @@ /* read Pentium cycle counter */ - rdtscl(last_tsc_low); + rdtscl(current_cpu_data.last_tsc_low); spin_lock(&i8253_lock); outb_p(0x00, 0x43); /* latch the count ASAP */ @@ -586,7 +587,7 @@ } while ((inb(0x61) & 0x20) == 0); rdtsc(endlow,endhigh); - last_tsc_low = endlow; + current_cpu_data.last_tsc_low = endlow; /* Error: ECTCNEVERSET */ if (count <= 1) @@ -623,7 +624,8 @@ return 0; } -void __init time_init(void) + +void __init time_init_cpu(struct cpuinfo_x86 *c) { extern int x86_udelay_tsc; @@ -660,7 +662,8 @@ if (cpu_has_tsc) { unsigned long tsc_quotient = calibrate_tsc(); if (tsc_quotient) { - fast_gettimeoffset_quotient = tsc_quotient; + unsigned long cpu_khz; + c->fast_gettimeoffset_quotient = tsc_quotient; use_tsc = 1; /* * We could be more selective here I suspect @@ -683,6 +686,7 @@ "0" (eax), "1" (edx)); printk("Detected %lu.%03lu MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000); } + c->cpu_khz = cpu_khz; } } @@ -703,4 +707,11 @@ #else setup_irq(0, &irq0); #endif +} + +extern struct cpuinfo_x86 boot_cpu_data; + +void inline __init time_init (void) +{ + time_init_cpu (&boot_cpu_data); } diff -uNr linux-2.4.2.sym/include/asm-i386/bugs.h linux-2.4.2.amp/include/asm-i386/bugs.h --- linux-2.4.2.sym/include/asm-i386/bugs.h Wed Mar 21 02:14:22 2001 +++ linux-2.4.2.amp/include/asm-i386/bugs.h Wed Mar 21 14:47:23 2001 @@ -21,6 +21,7 @@ */ #include +#include #include #include #include @@ -204,12 +205,16 @@ static void __init check_bugs(void) { - identify_cpu(&boot_cpu_data); + /* identify_cpu(&boot_cpu_data) and + * check_config() + * are called in smp_boot_cpus() on SMP kernels + */ #ifndef CONFIG_SMP + identify_cpu(&boot_cpu_data); printk("CPU: "); print_cpu_info(&boot_cpu_data); -#endif check_config(); +#endif check_fpu(); check_hlt(); check_popad(); diff -uNr linux-2.4.2.sym/include/asm-i386/processor.h linux-2.4.2.amp/include/asm-i386/processor.h --- linux-2.4.2.sym/include/asm-i386/processor.h Tue Mar 6 23:25:52 2001 +++ linux-2.4.2.amp/include/asm-i386/processor.h Wed Mar 21 02:10:14 2001 @@ -16,6 +16,7 @@ #include #include #include +#include /* * Default implementation of macro that returns current @@ -52,6 +53,10 @@ unsigned long *pmd_quick; unsigned long *pte_quick; unsigned long pgtable_cache_sz; + unsigned long cpu_khz; + unsigned long fast_gettimeoffset_quotient; + unsigned long last_tsc_low; + struct timeval xtime; }; #define X86_VENDOR_INTEL 0 diff -uNr linux-2.4.2.sym/init/main.c linux-2.4.2.amp/init/main.c --- linux-2.4.2.sym/init/main.c Thu Mar 1 16:44:10 2001 +++ linux-2.4.2.amp/init/main.c Wed Mar 21 14:39:32 2001 @@ -592,6 +592,12 @@ page_cache_init(mempages); kiobuf_setup(); signals_init(); + /* Moved smp_init() up, as bdev_init(), i.e. RAID5, may depend on the CPU features + * being present, which is unfortunately only known after all CPUs have been booted + * check_bugs() follows next to take care of FPU ... + * KG , 2001-01-21 */ + smp_init(); + check_bugs(); bdev_init(); inode_init(mempages); #if defined(CONFIG_SYSVIPC) @@ -600,7 +606,6 @@ #if defined(CONFIG_QUOTA) dquot_init_hash(); #endif - check_bugs(); printk("POSIX conformance testing by UNIFIX\n"); /* @@ -608,7 +613,6 @@ * Like idlers init is an unlocked kernel thread, which will * make syscalls (and thus be locked). */ - smp_init(); kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); unlock_kernel(); current->need_resched = 1;