this is the newest x86 SMP patchset (attached), against 2.3.99-pre5. The
patch is also available from:

        http://www.redhat.com/~mingo/smp-x86-patches/smp-2.3.99-5-B2

Changes:

- external APIC (82489DX) code rewrite, default configuration handling
  rewrite and fixes (Maciej W. Rozycki, tested by Eric Gilmore)

- support for i486 SMP boxes [yeah! :-)] (Maciej W. Rozycki)

- various fixes and cleanups (Maciej W. Rozycki, me)

- fixed CPU/process stats in UP-IOAPIC mode, first reported by Gabor Vitez
  (me)

some small unrelated x86 items:

- added the string-i486.h assembly version of strstr to asm-i386/string.h
  because it's much faster than the lib/ version. (me)

- added mem=exactmap option to enable setting of an exact e820 memory map,
  as specified by the user. Right now the kernel adds an unconditional
  low-RAM e820 region if mem= is added. (me)

with this patch applied the x86 SMP/APIC subsystem is again in 'no known
bugs' status - please resend reports to me if any problem is still
unfixed, or any new problem arises. The patch has been sanity booted on
8-way, dual, UP-IOAPIC and UP (486) systems.

        Ingo
--- linux/include/asm-i386/apic.h.orig  Sat Feb 12 19:48:05 2000
+++ linux/include/asm-i386/apic.h       Wed Apr 12 03:41:39 2000
@@ -3,6 +3,7 @@
 
 #include <linux/config.h>
 #include <asm/apicdef.h>
+#include <asm/system.h>
 
 #define APIC_DEBUG 1
 
@@ -20,7 +21,12 @@
 
 extern __inline void apic_write(unsigned long reg, unsigned long v)
 {
-       *((volatile unsigned long *)(APIC_BASE+reg))=v;
+       *((volatile unsigned long *)(APIC_BASE+reg)) = v;
+}
+
+extern __inline void apic_write_atomic(unsigned long reg, unsigned long v)
+{
+       xchg((volatile unsigned long *)(APIC_BASE+reg), v);
 }
 
 extern __inline unsigned long apic_read(unsigned long reg)
@@ -32,30 +38,33 @@
 
 #ifdef CONFIG_X86_GOOD_APIC
 # define FORCE_READ_AROUND_WRITE 0
-# define apic_readaround(x)
+# define apic_read_around(x)
+# define apic_write_around(x,y) apic_write((x),(y))
 #else
 # define FORCE_READ_AROUND_WRITE 1
-# define apic_readaround(x) apic_read(x)
+# define apic_read_around(x) apic_read(x)
+# define apic_write_around(x,y) apic_write_atomic((x),(y))
 #endif
 
-#define apic_write_around(x,y) \
-               do { apic_readaround(x); apic_write(x,y); } while (0)
-
 extern inline void ack_APIC_irq(void)
 {
-        /* Clear the IPI */
-
-       apic_readaround(APIC_EOI);
        /*
-        * on P6+ cores (CONFIG_X86_GOOD_APIC) ack_APIC_irq() actually
-        * gets compiled as a single instruction ... yummie.
+        * ack_APIC_irq() actually gets compiled as a single instruction:
+        * - a single rmw on Pentium/82489DX
+        * - a single write on P6+ cores (CONFIG_X86_GOOD_APIC)
+        * ... yummie.
         */
-        apic_write(APIC_EOI, 0); /* Docs say use 0 for future compatibility */
+
+       /* Docs say use 0 for future compatibility */
+       apic_write_around(APIC_EOI, 0);
 }
 
 extern int get_maxlvt(void);
+extern void connect_bsp_APIC (void);
+extern void disconnect_bsp_APIC (void);
 extern void disable_local_APIC (void);
 extern void cache_APIC_registers (void);
+extern void sync_Arb_IDs(void);
 extern void setup_local_APIC (void);
 extern void init_apic_mappings(void);
 extern void smp_local_timer_interrupt(struct pt_regs * regs);
--- linux/include/asm-i386/apicdef.h.orig       Thu Jan 20 18:51:42 2000
+++ linux/include/asm-i386/apicdef.h    Wed Apr 12 03:41:11 2000
@@ -29,8 +29,6 @@
 #define                        SET_APIC_LOGICAL_ID(x)  (((x)<<24))
 #define                        APIC_ALL_CPUS           0xFF
 #define                APIC_DFR        0xE0
-#define                        GET_APIC_DFR(x)         (((x)>>28)&0x0F)
-#define                        SET_APIC_DFR(x)         ((x)<<28)
 #define                APIC_SPIV       0xF0
 #define                APIC_ISR        0x100
 #define                APIC_TMR        0x180
@@ -47,22 +45,23 @@
 #define                        APIC_DEST_SELF          0x40000
 #define                        APIC_DEST_ALLINC        0x80000
 #define                        APIC_DEST_ALLBUT        0xC0000
-#define                        APIC_DEST_RR_MASK       0x30000
-#define                        APIC_DEST_RR_INVALID    0x00000
-#define                        APIC_DEST_RR_INPROG     0x10000
-#define                        APIC_DEST_RR_VALID      0x20000
-#define                        APIC_DEST_LEVELTRIG     0x08000
-#define                        APIC_DEST_ASSERT        0x04000
-#define                        APIC_DEST_BUSY          0x01000
+#define                        APIC_ICR_RR_MASK        0x30000
+#define                        APIC_ICR_RR_INVALID     0x00000
+#define                        APIC_ICR_RR_INPROG      0x10000
+#define                        APIC_ICR_RR_VALID       0x20000
+#define                        APIC_INT_LEVELTRIG      0x08000
+#define                        APIC_INT_ASSERT         0x04000
+#define                        APIC_ICR_BUSY           0x01000
 #define                        APIC_DEST_LOGICAL       0x00800
-#define                        APIC_DEST_DM_FIXED      0x00000
-#define                        APIC_DEST_DM_LOWEST     0x00100
-#define                        APIC_DEST_DM_SMI        0x00200
-#define                        APIC_DEST_DM_REMRD      0x00300
-#define                        APIC_DEST_DM_NMI        0x00400
-#define                        APIC_DEST_DM_INIT       0x00500
-#define                        APIC_DEST_DM_STARTUP    0x00600
-#define                        APIC_DEST_VECTOR_MASK   0x000FF
+#define                        APIC_DM_FIXED           0x00000
+#define                        APIC_DM_LOWEST          0x00100
+#define                        APIC_DM_SMI             0x00200
+#define                        APIC_DM_REMRD           0x00300
+#define                        APIC_DM_NMI             0x00400
+#define                        APIC_DM_INIT            0x00500
+#define                        APIC_DM_STARTUP         0x00600
+#define                        APIC_DM_EXTINT          0x00700
+#define                        APIC_VECTOR_MASK        0x000FF
 #define                APIC_ICR2       0x310
 #define                        GET_APIC_DEST_FIELD(x)  (((x)>>24)&0xFF)
 #define                        SET_APIC_DEST_FIELD(x)  ((x)<<24)
--- linux/include/asm-i386/bugs.h.orig  Sat Feb 12 19:56:00 2000
+++ linux/include/asm-i386/bugs.h       Wed Apr 12 03:41:44 2000
@@ -21,8 +21,6 @@
 #include <asm/processor.h>
 #include <asm/msr.h>
 
-#define CONFIG_BUGi386
-
 static int __init no_halt(char *s)
 {
        boot_cpu_data.hlt_works_ok = 0;
@@ -370,16 +368,18 @@
 }
  
 /*
- * Check wether we are able to run this kernel safely on SMP.
+ * Check whether we are able to run this kernel safely on SMP.
  *
  * - In order to run on a i386, we need to be compiled for i386
  *   (for due to lack of "invlpg" and working WP on a i386)
  * - In order to run on anything without a TSC, we need to be
  *   compiled for a i486.
- * - In order to work on a Pentium/SMP machine, we need to be
- *   compiled for a Pentium or lower, as a PPro config implies
- *   a properly working local APIC without the need to do extra
- *   reads from the APIC.
+ * - In order to support the local APIC on a buggy Pentium machine,
+ *   we need to be compiled with CONFIG_X86_GOOD_APIC disabled,
+ *   which happens implicitly if compiled for a Pentium or lower
+ *   (unless an advanced selection of CPU features is used) as an
+ *   otherwise config implies a properly working local APIC without
+ *   the need to do extra reads from the APIC.
 */
 
 static void __init check_config(void)
@@ -411,11 +411,18 @@
 #endif
 
 /*
- * If we were told we had a good APIC for SMP, we'd better be a PPro
- */
-#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");
+ * If we were told we had a good local APIC, check for buggy Pentia,
+ * i.e. all B steppings and the C2 stepping of P54C when using their
+ * integrated APIC (see 11AP erratum in "Pentium Processor
+ * Specification Update").
+ */
+#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_GOOD_APIC)
+       if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL
+           && boot_cpu_data.x86_capability & X86_FEATURE_APIC
+           && boot_cpu_data.x86 == 5
+           && boot_cpu_data.x86_model == 2
+           && (boot_cpu_data.x86_mask < 6 || boot_cpu_data.x86_mask == 11))
+               panic("Kernel compiled for PPro+, assumes a local APIC without the 
+read-before-write bug!");
 #endif
 }
 
