summaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/smp.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64/kernel/smp.c')
-rw-r--r--arch/sparc64/kernel/smp.c64
1 files changed, 44 insertions, 20 deletions
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index d1adeb2c7..2fa4945d8 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -94,7 +94,8 @@ void __init smp_store_cpu_info(int id)
cpu_data[id].udelay_val = loops_per_sec;
cpu_data[id].pgcache_size = 0;
- cpu_data[id].pte_cache = NULL;
+ cpu_data[id].pte_cache[0] = NULL;
+ cpu_data[id].pte_cache[1] = NULL;
cpu_data[id].pgdcache_size = 0;
cpu_data[id].pgd_cache = NULL;
cpu_data[id].idle_volume = 1;
@@ -184,7 +185,7 @@ void cpu_panic(void)
extern struct prom_cpuinfo linux_cpus[64];
-extern unsigned long smp_trampoline;
+extern unsigned long sparc64_cpu_startup;
/* The OBP cpu startup callback truncates the 3rd arg cookie to
* 32-bits (I think) so to be safe we have it read the pointer
@@ -210,15 +211,13 @@ void __init smp_boot_cpus(void)
continue;
if(cpu_present_map & (1UL << i)) {
- unsigned long entry = (unsigned long)(&smp_trampoline);
+ unsigned long entry = (unsigned long)(&sparc64_cpu_startup);
unsigned long cookie = (unsigned long)(&cpu_new_task);
struct task_struct *p;
int timeout;
int no;
- extern unsigned long phys_base;
- entry += phys_base - KERNBASE;
- cookie += phys_base - KERNBASE;
+ prom_printf("Starting CPU %d... ", i);
kernel_thread(start_secondary, NULL, CLONE_PID);
cpucount++;
@@ -247,9 +246,11 @@ void __init smp_boot_cpus(void)
cpu_number_map[i] = cpucount;
__cpu_logical_map[cpucount] = i;
prom_cpu_nodes[i] = linux_cpus[no].prom_node;
+ prom_printf("OK\n");
} else {
cpucount--;
printk("Processor %d is stuck.\n", i);
+ prom_printf("FAILED\n");
}
}
if(!callin_flag) {
@@ -537,14 +538,31 @@ void smp_release(void)
/* Imprisoned penguins run with %pil == 15, but PSTATE_IE set, so they
* can service tlb flush xcalls...
*/
+extern void prom_world(int);
+extern void save_alternate_globals(unsigned long *);
+extern void restore_alternate_globals(unsigned long *);
void smp_penguin_jailcell(void)
{
- flushw_user();
+ unsigned long global_save[24];
+
+ __asm__ __volatile__("flushw");
+ save_alternate_globals(global_save);
+ prom_world(1);
atomic_inc(&smp_capture_registry);
membar("#StoreLoad | #StoreStore");
while(penguins_are_doing_time)
membar("#LoadLoad");
+ restore_alternate_globals(global_save);
atomic_dec(&smp_capture_registry);
+ prom_world(0);
+}
+
+extern unsigned long xcall_promstop;
+
+void smp_promstop_others(void)
+{
+ if (smp_processors_ready)
+ smp_cross_call(&xcall_promstop, 0, 0, 0);
}
static inline void sparc64_do_profile(unsigned long pc, unsigned long g3)
@@ -701,14 +719,13 @@ static inline unsigned long find_flush_base(unsigned long size)
/* Failure. */
if(p >= (mem_map + max_mapnr))
return 0UL;
- if(PageSkip(p)) {
- p = p->next_hash;
- base = page_address(p);
+ if(PageReserved(p)) {
found = size;
+ base = page_address(p);
} else {
found -= PAGE_SIZE;
- p++;
}
+ p++;
}
return base;
}
@@ -718,7 +735,7 @@ cycles_t cacheflush_time;
static void __init smp_tune_scheduling (void)
{
unsigned long flush_base, flags, *p;
- unsigned int ecache_size;
+ unsigned int ecache_size, order;
cycles_t tick1, tick2, raw;
/* Approximate heuristic for SMP scheduling. It is an
@@ -733,18 +750,22 @@ static void __init smp_tune_scheduling (void)
*/
printk("SMP: Calibrating ecache flush... ");
ecache_size = prom_getintdefault(linux_cpus[0].prom_node,
- "ecache-size", (512 *1024));
- flush_base = find_flush_base(ecache_size << 1);
-
- if(flush_base != 0UL) {
+ "ecache-size", (512 * 1024));
+ if (ecache_size > (4 * 1024 * 1024))
+ ecache_size = (4 * 1024 * 1024);
+ for (order = 0UL; (PAGE_SIZE << order) < ecache_size; order++)
+ ;
+ flush_base = __get_free_pages(GFP_KERNEL, order);
+
+ if (flush_base != 0UL) {
__save_and_cli(flags);
/* Scan twice the size once just to get the TLB entries
* loaded and make sure the second scan measures pure misses.
*/
- for(p = (unsigned long *)flush_base;
- ((unsigned long)p) < (flush_base + (ecache_size<<1));
- p += (64 / sizeof(unsigned long)))
+ for (p = (unsigned long *)flush_base;
+ ((unsigned long)p) < (flush_base + (ecache_size<<1));
+ p += (64 / sizeof(unsigned long)))
*((volatile unsigned long *)p);
/* Now the real measurement. */
@@ -775,9 +796,12 @@ static void __init smp_tune_scheduling (void)
* sharing the cache and fitting.
*/
cacheflush_time = (raw - (raw >> 2));
- } else
+
+ free_pages(flush_base, order);
+ } else {
cacheflush_time = ((ecache_size << 2) +
(ecache_size << 1));
+ }
printk("Using heuristic of %d cycles.\n",
(int) cacheflush_time);