Merge branch 'core/xen' into x86/xen
[safe/jmp/linux-2.6] / arch / ia64 / kernel / smpboot.c
index e196097..bcea81e 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/mm.h>
 #include <linux/notifier.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/efi.h>
 #include <linux/percpu.h>
@@ -51,6 +50,7 @@
 #include <asm/machvec.h>
 #include <asm/mca.h>
 #include <asm/page.h>
+#include <asm/paravirt.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 #include <asm/processor.h>
@@ -59,6 +59,7 @@
 #include <asm/system.h>
 #include <asm/tlbflush.h>
 #include <asm/unistd.h>
+#include <asm/sn/arch.h>
 
 #define SMP_DEBUG 0
 
@@ -120,11 +121,10 @@ static volatile unsigned long go[SLAVE + 1];
 
 #define DEBUG_ITC_SYNC 0
 
-extern void __devinit calibrate_delay (void);
 extern void start_ap (void);
 extern unsigned long ia64_iobase;
 
-task_t *task_for_booting_cpu;
+struct task_struct *task_for_booting_cpu;
 
 /*
  * State for each CPU
@@ -138,9 +138,11 @@ cpumask_t cpu_possible_map = CPU_MASK_NONE;
 EXPORT_SYMBOL(cpu_possible_map);
 
 cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned;
-cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned;
+EXPORT_SYMBOL(cpu_core_map);
+DEFINE_PER_CPU_SHARED_ALIGNED(cpumask_t, cpu_sibling_map);
+EXPORT_PER_CPU_SYMBOL(cpu_sibling_map);
+
 int smp_num_siblings = 1;
-int smp_num_cpucores = 1;
 
 /* which logical CPU number maps to which CPU (physical APIC ID) */
 volatile int ia64_cpu_to_sapicid[NR_CPUS];
@@ -317,7 +319,7 @@ ia64_sync_itc (unsigned int master)
 
        go[MASTER] = 1;
 
-       if (smp_call_function_single(master, sync_master, NULL, 1, 0) < 0) {
+       if (smp_call_function_single(master, sync_master, NULL, 0) < 0) {
                printk(KERN_ERR "sync_itc: failed to get attention of CPU %u!\n", master);
                return;
        }
@@ -371,10 +373,11 @@ smp_setup_percpu_timer (void)
 {
 }
 
-static void __devinit
+static void __cpuinit
 smp_callin (void)
 {
        int cpuid, phys_id, itc_master;
+       struct cpuinfo_ia64 *last_cpuinfo, *this_cpuinfo;
        extern void ia64_init_itm(void);
        extern volatile int time_keeper_id;
 
@@ -394,10 +397,14 @@ smp_callin (void)
 
        fix_b0_for_bsp();
 
-       lock_ipi_calllock();
+       ipi_call_lock_irq();
+       spin_lock(&vector_lock);
+       /* Setup the per cpu irq handling data structures */
+       __setup_vector_irq(cpuid);
        cpu_set(cpuid, cpu_online_map);
-       unlock_ipi_calllock();
        per_cpu(cpu_state, cpuid) = CPU_ONLINE;
+       spin_unlock(&vector_lock);
+       ipi_call_unlock_irq();
 
        smp_setup_percpu_timer();
 
@@ -424,7 +431,21 @@ smp_callin (void)
         * Get our bogomips.
         */
        ia64_init_itm();
-       calibrate_delay();
+
+       /*
+        * Delay calibration can be skipped if new processor is identical to the
+        * previous processor.
+        */
+       last_cpuinfo = cpu_data(cpuid - 1);
+       this_cpuinfo = local_cpu_data;
+       if (last_cpuinfo->itc_freq != this_cpuinfo->itc_freq ||
+           last_cpuinfo->proc_freq != this_cpuinfo->proc_freq ||
+           last_cpuinfo->features != this_cpuinfo->features ||
+           last_cpuinfo->revision != this_cpuinfo->revision ||
+           last_cpuinfo->family != this_cpuinfo->family ||
+           last_cpuinfo->archrev != this_cpuinfo->archrev ||
+           last_cpuinfo->model != this_cpuinfo->model)
+               calibrate_delay();
        local_cpu_data->loops_per_jiffy = loops_per_jiffy;
 
 #ifdef CONFIG_IA32_SUPPORT
@@ -442,12 +463,14 @@ smp_callin (void)
 /*
  * Activate a secondary processor.  head.S calls this.
  */
-int __devinit
+int __cpuinit
 start_secondary (void *unused)
 {
        /* Early console may use I/O ports */
        ia64_set_kr(IA64_KR_IO_BASE, __pa(ia64_iobase));
+#ifndef CONFIG_PRINTK_TIME
        Dprintk("start_secondary: starting CPU 0x%x\n", hard_smp_processor_id());
+#endif
        efi_map_pal_code();
        cpu_init();
        preempt_disable();
@@ -457,35 +480,37 @@ start_secondary (void *unused)
        return 0;
 }
 
-struct pt_regs * __devinit idle_regs(struct pt_regs *regs)
+struct pt_regs * __cpuinit idle_regs(struct pt_regs *regs)
 {
        return NULL;
 }
 
 struct create_idle {
+       struct work_struct work;
        struct task_struct *idle;
        struct completion done;
        int cpu;
 };
 
-void
-do_fork_idle(void *_c_idle)
+void __cpuinit
+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);
 }
 