--- linux/include/asm-i386/mpspec.h.orig        Wed Apr 12 03:40:55 2000
+++ linux/include/asm-i386/mpspec.h     Wed Apr 12 04:05:13 2000
@@ -13,6 +13,11 @@
  
 #define SMP_MAGIC_IDENT        (('_'<<24)|('P'<<16)|('M'<<8)|'_')
 
+/*
+ * a maximum of 16 APICs with the current APIC ID architecture.
+ */
+#define MAX_APICS 16
+
 struct intel_mp_floating
 {
        char mpf_signature[4];          /* "_MP_"                       */
@@ -144,7 +149,8 @@
 enum mp_bustype {
        MP_BUS_ISA,
        MP_BUS_EISA,
-       MP_BUS_PCI
+       MP_BUS_PCI,
+       MP_BUS_MCA
 };
 extern int mp_bus_id_to_type [MAX_MP_BUSSES];
 extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES];
@@ -155,7 +161,7 @@
 extern void find_smp_config (void);
 extern void get_smp_config (void);
 extern int nr_ioapics;
-extern int apic_version [NR_CPUS];
+extern int apic_version [MAX_APICS];
 extern int mp_bus_id_to_type [MAX_MP_BUSSES];
 extern int mp_irq_entries;
 extern struct mpc_config_intsrc mp_irqs [MAX_IRQ_SOURCES];
--- linux/include/asm-i386/string.h.orig        Wed Apr 12 03:41:02 2000
+++ linux/include/asm-i386/string.h     Wed Apr 12 04:08:01 2000
@@ -452,6 +452,36 @@
 }
 /* end of additional stuff */
 
+#define __HAVE_ARCH_STRSTR
+extern inline char * strstr(const char * cs,const char * ct)
+{
+int    d0, d1;
+register char * __res;
+__asm__ __volatile__(
+       "movl %6,%%edi\n\t"
+       "repne\n\t"
+       "scasb\n\t"
+       "notl %%ecx\n\t"
+       "decl %%ecx\n\t"        /* NOTE! This also sets Z if searchstring='' */
+       "movl %%ecx,%%edx\n"
+       "1:\tmovl %6,%%edi\n\t"
+       "movl %%esi,%%eax\n\t"
+       "movl %%edx,%%ecx\n\t"
+       "repe\n\t"
+       "cmpsb\n\t"
+       "je 2f\n\t"             /* also works for empty string, see above */
+       "xchgl %%eax,%%esi\n\t"
+       "incl %%esi\n\t"
+       "cmpb $0,-1(%%eax)\n\t"
+       "jne 1b\n\t"
+       "xorl %%eax,%%eax\n\t"
+       "2:"
+       :"=a" (__res), "=&c" (d0), "=&S" (d1)
+       :"0" (0), "1" (0xffffffff), "2" (cs), "g" (ct)
+       :"dx", "di");
+return __res;
+}
+
 /*
  * This looks horribly ugly, but the compiler can optimize it totally,
  * as we by now know that both pattern and count is constant..
--- linux/arch/i386/kernel/apic.c.orig  Fri Feb 11 17:19:45 2000
+++ linux/arch/i386/kernel/apic.c       Wed Apr 12 03:55:45 2000
@@ -4,7 +4,9 @@
  *     (c) 1999, 2000 Ingo Molnar <[EMAIL PROTECTED]>
  *
  *     Fixes
- *     Maciej W. Rozycki       :       Bits for genuine 82489DX timers
+ *     Maciej W. Rozycki       :       Bits for genuine 82489DX APICs;
+ *                                     thanks to Eric Gilmore for
+ *                                     testing these extensively
  */
 
 #include <linux/config.h>
@@ -44,32 +46,96 @@
        return maxlvt;
 }
 
-void disable_local_APIC (void)
+static void clear_local_APIC(void)
 {
-       unsigned long value;
-        int maxlvt;
+       int maxlvt;
+       unsigned long v;
+
+       maxlvt = get_maxlvt();
 
        /*
-        * Disable APIC
+        * Careful: we have to set masks only first to deassert
+        * any level-triggered sources.
         */
-       value = apic_read(APIC_SPIV);
-       value &= ~(1<<8);
-       apic_write(APIC_SPIV,value);
+       v = apic_read(APIC_LVTT);
+       apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED);
+       v = apic_read(APIC_LVT0);
+       apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED);
+       v = apic_read(APIC_LVT1);
+       apic_write_around(APIC_LVT1, v | APIC_LVT_MASKED);
+       if (maxlvt >= 3) {
+               v = apic_read(APIC_LVTERR);
+               apic_write_around(APIC_LVTERR, v | APIC_LVT_MASKED);
+       }
+       if (maxlvt >= 4) {
+               v = apic_read(APIC_LVTPC);
+               apic_write_around(APIC_LVTPC, v | APIC_LVT_MASKED);
+       }
 
        /*
         * Clean APIC state for other OSs:
         */
-       value = apic_read(APIC_SPIV);
-       value &= ~(1<<8);
-       apic_write(APIC_SPIV,value);
-       maxlvt = get_maxlvt();
-       apic_write_around(APIC_LVTT, 0x00010000);
-       apic_write_around(APIC_LVT0, 0x00010000);
-       apic_write_around(APIC_LVT1, 0x00010000);
+       apic_write_around(APIC_LVTT, APIC_LVT_MASKED);
+       apic_write_around(APIC_LVT0, APIC_LVT_MASKED);
+       apic_write_around(APIC_LVT1, APIC_LVT_MASKED);
        if (maxlvt >= 3)
-               apic_write_around(APIC_LVTERR, 0x00010000);
+               apic_write_around(APIC_LVTERR, APIC_LVT_MASKED);
        if (maxlvt >= 4)
-               apic_write_around(APIC_LVTPC, 0x00010000);
+               apic_write_around(APIC_LVTPC, APIC_LVT_MASKED);
+}
+
+void __init connect_bsp_APIC(void)
+{
+       if (pic_mode) {
+               /*
+                * Do not trust the local APIC being empty at bootup.
+                */
+               clear_local_APIC();
+               /*
+                * PIC mode, enable symmetric IO mode in the IMCR,
+                * i.e. connect BSP's local APIC to INT and NMI lines.
+                */
+               printk("leaving PIC mode, enabling symmetric IO mode.\n");
+               outb(0x70, 0x22);
+               outb(0x01, 0x23);
+       }
+}
+
+void disconnect_bsp_APIC(void)
+{
+       if (pic_mode) {
+               /*
+                * Put the board back into PIC mode (has an effect
+                * only on certain older boards).  Note that APIC
+                * interrupts, including IPIs, won't work beyond
+                * this point!  The only exception are INIT IPIs.
+                */
+               printk("disabling symmetric IO mode, entering PIC mode.\n");
+               outb(0x70, 0x22);
+               outb(0x00, 0x23);
+       }
+}
+
+void disable_local_APIC(void)
+{
+       unsigned long value;
+
+       clear_local_APIC();
+
+       /*
+        * Disable APIC (implies clearing of registers
+        * for 82489DX!).
+        */
+       value = apic_read(APIC_SPIV);
+       value &= ~(1<<8);
+       apic_write_around(APIC_SPIV, value);
+}
+
+void __init sync_Arb_IDs(void)
+{
+       Dprintk("Synchronizing Arb IDs.\n");
+       apic_write_around(APIC_ICR, APIC_DEST_ALLINC | APIC_INT_LEVELTRIG
+                               | APIC_DM_INIT);
 }
 
 extern void __error_in_apic_c (void);
