1/* 2 * BK Id: %F% %I% %G% %U% %#% 3 */ 4/* 5 * Smp support for CHRP machines. 6 * 7 * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great 8 * deal of code from the sparc and intel versions. 9 * 10 * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu> 11 * 12 */ 13 14#include <linux/config.h> 15#include <linux/kernel.h> 16#include <linux/sched.h> 17#include <linux/smp.h> 18#include <linux/smp_lock.h> 19#include <linux/interrupt.h> 20#include <linux/kernel_stat.h> 21#include <linux/delay.h> 22#define __KERNEL_SYSCALLS__ 23#include <linux/unistd.h> 24#include <linux/init.h> 25#include <linux/spinlock.h> 26 27#include <asm/ptrace.h> 28#include <asm/atomic.h> 29#include <asm/irq.h> 30#include <asm/page.h> 31#include <asm/pgtable.h> 32#include <asm/hardirq.h> 33#include <asm/softirq.h> 34#include <asm/sections.h> 35#include <asm/io.h> 36#include <asm/prom.h> 37#include <asm/smp.h> 38#include <asm/residual.h> 39#include <asm/time.h> 40#include <asm/open_pic.h> 41 42extern unsigned long smp_chrp_cpu_nr; 43 44/* 45 * The CHRP RTAS note on multiprocessor systems: 46 * "In a multiprocessor system, each processor should 47 * call event-scan periodically, not always the same 48 * one. The event-scan function needs to be called a 49 * total of rtas-event-scan-rate times a minute" 50 * 51 * We must call on each cpu in on a regular basis 52 * so that firmware can watch for cpu unique errors. 53 */ 54static void spread_heartbeat(void) 55{ 56 unsigned count = heartbeat_count(0); 57 unsigned offset = count; 58 int i; 59 60 if (!count || smp_chrp_cpu_nr < 2) 61 return; 62 63 count *= smp_chrp_cpu_nr; 64 65 for (i = 0; i < smp_chrp_cpu_nr ; i++) 66 { 67 heartbeat_reset(i) = count; 68 heartbeat_count(i) = i * offset; 69 } 70 printk("RTAS Event Scan now every %u jiffes on each cpu\n", count); 71} 72 73static int __init 74smp_chrp_probe(void) 75{ 76 if (smp_chrp_cpu_nr > 1) 77 openpic_request_IPIs(); 78 79 return smp_chrp_cpu_nr; 80} 81 82static void __init 83smp_chrp_kick_cpu(int nr) 84{ 85 *(unsigned long *)KERNELBASE = nr; 86 asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory"); 87} 88 89static void __init 90smp_chrp_setup_cpu(int cpu_nr) 91{ 92 static atomic_t ready = ATOMIC_INIT(1); 93 static volatile int frozen = 0; 94 95 if (cpu_nr == 0) { 96 /* wait for all the others */ 97 while (atomic_read(&ready) < smp_num_cpus) 98 barrier(); 99 atomic_set(&ready, 1); 100 /* freeze the timebase */ 101 call_rtas("freeze-time-base", 0, 1, NULL); 102 mb(); 103 frozen = 1; 104 set_tb(0, 0); 105 last_jiffy_stamp(0) = 0; 106 while (atomic_read(&ready) < smp_num_cpus) 107 barrier(); 108 /* thaw the timebase again */ 109 call_rtas("thaw-time-base", 0, 1, NULL); 110 mb(); 111 frozen = 0; 112 smp_tb_synchronized = 1; 113 } else { 114 atomic_inc(&ready); 115 while (!frozen) 116 barrier(); 117 set_tb(0, 0); 118 last_jiffy_stamp(0) = 0; 119 mb(); 120 atomic_inc(&ready); 121 while (frozen) 122 barrier(); 123 } 124 125 if (OpenPIC_Addr) 126 do_openpic_setup_cpu(); 127} 128 129#ifdef CONFIG_POWER4 130static void __chrp 131smp_xics_message_pass(int target, int msg, unsigned long data, int wait) 132{ 133 /* for now, only do reschedule messages 134 since we only have one IPI */ 135 if (msg != PPC_MSG_RESCHEDULE) 136 return; 137 for (i = 0; i < smp_num_cpus; ++i) { 138 if (target == MSG_ALL || target == i 139 || (target == MSG_ALL_BUT_SELF 140 && i != smp_processor_id())) 141 xics_cause_IPI(i); 142 } 143} 144 145static int __chrp 146smp_xics_probe(void) 147{ 148 return smp_chrp_cpu_nr; 149} 150 151static void __chrp 152smp_xics_setup_cpu(int cpu_nr) 153{ 154 if (cpu_nr > 0) 155 xics_setup_cpu(); 156} 157#endif /* CONFIG_POWER4 */ 158 159/* CHRP with openpic */ 160struct smp_ops_t chrp_smp_ops __chrpdata = { 161 smp_openpic_message_pass, 162 smp_chrp_probe, 163 smp_chrp_kick_cpu, 164 smp_chrp_setup_cpu, 165}; 166 167#ifdef CONFIG_POWER4 168/* CHRP with new XICS interrupt controller */ 169struct smp_ops_t xics_smp_ops __chrpdata = { 170 smp_xics_message_pass, 171 smp_xics_probe, 172 smp_chrp_kick_cpu, 173 smp_xics_setup_cpu, 174}; 175#endif /* CONFIG_POWER4 */ 176