1a88b5ba8SSam Ravnborg /* smp.c: Sparc64 SMP support. 2a88b5ba8SSam Ravnborg * 3a88b5ba8SSam Ravnborg * Copyright (C) 1997, 2007, 2008 David S. Miller (davem@davemloft.net) 4a88b5ba8SSam Ravnborg */ 5a88b5ba8SSam Ravnborg 6a88b5ba8SSam Ravnborg #include <linux/module.h> 7a88b5ba8SSam Ravnborg #include <linux/kernel.h> 8a88b5ba8SSam Ravnborg #include <linux/sched.h> 9a88b5ba8SSam Ravnborg #include <linux/mm.h> 10a88b5ba8SSam Ravnborg #include <linux/pagemap.h> 11a88b5ba8SSam Ravnborg #include <linux/threads.h> 12a88b5ba8SSam Ravnborg #include <linux/smp.h> 13a88b5ba8SSam Ravnborg #include <linux/interrupt.h> 14a88b5ba8SSam Ravnborg #include <linux/kernel_stat.h> 15a88b5ba8SSam Ravnborg #include <linux/delay.h> 16a88b5ba8SSam Ravnborg #include <linux/init.h> 17a88b5ba8SSam Ravnborg #include <linux/spinlock.h> 18a88b5ba8SSam Ravnborg #include <linux/fs.h> 19a88b5ba8SSam Ravnborg #include <linux/seq_file.h> 20a88b5ba8SSam Ravnborg #include <linux/cache.h> 21a88b5ba8SSam Ravnborg #include <linux/jiffies.h> 22a88b5ba8SSam Ravnborg #include <linux/profile.h> 23a88b5ba8SSam Ravnborg #include <linux/lmb.h> 24a88b5ba8SSam Ravnborg #include <linux/cpu.h> 25a88b5ba8SSam Ravnborg 26a88b5ba8SSam Ravnborg #include <asm/head.h> 27a88b5ba8SSam Ravnborg #include <asm/ptrace.h> 28a88b5ba8SSam Ravnborg #include <asm/atomic.h> 29a88b5ba8SSam Ravnborg #include <asm/tlbflush.h> 30a88b5ba8SSam Ravnborg #include <asm/mmu_context.h> 31a88b5ba8SSam Ravnborg #include <asm/cpudata.h> 32a88b5ba8SSam Ravnborg #include <asm/hvtramp.h> 33a88b5ba8SSam Ravnborg #include <asm/io.h> 34a88b5ba8SSam Ravnborg #include <asm/timer.h> 35a88b5ba8SSam Ravnborg 36a88b5ba8SSam Ravnborg #include <asm/irq.h> 37a88b5ba8SSam Ravnborg #include <asm/irq_regs.h> 38a88b5ba8SSam Ravnborg #include <asm/page.h> 39a88b5ba8SSam Ravnborg #include <asm/pgtable.h> 40a88b5ba8SSam Ravnborg #include <asm/oplib.h> 41a88b5ba8SSam Ravnborg #include <asm/uaccess.h> 42a88b5ba8SSam Ravnborg #include <asm/starfire.h> 43a88b5ba8SSam Ravnborg #include <asm/tlb.h> 44a88b5ba8SSam Ravnborg #include <asm/sections.h> 45a88b5ba8SSam Ravnborg #include <asm/prom.h> 46a88b5ba8SSam Ravnborg #include <asm/mdesc.h> 47a88b5ba8SSam Ravnborg #include <asm/ldc.h> 48a88b5ba8SSam Ravnborg #include <asm/hypervisor.h> 49a88b5ba8SSam Ravnborg 50a88b5ba8SSam Ravnborg int sparc64_multi_core __read_mostly; 51a88b5ba8SSam Ravnborg 52a88b5ba8SSam Ravnborg DEFINE_PER_CPU(cpumask_t, cpu_sibling_map) = CPU_MASK_NONE; 53a88b5ba8SSam Ravnborg cpumask_t cpu_core_map[NR_CPUS] __read_mostly = 54a88b5ba8SSam Ravnborg { [0 ... NR_CPUS-1] = CPU_MASK_NONE }; 55a88b5ba8SSam Ravnborg 56a88b5ba8SSam Ravnborg EXPORT_PER_CPU_SYMBOL(cpu_sibling_map); 57a88b5ba8SSam Ravnborg EXPORT_SYMBOL(cpu_core_map); 58a88b5ba8SSam Ravnborg 59a88b5ba8SSam Ravnborg static cpumask_t smp_commenced_mask; 60a88b5ba8SSam Ravnborg 61a88b5ba8SSam Ravnborg void smp_info(struct seq_file *m) 62a88b5ba8SSam Ravnborg { 63a88b5ba8SSam Ravnborg int i; 64a88b5ba8SSam Ravnborg 65a88b5ba8SSam Ravnborg seq_printf(m, "State:\n"); 66a88b5ba8SSam Ravnborg for_each_online_cpu(i) 67a88b5ba8SSam Ravnborg seq_printf(m, "CPU%d:\t\tonline\n", i); 68a88b5ba8SSam Ravnborg } 69a88b5ba8SSam Ravnborg 70a88b5ba8SSam Ravnborg void smp_bogo(struct seq_file *m) 71a88b5ba8SSam Ravnborg { 72a88b5ba8SSam Ravnborg int i; 73a88b5ba8SSam Ravnborg 74a88b5ba8SSam Ravnborg for_each_online_cpu(i) 75a88b5ba8SSam Ravnborg seq_printf(m, 76a88b5ba8SSam Ravnborg "Cpu%dClkTck\t: %016lx\n", 77a88b5ba8SSam Ravnborg i, cpu_data(i).clock_tick); 78a88b5ba8SSam Ravnborg } 79a88b5ba8SSam Ravnborg 80a88b5ba8SSam Ravnborg extern void setup_sparc64_timer(void); 81a88b5ba8SSam Ravnborg 82a88b5ba8SSam Ravnborg static volatile unsigned long callin_flag = 0; 83a88b5ba8SSam Ravnborg 84a88b5ba8SSam Ravnborg void __cpuinit smp_callin(void) 85a88b5ba8SSam Ravnborg { 86a88b5ba8SSam Ravnborg int cpuid = hard_smp_processor_id(); 87a88b5ba8SSam Ravnborg 88a88b5ba8SSam Ravnborg __local_per_cpu_offset = __per_cpu_offset(cpuid); 89a88b5ba8SSam Ravnborg 90a88b5ba8SSam Ravnborg if (tlb_type == hypervisor) 91a88b5ba8SSam Ravnborg sun4v_ktsb_register(); 92a88b5ba8SSam Ravnborg 93a88b5ba8SSam Ravnborg __flush_tlb_all(); 94a88b5ba8SSam Ravnborg 95a88b5ba8SSam Ravnborg setup_sparc64_timer(); 96a88b5ba8SSam Ravnborg 97a88b5ba8SSam Ravnborg if (cheetah_pcache_forced_on) 98a88b5ba8SSam Ravnborg cheetah_enable_pcache(); 99a88b5ba8SSam Ravnborg 100a88b5ba8SSam Ravnborg local_irq_enable(); 101a88b5ba8SSam Ravnborg 102a88b5ba8SSam Ravnborg callin_flag = 1; 103a88b5ba8SSam Ravnborg __asm__ __volatile__("membar #Sync\n\t" 104a88b5ba8SSam Ravnborg "flush %%g6" : : : "memory"); 105a88b5ba8SSam Ravnborg 106a88b5ba8SSam Ravnborg /* Clear this or we will die instantly when we 107a88b5ba8SSam Ravnborg * schedule back to this idler... 108a88b5ba8SSam Ravnborg */ 109a88b5ba8SSam Ravnborg current_thread_info()->new_child = 0; 110a88b5ba8SSam Ravnborg 111a88b5ba8SSam Ravnborg /* Attach to the address space of init_task. */ 112a88b5ba8SSam Ravnborg atomic_inc(&init_mm.mm_count); 113a88b5ba8SSam Ravnborg current->active_mm = &init_mm; 114a88b5ba8SSam Ravnborg 115a88b5ba8SSam Ravnborg /* inform the notifiers about the new cpu */ 116a88b5ba8SSam Ravnborg notify_cpu_starting(cpuid); 117a88b5ba8SSam Ravnborg 118a88b5ba8SSam Ravnborg while (!cpu_isset(cpuid, smp_commenced_mask)) 119a88b5ba8SSam Ravnborg rmb(); 120a88b5ba8SSam Ravnborg 121a88b5ba8SSam Ravnborg ipi_call_lock(); 122a88b5ba8SSam Ravnborg cpu_set(cpuid, cpu_online_map); 123a88b5ba8SSam Ravnborg ipi_call_unlock(); 124a88b5ba8SSam Ravnborg 125a88b5ba8SSam Ravnborg /* idle thread is expected to have preempt disabled */ 126a88b5ba8SSam Ravnborg preempt_disable(); 127a88b5ba8SSam Ravnborg } 128a88b5ba8SSam Ravnborg 129a88b5ba8SSam Ravnborg void cpu_panic(void) 130a88b5ba8SSam Ravnborg { 131a88b5ba8SSam Ravnborg printk("CPU[%d]: Returns from cpu_idle!\n", smp_processor_id()); 132a88b5ba8SSam Ravnborg panic("SMP bolixed\n"); 133a88b5ba8SSam Ravnborg } 134a88b5ba8SSam Ravnborg 135a88b5ba8SSam Ravnborg /* This tick register synchronization scheme is taken entirely from 136a88b5ba8SSam Ravnborg * the ia64 port, see arch/ia64/kernel/smpboot.c for details and credit. 137a88b5ba8SSam Ravnborg * 138a88b5ba8SSam Ravnborg * The only change I've made is to rework it so that the master 139a88b5ba8SSam Ravnborg * initiates the synchonization instead of the slave. -DaveM 140a88b5ba8SSam Ravnborg */ 141a88b5ba8SSam Ravnborg 142a88b5ba8SSam Ravnborg #define MASTER 0 143a88b5ba8SSam Ravnborg #define SLAVE (SMP_CACHE_BYTES/sizeof(unsigned long)) 144a88b5ba8SSam Ravnborg 145a88b5ba8SSam Ravnborg #define NUM_ROUNDS 64 /* magic value */ 146a88b5ba8SSam Ravnborg #define NUM_ITERS 5 /* likewise */ 147a88b5ba8SSam Ravnborg 148a88b5ba8SSam Ravnborg static DEFINE_SPINLOCK(itc_sync_lock); 149a88b5ba8SSam Ravnborg static unsigned long go[SLAVE + 1]; 150a88b5ba8SSam Ravnborg 151a88b5ba8SSam Ravnborg #define DEBUG_TICK_SYNC 0 152a88b5ba8SSam Ravnborg 153a88b5ba8SSam Ravnborg static inline long get_delta (long *rt, long *master) 154a88b5ba8SSam Ravnborg { 155a88b5ba8SSam Ravnborg unsigned long best_t0 = 0, best_t1 = ~0UL, best_tm = 0; 156a88b5ba8SSam Ravnborg unsigned long tcenter, t0, t1, tm; 157a88b5ba8SSam Ravnborg unsigned long i; 158a88b5ba8SSam Ravnborg 159a88b5ba8SSam Ravnborg for (i = 0; i < NUM_ITERS; i++) { 160a88b5ba8SSam Ravnborg t0 = tick_ops->get_tick(); 161a88b5ba8SSam Ravnborg go[MASTER] = 1; 162a88b5ba8SSam Ravnborg membar_safe("#StoreLoad"); 163a88b5ba8SSam Ravnborg while (!(tm = go[SLAVE])) 164a88b5ba8SSam Ravnborg rmb(); 165a88b5ba8SSam Ravnborg go[SLAVE] = 0; 166a88b5ba8SSam Ravnborg wmb(); 167a88b5ba8SSam Ravnborg t1 = tick_ops->get_tick(); 168a88b5ba8SSam Ravnborg 169a88b5ba8SSam Ravnborg if (t1 - t0 < best_t1 - best_t0) 170a88b5ba8SSam Ravnborg best_t0 = t0, best_t1 = t1, best_tm = tm; 171a88b5ba8SSam Ravnborg } 172a88b5ba8SSam Ravnborg 173a88b5ba8SSam Ravnborg *rt = best_t1 - best_t0; 174a88b5ba8SSam Ravnborg *master = best_tm - best_t0; 175a88b5ba8SSam Ravnborg 176a88b5ba8SSam Ravnborg /* average best_t0 and best_t1 without overflow: */ 177a88b5ba8SSam Ravnborg tcenter = (best_t0/2 + best_t1/2); 178a88b5ba8SSam Ravnborg if (best_t0 % 2 + best_t1 % 2 == 2) 179a88b5ba8SSam Ravnborg tcenter++; 180a88b5ba8SSam Ravnborg return tcenter - best_tm; 181a88b5ba8SSam Ravnborg } 182a88b5ba8SSam Ravnborg 183a88b5ba8SSam Ravnborg void smp_synchronize_tick_client(void) 184a88b5ba8SSam Ravnborg { 185a88b5ba8SSam Ravnborg long i, delta, adj, adjust_latency = 0, done = 0; 186a88b5ba8SSam Ravnborg unsigned long flags, rt, master_time_stamp, bound; 187a88b5ba8SSam Ravnborg #if DEBUG_TICK_SYNC 188a88b5ba8SSam Ravnborg struct { 189a88b5ba8SSam Ravnborg long rt; /* roundtrip time */ 190a88b5ba8SSam Ravnborg long master; /* master's timestamp */ 191a88b5ba8SSam Ravnborg long diff; /* difference between midpoint and master's timestamp */ 192a88b5ba8SSam Ravnborg long lat; /* estimate of itc adjustment latency */ 193a88b5ba8SSam Ravnborg } t[NUM_ROUNDS]; 194a88b5ba8SSam Ravnborg #endif 195a88b5ba8SSam Ravnborg 196a88b5ba8SSam Ravnborg go[MASTER] = 1; 197a88b5ba8SSam Ravnborg 198a88b5ba8SSam Ravnborg while (go[MASTER]) 199a88b5ba8SSam Ravnborg rmb(); 200a88b5ba8SSam Ravnborg 201a88b5ba8SSam Ravnborg local_irq_save(flags); 202a88b5ba8SSam Ravnborg { 203a88b5ba8SSam Ravnborg for (i = 0; i < NUM_ROUNDS; i++) { 204a88b5ba8SSam Ravnborg delta = get_delta(&rt, &master_time_stamp); 205a88b5ba8SSam Ravnborg if (delta == 0) { 206a88b5ba8SSam Ravnborg done = 1; /* let's lock on to this... */ 207a88b5ba8SSam Ravnborg bound = rt; 208a88b5ba8SSam Ravnborg } 209a88b5ba8SSam Ravnborg 210a88b5ba8SSam Ravnborg if (!done) { 211a88b5ba8SSam Ravnborg if (i > 0) { 212a88b5ba8SSam Ravnborg adjust_latency += -delta; 213a88b5ba8SSam Ravnborg adj = -delta + adjust_latency/4; 214a88b5ba8SSam Ravnborg } else 215a88b5ba8SSam Ravnborg adj = -delta; 216a88b5ba8SSam Ravnborg 217a88b5ba8SSam Ravnborg tick_ops->add_tick(adj); 218a88b5ba8SSam Ravnborg } 219a88b5ba8SSam Ravnborg #if DEBUG_TICK_SYNC 220a88b5ba8SSam Ravnborg t[i].rt = rt; 221a88b5ba8SSam Ravnborg t[i].master = master_time_stamp; 222a88b5ba8SSam Ravnborg t[i].diff = delta; 223a88b5ba8SSam Ravnborg t[i].lat = adjust_latency/4; 224a88b5ba8SSam Ravnborg #endif 225a88b5ba8SSam Ravnborg } 226a88b5ba8SSam Ravnborg } 227a88b5ba8SSam Ravnborg local_irq_restore(flags); 228a88b5ba8SSam Ravnborg 229a88b5ba8SSam Ravnborg #if DEBUG_TICK_SYNC 230a88b5ba8SSam Ravnborg for (i = 0; i < NUM_ROUNDS; i++) 231a88b5ba8SSam Ravnborg printk("rt=%5ld master=%5ld diff=%5ld adjlat=%5ld\n", 232a88b5ba8SSam Ravnborg t[i].rt, t[i].master, t[i].diff, t[i].lat); 233a88b5ba8SSam Ravnborg #endif 234a88b5ba8SSam Ravnborg 235a88b5ba8SSam Ravnborg printk(KERN_INFO "CPU %d: synchronized TICK with master CPU " 236a88b5ba8SSam Ravnborg "(last diff %ld cycles, maxerr %lu cycles)\n", 237a88b5ba8SSam Ravnborg smp_processor_id(), delta, rt); 238a88b5ba8SSam Ravnborg } 239a88b5ba8SSam Ravnborg 240a88b5ba8SSam Ravnborg static void smp_start_sync_tick_client(int cpu); 241a88b5ba8SSam Ravnborg 242a88b5ba8SSam Ravnborg static void smp_synchronize_one_tick(int cpu) 243a88b5ba8SSam Ravnborg { 244a88b5ba8SSam Ravnborg unsigned long flags, i; 245a88b5ba8SSam Ravnborg 246a88b5ba8SSam Ravnborg go[MASTER] = 0; 247a88b5ba8SSam Ravnborg 248a88b5ba8SSam Ravnborg smp_start_sync_tick_client(cpu); 249a88b5ba8SSam Ravnborg 250a88b5ba8SSam Ravnborg /* wait for client to be ready */ 251a88b5ba8SSam Ravnborg while (!go[MASTER]) 252a88b5ba8SSam Ravnborg rmb(); 253a88b5ba8SSam Ravnborg 254a88b5ba8SSam Ravnborg /* now let the client proceed into his loop */ 255a88b5ba8SSam Ravnborg go[MASTER] = 0; 256a88b5ba8SSam Ravnborg membar_safe("#StoreLoad"); 257a88b5ba8SSam Ravnborg 258a88b5ba8SSam Ravnborg spin_lock_irqsave(&itc_sync_lock, flags); 259a88b5ba8SSam Ravnborg { 260a88b5ba8SSam Ravnborg for (i = 0; i < NUM_ROUNDS*NUM_ITERS; i++) { 261a88b5ba8SSam Ravnborg while (!go[MASTER]) 262a88b5ba8SSam Ravnborg rmb(); 263a88b5ba8SSam Ravnborg go[MASTER] = 0; 264a88b5ba8SSam Ravnborg wmb(); 265a88b5ba8SSam Ravnborg go[SLAVE] = tick_ops->get_tick(); 266a88b5ba8SSam Ravnborg membar_safe("#StoreLoad"); 267a88b5ba8SSam Ravnborg } 268a88b5ba8SSam Ravnborg } 269a88b5ba8SSam Ravnborg spin_unlock_irqrestore(&itc_sync_lock, flags); 270a88b5ba8SSam Ravnborg } 271a88b5ba8SSam Ravnborg 272a88b5ba8SSam Ravnborg #if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU) 273a88b5ba8SSam Ravnborg /* XXX Put this in some common place. XXX */ 274a88b5ba8SSam Ravnborg static unsigned long kimage_addr_to_ra(void *p) 275a88b5ba8SSam Ravnborg { 276a88b5ba8SSam Ravnborg unsigned long val = (unsigned long) p; 277a88b5ba8SSam Ravnborg 278a88b5ba8SSam Ravnborg return kern_base + (val - KERNBASE); 279a88b5ba8SSam Ravnborg } 280a88b5ba8SSam Ravnborg 281a88b5ba8SSam Ravnborg static void __cpuinit ldom_startcpu_cpuid(unsigned int cpu, unsigned long thread_reg) 282a88b5ba8SSam Ravnborg { 283a88b5ba8SSam Ravnborg extern unsigned long sparc64_ttable_tl0; 284a88b5ba8SSam Ravnborg extern unsigned long kern_locked_tte_data; 285a88b5ba8SSam Ravnborg struct hvtramp_descr *hdesc; 286a88b5ba8SSam Ravnborg unsigned long trampoline_ra; 287a88b5ba8SSam Ravnborg struct trap_per_cpu *tb; 288a88b5ba8SSam Ravnborg u64 tte_vaddr, tte_data; 289a88b5ba8SSam Ravnborg unsigned long hv_err; 290a88b5ba8SSam Ravnborg int i; 291a88b5ba8SSam Ravnborg 292a88b5ba8SSam Ravnborg hdesc = kzalloc(sizeof(*hdesc) + 293a88b5ba8SSam Ravnborg (sizeof(struct hvtramp_mapping) * 294a88b5ba8SSam Ravnborg num_kernel_image_mappings - 1), 295a88b5ba8SSam Ravnborg GFP_KERNEL); 296a88b5ba8SSam Ravnborg if (!hdesc) { 297a88b5ba8SSam Ravnborg printk(KERN_ERR "ldom_startcpu_cpuid: Cannot allocate " 298a88b5ba8SSam Ravnborg "hvtramp_descr.\n"); 299a88b5ba8SSam Ravnborg return; 300a88b5ba8SSam Ravnborg } 301a88b5ba8SSam Ravnborg 302a88b5ba8SSam Ravnborg hdesc->cpu = cpu; 303a88b5ba8SSam Ravnborg hdesc->num_mappings = num_kernel_image_mappings; 304a88b5ba8SSam Ravnborg 305a88b5ba8SSam Ravnborg tb = &trap_block[cpu]; 306a88b5ba8SSam Ravnborg tb->hdesc = hdesc; 307a88b5ba8SSam Ravnborg 308a88b5ba8SSam Ravnborg hdesc->fault_info_va = (unsigned long) &tb->fault_info; 309a88b5ba8SSam Ravnborg hdesc->fault_info_pa = kimage_addr_to_ra(&tb->fault_info); 310a88b5ba8SSam Ravnborg 311a88b5ba8SSam Ravnborg hdesc->thread_reg = thread_reg; 312a88b5ba8SSam Ravnborg 313a88b5ba8SSam Ravnborg tte_vaddr = (unsigned long) KERNBASE; 314a88b5ba8SSam Ravnborg tte_data = kern_locked_tte_data; 315a88b5ba8SSam Ravnborg 316a88b5ba8SSam Ravnborg for (i = 0; i < hdesc->num_mappings; i++) { 317a88b5ba8SSam Ravnborg hdesc->maps[i].vaddr = tte_vaddr; 318a88b5ba8SSam Ravnborg hdesc->maps[i].tte = tte_data; 319a88b5ba8SSam Ravnborg tte_vaddr += 0x400000; 320a88b5ba8SSam Ravnborg tte_data += 0x400000; 321a88b5ba8SSam Ravnborg } 322a88b5ba8SSam Ravnborg 323a88b5ba8SSam Ravnborg trampoline_ra = kimage_addr_to_ra(hv_cpu_startup); 324a88b5ba8SSam Ravnborg 325a88b5ba8SSam Ravnborg hv_err = sun4v_cpu_start(cpu, trampoline_ra, 326a88b5ba8SSam Ravnborg kimage_addr_to_ra(&sparc64_ttable_tl0), 327a88b5ba8SSam Ravnborg __pa(hdesc)); 328a88b5ba8SSam Ravnborg if (hv_err) 329a88b5ba8SSam Ravnborg printk(KERN_ERR "ldom_startcpu_cpuid: sun4v_cpu_start() " 330a88b5ba8SSam Ravnborg "gives error %lu\n", hv_err); 331a88b5ba8SSam Ravnborg } 332a88b5ba8SSam Ravnborg #endif 333a88b5ba8SSam Ravnborg 334a88b5ba8SSam Ravnborg extern unsigned long sparc64_cpu_startup; 335a88b5ba8SSam Ravnborg 336a88b5ba8SSam Ravnborg /* The OBP cpu startup callback truncates the 3rd arg cookie to 337a88b5ba8SSam Ravnborg * 32-bits (I think) so to be safe we have it read the pointer 338a88b5ba8SSam Ravnborg * contained here so we work on >4GB machines. -DaveM 339a88b5ba8SSam Ravnborg */ 340a88b5ba8SSam Ravnborg static struct thread_info *cpu_new_thread = NULL; 341a88b5ba8SSam Ravnborg 342a88b5ba8SSam Ravnborg static int __cpuinit smp_boot_one_cpu(unsigned int cpu) 343a88b5ba8SSam Ravnborg { 344a88b5ba8SSam Ravnborg struct trap_per_cpu *tb = &trap_block[cpu]; 345a88b5ba8SSam Ravnborg unsigned long entry = 346a88b5ba8SSam Ravnborg (unsigned long)(&sparc64_cpu_startup); 347a88b5ba8SSam Ravnborg unsigned long cookie = 348a88b5ba8SSam Ravnborg (unsigned long)(&cpu_new_thread); 349a88b5ba8SSam Ravnborg struct task_struct *p; 350a88b5ba8SSam Ravnborg int timeout, ret; 351a88b5ba8SSam Ravnborg 352a88b5ba8SSam Ravnborg p = fork_idle(cpu); 353a88b5ba8SSam Ravnborg if (IS_ERR(p)) 354a88b5ba8SSam Ravnborg return PTR_ERR(p); 355a88b5ba8SSam Ravnborg callin_flag = 0; 356a88b5ba8SSam Ravnborg cpu_new_thread = task_thread_info(p); 357a88b5ba8SSam Ravnborg 358a88b5ba8SSam Ravnborg if (tlb_type == hypervisor) { 359a88b5ba8SSam Ravnborg #if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU) 360a88b5ba8SSam Ravnborg if (ldom_domaining_enabled) 361a88b5ba8SSam Ravnborg ldom_startcpu_cpuid(cpu, 362a88b5ba8SSam Ravnborg (unsigned long) cpu_new_thread); 363a88b5ba8SSam Ravnborg else 364a88b5ba8SSam Ravnborg #endif 365a88b5ba8SSam Ravnborg prom_startcpu_cpuid(cpu, entry, cookie); 366a88b5ba8SSam Ravnborg } else { 367a88b5ba8SSam Ravnborg struct device_node *dp = of_find_node_by_cpuid(cpu); 368a88b5ba8SSam Ravnborg 369a88b5ba8SSam Ravnborg prom_startcpu(dp->node, entry, cookie); 370a88b5ba8SSam Ravnborg } 371a88b5ba8SSam Ravnborg 372a88b5ba8SSam Ravnborg for (timeout = 0; timeout < 50000; timeout++) { 373a88b5ba8SSam Ravnborg if (callin_flag) 374a88b5ba8SSam Ravnborg break; 375a88b5ba8SSam Ravnborg udelay(100); 376a88b5ba8SSam Ravnborg } 377a88b5ba8SSam Ravnborg 378a88b5ba8SSam Ravnborg if (callin_flag) { 379a88b5ba8SSam Ravnborg ret = 0; 380a88b5ba8SSam Ravnborg } else { 381a88b5ba8SSam Ravnborg printk("Processor %d is stuck.\n", cpu); 382a88b5ba8SSam Ravnborg ret = -ENODEV; 383a88b5ba8SSam Ravnborg } 384a88b5ba8SSam Ravnborg cpu_new_thread = NULL; 385a88b5ba8SSam Ravnborg 386a88b5ba8SSam Ravnborg if (tb->hdesc) { 387a88b5ba8SSam Ravnborg kfree(tb->hdesc); 388a88b5ba8SSam Ravnborg tb->hdesc = NULL; 389a88b5ba8SSam Ravnborg } 390a88b5ba8SSam Ravnborg 391a88b5ba8SSam Ravnborg return ret; 392a88b5ba8SSam Ravnborg } 393a88b5ba8SSam Ravnborg 394a88b5ba8SSam Ravnborg static void spitfire_xcall_helper(u64 data0, u64 data1, u64 data2, u64 pstate, unsigned long cpu) 395a88b5ba8SSam Ravnborg { 396a88b5ba8SSam Ravnborg u64 result, target; 397a88b5ba8SSam Ravnborg int stuck, tmp; 398a88b5ba8SSam Ravnborg 399a88b5ba8SSam Ravnborg if (this_is_starfire) { 400a88b5ba8SSam Ravnborg /* map to real upaid */ 401a88b5ba8SSam Ravnborg cpu = (((cpu & 0x3c) << 1) | 402a88b5ba8SSam Ravnborg ((cpu & 0x40) >> 4) | 403a88b5ba8SSam Ravnborg (cpu & 0x3)); 404a88b5ba8SSam Ravnborg } 405a88b5ba8SSam Ravnborg 406a88b5ba8SSam Ravnborg target = (cpu << 14) | 0x70; 407a88b5ba8SSam Ravnborg again: 408a88b5ba8SSam Ravnborg /* Ok, this is the real Spitfire Errata #54. 409a88b5ba8SSam Ravnborg * One must read back from a UDB internal register 410a88b5ba8SSam Ravnborg * after writes to the UDB interrupt dispatch, but 411a88b5ba8SSam Ravnborg * before the membar Sync for that write. 412a88b5ba8SSam Ravnborg * So we use the high UDB control register (ASI 0x7f, 413a88b5ba8SSam Ravnborg * ADDR 0x20) for the dummy read. -DaveM 414a88b5ba8SSam Ravnborg */ 415a88b5ba8SSam Ravnborg tmp = 0x40; 416a88b5ba8SSam Ravnborg __asm__ __volatile__( 417a88b5ba8SSam Ravnborg "wrpr %1, %2, %%pstate\n\t" 418a88b5ba8SSam Ravnborg "stxa %4, [%0] %3\n\t" 419a88b5ba8SSam Ravnborg "stxa %5, [%0+%8] %3\n\t" 420a88b5ba8SSam Ravnborg "add %0, %8, %0\n\t" 421a88b5ba8SSam Ravnborg "stxa %6, [%0+%8] %3\n\t" 422a88b5ba8SSam Ravnborg "membar #Sync\n\t" 423a88b5ba8SSam Ravnborg "stxa %%g0, [%7] %3\n\t" 424a88b5ba8SSam Ravnborg "membar #Sync\n\t" 425a88b5ba8SSam Ravnborg "mov 0x20, %%g1\n\t" 426a88b5ba8SSam Ravnborg "ldxa [%%g1] 0x7f, %%g0\n\t" 427a88b5ba8SSam Ravnborg "membar #Sync" 428a88b5ba8SSam Ravnborg : "=r" (tmp) 429a88b5ba8SSam Ravnborg : "r" (pstate), "i" (PSTATE_IE), "i" (ASI_INTR_W), 430a88b5ba8SSam Ravnborg "r" (data0), "r" (data1), "r" (data2), "r" (target), 431a88b5ba8SSam Ravnborg "r" (0x10), "0" (tmp) 432a88b5ba8SSam Ravnborg : "g1"); 433a88b5ba8SSam Ravnborg 434a88b5ba8SSam Ravnborg /* NOTE: PSTATE_IE is still clear. */ 435a88b5ba8SSam Ravnborg stuck = 100000; 436a88b5ba8SSam Ravnborg do { 437a88b5ba8SSam Ravnborg __asm__ __volatile__("ldxa [%%g0] %1, %0" 438a88b5ba8SSam Ravnborg : "=r" (result) 439a88b5ba8SSam Ravnborg : "i" (ASI_INTR_DISPATCH_STAT)); 440a88b5ba8SSam Ravnborg if (result == 0) { 441a88b5ba8SSam Ravnborg __asm__ __volatile__("wrpr %0, 0x0, %%pstate" 442a88b5ba8SSam Ravnborg : : "r" (pstate)); 443a88b5ba8SSam Ravnborg return; 444a88b5ba8SSam Ravnborg } 445a88b5ba8SSam Ravnborg stuck -= 1; 446a88b5ba8SSam Ravnborg if (stuck == 0) 447a88b5ba8SSam Ravnborg break; 448a88b5ba8SSam Ravnborg } while (result & 0x1); 449a88b5ba8SSam Ravnborg __asm__ __volatile__("wrpr %0, 0x0, %%pstate" 450a88b5ba8SSam Ravnborg : : "r" (pstate)); 451a88b5ba8SSam Ravnborg if (stuck == 0) { 45290181136SSam Ravnborg printk("CPU[%d]: mondo stuckage result[%016llx]\n", 453a88b5ba8SSam Ravnborg smp_processor_id(), result); 454a88b5ba8SSam Ravnborg } else { 455a88b5ba8SSam Ravnborg udelay(2); 456a88b5ba8SSam Ravnborg goto again; 457a88b5ba8SSam Ravnborg } 458a88b5ba8SSam Ravnborg } 459a88b5ba8SSam Ravnborg 460a88b5ba8SSam Ravnborg static void spitfire_xcall_deliver(struct trap_per_cpu *tb, int cnt) 461a88b5ba8SSam Ravnborg { 462a88b5ba8SSam Ravnborg u64 *mondo, data0, data1, data2; 463a88b5ba8SSam Ravnborg u16 *cpu_list; 464a88b5ba8SSam Ravnborg u64 pstate; 465a88b5ba8SSam Ravnborg int i; 466a88b5ba8SSam Ravnborg 467a88b5ba8SSam Ravnborg __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); 468a88b5ba8SSam Ravnborg cpu_list = __va(tb->cpu_list_pa); 469a88b5ba8SSam Ravnborg mondo = __va(tb->cpu_mondo_block_pa); 470a88b5ba8SSam Ravnborg data0 = mondo[0]; 471a88b5ba8SSam Ravnborg data1 = mondo[1]; 472a88b5ba8SSam Ravnborg data2 = mondo[2]; 473a88b5ba8SSam Ravnborg for (i = 0; i < cnt; i++) 474a88b5ba8SSam Ravnborg spitfire_xcall_helper(data0, data1, data2, pstate, cpu_list[i]); 475a88b5ba8SSam Ravnborg } 476a88b5ba8SSam Ravnborg 477a88b5ba8SSam Ravnborg /* Cheetah now allows to send the whole 64-bytes of data in the interrupt 478a88b5ba8SSam Ravnborg * packet, but we have no use for that. However we do take advantage of 479a88b5ba8SSam Ravnborg * the new pipelining feature (ie. dispatch to multiple cpus simultaneously). 480a88b5ba8SSam Ravnborg */ 481a88b5ba8SSam Ravnborg static void cheetah_xcall_deliver(struct trap_per_cpu *tb, int cnt) 482a88b5ba8SSam Ravnborg { 483a88b5ba8SSam Ravnborg int nack_busy_id, is_jbus, need_more; 484a88b5ba8SSam Ravnborg u64 *mondo, pstate, ver, busy_mask; 485a88b5ba8SSam Ravnborg u16 *cpu_list; 486a88b5ba8SSam Ravnborg 487a88b5ba8SSam Ravnborg cpu_list = __va(tb->cpu_list_pa); 488a88b5ba8SSam Ravnborg mondo = __va(tb->cpu_mondo_block_pa); 489a88b5ba8SSam Ravnborg 490a88b5ba8SSam Ravnborg /* Unfortunately, someone at Sun had the brilliant idea to make the 491a88b5ba8SSam Ravnborg * busy/nack fields hard-coded by ITID number for this Ultra-III 492a88b5ba8SSam Ravnborg * derivative processor. 493a88b5ba8SSam Ravnborg */ 494a88b5ba8SSam Ravnborg __asm__ ("rdpr %%ver, %0" : "=r" (ver)); 495a88b5ba8SSam Ravnborg is_jbus = ((ver >> 32) == __JALAPENO_ID || 496a88b5ba8SSam Ravnborg (ver >> 32) == __SERRANO_ID); 497a88b5ba8SSam Ravnborg 498a88b5ba8SSam Ravnborg __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); 499a88b5ba8SSam Ravnborg 500a88b5ba8SSam Ravnborg retry: 501a88b5ba8SSam Ravnborg need_more = 0; 502a88b5ba8SSam Ravnborg __asm__ __volatile__("wrpr %0, %1, %%pstate\n\t" 503a88b5ba8SSam Ravnborg : : "r" (pstate), "i" (PSTATE_IE)); 504a88b5ba8SSam Ravnborg 505a88b5ba8SSam Ravnborg /* Setup the dispatch data registers. */ 506a88b5ba8SSam Ravnborg __asm__ __volatile__("stxa %0, [%3] %6\n\t" 507a88b5ba8SSam Ravnborg "stxa %1, [%4] %6\n\t" 508a88b5ba8SSam Ravnborg "stxa %2, [%5] %6\n\t" 509a88b5ba8SSam Ravnborg "membar #Sync\n\t" 510a88b5ba8SSam Ravnborg : /* no outputs */ 511a88b5ba8SSam Ravnborg : "r" (mondo[0]), "r" (mondo[1]), "r" (mondo[2]), 512a88b5ba8SSam Ravnborg "r" (0x40), "r" (0x50), "r" (0x60), 513a88b5ba8SSam Ravnborg "i" (ASI_INTR_W)); 514a88b5ba8SSam Ravnborg 515a88b5ba8SSam Ravnborg nack_busy_id = 0; 516a88b5ba8SSam Ravnborg busy_mask = 0; 517a88b5ba8SSam Ravnborg { 518a88b5ba8SSam Ravnborg int i; 519a88b5ba8SSam Ravnborg 520a88b5ba8SSam Ravnborg for (i = 0; i < cnt; i++) { 521a88b5ba8SSam Ravnborg u64 target, nr; 522a88b5ba8SSam Ravnborg 523a88b5ba8SSam Ravnborg nr = cpu_list[i]; 524a88b5ba8SSam Ravnborg if (nr == 0xffff) 525a88b5ba8SSam Ravnborg continue; 526a88b5ba8SSam Ravnborg 527a88b5ba8SSam Ravnborg target = (nr << 14) | 0x70; 528a88b5ba8SSam Ravnborg if (is_jbus) { 529a88b5ba8SSam Ravnborg busy_mask |= (0x1UL << (nr * 2)); 530a88b5ba8SSam Ravnborg } else { 531a88b5ba8SSam Ravnborg target |= (nack_busy_id << 24); 532a88b5ba8SSam Ravnborg busy_mask |= (0x1UL << 533a88b5ba8SSam Ravnborg (nack_busy_id * 2)); 534a88b5ba8SSam Ravnborg } 535a88b5ba8SSam Ravnborg __asm__ __volatile__( 536a88b5ba8SSam Ravnborg "stxa %%g0, [%0] %1\n\t" 537a88b5ba8SSam Ravnborg "membar #Sync\n\t" 538a88b5ba8SSam Ravnborg : /* no outputs */ 539a88b5ba8SSam Ravnborg : "r" (target), "i" (ASI_INTR_W)); 540a88b5ba8SSam Ravnborg nack_busy_id++; 541a88b5ba8SSam Ravnborg if (nack_busy_id == 32) { 542a88b5ba8SSam Ravnborg need_more = 1; 543a88b5ba8SSam Ravnborg break; 544a88b5ba8SSam Ravnborg } 545a88b5ba8SSam Ravnborg } 546a88b5ba8SSam Ravnborg } 547a88b5ba8SSam Ravnborg 548a88b5ba8SSam Ravnborg /* Now, poll for completion. */ 549a88b5ba8SSam Ravnborg { 550a88b5ba8SSam Ravnborg u64 dispatch_stat, nack_mask; 551a88b5ba8SSam Ravnborg long stuck; 552a88b5ba8SSam Ravnborg 553a88b5ba8SSam Ravnborg stuck = 100000 * nack_busy_id; 554a88b5ba8SSam Ravnborg nack_mask = busy_mask << 1; 555a88b5ba8SSam Ravnborg do { 556a88b5ba8SSam Ravnborg __asm__ __volatile__("ldxa [%%g0] %1, %0" 557a88b5ba8SSam Ravnborg : "=r" (dispatch_stat) 558a88b5ba8SSam Ravnborg : "i" (ASI_INTR_DISPATCH_STAT)); 559a88b5ba8SSam Ravnborg if (!(dispatch_stat & (busy_mask | nack_mask))) { 560a88b5ba8SSam Ravnborg __asm__ __volatile__("wrpr %0, 0x0, %%pstate" 561a88b5ba8SSam Ravnborg : : "r" (pstate)); 562a88b5ba8SSam Ravnborg if (unlikely(need_more)) { 563a88b5ba8SSam Ravnborg int i, this_cnt = 0; 564a88b5ba8SSam Ravnborg for (i = 0; i < cnt; i++) { 565a88b5ba8SSam Ravnborg if (cpu_list[i] == 0xffff) 566a88b5ba8SSam Ravnborg continue; 567a88b5ba8SSam Ravnborg cpu_list[i] = 0xffff; 568a88b5ba8SSam Ravnborg this_cnt++; 569a88b5ba8SSam Ravnborg if (this_cnt == 32) 570a88b5ba8SSam Ravnborg break; 571a88b5ba8SSam Ravnborg } 572a88b5ba8SSam Ravnborg goto retry; 573a88b5ba8SSam Ravnborg } 574a88b5ba8SSam Ravnborg return; 575a88b5ba8SSam Ravnborg } 576a88b5ba8SSam Ravnborg if (!--stuck) 577a88b5ba8SSam Ravnborg break; 578a88b5ba8SSam Ravnborg } while (dispatch_stat & busy_mask); 579a88b5ba8SSam Ravnborg 580a88b5ba8SSam Ravnborg __asm__ __volatile__("wrpr %0, 0x0, %%pstate" 581a88b5ba8SSam Ravnborg : : "r" (pstate)); 582a88b5ba8SSam Ravnborg 583a88b5ba8SSam Ravnborg if (dispatch_stat & busy_mask) { 584a88b5ba8SSam Ravnborg /* Busy bits will not clear, continue instead 585a88b5ba8SSam Ravnborg * of freezing up on this cpu. 586a88b5ba8SSam Ravnborg */ 58790181136SSam Ravnborg printk("CPU[%d]: mondo stuckage result[%016llx]\n", 588a88b5ba8SSam Ravnborg smp_processor_id(), dispatch_stat); 589a88b5ba8SSam Ravnborg } else { 590a88b5ba8SSam Ravnborg int i, this_busy_nack = 0; 591a88b5ba8SSam Ravnborg 592a88b5ba8SSam Ravnborg /* Delay some random time with interrupts enabled 593a88b5ba8SSam Ravnborg * to prevent deadlock. 594a88b5ba8SSam Ravnborg */ 595a88b5ba8SSam Ravnborg udelay(2 * nack_busy_id); 596a88b5ba8SSam Ravnborg 597a88b5ba8SSam Ravnborg /* Clear out the mask bits for cpus which did not 598a88b5ba8SSam Ravnborg * NACK us. 599a88b5ba8SSam Ravnborg */ 600a88b5ba8SSam Ravnborg for (i = 0; i < cnt; i++) { 601a88b5ba8SSam Ravnborg u64 check_mask, nr; 602a88b5ba8SSam Ravnborg 603a88b5ba8SSam Ravnborg nr = cpu_list[i]; 604a88b5ba8SSam Ravnborg if (nr == 0xffff) 605a88b5ba8SSam Ravnborg continue; 606a88b5ba8SSam Ravnborg 607a88b5ba8SSam Ravnborg if (is_jbus) 608a88b5ba8SSam Ravnborg check_mask = (0x2UL << (2*nr)); 609a88b5ba8SSam Ravnborg else 610a88b5ba8SSam Ravnborg check_mask = (0x2UL << 611a88b5ba8SSam Ravnborg this_busy_nack); 612a88b5ba8SSam Ravnborg if ((dispatch_stat & check_mask) == 0) 613a88b5ba8SSam Ravnborg cpu_list[i] = 0xffff; 614a88b5ba8SSam Ravnborg this_busy_nack += 2; 615a88b5ba8SSam Ravnborg if (this_busy_nack == 64) 616a88b5ba8SSam Ravnborg break; 617a88b5ba8SSam Ravnborg } 618a88b5ba8SSam Ravnborg 619a88b5ba8SSam Ravnborg goto retry; 620a88b5ba8SSam Ravnborg } 621a88b5ba8SSam Ravnborg } 622a88b5ba8SSam Ravnborg } 623a88b5ba8SSam Ravnborg 624a88b5ba8SSam Ravnborg /* Multi-cpu list version. */ 625a88b5ba8SSam Ravnborg static void hypervisor_xcall_deliver(struct trap_per_cpu *tb, int cnt) 626a88b5ba8SSam Ravnborg { 627a88b5ba8SSam Ravnborg int retries, this_cpu, prev_sent, i, saw_cpu_error; 628a88b5ba8SSam Ravnborg unsigned long status; 629a88b5ba8SSam Ravnborg u16 *cpu_list; 630a88b5ba8SSam Ravnborg 631a88b5ba8SSam Ravnborg this_cpu = smp_processor_id(); 632a88b5ba8SSam Ravnborg 633a88b5ba8SSam Ravnborg cpu_list = __va(tb->cpu_list_pa); 634a88b5ba8SSam Ravnborg 635a88b5ba8SSam Ravnborg saw_cpu_error = 0; 636a88b5ba8SSam Ravnborg retries = 0; 637a88b5ba8SSam Ravnborg prev_sent = 0; 638a88b5ba8SSam Ravnborg do { 639a88b5ba8SSam Ravnborg int forward_progress, n_sent; 640a88b5ba8SSam Ravnborg 641a88b5ba8SSam Ravnborg status = sun4v_cpu_mondo_send(cnt, 642a88b5ba8SSam Ravnborg tb->cpu_list_pa, 643a88b5ba8SSam Ravnborg tb->cpu_mondo_block_pa); 644a88b5ba8SSam Ravnborg 645a88b5ba8SSam Ravnborg /* HV_EOK means all cpus received the xcall, we're done. */ 646a88b5ba8SSam Ravnborg if (likely(status == HV_EOK)) 647a88b5ba8SSam Ravnborg break; 648a88b5ba8SSam Ravnborg 649a88b5ba8SSam Ravnborg /* First, see if we made any forward progress. 650a88b5ba8SSam Ravnborg * 651a88b5ba8SSam Ravnborg * The hypervisor indicates successful sends by setting 652a88b5ba8SSam Ravnborg * cpu list entries to the value 0xffff. 653a88b5ba8SSam Ravnborg */ 654a88b5ba8SSam Ravnborg n_sent = 0; 655a88b5ba8SSam Ravnborg for (i = 0; i < cnt; i++) { 656a88b5ba8SSam Ravnborg if (likely(cpu_list[i] == 0xffff)) 657a88b5ba8SSam Ravnborg n_sent++; 658a88b5ba8SSam Ravnborg } 659a88b5ba8SSam Ravnborg 660a88b5ba8SSam Ravnborg forward_progress = 0; 661a88b5ba8SSam Ravnborg if (n_sent > prev_sent) 662a88b5ba8SSam Ravnborg forward_progress = 1; 663a88b5ba8SSam Ravnborg 664a88b5ba8SSam Ravnborg prev_sent = n_sent; 665a88b5ba8SSam Ravnborg 666a88b5ba8SSam Ravnborg /* If we get a HV_ECPUERROR, then one or more of the cpus 667a88b5ba8SSam Ravnborg * in the list are in error state. Use the cpu_state() 668a88b5ba8SSam Ravnborg * hypervisor call to find out which cpus are in error state. 669a88b5ba8SSam Ravnborg */ 670a88b5ba8SSam Ravnborg if (unlikely(status == HV_ECPUERROR)) { 671a88b5ba8SSam Ravnborg for (i = 0; i < cnt; i++) { 672a88b5ba8SSam Ravnborg long err; 673a88b5ba8SSam Ravnborg u16 cpu; 674a88b5ba8SSam Ravnborg 675a88b5ba8SSam Ravnborg cpu = cpu_list[i]; 676a88b5ba8SSam Ravnborg if (cpu == 0xffff) 677a88b5ba8SSam Ravnborg continue; 678a88b5ba8SSam Ravnborg 679a88b5ba8SSam Ravnborg err = sun4v_cpu_state(cpu); 680a88b5ba8SSam Ravnborg if (err == HV_CPU_STATE_ERROR) { 681a88b5ba8SSam Ravnborg saw_cpu_error = (cpu + 1); 682a88b5ba8SSam Ravnborg cpu_list[i] = 0xffff; 683a88b5ba8SSam Ravnborg } 684a88b5ba8SSam Ravnborg } 685a88b5ba8SSam Ravnborg } else if (unlikely(status != HV_EWOULDBLOCK)) 686a88b5ba8SSam Ravnborg goto fatal_mondo_error; 687a88b5ba8SSam Ravnborg 688a88b5ba8SSam Ravnborg /* Don't bother rewriting the CPU list, just leave the 689a88b5ba8SSam Ravnborg * 0xffff and non-0xffff entries in there and the 690a88b5ba8SSam Ravnborg * hypervisor will do the right thing. 691a88b5ba8SSam Ravnborg * 692a88b5ba8SSam Ravnborg * Only advance timeout state if we didn't make any 693a88b5ba8SSam Ravnborg * forward progress. 694a88b5ba8SSam Ravnborg */ 695a88b5ba8SSam Ravnborg if (unlikely(!forward_progress)) { 696a88b5ba8SSam Ravnborg if (unlikely(++retries > 10000)) 697a88b5ba8SSam Ravnborg goto fatal_mondo_timeout; 698a88b5ba8SSam Ravnborg 699a88b5ba8SSam Ravnborg /* Delay a little bit to let other cpus catch up 700a88b5ba8SSam Ravnborg * on their cpu mondo queue work. 701a88b5ba8SSam Ravnborg */ 702a88b5ba8SSam Ravnborg udelay(2 * cnt); 703a88b5ba8SSam Ravnborg } 704a88b5ba8SSam Ravnborg } while (1); 705a88b5ba8SSam Ravnborg 706a88b5ba8SSam Ravnborg if (unlikely(saw_cpu_error)) 707a88b5ba8SSam Ravnborg goto fatal_mondo_cpu_error; 708a88b5ba8SSam Ravnborg 709a88b5ba8SSam Ravnborg return; 710a88b5ba8SSam Ravnborg 711a88b5ba8SSam Ravnborg fatal_mondo_cpu_error: 712a88b5ba8SSam Ravnborg printk(KERN_CRIT "CPU[%d]: SUN4V mondo cpu error, some target cpus " 713a88b5ba8SSam Ravnborg "(including %d) were in error state\n", 714a88b5ba8SSam Ravnborg this_cpu, saw_cpu_error - 1); 715a88b5ba8SSam Ravnborg return; 716a88b5ba8SSam Ravnborg 717a88b5ba8SSam Ravnborg fatal_mondo_timeout: 718a88b5ba8SSam Ravnborg printk(KERN_CRIT "CPU[%d]: SUN4V mondo timeout, no forward " 719a88b5ba8SSam Ravnborg " progress after %d retries.\n", 720a88b5ba8SSam Ravnborg this_cpu, retries); 721a88b5ba8SSam Ravnborg goto dump_cpu_list_and_out; 722a88b5ba8SSam Ravnborg 723a88b5ba8SSam Ravnborg fatal_mondo_error: 724a88b5ba8SSam Ravnborg printk(KERN_CRIT "CPU[%d]: Unexpected SUN4V mondo error %lu\n", 725a88b5ba8SSam Ravnborg this_cpu, status); 726a88b5ba8SSam Ravnborg printk(KERN_CRIT "CPU[%d]: Args were cnt(%d) cpulist_pa(%lx) " 727a88b5ba8SSam Ravnborg "mondo_block_pa(%lx)\n", 728a88b5ba8SSam Ravnborg this_cpu, cnt, tb->cpu_list_pa, tb->cpu_mondo_block_pa); 729a88b5ba8SSam Ravnborg 730a88b5ba8SSam Ravnborg dump_cpu_list_and_out: 731a88b5ba8SSam Ravnborg printk(KERN_CRIT "CPU[%d]: CPU list [ ", this_cpu); 732a88b5ba8SSam Ravnborg for (i = 0; i < cnt; i++) 733a88b5ba8SSam Ravnborg printk("%u ", cpu_list[i]); 734a88b5ba8SSam Ravnborg printk("]\n"); 735a88b5ba8SSam Ravnborg } 736a88b5ba8SSam Ravnborg 737a88b5ba8SSam Ravnborg static void (*xcall_deliver_impl)(struct trap_per_cpu *, int); 738a88b5ba8SSam Ravnborg 739a88b5ba8SSam Ravnborg static void xcall_deliver(u64 data0, u64 data1, u64 data2, const cpumask_t *mask) 740a88b5ba8SSam Ravnborg { 741a88b5ba8SSam Ravnborg struct trap_per_cpu *tb; 742a88b5ba8SSam Ravnborg int this_cpu, i, cnt; 743a88b5ba8SSam Ravnborg unsigned long flags; 744a88b5ba8SSam Ravnborg u16 *cpu_list; 745a88b5ba8SSam Ravnborg u64 *mondo; 746a88b5ba8SSam Ravnborg 747a88b5ba8SSam Ravnborg /* We have to do this whole thing with interrupts fully disabled. 748a88b5ba8SSam Ravnborg * Otherwise if we send an xcall from interrupt context it will 749a88b5ba8SSam Ravnborg * corrupt both our mondo block and cpu list state. 750a88b5ba8SSam Ravnborg * 751a88b5ba8SSam Ravnborg * One consequence of this is that we cannot use timeout mechanisms 752a88b5ba8SSam Ravnborg * that depend upon interrupts being delivered locally. So, for 753a88b5ba8SSam Ravnborg * example, we cannot sample jiffies and expect it to advance. 754a88b5ba8SSam Ravnborg * 755a88b5ba8SSam Ravnborg * Fortunately, udelay() uses %stick/%tick so we can use that. 756a88b5ba8SSam Ravnborg */ 757a88b5ba8SSam Ravnborg local_irq_save(flags); 758a88b5ba8SSam Ravnborg 759a88b5ba8SSam Ravnborg this_cpu = smp_processor_id(); 760a88b5ba8SSam Ravnborg tb = &trap_block[this_cpu]; 761a88b5ba8SSam Ravnborg 762a88b5ba8SSam Ravnborg mondo = __va(tb->cpu_mondo_block_pa); 763a88b5ba8SSam Ravnborg mondo[0] = data0; 764a88b5ba8SSam Ravnborg mondo[1] = data1; 765a88b5ba8SSam Ravnborg mondo[2] = data2; 766a88b5ba8SSam Ravnborg wmb(); 767a88b5ba8SSam Ravnborg 768a88b5ba8SSam Ravnborg cpu_list = __va(tb->cpu_list_pa); 769a88b5ba8SSam Ravnborg 770a88b5ba8SSam Ravnborg /* Setup the initial cpu list. */ 771a88b5ba8SSam Ravnborg cnt = 0; 7728e757281SRusty Russell for_each_cpu(i, mask) { 773a88b5ba8SSam Ravnborg if (i == this_cpu || !cpu_online(i)) 774a88b5ba8SSam Ravnborg continue; 775a88b5ba8SSam Ravnborg cpu_list[cnt++] = i; 776a88b5ba8SSam Ravnborg } 777a88b5ba8SSam Ravnborg 778a88b5ba8SSam Ravnborg if (cnt) 779a88b5ba8SSam Ravnborg xcall_deliver_impl(tb, cnt); 780a88b5ba8SSam Ravnborg 781a88b5ba8SSam Ravnborg local_irq_restore(flags); 782a88b5ba8SSam Ravnborg } 783a88b5ba8SSam Ravnborg 784a88b5ba8SSam Ravnborg /* Send cross call to all processors mentioned in MASK_P 785a88b5ba8SSam Ravnborg * except self. Really, there are only two cases currently, 786a88b5ba8SSam Ravnborg * "&cpu_online_map" and "&mm->cpu_vm_mask". 787a88b5ba8SSam Ravnborg */ 788a88b5ba8SSam Ravnborg static void smp_cross_call_masked(unsigned long *func, u32 ctx, u64 data1, u64 data2, const cpumask_t *mask) 789a88b5ba8SSam Ravnborg { 790a88b5ba8SSam Ravnborg u64 data0 = (((u64)ctx)<<32 | (((u64)func) & 0xffffffff)); 791a88b5ba8SSam Ravnborg 792a88b5ba8SSam Ravnborg xcall_deliver(data0, data1, data2, mask); 793a88b5ba8SSam Ravnborg } 794a88b5ba8SSam Ravnborg 795a88b5ba8SSam Ravnborg /* Send cross call to all processors except self. */ 796a88b5ba8SSam Ravnborg static void smp_cross_call(unsigned long *func, u32 ctx, u64 data1, u64 data2) 797a88b5ba8SSam Ravnborg { 798a88b5ba8SSam Ravnborg smp_cross_call_masked(func, ctx, data1, data2, &cpu_online_map); 799a88b5ba8SSam Ravnborg } 800a88b5ba8SSam Ravnborg 801a88b5ba8SSam Ravnborg extern unsigned long xcall_sync_tick; 802a88b5ba8SSam Ravnborg 803a88b5ba8SSam Ravnborg static void smp_start_sync_tick_client(int cpu) 804a88b5ba8SSam Ravnborg { 805a88b5ba8SSam Ravnborg xcall_deliver((u64) &xcall_sync_tick, 0, 0, 806a88b5ba8SSam Ravnborg &cpumask_of_cpu(cpu)); 807a88b5ba8SSam Ravnborg } 808a88b5ba8SSam Ravnborg 809a88b5ba8SSam Ravnborg extern unsigned long xcall_call_function; 810a88b5ba8SSam Ravnborg 811f46df02aSRusty Russell void arch_send_call_function_ipi_mask(const struct cpumask *mask) 812a88b5ba8SSam Ravnborg { 813f46df02aSRusty Russell xcall_deliver((u64) &xcall_call_function, 0, 0, mask); 814a88b5ba8SSam Ravnborg } 815a88b5ba8SSam Ravnborg 816a88b5ba8SSam Ravnborg extern unsigned long xcall_call_function_single; 817a88b5ba8SSam Ravnborg 818a88b5ba8SSam Ravnborg void arch_send_call_function_single_ipi(int cpu) 819a88b5ba8SSam Ravnborg { 820a88b5ba8SSam Ravnborg xcall_deliver((u64) &xcall_call_function_single, 0, 0, 821a88b5ba8SSam Ravnborg &cpumask_of_cpu(cpu)); 822a88b5ba8SSam Ravnborg } 823a88b5ba8SSam Ravnborg 824a88b5ba8SSam Ravnborg void smp_call_function_client(int irq, struct pt_regs *regs) 825a88b5ba8SSam Ravnborg { 826a88b5ba8SSam Ravnborg clear_softint(1 << irq); 827a88b5ba8SSam Ravnborg generic_smp_call_function_interrupt(); 828a88b5ba8SSam Ravnborg } 829a88b5ba8SSam Ravnborg 830a88b5ba8SSam Ravnborg void smp_call_function_single_client(int irq, struct pt_regs *regs) 831a88b5ba8SSam Ravnborg { 832a88b5ba8SSam Ravnborg clear_softint(1 << irq); 833a88b5ba8SSam Ravnborg generic_smp_call_function_single_interrupt(); 834a88b5ba8SSam Ravnborg } 835a88b5ba8SSam Ravnborg 836a88b5ba8SSam Ravnborg static void tsb_sync(void *info) 837a88b5ba8SSam Ravnborg { 838a88b5ba8SSam Ravnborg struct trap_per_cpu *tp = &trap_block[raw_smp_processor_id()]; 839a88b5ba8SSam Ravnborg struct mm_struct *mm = info; 840a88b5ba8SSam Ravnborg 841a88b5ba8SSam Ravnborg /* It is not valid to test "currrent->active_mm == mm" here. 842a88b5ba8SSam Ravnborg * 843a88b5ba8SSam Ravnborg * The value of "current" is not changed atomically with 844a88b5ba8SSam Ravnborg * switch_mm(). But that's OK, we just need to check the 845a88b5ba8SSam Ravnborg * current cpu's trap block PGD physical address. 846a88b5ba8SSam Ravnborg */ 847a88b5ba8SSam Ravnborg if (tp->pgd_paddr == __pa(mm->pgd)) 848a88b5ba8SSam Ravnborg tsb_context_switch(mm); 849a88b5ba8SSam Ravnborg } 850a88b5ba8SSam Ravnborg 851a88b5ba8SSam Ravnborg void smp_tsb_sync(struct mm_struct *mm) 852a88b5ba8SSam Ravnborg { 853*81f1adf0SRusty Russell smp_call_function_many(mm_cpumask(mm), tsb_sync, mm, 1); 854a88b5ba8SSam Ravnborg } 855a88b5ba8SSam Ravnborg 856a88b5ba8SSam Ravnborg extern unsigned long xcall_flush_tlb_mm; 857a88b5ba8SSam Ravnborg extern unsigned long xcall_flush_tlb_pending; 858a88b5ba8SSam Ravnborg extern unsigned long xcall_flush_tlb_kernel_range; 859a88b5ba8SSam Ravnborg extern unsigned long xcall_fetch_glob_regs; 860a88b5ba8SSam Ravnborg extern unsigned long xcall_receive_signal; 861a88b5ba8SSam Ravnborg extern unsigned long xcall_new_mmu_context_version; 862a88b5ba8SSam Ravnborg #ifdef CONFIG_KGDB 863a88b5ba8SSam Ravnborg extern unsigned long xcall_kgdb_capture; 864a88b5ba8SSam Ravnborg #endif 865a88b5ba8SSam Ravnborg 866a88b5ba8SSam Ravnborg #ifdef DCACHE_ALIASING_POSSIBLE 867a88b5ba8SSam Ravnborg extern unsigned long xcall_flush_dcache_page_cheetah; 868a88b5ba8SSam Ravnborg #endif 869a88b5ba8SSam Ravnborg extern unsigned long xcall_flush_dcache_page_spitfire; 870a88b5ba8SSam Ravnborg 871a88b5ba8SSam Ravnborg #ifdef CONFIG_DEBUG_DCFLUSH 872a88b5ba8SSam Ravnborg extern atomic_t dcpage_flushes; 873a88b5ba8SSam Ravnborg extern atomic_t dcpage_flushes_xcall; 874a88b5ba8SSam Ravnborg #endif 875a88b5ba8SSam Ravnborg 876a88b5ba8SSam Ravnborg static inline void __local_flush_dcache_page(struct page *page) 877a88b5ba8SSam Ravnborg { 878a88b5ba8SSam Ravnborg #ifdef DCACHE_ALIASING_POSSIBLE 879a88b5ba8SSam Ravnborg __flush_dcache_page(page_address(page), 880a88b5ba8SSam Ravnborg ((tlb_type == spitfire) && 881a88b5ba8SSam Ravnborg page_mapping(page) != NULL)); 882a88b5ba8SSam Ravnborg #else 883a88b5ba8SSam Ravnborg if (page_mapping(page) != NULL && 884a88b5ba8SSam Ravnborg tlb_type == spitfire) 885a88b5ba8SSam Ravnborg __flush_icache_page(__pa(page_address(page))); 886a88b5ba8SSam Ravnborg #endif 887a88b5ba8SSam Ravnborg } 888a88b5ba8SSam Ravnborg 889a88b5ba8SSam Ravnborg void smp_flush_dcache_page_impl(struct page *page, int cpu) 890a88b5ba8SSam Ravnborg { 891a88b5ba8SSam Ravnborg int this_cpu; 892a88b5ba8SSam Ravnborg 893a88b5ba8SSam Ravnborg if (tlb_type == hypervisor) 894a88b5ba8SSam Ravnborg return; 895a88b5ba8SSam Ravnborg 896a88b5ba8SSam Ravnborg #ifdef CONFIG_DEBUG_DCFLUSH 897a88b5ba8SSam Ravnborg atomic_inc(&dcpage_flushes); 898a88b5ba8SSam Ravnborg #endif 899a88b5ba8SSam Ravnborg 900a88b5ba8SSam Ravnborg this_cpu = get_cpu(); 901a88b5ba8SSam Ravnborg 902a88b5ba8SSam Ravnborg if (cpu == this_cpu) { 903a88b5ba8SSam Ravnborg __local_flush_dcache_page(page); 904a88b5ba8SSam Ravnborg } else if (cpu_online(cpu)) { 905a88b5ba8SSam Ravnborg void *pg_addr = page_address(page); 906a88b5ba8SSam Ravnborg u64 data0 = 0; 907a88b5ba8SSam Ravnborg 908a88b5ba8SSam Ravnborg if (tlb_type == spitfire) { 909a88b5ba8SSam Ravnborg data0 = ((u64)&xcall_flush_dcache_page_spitfire); 910a88b5ba8SSam Ravnborg if (page_mapping(page) != NULL) 911a88b5ba8SSam Ravnborg data0 |= ((u64)1 << 32); 912a88b5ba8SSam Ravnborg } else if (tlb_type == cheetah || tlb_type == cheetah_plus) { 913a88b5ba8SSam Ravnborg #ifdef DCACHE_ALIASING_POSSIBLE 914a88b5ba8SSam Ravnborg data0 = ((u64)&xcall_flush_dcache_page_cheetah); 915a88b5ba8SSam Ravnborg #endif 916a88b5ba8SSam Ravnborg } 917a88b5ba8SSam Ravnborg if (data0) { 918a88b5ba8SSam Ravnborg xcall_deliver(data0, __pa(pg_addr), 919a88b5ba8SSam Ravnborg (u64) pg_addr, &cpumask_of_cpu(cpu)); 920a88b5ba8SSam Ravnborg #ifdef CONFIG_DEBUG_DCFLUSH 921a88b5ba8SSam Ravnborg atomic_inc(&dcpage_flushes_xcall); 922a88b5ba8SSam Ravnborg #endif 923a88b5ba8SSam Ravnborg } 924a88b5ba8SSam Ravnborg } 925a88b5ba8SSam Ravnborg 926a88b5ba8SSam Ravnborg put_cpu(); 927a88b5ba8SSam Ravnborg } 928a88b5ba8SSam Ravnborg 929a88b5ba8SSam Ravnborg void flush_dcache_page_all(struct mm_struct *mm, struct page *page) 930a88b5ba8SSam Ravnborg { 931a88b5ba8SSam Ravnborg void *pg_addr; 932a88b5ba8SSam Ravnborg int this_cpu; 933a88b5ba8SSam Ravnborg u64 data0; 934a88b5ba8SSam Ravnborg 935a88b5ba8SSam Ravnborg if (tlb_type == hypervisor) 936a88b5ba8SSam Ravnborg return; 937a88b5ba8SSam Ravnborg 938a88b5ba8SSam Ravnborg this_cpu = get_cpu(); 939a88b5ba8SSam Ravnborg 940a88b5ba8SSam Ravnborg #ifdef CONFIG_DEBUG_DCFLUSH 941a88b5ba8SSam Ravnborg atomic_inc(&dcpage_flushes); 942a88b5ba8SSam Ravnborg #endif 943a88b5ba8SSam Ravnborg data0 = 0; 944a88b5ba8SSam Ravnborg pg_addr = page_address(page); 945a88b5ba8SSam Ravnborg if (tlb_type == spitfire) { 946a88b5ba8SSam Ravnborg data0 = ((u64)&xcall_flush_dcache_page_spitfire); 947a88b5ba8SSam Ravnborg if (page_mapping(page) != NULL) 948a88b5ba8SSam Ravnborg data0 |= ((u64)1 << 32); 949a88b5ba8SSam Ravnborg } else if (tlb_type == cheetah || tlb_type == cheetah_plus) { 950a88b5ba8SSam Ravnborg #ifdef DCACHE_ALIASING_POSSIBLE 951a88b5ba8SSam Ravnborg data0 = ((u64)&xcall_flush_dcache_page_cheetah); 952a88b5ba8SSam Ravnborg #endif 953a88b5ba8SSam Ravnborg } 954a88b5ba8SSam Ravnborg if (data0) { 955a88b5ba8SSam Ravnborg xcall_deliver(data0, __pa(pg_addr), 956a88b5ba8SSam Ravnborg (u64) pg_addr, &cpu_online_map); 957a88b5ba8SSam Ravnborg #ifdef CONFIG_DEBUG_DCFLUSH 958a88b5ba8SSam Ravnborg atomic_inc(&dcpage_flushes_xcall); 959a88b5ba8SSam Ravnborg #endif 960a88b5ba8SSam Ravnborg } 961a88b5ba8SSam Ravnborg __local_flush_dcache_page(page); 962a88b5ba8SSam Ravnborg 963a88b5ba8SSam Ravnborg put_cpu(); 964a88b5ba8SSam Ravnborg } 965a88b5ba8SSam Ravnborg 966a88b5ba8SSam Ravnborg void smp_new_mmu_context_version_client(int irq, struct pt_regs *regs) 967a88b5ba8SSam Ravnborg { 968a88b5ba8SSam Ravnborg struct mm_struct *mm; 969a88b5ba8SSam Ravnborg unsigned long flags; 970a88b5ba8SSam Ravnborg 971a88b5ba8SSam Ravnborg clear_softint(1 << irq); 972a88b5ba8SSam Ravnborg 973a88b5ba8SSam Ravnborg /* See if we need to allocate a new TLB context because 974a88b5ba8SSam Ravnborg * the version of the one we are using is now out of date. 975a88b5ba8SSam Ravnborg */ 976a88b5ba8SSam Ravnborg mm = current->active_mm; 977a88b5ba8SSam Ravnborg if (unlikely(!mm || (mm == &init_mm))) 978a88b5ba8SSam Ravnborg return; 979a88b5ba8SSam Ravnborg 980a88b5ba8SSam Ravnborg spin_lock_irqsave(&mm->context.lock, flags); 981a88b5ba8SSam Ravnborg 982a88b5ba8SSam Ravnborg if (unlikely(!CTX_VALID(mm->context))) 983a88b5ba8SSam Ravnborg get_new_mmu_context(mm); 984a88b5ba8SSam Ravnborg 985a88b5ba8SSam Ravnborg spin_unlock_irqrestore(&mm->context.lock, flags); 986a88b5ba8SSam Ravnborg 987a88b5ba8SSam Ravnborg load_secondary_context(mm); 988a88b5ba8SSam Ravnborg __flush_tlb_mm(CTX_HWBITS(mm->context), 989a88b5ba8SSam Ravnborg SECONDARY_CONTEXT); 990a88b5ba8SSam Ravnborg } 991a88b5ba8SSam Ravnborg 992a88b5ba8SSam Ravnborg void smp_new_mmu_context_version(void) 993a88b5ba8SSam Ravnborg { 994a88b5ba8SSam Ravnborg smp_cross_call(&xcall_new_mmu_context_version, 0, 0, 0); 995a88b5ba8SSam Ravnborg } 996a88b5ba8SSam Ravnborg 997a88b5ba8SSam Ravnborg #ifdef CONFIG_KGDB 998a88b5ba8SSam Ravnborg void kgdb_roundup_cpus(unsigned long flags) 999a88b5ba8SSam Ravnborg { 1000a88b5ba8SSam Ravnborg smp_cross_call(&xcall_kgdb_capture, 0, 0, 0); 1001a88b5ba8SSam Ravnborg } 1002a88b5ba8SSam Ravnborg #endif 1003a88b5ba8SSam Ravnborg 1004a88b5ba8SSam Ravnborg void smp_fetch_global_regs(void) 1005a88b5ba8SSam Ravnborg { 1006a88b5ba8SSam Ravnborg smp_cross_call(&xcall_fetch_glob_regs, 0, 0, 0); 1007a88b5ba8SSam Ravnborg } 1008a88b5ba8SSam Ravnborg 1009a88b5ba8SSam Ravnborg /* We know that the window frames of the user have been flushed 1010a88b5ba8SSam Ravnborg * to the stack before we get here because all callers of us 1011a88b5ba8SSam Ravnborg * are flush_tlb_*() routines, and these run after flush_cache_*() 1012a88b5ba8SSam Ravnborg * which performs the flushw. 1013a88b5ba8SSam Ravnborg * 1014a88b5ba8SSam Ravnborg * The SMP TLB coherency scheme we use works as follows: 1015a88b5ba8SSam Ravnborg * 1016a88b5ba8SSam Ravnborg * 1) mm->cpu_vm_mask is a bit mask of which cpus an address 1017a88b5ba8SSam Ravnborg * space has (potentially) executed on, this is the heuristic 1018a88b5ba8SSam Ravnborg * we use to avoid doing cross calls. 1019a88b5ba8SSam Ravnborg * 1020a88b5ba8SSam Ravnborg * Also, for flushing from kswapd and also for clones, we 1021a88b5ba8SSam Ravnborg * use cpu_vm_mask as the list of cpus to make run the TLB. 1022a88b5ba8SSam Ravnborg * 1023a88b5ba8SSam Ravnborg * 2) TLB context numbers are shared globally across all processors 1024a88b5ba8SSam Ravnborg * in the system, this allows us to play several games to avoid 1025a88b5ba8SSam Ravnborg * cross calls. 1026a88b5ba8SSam Ravnborg * 1027a88b5ba8SSam Ravnborg * One invariant is that when a cpu switches to a process, and 1028a88b5ba8SSam Ravnborg * that processes tsk->active_mm->cpu_vm_mask does not have the 1029a88b5ba8SSam Ravnborg * current cpu's bit set, that tlb context is flushed locally. 1030a88b5ba8SSam Ravnborg * 1031a88b5ba8SSam Ravnborg * If the address space is non-shared (ie. mm->count == 1) we avoid 1032a88b5ba8SSam Ravnborg * cross calls when we want to flush the currently running process's 1033a88b5ba8SSam Ravnborg * tlb state. This is done by clearing all cpu bits except the current 1034a88b5ba8SSam Ravnborg * processor's in current->active_mm->cpu_vm_mask and performing the 1035a88b5ba8SSam Ravnborg * flush locally only. This will force any subsequent cpus which run 1036a88b5ba8SSam Ravnborg * this task to flush the context from the local tlb if the process 1037a88b5ba8SSam Ravnborg * migrates to another cpu (again). 1038a88b5ba8SSam Ravnborg * 1039a88b5ba8SSam Ravnborg * 3) For shared address spaces (threads) and swapping we bite the 1040a88b5ba8SSam Ravnborg * bullet for most cases and perform the cross call (but only to 1041a88b5ba8SSam Ravnborg * the cpus listed in cpu_vm_mask). 1042a88b5ba8SSam Ravnborg * 1043a88b5ba8SSam Ravnborg * The performance gain from "optimizing" away the cross call for threads is 1044a88b5ba8SSam Ravnborg * questionable (in theory the big win for threads is the massive sharing of 1045a88b5ba8SSam Ravnborg * address space state across processors). 1046a88b5ba8SSam Ravnborg */ 1047a88b5ba8SSam Ravnborg 1048a88b5ba8SSam Ravnborg /* This currently is only used by the hugetlb arch pre-fault 1049a88b5ba8SSam Ravnborg * hook on UltraSPARC-III+ and later when changing the pagesize 1050a88b5ba8SSam Ravnborg * bits of the context register for an address space. 1051a88b5ba8SSam Ravnborg */ 1052a88b5ba8SSam Ravnborg void smp_flush_tlb_mm(struct mm_struct *mm) 1053a88b5ba8SSam Ravnborg { 1054a88b5ba8SSam Ravnborg u32 ctx = CTX_HWBITS(mm->context); 1055a88b5ba8SSam Ravnborg int cpu = get_cpu(); 1056a88b5ba8SSam Ravnborg 1057a88b5ba8SSam Ravnborg if (atomic_read(&mm->mm_users) == 1) { 1058*81f1adf0SRusty Russell cpumask_copy(mm_cpumask(mm), cpumask_of(cpu)); 1059a88b5ba8SSam Ravnborg goto local_flush_and_out; 1060a88b5ba8SSam Ravnborg } 1061a88b5ba8SSam Ravnborg 1062a88b5ba8SSam Ravnborg smp_cross_call_masked(&xcall_flush_tlb_mm, 1063a88b5ba8SSam Ravnborg ctx, 0, 0, 1064*81f1adf0SRusty Russell mm_cpumask(mm)); 1065a88b5ba8SSam Ravnborg 1066a88b5ba8SSam Ravnborg local_flush_and_out: 1067a88b5ba8SSam Ravnborg __flush_tlb_mm(ctx, SECONDARY_CONTEXT); 1068a88b5ba8SSam Ravnborg 1069a88b5ba8SSam Ravnborg put_cpu(); 1070a88b5ba8SSam Ravnborg } 1071a88b5ba8SSam Ravnborg 1072a88b5ba8SSam Ravnborg void smp_flush_tlb_pending(struct mm_struct *mm, unsigned long nr, unsigned long *vaddrs) 1073a88b5ba8SSam Ravnborg { 1074a88b5ba8SSam Ravnborg u32 ctx = CTX_HWBITS(mm->context); 1075a88b5ba8SSam Ravnborg int cpu = get_cpu(); 1076a88b5ba8SSam Ravnborg 1077a88b5ba8SSam Ravnborg if (mm == current->active_mm && atomic_read(&mm->mm_users) == 1) 1078*81f1adf0SRusty Russell cpumask_copy(mm_cpumask(mm), cpumask_of(cpu)); 1079a88b5ba8SSam Ravnborg else 1080a88b5ba8SSam Ravnborg smp_cross_call_masked(&xcall_flush_tlb_pending, 1081a88b5ba8SSam Ravnborg ctx, nr, (unsigned long) vaddrs, 1082*81f1adf0SRusty Russell mm_cpumask(mm)); 1083a88b5ba8SSam Ravnborg 1084a88b5ba8SSam Ravnborg __flush_tlb_pending(ctx, nr, vaddrs); 1085a88b5ba8SSam Ravnborg 1086a88b5ba8SSam Ravnborg put_cpu(); 1087a88b5ba8SSam Ravnborg } 1088a88b5ba8SSam Ravnborg 1089a88b5ba8SSam Ravnborg void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end) 1090a88b5ba8SSam Ravnborg { 1091a88b5ba8SSam Ravnborg start &= PAGE_MASK; 1092a88b5ba8SSam Ravnborg end = PAGE_ALIGN(end); 1093a88b5ba8SSam Ravnborg if (start != end) { 1094a88b5ba8SSam Ravnborg smp_cross_call(&xcall_flush_tlb_kernel_range, 1095a88b5ba8SSam Ravnborg 0, start, end); 1096a88b5ba8SSam Ravnborg 1097a88b5ba8SSam Ravnborg __flush_tlb_kernel_range(start, end); 1098a88b5ba8SSam Ravnborg } 1099a88b5ba8SSam Ravnborg } 1100a88b5ba8SSam Ravnborg 1101a88b5ba8SSam Ravnborg /* CPU capture. */ 1102a88b5ba8SSam Ravnborg /* #define CAPTURE_DEBUG */ 1103a88b5ba8SSam Ravnborg extern unsigned long xcall_capture; 1104a88b5ba8SSam Ravnborg 1105a88b5ba8SSam Ravnborg static atomic_t smp_capture_depth = ATOMIC_INIT(0); 1106a88b5ba8SSam Ravnborg static atomic_t smp_capture_registry = ATOMIC_INIT(0); 1107a88b5ba8SSam Ravnborg static unsigned long penguins_are_doing_time; 1108a88b5ba8SSam Ravnborg 1109a88b5ba8SSam Ravnborg void smp_capture(void) 1110a88b5ba8SSam Ravnborg { 1111a88b5ba8SSam Ravnborg int result = atomic_add_ret(1, &smp_capture_depth); 1112a88b5ba8SSam Ravnborg 1113a88b5ba8SSam Ravnborg if (result == 1) { 1114a88b5ba8SSam Ravnborg int ncpus = num_online_cpus(); 1115a88b5ba8SSam Ravnborg 1116a88b5ba8SSam Ravnborg #ifdef CAPTURE_DEBUG 1117a88b5ba8SSam Ravnborg printk("CPU[%d]: Sending penguins to jail...", 1118a88b5ba8SSam Ravnborg smp_processor_id()); 1119a88b5ba8SSam Ravnborg #endif 1120a88b5ba8SSam Ravnborg penguins_are_doing_time = 1; 1121a88b5ba8SSam Ravnborg atomic_inc(&smp_capture_registry); 1122a88b5ba8SSam Ravnborg smp_cross_call(&xcall_capture, 0, 0, 0); 1123a88b5ba8SSam Ravnborg while (atomic_read(&smp_capture_registry) != ncpus) 1124a88b5ba8SSam Ravnborg rmb(); 1125a88b5ba8SSam Ravnborg #ifdef CAPTURE_DEBUG 1126a88b5ba8SSam Ravnborg printk("done\n"); 1127a88b5ba8SSam Ravnborg #endif 1128a88b5ba8SSam Ravnborg } 1129a88b5ba8SSam Ravnborg } 1130a88b5ba8SSam Ravnborg 1131a88b5ba8SSam Ravnborg void smp_release(void) 1132a88b5ba8SSam Ravnborg { 1133a88b5ba8SSam Ravnborg if (atomic_dec_and_test(&smp_capture_depth)) { 1134a88b5ba8SSam Ravnborg #ifdef CAPTURE_DEBUG 1135a88b5ba8SSam Ravnborg printk("CPU[%d]: Giving pardon to " 1136a88b5ba8SSam Ravnborg "imprisoned penguins\n", 1137a88b5ba8SSam Ravnborg smp_processor_id()); 1138a88b5ba8SSam Ravnborg #endif 1139a88b5ba8SSam Ravnborg penguins_are_doing_time = 0; 1140a88b5ba8SSam Ravnborg membar_safe("#StoreLoad"); 1141a88b5ba8SSam Ravnborg atomic_dec(&smp_capture_registry); 1142a88b5ba8SSam Ravnborg } 1143a88b5ba8SSam Ravnborg } 1144a88b5ba8SSam Ravnborg 1145a88b5ba8SSam Ravnborg /* Imprisoned penguins run with %pil == PIL_NORMAL_MAX, but PSTATE_IE 1146a88b5ba8SSam Ravnborg * set, so they can service tlb flush xcalls... 1147a88b5ba8SSam Ravnborg */ 1148a88b5ba8SSam Ravnborg extern void prom_world(int); 1149a88b5ba8SSam Ravnborg 1150a88b5ba8SSam Ravnborg void smp_penguin_jailcell(int irq, struct pt_regs *regs) 1151a88b5ba8SSam Ravnborg { 1152a88b5ba8SSam Ravnborg clear_softint(1 << irq); 1153a88b5ba8SSam Ravnborg 1154a88b5ba8SSam Ravnborg preempt_disable(); 1155a88b5ba8SSam Ravnborg 1156a88b5ba8SSam Ravnborg __asm__ __volatile__("flushw"); 1157a88b5ba8SSam Ravnborg prom_world(1); 1158a88b5ba8SSam Ravnborg atomic_inc(&smp_capture_registry); 1159a88b5ba8SSam Ravnborg membar_safe("#StoreLoad"); 1160a88b5ba8SSam Ravnborg while (penguins_are_doing_time) 1161a88b5ba8SSam Ravnborg rmb(); 1162a88b5ba8SSam Ravnborg atomic_dec(&smp_capture_registry); 1163a88b5ba8SSam Ravnborg prom_world(0); 1164a88b5ba8SSam Ravnborg 1165a88b5ba8SSam Ravnborg preempt_enable(); 1166a88b5ba8SSam Ravnborg } 1167a88b5ba8SSam Ravnborg 1168a88b5ba8SSam Ravnborg /* /proc/profile writes can call this, don't __init it please. */ 1169a88b5ba8SSam Ravnborg int setup_profiling_timer(unsigned int multiplier) 1170a88b5ba8SSam Ravnborg { 1171a88b5ba8SSam Ravnborg return -EINVAL; 1172a88b5ba8SSam Ravnborg } 1173a88b5ba8SSam Ravnborg 1174a88b5ba8SSam Ravnborg void __init smp_prepare_cpus(unsigned int max_cpus) 1175a88b5ba8SSam Ravnborg { 1176a88b5ba8SSam Ravnborg } 1177a88b5ba8SSam Ravnborg 1178a88b5ba8SSam Ravnborg void __devinit smp_prepare_boot_cpu(void) 1179a88b5ba8SSam Ravnborg { 1180a88b5ba8SSam Ravnborg } 1181a88b5ba8SSam Ravnborg 1182a88b5ba8SSam Ravnborg void __init smp_setup_processor_id(void) 1183a88b5ba8SSam Ravnborg { 1184a88b5ba8SSam Ravnborg if (tlb_type == spitfire) 1185a88b5ba8SSam Ravnborg xcall_deliver_impl = spitfire_xcall_deliver; 1186a88b5ba8SSam Ravnborg else if (tlb_type == cheetah || tlb_type == cheetah_plus) 1187a88b5ba8SSam Ravnborg xcall_deliver_impl = cheetah_xcall_deliver; 1188a88b5ba8SSam Ravnborg else 1189a88b5ba8SSam Ravnborg xcall_deliver_impl = hypervisor_xcall_deliver; 1190a88b5ba8SSam Ravnborg } 1191a88b5ba8SSam Ravnborg 1192a88b5ba8SSam Ravnborg void __devinit smp_fill_in_sib_core_maps(void) 1193a88b5ba8SSam Ravnborg { 1194a88b5ba8SSam Ravnborg unsigned int i; 1195a88b5ba8SSam Ravnborg 1196a88b5ba8SSam Ravnborg for_each_present_cpu(i) { 1197a88b5ba8SSam Ravnborg unsigned int j; 1198a88b5ba8SSam Ravnborg 1199a88b5ba8SSam Ravnborg cpus_clear(cpu_core_map[i]); 1200a88b5ba8SSam Ravnborg if (cpu_data(i).core_id == 0) { 1201a88b5ba8SSam Ravnborg cpu_set(i, cpu_core_map[i]); 1202a88b5ba8SSam Ravnborg continue; 1203a88b5ba8SSam Ravnborg } 1204a88b5ba8SSam Ravnborg 1205a88b5ba8SSam Ravnborg for_each_present_cpu(j) { 1206a88b5ba8SSam Ravnborg if (cpu_data(i).core_id == 1207a88b5ba8SSam Ravnborg cpu_data(j).core_id) 1208a88b5ba8SSam Ravnborg cpu_set(j, cpu_core_map[i]); 1209a88b5ba8SSam Ravnborg } 1210a88b5ba8SSam Ravnborg } 1211a88b5ba8SSam Ravnborg 1212a88b5ba8SSam Ravnborg for_each_present_cpu(i) { 1213a88b5ba8SSam Ravnborg unsigned int j; 1214a88b5ba8SSam Ravnborg 1215a88b5ba8SSam Ravnborg cpus_clear(per_cpu(cpu_sibling_map, i)); 1216a88b5ba8SSam Ravnborg if (cpu_data(i).proc_id == -1) { 1217a88b5ba8SSam Ravnborg cpu_set(i, per_cpu(cpu_sibling_map, i)); 1218a88b5ba8SSam Ravnborg continue; 1219a88b5ba8SSam Ravnborg } 1220a88b5ba8SSam Ravnborg 1221a88b5ba8SSam Ravnborg for_each_present_cpu(j) { 1222a88b5ba8SSam Ravnborg if (cpu_data(i).proc_id == 1223a88b5ba8SSam Ravnborg cpu_data(j).proc_id) 1224a88b5ba8SSam Ravnborg cpu_set(j, per_cpu(cpu_sibling_map, i)); 1225a88b5ba8SSam Ravnborg } 1226a88b5ba8SSam Ravnborg } 1227a88b5ba8SSam Ravnborg } 1228a88b5ba8SSam Ravnborg 1229a88b5ba8SSam Ravnborg int __cpuinit __cpu_up(unsigned int cpu) 1230a88b5ba8SSam Ravnborg { 1231a88b5ba8SSam Ravnborg int ret = smp_boot_one_cpu(cpu); 1232a88b5ba8SSam Ravnborg 1233a88b5ba8SSam Ravnborg if (!ret) { 1234a88b5ba8SSam Ravnborg cpu_set(cpu, smp_commenced_mask); 1235a88b5ba8SSam Ravnborg while (!cpu_isset(cpu, cpu_online_map)) 1236a88b5ba8SSam Ravnborg mb(); 1237a88b5ba8SSam Ravnborg if (!cpu_isset(cpu, cpu_online_map)) { 1238a88b5ba8SSam Ravnborg ret = -ENODEV; 1239a88b5ba8SSam Ravnborg } else { 1240a88b5ba8SSam Ravnborg /* On SUN4V, writes to %tick and %stick are 1241a88b5ba8SSam Ravnborg * not allowed. 1242a88b5ba8SSam Ravnborg */ 1243a88b5ba8SSam Ravnborg if (tlb_type != hypervisor) 1244a88b5ba8SSam Ravnborg smp_synchronize_one_tick(cpu); 1245a88b5ba8SSam Ravnborg } 1246a88b5ba8SSam Ravnborg } 1247a88b5ba8SSam Ravnborg return ret; 1248a88b5ba8SSam Ravnborg } 1249a88b5ba8SSam Ravnborg 1250a88b5ba8SSam Ravnborg #ifdef CONFIG_HOTPLUG_CPU 1251a88b5ba8SSam Ravnborg void cpu_play_dead(void) 1252a88b5ba8SSam Ravnborg { 1253a88b5ba8SSam Ravnborg int cpu = smp_processor_id(); 1254a88b5ba8SSam Ravnborg unsigned long pstate; 1255a88b5ba8SSam Ravnborg 1256a88b5ba8SSam Ravnborg idle_task_exit(); 1257a88b5ba8SSam Ravnborg 1258a88b5ba8SSam Ravnborg if (tlb_type == hypervisor) { 1259a88b5ba8SSam Ravnborg struct trap_per_cpu *tb = &trap_block[cpu]; 1260a88b5ba8SSam Ravnborg 1261a88b5ba8SSam Ravnborg sun4v_cpu_qconf(HV_CPU_QUEUE_CPU_MONDO, 1262a88b5ba8SSam Ravnborg tb->cpu_mondo_pa, 0); 1263a88b5ba8SSam Ravnborg sun4v_cpu_qconf(HV_CPU_QUEUE_DEVICE_MONDO, 1264a88b5ba8SSam Ravnborg tb->dev_mondo_pa, 0); 1265a88b5ba8SSam Ravnborg sun4v_cpu_qconf(HV_CPU_QUEUE_RES_ERROR, 1266a88b5ba8SSam Ravnborg tb->resum_mondo_pa, 0); 1267a88b5ba8SSam Ravnborg sun4v_cpu_qconf(HV_CPU_QUEUE_NONRES_ERROR, 1268a88b5ba8SSam Ravnborg tb->nonresum_mondo_pa, 0); 1269a88b5ba8SSam Ravnborg } 1270a88b5ba8SSam Ravnborg 1271a88b5ba8SSam Ravnborg cpu_clear(cpu, smp_commenced_mask); 1272a88b5ba8SSam Ravnborg membar_safe("#Sync"); 1273a88b5ba8SSam Ravnborg 1274a88b5ba8SSam Ravnborg local_irq_disable(); 1275a88b5ba8SSam Ravnborg 1276a88b5ba8SSam Ravnborg __asm__ __volatile__( 1277a88b5ba8SSam Ravnborg "rdpr %%pstate, %0\n\t" 1278a88b5ba8SSam Ravnborg "wrpr %0, %1, %%pstate" 1279a88b5ba8SSam Ravnborg : "=r" (pstate) 1280a88b5ba8SSam Ravnborg : "i" (PSTATE_IE)); 1281a88b5ba8SSam Ravnborg 1282a88b5ba8SSam Ravnborg while (1) 1283a88b5ba8SSam Ravnborg barrier(); 1284a88b5ba8SSam Ravnborg } 1285a88b5ba8SSam Ravnborg 1286a88b5ba8SSam Ravnborg int __cpu_disable(void) 1287a88b5ba8SSam Ravnborg { 1288a88b5ba8SSam Ravnborg int cpu = smp_processor_id(); 1289a88b5ba8SSam Ravnborg cpuinfo_sparc *c; 1290a88b5ba8SSam Ravnborg int i; 1291a88b5ba8SSam Ravnborg 1292a88b5ba8SSam Ravnborg for_each_cpu_mask(i, cpu_core_map[cpu]) 1293a88b5ba8SSam Ravnborg cpu_clear(cpu, cpu_core_map[i]); 1294a88b5ba8SSam Ravnborg cpus_clear(cpu_core_map[cpu]); 1295a88b5ba8SSam Ravnborg 1296a88b5ba8SSam Ravnborg for_each_cpu_mask(i, per_cpu(cpu_sibling_map, cpu)) 1297a88b5ba8SSam Ravnborg cpu_clear(cpu, per_cpu(cpu_sibling_map, i)); 1298a88b5ba8SSam Ravnborg cpus_clear(per_cpu(cpu_sibling_map, cpu)); 1299a88b5ba8SSam Ravnborg 1300a88b5ba8SSam Ravnborg c = &cpu_data(cpu); 1301a88b5ba8SSam Ravnborg 1302a88b5ba8SSam Ravnborg c->core_id = 0; 1303a88b5ba8SSam Ravnborg c->proc_id = -1; 1304a88b5ba8SSam Ravnborg 1305a88b5ba8SSam Ravnborg smp_wmb(); 1306a88b5ba8SSam Ravnborg 1307a88b5ba8SSam Ravnborg /* Make sure no interrupts point to this cpu. */ 1308a88b5ba8SSam Ravnborg fixup_irqs(); 1309a88b5ba8SSam Ravnborg 1310a88b5ba8SSam Ravnborg local_irq_enable(); 1311a88b5ba8SSam Ravnborg mdelay(1); 1312a88b5ba8SSam Ravnborg local_irq_disable(); 1313a88b5ba8SSam Ravnborg 1314a88b5ba8SSam Ravnborg ipi_call_lock(); 1315a88b5ba8SSam Ravnborg cpu_clear(cpu, cpu_online_map); 1316a88b5ba8SSam Ravnborg ipi_call_unlock(); 1317a88b5ba8SSam Ravnborg 1318a88b5ba8SSam Ravnborg return 0; 1319a88b5ba8SSam Ravnborg } 1320a88b5ba8SSam Ravnborg 1321a88b5ba8SSam Ravnborg void __cpu_die(unsigned int cpu) 1322a88b5ba8SSam Ravnborg { 1323a88b5ba8SSam Ravnborg int i; 1324a88b5ba8SSam Ravnborg 1325a88b5ba8SSam Ravnborg for (i = 0; i < 100; i++) { 1326a88b5ba8SSam Ravnborg smp_rmb(); 1327a88b5ba8SSam Ravnborg if (!cpu_isset(cpu, smp_commenced_mask)) 1328a88b5ba8SSam Ravnborg break; 1329a88b5ba8SSam Ravnborg msleep(100); 1330a88b5ba8SSam Ravnborg } 1331a88b5ba8SSam Ravnborg if (cpu_isset(cpu, smp_commenced_mask)) { 1332a88b5ba8SSam Ravnborg printk(KERN_ERR "CPU %u didn't die...\n", cpu); 1333a88b5ba8SSam Ravnborg } else { 1334a88b5ba8SSam Ravnborg #if defined(CONFIG_SUN_LDOMS) 1335a88b5ba8SSam Ravnborg unsigned long hv_err; 1336a88b5ba8SSam Ravnborg int limit = 100; 1337a88b5ba8SSam Ravnborg 1338a88b5ba8SSam Ravnborg do { 1339a88b5ba8SSam Ravnborg hv_err = sun4v_cpu_stop(cpu); 1340a88b5ba8SSam Ravnborg if (hv_err == HV_EOK) { 1341a88b5ba8SSam Ravnborg cpu_clear(cpu, cpu_present_map); 1342a88b5ba8SSam Ravnborg break; 1343a88b5ba8SSam Ravnborg } 1344a88b5ba8SSam Ravnborg } while (--limit > 0); 1345a88b5ba8SSam Ravnborg if (limit <= 0) { 1346a88b5ba8SSam Ravnborg printk(KERN_ERR "sun4v_cpu_stop() fails err=%lu\n", 1347a88b5ba8SSam Ravnborg hv_err); 1348a88b5ba8SSam Ravnborg } 1349a88b5ba8SSam Ravnborg #endif 1350a88b5ba8SSam Ravnborg } 1351a88b5ba8SSam Ravnborg } 1352a88b5ba8SSam Ravnborg #endif 1353a88b5ba8SSam Ravnborg 1354a88b5ba8SSam Ravnborg void __init smp_cpus_done(unsigned int max_cpus) 1355a88b5ba8SSam Ravnborg { 1356a88b5ba8SSam Ravnborg } 1357a88b5ba8SSam Ravnborg 1358a88b5ba8SSam Ravnborg void smp_send_reschedule(int cpu) 1359a88b5ba8SSam Ravnborg { 1360a88b5ba8SSam Ravnborg xcall_deliver((u64) &xcall_receive_signal, 0, 0, 1361a88b5ba8SSam Ravnborg &cpumask_of_cpu(cpu)); 1362a88b5ba8SSam Ravnborg } 1363a88b5ba8SSam Ravnborg 1364a88b5ba8SSam Ravnborg void smp_receive_signal_client(int irq, struct pt_regs *regs) 1365a88b5ba8SSam Ravnborg { 1366a88b5ba8SSam Ravnborg clear_softint(1 << irq); 1367a88b5ba8SSam Ravnborg } 1368a88b5ba8SSam Ravnborg 1369a88b5ba8SSam Ravnborg /* This is a nop because we capture all other cpus 1370a88b5ba8SSam Ravnborg * anyways when making the PROM active. 1371a88b5ba8SSam Ravnborg */ 1372a88b5ba8SSam Ravnborg void smp_send_stop(void) 1373a88b5ba8SSam Ravnborg { 1374a88b5ba8SSam Ravnborg } 1375a88b5ba8SSam Ravnborg 1376a88b5ba8SSam Ravnborg unsigned long __per_cpu_base __read_mostly; 1377a88b5ba8SSam Ravnborg unsigned long __per_cpu_shift __read_mostly; 1378a88b5ba8SSam Ravnborg 1379a88b5ba8SSam Ravnborg EXPORT_SYMBOL(__per_cpu_base); 1380a88b5ba8SSam Ravnborg EXPORT_SYMBOL(__per_cpu_shift); 1381a88b5ba8SSam Ravnborg 1382a88b5ba8SSam Ravnborg void __init real_setup_per_cpu_areas(void) 1383a88b5ba8SSam Ravnborg { 1384a88b5ba8SSam Ravnborg unsigned long paddr, goal, size, i; 1385a88b5ba8SSam Ravnborg char *ptr; 1386a88b5ba8SSam Ravnborg 1387a88b5ba8SSam Ravnborg /* Copy section for each CPU (we discard the original) */ 1388a88b5ba8SSam Ravnborg goal = PERCPU_ENOUGH_ROOM; 1389a88b5ba8SSam Ravnborg 1390a88b5ba8SSam Ravnborg __per_cpu_shift = PAGE_SHIFT; 1391a88b5ba8SSam Ravnborg for (size = PAGE_SIZE; size < goal; size <<= 1UL) 1392a88b5ba8SSam Ravnborg __per_cpu_shift++; 1393a88b5ba8SSam Ravnborg 1394a88b5ba8SSam Ravnborg paddr = lmb_alloc(size * NR_CPUS, PAGE_SIZE); 1395a88b5ba8SSam Ravnborg if (!paddr) { 1396a88b5ba8SSam Ravnborg prom_printf("Cannot allocate per-cpu memory.\n"); 1397a88b5ba8SSam Ravnborg prom_halt(); 1398a88b5ba8SSam Ravnborg } 1399a88b5ba8SSam Ravnborg 1400a88b5ba8SSam Ravnborg ptr = __va(paddr); 1401a88b5ba8SSam Ravnborg __per_cpu_base = ptr - __per_cpu_start; 1402a88b5ba8SSam Ravnborg 1403a88b5ba8SSam Ravnborg for (i = 0; i < NR_CPUS; i++, ptr += size) 1404a88b5ba8SSam Ravnborg memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start); 1405a88b5ba8SSam Ravnborg 1406a88b5ba8SSam Ravnborg /* Setup %g5 for the boot cpu. */ 1407a88b5ba8SSam Ravnborg __local_per_cpu_offset = __per_cpu_offset(smp_processor_id()); 1408a88b5ba8SSam Ravnborg } 1409