vserver 1.9.5.x5
[linux-2.6.git] / arch / x86_64 / kernel / apic.c
index 6fb84e2..dbccec4 100644 (file)
@@ -32,6 +32,9 @@
 #include <asm/mtrr.h>
 #include <asm/mpspec.h>
 #include <asm/pgalloc.h>
+#include <asm/mach_apic.h>
+
+int apic_verbosity;
 
 int disable_apic_timer __initdata;
 
@@ -123,7 +126,7 @@ void __init connect_bsp_APIC(void)
                 * PIC mode, enable APIC mode in the IMCR, i.e.
                 * connect BSP's local APIC to INT and NMI lines.
                 */
-               printk(KERN_INFO "leaving PIC mode, enabling APIC mode.\n");
+               apic_printk(APIC_VERBOSE, "leaving PIC mode, enabling APIC mode.\n");
                outb(0x70, 0x22);
                outb(0x01, 0x23);
        }
@@ -138,7 +141,7 @@ void disconnect_bsp_APIC(void)
                 * interrupts, including IPIs, won't work beyond
                 * this point!  The only exception are INIT IPIs.
                 */
-               printk(KERN_INFO "disabling APIC mode, entering PIC mode.\n");
+               apic_printk(APIC_QUIET, "disabling APIC mode, entering PIC mode.\n");
                outb(0x70, 0x22);
                outb(0x00, 0x23);
        }
@@ -172,10 +175,10 @@ int __init verify_local_APIC(void)
         * The version register is read-only in a real APIC.
         */
        reg0 = apic_read(APIC_LVR);
-       Dprintk("Getting VERSION: %x\n", reg0);
+       apic_printk(APIC_DEBUG, "Getting VERSION: %x\n", reg0);
        apic_write(APIC_LVR, reg0 ^ APIC_LVR_MASK);
        reg1 = apic_read(APIC_LVR);
-       Dprintk("Getting VERSION: %x\n", reg1);
+       apic_printk(APIC_DEBUG, "Getting VERSION: %x\n", reg1);
 
        /*
         * The two version reads above should print the same
@@ -199,10 +202,10 @@ int __init verify_local_APIC(void)
         * The ID register is read/write in a real APIC.
         */
        reg0 = apic_read(APIC_ID);
-       Dprintk("Getting ID: %x\n", reg0);
+       apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg0);
        apic_write(APIC_ID, reg0 ^ APIC_ID_MASK);
        reg1 = apic_read(APIC_ID);
-       Dprintk("Getting ID: %x\n", reg1);
+       apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg1);
        apic_write(APIC_ID, reg0);
        if (reg1 != (reg0 ^ APIC_ID_MASK))
                return 0;
@@ -213,21 +216,26 @@ int __init verify_local_APIC(void)
         * compatibility mode, but most boxes are anymore.
         */
        reg0 = apic_read(APIC_LVT0);
-       Dprintk("Getting LVT0: %x\n", reg0);
+       apic_printk(APIC_DEBUG,"Getting LVT0: %x\n", reg0);
        reg1 = apic_read(APIC_LVT1);
-       Dprintk("Getting LVT1: %x\n", reg1);
+       apic_printk(APIC_DEBUG, "Getting LVT1: %x\n", reg1);
 
        return 1;
 }
 
 void __init sync_Arb_IDs(void)
 {
+       /* Unsupported on P4 - see Intel Dev. Manual Vol. 3, Ch. 8.6.1 */
+       unsigned int ver = GET_APIC_VERSION(apic_read(APIC_LVR));
+       if (ver >= 0x14)        /* P4 or higher */
+               return;
+
        /*
         * Wait for idle.
         */
        apic_wait_icr_idle();
 
-       Dprintk("Synchronizing Arb IDs.\n");
+       apic_printk(APIC_DEBUG, "Synchronizing Arb IDs.\n");
        apic_write_around(APIC_ICR, APIC_DEST_ALLINC | APIC_INT_LEVELTRIG
                                | APIC_DM_INIT);
 }
