diff -ur 2.2.10/arch/i386/kernel/smp.c 2.2.10-ipi/arch/i386/kernel/smp.c --- 2.2.10/arch/i386/kernel/smp.c Tue Jul 13 00:33:20 1999 +++ 2.2.10-ipi/arch/i386/kernel/smp.c Tue Aug 3 01:07:34 1999 @@ -1478,6 +1478,16 @@ return cfg; } +static inline int __prepare_ICR_NMI (unsigned int shortcut) +{ + unsigned int cfg; + + cfg = __get_ICR(); + cfg |= APIC_DEST_DM_NMI|shortcut; + + return cfg; +} + static inline int __prepare_ICR2 (unsigned int dest) { unsigned int cfg; @@ -1518,11 +1528,46 @@ #endif } +static inline void __send_IPI_shortcut_NMI(unsigned int shortcut) +{ + 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_APIC_SERIALIZATION + unsigned long flags; + + __save_flags(flags); + __cli(); +#endif + + /* + * No need to touch the target chip field + */ + + cfg = __prepare_ICR_NMI(shortcut); + + /* + * Send the IPI. The write to APIC_ICR fires this off. + */ + apic_write(APIC_ICR, cfg); +#if FORCE_APIC_SERIALIZATION + __restore_flags(flags); +#endif +} + static inline void send_IPI_allbutself(int vector) { __send_IPI_shortcut(APIC_DEST_ALLBUT, vector); } +static inline void send_IPI_allbutself_NMI(void) +{ + __send_IPI_shortcut_NMI(APIC_DEST_ALLBUT); +} + static inline void send_IPI_all(int vector) { __send_IPI_shortcut(APIC_DEST_ALLINC, vector); @@ -1617,7 +1662,10 @@ clear_bit(cpu, &smp_invalidate_needed); --stuck; if (!stuck) { + __sti(); printk("stuck on TLB IPI wait (CPU#%d)\n",cpu); + send_IPI_allbutself_NMI(); + *(int *) 0 = 0; break; } } diff -ur 2.2.10/arch/i386/kernel/traps.c 2.2.10-ipi/arch/i386/kernel/traps.c --- 2.2.10/arch/i386/kernel/traps.c Sat Feb 20 16:38:05 1999 +++ 2.2.10-ipi/arch/i386/kernel/traps.c Tue Aug 3 01:06:57 1999 @@ -324,16 +324,25 @@ asmlinkage void do_nmi(struct pt_regs * regs, long error_code) { - unsigned char reason = inb(0x61); extern atomic_t nmi_counter; + extern unsigned long smp_invalidate_needed; atomic_inc(&nmi_counter); + if (test_and_clear_bit(smp_processor_id(), &smp_invalidate_needed)) + { + local_flush_tlb(); + die("missed tlb flush\n", regs, error_code); + return; + } +{ + unsigned char reason = inb(0x61); if (reason & 0x80) mem_parity_error(reason, regs); if (reason & 0x40) io_check_error(reason, regs); if (!(reason & 0xc0)) unknown_nmi_error(reason, regs); +} } /*