-static int __devinit
+static int __cpuinit
 do_boot_cpu (int sapicid, int cpu)
 {
        int timeout;
        struct create_idle c_idle = {
+               .work = __WORK_INITIALIZER(c_idle.work, do_fork_idle),
                .cpu    = cpu,
                .done   = COMPLETION_INITIALIZER(c_idle.done),
        };
-       DECLARE_WORK(work, do_fork_idle, &c_idle);
 
        c_idle.idle = get_idle_for_cpu(cpu);
        if (c_idle.idle) {
@@ -497,9 +522,9 @@ do_boot_cpu (int sapicid, int cpu)
         * We can't use kernel_thread since we must avoid to reschedule the child.
         */
        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);
        }
 
@@ -621,6 +646,7 @@ void __devinit smp_prepare_boot_cpu(void)
        cpu_set(smp_processor_id(), cpu_online_map);
        cpu_set(smp_processor_id(), cpu_callin_map);
        per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
+       paravirt_post_smp_prepare_boot_cpu();
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
@@ -629,12 +655,12 @@ clear_cpu_sibling_map(int cpu)
 {
        int i;
 
-       for_each_cpu_mask(i, cpu_sibling_map[cpu])
-               cpu_clear(cpu, cpu_sibling_map[i]);
+       for_each_cpu_mask(i, per_cpu(cpu_sibling_map, cpu))
+               cpu_clear(cpu, per_cpu(cpu_sibling_map, i));
        for_each_cpu_mask(i, cpu_core_map[cpu])
                cpu_clear(cpu, cpu_core_map[i]);
 
-       cpu_sibling_map[cpu] = cpu_core_map[cpu] = CPU_MASK_NONE;
+       per_cpu(cpu_sibling_map, cpu) = cpu_core_map[cpu] = CPU_MASK_NONE;
 }
 
 static void
@@ -645,7 +671,7 @@ remove_siblinginfo(int cpu)
        if (cpu_data(cpu)->threads_per_core == 1 &&
            cpu_data(cpu)->cores_per_socket == 1) {
                cpu_clear(cpu, cpu_core_map[cpu]);
-               cpu_clear(cpu, cpu_sibling_map[cpu]);
+               cpu_clear(cpu, per_cpu(cpu_sibling_map, cpu));
                return;
        }
 
@@ -678,7 +704,7 @@ int migrate_platform_irqs(unsigned int cpu)
                        set_cpei_target_cpu(new_cpei_cpu);
                        desc = irq_desc + ia64_cpe_irq;
                        /*
-                        * Switch for now, immediatly, we need to do fake intr
+                        * Switch for now, immediately, we need to do fake intr
                         * as other interrupts, but need to study CPEI behaviour with
                         * polling before making changes.
                         */
@@ -710,6 +736,11 @@ int __cpu_disable(void)
                return (-EBUSY);
        }
 
+       if (ia64_platform_is("sn2")) {
+               if (!sn_cpu_disable_allowed(cpu))
+                       return -EBUSY;
+       }
+
        cpu_clear(cpu, cpu_online_map);
 
        if (migrate_platform_irqs(cpu)) {
@@ -740,17 +771,6 @@ void __cpu_die(unsigned int cpu)
        }
        printk(KERN_ERR "CPU %u didn't die...\n", cpu);
 }
-#else /* !CONFIG_HOTPLUG_CPU */
-int __cpu_disable(void)
-{
-       return -ENOSYS;
-}
-
-void __cpu_die(unsigned int cpu)
-{
-       /* We said "no" in __cpu_disable */
-       BUG();
-}
 #endif /* CONFIG_HOTPLUG_CPU */
 
 void