@@ -78,6 +144,9 @@
 {
        unsigned long value, ver, maxlvt;
 
+       value = apic_read(APIC_LVR);
+       ver = GET_APIC_VERSION(value);
+
        if ((SPURIOUS_APIC_VECTOR & 0x0f) != 0x0f)
                __error_in_apic_c();
 
@@ -87,11 +156,12 @@
        if (!test_bit(GET_APIC_ID(apic_read(APIC_ID)), &phys_cpu_present_map))
                BUG();
 
-       value = apic_read(APIC_SPIV);
+       value = apic_read(APIC_SPIV);
+       value &= ~APIC_VECTOR_MASK;
        /*
         * Enable APIC
         */
-       value |= (1<<8);
+       value |= (1<<8);
 
        /*
         * Some unknown Intel IO/APIC (or APIC) errata is biting us with
@@ -106,9 +176,9 @@
         *   PCI Ne2000 networking cards and PII/PIII processors, dual
         *   BX chipset. ]
         */
-#if 0
+#if 0
        /* Enable focus processor (bit==0) */
-       value &= ~(1<<9);
+       value &= ~(1<<9);
 #else
        /* Disable focus processor (bit==1) */
        value |= (1<<9);
@@ -117,7 +187,7 @@
         * Set spurious IRQ vector
         */
        value |= SPURIOUS_APIC_VECTOR;
-       apic_write(APIC_SPIV,value);
+       apic_write_around(APIC_SPIV, value);
 
        /*
         * Set up LVT0, LVT1:
@@ -126,48 +196,44 @@
         * strictly necessery in pure symmetric-IO mode, but sometimes
         * we delegate interrupts to the 8259A.
         */
-       if (!smp_processor_id()) {
-               value = 0x00000700;
+       /*
+        * TODO: set up through-local-APIC from through-I/O-APIC? --macro
+        */
+       value = apic_read(APIC_LVT0) & APIC_LVT_MASKED;
+       if (!smp_processor_id() && (pic_mode || !value)) {
+               value = APIC_DM_EXTINT;
                printk("enabled ExtINT on CPU#%d\n", smp_processor_id());
        } else {
-               value = 0x00010700;
+               value = APIC_DM_EXTINT | APIC_LVT_MASKED;
                printk("masked ExtINT on CPU#%d\n", smp_processor_id());
        }
-       apic_write_around(APIC_LVT0,value);
+       apic_write_around(APIC_LVT0, value);
 
        /*
         * only the BP should see the LINT1 NMI signal, obviously.
         */
        if (!smp_processor_id())
-               value = 0x00000400;             // unmask NMI
+               value = APIC_DM_NMI;
        else
-               value = 0x00010400;             // mask NMI
-       apic_write_around(APIC_LVT1,value);
+               value = APIC_DM_NMI | APIC_LVT_MASKED;
+       if (!APIC_INTEGRATED(ver))              /* 82489DX */
+               value |= APIC_LVT_LEVEL_TRIGGER;
+       apic_write_around(APIC_LVT1, value);
 
-       value = apic_read(APIC_LVR);
-       ver = GET_APIC_VERSION(value);
        if (APIC_INTEGRATED(ver)) {             /* !82489DX */
                maxlvt = get_maxlvt();
-               /*
-                * Due to the Pentium erratum 3AP.
-                */
-               if (maxlvt > 3) {
-                       apic_readaround(APIC_SPIV); // not strictly necessery
+               if (maxlvt > 3)         /* Due to the Pentium erratum 3AP. */
                        apic_write(APIC_ESR, 0);
-               }
                value = apic_read(APIC_ESR);
                printk("ESR value before enabling vector: %08lx\n", value);
 
-               value = apic_read(APIC_LVTERR);
                value = ERROR_APIC_VECTOR;      // enables sending errors
-               apic_write(APIC_LVTERR,value);
+               apic_write_around(APIC_LVTERR, value);
                /*
                 * spec says clear errors after enabling vector.
                 */
-               if (maxlvt != 3) {
-                       apic_readaround(APIC_SPIV);
+               if (maxlvt > 3)
                        apic_write(APIC_ESR, 0);
-               }
                value = apic_read(APIC_ESR);
                printk("ESR value after enabling vector: %08lx\n", value);
        } else
@@ -177,22 +243,23 @@
         * Set Task Priority to 'accept all'. We never change this
         * later on.
         */
-       value = apic_read(APIC_TASKPRI);
-       value &= ~APIC_TPRI_MASK;
-       apic_write(APIC_TASKPRI,value);
+       value = apic_read(APIC_TASKPRI);
+       value &= ~APIC_TPRI_MASK;
+       apic_write_around(APIC_TASKPRI, value);
 
        /*
         * Set up the logical destination ID and put the
         * APIC into flat delivery mode.
         */
-       value = apic_read(APIC_LDR);
+       value = apic_read(APIC_LDR);
        value &= ~APIC_LDR_MASK;
        value |= (1<<(smp_processor_id()+24));
-       apic_write(APIC_LDR,value);
+       apic_write_around(APIC_LDR, value);
 
-       value = apic_read(APIC_DFR);
-       value |= SET_APIC_DFR(0xf);
-       apic_write(APIC_DFR, value);
+       /*
+        * Must be "all ones" explicitly for 82489DX.
+        */
+       apic_write_around(APIC_DFR, 0xffffffff);
 }
 
 void __init init_apic_mappings(void)
@@ -214,6 +281,13 @@
        set_fixmap_nocache(FIX_APIC_BASE, apic_phys);
        Dprintk("mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys);
 
+       /*
+        * Fetch the APIC ID of the BSP in case we have a
+        * default configuration (or the MP table is broken).
+        */
+       if (boot_cpu_id == -1U)
+               boot_cpu_id = GET_APIC_ID(apic_read(APIC_ID));
+
 #ifdef CONFIG_X86_IO_APIC
        {
                unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;
@@ -285,7 +359,7 @@
         * chipset timer can cause.
         */
 
-       } while (delta<300);
+       } while (delta < 300);
 }
 
 /*
@@ -305,21 +379,19 @@
 {
        unsigned int lvtt1_value, tmp_value;
 
-       tmp_value = apic_read(APIC_LVTT);
        lvtt1_value = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) |
                        APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR;
-       apic_write(APIC_LVTT, lvtt1_value);
+       apic_write_around(APIC_LVTT, lvtt1_value);
 
        /*
         * Divide PICLK by 16
         */
        tmp_value = apic_read(APIC_TDCR);
-       apic_write(APIC_TDCR, (tmp_value
+       apic_write_around(APIC_TDCR, (tmp_value
                                & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE))
                                | APIC_TDR_DIV_16);
 
-       tmp_value = apic_read(APIC_TMICT);
-       apic_write(APIC_TMICT, clocks/APIC_DIVISOR);
+       apic_write_around(APIC_TMICT, clocks/APIC_DIVISOR);
 }
 
 void setup_APIC_timer(void * data)
@@ -353,6 +425,12 @@
 
        t0 = apic_read(APIC_TMCCT)*APIC_DIVISOR;
        do {
+               /*
+                * It looks like the 82489DX cannot handle
+                * consecutive reads of the TMCCT register well;
+                * this dummy read prevents it from a lockup.
+                */
+               apic_read(APIC_SPIV);
                t1 = apic_read(APIC_TMCCT)*APIC_DIVISOR;
                delta = (int)(t0 - t1 - slice*(smp_processor_id()+1));
        } while (delta < 0);
@@ -490,6 +568,41 @@
 
 #undef APIC_DIVISOR
 
+#ifdef CONFIG_SMP
+static inline void handle_smp_time (int user, int cpu)
+{
+       int system = !user;
+       struct task_struct * p = current;
+       /*
+        * After doing the above, we need to make like
+        * a normal interrupt - otherwise timer interrupts
+        * ignore the global interrupt lock, which is the
+        * WrongThing (tm) to do.
+        */
+
+       irq_enter(cpu, 0);
+       update_one_process(p, 1, user, system, cpu);
+       if (p->pid) {
+               p->counter -= 1;
+               if (p->counter <= 0) {
+                       p->counter = 0;
+                       p->need_resched = 1;
+               }
+               if (p->priority < DEF_PRIORITY) {
+                       kstat.cpu_nice += user;
+                       kstat.per_cpu_nice[cpu] += user;
+               } else {
+                       kstat.cpu_user += user;
+                       kstat.per_cpu_user[cpu] += user;
+               }
+               kstat.cpu_system += system;
+               kstat.per_cpu_system[cpu] += system;
+
+       }
+       irq_exit(cpu, 0);
+}
+#endif
+
 /*
  * Local timer interrupt handler. It does both profiling and
  * process statistics/rescheduling.
@@ -502,7 +615,6 @@
 
 inline void smp_local_timer_interrupt(struct pt_regs * regs)
 {
-       int user = (user_mode(regs) != 0);
        int cpu = smp_processor_id();
 
        /*
@@ -511,13 +623,8 @@
         * updated with atomic operations). This is especially
         * useful with a profiling multiplier != 1
         */
-       if (!user)
-               x86_do_profile(regs->eip);
 
        if (--prof_counter[cpu] <= 0) {
-               int system = 1 - user;
-               struct task_struct * p = current;
-
                /*
                 * The multiplier may have changed since the last time we got
                 * to this point as a result of the user writing to
@@ -532,33 +639,9 @@
                        prof_old_multiplier[cpu] = prof_counter[cpu];
                }
 
-               /*
-                * After doing the above, we need to make like
-                * a normal interrupt - otherwise timer interrupts
-                * ignore the global interrupt lock, which is the
-                * WrongThing (tm) to do.
-                */
-
-               irq_enter(cpu, 0);
-               update_one_process(p, 1, user, system, cpu);
-               if (p->pid) {
-                       p->counter -= 1;
-                       if (p->counter <= 0) {
-                               p->counter = 0;
-                               p->need_resched = 1;
-                       }
-                       if (p->priority < DEF_PRIORITY) {
-                               kstat.cpu_nice += user;
-                               kstat.per_cpu_nice[cpu] += user;
-                       } else {
-                               kstat.cpu_user += user;
-                               kstat.per_cpu_user[cpu] += user;
-                       }
-                       kstat.cpu_system += system;
-                       kstat.per_cpu_system[cpu] += system;
-
-               }
-               irq_exit(cpu, 0);
+#ifdef CONFIG_SMP
+               handle_smp_time(user_mode(regs), cpu);
+#endif
        }
 
        /*
@@ -603,7 +686,17 @@
  */
 asmlinkage void smp_spurious_interrupt(void)
 {
-       ack_APIC_irq();
+       unsigned long v;
+
+       /*
+        * Check if this really is a spurious interrupt and ACK it
+        * if it is a vectored one.  Just in case...
+        * Spurious interrupts should not be ACKed.
+        */
+       v = apic_read(APIC_ISR + ((SPURIOUS_APIC_VECTOR & ~0x1f) >> 1));
+       if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f)))
+               ack_APIC_irq();
+
        /* see sw-dev-man vol 3, chapter 7.4.13.5 */
        printk("spurious APIC interrupt on CPU#%d, should never happen.\n",
                        smp_processor_id());
