Merge branch 'syscore' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspen...
[pandora-kernel.git] / arch / x86 / kernel / apic / apic.c
index 76b96d7..fabf01e 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/ftrace.h>
 #include <linux/ioport.h>
 #include <linux/module.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/delay.h>
 #include <linux/timex.h>
 #include <linux/dmar.h>
@@ -43,6 +43,7 @@
 #include <asm/i8259.h>
 #include <asm/proto.h>
 #include <asm/apic.h>
+#include <asm/io_apic.h>
 #include <asm/desc.h>
 #include <asm/hpet.h>
 #include <asm/idle.h>
@@ -78,12 +79,21 @@ EXPORT_EARLY_PER_CPU_SYMBOL(x86_cpu_to_apicid);
 EXPORT_EARLY_PER_CPU_SYMBOL(x86_bios_cpu_apicid);
 
 #ifdef CONFIG_X86_32
+
+/*
+ * On x86_32, the mapping between cpu and logical apicid may vary
+ * depending on apic in use.  The following early percpu variable is
+ * used for the mapping.  This is where the behaviors of x86_64 and 32
+ * actually diverge.  Let's keep it ugly for now.
+ */
+DEFINE_EARLY_PER_CPU(int, x86_cpu_to_logical_apicid, BAD_APICID);
+
 /*
  * Knob to control our willingness to enable the local APIC.
  *
  * +1=force-enable
  */
-static int force_enable_local_apic;
+static int force_enable_local_apic __initdata;
 /*
  * APIC command line parameters
  */
@@ -153,7 +163,7 @@ early_param("nox2apic", setup_nox2apic);
 unsigned long mp_lapic_addr;
 int disable_apic;
 /* Disable local APIC timer from the kernel commandline or via dmi quirk */
-static int disable_apic_timer __cpuinitdata;
+static int disable_apic_timer __initdata;
 /* Local APIC timer works in C2 */
 int local_apic_timer_c2_ok;
 EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok);
