* Mikael Pettersson : PM converted to driver model.
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/sysdev.h>
#include <linux/cpu.h>
#include <linux/module.h>
+#include <linux/dmi.h>
#include <asm/atomic.h>
#include <asm/smp.h>
#include <asm/arch_hooks.h>
#include <asm/hpet.h>
#include <asm/i8253.h>
+#include <asm/nmi.h>
#include <mach_apic.h>
#include <mach_apicdef.h>
* 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
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 */
}
/* 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;
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) {
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)
return 1;
}
-__setup("apic=", apic_set_verbosity);
+__setup("apic", apic_set_verbosity);
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;
}
/*
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);
}
}
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.