--- linux/arch/i386/kernel/i386_ksyms.c.orig    Wed Apr 12 03:41:01 2000
+++ linux/arch/i386/kernel/i386_ksyms.c Wed Apr 12 03:41:11 2000
@@ -68,7 +68,6 @@
 EXPORT_SYMBOL_NOVERS(__down_read_failed);
 EXPORT_SYMBOL_NOVERS(__rwsem_wake);
 /* Networking helper routines. */
-EXPORT_SYMBOL(csum_partial_copy);
 EXPORT_SYMBOL(csum_partial_copy_generic);
 /* Delay loops */
 EXPORT_SYMBOL(__udelay);
@@ -84,7 +83,6 @@
 
 EXPORT_SYMBOL(strtok);
 EXPORT_SYMBOL(strpbrk);
-EXPORT_SYMBOL(strstr);
 
 EXPORT_SYMBOL(strncpy_from_user);
 EXPORT_SYMBOL(__strncpy_from_user);
--- linux/arch/i386/kernel/i8259.c.orig Wed Apr 12 03:41:01 2000
+++ linux/arch/i386/kernel/i8259.c      Wed Apr 12 03:41:11 2000
@@ -415,7 +415,7 @@
        for (i = 0; i < NR_IRQS; i++) {
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = 0;
-               irq_desc[i].depth = 0;
+               irq_desc[i].depth = 1;
 
                if (i < 16) {
                        /*
--- linux/arch/i386/kernel/io_apic.c.orig       Wed Apr 12 03:41:01 2000
+++ linux/arch/i386/kernel/io_apic.c    Wed Apr 12 04:05:13 2000
@@ -13,7 +13,9 @@
  *     and Ingo Molnar <[EMAIL PROTECTED]>
  *
  *     Fixes
- *     Maciej W. Rozycki       :       Bits for genuine 82489DX APICs
+ *     Maciej W. Rozycki       :       Bits for genuine 82489DX APICs;
+ *                                     thanks to Eric Gilmore for
+ *                                     testing these extensively
  */
 
 #include <linux/mm.h>
@@ -46,9 +48,6 @@
 /* MP IRQ source entries */
 int mp_irq_entries = 0;
 
-/* non-0 if default (table-less) MP configuration */
-int mpc_default_type = 0;
-
 /*
  * Rough estimation of how many shared IRQs there are, can
  * be changed anytime.
@@ -166,7 +165,7 @@
 
 #define MAX_PIRQS 8
 int pirq_entries [MAX_PIRQS];
-int pirqs_enabled;
+int pirqs_enabled = 0;
 int skip_ioapic_setup = 0;
 
 static int __init ioapic_setup(char *str)
@@ -235,7 +234,8 @@
                int lbus = mp_irqs[i].mpc_srcbus;
 
                if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA ||
-                    mp_bus_id_to_type[lbus] == MP_BUS_EISA) &&
+                    mp_bus_id_to_type[lbus] == MP_BUS_EISA ||
+                    mp_bus_id_to_type[lbus] == MP_BUS_MCA) &&
                    (mp_irqs[i].mpc_irqtype == type) &&
                    (mp_irqs[i].mpc_srcbusirq == 0x00))
 
@@ -260,13 +260,15 @@
                        if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic)
                                break;
 
-               if ((apic || IO_APIC_IRQ(mp_irqs[i].mpc_dstirq)) &&
-                   (mp_bus_id_to_type[lbus] == MP_BUS_PCI) &&
+               if ((mp_bus_id_to_type[lbus] == MP_BUS_PCI) &&
                    !mp_irqs[i].mpc_irqtype &&
                    (bus == mp_bus_id_to_pci_bus[mp_irqs[i].mpc_srcbus]) &&
                    (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f))) {
                        int irq = pin_2_irq(i,apic,mp_irqs[i].mpc_dstirq);
 
+                       if (!(apic || IO_APIC_IRQ(irq)))
+                               continue;
+
                        if (pci_pin == (mp_irqs[i].mpc_srcbusirq & 3))
                                return irq;
                        /*
@@ -298,15 +300,27 @@
  * EISA conforming in the MP table, that means its trigger type must
  * be read in from the ELCR */
 
-#define default_EISA_trigger(idx)      (EISA_ELCR(mp_irqs[idx].mpc_dstirq))
+#define default_EISA_trigger(idx)      (EISA_ELCR(mp_irqs[idx].mpc_srcbusirq))
 #define default_EISA_polarity(idx)     (0)
 
-/* ISA interrupts are always polarity zero edge triggered, even when
- * listed as conforming in the MP table. */
+/* ISA interrupts are always polarity zero edge triggered,
+ * when listed as conforming in the MP table. */
 
 #define default_ISA_trigger(idx)       (0)
 #define default_ISA_polarity(idx)      (0)
 
+/* PCI interrupts are always polarity one level triggered,
+ * when listed as conforming in the MP table. */
+
+#define default_PCI_trigger(idx)       (1)
+#define default_PCI_polarity(idx)      (1)
+
+/* MCA interrupts are always polarity zero level triggered,
+ * when listed as conforming in the MP table. */
+
+#define default_MCA_trigger(idx)       (1)
+#define default_MCA_polarity(idx)      (0)
+
 static int __init MPBIOS_polarity(int idx)
 {
        int bus = mp_irqs[idx].mpc_srcbus;
@@ -326,14 +340,19 @@
                                        polarity = default_ISA_polarity(idx);
                                        break;
                                }
-                               case MP_BUS_EISA:
+                               case MP_BUS_EISA: /* EISA pin */
                                {
                                        polarity = default_EISA_polarity(idx);
                                        break;
                                }
                                case MP_BUS_PCI: /* PCI pin */
                                {
-                                       polarity = 1;
+                                       polarity = default_PCI_polarity(idx);
+                                       break;
+                               }
+                               case MP_BUS_MCA: /* MCA pin */
+                               {
+                                       polarity = default_MCA_polarity(idx);
                                        break;
                                }
                                default:
@@ -385,19 +404,24 @@
                {
                        switch (mp_bus_id_to_type[bus])
                        {
-                               case MP_BUS_ISA:
+                               case MP_BUS_ISA: /* ISA pin */
                                {
                                        trigger = default_ISA_trigger(idx);
                                        break;
                                }
-                               case MP_BUS_EISA:
+                               case MP_BUS_EISA: /* EISA pin */
                                {
                                        trigger = default_EISA_trigger(idx);
                                        break;
                                }
-                               case MP_BUS_PCI: /* PCI pin, level */
+                               case MP_BUS_PCI: /* PCI pin */
                                {
-                                       trigger = 1;
+                                       trigger = default_PCI_trigger(idx);
+                                       break;
+                               }
+                               case MP_BUS_MCA: /* MCA pin */
+                               {
+                                       trigger = default_MCA_trigger(idx);
                                        break;
                                }
                                default:
@@ -460,6 +484,7 @@
        {
                case MP_BUS_ISA: /* ISA pin */
                case MP_BUS_EISA:
+               case MP_BUS_MCA:
                {
                        irq = mp_irqs[idx].mpc_srcbusirq;
                        break;
@@ -624,8 +649,8 @@
 
        disable_8259A_irq(0);
 
-       apic_readaround(APIC_LVT0);
-       apic_write(APIC_LVT0, 0x00010700);      // mask LVT0
+       /* mask LVT0 */
+       apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
 
        init_8259A(1);
 
@@ -650,8 +675,8 @@
        /*
         * Add it to the IO-APIC irq-routing table:
         */
-       io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0));
        io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1));
+       io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0));
 
        enable_8259A_irq(0);
 }
@@ -725,8 +750,8 @@
 
        printk(KERN_DEBUG ".... IRQ redirection table:\n");
 
-       printk(KERN_DEBUG " NR Log Phy ");
-       printk(KERN_DEBUG "Mask Trig IRR Pol Stat Dest Deli Vect:   \n");
+       printk(KERN_DEBUG " NR Log Phy Mask Trig IRR Pol"
+                         " Stat Dest Deli Vect:   \n");
 
        for (i = 0; i <= reg_01.entries; i++) {
                struct IO_APIC_route_entry entry;
@@ -831,13 +856,8 @@
        print_APIC_bitfield(APIC_IRR);
 
        if (APIC_INTEGRATED(ver)) {             /* !82489DX */
-               /*
-                * Due to the Pentium erratum 3AP.
-                */
-               if (maxlvt > 3) {
-                       apic_readaround(APIC_SPIV); // not strictly necessery
+               if (maxlvt > 3)         /* Due to the Pentium erratum 3AP. */
                        apic_write(APIC_ESR, 0);
-               }
                v = apic_read(APIC_ESR);
                printk(KERN_DEBUG "... APIC ESR: %08x\n", v);
        }
@@ -879,6 +899,32 @@
        print_local_APIC(NULL);
 }
 
