X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fi386%2Fkernel%2Fapic.c;h=776d9be26af9ea5906bc0e04798878e69d3b51a3;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=5bec4fbdb40b9ee9e99a4e3b66785662d9e495c9;hpb=16c70f8c1b54b61c3b951b6fb220df250fe09b32;p=linux-2.6.git diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index 5bec4fbdb..776d9be26 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include @@ -53,10 +52,18 @@ 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; +static int enable_local_apic __initdata = 0; /* -1=force-disable, +1=force-enable */ + +static inline void lapic_disable(void) +{ + enable_local_apic = -1; + clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability); +} + +static inline void lapic_enable(void) +{ + enable_local_apic = 1; +} /* * Debug level @@ -590,8 +597,7 @@ void __devinit setup_local_APIC(void) printk("No ESR for 82489DX.\n"); } - if (nmi_watchdog == NMI_LOCAL_APIC) - setup_apic_nmi_watchdog(); + setup_apic_nmi_watchdog(NULL); apic_pm_activate(); } @@ -641,23 +647,30 @@ static struct { static int lapic_suspend(struct sys_device *dev, pm_message_t state) { unsigned long flags; + int maxlvt; if (!apic_pm_state.active) return 0; + maxlvt = get_maxlvt(); + apic_pm_state.apic_id = apic_read(APIC_ID); apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI); apic_pm_state.apic_ldr = apic_read(APIC_LDR); apic_pm_state.apic_dfr = apic_read(APIC_DFR); apic_pm_state.apic_spiv = apic_read(APIC_SPIV); apic_pm_state.apic_lvtt = apic_read(APIC_LVTT); - apic_pm_state.apic_lvtpc = apic_read(APIC_LVTPC); + if (maxlvt >= 4) + apic_pm_state.apic_lvtpc = apic_read(APIC_LVTPC); apic_pm_state.apic_lvt0 = apic_read(APIC_LVT0); apic_pm_state.apic_lvt1 = apic_read(APIC_LVT1); apic_pm_state.apic_lvterr = apic_read(APIC_LVTERR); apic_pm_state.apic_tmict = apic_read(APIC_TMICT); apic_pm_state.apic_tdcr = apic_read(APIC_TDCR); - apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR); +#ifdef CONFIG_X86_MCE_P4THERMAL + if (maxlvt >= 5) + apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR); +#endif local_irq_save(flags); disable_local_APIC(); @@ -669,10 +682,13 @@ static int lapic_resume(struct sys_device *dev) { unsigned int l, h; unsigned long flags; + int maxlvt; if (!apic_pm_state.active) return 0; + maxlvt = get_maxlvt(); + local_irq_save(flags); /* @@ -694,8 +710,12 @@ static int lapic_resume(struct sys_device *dev) apic_write(APIC_SPIV, apic_pm_state.apic_spiv); apic_write(APIC_LVT0, apic_pm_state.apic_lvt0); apic_write(APIC_LVT1, apic_pm_state.apic_lvt1); - apic_write(APIC_LVTTHMR, apic_pm_state.apic_thmr); - apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc); +#ifdef CONFIG_X86_MCE_P4THERMAL + if (maxlvt >= 5) + apic_write(APIC_LVTTHMR, apic_pm_state.apic_thmr); +#endif + if (maxlvt >= 4) + apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc); apic_write(APIC_LVTT, apic_pm_state.apic_lvtt); apic_write(APIC_TDCR, apic_pm_state.apic_tdcr); apic_write(APIC_TMICT, apic_pm_state.apic_tmict); @@ -757,10 +777,6 @@ 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) @@ -768,7 +784,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) { @@ -799,9 +815,8 @@ static int __init detect_init_APIC (void) * APIC only if "lapic" specified. */ if (enable_local_apic <= 0) { - if (!apic_disabled_by_dmi) - printk("Local APIC disabled by BIOS -- " - "you can enable it with \"lapic\"\n"); + printk("Local APIC disabled by BIOS -- " + "you can enable it with \"lapic\"\n"); return -1; } /* @@ -1192,11 +1207,11 @@ EXPORT_SYMBOL(switch_ipi_to_APIC_timer); * value into /proc/profile. */ -inline void smp_local_timer_interrupt(struct pt_regs * regs) +inline void smp_local_timer_interrupt(void) { - profile_tick(CPU_PROFILING, regs); + profile_tick(CPU_PROFILING); #ifdef CONFIG_SMP - update_process_times(user_mode_vm(regs)); + update_process_times(user_mode_vm(get_irq_regs())); #endif /* @@ -1222,6 +1237,7 @@ inline void smp_local_timer_interrupt(struct pt_regs * regs) fastcall void smp_apic_timer_interrupt(struct pt_regs *regs) { + struct pt_regs *old_regs = set_irq_regs(regs); int cpu = smp_processor_id(); /* @@ -1240,12 +1256,13 @@ fastcall void smp_apic_timer_interrupt(struct pt_regs *regs) * interrupt lock, which is the WrongThing (tm) to do. */ irq_enter(); - smp_local_timer_interrupt(regs); + smp_local_timer_interrupt(); irq_exit(); + set_irq_regs(old_regs); } #ifndef CONFIG_SMP -static void up_apic_timer_interrupt_call(struct pt_regs *regs) +static void up_apic_timer_interrupt_call(void) { int cpu = smp_processor_id(); @@ -1254,11 +1271,11 @@ static void up_apic_timer_interrupt_call(struct pt_regs *regs) */ per_cpu(irq_stat, cpu).apic_timer_irqs++; - smp_local_timer_interrupt(regs); + smp_local_timer_interrupt(); } #endif -void smp_send_timer_broadcast_ipi(struct pt_regs *regs) +void smp_send_timer_broadcast_ipi(void) { cpumask_t mask; @@ -1271,7 +1288,7 @@ void smp_send_timer_broadcast_ipi(struct pt_regs *regs) * We can directly call the apic timer interrupt handler * in UP case. Minus all irq related functions */ - up_apic_timer_interrupt_call(regs); + up_apic_timer_interrupt_call(); #endif } } @@ -1335,64 +1352,6 @@ 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. @@ -1440,3 +1399,18 @@ int __init APIC_init_uniprocessor (void) return 0; } + +static int __init parse_lapic(char *arg) +{ + lapic_enable(); + return 0; +} +early_param("lapic", parse_lapic); + +static int __init parse_nolapic(char *arg) +{ + lapic_disable(); + return 0; +} +early_param("nolapic", parse_nolapic); +