[patch] Katmai/PIII support for Linux pre-2.2.2-1

MOLNAR Ingo (mingo@chiara.csoma.elte.hu)
Wed, 3 Feb 1999 19:11:11 +0100 (CET)


the attached patch implements Linux support for the 'fast/extended FPU
store/restore' instructions and uses it for context switching / signal
handling. OS support for MMX2 registers is necessary for the PIII
(Katmai), otherwise MMX2 registers are not saved properly across context
switches. The FXSAVE/FXRESTORE instructions are available in later PIIs
and the Xeon too, this is why i could implement this on my Xeon.

(i'd first like to thank Philipp Rumpf for reminding Alan and me on this
problem and sending me a concept-patch. While my patch goes a much
different way, his patch was certainly very helpful in doing the design
decisions)

The speed of the new instructions is rather spectacular, here is the
latency of the 'old' FPU-save+restore instructions:

[mingo@moon mingo]$ ./fsave
224
220
219
213
213
213

(the simple testprogram saves/restores the FPU using the 'old'
fsave/frstor instructions in a loop, thus we can see that the cold-cache
cost is 224 cycles, the hot-cache one is 213 cycles.)

the new instructions are much faster:

[mingo@moon mingo]$ ./fxsave
131
97
97
97
97

this is a 219% speedup over the old method. Of course for proper MMX2
operation we _need_ this feature, but it's nice to have a speedup as well
at the same time.

I have added a new 'PIII/Xeon/Deschutes' CPU family:

( ) 386
( ) 486/Cx486
( ) 586/K5/5x86/6x86
( ) Pentium/K6/TSC
( ) PPro/6x86MX/PII
(X) PIII/Xeon/Deschutes

kernels compiled for the PII will not run on earlier processors because we
do not want to slow down the context-switch path with conditional jumps,
nor do we want to do boot-time dynamic linking. The FPU layout also
differs significantly, so it doesnt make much sense to 'unify' the two
layouts into the same kernel binary. The internal CONFIG_X86_FX flag was a
natural extension of the existing x86 CPU-feature framework.

i have tested the patch 'lightly', ie. Quake runs ;) and basic FPU
operations/debugging works, but there might be some rough edges left. It
would be nice if people with the proper hardware could test this stuff
out. An easy test is to check out the 'osfxsr' flag in cpuinfo:

[mingo@moon mingo]$ cat /proc/cpuinfo | grep osf
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca
cmov pat pse36 mmx osfxsr
^^^^^^<--- this one

anyone who is interested and has that flag can test out this patch. The
patch has been developed on an SMP Xeon system, it should work on UP just
fine as well. (let me know if it doesnt) The patch is based on
pre-patch-2.2.2-1.

reports, comments, suggestions welcome,

-- mingo

ps. [due to the rewritten/restructured FPU code i dont think this is a
2.2.2 patch, when enough people have tested it then maybe we can fit it
into the 2.2 line, if not then i'll maintain it together with my
'arbitrary number of threads' patch.]

--- linux/include/asm-i386/processor.h.orig2 Wed Feb 3 11:09:22 1999
+++ linux/include/asm-i386/processor.h Wed Feb 3 18:38:03 1999
@@ -7,10 +7,11 @@
#ifndef __ASM_I386_PROCESSOR_H
#define __ASM_I386_PROCESSOR_H

+#include <linux/config.h>
#include <asm/vm86.h>
#include <asm/math_emu.h>
-#include <asm/segment.h>
#include <asm/page.h>
+#include <asm/user.h>

/*
* CPU type and hardware bug flags. Kept separately for each CPU.
@@ -88,6 +89,35 @@

extern struct cpuinfo_x86 boot_cpu_data;

+#define X86_CR4_VME 0x0001 /* enable vm86 extensions */
+#define X86_CR4_PVI 0x0002 /* virtual interrupts flag enable */
+#define X86_CR4_TSD 0x0004 /* disable time stamp at ipl 3 */
+#define X86_CR4_DE 0x0008 /* enable debugging extensions */
+#define X86_CR4_PSE 0x0010 /* enable page size extensions */
+#define X86_CR4_PAE 0x0020 /* enable physical address extensions */
+#define X86_CR4_MCE 0x0040 /* Machine check enable */
+#define X86_CR4_PGE 0x0080 /* enable global pages */
+#define X86_CR4_PCE 0x0100 /* enable performance counters at ipl 3 */
+#define X86_CR4_FXSR 0x0200 /* fast FPU save/restore */
+
+/*
+ * Save the cr4 feature set we're using (ie
+ * Pentium 4MB enable and PPro Global page
+ * enable), so that any CPU's that boot up
+ * after us can get the correct flags.
+ */
+extern unsigned long mmu_cr4_features;
+
+static inline void set_in_cr4(unsigned long mask)
+{
+ mmu_cr4_features |= mask;
+ __asm__("movl %%cr4,%%eax\n\t"
+ "orl %0,%%eax\n\t"
+ "movl %%eax,%%cr4\n"
+ : : "irg" (mask)
+ :"ax");
+}
+
#ifdef __SMP__
extern struct cpuinfo_x86 cpu_data[];
#define current_cpu_data cpu_data[smp_processor_id()]
@@ -164,6 +194,23 @@
*/
#define IO_BITMAP_SIZE 32

