diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-04 07:40:19 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-04 07:40:19 +0000 |
commit | 33263fc5f9ac8e8cb2b22d06af3ce5ac1dd815e4 (patch) | |
tree | 2d1b86a40bef0958a68cf1a2eafbeb0667a70543 /arch/i386/kernel/smpboot.c | |
parent | 216f5f51aa02f8b113aa620ebc14a9631a217a00 (diff) |
Merge with Linux 2.3.32.
Diffstat (limited to 'arch/i386/kernel/smpboot.c')
-rw-r--r-- | arch/i386/kernel/smpboot.c | 55 |
1 files changed, 48 insertions, 7 deletions
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index 85f439978..811f00f38 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -44,6 +44,7 @@ #include <linux/delay.h> #include <linux/mc146818rtc.h> #include <asm/mtrr.h> +#include <asm/pgalloc.h> /* Set if we find a B stepping CPU */ static int smp_b_stepping = 0; @@ -649,10 +650,11 @@ void __init smp_alloc_memory(void) void __init smp_store_cpu_info(int id) { - struct cpuinfo_x86 *c=&cpu_data[id]; + struct cpuinfo_x86 *c = cpu_data + id; *c = boot_cpu_data; c->pte_quick = 0; + c->pmd_quick = 0; c->pgd_quick = 0; c->pgtable_cache_sz = 0; identify_cpu(c); @@ -706,7 +708,35 @@ int get_maxlvt(void) return maxlvt; } -void __init setup_local_APIC(void) +void disable_local_APIC (void) +{ + unsigned long value; + int maxlvt; + + /* + * Disable APIC + */ + value = apic_read(APIC_SPIV); + value &= ~(1<<8); + apic_write(APIC_SPIV,value); + + /* + * 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); + if (maxlvt >= 3) + apic_write_around(APIC_LVTERR, 0x00010000); + if (maxlvt >= 4) + apic_write_around(APIC_LVTPC, 0x00010000); +} + +void __init setup_local_APIC (void) { unsigned long value, ver, maxlvt; @@ -714,11 +744,24 @@ void __init setup_local_APIC(void) __error_in_io_apic_c(); value = apic_read(APIC_SPIV); - value = 0xf; /* * Enable APIC */ value |= (1<<8); + + /* + * Some unknown Intel IO/APIC (or APIC) errata is biting us with + * certain networking cards. If high frequency interrupts are + * happening on a particular IOAPIC pin, plus the IOAPIC routing + * entry is masked/unmasked at a high rate as well then sooner or + * later IOAPIC line gets 'stuck', no more interrupts are received + * from the device. If focus CPU is disabled then the hang goes + * away, oh well :-( + * + * [ This bug can be reproduced easily with a level-triggered + * PCI Ne2000 networking cards and PII/PIII processors, dual + * BX chipset. ] + */ #if 0 /* Enable focus processor (bit==0) */ value &= ~(1<<9); @@ -821,8 +864,7 @@ void __init init_smp_mappings(void) * could use the real zero-page, but it's safer * this way if some buggy code writes to this page ... */ - apic_phys = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); - memset((void *)apic_phys, 0, PAGE_SIZE); + apic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE); apic_phys = __pa(apic_phys); } set_fixmap(FIX_APIC_BASE, apic_phys); @@ -837,8 +879,7 @@ void __init init_smp_mappings(void) if (smp_found_config) { ioapic_phys = mp_ioapics[i].mpc_apicaddr; } else { - ioapic_phys = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); - memset((void *)ioapic_phys, 0, PAGE_SIZE); + ioapic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE); ioapic_phys = __pa(ioapic_phys); } set_fixmap(idx,ioapic_phys); |