x86, 32-bit: trim memory not covered by wb mtrrs
[deliverable/linux.git] / arch / x86 / kernel / apic_64.c
index 915808bd8a2ad8b76bd8546add7fd5b16aec3962..a7a38c9da13690e3955b5bf3d0aded68acf6380f 100644 (file)
 #include <linux/mc146818rtc.h>
 #include <linux/kernel_stat.h>
 #include <linux/sysdev.h>
-#include <linux/module.h>
 #include <linux/ioport.h>
 #include <linux/clockchips.h>
 #include <linux/acpi_pmtmr.h>
+#include <linux/module.h>
 
 #include <asm/atomic.h>
 #include <asm/smp.h>
 #include <asm/mtrr.h>
 #include <asm/mpspec.h>
+#include <asm/hpet.h>
 #include <asm/pgalloc.h>
 #include <asm/mach_apic.h>
 #include <asm/nmi.h>
 #include <asm/idle.h>
 #include <asm/proto.h>
 #include <asm/timex.h>
-#include <asm/hpet.h>
 #include <asm/apic.h>
 
-int apic_verbosity;
 int disable_apic_timer __cpuinitdata;
 static int apic_calibrate_pmtmr __initdata;
 int disable_apic;
 
-/* Local APIC timer works in C2? */
+/* Local APIC timer works in C2 */
 int local_apic_timer_c2_ok;
 EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok);
 
+/*
+ * Debug level, exported for io_apic.c
+ */
+int apic_verbosity;
+
 static struct resource lapic_resource = {
        .name = "Local APIC",
        .flags = IORESOURCE_MEM | IORESOURCE_BUSY,
@@ -77,6 +81,8 @@ static struct clock_event_device lapic_clockevent = {
 };
 static DEFINE_PER_CPU(struct clock_event_device, lapic_events);
 
+static unsigned long apic_phys;
+
 /*
  * Get the LAPIC version
  */
@@ -130,7 +136,7 @@ u32 safe_apic_wait_icr_idle(void)
 /**
  * enable_NMI_through_LVT0 - enable NMI through local vector table 0
  */
-void enable_NMI_through_LVT0(void *dummy)
+void __cpuinit enable_NMI_through_LVT0(void)
 {
        unsigned int v;
 
@@ -187,17 +193,35 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
 }
 
 /*
- * Setup extended LVT (K8 specific)
+ * Setup extended LVT, AMD specific (K8, family 10h)
+ *
+ * Vector mappings are hard coded. On K8 only offset 0 (APIC500) and
+ * MCE interrupts are supported. Thus MCE offset must be set to 0.
  */
-void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector,
-                            unsigned char msg_type, unsigned char mask)
+
+#define APIC_EILVT_LVTOFF_MCE 0
+#define APIC_EILVT_LVTOFF_IBS 1
+
+static void setup_APIC_eilvt(u8 lvt_off, u8 vector, u8 msg_type, u8 mask)
 {
-       unsigned long reg = (lvt_off << 4) + K8_APIC_EXT_LVT_BASE;
+       unsigned long reg = (lvt_off << 4) + APIC_EILVT0;
        unsigned int  v   = (mask << 16) | (msg_type << 8) | vector;
 
        apic_write(reg, v);
 }
 
+u8 setup_APIC_eilvt_mce(u8 vector, u8 msg_type, u8 mask)
+{
+       setup_APIC_eilvt(APIC_EILVT_LVTOFF_MCE, vector, msg_type, mask);
+       return APIC_EILVT_LVTOFF_MCE;
+}
+
+u8 setup_APIC_eilvt_ibs(u8 vector, u8 msg_type, u8 mask)
+{
+       setup_APIC_eilvt(APIC_EILVT_LVTOFF_IBS, vector, msg_type, mask);
+       return APIC_EILVT_LVTOFF_IBS;
+}
+
 /*
  * Program the next event, relative to now
  */
@@ -337,6 +361,11 @@ static void __init calibrate_APIC_clock(void)
        calibration_result = result / HZ;
 }
 
+/*
+ * Setup the boot APIC
+ *
+ * Calibrate and verify the result.
+ */
 void __init setup_boot_APIC_clock(void)
 {
        /*
@@ -348,14 +377,28 @@ void __init setup_boot_APIC_clock(void)
        if (disable_apic_timer) {
                printk(KERN_INFO "Disabling APIC timer\n");
                /* No broadcast on UP ! */
-               if (num_possible_cpus() > 1)
+               if (num_possible_cpus() > 1) {
+                       lapic_clockevent.mult = 1;
                        setup_APIC_timer();
+               }
                return;
        }
 
        printk(KERN_INFO "Using local APIC timer interrupts.\n");
        calibrate_APIC_clock();
 