+/*
+ * We have two (incompatible) floating-point state formats:
+ *
+ * - the new MMX2-ready format used by newer PII / Xeon / PII (Katmai) CPUs
+ * - the 'old' i387 FPU format used by everything else
+ *
+ * we use the one apropriate for the CPU picked at kernel compilation time.
+ *
+ * to keep the FPU code more transparent, we define the same
+ * structure in both cases, the parameter names are identical too.
+ * (except for the FPU register names, for which we define access
+ * functions)
+ * their layout is not identical, plus the new format has additional,
+ * currently unused fields.
+ */
+
+#ifndef CONFIG_X86_FX
struct i387_hard_struct {
long cwd;
long swd;
@@ -176,6 +223,62 @@
long status; /* software status information */
};

+/*
+ * Fill out the reserved bits
+ */
+#define i387_set_cwd(x,v) do { (x).cwd = ((long)(v) | 0xffff0000); } while (0)
+#define i387_set_swd(x,v) do { (x).swd = ((long)(v) | 0xffff0000); } while (0)
+#define i387_set_twd(x,v) do { (x).twd = ((long)(v) | 0xffff0000); } while (0)
+
+#define i387_save_hard(x) \
+ do { __asm__("fnsave %0; fwait;": "=m" (x)); } while (0)
+
+#define i387_restore_hard(x) \
+ do { __asm__("frstor %0": :"m" (x)); } while (0)
+
+#else
+
+/*
+ * has to be 128-bit aligned
+ */
+struct i387_hard_struct {
+ unsigned short cwd2;
+ unsigned short swd2;
+ unsigned short twd2;
+ unsigned short __reserved_01;
+ unsigned short fopcode2;
+ long fip2;
+ long fcs2;
+ long foo2;
+ long fos2;
+ long __reserved_02, __reserved_03;
+ long st_space2[32]; /* 8*16 bytes for each FP/MMX-reg = 128 bytes */
+ long __reserved_04 [22*16]; /* 22 cachelines for MMX2 registers */
+} __attribute__ ((aligned (16)));
+
+#define i387_set_cwd(x,v) do { (x).cwd2 = (short)(v); } while (0)
+#define i387_set_swd(x,v) do { (x).swd2 = (short)(v); } while (0)
+#define i387_set_twd(x,v) do { (x).twd2 = (short)(v); } while (0)
+
+/*
+ * GAS is not ready yet, so we encode the FXSAVE/FXRSTOR
+ * opcodes directly:
+ */
+#define i387_save_hard(x) \
+do { __asm__ __volatile__(".byte 0x0f, 0xae, 0x06": :"S" (&(x))); } while (0)
+
+#define i387_restore_hard(x) \
+do { __asm__ __volatile__(".byte 0x0f, 0xae, 0x4f, 0x00": :"D" (&(x))); } while (0)
+
+#endif
+
+extern int i387_hard_to_user ( struct user_i387_struct * user,
+ struct i387_hard_struct * hard);
+extern int i387_user_to_hard (struct i387_hard_struct * hard,
+ struct user_i387_struct * user);
+extern void i387_hard_to_hard (struct i387_hard_struct * hard1,
+ struct i387_hard_struct * hard2);
+
struct i387_soft_struct {
long cwd;
long swd;
@@ -287,7 +390,7 @@
* FPU lazy state save handling..
*/
#define save_fpu(tsk) do { \
- asm volatile("fnsave %0\n\tfwait":"=m" (tsk->tss.i387)); \
+ i387_save_hard(tsk->tss.i387); \
tsk->flags &= ~PF_USEDFPU; \
stts(); \
} while (0)
--- linux/include/asm-i386/bugs.h.orig2 Wed Feb 3 18:14:54 1999
+++ linux/include/asm-i386/bugs.h Wed Feb 3 18:18:31 1999
@@ -18,6 +18,7 @@
*/

