[SPARC32]: Fix sparc32 modpost warnings with sunzilog
[safe/jmp/linux-2.6] / arch / sparc64 / kernel / smp.c
index 7dc28a4..cc09d82 100644 (file)
@@ -31,6 +31,7 @@
 #include <asm/cpudata.h>
 
 #include <asm/irq.h>
+#include <asm/irq_regs.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/oplib.h>
@@ -39,6 +40,7 @@
 #include <asm/starfire.h>
 #include <asm/tlb.h>
 #include <asm/sections.h>
+#include <asm/prom.h>
 
 extern void calibrate_delay(void);
 
@@ -76,41 +78,42 @@ void smp_bogo(struct seq_file *m)
 
 void __init smp_store_cpu_info(int id)
 {
-       int cpu_node, def;
+       struct device_node *dp;
+       int def;
 
        /* multiplier and counter set by
           smp_setup_percpu_timer()  */
        cpu_data(id).udelay_val                 = loops_per_jiffy;
 
-       cpu_find_by_mid(id, &cpu_node);
-       cpu_data(id).clock_tick = prom_getintdefault(cpu_node,
-                                                    "clock-frequency", 0);
+       cpu_find_by_mid(id, &dp);
+       cpu_data(id).clock_tick =
+               of_getintprop_default(dp, "clock-frequency", 0);
 
        def = ((tlb_type == hypervisor) ? (8 * 1024) : (16 * 1024));
-       cpu_data(id).dcache_size = prom_getintdefault(cpu_node, "dcache-size",
-                                                     def);
+       cpu_data(id).dcache_size =
+               of_getintprop_default(dp, "dcache-size", def);
 
        def = 32;
        cpu_data(id).dcache_line_size =
-               prom_getintdefault(cpu_node, "dcache-line-size", def);
+               of_getintprop_default(dp, "dcache-line-size", def);
 
        def = 16 * 1024;
-       cpu_data(id).icache_size = prom_getintdefault(cpu_node, "icache-size",
-                                                     def);
+       cpu_data(id).icache_size =
+               of_getintprop_default(dp, "icache-size", def);
 
        def = 32;
        cpu_data(id).icache_line_size =
-               prom_getintdefault(cpu_node, "icache-line-size", def);
+               of_getintprop_default(dp, "icache-line-size", def);
 
        def = ((tlb_type == hypervisor) ?
               (3 * 1024 * 1024) :
               (4 * 1024 * 1024));
-       cpu_data(id).ecache_size = prom_getintdefault(cpu_node, "ecache-size",
-                                                     def);
+       cpu_data(id).ecache_size =
+               of_getintprop_default(dp, "ecache-size", def);
 
        def = 64;
        cpu_data(id).ecache_line_size =
-               prom_getintdefault(cpu_node, "ecache-line-size", def);
+               of_getintprop_default(dp, "ecache-line-size", def);
 
        printk("CPU[%d]: Caches "
               "D[sz(%d):line_sz(%d)] "
@@ -342,10 +345,10 @@ static int __devinit smp_boot_one_cpu(unsigned int cpu)
 
                prom_startcpu_cpuid(cpu, entry, cookie);
        } else {
-               int cpu_node;
+               struct device_node *dp;
 
-               cpu_find_by_mid(cpu, &cpu_node);
-               prom_startcpu(cpu_node, entry, cookie);
+               cpu_find_by_mid(cpu, &dp);
+               prom_startcpu(dp->node, entry, cookie);
        }
 
        for (timeout = 0; timeout < 5000000; timeout++) {
@@ -745,12 +748,21 @@ struct call_data_struct {
        int wait;
 };
 
-static DEFINE_SPINLOCK(call_lock);
+static __cacheline_aligned_in_smp DEFINE_SPINLOCK(call_lock);
 static struct call_data_struct *call_data;
 
 extern unsigned long xcall_call_function;
 
-/*
+/**
+ * smp_call_function(): Run a function on all other CPUs.
+ * @func: The function to run. This must be fast and non-blocking.
+ * @info: An arbitrary pointer to pass to the function.
+ * @nonatomic: currently unused.
+ * @wait: If true, wait (atomically) until function has completed on other CPUs.
+ *
+ * Returns 0 on success, else a negative status code. Does not return until
+ * remote CPUs are nearly ready to execute <<func>> or are or have executed.
+ *
  * You must not call this function with disabled interrupts or from a
  * hardware interrupt handler or from a bottom half handler.
  */
@@ -759,7 +771,6 @@ static int smp_call_function_mask(void (*func)(void *info), void *info,
 {
        struct call_data_struct data;
        int cpus;
-       long timeout;
 
        /* Can deadlock when called with interrupts disabled */
        WARN_ON(irqs_disabled());
@@ -777,31 +788,18 @@ static int smp_call_function_mask(void (*func)(void *info), void *info,
                goto out_unlock;
 
        call_data = &data;
+       mb();
 
        smp_cross_call_masked(&xcall_call_function, 0, 0, 0, mask);
 
-       /* 
-        * Wait for other cpus to complete function or at
-        * least snap the call data.
-        */
-       timeout = 1000000;
-       while (atomic_read(&data.finished) != cpus) {
-               if (--timeout <= 0)
-                       goto out_timeout;
-               barrier();
-               udelay(1);
-       }
+       /* Wait for response */
+       while (atomic_read(&data.finished) != cpus)
+               cpu_relax();
 
 out_unlock:
        spin_unlock(&call_lock);
 
        return 0;
-
-out_timeout:
-       spin_unlock(&call_lock);
-       printk("XCALL: Remote cpus not responding, ncpus=%d finished=%d\n",
-              cpus, atomic_read(&data.finished));
-       return 0;
 }
 
 int smp_call_function(void (*func)(void *info), void *info,
@@ -830,9 +828,16 @@ void smp_call_function_client(int irq, struct pt_regs *regs)
 
 static void tsb_sync(void *info)
 {
+       struct trap_per_cpu *tp = &trap_block[raw_smp_processor_id()];
        struct mm_struct *mm = info;
 
-       if (current->active_mm == mm)
+       /* It is not valid to test "currrent->active_mm == mm" here.
+        *
+        * The value of "current" is not changed atomically with
+        * switch_mm().  But that's OK, we just need to check the
+        * current cpu's trap block PGD physical address.
+        */
+       if (tp->pgd_paddr == __pa(mm->pgd))
                tsb_context_switch(mm);
 }
 
@@ -1183,6 +1188,7 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
        unsigned long compare, tick, pstate;
        int cpu = smp_processor_id();
        int user = user_mode(regs);
+       struct pt_regs *old_regs;
 
        /*
         * Check for level 14 softint.
@@ -1199,8 +1205,9 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
                clear_softint(tick_mask);
        }
 
+       old_regs = set_irq_regs(regs);
        do {
-               profile_tick(CPU_PROFILING, regs);
+               profile_tick(CPU_PROFILING);
                if (!--prof_counter(cpu)) {
                        irq_enter();
 
@@ -1232,6 +1239,7 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
                                     : /* no outputs */
                                     : "r" (pstate));
        } while (time_after_eq(tick, compare));
+       set_irq_regs(old_regs);
 }
 
 static void __init smp_setup_percpu_timer(void)
@@ -1262,7 +1270,6 @@ void __init smp_tick_init(void)
        boot_cpu_id = hard_smp_processor_id();
        current_tick_offset = timer_tick_offset;
 
-       cpu_set(boot_cpu_id, cpu_online_map);
        prof_counter(boot_cpu_id) = prof_multiplier(boot_cpu_id) = 1;
 }
 
@@ -1278,7 +1285,7 @@ int setup_profiling_timer(unsigned int multiplier)
                return -EINVAL;
 
        spin_lock_irqsave(&prof_setup_lock, flags);
-       for_each_cpu(i)
+       for_each_possible_cpu(i)
                prof_multiplier(i) = multiplier;
        current_tick_offset = (timer_tick_offset / multiplier);
        spin_unlock_irqrestore(&prof_setup_lock, flags);
@@ -1286,6 +1293,41 @@ int setup_profiling_timer(unsigned int multiplier)
        return 0;
 }
 
