Merge branch 'drm-patches' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
[pandora-kernel.git] / arch / x86_64 / kernel / smpboot.c
index b7c7059..daf1933 100644 (file)
 #include <linux/bootmem.h>
 #include <linux/thread_info.h>
 #include <linux/module.h>
-
 #include <linux/delay.h>
 #include <linux/mc146818rtc.h>
+#include <linux/smp.h>
+
 #include <asm/mtrr.h>
 #include <asm/pgalloc.h>
 #include <asm/desc.h>
@@ -59,6 +60,7 @@
 #include <asm/irq.h>
 #include <asm/hw_irq.h>
 #include <asm/numa.h>
+#include <asm/genapic.h>
 
 /* Number of siblings per CPU package */
 int smp_num_siblings = 1;
@@ -580,12 +582,16 @@ void __cpuinit start_secondary(void)
         * smp_call_function().
         */
        lock_ipi_call_lock();
+       spin_lock(&vector_lock);
 
+       /* Setup the per cpu irq handling data structures */
+       __setup_vector_irq(smp_processor_id());
        /*
         * Allow the master to continue.
         */
        cpu_set(smp_processor_id(), cpu_online_map);
        per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
+       spin_unlock(&vector_lock);
        unlock_ipi_call_lock();
 
        cpu_idle();
@@ -748,14 +754,16 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta
 }
 
 struct create_idle {
+       struct work_struct work;
        struct task_struct *idle;
        struct completion done;
        int cpu;
 };
 
-void do_fork_idle(void *_c_idle)
+void do_fork_idle(struct work_struct *work)
 {
-       struct create_idle *c_idle = _c_idle;
+       struct create_idle *c_idle =
+               container_of(work, struct create_idle, work);
 
        c_idle->idle = fork_idle(c_idle->cpu);
        complete(&c_idle->done);
@@ -770,12 +778,10 @@ static int __cpuinit do_boot_cpu(int cpu, int apicid)
        int timeout;
        unsigned long start_rip;
        struct create_idle c_idle = {
+               .work = __WORK_INITIALIZER(c_idle.work, do_fork_idle),
                .cpu = cpu,
-               .done = COMPLETION_INITIALIZER(c_idle.done),
+               .done = COMPLETION_INITIALIZER_ONSTACK(c_idle.done),
        };
-       DECLARE_WORK(work, do_fork_idle, &c_idle);
-
-       lockdep_set_class(&c_idle.done.wait.lock, &waitqueue_lock_key);
 
        /* allocate memory for gdts of secondary cpus. Hotplug is considered */
        if (!cpu_gdt_descr[cpu].address &&
@@ -800,7 +806,6 @@ static int __cpuinit do_boot_cpu(int cpu, int apicid)
                                cpu, node);
        }
 
-
        alternatives_smp_switch(1);
 
        c_idle.idle = get_idle_for_cpu(cpu);
@@ -823,9 +828,9 @@ static int __cpuinit do_boot_cpu(int cpu, int apicid)
         * thread.
         */
        if (!keventd_up() || current_is_keventd())
-               work.func(work.data);
+               c_idle.work.func(&c_idle.work);
        else {
-               schedule_work(&work);
+               schedule_work(&c_idle.work);
                wait_for_completion(&c_idle.done);
        }
 
@@ -1092,7 +1097,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
        /*
         * Switch from PIC to APIC mode.
         */
-       connect_bsp_APIC();
        setup_local_APIC();
 
        if (GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_id) {
@@ -1166,6 +1170,13 @@ int __cpuinit __cpu_up(unsigned int cpu)
 
        while (!cpu_isset(cpu, cpu_online_map))
                cpu_relax();
+
+       if (num_online_cpus() > 8 && genapic == &apic_flat) {
+               printk(KERN_WARNING
+                      "flat APIC routing can't be used with > 8 cpus\n");
+               BUG();
+       }
+
        err = 0;
 
        return err;
@@ -1177,12 +1188,9 @@ int __cpuinit __cpu_up(unsigned int cpu)
 void __init smp_cpus_done(unsigned int max_cpus)
 {
        smp_cleanup_boot();
-
-#ifdef CONFIG_X86_IO_APIC
        setup_ioapic_dest();
-#endif
-
        check_nmi_watchdog();
+       time_init_gtod();
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
@@ -1235,6 +1243,8 @@ int __cpu_disable(void)
        if (cpu == 0)
                return -EBUSY;
 
+       if (nmi_watchdog == NMI_LOCAL_APIC)
+               stop_apic_nmi_watchdog(NULL);
        clear_local_APIC();
 
        /*
@@ -1249,8 +1259,10 @@ int __cpu_disable(void)
        local_irq_disable();
        remove_siblinginfo(cpu);
 
+       spin_lock(&vector_lock);
        /* It's now safe to remove this processor from the online map */
        cpu_clear(cpu, cpu_online_map);
+       spin_unlock(&vector_lock);
        remove_cpu_from_maps();
        fixup_irqs(cpu_online_map);
        return 0;
@@ -1274,11 +1286,11 @@ void __cpu_die(unsigned int cpu)
        printk(KERN_ERR "CPU %u didn't die...\n", cpu);
 }
 
-__init int setup_additional_cpus(char *s)
+static __init int setup_additional_cpus(char *s)
 {
-       return get_option(&s, &additional_cpus);
+       return s && get_option(&s, &additional_cpus) ? 0 : -EINVAL;
 }
-__setup("additional_cpus=", setup_additional_cpus);
+early_param("additional_cpus", setup_additional_cpus);
 
 #else /* ... !CONFIG_HOTPLUG_CPU */