[SPARC64]: More sensible udelay implementation.
[pandora-kernel.git] / arch / sparc64 / kernel / smp.c
index c550bba..69a1183 100644 (file)
@@ -1,6 +1,6 @@
 /* smp.c: Sparc64 SMP support.
  *
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997, 2007 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/module.h>
@@ -28,6 +28,8 @@
 #include <asm/tlbflush.h>
 #include <asm/mmu_context.h>
 #include <asm/cpudata.h>
+#include <asm/hvtramp.h>
+#include <asm/io.h>
 
 #include <asm/irq.h>
 #include <asm/irq_regs.h>
 #include <asm/sections.h>
 #include <asm/prom.h>
 #include <asm/mdesc.h>
+#include <asm/ldc.h>
 
 extern void calibrate_delay(void);
 
-/* Please don't make this stuff initdata!!!  --DaveM */
-unsigned char boot_cpu_id;
+int sparc64_multi_core __read_mostly;
 
+cpumask_t cpu_possible_map __read_mostly = CPU_MASK_NONE;
 cpumask_t cpu_online_map __read_mostly = CPU_MASK_NONE;
-cpumask_t phys_cpu_present_map __read_mostly = CPU_MASK_NONE;
 cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly =
        { [0 ... NR_CPUS-1] = CPU_MASK_NONE };
+cpumask_t cpu_core_map[NR_CPUS] __read_mostly =
+       { [0 ... NR_CPUS-1] = CPU_MASK_NONE };
+
+EXPORT_SYMBOL(cpu_possible_map);
+EXPORT_SYMBOL(cpu_online_map);
+EXPORT_SYMBOL(cpu_sibling_map);
+EXPORT_SYMBOL(cpu_core_map);
+
 static cpumask_t smp_commenced_mask;
 static cpumask_t cpu_callout_map;
 
@@ -69,10 +79,7 @@ void smp_bogo(struct seq_file *m)
        
        for_each_online_cpu(i)
                seq_printf(m,
-                          "Cpu%dBogo\t: %lu.%02lu\n"
                           "Cpu%dClkTck\t: %016lx\n",
-                          i, cpu_data(i).udelay_val / (500000/HZ),
-                          (cpu_data(i).udelay_val / (5000/HZ)) % 100,
                           i, cpu_data(i).clock_tick);
 }
 
@@ -80,9 +87,10 @@ extern void setup_sparc64_timer(void);
 
 static volatile unsigned long callin_flag = 0;
 
-void __init smp_callin(void)
+void __devinit smp_callin(void)
 {
        int cpuid = hard_smp_processor_id();
+       struct trap_per_cpu *tb = &trap_block[cpuid];;
 
        __local_per_cpu_offset = __per_cpu_offset(cpuid);
 
@@ -98,8 +106,6 @@ void __init smp_callin(void)
 
        local_irq_enable();
 
-       calibrate_delay();
-       cpu_data(cpuid).udelay_val = loops_per_jiffy;
        callin_flag = 1;
        __asm__ __volatile__("membar #Sync\n\t"
                             "flush  %%g6" : : : "memory");
@@ -113,6 +119,11 @@ void __init smp_callin(void)
        atomic_inc(&init_mm.mm_count);
        current->active_mm = &init_mm;
 
+       if (tb->hdesc) {
+               kfree(tb->hdesc);
+               tb->hdesc = NULL;
+       }
+
        while (!cpu_isset(cpuid, smp_commenced_mask))
                rmb();
 
@@ -264,6 +275,64 @@ static void smp_synchronize_one_tick(int cpu)
        spin_unlock_irqrestore(&itc_sync_lock, flags);
 }
 
+#if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU)
+/* XXX Put this in some common place. XXX */
+static unsigned long kimage_addr_to_ra(void *p)
+{
+       unsigned long val = (unsigned long) p;
+
+       return kern_base + (val - KERNBASE);
+}
+
+static void ldom_startcpu_cpuid(unsigned int cpu, unsigned long thread_reg)
+{
+       extern unsigned long sparc64_ttable_tl0;
+       extern unsigned long kern_locked_tte_data;
+       extern int bigkernel;
+       struct hvtramp_descr *hdesc;
+       unsigned long trampoline_ra;
+       struct trap_per_cpu *tb;
+       u64 tte_vaddr, tte_data;
+       unsigned long hv_err;
+
+       hdesc = kzalloc(sizeof(*hdesc), GFP_KERNEL);
+       if (!hdesc) {
+               printk(KERN_ERR "ldom_startcpu_cpuid: Cannot allocate "
+                      "hvtramp_descr.\n");
+               return;
+       }
+
+       hdesc->cpu = cpu;
+       hdesc->num_mappings = (bigkernel ? 2 : 1);
+
+       tb = &trap_block[cpu];
+       tb->hdesc = hdesc;
+
+       hdesc->fault_info_va = (unsigned long) &tb->fault_info;
+       hdesc->fault_info_pa = kimage_addr_to_ra(&tb->fault_info);
+
+       hdesc->thread_reg = thread_reg;
+
+       tte_vaddr = (unsigned long) KERNBASE;
+       tte_data = kern_locked_tte_data;
+
+       hdesc->maps[0].vaddr = tte_vaddr;
+       hdesc->maps[0].tte   = tte_data;
+       if (bigkernel) {
+               tte_vaddr += 0x400000;
+               tte_data  += 0x400000;
+               hdesc->maps[1].vaddr = tte_vaddr;
+               hdesc->maps[1].tte   = tte_data;
+       }
+
+       trampoline_ra = kimage_addr_to_ra(hv_cpu_startup);
+
+       hv_err = sun4v_cpu_start(cpu, trampoline_ra,
+                                kimage_addr_to_ra(&sparc64_ttable_tl0),
+                                __pa(hdesc));
+}
+#endif
+
 extern void sun4v_init_mondo_queues(int use_bootmem, int cpu, int alloc, int load);
 
 extern unsigned long sparc64_cpu_startup;