@@ -298,8 +306,7 @@ void __init setup_local_APIC (void)
         * Double-check whether this APIC is really registered.
         * This is meaningless in clustered apic mode, so we skip it.
         */
-       if (!clustered_apic_mode &&
-               !physid_isset(GET_APIC_ID(apic_read(APIC_ID)), phys_cpu_present_map))
+       if (!apic_id_registered())
                BUG();
 
        /*
@@ -307,23 +314,7 @@ void __init setup_local_APIC (void)
         * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel
         * document number 292116).  So here it goes...
         */
-
-       if (!clustered_apic_mode) {
-               /*
-                * In clustered apic mode, the firmware does this for us 
-                * Put the APIC into flat delivery mode.
-                * Must be "all ones" explicitly for 82489DX.
-                */
-               apic_write_around(APIC_DFR, 0xffffffff);
-
-               /*
-                * Set up the logical destination ID.
-                */
-               value = apic_read(APIC_LDR);
-               value &= ~APIC_LDR_MASK;
-               value |= (1<<(smp_processor_id()+24));
-               apic_write_around(APIC_LDR, value);
-       }
+       init_apic_ldr();
 
        /*
         * Set Task Priority to 'accept all'. We never change this
@@ -388,10 +379,10 @@ void __init setup_local_APIC (void)
        value = apic_read(APIC_LVT0) & APIC_LVT_MASKED;
        if (!smp_processor_id() && (pic_mode || !value)) {
                value = APIC_DM_EXTINT;
-               Dprintk(KERN_INFO "enabled ExtINT on CPU#%d\n", smp_processor_id());
+               apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n", smp_processor_id());
        } else {
                value = APIC_DM_EXTINT | APIC_LVT_MASKED;
-               Dprintk(KERN_INFO "masked ExtINT on CPU#%d\n", smp_processor_id());
+               apic_printk(APIC_VERBOSE, "masked ExtINT on CPU#%d\n", smp_processor_id());
        }
        apic_write_around(APIC_LVT0, value);
 
@@ -407,12 +398,11 @@ void __init setup_local_APIC (void)
        apic_write_around(APIC_LVT1, value);
 
        if (APIC_INTEGRATED(ver) && !esr_disable) {             /* !82489DX */
+               unsigned oldvalue;
                maxlvt = get_maxlvt();
                if (maxlvt > 3)         /* Due to the Pentium erratum 3AP. */
                        apic_write(APIC_ESR, 0);
-               value = apic_read(APIC_ESR);
-               Dprintk("ESR value before enabling vector: %08x\n", value);
-
+               oldvalue = apic_read(APIC_ESR);
                value = ERROR_APIC_VECTOR;      // enables sending errors
                apic_write_around(APIC_LVTERR, value);
                /*
@@ -421,7 +411,10 @@ void __init setup_local_APIC (void)
                if (maxlvt > 3)
                        apic_write(APIC_ESR, 0);
                value = apic_read(APIC_ESR);
-               Dprintk("ESR value after enabling vector: %08x\n", value);
+               if (value != oldvalue)
+                       apic_printk(APIC_VERBOSE,
+                       "ESR value after enabling vector: %08x, after %08x\n",
+                       oldvalue, value);
        } else {
                if (esr_disable)        
                        /* 
@@ -430,9 +423,9 @@ void __init setup_local_APIC (void)
                         * ESR disabled - we can't do anything useful with the
                         * errors anyway - mbligh
                         */
-                       printk("Leaving ESR disabled.\n");
+                       apic_printk(APIC_DEBUG, "Leaving ESR disabled.\n");
                else 
-                       printk("No ESR for 82489DX.\n");
+                       apic_printk(APIC_DEBUG, "No ESR for 82489DX.\n");
        }
 
        nmi_watchdog_default();
@@ -564,6 +557,21 @@ static void apic_pm_activate(void) { }
 
 #endif /* CONFIG_PM */
 
