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