X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fi386%2Fkernel%2Fapic.c;fp=arch%2Fi386%2Fkernel%2Fapic.c;h=5bec4fbdb40b9ee9e99a4e3b66785662d9e495c9;hb=16c70f8c1b54b61c3b951b6fb220df250fe09b32;hp=3d4b2f3d116a796ffad8ef911353b6a71a2f43b7;hpb=4e76c8a9fa413ccc09d3f7f664183dcce3555d57;p=linux-2.6.git diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index 3d4b2f3d1..5bec4fbdb 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c @@ -14,7 +14,6 @@ * Mikael Pettersson : PM converted to driver model. */ -#include #include #include @@ -27,6 +26,7 @@ #include #include #include +#include #include #include @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -53,6 +54,9 @@ static cpumask_t timer_bcast_ipi; * Knob to control our willingness to enable the local APIC. */ int enable_local_apic __initdata = 0; /* -1=force-disable, +1=force-enable */ +int prefer_apic __initdata = 0; /* when enable_local_apic == 0 prefer APIC but don't force against + BIOS wishes */ +int apic_disabled_by_dmi __initdata; /* * Debug level @@ -62,7 +66,7 @@ int apic_verbosity; static void apic_pm_activate(void); -int modern_apic(void) +static int modern_apic(void) { unsigned int lvr, version; /* AMD systems use old APIC versions, so check the CPU */ @@ -113,7 +117,7 @@ void __init apic_intr_init(void) } /* Using APIC to generate smp_local_timer_interrupt? */ -int using_apic_timer = 0; +int using_apic_timer __read_mostly = 0; static int enabled_via_apicbase; @@ -156,7 +160,7 @@ void clear_local_APIC(void) maxlvt = get_maxlvt(); /* - * Masking an LVT entry on a P6 can trigger a local APIC error + * Masking an LVT entry can trigger a local APIC error * if the vector is zero. Mask LVTERR first to prevent this. */ if (maxlvt >= 3) { @@ -753,6 +757,10 @@ static void apic_pm_activate(void) { } static int __init apic_set_verbosity(char *str) { + if (*str == '=') + ++str; + if (*str == 0) + prefer_apic = 1; if (strcmp("debug", str) == 0) apic_verbosity = APIC_DEBUG; else if (strcmp("verbose", str) == 0) @@ -760,7 +768,7 @@ static int __init apic_set_verbosity(char *str) return 1; } -__setup("apic=", apic_set_verbosity); +__setup("apic", apic_set_verbosity); static int __init detect_init_APIC (void) { @@ -791,8 +799,9 @@ static int __init detect_init_APIC (void) * APIC only if "lapic" specified. */ if (enable_local_apic <= 0) { - printk("Local APIC disabled by BIOS -- " - "you can enable it with \"lapic\"\n"); + if (!apic_disabled_by_dmi) + printk("Local APIC disabled by BIOS -- " + "you can enable it with \"lapic\"\n"); return -1; } /* @@ -1117,7 +1126,18 @@ void disable_APIC_timer(void) unsigned long v; v = apic_read(APIC_LVTT); - apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED); + /* + * When an illegal vector value (0-15) is written to an LVT + * entry and delivery mode is Fixed, the APIC may signal an + * illegal vector error, with out regard to whether the mask + * bit is set or whether an interrupt is actually seen on input. + * + * Boot sequence might call this function when the LVTT has + * '0' vector value. So make sure vector field is set to + * valid value. + */ + v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR); + apic_write_around(APIC_LVTT, v); } } @@ -1315,6 +1335,64 @@ fastcall void smp_error_interrupt(struct pt_regs *regs) irq_exit(); } +#ifdef CONFIG_X86_APIC_AUTO + +/* Some heuristics to decide when to enable the APICs */ + +static __init int dmi_enable_apic(void) +{ + int year; + int apic; + char *vendor; + + /* If the machine has more than one CPU try to use APIC because it'll + be running the SMP kernel with APIC soon anyways. + This won't cover dual core, but they are handled by the date check + below. */ + if (dmi_cpus > 1) + return 1; + + year = dmi_get_year(DMI_BIOS_DATE); + vendor = dmi_get_system_info(DMI_BIOS_VENDOR); + apic = 0; + + /* All Intel BIOS since 1998 assumed APIC on. Don't include 1998 itself + because we're not sure for that. */ + if (vendor && !strncmp(vendor, "Intel", 5)) + apic = 1; + /* Use APIC for anything since 2001 */ + else if (year >= 2001) + apic = 1; + +#ifdef CONFIG_ACPI + /* When ACPI is disabled also default to APIC off on very new systems (>= 2004) + which typically don't have working mptables anymore */ + if (acpi_noirq && year >= 2004) + apic = 0; +#endif + + if (!apic) + apic_disabled_by_dmi = 1; + + return apic; +} + +void __init dmi_check_apic(void) +{ + if (enable_local_apic != 0 || prefer_apic) + return; + if (!dmi_enable_apic()) { + clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability); + nr_ioapics = 0; + enable_local_apic = -1; + printk(KERN_INFO "IO/L-APIC disabled because your old system seems to be old\n"); + printk(KERN_INFO "overwrite with \"apic\"\n"); + return; + } + printk(KERN_INFO "IO/L-APIC allowed because system is MP or new enough\n"); +} +#endif + /* * This initializes the IO-APIC and APIC hardware if this is * a UP kernel.