Merge branches 'release' and 'menlo' into release
[linux-2.6] / arch / arm / mach-realview / platsmp.c
1 /*
2  *  linux/arch/arm/mach-realview/platsmp.c
3  *
4  *  Copyright (C) 2002 ARM Ltd.
5  *  All Rights Reserved
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11 #include <linux/init.h>
12 #include <linux/errno.h>
13 #include <linux/delay.h>
14 #include <linux/device.h>
15 #include <linux/smp.h>
16
17 #include <asm/cacheflush.h>
18 #include <asm/hardware/arm_scu.h>
19 #include <asm/hardware.h>
20 #include <asm/io.h>
21 #include <asm/mach-types.h>
22
23 extern void realview_secondary_startup(void);
24
25 /*
26  * control for which core is the next to come out of the secondary
27  * boot "holding pen"
28  */
29 volatile int __cpuinitdata pen_release = -1;
30
31 static unsigned int __init get_core_count(void)
32 {
33         unsigned int ncores;
34
35         if (machine_is_realview_eb() && core_tile_eb11mp()) {
36                 ncores = __raw_readl(__io_address(REALVIEW_EB11MP_SCU_BASE) + SCU_CONFIG);
37                 ncores = (ncores & 0x03) + 1;
38         } else
39                 ncores = 1;
40
41         return ncores;
42 }
43
44 static DEFINE_SPINLOCK(boot_lock);
45
46 void __cpuinit platform_secondary_init(unsigned int cpu)
47 {
48         /*
49          * the primary core may have used a "cross call" soft interrupt
50          * to get this processor out of WFI in the BootMonitor - make
51          * sure that we are no longer being sent this soft interrupt
52          */
53         smp_cross_call_done(cpumask_of_cpu(cpu));
54
55         /*
56          * if any interrupts are already enabled for the primary
57          * core (e.g. timer irq), then they will not have been enabled
58          * for us: do so
59          */
60         gic_cpu_init(0, __io_address(REALVIEW_EB11MP_GIC_CPU_BASE));
61
62         /*
63          * let the primary processor know we're out of the
64          * pen, then head off into the C entry point
65          */
66         pen_release = -1;
67         smp_wmb();
68
69         /*
70          * Synchronise with the boot thread.
71          */
72         spin_lock(&boot_lock);
73         spin_unlock(&boot_lock);
74 }
75
76 int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
77 {
78         unsigned long timeout;
79
80         /*
81          * set synchronisation state between this boot processor
82          * and the secondary one
83          */
84         spin_lock(&boot_lock);
85
86         /*
87          * The secondary processor is waiting to be released from
88          * the holding pen - release it, then wait for it to flag
89          * that it has been released by resetting pen_release.
90          *
91          * Note that "pen_release" is the hardware CPU ID, whereas
92          * "cpu" is Linux's internal ID.
93          */
94         pen_release = cpu;
95         flush_cache_all();
96
97         /*
98          * XXX
99          *
100          * This is a later addition to the booting protocol: the
101          * bootMonitor now puts secondary cores into WFI, so
102          * poke_milo() no longer gets the cores moving; we need
103          * to send a soft interrupt to wake the secondary core.
104          * Use smp_cross_call() for this, since there's little
105          * point duplicating the code here
106          */
107         smp_cross_call(cpumask_of_cpu(cpu));
108
109         timeout = jiffies + (1 * HZ);
110         while (time_before(jiffies, timeout)) {
111                 smp_rmb();
112                 if (pen_release == -1)
113                         break;
114
115                 udelay(10);
116         }
117
118         /*
119          * now the secondary core is starting up let it run its
120          * calibrations, then wait for it to finish
121          */
122         spin_unlock(&boot_lock);
123
124         return pen_release != -1 ? -ENOSYS : 0;
125 }
126
127 static void __init poke_milo(void)
128 {
129         extern void secondary_startup(void);
130
131         /* nobody is to be released from the pen yet */
132         pen_release = -1;
133
134         /*
135          * write the address of secondary startup into the system-wide
136          * flags register, then clear the bottom two bits, which is what
137          * BootMonitor is waiting for
138          */
139 #if 1
140 #define REALVIEW_SYS_FLAGSS_OFFSET 0x30
141         __raw_writel(virt_to_phys(realview_secondary_startup),
142                      __io_address(REALVIEW_SYS_BASE) +
143                      REALVIEW_SYS_FLAGSS_OFFSET);
144 #define REALVIEW_SYS_FLAGSC_OFFSET 0x34
145         __raw_writel(3,
146                      __io_address(REALVIEW_SYS_BASE) +
147                      REALVIEW_SYS_FLAGSC_OFFSET);
148 #endif
149
150         mb();
151 }
152
153 /*
154  * Initialise the CPU possible map early - this describes the CPUs
155  * which may be present or become present in the system.
156  */
157 void __init smp_init_cpus(void)
158 {
159         unsigned int i, ncores = get_core_count();
160
161         for (i = 0; i < ncores; i++)
162                 cpu_set(i, cpu_possible_map);
163 }
164
165 void __init smp_prepare_cpus(unsigned int max_cpus)
166 {
167         unsigned int ncores = get_core_count();
168         unsigned int cpu = smp_processor_id();
169         int i;
170
171         /* sanity check */
172         if (ncores == 0) {
173                 printk(KERN_ERR
174                        "Realview: strange CM count of 0? Default to 1\n");
175
176                 ncores = 1;
177         }
178
179         if (ncores > NR_CPUS) {
180                 printk(KERN_WARNING
181                        "Realview: no. of cores (%d) greater than configured "
182                        "maximum of %d - clipping\n",
183                        ncores, NR_CPUS);
184                 ncores = NR_CPUS;
185         }
186
187         smp_store_cpu_info(cpu);
188
189         /*
190          * are we trying to boot more cores than exist?
191          */
192         if (max_cpus > ncores)
193                 max_cpus = ncores;
194
195 #ifdef CONFIG_LOCAL_TIMERS
196         /*
197          * Enable the local timer for primary CPU. If the device is
198          * dummy (!CONFIG_LOCAL_TIMERS), it was already registers in
199          * realview_timer_init
200          */
201         if (machine_is_realview_eb() && core_tile_eb11mp())
202                 local_timer_setup(cpu);
203 #endif
204
205         /*
206          * Initialise the present map, which describes the set of CPUs
207          * actually populated at the present time.
208          */
209         for (i = 0; i < max_cpus; i++)
210                 cpu_set(i, cpu_present_map);
211
212         /*
213          * Do we need any more CPUs? If so, then let them know where
214          * to start. Note that, on modern versions of MILO, the "poke"
215          * doesn't actually do anything until each individual core is
216          * sent a soft interrupt to get it out of WFI
217          */
218         if (max_cpus > 1)
219                 poke_milo();
220 }