--- linux/mm/highmem.c.orig2 Mon Jan 17 05:09:05 2000 +++ linux/mm/highmem.c Mon Jan 17 05:55:43 2000 @@ -125,10 +125,10 @@ page = pte_page(pte); page->virtual = 0; } - flush_tlb_all(); + flush_tlb_all_kernel(); } -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/asm-i386/pgtable.h.orig2 Mon Jan 17 04:58:04 2000 +++ linux/include/asm-i386/pgtable.h Mon Jan 17 05:36:11 2000 @@ -30,6 +30,23 @@ #define __flush_tlb() \ do { unsigned long tmpreg; __asm__ __volatile__("movl %%cr3,%0\n\tmovl %0,%%cr3":"=r" (tmpreg) : :"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 %%cr4,%%eax; \ + movl %%eax,%%ecx; \ + andl $0xffffff7f,%%eax; # turn off PGE (CR4[7]) in EAX \n \ + movl %%eax,%%cr4; \ + movl %%cr3,%%ebx; \ + movl %%ebx,%%cr3; \ + movl %%ecx,%%cr4; \ + " : : : "cc", "eax", "ebx", "ecx", "memory" \ + ); \ +} while (0) + #ifndef CONFIG_X86_INVLPG #define __flush_tlb_one(addr) __flush_tlb() #else @@ -117,6 +134,7 @@ #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_NOCACHE __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_PCD | _PAGE_ACCESSED) #define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED) /* --- linux/include/asm-i386/pgalloc.h.orig2 Mon Jan 17 05:04:42 2000 +++ linux/include/asm-i386/pgalloc.h Mon Jan 17 05:05:52 2000 @@ -184,6 +184,7 @@ * * - flush_tlb() flushes the current mm struct TLBs * - flush_tlb_all() flushes all processes TLBs + * - flush_tlb_all_kernel() flushes all processes TLBs, including special TLBs * - flush_tlb_mm(mm) flushes the specified mm context TLB's * - flush_tlb_page(vma, vmaddr) flushes one page * - flush_tlb_range(mm, start, end) flushes a range of pages @@ -196,6 +197,7 @@ #define flush_tlb() __flush_tlb() #define flush_tlb_all() __flush_tlb() +#define flush_tlb_all_kernel() __flush_tlb_global() #define local_flush_tlb() __flush_tlb() static inline void flush_tlb_mm(struct mm_struct *mm) @@ -231,6 +233,7 @@ __flush_tlb() extern void flush_tlb_all(void); +extern void flush_tlb_all_kernel(void); extern void flush_tlb_current_task(void); extern void flush_tlb_mm(struct mm_struct *); extern void flush_tlb_page(struct vm_area_struct *, unsigned long); --- linux/include/asm-i386/fixmap.h.orig2 Mon Jan 17 05:32:54 2000 +++ linux/include/asm-i386/fixmap.h Mon Jan 17 05:37:19 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/arch/i386/mm/init.c.orig2 Mon Jan 17 05:09:46 2000 +++ linux/arch/i386/mm/init.c Mon Jan 17 05:35:20 2000 @@ -239,7 +239,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,7 +250,7 @@ pgd = swapper_pg_dir + __pgd_offset(vaddr); pmd = pmd_offset(pgd, vaddr); pte = pte_offset(pmd, vaddr); - prot = PAGE_KERNEL; + prot = flags; if (boot_cpu_data.x86_capability & X86_FEATURE_PGE) pgprot_val(prot) |= _PAGE_GLOBAL; set_pte(pte, mk_pte_phys(phys, prot)); @@ -260,15 +261,15 @@ __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) @@ -414,7 +415,7 @@ #else set_pgd(swapper_pg_dir+i, __pgd(0)); #endif - flush_tlb_all(); + flush_tlb_all_kernel(); } /* --- linux/arch/i386/kernel/smp.c.orig2 Mon Jan 17 05:05:59 2000 +++ linux/arch/i386/kernel/smp.c Mon Jan 17 05:11:32 2000 @@ -390,16 +390,38 @@ } } +static inline void do_flush_tlb_all_kernel_local(void) +{ + __flush_tlb_global(); + if (!current->mm && current->active_mm) { + unsigned long cpu = smp_processor_id(); + + clear_bit(cpu, ¤t->active_mm->cpu_vm_mask); + cpu_tlbbad[cpu] = 1; + } +} + static void flush_tlb_all_ipi(void* info) { do_flush_tlb_all_local(); } +static void flush_tlb_all_kernel_ipi(void* info) +{ + do_flush_tlb_all_kernel_local(); +} + void flush_tlb_all(void) { smp_call_function (flush_tlb_all_ipi,0,1,1); do_flush_tlb_all_local(); +} + +void flush_tlb_all_kernel(void) +{ + smp_call_function (flush_tlb_all_kernel_ipi,0,1,1); + do_flush_tlb_all_kernel_local(); } /* --- linux/arch/i386/kernel/io_apic.c.orig2 Mon Jan 17 05:16:06 2000 +++ linux/arch/i386/kernel/io_apic.c Mon Jan 17 05:23:48 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; @@ -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 Mon Jan 17 05:37:59 2000 @@ -865,7 +865,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 +880,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++;