+void /*__init*/ print_PIC(void)
+{
+       unsigned int v, flags;
+
+       printk(KERN_DEBUG "\nprinting PIC contents\n");
+
+       v = inb(0xa1) << 8 | inb(0x21);
+       printk(KERN_DEBUG "... PIC  IMR: %04x\n", v);
+
+       v = inb(0xa0) << 8 | inb(0x20);
+       printk(KERN_DEBUG "... PIC  IRR: %04x\n", v);
+
+       __save_flags(flags);
+       __cli();
+       outb(0x0b,0xa0);
+       outb(0x0b,0x20);
+       v = inb(0xa0) << 8 | inb(0x20);
+       outb(0x0a,0xa0);
+       outb(0x0a,0x20);
+       __restore_flags(flags);
+       printk(KERN_DEBUG "... PIC  ISR: %04x\n", v);
+
+       v = inb(0x4d1) << 8 | inb(0x4d0);
+       printk(KERN_DEBUG "... PIC ELCR: %04x\n", v);
+}
+
 static void __init enable_IO_APIC(void)
 {
        struct IO_APIC_reg_01 reg_01;
@@ -890,16 +936,7 @@
        }
        if (!pirqs_enabled)
                for (i = 0; i < MAX_PIRQS; i++)
-                       pirq_entries[i] =- 1;
-
-       if (pic_mode) {
-               /*
-                * PIC mode, enable symmetric IO mode in the IMCR.
-                */
-               printk("leaving PIC mode, enabling symmetric IO mode.\n");
-               outb(0x70, 0x22);
-               outb(0x01, 0x23);
-       }
+                       pirq_entries[i] = -1;
 
        /*
         * The number of IO-APIC IRQ registers (== #pins):
@@ -925,15 +962,7 @@
         */
        clear_IO_APIC();
 
-       /*
-        * Put it back into PIC mode (has an effect only on
-        * certain older boards)
-        */
-       if (pic_mode) {
-               printk("disabling symmetric IO mode, entering PIC mode.\n");
-               outb_p(0x70, 0x22);
-               outb_p(0x00, 0x23);
-       }
+       disconnect_bsp_APIC();
 }
 
 /*
@@ -986,48 +1015,6 @@
        }
 }
 
-static void __init construct_default_ISA_mptable(void)
-{
-       int i, pos = 0;
-       const int bus_type = (mpc_default_type == 2 || mpc_default_type == 3 ||
-                             mpc_default_type == 6) ? MP_BUS_EISA : MP_BUS_ISA;
-
-       for (i = 0; i < 16; i++) {
-               if (!IO_APIC_IRQ(i))
-                       continue;
-
-               mp_irqs[pos].mpc_irqtype = mp_INT;
-               mp_irqs[pos].mpc_irqflag = 0;           /* default */
-               mp_irqs[pos].mpc_srcbus = 0;
-               mp_irqs[pos].mpc_srcbusirq = i;
-               mp_irqs[pos].mpc_dstapic = 0;
-               mp_irqs[pos].mpc_dstirq = i;
-               pos++;
-       }
-       mp_irq_entries = pos;
-       mp_bus_id_to_type[0] = bus_type;
-
-       /*
-        * MP specification 1.4 defines some extra rules for default
-        * configurations, fix them up here:
-        */
-       switch (mpc_default_type)
-       {
-               case 2:
-               /*
-                * IRQ0 is not connected:
-                */
-                       mp_irqs[0].mpc_irqtype = mp_ExtINT;
-                       break;
-               default:
-               /*
-                * pin 2 is IRQ0:
-                */
-                       mp_irqs[0].mpc_dstirq = 2;
-       }
-
-}
-
 /*
  * There is a nasty bug in some older SMP boards, their mptable lies
  * about the timer IRQ. We do the following to work around the situation:
@@ -1041,9 +1028,17 @@
        unsigned int t1 = jiffies;
 
        sti();
-       mdelay(40);
+       /* Let ten ticks pass... */
+       mdelay((10 * 1000) / HZ);
 
-       if (jiffies-t1>1)
+       /*
+        * Expect a few ticks at least, to be sure some possible
+        * glue logic does not lock up after one or two first
+        * ticks in a non-ExtINT mode.  Also the local APIC
+        * might have cached one ExtINT interrupt.  Finally, at
+        * least one tick may be lost due to delays.
+        */
+       if (jiffies - t1 > 4)
                return 1;
 
        return 0;
@@ -1257,8 +1252,14 @@
 
 static void enable_NMI_through_LVT0 (void * dummy)
 {
-       apic_readaround(APIC_LVT0);
-       apic_write(APIC_LVT0, 0x00000400);      // unmask and set to NMI
+       unsigned int v, ver;
+
+       ver = apic_read(APIC_LVR);
+       ver = GET_APIC_VERSION(ver);
+       v = APIC_DM_NMI;                        /* unmask and set to NMI */
+       if (!APIC_INTEGRATED(ver))              /* 82489DX */
+               v |= APIC_LVT_LEVEL_TRIGGER;
+       apic_write_around(APIC_LVT0, v);
 }
 
 static void setup_nmi (void)
@@ -1303,24 +1304,23 @@
 
        printk(KERN_INFO "..TIMER: vector=%d pin1=%d pin2=%d\n", vector, pin1, pin2);
 
-       /*
-        * Ok, does IRQ0 through the IOAPIC work?
-        */
-       if (timer_irq_works()) {
-               if (nmi_watchdog) {
-                       disable_8259A_irq(0);
-                       init_8259A(1);
-                       setup_nmi();
-                       enable_8259A_irq(0);
-                       if (nmi_irq_works())
-                               return;
-               } else
-                       return;
-       }
-
        if (pin1 != -1) {
-               printk(KERN_ERR "..MP-BIOS bug: 8254 timer not connected to 
IO-APIC\n");
+               /*
+                * Ok, does IRQ0 through the IOAPIC work?
+                */
+               unmask_IO_APIC_irq(0);
+               if (timer_irq_works()) {
+                       if (nmi_watchdog) {
+                               disable_8259A_irq(0);
+                               init_8259A(1);
+                               setup_nmi();
+                               enable_8259A_irq(0);
+                               nmi_irq_works();
+                       }
+                       return;
+               }
                clear_IO_APIC_pin(0, pin1);
+               printk(KERN_ERR "..MP-BIOS bug: 8254 timer not connected to 
+IO-APIC\n");
        }
 
        printk(KERN_INFO "...trying to set up timer (IRQ0) through the 8259A ... ");
@@ -1334,10 +1334,9 @@
                        printk("works.\n");
                        if (nmi_watchdog) {
                                setup_nmi();
-                               if (nmi_irq_works())
-                                       return;
-                       } else
-                               return;
+                               nmi_irq_works();
+                       }
+                       return;
                }
                /*
                 * Cleanup, just in case ...
@@ -1355,9 +1354,8 @@
 
        disable_8259A_irq(0);
        irq_desc[0].handler = &lapic_irq_type;
-       init_8259A(1);                                  // AEOI mode
-       apic_readaround(APIC_LVT0);
-       apic_write(APIC_LVT0, 0x00000000 | vector);     // Fixed mode
+       init_8259A(1);                                          /* AEOI mode */
+       apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector);   /* Fixed mode */
        enable_8259A_irq(0);
 
        if (timer_irq_works()) {
@@ -1392,20 +1390,11 @@
        printk("ENABLING IO-APIC IRQs\n");
 
        /*
-        * If there are no explicit MP IRQ entries, it's either one of the
-        * default configuration types or we are broken. In both cases it's
-        * fine to set up most of the low 16 IO-APIC pins to ISA defaults.
-        */
-       if (!mp_irq_entries) {
-               printk("no explicit IRQ entries, using default mptable\n");
-               construct_default_ISA_mptable();
-       }
-
-       /*
         * Set up the IO-APIC IRQ routing table by parsing the MP-BIOS
         * mptable:
         */
        setup_ioapic_ids_from_mpc();
+       sync_Arb_IDs();
        setup_IO_APIC_irqs();
        init_IO_APIC_traps();
        check_timer();
@@ -1421,6 +1410,7 @@
 {
        if (!smp_found_config)
                return;
+       connect_bsp_APIC();
        setup_local_APIC();
        setup_IO_APIC();
        setup_APIC_clocks();
--- linux/arch/i386/kernel/mpparse.c.orig       Wed Apr 12 03:40:53 2000
+++ linux/arch/i386/kernel/mpparse.c    Wed Apr 12 04:07:09 2000
@@ -9,7 +9,7 @@
  *             Erich Boleyn    :       MP v1.4 and additional changes.
  *             Alan Cox        :       Added EBDA scanning
  *             Ingo Molnar     :       various cleanups and rewrites
- *     Maciej W. Rozycki       :       Bits for genuine 82489DX APICs
+ *     Maciej W. Rozycki       :       Bits for default MP configurations
  */
 
 #include <linux/mm.h>
@@ -34,7 +34,7 @@
  * Various Linux-internal data structures created from the
  * MP-table.
  */
-int apic_version [NR_CPUS];
+int apic_version [MAX_APICS];
 int mp_bus_id_to_type [MAX_MP_BUSSES] = { -1, };
 int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { -1, };
 int mp_current_pci_id = 0;
@@ -42,9 +42,9 @@
 unsigned long mp_lapic_addr = 0;
 
 /* Processor that is doing the boot up */
-unsigned int boot_cpu_id = 0;
+unsigned int boot_cpu_id = -1U;
 /* Internal processor count */
-static unsigned int num_processors = 1;
+static unsigned int num_processors = 0;
 
 /* Bitmask of physically existing CPUs */
 unsigned long phys_cpu_present_map = 0;
@@ -132,13 +132,12 @@
        if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) {
                Dprintk("    Bootup CPU\n");
                boot_cpu_id = m->mpc_apicid;
-       } else
-               /* Boot CPU already counted */
-               num_processors++;
+       }
+       num_processors++;
 