#include <linux/config.h>
+#include <linux/stddef.h>
#include <asm/processor.h>

#define CONFIG_BUGi386
@@ -61,6 +62,24 @@
#endif
return;
}
+#if CONFIG_X86_FX
+ /*
+ * If we got so far we can safely turn on FXSAVE/FXRESTORE,
+ * but make sure we are 16-byte aligned first.
+ */
+ if (offsetof(struct task_struct, tss.i387.hard) & 15) {
+ /*
+ * This triggers a link-time error if we manage to
+ * break alignment somehow.
+ */
+ extern void __buggy_fxsr_alignment(void);
+
+ __buggy_fxsr_alignment();
+ }
+ printk("Enabling fast FPU / MMX2 save and restore ... ");
+ set_in_cr4(X86_CR4_FXSR);
+ printk("done.\n");
+#endif
/*
* check if exception 16 works correctly.. This is truly evil
* code: it disables the high 8 interrupts to make sure that
@@ -84,23 +103,31 @@
return;
if (!ignore_irq13) {
printk("OK, FPU using old IRQ 13 error reporting\n");
- return;
+ } else {
+ __asm__("fninit\n\t"
+ "fldl %1\n\t"
+ "fdivl %2\n\t"
+ "fmull %2\n\t"
+ "fldl %1\n\t"
+ "fsubp %%st,%%st(1)\n\t"
+ "fistpl %0\n\t"
+ "fwait\n\t"
+ "fninit"
+ : "=m" (*&boot_cpu_data.fdiv_bug)
+ : "m" (*&x), "m" (*&y));
+ if (!boot_cpu_data.fdiv_bug)
+ printk("OK, FPU using exception 16 error reporting.\n");
+ else
+ printk("Hmm, FPU using exception 16 error reporting with FDIV bug.\n");
}
- __asm__("fninit\n\t"
- "fldl %1\n\t"
- "fdivl %2\n\t"
- "fmull %2\n\t"
- "fldl %1\n\t"
- "fsubp %%st,%%st(1)\n\t"
- "fistpl %0\n\t"
- "fwait\n\t"
- "fninit"
- : "=m" (*&boot_cpu_data.fdiv_bug)
- : "m" (*&x), "m" (*&y));
- if (!boot_cpu_data.fdiv_bug)
- printk("OK, FPU using exception 16 error reporting.\n");
- else
- printk("Hmm, FPU using exception 16 error reporting with FDIV bug.\n");
+#if CONFIG_X86_FX
+ /*
+ * Silly check but we want to have a perfect FPU for
+ * FXSAVE/FXRESTORE.
+ */
+ if (boot_cpu_data.fdiv_bug || !ignore_irq13)
+ panic("huh, Xeon/Katmai/PIII CPU but buggy FPU?");
+#endif
}

__initfunc(static void check_hlt(void))
@@ -352,6 +379,13 @@
#if defined(CONFIG_X86_GOOD_APIC) && defined(CONFIG_SMP)
if (smp_found_config && boot_cpu_data.x86 <= 5)
panic("Kernel compiled for PPro+, assumes local APIC without read-before-write bug");
+#endif
+/*
+ * If we configured for FXRS we better have it!
+ */
+#if CONFIG_X86_FX
+ if (!(boot_cpu_data.x86_capability & X86_FEATURE_FXSR))
+ panic("Kernel configured for Xeon/Katmai/PIII, but CPU does not support FXSR!");
#endif
}

--- linux/include/asm-i386/user.h.orig2 Wed Feb 3 13:23:06 1999
+++ linux/include/asm-i386/user.h Wed Feb 3 13:23:18 1999
@@ -31,14 +31,14 @@
*/

