--- linux/kernel/sched.c.orig2 Tue Jan 18 12:26:10 2000 +++ linux/kernel/sched.c Tue Jan 18 13:33:17 2000 @@ -82,7 +82,7 @@ #ifdef __SMP__ -#define idle_task(cpu) (init_tasks[cpu_number_map[(cpu)]]) +#define idle_task(cpu) (init_tasks[cpu_number_map(cpu)]) #define can_schedule(p) (!(p)->has_cpu) #else @@ -1168,10 +1168,10 @@ * We have to do a little magic to get the first * process right in SMP mode. */ - int cpu=hard_smp_processor_id(); + int cpu = smp_processor_id(); int nr; - init_task.processor=cpu; + init_task.processor = cpu; for(nr = 0; nr < PIDHASH_SZ; nr++) pidhash[nr] = NULL; --- linux/mm/highmem.c.orig2 Mon Jan 17 05:09:05 2000 +++ linux/mm/highmem.c Tue Jan 18 18:37:49 2000 @@ -128,7 +128,7 @@ flush_tlb_all(); } -static unsigned long map_new_virtual(struct page *page) +static inline unsigned long map_new_virtual(struct page *page) { unsigned long vaddr; int count; @@ -170,12 +170,6 @@ } vaddr = PKMAP_ADDR(last_pkmap_nr); pkmap_page_table[last_pkmap_nr] = mk_pte(page, kmap_prot); - /* - * Subtle! For some reason if we dont do this TLB flush then - * we get data corruption and weird behavior in dbench runs. - * But invlpg this should not be necessery ... Any ideas? - */ - __flush_tlb_one(vaddr); pkmap_count[last_pkmap_nr] = 1; page->virtual = vaddr; --- linux/include/linux/smp.h.orig2 Tue Jan 18 13:35:36 2000 +++ linux/include/linux/smp.h Tue Jan 18 13:35:38 2000 @@ -76,7 +76,6 @@ #define smp_num_cpus 1 #define smp_processor_id() 0 -#define hard_smp_processor_id() 0 #define smp_threads_ready 1 #define kernel_lock() #define cpu_logical_map(cpu) 0 --- linux/include/asm-i386/pgtable.h.orig2 Mon Jan 17 04:58:04 2000 +++ linux/include/asm-i386/pgtable.h Tue Jan 18 11:41:30 2000 @@ -27,8 +27,49 @@ #define flush_page_to_ram(page) do { } while (0) #define flush_icache_range(start, end) do { } while (0) -#define __flush_tlb() \ -do { unsigned long tmpreg; __asm__ __volatile__("movl %%cr3,%0\n\tmovl %0,%%cr3":"=r" (tmpreg) : :"memory"); } while (0) +#define __flush_tlb() \ + do { \ + __asm__ __volatile__ \ + ("movl %0, %%cr3;" \ + : \ + : "r" __pa(current->active_mm->pgd) \ + : "memory" \ + ); \ + } while (0) + +/* + * Global pages have to be flushed a bit differently. Not a real + * performance problem because this does not happen often. + */ +#define __flush_tlb_global() \ + do { \ + __asm__ __volatile__( \ + "movl %0, %%cr4; # turn off PGE \n" \ + "mov %2, %%cr3; # flush TLB \n" \ + "mov %1, %%cr4; # turn PGE back on \n" \ + : \ + : "r" (mmu_cr4_features), \ + "r" (mmu_cr4_features & ~X86_CR4_PGE), \ + "r" (__pa(current->active_mm->pgd)) \ + : "memory"); \ + } while (0) + +extern unsigned long pgkern_mask; + +/* + * Do not check the PGE bit unnecesserily if this is a PPro+ kernel. + */ +#ifdef CONFIG_X86_PGE +# define __flush_tlb_all() __flush_tlb_global() +#else +# define __flush_tlb_all() \ + do { \ + if (cpu_has_pge) \ + __flush_tlb_global(); \ + else \ + __flush_tlb(); \ + } while (0) +#endif #ifndef CONFIG_X86_INVLPG #define __flush_tlb_one(addr) __flush_tlb() @@ -116,12 +157,37 @@ #define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED) #define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) #define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) -#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED) -#define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED) + +#define __PAGE_KERNEL \ + (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED) +#define __PAGE_KERNEL_NOCACHE \ + (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_PCD | _PAGE_ACCESSED) +#define __PAGE_KERNEL_RO \ + (_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED) + +#ifdef CONFIG_X86_PGE +# define MAKE_GLOBAL(x) __pgprot((x) | _PAGE_GLOBAL) +#else +# define MAKE_GLOBAL(x) \ + ({ \ + pgprot_t __ret; \ + \ + if (cpu_has_pge) \ + __ret = __pgprot((x) | _PAGE_GLOBAL); \ + else \ + __ret = __pgprot(x); \ + __ret; \ + }) +#endif + +#define PAGE_KERNEL MAKE_GLOBAL(__PAGE_KERNEL) +#define PAGE_KERNEL_RO MAKE_GLOBAL(__PAGE_KERNEL_RO) +#define PAGE_KERNEL_NOCACHE MAKE_GLOBAL(__PAGE_KERNEL_NOCACHE) /* - * The i386 can't do page protection for execute, and considers that the same are read. - * Also, write permissions imply read permissions. This is the closest we can get.. + * The i386 can't do page protection for execute, and considers that + * the same are read. Also, write permissions imply read permissions. + * This is the closest we can get.. */ #define __P000 PAGE_NONE #define __P001 PAGE_READONLY --- linux/include/asm-i386/pgalloc.h.orig2 Mon Jan 17 05:04:42 2000 +++ linux/include/asm-i386/pgalloc.h Tue Jan 18 12:42:19 2000 @@ -195,7 +195,7 @@ #ifndef __SMP__ #define flush_tlb() __flush_tlb() -#define flush_tlb_all() __flush_tlb() +#define flush_tlb_all() __flush_tlb_all() #define local_flush_tlb() __flush_tlb() static inline void flush_tlb_mm(struct mm_struct *mm) --- linux/include/asm-i386/fixmap.h.orig2 Mon Jan 17 05:32:54 2000 +++ linux/include/asm-i386/fixmap.h Tue Jan 18 11:41:30 2000 @@ -68,8 +68,16 @@ __end_of_fixed_addresses }; -extern void set_fixmap (enum fixed_addresses idx, unsigned long phys); +extern void __set_fixmap (enum fixed_addresses idx, + unsigned long phys, pgprot_t flags); +#define set_fixmap(idx, phys) \ + __set_fixmap(idx, phys, PAGE_KERNEL) +/* + * Some hardware wants to get fixmapped without caching. + */ +#define set_fixmap_nocache(idx, phys) \ + __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE) /* * used by vmalloc.c. * --- linux/include/asm-i386/smp.h.orig2 Tue Jan 18 12:24:33 2000 +++ linux/include/asm-i386/smp.h Tue Jan 18 12:42:08 2000 @@ -168,7 +168,7 @@ extern void init_smp_config(void); extern void init_smp_mappings(void); extern void smp_alloc_memory(void); -extern unsigned long cpu_present_map; +extern unsigned long phys_cpu_present_map; extern unsigned long cpu_online_map; extern volatile unsigned long smp_invalidate_needed; extern int pic_mode; @@ -182,12 +182,27 @@ extern void (*mtrr_hook) (void); extern void setup_APIC_clocks(void); extern void zap_low_mappings (void); -extern volatile int cpu_number_map[NR_CPUS]; -extern volatile int __cpu_logical_map[NR_CPUS]; + +/* + * On x86 all CPUs are mapped 1:1 to the APIC space. + * This simplifies scheduling and IPI sending and + * compresses data structures. + */ extern inline int cpu_logical_map(int cpu) { - return __cpu_logical_map[cpu]; + return cpu; } +extern inline int cpu_number_map(int cpu) +{ + return cpu; +} + +/* + * Some lowlevel functions might want to know about + * the real APIC ID <-> CPU # mapping. + */ +extern volatile int x86_apicid_to_cpu[NR_CPUS]; +extern volatile int x86_cpu_to_apicid[NR_CPUS]; extern __inline void apic_write(unsigned long reg, unsigned long v) { --- linux/include/asm-i386/bugs.h.orig2 Tue Jan 18 10:57:17 2000 +++ linux/include/asm-i386/bugs.h Tue Jan 18 11:41:30 2000 @@ -398,8 +398,16 @@ * If we configured ourselves for a TSC, we'd better have one! */ #ifdef CONFIG_X86_TSC - if (!(boot_cpu_data.x86_capability & X86_FEATURE_TSC)) - panic("Kernel compiled for Pentium+, requires TSC"); + if (!cpu_has_tsc) + panic("Kernel compiled for Pentium+, requires TSC feature!"); +#endif + +/* + * If we configured ourselves for PGE, we'd better have it. + */ +#ifdef CONFIG_X86_PGE + if (!cpu_has_pge) + panic("Kernel compiled for PPro+, requires PGE feature!"); #endif /* --- linux/include/asm-i386/processor.h.orig2 Tue Jan 18 10:58:24 2000 +++ linux/include/asm-i386/processor.h Tue Jan 18 11:41:30 2000 @@ -115,7 +115,7 @@ #define cpu_has_pae \ (boot_cpu_data.x86_capability & X86_FEATURE_PAE) #define cpu_has_tsc \ - (cpu_data[smp_processor_id()].x86_capability & X86_FEATURE_TSC) + (boot_cpu_data.x86_capability & X86_FEATURE_TSC) extern char ignore_irq13; --- linux/drivers/net/pcmcia/tulip_cb.c.orig2 Tue Jan 18 13:34:37 2000 +++ linux/drivers/net/pcmcia/tulip_cb.c Tue Jan 18 13:34:42 2000 @@ -2478,7 +2478,7 @@ if (test_and_set_bit(0, (void*)&dev->interrupt)) { printk(KERN_ERR "%s: Duplicate entry of the interrupt handler by " "processor %d.\n", - dev->name, hard_smp_processor_id()); + dev->name, smp_processor_id()); dev->interrupt = 0; return; } --- linux/drivers/net/tulip.c.orig2 Tue Jan 18 13:34:10 2000 +++ linux/drivers/net/tulip.c Tue Jan 18 13:34:21 2000 @@ -102,7 +102,6 @@ #endif #if (LINUX_VERSION_CODE < 0x20123) -#define hard_smp_processor_id() smp_processor_id() #define test_and_set_bit(val, addr) set_bit(val, addr) #endif @@ -2164,7 +2163,7 @@ #ifdef SMP_CHECK printk(KERN_ERR "%s: Re-entering the interrupt handler with proc %d," " proc %d already handling.\n", dev->name, - tp->smp_proc_id, hard_smp_processor_id()); + tp->smp_proc_id, smp_processor_id()); #else printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name); #endif @@ -2172,7 +2171,7 @@ } dev->interrupt = 1; #ifdef SMP_CHECK - tp->smp_proc_id = hard_smp_processor_id(); + tp->smp_proc_id = smp_processor_id(); #endif do { --- linux/drivers/char/console.c.orig2 Tue Jan 18 15:37:28 2000 +++ linux/drivers/char/console.c Tue Jan 18 17:21:40 2000 @@ -824,6 +824,7 @@ { int min_y, max_y; +// __beep(); if (new_x < 0) x = 0; else @@ -1890,7 +1891,7 @@ && (c != 127 || disp_ctrl) && (c != 128+27); - if (vc_state == ESnormal && ok) { + if (1 && (vc_state == ESnormal && ok)) { /* Now try to find out how to display it */ tc = conv_uni_to_pc(vc_cons[currcons].d, tc); if ( tc == -4 ) { @@ -1936,6 +1937,7 @@ continue; } FLUSH +// __beep(); do_con_trol(tty, currcons, c); } FLUSH @@ -2008,7 +2010,7 @@ if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1)) currcons = kmsg_redirect - 1; - /* read `x' only after setting currecons properly (otherwise + /* read `x' only after setting currcons properly (otherwise the `x' macro will read the x of the foreground console). */ myx = x; @@ -2031,7 +2033,7 @@ * Problems caused when we have need_wrap set on '\n' character */ while (count--) { c = *b++; - if (c == 10 || c == 13 || c == 8 || need_wrap) { + if (c == 10 || c == 13 || c == 8 || c == 6 || c == 5 || need_wrap) { if (cnt > 0) { if (IS_VISIBLE) sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x); @@ -2044,6 +2046,23 @@ bs(currcons); start = (ushort *)pos; myx = x; + continue; + } + if (c == 6) { /* up */ + if (y) { + y--; + pos -= video_size_row; + } + start = (ushort *)pos; + continue; + } + if (c == 5) { /* right */ + if (x < video_num_columns-1) { + x++; + pos += 2; + } + myx = x; + start = (ushort *)pos; continue; } if (c != 13) --- linux/arch/i386/mm/init.c.orig2 Mon Jan 17 05:09:46 2000 +++ linux/arch/i386/mm/init.c Tue Jan 18 11:30:18 2000 @@ -194,8 +194,6 @@ kmap_pte = kmap_get_fixmap_pte(kmap_vstart); kmap_prot = PAGE_KERNEL; - if (boot_cpu_data.x86_capability & X86_FEATURE_PGE) - pgprot_val(kmap_prot) |= _PAGE_GLOBAL; } #endif @@ -239,7 +237,8 @@ extern char _text, _etext, _edata, __bss_start, _end; extern char __init_begin, __init_end; -static void set_pte_phys (unsigned long vaddr, unsigned long phys) +static inline void set_pte_phys (unsigned long vaddr, + unsigned long phys, pgprot_t flags) { pgprot_t prot; pgd_t *pgd; @@ -249,26 +248,25 @@ pgd = swapper_pg_dir + __pgd_offset(vaddr); pmd = pmd_offset(pgd, vaddr); pte = pte_offset(pmd, vaddr); - prot = PAGE_KERNEL; - if (boot_cpu_data.x86_capability & X86_FEATURE_PGE) - pgprot_val(prot) |= _PAGE_GLOBAL; + pgprot_val(prot) = pgprot_val(PAGE_KERNEL) | pgprot_val(flags); set_pte(pte, mk_pte_phys(phys, prot)); /* * It's enough to flush this one mapping. + * (PGE mappings get flushed as well) */ __flush_tlb_one(vaddr); } -void set_fixmap (enum fixed_addresses idx, unsigned long phys) +void __set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t flags) { unsigned long address = __fix_to_virt(idx); if (idx >= __end_of_fixed_addresses) { - printk("Invalid set_fixmap\n"); + printk("Invalid __set_fixmap\n"); return; } - set_pte_phys(address,phys); + set_pte_phys(address, phys, flags); } static void __init fixrange_init (unsigned long start, unsigned long end, pgd_t *pgd_base) @@ -439,7 +437,7 @@ set_in_cr4(X86_CR4_PAE); #endif - __flush_tlb(); + __flush_tlb_all(); #ifdef __SMP__ init_smp_mappings(); --- linux/arch/i386/mm/fault.c.orig2 Tue Jan 18 11:09:18 2000 +++ linux/arch/i386/mm/fault.c Tue Jan 18 11:10:09 2000 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -76,7 +77,7 @@ return 0; } -static inline void handle_wp_test (void) +static void __init handle_wp_test (void) { const unsigned long vaddr = PAGE_OFFSET; pgd_t *pgd; @@ -91,7 +92,7 @@ pmd = pmd_offset(pgd, vaddr); pte = pte_offset(pmd, vaddr); *pte = mk_pte_phys(0, PAGE_KERNEL); - local_flush_tlb(); + __flush_tlb_all(); boot_cpu_data.wp_works_ok = 1; /* --- linux/arch/i386/kernel/traps.c.orig2 Tue Jan 18 11:28:06 2000 +++ linux/arch/i386/kernel/traps.c Tue Jan 18 11:28:52 2000 @@ -600,7 +600,10 @@ pte = pte_offset(pmd, page); __free_page(pte_page(*pte)); *pte = mk_pte_phys(__pa(&idt_table), PAGE_KERNEL_RO); - local_flush_tlb(); + /* + * Not that any PGE-capable kernel should have the f00f bug ... + */ + __flush_tlb_all(); /* * "idt" is magic - it overlaps the idt_descr --- linux/arch/i386/kernel/smp.c.orig2 Mon Jan 17 05:05:59 2000 +++ linux/arch/i386/kernel/smp.c Tue Jan 18 13:49:25 2000 @@ -2,7 +2,7 @@ * Intel SMP support routines. * * (c) 1995 Alan Cox, Building #3 - * (c) 1998-99 Ingo Molnar + * (c) 1998-99, 2000 Ingo Molnar * * This code is released under the GNU public license version 2 or * later. @@ -381,7 +381,7 @@ static inline void do_flush_tlb_all_local(void) { - local_flush_tlb(); + __flush_tlb_all(); if (!current->mm && current->active_mm) { unsigned long cpu = smp_processor_id(); @@ -702,7 +702,7 @@ void setup_APIC_timer(void * data) { - unsigned int clocks = (unsigned int) data, slice, t0, t1, nr; + unsigned int clocks = (unsigned int) data, slice, t0, t1; unsigned long flags; int delta; @@ -719,9 +719,10 @@ */ slice = clocks / (smp_num_cpus+1); - nr = cpu_number_map[smp_processor_id()] + 1; - printk("cpu: %d, clocks: %d, slice: %d, nr: %d.\n", - smp_processor_id(), clocks, slice, nr); + printk("cpu: %d, clocks: %d, slice: %d, phys nr: %d.\n", + smp_processor_id(), clocks, + slice, x86_cpu_to_apicid[smp_processor_id()]); + /* * Wait for IRQ0's slice: */ @@ -732,7 +733,7 @@ t0 = apic_read(APIC_TMCCT)*APIC_DIVISOR; do { t1 = apic_read(APIC_TMCCT)*APIC_DIVISOR; - delta = (int)(t0 - t1 - slice*nr); + delta = (int)(t0 - t1 - slice*(smp_processor_id()+1)); } while (delta < 0); __setup_APIC_LVTT(clocks); --- linux/arch/i386/kernel/io_apic.c.orig2 Mon Jan 17 05:16:06 2000 +++ linux/arch/i386/kernel/io_apic.c Tue Jan 18 12:40:50 2000 @@ -997,7 +997,7 @@ } } -static void __init setup_ioapic_id(void) +static void __init setup_ioapic_default_id(void) { struct IO_APIC_reg_00 reg_00; @@ -1012,7 +1012,7 @@ * system must have a unique ID or we get lots of nice * 'stuck on smp_invalidate_needed IPI wait' messages. */ - if (cpu_present_map & (1<<0x2)) + if (phys_cpu_present_map & (1<<0x2)) panic("APIC ID 2 already used"); /* @@ -1031,6 +1031,47 @@ panic("could not set ID"); } +/* + * function to set the IO-APIC physical IDs based on the + * values stored in the MPC table. + * + * by Matt Domsch Tue Dec 21 12:25:05 CST 1999 + */ + +static void __init setup_ioapic_ids_from_mpc (void) +{ + struct IO_APIC_reg_00 reg_00; + int apic; + + /* + * Set the IOAPIC ID to the value stored in the MPC table. + */ + for (apic = 0; apic < nr_ioapics; apic++) { + + /* Read the register 0 value */ + *(int *)®_00 = io_apic_read(apic, 0); + + /* + * Read the right value from the MPC table and + * write it into the ID register. + */ + printk("...changing IO-APIC physical APIC ID to %d ...", + mp_ioapics[apic].mpc_apicid); + + reg_00.ID = mp_ioapics[apic].mpc_apicid; + io_apic_write(apic, 0, *(int *)®_00); + + /* + * Sanity check + */ + *(int *)®_00 = io_apic_read(apic, 0); + if (reg_00.ID != mp_ioapics[apic].mpc_apicid) + panic("could not set ID!\n"); + else + printk(" ok.\n"); + } +} + static void __init construct_default_ISA_mptable(void) { int i, pos = 0; @@ -1071,7 +1112,7 @@ mp_irqs[0].mpc_dstirq = 2; } - setup_ioapic_id(); + setup_ioapic_default_id(); } /* @@ -1422,6 +1463,7 @@ * Set up the IO-APIC IRQ routing table by parsing the MP-BIOS * mptable: */ + setup_ioapic_ids_from_mpc(); setup_IO_APIC_irqs(); init_IO_APIC_traps(); check_timer(); --- linux/arch/i386/kernel/smpboot.c.orig2 Mon Jan 17 05:37:43 2000 +++ linux/arch/i386/kernel/smpboot.c Tue Jan 18 17:24:40 2000 @@ -2,7 +2,7 @@ * Intel MP v1.1/v1.4 specification compliant parsing routines. * * (c) 1995 Alan Cox, Building #3 - * (c) 1998, 1999 Ingo Molnar + * (c) 1998, 1999, 2000 Ingo Molnar * * Much of the core SMP work is based on previous work by Thomas Radke, to * whom a great many thanks are extended. @@ -63,14 +63,14 @@ int smp_found_config = 0; /* Bitmask of physically existing CPUs */ -unsigned long cpu_present_map = 0; +unsigned long phys_cpu_present_map = 0; /* Bitmask of currently online CPUs */ unsigned long cpu_online_map = 0; -/* which CPU maps to which logical number */ -volatile int cpu_number_map[NR_CPUS]; -/* which logical number maps to which CPU */ -volatile int __cpu_logical_map[NR_CPUS]; +/* which CPU (physical APIC ID) maps to which logical CPU number */ +volatile int x86_apicid_to_cpu[NR_CPUS]; +/* which logical CPU number maps to which CPU (physical APIC ID) */ +volatile int x86_cpu_to_apicid[NR_CPUS]; static volatile unsigned long cpu_callin_map = 0; static volatile unsigned long cpu_callout_map = 0; @@ -101,7 +101,7 @@ extern void cache_APIC_registers (void); -#define SMP_DEBUG 1 +#define SMP_DEBUG 0 #if SMP_DEBUG #define dprintk(x...) printk(##x) @@ -232,7 +232,7 @@ } ver = m->mpc_apicver; - cpu_present_map |= (1<mpc_apicid); + phys_cpu_present_map |= 1 << m->mpc_apicid; /* * Validate version */ @@ -436,7 +436,7 @@ /* * 2 CPUs, numbered 0 & 1. */ - cpu_present_map = 3; + phys_cpu_present_map = 3; num_processors = 2; nr_ioapics = 1; @@ -494,9 +494,9 @@ if (mpf->mpf_physptr) smp_read_mpc((void *)mpf->mpf_physptr); - __cpu_logical_map[0] = boot_cpu_id; - global_irq_holder = boot_cpu_id; - current->processor = boot_cpu_id; + x86_cpu_to_apicid[0] = boot_cpu_id; + global_irq_holder = 0; + current->processor = 0; printk("Processors: %d\n", num_processors); /* @@ -582,7 +582,7 @@ { smp_found_config = 1; - cpu_present_map |= 2; /* or in id 1 */ + phys_cpu_present_map |= 2; /* or in id 1 */ apic_version[1] |= 0x10; /* integrated APIC */ apic_version[0] |= 0x10; @@ -741,6 +741,12 @@ if ((SPURIOUS_APIC_VECTOR & 0x0f) != 0x0f) __error_in_io_apic_c(); + /* + * Double-check wether this APIC is really registered. + */ + if (!test_bit(GET_APIC_ID(apic_read(APIC_ID)), &phys_cpu_present_map)) + BUG(); + value = apic_read(APIC_SPIV); /* * Enable APIC @@ -780,19 +786,19 @@ * strictly necessery in pure symmetric-IO mode, but sometimes * we delegate interrupts to the 8259A. */ - if (hard_smp_processor_id() == boot_cpu_id) { + if (!smp_processor_id()) { value = 0x00000700; - printk("enabled ExtINT on CPU#%d\n", hard_smp_processor_id()); + printk("enabled ExtINT on CPU#%d\n", smp_processor_id()); } else { value = 0x00010700; - printk("masked ExtINT on CPU#%d\n", hard_smp_processor_id()); + printk("masked ExtINT on CPU#%d\n", smp_processor_id()); } apic_write_around(APIC_LVT0,value); /* * only the BP should see the LINT1 NMI signal, obviously. */ - if (hard_smp_processor_id() == boot_cpu_id) + if (!smp_processor_id()) value = 0x00000400; // unmask NMI else value = 0x00010400; // mask NMI @@ -865,7 +871,7 @@ apic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE); apic_phys = __pa(apic_phys); } - set_fixmap(FIX_APIC_BASE, apic_phys); + set_fixmap_nocache(FIX_APIC_BASE, apic_phys); dprintk("mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys); #ifdef CONFIG_X86_IO_APIC @@ -880,7 +886,7 @@ ioapic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE); ioapic_phys = __pa(ioapic_phys); } - set_fixmap(idx,ioapic_phys); + set_fixmap_nocache(idx, ioapic_phys); dprintk("mapped IOAPIC to %08lx (%08lx)\n", __fix_to_virt(idx), ioapic_phys); idx++; @@ -988,20 +994,14 @@ } sum = 0; - for (i = 0; i < NR_CPUS; i++) { - if (!(cpu_online_map & (1 << i))) - continue; - + for (i = 0; i < smp_num_cpus; i++) { t0 = tsc_values[i]; sum += t0; } avg = div64(sum, smp_num_cpus); sum = 0; - for (i = 0; i < NR_CPUS; i++) { - if (!(cpu_online_map & (1 << i))) - continue; - + for (i = 0; i < smp_num_cpus; i++) { delta = tsc_values[i] - avg; if (delta < 0) delta = -delta; @@ -1053,19 +1053,66 @@ } #undef NR_LOOPS +/* + (o_ + (o_ (o_ //\ + (/)_ (/)_ V_/_ + + */ + +#define printks(s) printk("%s",s) + +static void movex (int deltax) +{ + int count = deltax, i; + + if (count < 0) + count = -count; + + for (i = 0; i < count; i++) + if (deltax < 0) + printks("\10"); + else + printks("\5"); +} + +static void moveup (int delta) +{ + int i; + + for (i = 0; i < delta; i++) + printks("\6"); +} + +void penguin (int nr) +{ + moveup(11); + movex(nr*7); printks(" (o_ \n"); + movex(nr*7); printks(" //\\ \n"); + movex(nr*7); printks(" V_/_\n\n"); + mdelay(200); +} + extern void calibrate_delay(void); void __init smp_callin(void) { - int cpuid; + int cpuid, phys_id; unsigned long timeout; /* * (This works even if the APIC is not enabled.) */ - cpuid = GET_APIC_ID(apic_read(APIC_ID)); + phys_id = GET_APIC_ID(apic_read(APIC_ID)); + cpuid = current->processor; + if (test_and_set_bit(cpuid, &cpu_online_map)) { + printk("huh, phys CPU#%d, CPU#%d already present??\n", + phys_id, cpuid); + BUG(); + } + dprintk("CPU#%d (phys ID: %d) waiting for CALLOUT\n", cpuid, phys_id); - dprintk("CPU#%d waiting for CALLOUT\n", cpuid); + penguin(cpuid); /* * STARTUP IPIs are fragile beasts as they might sometimes @@ -1131,7 +1178,7 @@ * Synchronize the TSC with the BP */ if (cpu_has_tsc) - synchronize_tsc_ap (); + synchronize_tsc_ap(); } int cpucount = 0; @@ -1196,21 +1243,21 @@ return do_fork(CLONE_VM|CLONE_PID, 0, ®s); } -static void __init do_boot_cpu(int i) +static void __init do_boot_cpu (int apicid) { unsigned long cfg; struct task_struct *idle; unsigned long send_status, accept_status; - int timeout, num_starts, j; + int timeout, num_starts, j, cpu; unsigned long start_eip; - cpucount++; + cpu = ++cpucount; /* * We can't use kernel_thread since we must avoid to * reschedule the child. */ if (fork_by_hand() < 0) - panic("failed fork for CPU %d", i); + panic("failed fork for CPU %d", cpu); /* * We remove it from the pidhash and the runqueue @@ -1218,23 +1265,23 @@ */ idle = init_task.prev_task; if (!idle) - panic("No idle process for CPU %d", i); + panic("No idle process for CPU %d", cpu); - idle->processor = i; - __cpu_logical_map[cpucount] = i; - cpu_number_map[i] = cpucount; + idle->processor = cpu; + x86_cpu_to_apicid[cpu] = apicid; + x86_apicid_to_cpu[apicid] = cpu; idle->has_cpu = 1; /* we schedule the first task manually */ idle->thread.eip = (unsigned long) start_secondary; del_from_runqueue(idle); unhash_process(idle); - init_tasks[cpucount] = idle; + init_tasks[cpu] = idle; /* start_eip had better be page-aligned! */ start_eip = setup_trampoline(); /* So we see what's up */ - printk("Booting processor %d eip %lx\n", i, start_eip); + printk("Booting processor %d eip %lx\n", cpu, start_eip); stack_start.esp = (void *) (1024 + PAGE_SIZE + (char *)idle); /* @@ -1255,8 +1302,7 @@ /* * Be paranoid about clearing APIC errors. */ - - if (APIC_INTEGRATED(apic_version[i])) { + if (APIC_INTEGRATED(apic_version[apicid])) { apic_readaround(APIC_SPIV); apic_write(APIC_ESR, 0); accept_status = (apic_read(APIC_ESR) & 0xEF); @@ -1283,7 +1329,7 @@ /* * Target chip */ - apic_write(APIC_ICR2, cfg | SET_APIC_DEST_FIELD(i)); + apic_write(APIC_ICR2, cfg | SET_APIC_DEST_FIELD(apicid)); /* * Send IPI @@ -1299,7 +1345,7 @@ /* Target chip */ cfg = apic_read(APIC_ICR2); cfg &= 0x00FFFFFF; - apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); + apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(apicid)); /* Send IPI */ cfg = apic_read(APIC_ICR); @@ -1314,8 +1360,7 @@ * If we don't have an integrated APIC, don't * send the STARTUP IPIs. */ - - if (APIC_INTEGRATED(apic_version[i])) + if (APIC_INTEGRATED(apic_version[apicid])) num_starts = 2; else num_starts = 0; @@ -1323,6 +1368,7 @@ /* * Run STARTUP IPI loop. */ + dprintk("#startup loops: %d.\n", num_starts); for (j = 1; j <= num_starts; j++) { dprintk("Sending STARTUP #%d.\n",j); @@ -1338,7 +1384,7 @@ /* Target chip */ cfg = apic_read(APIC_ICR2); cfg &= 0x00FFFFFF; - apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); + apic_write(APIC_ICR2, cfg | SET_APIC_DEST_FIELD(apicid)); /* Boot on the stack */ cfg = apic_read(APIC_ICR); @@ -1377,24 +1423,24 @@ /* * allow APs to start initializing. */ - dprintk("Before Callout %d.\n", i); - set_bit(i, &cpu_callout_map); - dprintk("After Callout %d.\n", i); + dprintk("Before Callout %d.\n", cpu); + set_bit(cpu, &cpu_callout_map); + dprintk("After Callout %d.\n", cpu); /* * Wait 5s total for a response */ - for (timeout = 0; timeout < 50000; timeout++) { - if (test_bit(i, &cpu_callin_map)) + for (timeout = 0; timeout < 1000000000; timeout++) { + if (test_bit(cpu, &cpu_callin_map)) break; /* It has booted */ udelay(100); } - if (test_bit(i, &cpu_callin_map)) { + if (test_bit(cpu, &cpu_callin_map)) { /* number CPUs logically, starting from 1 (BSP is 0) */ - printk("OK.\n"); - printk("CPU%d: ", i); - print_cpu_info(&cpu_data[i]); + dprintk("OK.\n"); + printk("CPU%d: ", cpu); + print_cpu_info(&cpu_data[cpu]); } else { if (*((volatile unsigned char *)phys_to_virt(8192)) == 0xA5) /* trampoline code not run */ @@ -1404,8 +1450,8 @@ } dprintk("CPU has booted.\n"); } else { - __cpu_logical_map[cpucount] = -1; - cpu_number_map[i] = -1; + x86_cpu_to_apicid[cpu] = -1; + x86_apicid_to_cpu[apicid] = -1; cpucount--; } @@ -1460,7 +1506,7 @@ void __init smp_boot_cpus(void) { - int i; + int apicid, cpu; #ifdef CONFIG_MTRR /* Must be done before other processors booted */ @@ -1471,52 +1517,55 @@ * and the per-CPU profiling counter/multiplier */ - for (i = 0; i < NR_CPUS; i++) { - cpu_number_map[i] = -1; - prof_counter[i] = 1; - prof_old_multiplier[i] = 1; - prof_multiplier[i] = 1; + for (apicid = 0; apicid < NR_CPUS; apicid++) { + x86_apicid_to_cpu[apicid] = -1; + prof_counter[apicid] = 1; + prof_old_multiplier[apicid] = 1; + prof_multiplier[apicid] = 1; } /* * Setup boot CPU information */ - - smp_store_cpu_info(boot_cpu_id); /* Final full version of the data */ + smp_store_cpu_info(0); /* Final full version of the data */ smp_tune_scheduling(); - printk("CPU%d: ", boot_cpu_id); - print_cpu_info(&cpu_data[boot_cpu_id]); + printk("CPU%d: ", 0); + print_cpu_info(&cpu_data[0]); /* - * not necessary because the MP table should list the boot - * CPU too, but we do it for the sake of robustness anyway. - * (and for the case when a non-SMP board boots an SMP kernel) + * We have the boot CPU online for sure. */ - cpu_present_map |= (1 << hard_smp_processor_id()); - - cpu_number_map[boot_cpu_id] = 0; - + set_bit(0, &cpu_online_map); + x86_apicid_to_cpu[boot_cpu_id] = 0; init_idle(); /* * If we couldnt find an SMP configuration at boot time, * get out of here now! */ - if (!smp_found_config) { printk(KERN_NOTICE "SMP motherboard not detected. Using dummy APIC emulation.\n"); #ifndef CONFIG_VISWS io_apic_irqs = 0; #endif - cpu_online_map = cpu_present_map; + cpu_online_map = phys_cpu_present_map = 1; smp_num_cpus = 1; goto smp_done; } /* - * If SMP should be disabled, then really disable it! + * Should not be necessary because the MP table should list the boot + * CPU too, but we do it for the sake of robustness anyway. */ + if (!test_bit(boot_cpu_id, &phys_cpu_present_map)) { + printk("weird, boot CPU (#%d) not listed by the BIOS.\n", + boot_cpu_id); + phys_cpu_present_map |= (1 << hard_smp_processor_id()); + } + /* + * If SMP should be disabled, then really disable it! + */ if (!max_cpus) { smp_found_config = 0; printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n"); @@ -1551,7 +1600,6 @@ * compatibility mode, but most boxes are anymore. */ - reg = apic_read(APIC_LVT0); dprintk("Getting LVT0: %x\n", reg); @@ -1568,42 +1616,37 @@ /* * Now scan the CPU present map and fire up the other CPUs. */ + dprintk("CPU present map: %lx\n", phys_cpu_present_map); - /* - * Add all detected CPUs. (later on we can down individual - * CPUs which will change cpu_online_map but not necessarily - * cpu_present_map. We are pretty much ready for hot-swap CPUs.) - */ - cpu_online_map = cpu_present_map; - mb(); - - dprintk("CPU map: %lx\n", cpu_present_map); + printk("\n\n\n\n\n\n\n\n\n\n\n\n"); + penguin(0); + printk("\n\n\n\n\n"); - for (i = 0; i < NR_CPUS; i++) { + for (apicid = 0; apicid < NR_CPUS; apicid++) { /* * Don't even attempt to start the boot CPU! */ - if (i == boot_cpu_id) + if (apicid == boot_cpu_id) continue; - if ((cpu_online_map & (1 << i)) - && (max_cpus < 0 || max_cpus > cpucount+1)) { - do_boot_cpu(i); - } + if (!(phys_cpu_present_map & (1 << apicid))) + continue; + if ((max_cpus >= 0) && (max_cpus < cpucount+1)) + continue; + + do_boot_cpu(apicid); /* * Make sure we unmap all failed CPUs */ - if (cpu_number_map[i] == -1 && (cpu_online_map & (1 << i))) { - printk("CPU #%d not responding - cannot use it.\n",i); - cpu_online_map &= ~(1 << i); - } + if ((x86_apicid_to_cpu[apicid] == -1) && + (phys_cpu_present_map & (1 << apicid))) + printk("phys CPU #%d not responding - cannot use it.\n",apicid); } /* * Cleanup possible dangling ends... */ - #ifndef CONFIG_VISWS { /* @@ -1628,12 +1671,11 @@ dprintk("Before bogomips.\n"); if (!cpucount) { printk(KERN_ERR "Error: only one processor found.\n"); - cpu_online_map = (1<