-       if (m->mpc_apicid > NR_CPUS) {
-               printk("Processor #%d unused. (Max %d processors).\n",
-                       m->mpc_apicid, NR_CPUS);
+       if (m->mpc_apicid > MAX_APICS) {
+               printk("Processor #%d INVALID. (Max ID: %d).\n",
+                       m->mpc_apicid, MAX_APICS);
                return;
        }
        ver = m->mpc_apicver;
@@ -164,18 +163,18 @@
 
        if (strncmp(str, "ISA", 3) == 0) {
                mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA;
-       } else {
-       if (strncmp(str, "EISA", 4) == 0) {
+       } else if (strncmp(str, "EISA", 4) == 0) {
                mp_bus_id_to_type[m->mpc_busid] = MP_BUS_EISA;
-       } else {
-       if (strncmp(str, "PCI", 3) == 0) {
+       } else if (strncmp(str, "PCI", 3) == 0) {
                mp_bus_id_to_type[m->mpc_busid] = MP_BUS_PCI;
                mp_bus_id_to_pci_bus[m->mpc_busid] = mp_current_pci_id;
                mp_current_pci_id++;
+       } else if (strncmp(str, "MCA", 3) == 0) {
+               mp_bus_id_to_type[m->mpc_busid] = MP_BUS_MCA;
        } else {
                printk("Unknown bustype %s\n", str);
                panic("cannot handle bus - mail to [EMAIL PROTECTED]");
-       } } }
+       }
 }
 
 static void __init MP_ioapic_info (struct mpc_config_ioapic *m)
@@ -197,12 +196,22 @@
 static void __init MP_intsrc_info (struct mpc_config_intsrc *m)
 {
        mp_irqs [mp_irq_entries] = *m;
+       Dprintk("Int: type %d, pol %d, trig %d, bus %d,"
+               " IRQ %02x, APIC ID %x, APIC INT %02x\n",
+                       m->mpc_irqtype, m->mpc_irqflag & 3,
+                       (m->mpc_irqflag >> 2) & 3, m->mpc_srcbus,
+                       m->mpc_srcbusirq, m->mpc_dstapic, m->mpc_dstirq);
        if (++mp_irq_entries == MAX_IRQ_SOURCES)
                panic("Max # of irq sources exceeded!!\n");
 }
 
 static void __init MP_lintsrc_info (struct mpc_config_lintsrc *m)
 {
+       Dprintk("Lint: type %d, pol %d, trig %d, bus %d,"
+               " IRQ %02x, APIC ID %x, APIC LINT %02x\n",
+                       m->mpc_irqtype, m->mpc_irqflag & 3,
+                       (m->mpc_irqflag >> 2) &3, m->mpc_srcbusid,
+                       m->mpc_srcbusirq, m->mpc_destapic, m->mpc_destapiclint);
        /*
         * Well it seems all SMP boards in existence
         * use ExtINT/LVT1 == LINT0 and
@@ -316,6 +325,122 @@
        return num_processors;
 }
 
+static void __init construct_default_ioirq_mptable(int mpc_default_type)
+{
+       struct mpc_config_intsrc intsrc;
+       int i;
+
+       intsrc.mpc_type = MP_INTSRC;
+       intsrc.mpc_irqflag = 0;                 /* conforming */
+       intsrc.mpc_srcbus = 0;
+       intsrc.mpc_dstapic = mp_ioapics[0].mpc_apicid;
+
+       intsrc.mpc_irqtype = mp_INT;
+       for (i = 0; i < 16; i++) {
+               switch (mpc_default_type) {
+               case 2:
+                       if (i == 0 || i == 13)
+                               continue;       /* IRQ0 & IRQ13 not connected */
+                       /* fall through */
+               default:
+                       if (i == 2)
+                               continue;       /* IRQ2 is never connected */
+               }
+
+               intsrc.mpc_srcbusirq = i;
+               intsrc.mpc_dstirq = i ? i : 2;          /* IRQ0 to INTIN2 */
+               MP_intsrc_info(&intsrc);
+       }
+
+       intsrc.mpc_irqtype = mp_ExtINT;
+       intsrc.mpc_srcbusirq = 0;
+       intsrc.mpc_dstirq = 0;                          /* 8259A to INTIN0 */
+       MP_intsrc_info(&intsrc);
+}
+
+static inline void __init construct_default_ISA_mptable(int mpc_default_type)
+{
+       struct mpc_config_processor processor;
+       struct mpc_config_bus bus;
+       struct mpc_config_ioapic ioapic;
+       struct mpc_config_lintsrc lintsrc;
+       int linttypes[2] = { mp_ExtINT, mp_NMI };
+       int i;
+
+       /*
+        * local APIC has default address
+        */
+       mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
+
+       /*
+        * 2 CPUs, numbered 0 & 1.
+        */
+       processor.mpc_type = MP_PROCESSOR;
+       /* Either an integrated APIC or a discrete 82489DX. */
+       processor.mpc_apicver = mpc_default_type > 4 ? 0x10 : 0x01;
+       processor.mpc_cpuflag = CPU_ENABLED;
+       processor.mpc_cpufeature = (boot_cpu_data.x86 << 8) |
+                                  (boot_cpu_data.x86_model << 4) |
+                                  boot_cpu_data.x86_mask;
+       processor.mpc_featureflag = boot_cpu_data.x86_capability;
+       processor.mpc_reserved[0] = 0;
+       processor.mpc_reserved[1] = 0;
+       for (i = 0; i < 2; i++) {
+               processor.mpc_apicid = i;
+               MP_processor_info(&processor);
+       }
+
+       bus.mpc_type = MP_BUS;
+       bus.mpc_busid = 0;
+       switch (mpc_default_type) {
+               default:
+                       printk("???\nUnknown standard configuration %d\n",
+                               mpc_default_type);
+                       /* fall through */
+               case 1:
+               case 5:
+                       memcpy(bus.mpc_bustype, "ISA   ", 6);
+                       break;
+               case 2:
+               case 6:
+               case 3:
+                       memcpy(bus.mpc_bustype, "EISA  ", 6);
+                       break;
+               case 4:
+               case 7:
+                       memcpy(bus.mpc_bustype, "MCA   ", 6);
+       }
+       MP_bus_info(&bus);
+       if (mpc_default_type > 4) {
+               bus.mpc_busid = 1;
+               memcpy(bus.mpc_bustype, "PCI   ", 6);
+               MP_bus_info(&bus);
+       }
+
+       ioapic.mpc_type = MP_IOAPIC;
+       ioapic.mpc_apicid = 2;
+       ioapic.mpc_apicver = mpc_default_type > 4 ? 0x10 : 0x01;
+       ioapic.mpc_flags = MPC_APIC_USABLE;
+       ioapic.mpc_apicaddr = 0xFEC00000;
+       MP_ioapic_info(&ioapic);
+
+       /*
+        * We set up most of the low 16 IO-APIC pins according to MPS rules.
+        */
+       construct_default_ioirq_mptable(mpc_default_type);
+
+       lintsrc.mpc_type = MP_LINTSRC;
+       lintsrc.mpc_irqflag = 0;                /* conforming */
+       lintsrc.mpc_srcbusid = 0;
+       lintsrc.mpc_srcbusirq = 0;
+       lintsrc.mpc_destapic = MP_APIC_ALL;
+       for (i = 0; i < 2; i++) {
+               lintsrc.mpc_irqtype = linttypes[i];
+               lintsrc.mpc_destapiclint = i;
+               MP_lintsrc_info(&lintsrc);
+       }
+}
+
 static struct intel_mp_floating *mpf_found;
 
 /*
@@ -332,83 +457,43 @@
                printk("    Virtual Wire compatibility mode.\n");
                pic_mode = 0;
        }
-       /*
-        * default CPU id - if it's different in the mptable
-        * then we change it before first using it.
-        */
-       boot_cpu_id = 0;
+
        /*
         * Now see if we need to read further.
         */
        if (mpf->mpf_feature1 != 0) {
+
                printk("Default MP configuration #%d\n", mpf->mpf_feature1);
+               construct_default_ISA_mptable(mpf->mpf_feature1);
 
-               /*
-                * local APIC has default address
-                */
-               mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
+       } else if (mpf->mpf_physptr) {
 
                /*
-                * 2 CPUs, numbered 0 & 1.
+                * Read the physical hardware table.  Anything here will
+                * override the defaults.
                 */
-               phys_cpu_present_map = 3;
-               num_processors = 2;
+               smp_read_mpc((void *)mpf->mpf_physptr);
 
-               nr_ioapics = 1;
-               mp_ioapics[0].mpc_apicaddr = 0xFEC00000;
-               mp_ioapics[0].mpc_apicid = 2;
                /*
-                * Save the default type number, we
-                * need it later to set the IO-APIC
-                * up properly:
+                * If there are no explicit MP IRQ entries, then we are
+                * broken.  We set up most of the low 16 IO-APIC pins to
+                * ISA defaults and hope it will work.
                 */
-               mpc_default_type = mpf->mpf_feature1;
+               if (!mp_irq_entries) {
+                       struct mpc_config_bus bus;
 
-               printk("Bus #0 is ");
-       }
+                       printk("BIOS bug, no explicit IRQ entries, using default 
+mptable. (tell your hw vendor)\n");
 
-       switch (mpf->mpf_feature1) {
-               case 1:
-               case 5:
-                       printk("ISA\n");
-                       break;
-               case 2:
-                       printk("EISA with no IRQ0 and no IRQ13 DMA chaining\n");
-                       break;
-               case 6:
-               case 3:
-                       printk("EISA\n");
-                       break;
-               case 4:
-               case 7:
-                       printk("MCA\n");
-                       break;
-               case 0:
-                       if (!mpf->mpf_physptr)
-                               BUG();
-                       break;
-               default:
-                       printk("???\nUnknown standard configuration %d\n",
-                               mpf->mpf_feature1);
-                       return;
-       }
-       if (mpf->mpf_feature1 > 4) {
-               printk("Bus #1 is PCI\n");
+                       bus.mpc_type = MP_BUS;
+                       bus.mpc_busid = 0;
+                       memcpy(bus.mpc_bustype, "ISA   ", 6);
+                       MP_bus_info(&bus);
 
-               /*
-                * Set local APIC version to the integrated form.
-                * It's initialized to zero otherwise, representing
-                * a discrete 82489DX.
-                */
-               apic_version[0] = 0x10;
-               apic_version[1] = 0x10;
-       }
-       /*
-        * Read the physical hardware table. Anything here will override the
-        * defaults.
-        */
-       if (mpf->mpf_physptr)
-               smp_read_mpc((void *)mpf->mpf_physptr);
+                       construct_default_ioirq_mptable(0);
+               }
+
+       } else
+               BUG();
 
        printk("Processors: %d\n", num_processors);
        /*
--- linux/arch/i386/kernel/setup.c.orig Wed Apr 12 03:41:03 2000
+++ linux/arch/i386/kernel/setup.c      Wed Apr 12 03:41:11 2000
@@ -495,6 +495,10 @@
                        if (!memcmp(from+4, "nopentium", 9)) {
                                from += 9+4;
                                boot_cpu_data.x86_capability &= ~X86_FEATURE_PSE;
+                       } else if (!memcmp(from+4, "exactmap", 8)) {
+                               from += 8+4;
+                               e820.nr_map = 0;
+                               usermem = 1;
                        } else {
                                /* If the user specifies memory size, we
                                 * blow away any automatically generated
--- linux/arch/i386/kernel/smp.c.orig   Fri Feb 11 17:19:45 2000
+++ linux/arch/i386/kernel/smp.c        Wed Apr 12 03:41:11 2000
@@ -111,108 +111,26 @@
  * We use 'broadcast', CPU->CPU IPIs and self-IPIs too.
  */
 