struct user_i387_struct {
- long cwd;
- long swd;
- long twd;
- long fip;
- long fcs;
- long foo;
- long fos;
- long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
+ long cwd2;
+ long swd2;
+ long twd2;
+ long fip2;
+ long fcs2;
+ long foo2;
+ long fos2;
+ long st_space2[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
};

/*
--- linux/arch/i386/mm/init.c.orig2 Wed Feb 3 14:19:32 1999
+++ linux/arch/i386/mm/init.c Wed Feb 3 18:08:38 1999
@@ -182,34 +182,6 @@
extern char _text, _etext, _edata, __bss_start, _end;
extern char __init_begin, __init_end;

-#define X86_CR4_VME 0x0001 /* enable vm86 extensions */
-#define X86_CR4_PVI 0x0002 /* virtual interrupts flag enable */
-#define X86_CR4_TSD 0x0004 /* disable time stamp at ipl 3 */
-#define X86_CR4_DE 0x0008 /* enable debugging extensions */
-#define X86_CR4_PSE 0x0010 /* enable page size extensions */
-#define X86_CR4_PAE 0x0020 /* enable physical address extensions */
-#define X86_CR4_MCE 0x0040 /* Machine check enable */
-#define X86_CR4_PGE 0x0080 /* enable global pages */
-#define X86_CR4_PCE 0x0100 /* enable performance counters at ipl 3 */
-
-/*
- * Save the cr4 feature set we're using (ie
- * Pentium 4MB enable and PPro Global page
- * enable), so that any CPU's that boot up
- * after us can get the correct flags.
- */
-unsigned long mmu_cr4_features __initdata = 0;
-
-static inline void set_in_cr4(unsigned long mask)
-{
- mmu_cr4_features |= mask;
- __asm__("movl %%cr4,%%eax\n\t"
- "orl %0,%%eax\n\t"
- "movl %%eax,%%cr4\n"
- : : "irg" (mask)
- :"ax");
-}
-
/*
* allocate page table(s) for compile-time fixed mappings
*/
--- linux/arch/i386/kernel/ptrace.c.orig2 Wed Feb 3 13:08:47 1999
+++ linux/arch/i386/kernel/ptrace.c Wed Feb 3 13:44:43 1999
@@ -615,6 +615,9 @@
};