@@ -292,14 +361,20 @@ static int __devinit smp_boot_one_cpu(unsigned int cpu)
                /* Alloc the mondo queues, cpu will load them.  */
                sun4v_init_mondo_queues(0, cpu, 1, 0);
 
-               prom_startcpu_cpuid(cpu, entry, cookie);
+#if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU)
+               if (ldom_domaining_enabled)
+                       ldom_startcpu_cpuid(cpu,
+                                           (unsigned long) cpu_new_thread);
+               else
+#endif
+                       prom_startcpu_cpuid(cpu, entry, cookie);
        } else {
                struct device_node *dp = of_find_node_by_cpuid(cpu);
 
                prom_startcpu(dp->node, entry, cookie);
        }
 
-       for (timeout = 0; timeout < 5000000; timeout++) {
+       for (timeout = 0; timeout < 50000; timeout++) {
                if (callin_flag)
                        break;
                udelay(100);
@@ -1148,61 +1223,14 @@ void smp_penguin_jailcell(int irq, struct pt_regs *regs)
        preempt_enable();
 }
 
-void __init smp_tick_init(void)
-{
-       boot_cpu_id = hard_smp_processor_id();
-}
-
 /* /proc/profile writes can call this, don't __init it please. */
 int setup_profiling_timer(unsigned int multiplier)
 {
        return -EINVAL;
 }
 
-static void __init smp_tune_scheduling(void)
-{
-       unsigned int smallest = ~0U;
-       int i;
-
-       for (i = 0; i < NR_CPUS; i++) {
-               unsigned int val = cpu_data(i).ecache_size;
-
-               if (val && val < smallest)
-                       smallest = val;
-       }
-
-       /* Any value less than 256K is nonsense.  */
-       if (smallest < (256U * 1024U))
-               smallest = 256 * 1024;
-
-       max_cache_size = smallest;
-
-       if (smallest < 1U * 1024U * 1024U)
-               printk(KERN_INFO "Using max_cache_size of %uKB\n",
-                      smallest / 1024U);
-       else
-               printk(KERN_INFO "Using max_cache_size of %uMB\n",
-                      smallest / 1024U / 1024U);
-}
-
-/* Constrain the number of cpus to max_cpus.  */
 void __init smp_prepare_cpus(unsigned int max_cpus)
 {
-       int i;
-
-       if (num_possible_cpus() > max_cpus) {
-               for_each_possible_cpu(i) {
-                       if (i != boot_cpu_id) {
-                               cpu_clear(i, phys_cpu_present_map);
-                               cpu_clear(i, cpu_present_map);
-                               if (num_possible_cpus() <= max_cpus)
-                                       break;
-                       }
-               }
-       }
-
-       cpu_data(boot_cpu_id).udelay_val = loops_per_jiffy;
-       smp_tune_scheduling();
 }
 
 void __devinit smp_prepare_boot_cpu(void)
@@ -1217,13 +1245,28 @@ void __devinit smp_fill_in_sib_core_maps(void)
                unsigned int j;
 
                if (cpu_data(i).core_id == 0) {
-                       cpu_set(i, cpu_sibling_map[i]);
+                       cpu_set(i, cpu_core_map[i]);
                        continue;
                }
 
                for_each_possible_cpu(j) {
                        if (cpu_data(i).core_id ==
                            cpu_data(j).core_id)
+                               cpu_set(j, cpu_core_map[i]);
+               }
+       }
+
+       for_each_possible_cpu(i) {
+               unsigned int j;
+
+               if (cpu_data(i).proc_id == -1) {
+                       cpu_set(i, cpu_sibling_map[i]);
+                       continue;
+               }
+
+               for_each_possible_cpu(j) {
+                       if (cpu_data(i).proc_id ==
+                           cpu_data(j).proc_id)
                                cpu_set(j, cpu_sibling_map[i]);
                }
        }
@@ -1250,18 +1293,22 @@ int __cpuinit __cpu_up(unsigned int cpu)
        return ret;
 }
 
-void __init smp_cpus_done(unsigned int max_cpus)
+#ifdef CONFIG_HOTPLUG_CPU
+int __cpu_disable(void)
 {
-       unsigned long bogosum = 0;
-       int i;
+       printk(KERN_ERR "SMP: __cpu_disable() on cpu %d\n",
+              smp_processor_id());
+       return -ENODEV;
+}
 
-       for_each_online_cpu(i)
-               bogosum += cpu_data(i).udelay_val;
-       printk("Total of %ld processors activated "
-              "(%lu.%02lu BogoMIPS).\n",
-              (long) num_online_cpus(),
-              bogosum/(500000/HZ),
-              (bogosum/(5000/HZ))%100);
+void __cpu_die(unsigned int cpu)
+{
+       printk(KERN_ERR "SMP: __cpu_die(%u)\n", cpu);
+}
+#endif
+
+void __init smp_cpus_done(unsigned int max_cpus)
+{
 }
 
 void smp_send_reschedule(int cpu)