Fix hang during secondary CPU sibling init caused by nested spinlocks.
[coreboot.git] / src / cpu / x86 / lapic / lapic_cpu_init.c
1 #include <cpu/x86/lapic.h>
2 #include <delay.h>
3 #include <string.h>
4 #include <console/console.h>
5 #include <arch/hlt.h>
6 #include <device/device.h>
7 #include <device/path.h>
8 #include <smp/atomic.h>
9 #include <smp/spinlock.h>
10 #include <cpu/cpu.h>
11
12
13 #if CONFIG_SMP == 1
14
15 /* This is a lot more paranoid now, since Linux can NOT handle
16  * being told there is a CPU when none exists. So any errors 
17  * will return 0, meaning no CPU. 
18  *
19  * We actually handling that case by noting which cpus startup
20  * and not telling anyone about the ones that dont.
21  */ 
22 static int lapic_start_cpu(unsigned long apicid)
23 {
24         int timeout;
25         unsigned long send_status, accept_status, start_eip;
26         int j, num_starts, maxlvt;
27         extern char _secondary_start[];
28                 
29         /*
30          * Starting actual IPI sequence...
31          */
32
33         printk_spew("Asserting INIT.\n");
34
35         /*
36          * Turn INIT on target chip
37          */
38         lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));
39
40         /*
41          * Send IPI
42          */
43         
44         lapic_write_around(LAPIC_ICR, LAPIC_INT_LEVELTRIG | LAPIC_INT_ASSERT
45                                 | LAPIC_DM_INIT);
46
47         printk_spew("Waiting for send to finish...\n");
48         timeout = 0;
49         do {
50                 printk_spew("+");
51                 udelay(100);
52                 send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY;
53         } while (send_status && (timeout++ < 1000));
54         if (timeout >= 1000) {
55                 printk_err("CPU %d: First apic write timed out. Disabling\n",
56                          apicid);
57                 // too bad. 
58                 printk_err("ESR is 0x%x\n", lapic_read(LAPIC_ESR));
59                 if (lapic_read(LAPIC_ESR)) {
60                         printk_err("Try to reset ESR\n");
61                         lapic_write_around(LAPIC_ESR, 0);
62                         printk_err("ESR is 0x%x\n", lapic_read(LAPIC_ESR));
63                 }
64                 return 0;
65         }
66         mdelay(10);
67
68         printk_spew("Deasserting INIT.\n");
69
70         /* Target chip */
71         lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));
72
73         /* Send IPI */
74         lapic_write_around(LAPIC_ICR, LAPIC_INT_LEVELTRIG | LAPIC_DM_INIT);
75         
76         printk_spew("Waiting for send to finish...\n");
77         timeout = 0;
78         do {
79                 printk_spew("+");
80                 udelay(100);
81                 send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY;
82         } while (send_status && (timeout++ < 1000));
83         if (timeout >= 1000) {
84                 printk_err("CPU %d: Second apic write timed out. Disabling\n",
85                          apicid);
86                 // too bad. 
87                 return 0;
88         }
89
90         start_eip = (unsigned long)_secondary_start;
91         printk_spew("start_eip=0x%08lx\n", start_eip);
92        
93         num_starts = 2;
94
95         /*
96          * Run STARTUP IPI loop.
97          */
98         printk_spew("#startup loops: %d.\n", num_starts);
99
100         maxlvt = 4;
101
102         for (j = 1; j <= num_starts; j++) {
103                 printk_spew("Sending STARTUP #%d to %u.\n", j, apicid);
104                 lapic_read_around(LAPIC_SPIV);
105                 lapic_write(LAPIC_ESR, 0);
106                 lapic_read(LAPIC_ESR);
107                 printk_spew("After apic_write.\n");
108
109                 /*
110                  * STARTUP IPI
111                  */
112
113                 /* Target chip */
114                 lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));
115
116                 /* Boot on the stack */
117                 /* Kick the second */
118                 lapic_write_around(LAPIC_ICR, LAPIC_DM_STARTUP
119                                         | (start_eip >> 12));
120
121                 /*
122                  * Give the other CPU some time to accept the IPI.
123                  */
124                 udelay(300);
125
126                 printk_spew("Startup point 1.\n");
127
128                 printk_spew("Waiting for send to finish...\n");
129                 timeout = 0;
130                 do {
131                         printk_spew("+");
132                         udelay(100);
133                         send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY;
134                 } while (send_status && (timeout++ < 1000));
135
136                 /*
137                  * Give the other CPU some time to accept the IPI.
138                  */
139                 udelay(200);
140                 /*
141                  * Due to the Pentium erratum 3AP.
142                  */
143                 if (maxlvt > 3) {
144                         lapic_read_around(LAPIC_SPIV);
145                         lapic_write(LAPIC_ESR, 0);
146                 }
147                 accept_status = (lapic_read(LAPIC_ESR) & 0xEF);
148                 if (send_status || accept_status)
149                         break;
150         }
151         printk_spew("After Startup.\n");
152         if (send_status)
153                 printk_warning("APIC never delivered???\n");
154         if (accept_status)
155                 printk_warning("APIC delivery error (%lx).\n", accept_status);
156         if (send_status || accept_status)
157                 return 0;
158         return 1;
159 }
160
161 /* Number of cpus that are currently running in linuxbios */
162 static atomic_t active_cpus = ATOMIC_INIT(1);
163
164 /* start_cpu_lock covers last_cpu_index and secondary_stack.
165  * Only starting one cpu at a time let's me remove the logic
166  * for select the stack from assembly language.
167  *
168  * In addition communicating by variables to the cpu I
169  * am starting allows me to veryify it has started before
170  * start_cpu returns.
171  */
172
173 static spinlock_t start_cpu_lock = SPIN_LOCK_UNLOCKED;
174 static unsigned last_cpu_index = 0;
175 volatile unsigned long secondary_stack;
176
177 int start_cpu(device_t cpu)
178 {
179         extern unsigned char _estack[];
180         struct cpu_info *info;
181         unsigned long stack_end;
182         unsigned long apicid;
183         unsigned long index;
184         unsigned long count;
185         int result;
186
187         spin_lock(&start_cpu_lock);
188
189         /* Get the cpu's apicid */
190         apicid = cpu->path.u.apic.apic_id;
191
192         /* Get an index for the new processor */
193         index = ++last_cpu_index;
194         
195         /* Find end of the new processors stack */
196         stack_end = ((unsigned long)_estack) - (STACK_SIZE*index) - sizeof(struct cpu_info);
197         
198         /* Record the index and which cpu structure we are using */
199         info = (struct cpu_info *)stack_end;
200         info->index = index;
201         info->cpu   = cpu;
202
203         /* Advertise the new stack to start_cpu */
204         secondary_stack = stack_end;
205
206         /* Until the cpu starts up report the cpu is not enabled */
207         cpu->enabled = 0;
208         cpu->initialized = 0;
209
210         /* Start the cpu */
211         result = lapic_start_cpu(apicid);
212
213         if (result) {
214                 result = 0;
215                 /* Wait 1s or until the new the new cpu calls in */
216                 for(count = 0; count < 100000 ; count++) {
217                         if (secondary_stack == 0) {
218                                 result = 1;
219                                 break;
220                         }
221                         udelay(10);
222                 }
223         }
224         secondary_stack = 0;
225         spin_unlock(&start_cpu_lock);
226         return result;
227 }
228
229 /* C entry point of secondary cpus */
230
231 // secondary_cpu_lock is used to serialize initialization of secondary CPUs
232 // This can be used to avoid interleaved debugging messages.
233
234 static spinlock_t secondary_cpu_lock = SPIN_LOCK_UNLOCKED;
235
236 void secondary_cpu_init(void)
237 {
238         atomic_inc(&active_cpus);
239
240 #if SERIAL_CPU_INIT == 1
241         spin_lock(&secondary_cpu_lock);
242 #endif
243
244         cpu_initialize();
245
246 #if SERIAL_CPU_INIT == 1
247         spin_unlock(&secondary_cpu_lock);
248 #endif
249
250         atomic_dec(&active_cpus);
251         stop_this_cpu();
252 }
253
254 static void initialize_other_cpus(struct bus *cpu_bus)
255 {
256         int old_active_count, active_count;
257         device_t cpu;
258         /* Loop through the cpus once getting them started */
259         for(cpu = cpu_bus->children; cpu ; cpu = cpu->sibling) {
260                 if (cpu->path.type != DEVICE_PATH_APIC) {
261                         continue;
262                 }
263                 if (!cpu->enabled) {
264                         continue;
265                 }
266                 if (cpu->initialized) {
267                         continue;
268                 }
269                 if (!start_cpu(cpu)) {
270                         /* Record the error in cpu? */
271                         printk_err("CPU  %u would not start!\n",
272                                 cpu->path.u.apic.apic_id);
273                 }
274 #if SERIAL_CPU_INIT == 1
275   #if CONFIG_MAX_CPUS>2
276                 udelay(10);
277   #endif
278 #endif
279         }
280
281         /* Now loop until the other cpus have finished initializing */
282         old_active_count = 1;
283         active_count = atomic_read(&active_cpus);
284         while(active_count > 1) {
285                 if (active_count != old_active_count) {
286                         printk_info("Waiting for %d CPUS to stop\n", active_count - 1);
287                         old_active_count = active_count;
288                 }
289                 udelay(10);
290                 active_count = atomic_read(&active_cpus);
291         }
292         for(cpu = cpu_bus->children; cpu; cpu = cpu->sibling) {
293                 if (cpu->path.type != DEVICE_PATH_APIC) {
294                         continue;
295                 }
296                 if (!cpu->initialized) {
297                         printk_err("CPU %u did not initialize!\n", 
298                                 cpu->path.u.apic.apic_id);
299 #warning "FIXME do I need a mainboard_cpu_fixup function?"
300                 }
301         }
302         printk_debug("All AP CPUs stopped\n");
303 }
304
305 #else /* CONFIG_SMP */
306 #define initialize_other_cpus(root) do {} while(0)
307 #endif /* CONFIG_SMP */
308
309 void initialize_cpus(struct bus *cpu_bus)
310 {
311         struct device_path cpu_path;
312         struct cpu_info *info;
313
314         /* Find the info struct for this cpu */
315         info = cpu_info();
316
317 #if NEED_LAPIC == 1
318         /* Ensure the local apic is enabled */
319         enable_lapic();
320
321         /* Get the device path of the boot cpu */
322         cpu_path.type           = DEVICE_PATH_APIC;
323         cpu_path.u.apic.apic_id = lapicid();
324 #else
325         /* Get the device path of the boot cpu */
326         cpu_path.type           = DEVICE_PATH_CPU;
327         cpu_path.u.cpu.id       = 0;
328 #endif
329         
330         /* Find the device structure for the boot cpu */
331         info->cpu = alloc_find_dev(cpu_bus, &cpu_path);
332         
333         /* Initialize the bootstrap processor */
334         cpu_initialize();
335
336         /* Now initialize the rest of the cpus */
337         initialize_other_cpus(cpu_bus);
338 }
339