case PTRACE_GETFPREGS: { /* Get the child FPU state. */
+ /*
+ * user-space expects an 'old-style' FPU dump.
+ */
if (!access_ok(VERIFY_WRITE, (unsigned *)data,
sizeof(struct user_i387_struct)))
{
@@ -624,15 +627,17 @@
ret = 0;
if ( !child->used_math ) {
/* Simulate an empty FPU. */
- child->tss.i387.hard.cwd = 0xffff037f;
- child->tss.i387.hard.swd = 0xffff0000;
- child->tss.i387.hard.twd = 0xffffffff;
+ i387_set_cwd(child->tss.i387.hard, 0x037f);
+ i387_set_swd(child->tss.i387.hard, 0x0000);
+ i387_set_twd(child->tss.i387.hard, 0xffff);
}
#ifdef CONFIG_MATH_EMULATION
if ( boot_cpu_data.hard_math ) {
#endif
- __copy_to_user((void *)data, &child->tss.i387.hard,
- sizeof(struct user_i387_struct));
+ i387_hard_to_user(
+ (struct user_i387_struct *)data,
+ &child->tss.i387.hard
+ );
#ifdef CONFIG_MATH_EMULATION
} else {
save_i387_soft(&child->tss.i387.soft,
@@ -653,8 +658,12 @@
#ifdef CONFIG_MATH_EMULATION
if ( boot_cpu_data.hard_math ) {
#endif
- __copy_from_user(&child->tss.i387.hard, (void *)data,
- sizeof(struct user_i387_struct));
+ {
+ i387_user_to_hard(
+ &child->tss.i387.hard,
+ (struct user_i387_struct *)data
+ );
+ }
#ifdef CONFIG_MATH_EMULATION
} else {
restore_i387_soft(&child->tss.i387.soft,
--- linux/arch/i386/kernel/traps.c.orig2 Wed Feb 3 13:11:25 1999
+++ linux/arch/i386/kernel/traps.c Wed Feb 3 16:34:45 1999
@@ -451,17 +451,16 @@
asmlinkage void math_state_restore(struct pt_regs regs)
{
__asm__ __volatile__("clts"); /* Allow maths ops (or we recurse) */
- if(current->used_math)
- __asm__("frstor %0": :"m" (current->tss.i387));
- else
- {
+ if(current->used_math) {
+ i387_restore_hard(current->tss.i387);
+ } else {
/*
* Our first FPU usage, clean the chip.
*/
__asm__("fninit");
current->used_math = 1;
}
- current->flags|=PF_USEDFPU; /* So we fnsave on switch_to() */
+ current->flags|=PF_USEDFPU; /* So we fpu_save on switch_to() */
}

#ifndef CONFIG_MATH_EMULATION
--- linux/arch/i386/kernel/signal.c.orig2 Wed Feb 3 13:16:29 1999
+++ linux/arch/i386/kernel/signal.c Wed Feb 3 16:46:39 1999
@@ -153,9 +153,16 @@

static inline int restore_i387_hard(struct _fpstate *buf)
{
+ int err = 0;
struct task_struct *tsk = current;
clear_fpu(tsk);
- return __copy_from_user(&tsk->tss.i387.hard, buf, sizeof(*buf));
+
+#ifdef CONFIG_MATH_EMULATION
+ err = get_user(tsk->tss.i387.hard.status, &buf->status);
+#endif
+ err |= i387_user_to_hard(&tsk->tss.i387.hard,
+ (struct user_i387_struct *)buf);
+ return err;
}

static inline int restore_i387(struct _fpstate *buf)
@@ -305,11 +312,16 @@

static inline int save_i387_hard(struct _fpstate * buf)
{
+ int err = 0;
struct task_struct *tsk = current;

unlazy_fpu(tsk);
- tsk->tss.i387.hard.status = tsk->tss.i387.hard.swd;
- if (__copy_to_user(buf, &tsk->tss.i387.hard, sizeof(*buf)))
+#ifdef CONFIG_MATH_EMULATION
+ err = put_user(tsk->tss.i387.hard.status, &buf->status);
+#endif
+ err |= i387_hard_to_user((struct user_i387_struct *)buf,
+ &tsk->tss.i387.hard);
+ if (err)
return -1;
return 1;
}
--- linux/arch/i386/kernel/process.c.orig2 Wed Feb 3 13:30:37 1999
+++ linux/arch/i386/kernel/process.c Wed Feb 3 16:36:11 1999
@@ -580,6 +580,135 @@
}

/*
+ * FPU state handling functions
+ */
+
+#ifndef CONFIG_X86_FX
+
+int i387_hard_to_user ( struct user_i387_struct * user,
+ struct i387_hard_struct * hard)
+{
+ int err;
+
+ err = __copy_to_user((void *)(user), (hard),
+ sizeof(struct user_i387_struct));
+ return err;
+}
+
+int i387_user_to_hard (struct i387_hard_struct * hard,
+ struct user_i387_struct * user)
+{
+ int err;
+
+ err = __copy_from_user((hard), (void *)(user),
+ sizeof(struct user_i387_struct));
+ return err;
+
+}
+
+void i387_hard_to_hard (struct i387_hard_struct * hard1,
+ struct i387_hard_struct * hard2)
+{
+ *hard1 = *hard2;
+}
+
+#else
+
+int i387_hard_to_user ( struct user_i387_struct * user,
+ struct i387_hard_struct * hard)
+{
+ int i, err = 0;
+ short *tmp, *tmp2;
+
+#define PUT(x) err |= put_user (hard->x, &user->x)
+ PUT(cwd2);
+ PUT(swd2);
+ PUT(twd2);
+ PUT(fip2);
+ PUT(fcs2);
+ PUT(foo2);
+ PUT(fos2);
+#undef PUT
+
+ tmp = (short *)&user->st_space2;
+ tmp2 = (short *)&hard->st_space2;
+
+ /*
+ * Transform the two layouts:
+ * (we do not mix 32-bit access with 16-bit access because
+ * thats suboptimal on PPros)
+ */
+ for (i = 0; i < 8; i++) {
+ err |= put_user(*tmp2, tmp); tmp++; tmp2++;
+ err |= put_user(*tmp2, tmp); tmp++; tmp2++;
+ err |= put_user(*tmp2, tmp); tmp++; tmp2++;
+ err |= put_user(*tmp2, tmp); tmp++; tmp2++;
+ err |= put_user(*tmp2, tmp); tmp++; tmp2 += 3;
+ }
+ return err;
+}
+
+int i387_user_to_hard (struct i387_hard_struct * hard,
+ struct user_i387_struct * user)
+{
+ int i, err = 0;
+ short *tmp, *tmp2;
+
+#define GET(x) err |= get_user (hard->x, &user->x)
+ GET(cwd2);
+ GET(swd2);
+ GET(twd2);
+ GET(fip2);
+ GET(fcs2);
+ GET(foo2);
+ GET(fos2);
+#undef GET
+
+ tmp2 = (short *)&hard->st_space2;
+ tmp = (short *)&user->st_space2;
+
+ for (i = 0; i < 8; i++) {
+ err |= get_user(*tmp2, tmp); tmp++; tmp2++;
+ err |= get_user(*tmp2, tmp); tmp++; tmp2++;
+ err |= get_user(*tmp2, tmp); tmp++; tmp2++;
+ err |= get_user(*tmp2, tmp); tmp++; tmp2++;
+ err |= get_user(*tmp2, tmp); tmp++; tmp2 += 3;
+ }
+ return err;
+}
+
+/*
+ * We do not have to copy all 512 bytes for now
+ */
+void i387_hard_to_hard (struct i387_hard_struct * hard1,
+ struct i387_hard_struct * hard2)
+{
+ int i;
+ short *tmp, *tmp2;
+
+ hard1->cwd2 = hard2->cwd2;
+ hard1->swd2 = hard2->swd2;
+ hard1->twd2 = hard2->twd2;
+ hard1->fip2 = hard2->fip2;
+ hard1->fcs2 = hard2->fcs2;
+ hard1->foo2 = hard2->foo2;
+ hard1->fos2 = hard2->fos2;
+
+ tmp2 = (short *)&hard1->st_space2;
+ tmp = (short *)&hard2->st_space2;
+
+ for (i = 0; i < 8; i++) {
+ *tmp2 = *tmp; tmp++; tmp2++;
+ *tmp2 = *tmp; tmp++; tmp2++;
+ *tmp2 = *tmp; tmp++; tmp2++;
+ *tmp2 = *tmp; tmp++; tmp2++;
+ *tmp2 = *tmp; tmp++; tmp2 += 3;
+ }
+}
+
+#endif
+
+/*
* Save a segment.
*/
#define savesegment(seg,value) \
@@ -690,8 +819,8 @@
/*
* switch_to(x,yn) should switch tasks from x to y.
*
- * We fsave/fwait so that an exception goes off at the right time
- * (as a call from the fsave or fwait in effect) rather than to
+ * We fpu_save so that an exception goes off at the right time
+ * (as a call from the f*save or fwait in effect) rather than to
* the wrong process. Lazy FP saving no longer makes any sense
* with modern CPU's, and this simplifies a lot of things (SMP
* and UP become the same).
--- linux/arch/i386/kernel/setup.c.orig2 Wed Feb 3 17:05:49 1999
+++ linux/arch/i386/kernel/setup.c Wed Feb 3 17:06:23 1999
@@ -46,6 +46,7 @@

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 ..
--- linux/arch/i386/config.in.orig2 Wed Feb 3 11:09:49 1999
+++ linux/arch/i386/config.in Wed Feb 3 18:36:01 1999
@@ -16,7 +16,8 @@
486/Cx486 CONFIG_M486 \
586/K5/5x86/6x86 CONFIG_M586 \
Pentium/K6/TSC CONFIG_M586TSC \
- PPro/6x86MX CONFIG_M686" PPro
+ PPro/6x86MX/PII CONFIG_M686 \
+ PIII/Xeon/Deschutes CONFIG_M686FX" PIII
#
# Define implied options from the CPU selection here
#
@@ -31,6 +32,9 @@
fi
if [ "$CONFIG_M686" = "y" ]; then
define_bool CONFIG_X86_GOOD_APIC y
+fi
+if [ "$CONFIG_M686FX" = "y" ]; then
+ define_bool CONFIG_X86_FX y
fi

bool 'Math emulation' CONFIG_MATH_EMULATION
--- linux/Documentation/Configure.help.orig2 Wed Feb 3 18:33:19 1999
+++ linux/Documentation/Configure.help Wed Feb 3 18:37:56 1999
@@ -1593,9 +1593,10 @@
all x86 CPU types (albeit not optimally fast), you can specify
"386" here.

- If you specify one of "486" or "Pentium" or "PPro", then the kernel
- will not necessarily run on earlier architectures (ie a Pentium
- optimized kernel will run on a PPro, but not necessarily on a i486).
+ If you specify one of "486" or "Pentium" or "PPro" or "PIII", then
+ the kernel will not necessarily run on earlier architectures (ie a
+ Pentium optimized kernel will run on a PPro, but not necessarily on
+ a i486).

Here are the settings recommended for greatest speed:
- "386" for the AMD/Cyrix/Intel 386DX/DXL/SL/SLC/SX and
@@ -1608,6 +1609,8 @@
This option will assume that you have a time stamp counter.
- "PPro" for the Cyrix/IBM/National Semiconductor 6x86MX, MII and
Intel Pentium II/Pentium Pro.
+ - "PIII/Xeon/Deschutes" for the PIII (Katmai), Xeon and later PIIs
+ with the Deschutes core. You have to chose this for MMX2 support.

If you don't know what to do, choose "386".

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/