-static unsigned int cached_APIC_ICR;
-static unsigned int cached_APIC_ICR2;
-
-/*
- * Caches reserved bits, APIC reads are (mildly) expensive
- * and force otherwise unnecessary CPU synchronization.
- *
- * (We could cache other APIC registers too, but these are the
- * main ones used in RL.)
- */
-#define slow_ICR (apic_read(APIC_ICR) & ~0xFDFFF)
-#define slow_ICR2 (apic_read(APIC_ICR2) & 0x00FFFFFF)
-
-void cache_APIC_registers (void)
-{
-       cached_APIC_ICR = slow_ICR;
-       cached_APIC_ICR2 = slow_ICR2;
-       mb();
-}
-
-static inline unsigned int __get_ICR (void)
-{
-#if FORCE_READ_AROUND_WRITE
-       /*
-        * Wait for the APIC to become ready - this should never occur. It's
-        * a debugging check really.
-        */
-       int count = 0;
-       unsigned int cfg;
-
-       while (count < 1000)
-       {
-               cfg = slow_ICR;
-               if (!(cfg&(1<<12)))
-                       return cfg;
-               printk("CPU #%d: ICR still busy [%08x]\n",
-                                       smp_processor_id(), cfg);
-               irq_err_count++;
-               count++;
-               udelay(10);
-       }
-       printk("CPU #%d: previous IPI still not cleared after 10mS\n",
-                       smp_processor_id());
-       return cfg;
-#else
-       return cached_APIC_ICR;
-#endif
-}
-
-static inline unsigned int __get_ICR2 (void)
-{
-#if FORCE_READ_AROUND_WRITE
-       return slow_ICR2;
-#else
-       return cached_APIC_ICR2;
-#endif
-}
-
-#define LOGICAL_DELIVERY 1
-
 static inline int __prepare_ICR (unsigned int shortcut, int vector)
 {
-       unsigned int cfg;
-
-       cfg = __get_ICR();
-       cfg |= APIC_DEST_DM_FIXED|shortcut|vector
-#if LOGICAL_DELIVERY
-               |APIC_DEST_LOGICAL
-#endif
-               ;
-
-       return cfg;
+       return APIC_DM_FIXED | shortcut | vector | APIC_DEST_LOGICAL;
 }
 
 static inline int __prepare_ICR2 (unsigned int mask)
 {
-       unsigned int cfg;
-
-       cfg = __get_ICR2();
-#if LOGICAL_DELIVERY
-       cfg |= SET_APIC_DEST_FIELD(mask);
-#else
-       cfg |= SET_APIC_DEST_FIELD(mask);
-#endif
-
-       return cfg;
+       return SET_APIC_DEST_FIELD(mask);
 }
 
 static inline void __send_IPI_shortcut(unsigned int shortcut, int vector)
 {
+       /*
+        * Subtle. In the case of the 'never do double writes' workaround
+        * we have to lock out interrupts to be safe.  As we don't care
+        * of the value read we use an atomic rmw access to avoid costly
+        * cli/sti.  Otherwise we use an even cheaper single atomic write
+        * to the APIC.
+        */
        unsigned int cfg;
-/*
- * Subtle. In the case of the 'never do double writes' workaround we
- * have to lock out interrupts to be safe. Otherwise it's just one
- * single atomic write to the APIC, no need for cli/sti.
- */
-#if FORCE_READ_AROUND_WRITE
-       unsigned long flags;
-
-       __save_flags(flags);
-       __cli();
-#endif
 
        /*
         * No need to touch the target chip field
@@ -222,10 +140,7 @@
        /*
         * Send the IPI. The write to APIC_ICR fires this off.
         */
-       apic_write(APIC_ICR, cfg);
-#if FORCE_READ_AROUND_WRITE
-       __restore_flags(flags);
-#endif
+       apic_write_around(APIC_ICR, cfg);
 }
 
 static inline void send_IPI_allbutself(int vector)
@@ -252,19 +167,16 @@
 static inline void send_IPI_mask(int mask, int vector)
 {
        unsigned long cfg;
-#if FORCE_READ_AROUND_WRITE
        unsigned long flags;
 
        __save_flags(flags);
        __cli();
-#endif
 
        /*
         * prepare target chip field
         */
-
        cfg = __prepare_ICR2(mask);
-       apic_write(APIC_ICR2, cfg);
+       apic_write_around(APIC_ICR2, cfg);
 
        /*
         * program the ICR 
@@ -274,10 +186,8 @@
        /*
         * Send the IPI. The write to APIC_ICR fires this off.
         */
-       apic_write(APIC_ICR, cfg);
-#if FORCE_READ_AROUND_WRITE
+       apic_write_around(APIC_ICR, cfg);
        __restore_flags(flags);
-#endif
 }
 
 /*
--- linux/arch/i386/kernel/smpboot.c.orig       Tue Feb  1 01:33:22 2000
+++ linux/arch/i386/kernel/smpboot.c    Wed Apr 12 03:41:11 2000
@@ -28,6 +28,7 @@
  *                                     from Jose Renau
  *             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
  */
 
 #include <linux/config.h>
