aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ppc64/kernel/pmac_smp.c
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2005-10-22 02:06:27 -0400
committerPaul Mackerras <paulus@samba.org>2005-10-22 02:06:27 -0400
commit834289447542b7ec55c0847486616d4d53ddf891 (patch)
tree3fce91fba1ee65ff00e927cca981980eb07f3019 /arch/ppc64/kernel/pmac_smp.c
parent35499c0195e46f479cf6ac16ad8d3f394b5fcc10 (diff)
ppc64: Use arch/powerpc/platforms/powermac for powermac build.
This switches the ARCH=ppc64 build to use arch/powerpc/platforms/powermac instead of arch/ppc64/kernel/pmac*, and deletes the latter set of files. Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/ppc64/kernel/pmac_smp.c')
-rw-r--r--arch/ppc64/kernel/pmac_smp.c316
1 files changed, 0 insertions, 316 deletions
diff --git a/arch/ppc64/kernel/pmac_smp.c b/arch/ppc64/kernel/pmac_smp.c
deleted file mode 100644
index 83c2f8dc1ec6..000000000000
--- a/arch/ppc64/kernel/pmac_smp.c
+++ /dev/null
@@ -1,316 +0,0 @@
1/*
2 * SMP support for power macintosh.
3 *
4 * We support both the old "powersurge" SMP architecture
5 * and the current Core99 (G4 PowerMac) machines.
6 *
7 * Note that we don't support the very first rev. of
8 * Apple/DayStar 2 CPUs board, the one with the funky
9 * watchdog. Hopefully, none of these should be there except
10 * maybe internally to Apple. I should probably still add some
11 * code to detect this card though and disable SMP. --BenH.
12 *
13 * Support Macintosh G4 SMP by Troy Benjegerdes (hozer@drgw.net)
14 * and Ben Herrenschmidt <benh@kernel.crashing.org>.
15 *
16 * Support for DayStar quad CPU cards
17 * Copyright (C) XLR8, Inc. 1994-2000
18 *
19 * This program is free software; you can redistribute it and/or
20 * modify it under the terms of the GNU General Public License
21 * as published by the Free Software Foundation; either version
22 * 2 of the License, or (at your option) any later version.
23 */
24
25#undef DEBUG
26
27#include <linux/config.h>
28#include <linux/kernel.h>
29#include <linux/sched.h>
30#include <linux/smp.h>
31#include <linux/smp_lock.h>
32#include <linux/interrupt.h>
33#include <linux/kernel_stat.h>
34#include <linux/init.h>
35#include <linux/spinlock.h>
36#include <linux/errno.h>
37#include <linux/irq.h>
38
39#include <asm/ptrace.h>
40#include <asm/atomic.h>
41#include <asm/irq.h>
42#include <asm/page.h>
43#include <asm/pgtable.h>
44#include <asm/sections.h>
45#include <asm/io.h>
46#include <asm/prom.h>
47#include <asm/smp.h>
48#include <asm/machdep.h>
49#include <asm/pmac_feature.h>
50#include <asm/time.h>
51#include <asm/cacheflush.h>
52#include <asm/keylargo.h>
53#include <asm/pmac_low_i2c.h>
54#include <asm/mpic.h>
55
56#ifdef DEBUG
57#define DBG(fmt...) udbg_printf(fmt)
58#else
59#define DBG(fmt...)
60#endif
61
62extern void __secondary_start_pmac_0(void);
63
64extern struct smp_ops_t *smp_ops;
65
66static void (*pmac_tb_freeze)(int freeze);
67static struct device_node *pmac_tb_clock_chip_host;
68static u8 pmac_tb_pulsar_addr;
69static DEFINE_SPINLOCK(timebase_lock);
70static unsigned long timebase;
71
72static void smp_core99_cypress_tb_freeze(int freeze)
73{
74 u8 data;
75 int rc;
76
77 /* Strangely, the device-tree says address is 0xd2, but darwin
78 * accesses 0xd0 ...
79 */
80 pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined);
81 rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,
82 0xd0 | pmac_low_i2c_read,
83 0x81, &data, 1);
84 if (rc != 0)
85 goto bail;
86
87 data = (data & 0xf3) | (freeze ? 0x00 : 0x0c);
88
89 pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub);
90 rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,
91 0xd0 | pmac_low_i2c_write,
92 0x81, &data, 1);
93
94 bail:
95 if (rc != 0) {
96 printk("Cypress Timebase %s rc: %d\n",
97 freeze ? "freeze" : "unfreeze", rc);
98 panic("Timebase freeze failed !\n");
99 }
100}
101
102static void smp_core99_pulsar_tb_freeze(int freeze)
103{
104 u8 data;
105 int rc;
106
107 pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined);
108 rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,
109 pmac_tb_pulsar_addr | pmac_low_i2c_read,
110 0x2e, &data, 1);
111 if (rc != 0)
112 goto bail;
113
114 data = (data & 0x88) | (freeze ? 0x11 : 0x22);
115
116 pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub);
117 rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host,
118 pmac_tb_pulsar_addr | pmac_low_i2c_write,
119 0x2e, &data, 1);
120 bail:
121 if (rc != 0) {
122 printk(KERN_ERR "Pulsar Timebase %s rc: %d\n",
123 freeze ? "freeze" : "unfreeze", rc);
124 panic("Timebase freeze failed !\n");
125 }
126}
127
128
129static void smp_core99_give_timebase(void)
130{
131 /* Open i2c bus for synchronous access */
132 if (pmac_low_i2c_open(pmac_tb_clock_chip_host, 0))
133 panic("Can't open i2c for TB sync !\n");
134
135 spin_lock(&timebase_lock);
136 (*pmac_tb_freeze)(1);
137 mb();
138 timebase = get_tb();
139 spin_unlock(&timebase_lock);
140
141 while (timebase)
142 barrier();
143
144 spin_lock(&timebase_lock);
145 (*pmac_tb_freeze)(0);
146 spin_unlock(&timebase_lock);
147
148 /* Close i2c bus */
149 pmac_low_i2c_close(pmac_tb_clock_chip_host);
150}
151
152
153static void __devinit smp_core99_take_timebase(void)
154{
155 while (!timebase)
156 barrier();
157 spin_lock(&timebase_lock);
158 set_tb(timebase >> 32, timebase & 0xffffffff);
159 timebase = 0;
160 spin_unlock(&timebase_lock);
161}
162
163
164static int __init smp_core99_probe(void)
165{
166 struct device_node *cpus;
167 struct device_node *cc;
168 int ncpus = 0;
169
170 /* Maybe use systemconfiguration here ? */
171 if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345);
172
173 /* Count CPUs in the device-tree */
174 for (cpus = NULL; (cpus = of_find_node_by_type(cpus, "cpu")) != NULL;)
175 ++ncpus;
176
177 printk(KERN_INFO "PowerMac SMP probe found %d cpus\n", ncpus);
178
179 /* Nothing more to do if less than 2 of them */
180 if (ncpus <= 1)
181 return 1;
182
183 /* HW sync only on these platforms */
184 if (!machine_is_compatible("PowerMac7,2") &&
185 !machine_is_compatible("PowerMac7,3") &&
186 !machine_is_compatible("RackMac3,1"))
187 goto nohwsync;
188
189 /* Look for the clock chip */
190 for (cc = NULL; (cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL;) {
191 struct device_node *p = of_get_parent(cc);
192 u32 *reg;
193 int ok;
194 ok = p && device_is_compatible(p, "uni-n-i2c");
195 if (!ok)
196 goto next;
197 reg = (u32 *)get_property(cc, "reg", NULL);
198 if (reg == NULL)
199 goto next;
200 switch (*reg) {
201 case 0xd2:
202 if (device_is_compatible(cc, "pulsar-legacy-slewing")) {
203 pmac_tb_freeze = smp_core99_pulsar_tb_freeze;
204 pmac_tb_pulsar_addr = 0xd2;
205 printk(KERN_INFO "Timebase clock is Pulsar chip\n");
206 } else if (device_is_compatible(cc, "cy28508")) {
207 pmac_tb_freeze = smp_core99_cypress_tb_freeze;
208 printk(KERN_INFO "Timebase clock is Cypress chip\n");
209 }
210 break;
211 case 0xd4:
212 pmac_tb_freeze = smp_core99_pulsar_tb_freeze;
213 pmac_tb_pulsar_addr = 0xd4;
214 printk(KERN_INFO "Timebase clock is Pulsar chip\n");
215 break;
216 }
217 if (pmac_tb_freeze != NULL) {
218 pmac_tb_clock_chip_host = p;
219 smp_ops->give_timebase = smp_core99_give_timebase;
220 smp_ops->take_timebase = smp_core99_take_timebase;
221 of_node_put(cc);
222 of_node_put(p);
223 break;
224 }
225 next:
226 of_node_put(p);
227 }
228
229 nohwsync:
230 mpic_request_ipis();
231
232 return ncpus;
233}
234
235static void __init smp_core99_kick_cpu(int nr)
236{
237 unsigned int save_vector, j;
238 unsigned long new_vector;
239 unsigned long flags;
240 volatile unsigned int *vector
241 = ((volatile unsigned int *)(KERNELBASE+0x100));
242
243 if (nr < 1 || nr > 3)
244 return;
245 if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346);
246
247 local_irq_save(flags);
248 local_irq_disable();
249
250 /* Save reset vector */
251 save_vector = *vector;
252
253 /* Setup fake reset vector that does
254 * b __secondary_start_pmac_0 + nr*8 - KERNELBASE
255 */
256 new_vector = (unsigned long) __secondary_start_pmac_0 + nr * 8;
257 *vector = 0x48000002 + (new_vector - KERNELBASE);
258
259 /* flush data cache and inval instruction cache */
260 flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
261
262 /* Put some life in our friend */
263 pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0);
264 paca[nr].cpu_start = 1;
265
266 /* FIXME: We wait a bit for the CPU to take the exception, I should
267 * instead wait for the entry code to set something for me. Well,
268 * ideally, all that crap will be done in prom.c and the CPU left
269 * in a RAM-based wait loop like CHRP.
270 */
271 for (j = 1; j < 1000000; j++)
272 mb();
273
274 /* Restore our exception vector */
275 *vector = save_vector;
276 flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
277
278 local_irq_restore(flags);
279 if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347);
280}
281
282static void __init smp_core99_setup_cpu(int cpu_nr)
283{
284 /* Setup MPIC */
285 mpic_setup_this_cpu();
286
287 if (cpu_nr == 0) {
288 extern void g5_phy_disable_cpu1(void);
289
290 /* If we didn't start the second CPU, we must take
291 * it off the bus
292 */
293 if (num_online_cpus() < 2)
294 g5_phy_disable_cpu1();
295 if (ppc_md.progress) ppc_md.progress("smp_core99_setup_cpu 0 done", 0x349);
296 }
297}
298
299struct smp_ops_t core99_smp_ops = {
300 .message_pass = smp_mpic_message_pass,
301 .probe = smp_core99_probe,
302 .kick_cpu = smp_core99_kick_cpu,
303 .setup_cpu = smp_core99_setup_cpu,
304 .give_timebase = smp_generic_give_timebase,
305 .take_timebase = smp_generic_take_timebase,
306};
307
308void __init pmac_setup_smp(void)
309{
310 smp_ops = &core99_smp_ops;
311#ifdef CONFIG_HOTPLUG_CPU
312 smp_ops->cpu_enable = generic_cpu_enable;
313 smp_ops->cpu_disable = generic_cpu_disable;
314 smp_ops->cpu_die = generic_cpu_die;
315#endif
316}