@@ -781,14 +801,14 @@ set_cpu_sibling_map(int cpu)
                        cpu_set(i, cpu_core_map[cpu]);
                        cpu_set(cpu, cpu_core_map[i]);
                        if (cpu_data(cpu)->core_id == cpu_data(i)->core_id) {
-                               cpu_set(i, cpu_sibling_map[cpu]);
-                               cpu_set(cpu, cpu_sibling_map[i]);
+                               cpu_set(i, per_cpu(cpu_sibling_map, cpu));
+                               cpu_set(cpu, per_cpu(cpu_sibling_map, i));
                        }
                }
        }
 }
 
-int __devinit
+int __cpuinit
 __cpu_up (unsigned int cpu)
 {
        int ret;
@@ -813,7 +833,7 @@ __cpu_up (unsigned int cpu)
 
        if (cpu_data(cpu)->threads_per_core == 1 &&
            cpu_data(cpu)->cores_per_socket == 1) {
-               cpu_set(cpu, cpu_sibling_map[cpu]);
+               cpu_set(cpu, per_cpu(cpu_sibling_map, cpu));
                cpu_set(cpu, cpu_core_map[cpu]);
                return 0;
        }
@@ -824,7 +844,7 @@ __cpu_up (unsigned int cpu)
 }
 
 /*
- * Assume that CPU's have been discovered by some platform-dependent interface.  For
+ * Assume that CPUs have been discovered by some platform-dependent interface.  For
  * SoftSDV/Lion, that would be ACPI.
  *
  * Setup of the IPI irq handler is done in irq.c:init_IRQ_SMP().
@@ -838,7 +858,7 @@ init_smp_config(void)
        } *ap_startup;
        long sal_ret;
 
-       /* Tell SAL where to drop the AP's.  */
+       /* Tell SAL where to drop the APs.  */
        ap_startup = (struct fptr *) start_ap;
        sal_ret = ia64_sal_set_vectors(SAL_VECTOR_OS_BOOT_RENDEZ,
                                       ia64_tpa(ap_startup->fp), ia64_tpa(ap_startup->gp), 0, 0, 0, 0);
@@ -858,20 +878,34 @@ identify_siblings(struct cpuinfo_ia64 *c)
        u16 pltid;
        pal_logical_to_physical_t info;
 
-       if (smp_num_cpucores == 1 && smp_num_siblings == 1)
-               return;
+       status = ia64_pal_logical_to_phys(-1, &info);
+       if (status != PAL_STATUS_SUCCESS) {
+               if (status != PAL_STATUS_UNIMPLEMENTED) {
+                       printk(KERN_ERR
+                               "ia64_pal_logical_to_phys failed with %ld\n",
+                               status);
+                       return;
+               }
 
-       if ((status = ia64_pal_logical_to_phys(-1, &info)) != PAL_STATUS_SUCCESS) {
-               printk(KERN_ERR "ia64_pal_logical_to_phys failed with %ld\n",
-                      status);
-               return;
+               info.overview_ppid = 0;
+               info.overview_cpp  = 1;
+               info.overview_tpc  = 1;
        }
-       if ((status = ia64_sal_physical_id_info(&pltid)) != PAL_STATUS_SUCCESS) {
-               printk(KERN_ERR "ia64_sal_pltid failed with %ld\n", status);
+
+       status = ia64_sal_physical_id_info(&pltid);
+       if (status != PAL_STATUS_SUCCESS) {
+               if (status != PAL_STATUS_UNIMPLEMENTED)
+                       printk(KERN_ERR
+                               "ia64_sal_pltid failed with %ld\n",
+                               status);
                return;
        }
 
        c->socket_id =  (pltid << 8) | info.overview_ppid;
+
+       if (info.overview_cpp == 1 && info.overview_tpc == 1)
+               return;
+
        c->cores_per_socket = info.overview_cpp;
        c->threads_per_core = info.overview_tpc;
        c->num_log = info.overview_num_log;
@@ -879,3 +913,27 @@ identify_siblings(struct cpuinfo_ia64 *c)
        c->core_id = info.log1_cid;
        c->thread_id = info.log1_tid;
 }
+
+/*
+ * returns non zero, if multi-threading is enabled
+ * on at least one physical package. Due to hotplug cpu
+ * and (maxcpus=), all threads may not necessarily be enabled
+ * even though the processor supports multi-threading.
+ */
+int is_multithreading_enabled(void)
+{
+       int i, j;
+
+       for_each_present_cpu(i) {
+               for_each_present_cpu(j) {
+                       if (j == i)
+                               continue;
+                       if ((cpu_data(j)->socket_id == cpu_data(i)->socket_id)) {
+                               if (cpu_data(j)->core_id == cpu_data(i)->core_id)
+                                       return 1;
+                       }
+               }
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(is_multithreading_enabled);