@@ -489,11 +490,43 @@
        return do_fork(CLONE_VM|CLONE_PID, 0, &regs);
 }
 
+#if APIC_DEBUG
+static inline void inquire_remote_apic(int apicid)
+{
+       int i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 };
+       char *names[] = { "ID", "VERSION", "SPIV" };
+       int timeout, status;
+
+       printk("Inquiring remote APIC #%d...\n", apicid);
+
+       for (i = 0; i < sizeof(regs) / sizeof(*regs); i++) {
+               printk("... APIC #%d %s: ", apicid, names[i]);
+
+               apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
+               apic_write_around(APIC_ICR, APIC_DM_REMRD | regs[i]);
+
+               timeout = 0;
+               do {
+                       udelay(100);
+                       status = apic_read(APIC_ICR) & APIC_ICR_RR_MASK;
+               } while (status == APIC_ICR_RR_INPROG && timeout++ < 1000);
+
+               switch (status) {
+               case APIC_ICR_RR_VALID:
+                       status = apic_read(APIC_RRR);
+                       printk("%08x\n", status);
+                       break;
+               default:
+                       printk("failed\n");
+               }
+       }
+}
+#endif
+
 static void __init do_boot_cpu (int apicid)
 {
-       unsigned long cfg;
        struct task_struct *idle;
-       unsigned long send_status, accept_status;
+       unsigned long send_status, accept_status, boot_status, maxlvt;
        int timeout, num_starts, j, cpu;
        unsigned long start_eip;
 
@@ -527,7 +560,7 @@
        start_eip = setup_trampoline();
 
        /* So we see what's up   */
-       printk("Booting processor %d eip %lx\n", cpu, start_eip);
+       printk("Booting processor %d/%d eip %lx\n", cpu, apicid, start_eip);
        stack_start.esp = (void *) (1024 + PAGE_SIZE + (char *)idle);
 
        /*
@@ -549,16 +582,17 @@
         * Be paranoid about clearing APIC errors.
         */
        if (APIC_INTEGRATED(apic_version[apicid])) {
-               apic_readaround(APIC_SPIV);
+               apic_read_around(APIC_SPIV);
                apic_write(APIC_ESR, 0);
-               accept_status = (apic_read(APIC_ESR) & 0xEF);
+               apic_read(APIC_ESR);
        }
 
        /*
         * Status is now clean
         */
-       send_status =   0;
+       send_status = 0;
        accept_status = 0;
+       boot_status = 0;
 
        /*
         * Starting actual IPI sequence...
@@ -567,37 +601,41 @@
        Dprintk("Asserting INIT.\n");
 
        /*
-        * Turn INIT on
-        */
-       cfg = apic_read(APIC_ICR2);
-       cfg &= 0x00FFFFFF;
-
-       /*
-        * Target chip
+        * Turn INIT on target chip
         */
-       apic_write(APIC_ICR2, cfg | SET_APIC_DEST_FIELD(apicid));
+       apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
 
        /*
         * Send IPI
         */
-       cfg = apic_read(APIC_ICR);
-       cfg &= ~0xCDFFF;
-       cfg |= (APIC_DEST_LEVELTRIG | APIC_DEST_ASSERT | APIC_DEST_DM_INIT);
-       apic_write(APIC_ICR, cfg);
+       apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT
+                               | APIC_DM_INIT);
+
+       Dprintk("Waiting for send to finish...\n");
+       timeout = 0;
+       do {
+               Dprintk("+");
+               udelay(100);
+               send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
+       } while (send_status && (timeout++ < 1000));
+
+       mdelay(10);
 
-       udelay(200);
        Dprintk("Deasserting INIT.\n");
 
        /* Target chip */
-       cfg = apic_read(APIC_ICR2);
-       cfg &= 0x00FFFFFF;
-       apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(apicid));
+       apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
 
        /* Send IPI */
-       cfg = apic_read(APIC_ICR);
-       cfg &= ~0xCDFFF;
-       cfg |= (APIC_DEST_LEVELTRIG | APIC_DEST_DM_INIT);
-       apic_write(APIC_ICR, cfg);
+       apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
+
+       Dprintk("Waiting for send to finish...\n");
+       timeout = 0;
+       do {
+               Dprintk("+");
+               udelay(100);
+               send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
+       } while (send_status && (timeout++ < 1000));
 
        /*
         * Should we send STARTUP IPIs ?
@@ -616,9 +654,11 @@
         */
        Dprintk("#startup loops: %d.\n", num_starts);
 
+       maxlvt = get_maxlvt();
+
        for (j = 1; j <= num_starts; j++) {
                Dprintk("Sending STARTUP #%d.\n",j);
-               apic_readaround(APIC_SPIV);
+               apic_read_around(APIC_SPIV);
                apic_write(APIC_ESR, 0);
                apic_read(APIC_ESR);
                Dprintk("After apic_write.\n");
@@ -628,17 +668,12 @@
                 */
 
                /* Target chip */
-               cfg = apic_read(APIC_ICR2);
-               cfg &= 0x00FFFFFF;
-               apic_write(APIC_ICR2, cfg | SET_APIC_DEST_FIELD(apicid));
+               apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
 
                /* Boot on the stack */
-               cfg = apic_read(APIC_ICR);
-               cfg &= ~0xCDFFF;
-               cfg |= (APIC_DEST_DM_STARTUP | (start_eip >> 12));
-
                /* Kick the second */
-               apic_write(APIC_ICR, cfg);
+               apic_write_around(APIC_ICR, APIC_DM_STARTUP
+                                       | (start_eip >> 12));
 
                Dprintk("Startup point 1.\n");
 
@@ -647,13 +682,20 @@
                do {
                        Dprintk("+");
                        udelay(100);
-                       send_status = apic_read(APIC_ICR) & 0x1000;
+                       send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
                } while (send_status && (timeout++ < 1000));
 
                /*
                 * Give the other CPU some time to accept the IPI.
                 */
                udelay(200);
+               /*
+                * Due to the Pentium erratum 3AP.
+                */
+               if (maxlvt > 3) {
+                       apic_read_around(APIC_SPIV);
+                       apic_write(APIC_ESR, 0);
+               }
                accept_status = (apic_read(APIC_ESR) & 0xEF);
                if (send_status || accept_status)
                        break;
@@ -676,7 +718,7 @@
                /*
                 * Wait 5s total for a response
                 */
-               for (timeout = 0; timeout < 1000000000; timeout++) {
+               for (timeout = 0; timeout < 50000; timeout++) {
                        if (test_bit(cpu, &cpu_callin_map))
                                break;  /* It has booted */
                        udelay(100);
@@ -687,15 +729,22 @@
                        Dprintk("OK.\n");
                        printk("CPU%d: ", cpu);
                        print_cpu_info(&cpu_data[cpu]);
+                       Dprintk("CPU has booted.\n");
                } else {
+                       boot_status = 1;
                        if (*((volatile unsigned char *)phys_to_virt(8192))
-                                       == 0xA5) /* trampoline code not run */
+                                       == 0xA5)
+                               /* trampoline started but...? */
                                printk("Stuck ??\n");
                        else
-                               printk("CPU booted but not responding.\n");
+                               /* trampoline code not run */
+                               printk("Not responding.\n");
+#if APIC_DEBUG
+                       inquire_remote_apic(apicid);
+#endif
                }
-               Dprintk("CPU has booted.\n");
-       } else {
+       }
+       if (send_status || accept_status || boot_status) {
                x86_cpu_to_apicid[cpu] = -1;
                x86_apicid_to_cpu[apicid] = -1;
                cpucount--;
@@ -858,6 +907,7 @@
                Dprintk("Getting LVT1: %x\n", reg);
        }
 
+       connect_bsp_APIC();
        setup_local_APIC();
 
        if (GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_id)
@@ -877,7 +927,7 @@
 
                if (!(phys_cpu_present_map & (1 << apicid)))
                        continue;
-               if ((max_cpus >= 0) && (max_cpus < cpucount+1))
+               if ((max_cpus >= 0) && (max_cpus <= cpucount+1))
                        continue;
 
                do_boot_cpu(apicid);
@@ -934,7 +984,6 @@
                printk(KERN_WARNING "WARNING: SMP operation may be unreliable with B 
stepping processors.\n");
        Dprintk("Boot done.\n");
 
-       cache_APIC_registers();
 #ifndef CONFIG_VISWS
        /*
         * Here we can be sure that there is an IO-APIC in the system. Let's
--- linux/arch/i386/kernel/visws_apic.c.orig    Sun Nov 28 00:27:48 1999
+++ linux/arch/i386/kernel/visws_apic.c Wed Apr 12 03:41:11 2000
@@ -376,7 +376,7 @@
        for (i = 0; i < 16; i++) {
                irq_desc[i].status = IRQ_DISABLED;
                irq_desc[i].action = 0;
-               irq_desc[i].depth = 0;
+               irq_desc[i].depth = 1;
 
                /*
                 * Cobalt IRQs are mapped to standard ISA

Reply via email to