+static void __init smp_tune_scheduling(void)
+{
+       struct device_node *dp;
+       int instance;
+       unsigned int def, smallest = ~0U;
+
+       def = ((tlb_type == hypervisor) ?
+              (3 * 1024 * 1024) :
+              (4 * 1024 * 1024));
+
+       instance = 0;
+       while (!cpu_find_by_instance(instance, &dp, NULL)) {
+               unsigned int val;
+
+               val = of_getintprop_default(dp, "ecache-size", def);
+               if (val < smallest)
+                       smallest = val;
+
+               instance++;
+       }
+
+       /* 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)
 {
@@ -1306,12 +1348,12 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
                }
        }
 
-       for_each_cpu(i) {
+       for_each_possible_cpu(i) {
                if (tlb_type == hypervisor) {
                        int j;
 
                        /* XXX get this mapping from machine description */
-                       for_each_cpu(j) {
+                       for_each_possible_cpu(j) {
                                if ((j >> 2) == (i >> 2))
                                        cpu_set(j, cpu_sibling_map[i]);
                        }
@@ -1321,6 +1363,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
        }
 
        smp_store_cpu_info(boot_cpu_id);
+       smp_tune_scheduling();
 }
 
 /* Set this up early so that things like the scheduler can init
@@ -1343,18 +1386,6 @@ void __init smp_setup_cpu_possible_map(void)
 
 void __devinit smp_prepare_boot_cpu(void)
 {
-       int cpu = hard_smp_processor_id();
-
-       if (cpu >= NR_CPUS) {
-               prom_printf("Serious problem, boot cpu id >= NR_CPUS\n");
-               prom_halt();
-       }
-
-       current_thread_info()->cpu = cpu;
-       __local_per_cpu_offset = __per_cpu_offset(cpu);
-
-       cpu_set(smp_processor_id(), cpu_online_map);
-       cpu_set(smp_processor_id(), phys_cpu_present_map);
 }
 
 int __devinit __cpu_up(unsigned int cpu)
@@ -1431,4 +1462,7 @@ void __init setup_per_cpu_areas(void)
 
        for (i = 0; i < NR_CPUS; i++, ptr += size)
                memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
+
+       /* Setup %g5 for the boot cpu.  */
+       __local_per_cpu_offset = __per_cpu_offset(smp_processor_id());
 }