diff -ruN linux-2.4.18-pre7.early-dmi-scan/arch/i386/kernel/apic.c linux-2.4.18-pre7.dmi-apic-fixups/arch/i386/kernel/apic.c --- linux-2.4.18-pre7.early-dmi-scan/arch/i386/kernel/apic.c Sun Jan 27 10:12:27 2002 +++ linux-2.4.18-pre7.dmi-apic-fixups/arch/i386/kernel/apic.c Sun Jan 27 11:27:33 2002 @@ -578,12 +578,17 @@ * Detect and enable local APICs on non-SMP boards. * Original code written by Keir Fraser. */ +int dont_enable_local_apic __initdata = 0; static int __init detect_init_APIC (void) { u32 h, l, features; extern void get_cpu_vendor(struct cpuinfo_x86*); + /* Disabled by DMI scan or kernel option? */ + if (dont_enable_local_apic) + return -1; + /* Workaround for us being called before identify_cpu(). */ get_cpu_vendor(&boot_cpu_data); @@ -901,8 +906,14 @@ static unsigned int calibration_result; +int dont_use_local_apic_timer __initdata = 0; + void __init setup_APIC_clocks (void) { + /* Disabled by DMI scan or kernel option? */ + if (dont_use_local_apic_timer) + return; + printk("Using local APIC timer interrupts.\n"); using_apic_timer = 1; diff -ruN linux-2.4.18-pre7.early-dmi-scan/arch/i386/kernel/dmi_scan.c linux-2.4.18-pre7.dmi-apic-fixups/arch/i386/kernel/dmi_scan.c --- linux-2.4.18-pre7.early-dmi-scan/arch/i386/kernel/dmi_scan.c Sun Jan 27 11:24:41 2002 +++ linux-2.4.18-pre7.dmi-apic-fixups/arch/i386/kernel/dmi_scan.c Sun Jan 27 11:27:33 2002 @@ -415,6 +415,43 @@ return 0; } +/* + * Some machines, usually laptops, can't handle an enabled local APIC. + * The symptoms include hangs or reboots when suspending or resuming, + * attaching or detaching the power cord, or entering BIOS setup screens + * through magic key sequences. + */ +static int __init local_apic_kills_bios(struct dmi_blacklist *d) +{ +#ifdef CONFIG_X86_LOCAL_APIC + extern int dont_enable_local_apic; + if (!dont_enable_local_apic) { + dont_enable_local_apic = 1; + printk(KERN_WARNING "%s with broken BIOS detected. " + "Refusing to enable the local APIC.\n", + d->ident); + } +#endif + return 0; +} + +/* + * The Intel AL440LX mainboard will hang randomly if the local APIC + * timer is running and the APM BIOS hasn't been disabled. + */ +static int __init apm_kills_local_apic_timer(struct dmi_blacklist *d) +{ +#ifdef CONFIG_X86_LOCAL_APIC + extern int dont_use_local_apic_timer; + if (apm_info.bios.version && !dont_use_local_apic_timer) { + dont_use_local_apic_timer = 1; + printk(KERN_WARNING "%s with broken BIOS detected. " + "The local APIC timer will not be used.\n", + d->ident); + } +#endif + return 0; +} /* * Simple "print if true" callback @@ -564,6 +601,25 @@ MATCH(DMI_BIOS_DATE, "09/12/00"), NO_MATCH } }, + /* Machines which have problems handling enabled local APICs */ + + { local_apic_kills_bios, "Dell Inspiron", { + MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), + MATCH(DMI_PRODUCT_NAME, "Inspiron"), + NO_MATCH, NO_MATCH + } }, + + { local_apic_kills_bios, "Dell Latitude", { + MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), + MATCH(DMI_PRODUCT_NAME, "Latitude"), + NO_MATCH, NO_MATCH + } }, + + { apm_kills_local_apic_timer, "Intel AL440LX", { + MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), + MATCH(DMI_BOARD_NAME, "AL440LX"), + NO_MATCH, NO_MATCH } }, + /* Problem Intel 440GX bioses */ { broken_pirq, "SABR1 Bios", { /* Bad $PIR */ diff -ruN linux-2.4.18-pre7.early-dmi-scan/arch/i386/kernel/setup.c linux-2.4.18-pre7.dmi-apic-fixups/arch/i386/kernel/setup.c --- linux-2.4.18-pre7.early-dmi-scan/arch/i386/kernel/setup.c Sun Jan 27 11:24:41 2002 +++ linux-2.4.18-pre7.dmi-apic-fixups/arch/i386/kernel/setup.c Sun Jan 27 11:27:33 2002 @@ -995,7 +995,6 @@ */ if (smp_found_config) get_smp_config(); - init_apic_mappings(); #endif diff -ruN linux-2.4.18-pre7.early-dmi-scan/arch/i386/kernel/traps.c linux-2.4.18-pre7.dmi-apic-fixups/arch/i386/kernel/traps.c --- linux-2.4.18-pre7.early-dmi-scan/arch/i386/kernel/traps.c Thu Oct 11 13:34:39 2001 +++ linux-2.4.18-pre7.dmi-apic-fixups/arch/i386/kernel/traps.c Sun Jan 27 11:27:33 2002 @@ -920,6 +920,10 @@ EISA_bus = 1; #endif +#ifdef CONFIG_X86_LOCAL_APIC + init_apic_mappings(); +#endif + set_trap_gate(0,÷_error); set_trap_gate(1,&debug); set_intr_gate(2,&nmi);