Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6
[safe/jmp/linux-2.6] / arch / x86 / kernel / apic / apic.c
index a4c9cf0..c02cc69 100644 (file)
@@ -14,6 +14,7 @@
  *     Mikael Pettersson       :       PM converted to driver model.
  */
 
+#include <linux/perf_event.h>
 #include <linux/kernel_stat.h>
 #include <linux/mc146818rtc.h>
 #include <linux/acpi_pmtmr.h>
@@ -34,6 +35,8 @@
 #include <linux/smp.h>
 #include <linux/mm.h>
 
+#include <asm/perf_event.h>
+#include <asm/x86_init.h>
 #include <asm/pgalloc.h>
 #include <asm/atomic.h>
 #include <asm/mpspec.h>
@@ -47,6 +50,8 @@
 #include <asm/mtrr.h>
 #include <asm/smp.h>
 #include <asm/mce.h>
+#include <asm/kvm_para.h>
+#include <asm/tsc.h>
 
 unsigned int num_processors;
 
@@ -57,12 +62,6 @@ unsigned int boot_cpu_physical_apicid = -1U;
 
 /*
  * The highest APIC ID seen during enumeration.
- *
- * This determines the messaging protocol we can use: if all APIC IDs
- * are in the 0 ... 7 range, then we can use logical addressing which
- * has some performance advantages (better broadcasting).
- *
- * If there's an APIC ID above 8, we use physical addressing.
  */
 unsigned int max_physical_apicid;
 
@@ -138,7 +137,6 @@ int x2apic_mode;
 #ifdef CONFIG_X86_X2APIC
 /* x2apic enabled before OS handover */
 static int x2apic_preenabled;
-static int disable_x2apic;
 static __init int setup_nox2apic(char *str)
 {
        if (x2apic_enabled()) {
@@ -147,7 +145,6 @@ static __init int setup_nox2apic(char *str)
                return 0;
        }
 
-       disable_x2apic = 1;
        setup_clear_cpu_cap(X86_FEATURE_X2APIC);
        return 0;
 }
@@ -239,28 +236,13 @@ static int modern_apic(void)
 }
 
 /*
- * bare function to substitute write operation
- * and it's _that_ fast :)
- */
-static void native_apic_write_dummy(u32 reg, u32 v)
-{
-       WARN_ON_ONCE((cpu_has_apic || !disable_apic));
-}
-
-static u32 native_apic_read_dummy(u32 reg)
-{
-       WARN_ON_ONCE((cpu_has_apic && !disable_apic));
-       return 0;
-}
-
-/*
- * right after this call apic->write/read doesn't do anything
- * note that there is no restore operation it works one way
+ * right after this call apic become NOOP driven
+ * so apic->write/read doesn't do anything
  */
 void apic_disable(void)
 {
-       apic->read = native_apic_read_dummy;
-       apic->write = native_apic_write_dummy;
+       pr_info("APIC: switched to apic NOOP\n");
+       apic = &apic_noop;
 }
 
 void native_apic_wait_icr_idle(void)
@@ -457,7 +439,7 @@ static void lapic_timer_setup(enum clock_event_mode mode,
                v = apic_read(APIC_LVTT);
                v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
                apic_write(APIC_LVTT, v);
-               apic_write(APIC_TMICT, 0xffffffff);
+               apic_write(APIC_TMICT, 0);
                break;
        case CLOCK_EVT_MODE_RESUME:
                /* Nothing to do here */
@@ -600,7 +582,7 @@ calibrate_by_pmtimer(long deltapm, long *delta, long *deltatsc)
                res = (((u64)(*deltatsc)) * pm_100ms);
                do_div(res, deltapm);
                apic_printk(APIC_VERBOSE, "TSC delta adjusted to "
-                                         "PM-Timer: %lu (%ld) \n",
+                                         "PM-Timer: %lu (%ld)\n",
                                        (unsigned long)res, *deltatsc);
                *deltatsc = (long)res;
        }
@@ -660,7 +642,7 @@ static int __init calibrate_APIC_clock(void)
        calibration_result = (delta * APIC_DIVISOR) / LAPIC_CAL_LOOPS;
 
        apic_printk(APIC_VERBOSE, "..... delta %ld\n", delta);