+       /*
+        * Do a sanity check on the APIC calibration result
+        */
+       if (calibration_result < (1000000 / HZ)) {
+               printk(KERN_WARNING
+                      "APIC frequency too slow, disabling apic timer\n");
+               /* No broadcast on UP ! */
+               if (num_possible_cpus() > 1)
+                       setup_APIC_timer();
+               return;
+       }
+
        /*
         * If nmi_watchdog is set to IO_APIC, we need the
         * PIT/HPET going.  Otherwise register lapic as a dummy
@@ -484,6 +527,11 @@ void clear_local_APIC(void)
        int maxlvt = lapic_get_maxlvt();
        u32 v;
 
+       /* APIC hasn't been mapped yet */
+       if (!apic_phys)
+               return;
+
+       maxlvt = lapic_get_maxlvt();
        /*
         * Masking an LVT entry can trigger a local APIC error
         * if the vector is zero. Mask LVTERR first to prevent this.
@@ -677,7 +725,7 @@ void __init init_bsp_APIC(void)
  */
 void __cpuinit setup_local_APIC(void)
 {
-       unsigned int value, maxlvt;
+       unsigned int value;
        int i, j;
 
        value = apic_read(APIC_LVR);
@@ -773,25 +821,23 @@ void __cpuinit setup_local_APIC(void)
        else
                value = APIC_DM_NMI | APIC_LVT_MASKED;
        apic_write(APIC_LVT1, value);
+}
 
-       {
-               unsigned oldvalue;
-               maxlvt = lapic_get_maxlvt();
-               oldvalue = apic_read(APIC_ESR);
-               value = ERROR_APIC_VECTOR;      // enables sending errors
-               apic_write(APIC_LVTERR, value);
-               /*
-                * spec says clear errors after enabling vector.
-                */
-               if (maxlvt > 3)
-                       apic_write(APIC_ESR, 0);
-               value = apic_read(APIC_ESR);
-               if (value != oldvalue)
-                       apic_printk(APIC_VERBOSE,
-                       "ESR value after enabling vector: %08x, after %08x\n",
-                       oldvalue, value);
-       }
+void __cpuinit lapic_setup_esr(void)
+{
+       unsigned maxlvt = lapic_get_maxlvt();
 
+       apic_write(APIC_LVTERR, ERROR_APIC_VECTOR);
+       /*
+        * spec says clear errors after enabling vector.
+        */
+       if (maxlvt > 3)
+               apic_write(APIC_ESR, 0);
+}
+
+void __cpuinit end_local_APIC_setup(void)
+{
+       lapic_setup_esr();
        nmi_watchdog_default();
        setup_apic_nmi_watchdog(NULL);
        apic_pm_activate();
@@ -820,8 +866,6 @@ static int __init detect_init_APIC(void)
  */
 void __init init_apic_mappings(void)
 {
-       unsigned long apic_phys;
-
        /*
         * If no local APIC can be found then set up a fake all
         * zeroes page to simulate the local APIC and another
@@ -872,6 +916,15 @@ int __init APIC_init_uniprocessor(void)
 
        setup_local_APIC();
 
+       /*
+        * Now enable IO-APICs, actually call clear_IO_APIC
+        * We need clear_IO_APIC before enabling vector on BP
+        */
+       if (!skip_ioapic_setup && nr_ioapics)
+               enable_IO_APIC();
+
+       end_local_APIC_setup();
+
        if (smp_found_config && !skip_ioapic_setup && nr_ioapics)
                setup_IO_APIC();
        else
@@ -1084,8 +1137,8 @@ static struct sysdev_class lapic_sysclass = {
 };
 
 static struct sys_device device_lapic = {
-       .id             = 0,
-       .cls            = &lapic_sysclass,
+       .id     = 0,
+       .cls    = &lapic_sysclass,
 };
 
 static void __cpuinit apic_pm_activate(void)
@@ -1096,9 +1149,11 @@ static void __cpuinit apic_pm_activate(void)
 static int __init init_lapic_sysfs(void)
 {
        int error;
+
        if (!cpu_has_apic)
                return 0;
        /* XXX: remove suspend/resume procs if !apic_pm_state.active? */
+
        error = sysdev_class_register(&lapic_sysclass);
        if (!error)
                error = sysdev_register(&device_lapic);
@@ -1125,19 +1180,32 @@ __cpuinit int apic_is_clustered_box(void)
 {
        int i, clusters, zeros;
        unsigned id;
+       u16 *bios_cpu_apicid = x86_bios_cpu_apicid_early_ptr;
        DECLARE_BITMAP(clustermap, NUM_APIC_CLUSTERS);
 
        bitmap_zero(clustermap, NUM_APIC_CLUSTERS);
 
        for (i = 0; i < NR_CPUS; i++) {
-               id = bios_cpu_apicid[i];
+               /* are we being called early in kernel startup? */
+               if (bios_cpu_apicid) {
+                       id = bios_cpu_apicid[i];
+               }
+               else if (i < nr_cpu_ids) {
+                       if (cpu_present(i))
+                               id = per_cpu(x86_bios_cpu_apicid, i);
+                       else
+                               continue;
+               }
+               else
+                       break;
+
                if (id != BAD_APICID)
                        __set_bit(APIC_CLUSTERID(id), clustermap);
        }
 
        /* Problem:  Partially populated chassis may not have CPUs in some of
         * the APIC clusters they have been allocated.  Only present CPUs have
-        * bios_cpu_apicid entries, thus causing zeroes in the bitmap.  Since
+        * x86_bios_cpu_apicid entries, thus causing zeroes in the bitmap.  Since
         * clusters are allocated sequentially, count zeros only if they are
         * bounded by ones.
         */
@@ -1186,7 +1254,7 @@ early_param("apic", apic_set_verbosity);
 static __init int setup_disableapic(char *str)
 {
        disable_apic = 1;
-       clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
+       clear_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC);
        return 0;
 }
 early_param("disableapic", setup_disableapic);
This page took 0.027809 seconds and 5 git commands to generate.