+static int __init apic_set_verbosity(char *str)
+{
+       if (strcmp("debug", str) == 0)
+               apic_verbosity = APIC_DEBUG;
+       else if (strcmp("verbose", str) == 0)
+               apic_verbosity = APIC_VERBOSE;
+       else
+               printk(KERN_WARNING "APIC Verbosity level %s not recognised"
+                               " use apic=verbose or apic=debug", str);
+
+       return 0;
+}
+
+__setup("apic=", apic_set_verbosity);
+
 /*
  * Detect and enable local APICs on non-SMP boards.
  * Original code written by Keir Fraser.
@@ -599,7 +607,7 @@ void __init init_apic_mappings(void)
                apic_phys = mp_lapic_addr;
 
        set_fixmap_nocache(FIX_APIC_BASE, apic_phys);
-       Dprintk("mapped APIC to %16lx (%16lx)\n", APIC_BASE, apic_phys);
+       apic_printk(APIC_VERBOSE,"mapped APIC to %16lx (%16lx)\n", APIC_BASE, apic_phys);
 
        /*
         * Fetch the APIC ID of the BSP in case we have a
@@ -621,7 +629,7 @@ void __init init_apic_mappings(void)
                                ioapic_phys = __pa(ioapic_phys);
                        }
                        set_fixmap_nocache(idx, ioapic_phys);
-                       Dprintk("mapped IOAPIC to %016lx (%016lx)\n",
+                       apic_printk(APIC_VERBOSE,"mapped IOAPIC to %016lx (%016lx)\n",
                                        __fix_to_virt(idx), ioapic_phys);
                        idx++;
                }
@@ -836,8 +844,7 @@ void smp_local_timer_interrupt(struct pt_regs *regs)
 {
        int cpu = smp_processor_id();
 
-       x86_do_profile(regs);
-
+       profile_tick(CPU_PROFILING, regs);
        if (--per_cpu(prof_counter, cpu) <= 0) {
                /*
                 * The multiplier may have changed since the last time we got
@@ -903,6 +910,54 @@ void smp_apic_timer_interrupt(struct pt_regs *regs)
        irq_exit();
 }
 
+/*
+ * oem_force_hpet_timer -- force HPET mode for some boxes.
+ *
+ * Thus far, the major user of this is IBM's Summit2 series:
+ *
+ * Clustered boxes may have unsynced TSC problems if they are
+ * multi-chassis. Use available data to take a good guess.
+ * If in doubt, go HPET.
+ */
+__init int oem_force_hpet_timer(void)
+{
+       int i, clusters, zeros;
+       unsigned id;
+       DECLARE_BITMAP(clustermap, NUM_APIC_CLUSTERS);
+
+       bitmap_empty(clustermap, NUM_APIC_CLUSTERS);
+
+       for (i = 0; i < NR_CPUS; i++) {
+               id = bios_cpu_apicid[i];
+               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
+        * clusters are allocated sequentially, count zeros only if they are
+        * bounded by ones.
+        */
+       clusters = 0;
+       zeros = 0;
+       for (i = 0; i < NUM_APIC_CLUSTERS; i++) {
+               if (test_bit(i, clustermap)) {
+                       clusters += 1 + zeros;
+                       zeros = 0;
+               } else
+                       ++zeros;
+       }
+
+       /*
+        * If clusters > 2, then should be multi-chassis.  Return 1 for HPET.
+        * Else return 0 to use TSC.
+        * May have to revisit this when multi-core + hyperthreaded CPUs come
+        * out, but AFAIK this will work even for them.
+        */
+       return (clusters > 2);
+}
+
 /*
  * This interrupt should _never_ happen with our APIC/SMP architecture
  */
@@ -962,7 +1017,7 @@ asmlinkage void smp_error_interrupt(void)
           6: Received illegal vector
           7: Illegal register address
        */
-       printk (KERN_INFO "APIC error on CPU%d: %02x(%02x)\n",
+       printk (KERN_DEBUG "APIC error on CPU%d: %02x(%02x)\n",
                smp_processor_id(), v , v1);
        irq_exit();
 }