-       apic_printk(APIC_VERBOSE, "..... mult: %ld\n", lapic_clockevent.mult);
+       apic_printk(APIC_VERBOSE, "..... mult: %u\n", lapic_clockevent.mult);
        apic_printk(APIC_VERBOSE, "..... calibration result: %u\n",
                    calibration_result);
 
@@ -897,7 +879,7 @@ void clear_local_APIC(void)
        }
 
        /* lets not touch this if we didn't frob it */
-#if defined(CONFIG_X86_MCE_P4THERMAL) || defined(CONFIG_X86_MCE_INTEL)
+#ifdef CONFIG_X86_THERMAL_VECTOR
        if (maxlvt >= 5) {
                v = apic_read(APIC_LVTTHMR);
                apic_write(APIC_LVTTHMR, v | APIC_LVT_MASKED);
@@ -977,7 +959,7 @@ void lapic_shutdown(void)
 {
        unsigned long flags;
 
-       if (!cpu_has_apic)
+       if (!cpu_has_apic && !apic_from_smp_config())
                return;
 
        local_irq_save(flags);
@@ -1170,8 +1152,13 @@ static void __cpuinit lapic_setup_esr(void)
  */
 void __cpuinit setup_local_APIC(void)
 {
-       unsigned int value;
-       int i, j;
+       unsigned int value, queued;
+       int i, j, acked = 0;
+       unsigned long long tsc = 0, ntsc;
+       long long max_loops = cpu_khz;
+
+       if (cpu_has_tsc)
+               rdtscll(tsc);
 
        if (disable_apic) {
                arch_disable_smp_support();
@@ -1187,6 +1174,7 @@ void __cpuinit setup_local_APIC(void)
                apic_write(APIC_ESR, 0);
        }
 #endif
+       perf_events_lapic_init();
 
        preempt_disable();
 
@@ -1194,8 +1182,7 @@ void __cpuinit setup_local_APIC(void)
         * Double-check whether this APIC is really registered.
         * This is meaningless in clustered apic mode, so we skip it.
         */
-       if (!apic->apic_id_registered())
-               BUG();
+       BUG_ON(!apic->apic_id_registered());
 
        /*
         * Intel recommends to set DFR, LDR and TPR before enabling
@@ -1223,13 +1210,32 @@ void __cpuinit setup_local_APIC(void)
         * the interrupt. Hence a vector might get locked. It was noticed
         * for timer irq (vector 0x31). Issue an extra EOI to clear ISR.
         */
-       for (i = APIC_ISR_NR - 1; i >= 0; i--) {
-               value = apic_read(APIC_ISR + i*0x10);
-               for (j = 31; j >= 0; j--) {
-                       if (value & (1<<j))
-                               ack_APIC_irq();
+       do {
+               queued = 0;
+               for (i = APIC_ISR_NR - 1; i >= 0; i--)
+                       queued |= apic_read(APIC_IRR + i*0x10);
+
+               for (i = APIC_ISR_NR - 1; i >= 0; i--) {
+                       value = apic_read(APIC_ISR + i*0x10);
+                       for (j = 31; j >= 0; j--) {
+                               if (value & (1<<j)) {
+                                       ack_APIC_irq();
+                                       acked++;
+                               }
+                       }
                }
-       }
+               if (acked > 256) {
+                       printk(KERN_ERR "LAPIC pending interrupts after %d EOI\n",
+                              acked);
+                       break;
+               }
+               if (cpu_has_tsc) {
+                       rdtscll(ntsc);
+                       max_loops = (cpu_khz << 10) - (ntsc - tsc);
+               } else
+                       max_loops--;
+       } while (queued && max_loops > 0);
+       WARN_ON(max_loops <= 0);
 
        /*
         * Now that we are all set up, enable the APIC
@@ -1354,58 +1360,83 @@ void enable_x2apic(void)
 
        rdmsr(MSR_IA32_APICBASE, msr, msr2);
        if (!(msr & X2APIC_ENABLE)) {
-               pr_info("Enabling x2apic\n");
+               printk_once(KERN_INFO "Enabling x2apic\n");
                wrmsr(MSR_IA32_APICBASE, msr | X2APIC_ENABLE, 0);
        }
 }
 #endif /* CONFIG_X86_X2APIC */
 
-void __init enable_IR_x2apic(void)
+int __init enable_IR(void)
 {
 #ifdef CONFIG_INTR_REMAP
-       int ret;
-       unsigned long flags;
-       struct IO_APIC_route_entry **ioapic_entries = NULL;
-
-       ret = dmar_table_init();
-       if (ret) {
-               pr_debug("dmar_table_init() failed with %d:\n", ret);
-               goto ir_failed;
-       }
-
        if (!intr_remapping_supported()) {
                pr_debug("intr-remapping not supported\n");
-               goto ir_failed;
+               return 0;
        }
 
-
        if (!x2apic_preenabled && skip_ioapic_setup) {
                pr_info("Skipped enabling intr-remap because of skipping "
                        "io-apic setup\n");
-               return;
+               return 0;
        }
 
+       if (enable_intr_remapping(x2apic_supported()))
+               return 0;
+
+       pr_info("Enabled Interrupt-remapping\n");
+
+       return 1;
+
+#endif
+       return 0;
+}
+
+void __init enable_IR_x2apic(void)
+{
+       unsigned long flags;
+       struct IO_APIC_route_entry **ioapic_entries = NULL;
+       int ret, x2apic_enabled = 0;
+       int dmar_table_init_ret;
+
+       dmar_table_init_ret = dmar_table_init();
+       if (dmar_table_init_ret && !x2apic_supported())
+               return;
+
        ioapic_entries = alloc_ioapic_entries();
        if (!ioapic_entries) {
-               pr_info("Allocate ioapic_entries failed: %d\n", ret);
-               goto end;
+               pr_err("Allocate ioapic_entries failed\n");
+               goto out;
        }
 
        ret = save_IO_APIC_setup(ioapic_entries);
        if (ret) {
                pr_info("Saving IO-APIC state failed: %d\n", ret);
-               goto end;
+               goto out;
        }
 
        local_irq_save(flags);
+       legacy_pic->mask_all();
        mask_IO_APIC_setup(ioapic_entries);
-       mask_8259A();
 
-       ret = enable_intr_remapping(x2apic_supported());
-       if (ret)
-               goto end_restore;
+       if (dmar_table_init_ret)
+               ret = 0;
+       else
+               ret = enable_IR();
 
-       pr_info("Enabled Interrupt-remapping\n");
+       if (!ret) {
+               /* IR is required if there is APIC ID > 255 even when running
+                * under KVM
+                */
+               if (max_physical_apicid > 255 || !kvm_para_available())
+                       goto nox2apic;
+               /*
+                * without IR all CPUs can be addressed by IOAPIC/MSI
+                * only in physical mode
+                */
+               x2apic_force_phys();
+       }
+
+       x2apic_enabled = 1;
 
        if (x2apic_supported() && !x2apic_mode) {
                x2apic_mode = 1;
@@ -1413,41 +1444,25 @@ void __init enable_IR_x2apic(void)
                pr_info("Enabled x2apic\n");
        }
 
-end_restore:
-       if (ret)
-               /*
-                * IR enabling failed
-                */
+nox2apic:
+       if (!ret) /* IR enabling failed */
                restore_IO_APIC_setup(ioapic_entries);
-
-       unmask_8259A();
+       legacy_pic->restore_mask();
        local_irq_restore(flags);
 
-end:
+out:
        if (ioapic_entries)
                free_ioapic_entries(ioapic_entries);
 
-       if (!ret)
+       if (x2apic_enabled)
                return;
 
-ir_failed:
        if (x2apic_preenabled)
-               panic("x2apic enabled by bios. But IR enabling failed");
+               panic("x2apic: enabled by BIOS but kernel init failed.");
        else if (cpu_has_x2apic)
-               pr_info("Not enabling x2apic,Intr-remapping\n");
-#else
-       if (!cpu_has_x2apic)
-               return;
-
-       if (x2apic_preenabled)
-               panic("x2apic enabled prior OS handover,"
-                     " enable CONFIG_X86_X2APIC, CONFIG_INTR_REMAP");
-#endif
-
-       return;
+               pr_info("Not enabling x2apic, Intr-remapping init failed.\n");
 }
 
-
 #ifdef CONFIG_X86_64
 /*
  * Detect and enable local APICs on non-SMP boards.
@@ -1548,8 +1563,6 @@ no_apic:
 #ifdef CONFIG_X86_64
 void __init early_init_lapic_mapping(void)
 {
-       unsigned long phys_addr;
-
        /*
         * If no local APIC can be found then go out
         * : it means there is no mpatable and MADT
@@ -1557,11 +1570,9 @@ void __init early_init_lapic_mapping(void)
        if (!smp_found_config)
                return;
 
-       phys_addr = mp_lapic_addr;
-
-       set_fixmap_nocache(FIX_APIC_BASE, phys_addr);
+       set_fixmap_nocache(FIX_APIC_BASE, mp_lapic_addr);
        apic_printk(APIC_VERBOSE, "mapped APIC to %16lx (%16lx)\n",
-                   APIC_BASE, phys_addr);
+                   APIC_BASE, mp_lapic_addr);
 
        /*
         * Fetch the APIC ID of the BSP in case we have a
@@ -1650,13 +1661,12 @@ int __init APIC_init_uniprocessor(void)
            APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) {
                pr_err("BIOS bug, local APIC 0x%x not detected!...\n",
                        boot_cpu_physical_apicid);
-               clear_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC);
                return -1;
        }
 #endif
 
+#ifndef CONFIG_SMP
        enable_IR_x2apic();
-#ifdef CONFIG_X86_64
        default_setup_apic_routing();
 #endif
 
@@ -1700,7 +1710,7 @@ int __init APIC_init_uniprocessor(void)
        localise_nmi_watchdog();
 #endif
 
-       setup_boot_clock();
+       x86_init.timers.setup_percpu_clockev();
 #ifdef CONFIG_X86_64
        check_nmi_watchdog();
 #endif
@@ -1906,28 +1916,6 @@ void __cpuinit generic_processor_info(int apicid, int version)
        if (apicid > max_physical_apicid)
                max_physical_apicid = apicid;
 
-#ifdef CONFIG_X86_32
-       /*
-        * Would be preferable to switch to bigsmp when CONFIG_HOTPLUG_CPU=y
-        * but we need to work other dependencies like SMP_SUSPEND etc
-        * before this can be done without some confusion.
-        * if (CPU_HOTPLUG_ENABLED || num_processors > 8)
-        *       - Ashok Raj <ashok.raj@intel.com>
-        */
-       if (max_physical_apicid >= 8) {
-               switch (boot_cpu_data.x86_vendor) {
-               case X86_VENDOR_INTEL:
-                       if (!APIC_XAPIC(version)) {
-                               def_to_bigsmp = 0;
-                               break;
-                       }
-                       /* If P4 and above fall through */
-               case X86_VENDOR_AMD:
-                       def_to_bigsmp = 1;
-               }
-       }
-#endif
-
 #if defined(CONFIG_SMP) || defined(CONFIG_X86_64)
        early_per_cpu(x86_cpu_to_apicid, cpu) = apicid;
        early_per_cpu(x86_bios_cpu_apicid, cpu) = apicid;
@@ -2014,7 +2002,7 @@ static int lapic_suspend(struct sys_device *dev, pm_message_t state)
        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);
-#if defined(CONFIG_X86_MCE_P4THERMAL) || defined(CONFIG_X86_MCE_INTEL)
+#ifdef CONFIG_X86_THERMAL_VECTOR
        if (maxlvt >= 5)
                apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR);
 #endif
@@ -2057,7 +2045,7 @@ static int lapic_resume(struct sys_device *dev)
                }
 
                mask_IO_APIC_setup(ioapic_entries);
-               mask_8259A();
+               legacy_pic->mask_all();
        }
 
        if (x2apic_mode)
@@ -2101,7 +2089,7 @@ static int lapic_resume(struct sys_device *dev)
 
        if (intr_remapping_enabled) {
                reenable_intr_remapping(x2apic_mode);
-               unmask_8259A();
+               legacy_pic->restore_mask();
                restore_IO_APIC_setup(ioapic_entries);
                free_ioapic_entries(ioapic_entries);
        }