--- 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 #include +#include #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 #include -#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 * * 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 @@ -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 * * 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 @@ -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 @@ -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 linux-smp@vger.rutgers.edu"); - } } } + } } 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 @@ -489,11 +490,43 @@ return do_fork(CLONE_VM|CLONE_PID, 0, ®s); } +#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