@@ -177,29 +187,8 @@ static struct resource lapic_resource = {
 
 static unsigned int calibration_result;
 
-static int lapic_next_event(unsigned long delta,
-                           struct clock_event_device *evt);
-static void lapic_timer_setup(enum clock_event_mode mode,
-                             struct clock_event_device *evt);
-static void lapic_timer_broadcast(const struct cpumask *mask);
 static void apic_pm_activate(void);
 
-/*
- * The local apic timer can be used for any function which is CPU local.
- */
-static struct clock_event_device lapic_clockevent = {
-       .name           = "lapic",
-       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT
-                       | CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_DUMMY,
-       .shift          = 32,
-       .set_mode       = lapic_timer_setup,
-       .set_next_event = lapic_next_event,
-       .broadcast      = lapic_timer_broadcast,
-       .rating         = 100,
-       .irq            = -1,
-};
-static DEFINE_PER_CPU(struct clock_event_device, lapic_events);
-
 static unsigned long apic_phys;
 
 /*
@@ -238,7 +227,7 @@ static int modern_apic(void)
  * right after this call apic become NOOP driven
  * so apic->write/read doesn't do anything
  */
-void apic_disable(void)
+static void __init apic_disable(void)
 {
        pr_info("APIC: switched to apic NOOP\n");
        apic = &apic_noop;
@@ -282,23 +271,6 @@ u64 native_apic_icr_read(void)
        return icr1 | ((u64)icr2 << 32);
 }
 
-/**
- * enable_NMI_through_LVT0 - enable NMI through local vector table 0
- */
-void __cpuinit enable_NMI_through_LVT0(void)
-{
-       unsigned int v;
-
-       /* unmask and set to NMI */
-       v = APIC_DM_NMI;
-
-       /* Level triggered for 82489DX (32bit mode) */
-       if (!lapic_is_integrated())
-               v |= APIC_LVT_LEVEL_TRIGGER;
-
-       apic_write(APIC_LVT0, v);
-}
-
 #ifdef CONFIG_X86_32
 /**
  * get_physical_broadcast - Get number of physical broadcast IDs
@@ -508,6 +480,23 @@ static void lapic_timer_broadcast(const struct cpumask *mask)
 #endif
 }
 
+
+/*
+ * The local apic timer can be used for any function which is CPU local.
+ */
+static struct clock_event_device lapic_clockevent = {
+       .name           = "lapic",
+       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT
+                       | CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_DUMMY,
+       .shift          = 32,
+       .set_mode       = lapic_timer_setup,
+       .set_next_event = lapic_next_event,
+       .broadcast      = lapic_timer_broadcast,
+       .rating         = 100,
+       .irq            = -1,
+};
+static DEFINE_PER_CPU(struct clock_event_device, lapic_events);
+
 /*
  * Setup the local APIC timer for this CPU. Copy the initialized values
  * of the boot CPU and register the clock event in the framework.
@@ -1209,7 +1198,7 @@ void __cpuinit setup_local_APIC(void)
                rdtscll(tsc);
 
        if (disable_apic) {
-               arch_disable_smp_support();
+               disable_ioapic_support();
                return;
        }
 
@@ -1237,6 +1226,19 @@ void __cpuinit setup_local_APIC(void)
         */
        apic->init_apic_ldr();
 
+#ifdef CONFIG_X86_32
+       /*
+        * APIC LDR is initialized.  If logical_apicid mapping was
+        * initialized during get_smp_config(), make sure it matches the
+        * actual value.
+        */
+       i = early_per_cpu(x86_cpu_to_logical_apicid, cpu);
+       WARN_ON(i != BAD_APICID && i != logical_smp_processor_id());
+       /* always use the value from LDR */
+       early_per_cpu(x86_cpu_to_logical_apicid, cpu) =
+               logical_smp_processor_id();
+#endif
+
        /*
         * Set Task Priority to 'accept all'. We never change this
         * later on.
@@ -1448,7 +1450,7 @@ int __init enable_IR(void)
 void __init enable_IR_x2apic(void)
 {
        unsigned long flags;
-       struct IO_APIC_route_entry **ioapic_entries = NULL;
+       struct IO_APIC_route_entry **ioapic_entries;
        int ret, x2apic_enabled = 0;
        int dmar_table_init_ret;
 
@@ -1537,7 +1539,7 @@ static int __init detect_init_APIC(void)
 }
 #else
 
-static int apic_verify(void)
+static int __init apic_verify(void)
 {
        u32 features, h, l;
 
@@ -1562,7 +1564,7 @@ static int apic_verify(void)
        return 0;
 }
 
-int apic_force_enable(void)
+int __init apic_force_enable(unsigned long addr)
 {
        u32 h, l;
 
@@ -1578,7 +1580,7 @@ int apic_force_enable(void)
        if (!(l & MSR_IA32_APICBASE_ENABLE)) {
                pr_info("Local APIC disabled by BIOS -- reenabling.\n");
                l &= ~MSR_IA32_APICBASE_BASE;
-               l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;
+               l |= MSR_IA32_APICBASE_ENABLE | addr;
                wrmsr(MSR_IA32_APICBASE, l, h);
                enabled_via_apicbase = 1;
        }
@@ -1619,7 +1621,7 @@ static int __init detect_init_APIC(void)
                                "you can enable it with \"lapic\"\n");
                        return -1;
                }
-               if (apic_force_enable())
+               if (apic_force_enable(APIC_DEFAULT_PHYS_BASE))
                        return -1;
        } else {
                if (apic_verify())
@@ -1930,17 +1932,6 @@ void __cpuinit generic_processor_info(int apicid, int version)
 {
        int cpu;
 
-       /*
-        * Validate version
-        */
-       if (version == 0x0) {
-               pr_warning("BIOS bug, APIC version is 0 for CPU#%d! "
-                          "fixing up to 0x10. (tell your hw vendor)\n",
-                               version);
-               version = 0x10;
-       }
-       apic_version[apicid] = version;
-
        if (num_processors >= nr_cpu_ids) {
                int max = nr_cpu_ids;
                int thiscpu = max + disabled_cpus;
@@ -1954,22 +1945,34 @@ void __cpuinit generic_processor_info(int apicid, int version)
        }
 
        num_processors++;
-       cpu = cpumask_next_zero(-1, cpu_present_mask);
-
-       if (version != apic_version[boot_cpu_physical_apicid])
-               WARN_ONCE(1,
-                       "ACPI: apic version mismatch, bootcpu: %x cpu %d: %x\n",
-                       apic_version[boot_cpu_physical_apicid], cpu, version);
-
-       physid_set(apicid, phys_cpu_present_map);
        if (apicid == boot_cpu_physical_apicid) {
                /*
                 * x86_bios_cpu_apicid is required to have processors listed
                 * in same order as logical cpu numbers. Hence the first
                 * entry is BSP, and so on.
+                * boot_cpu_init() already hold bit 0 in cpu_present_mask
+                * for BSP.
                 */
                cpu = 0;
+       } else
+               cpu = cpumask_next_zero(-1, cpu_present_mask);
+
+       /*
+        * Validate version
+        */
+       if (version == 0x0) {
+               pr_warning("BIOS bug: APIC version is 0 for CPU %d/0x%x, fixing up to 0x10\n",
+                          cpu, apicid);
+               version = 0x10;
+       }
+       apic_version[apicid] = version;
+
+       if (version != apic_version[boot_cpu_physical_apicid]) {
+               pr_warning("BIOS bug: APIC version mismatch, boot CPU: %x, CPU %d: version %x\n",
+                       apic_version[boot_cpu_physical_apicid], cpu, version);
        }
+
+       physid_set(apicid, phys_cpu_present_map);
        if (apicid > max_physical_apicid)
                max_physical_apicid = apicid;
 
@@ -1977,7 +1980,10 @@ void __cpuinit generic_processor_info(int apicid, int version)
        early_per_cpu(x86_cpu_to_apicid, cpu) = apicid;
        early_per_cpu(x86_bios_cpu_apicid, cpu) = apicid;
 #endif
-
+#ifdef CONFIG_X86_32
+       early_per_cpu(x86_cpu_to_logical_apicid, cpu) =
+               apic->x86_32_early_logical_apicid(cpu);
+#endif
        set_cpu_possible(cpu, true);
        set_cpu_present(cpu, true);
 }
@@ -1998,10 +2004,14 @@ void default_init_apic_ldr(void)
 }
 
 #ifdef CONFIG_X86_32
-int default_apicid_to_node(int logical_apicid)
+int default_x86_32_numa_cpu_node(int cpu)
 {
-#ifdef CONFIG_SMP
-       return apicid_2_node[hard_smp_processor_id()];
+#ifdef CONFIG_NUMA
+       int apicid = early_per_cpu(x86_cpu_to_apicid, cpu);
+
+       if (apicid != BAD_APICID)
+               return __apicid_to_node[apicid];
+       return NUMA_NO_NODE;
 #else
        return 0;
 #endif
@@ -2036,7 +2046,7 @@ static struct {
        unsigned int apic_thmr;
 } apic_pm_state;
 
-static int lapic_suspend(struct sys_device *dev, pm_message_t state)
+static int lapic_suspend(void)
 {
        unsigned long flags;
        int maxlvt;
@@ -2074,23 +2084,21 @@ static int lapic_suspend(struct sys_device *dev, pm_message_t state)
        return 0;
 }
 
-static int lapic_resume(struct sys_device *dev)
+static void lapic_resume(void)
 {
        unsigned int l, h;
        unsigned long flags;
-       int maxlvt;
-       int ret = 0;
+       int maxlvt, ret;
        struct IO_APIC_route_entry **ioapic_entries = NULL;
 
        if (!apic_pm_state.active)
-               return 0;
+               return;
 
        local_irq_save(flags);
        if (intr_remapping_enabled) {
                ioapic_entries = alloc_ioapic_entries();
                if (!ioapic_entries) {
                        WARN(1, "Alloc ioapic_entries in lapic resume failed.");
-                       ret = -ENOMEM;
                        goto restore;
                }
 
@@ -2152,8 +2160,6 @@ static int lapic_resume(struct sys_device *dev)
        }
 restore:
        local_irq_restore(flags);
-
-       return ret;
 }
 
 /*
@@ -2161,17 +2167,11 @@ restore:
  * are needed on every CPU up until machine_halt/restart/poweroff.
  */
 
-static struct sysdev_class lapic_sysclass = {
-       .name           = "lapic",
+static struct syscore_ops lapic_syscore_ops = {
        .resume         = lapic_resume,
        .suspend        = lapic_suspend,
 };
 
-static struct sys_device device_lapic = {
-       .id     = 0,
-       .cls    = &lapic_sysclass,
-};
-
 static void __cpuinit apic_pm_activate(void)
 {
        apic_pm_state.active = 1;
@@ -2179,16 +2179,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? */
+       if (cpu_has_apic)
+               register_syscore_ops(&lapic_syscore_ops);
 
-       error = sysdev_class_register(&lapic_sysclass);
-       if (!error)
-               error = sysdev_register(&device_lapic);
-       return error;
+       return 0;
 }
 
 /* local apic needs to resume before other devices access its registers. */