ia64/xen-unstable

view linux-2.6-xen-sparse/arch/xen/kernel/smpboot.c @ 7610:5ed53e973b83

Changeset 7419 introduced a check for DOM0 before setting a bit in the
cpu_present map. This prevents domU SMP kernels without HOTPLUG_CPU
support from booting. Secondary cpus need to be present and online
before init/main.c:do_basic_setup() calls init_workqueues() (which
initializes per-cpu workqueues).

Without this patch, non HOTPLUG_CPU enabled kernels hang when flushing
cpu workqueues as the spinlock in the structure is never initialized (it
has a default value of zero which means the lock has been acquired on
x86).

Signed-off-by: Ryan Harper <ryanh@us.ibm.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Wed Nov 02 00:08:01 2005 +0100 (2005-11-02)
parents 305649f5ad56
children 0915074c356e
line source
1 /*
2 * Xen SMP booting functions
3 *
4 * See arch/i386/kernel/smpboot.c for copyright and credits for derived
5 * portions of this file.
6 */
8 #include <linux/module.h>
9 #include <linux/config.h>
10 #include <linux/init.h>
11 #include <linux/kernel.h>
12 #include <linux/mm.h>
13 #include <linux/sched.h>
14 #include <linux/kernel_stat.h>
15 #include <linux/smp_lock.h>
16 #include <linux/irq.h>
17 #include <linux/bootmem.h>
18 #include <linux/notifier.h>
19 #include <linux/cpu.h>
20 #include <linux/percpu.h>
21 #include <asm/desc.h>
22 #include <asm/arch_hooks.h>
23 #include <asm/pgalloc.h>
24 #include <asm-xen/evtchn.h>
25 #include <asm-xen/xen-public/vcpu.h>
26 #include <asm-xen/xenbus.h>
28 #ifdef CONFIG_SMP_ALTERNATIVES
29 #include <asm/smp_alt.h>
30 #endif
32 extern irqreturn_t smp_reschedule_interrupt(int, void *, struct pt_regs *);
33 extern irqreturn_t smp_call_function_interrupt(int, void *, struct pt_regs *);
35 extern void local_setup_timer(unsigned int cpu);
36 extern void local_teardown_timer(unsigned int cpu);
38 extern void hypervisor_callback(void);
39 extern void failsafe_callback(void);
40 extern void system_call(void);
41 extern void smp_trap_init(trap_info_t *);
43 extern cpumask_t cpu_initialized;
45 /* Number of siblings per CPU package */
46 int smp_num_siblings = 1;
47 int phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */
48 EXPORT_SYMBOL(phys_proc_id);
49 int cpu_core_id[NR_CPUS]; /* Core ID of each logical CPU */
50 EXPORT_SYMBOL(cpu_core_id);
52 cpumask_t cpu_online_map;
53 EXPORT_SYMBOL(cpu_online_map);
54 cpumask_t cpu_possible_map;
55 EXPORT_SYMBOL(cpu_possible_map);
57 struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned;
58 EXPORT_SYMBOL(cpu_data);
60 #ifdef CONFIG_HOTPLUG_CPU
61 DEFINE_PER_CPU(int, cpu_state) = { 0 };
62 #endif
64 static DEFINE_PER_CPU(int, resched_irq);
65 static DEFINE_PER_CPU(int, callfunc_irq);
66 static char resched_name[NR_CPUS][15];
67 static char callfunc_name[NR_CPUS][15];
69 u8 cpu_2_logical_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
71 void *xquad_portio;
73 cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned;
74 cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned;
75 EXPORT_SYMBOL(cpu_core_map);
77 #if defined(__i386__)
78 u8 x86_cpu_to_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = 0xff };
79 EXPORT_SYMBOL(x86_cpu_to_apicid);
80 #elif !defined(CONFIG_X86_IO_APIC)
81 unsigned int maxcpus = NR_CPUS;
82 #endif
84 void __init smp_alloc_memory(void)
85 {
86 }
88 static void xen_smp_intr_init(unsigned int cpu)
89 {
90 per_cpu(resched_irq, cpu) =
91 bind_ipi_to_irq(RESCHEDULE_VECTOR, cpu);
92 sprintf(resched_name[cpu], "resched%d", cpu);
93 BUG_ON(request_irq(per_cpu(resched_irq, cpu), smp_reschedule_interrupt,
94 SA_INTERRUPT, resched_name[cpu], NULL));
96 per_cpu(callfunc_irq, cpu) =
97 bind_ipi_to_irq(CALL_FUNCTION_VECTOR, cpu);
98 sprintf(callfunc_name[cpu], "callfunc%d", cpu);
99 BUG_ON(request_irq(per_cpu(callfunc_irq, cpu),
100 smp_call_function_interrupt,
101 SA_INTERRUPT, callfunc_name[cpu], NULL));
103 if (cpu != 0)
104 local_setup_timer(cpu);
105 }
107 #ifdef CONFIG_HOTPLUG_CPU
108 static void xen_smp_intr_exit(unsigned int cpu)
109 {
110 if (cpu != 0)
111 local_teardown_timer(cpu);
113 free_irq(per_cpu(resched_irq, cpu), NULL);
114 unbind_ipi_from_irq(RESCHEDULE_VECTOR, cpu);
116 free_irq(per_cpu(callfunc_irq, cpu), NULL);
117 unbind_ipi_from_irq(CALL_FUNCTION_VECTOR, cpu);
118 }
119 #endif
121 static void cpu_bringup(void)
122 {
123 if (!cpu_isset(smp_processor_id(), cpu_initialized))
124 cpu_init();
125 local_irq_enable();
126 cpu_idle();
127 }
129 void vcpu_prepare(int vcpu)
130 {
131 vcpu_guest_context_t ctxt;
132 struct task_struct *idle = idle_task(vcpu);
134 if (vcpu == 0)
135 return;
137 memset(&ctxt, 0, sizeof(ctxt));
139 ctxt.flags = VGCF_IN_KERNEL;
140 ctxt.user_regs.ds = __USER_DS;
141 ctxt.user_regs.es = __USER_DS;
142 ctxt.user_regs.fs = 0;
143 ctxt.user_regs.gs = 0;
144 ctxt.user_regs.ss = __KERNEL_DS;
145 ctxt.user_regs.eip = (unsigned long)cpu_bringup;
146 ctxt.user_regs.eflags = X86_EFLAGS_IF | 0x1000; /* IOPL_RING1 */
148 memset(&ctxt.fpu_ctxt, 0, sizeof(ctxt.fpu_ctxt));
150 smp_trap_init(ctxt.trap_ctxt);
152 ctxt.ldt_ents = 0;
154 ctxt.gdt_frames[0] = virt_to_mfn(cpu_gdt_descr[vcpu].address);
155 ctxt.gdt_ents = cpu_gdt_descr[vcpu].size / 8;
157 #ifdef __i386__
158 ctxt.user_regs.cs = __KERNEL_CS;
159 ctxt.user_regs.esp = idle->thread.esp;
161 ctxt.kernel_ss = __KERNEL_DS;
162 ctxt.kernel_sp = idle->thread.esp0;
164 ctxt.event_callback_cs = __KERNEL_CS;
165 ctxt.event_callback_eip = (unsigned long)hypervisor_callback;
166 ctxt.failsafe_callback_cs = __KERNEL_CS;
167 ctxt.failsafe_callback_eip = (unsigned long)failsafe_callback;
169 ctxt.ctrlreg[3] = virt_to_mfn(swapper_pg_dir) << PAGE_SHIFT;
170 #else
171 ctxt.user_regs.cs = __KERNEL_CS | 3;
172 ctxt.user_regs.esp = idle->thread.rsp;
174 ctxt.kernel_ss = __KERNEL_DS;
175 ctxt.kernel_sp = idle->thread.rsp0;
177 ctxt.event_callback_eip = (unsigned long)hypervisor_callback;
178 ctxt.failsafe_callback_eip = (unsigned long)failsafe_callback;
179 ctxt.syscall_callback_eip = (unsigned long)system_call;
181 ctxt.ctrlreg[3] = virt_to_mfn(init_level4_pgt) << PAGE_SHIFT;
183 ctxt.gs_base_kernel = (unsigned long)(cpu_pda + vcpu);
184 #endif
186 BUG_ON(HYPERVISOR_vcpu_op(VCPUOP_initialise, vcpu, &ctxt));
187 }
189 void __init smp_prepare_cpus(unsigned int max_cpus)
190 {
191 int cpu, rc;
192 struct task_struct *idle;
194 cpu_data[0] = boot_cpu_data;
196 cpu_2_logical_apicid[0] = 0;
197 x86_cpu_to_apicid[0] = 0;
199 current_thread_info()->cpu = 0;
200 cpu_sibling_map[0] = cpumask_of_cpu(0);
201 cpu_core_map[0] = cpumask_of_cpu(0);
203 if (max_cpus != 0)
204 xen_smp_intr_init(0);
206 for (cpu = 1; cpu < max_cpus; cpu++) {
207 rc = HYPERVISOR_vcpu_op(VCPUOP_is_up, cpu, NULL);
208 if (rc == -ENOENT)
209 break;
210 BUG_ON(rc != 0);
212 cpu_data[cpu] = boot_cpu_data;
213 cpu_2_logical_apicid[cpu] = cpu;
214 x86_cpu_to_apicid[cpu] = cpu;
216 idle = fork_idle(cpu);
217 if (IS_ERR(idle))
218 panic("failed fork for CPU %d", cpu);
220 #ifdef __x86_64__
221 cpu_pda[cpu].pcurrent = idle;
222 cpu_pda[cpu].cpunumber = cpu;
223 per_cpu(init_tss,cpu).rsp0 = idle->thread.rsp;
224 clear_ti_thread_flag(idle->thread_info, TIF_FORK);
225 #endif
227 irq_ctx_init(cpu);
229 cpu_gdt_descr[cpu].address =
230 __get_free_page(GFP_KERNEL|__GFP_ZERO);
231 BUG_ON(cpu_gdt_descr[0].size > PAGE_SIZE);
232 cpu_gdt_descr[cpu].size = cpu_gdt_descr[0].size;
233 memcpy((void *)cpu_gdt_descr[cpu].address,
234 (void *)cpu_gdt_descr[0].address,
235 cpu_gdt_descr[0].size);
236 make_page_readonly((void *)cpu_gdt_descr[cpu].address);
238 cpu_set(cpu, cpu_possible_map);
239 #ifdef CONFIG_HOTPLUG_CPU
240 if (xen_start_info->flags & SIF_INITDOMAIN)
241 cpu_set(cpu, cpu_present_map);
242 #else
243 cpu_set(cpu, cpu_present_map);
244 #endif
246 vcpu_prepare(cpu);
247 }
249 /* Currently, Xen gives no dynamic NUMA/HT info. */
250 for (cpu = 1; cpu < NR_CPUS; cpu++) {
251 cpu_sibling_map[cpu] = cpumask_of_cpu(cpu);
252 cpu_core_map[cpu] = cpumask_of_cpu(cpu);
253 }
255 #ifdef CONFIG_X86_IO_APIC
256 /*
257 * Here we can be sure that there is an IO-APIC in the system. Let's
258 * go and set it up:
259 */
260 if (!skip_ioapic_setup && nr_ioapics)
261 setup_IO_APIC();
262 #endif
263 }
265 void __devinit smp_prepare_boot_cpu(void)
266 {
267 cpu_possible_map = cpumask_of_cpu(0);
268 cpu_present_map = cpumask_of_cpu(0);
269 cpu_online_map = cpumask_of_cpu(0);
270 }
272 #ifdef CONFIG_HOTPLUG_CPU
274 static void vcpu_hotplug(unsigned int cpu)
275 {
276 int err;
277 char dir[32], state[32];
279 if ((cpu >= NR_CPUS) || !cpu_possible(cpu))
280 return;
282 sprintf(dir, "cpu/%d", cpu);
283 err = xenbus_scanf(NULL, dir, "availability", "%s", state);
284 if (err != 1) {
285 printk(KERN_ERR "XENBUS: Unable to read cpu state\n");
286 return;
287 }
289 if (strcmp(state, "online") == 0) {
290 cpu_set(cpu, cpu_present_map);
291 (void)cpu_up(cpu);
292 } else if (strcmp(state, "offline") == 0) {
293 (void)cpu_down(cpu);
294 } else {
295 printk(KERN_ERR "XENBUS: unknown state(%s) on CPU%d\n",
296 state, cpu);
297 }
298 }
300 static void handle_vcpu_hotplug_event(
301 struct xenbus_watch *watch, const char **vec, unsigned int len)
302 {
303 int cpu;
304 char *cpustr;
305 const char *node = vec[XS_WATCH_PATH];
307 if ((cpustr = strstr(node, "cpu/")) != NULL) {
308 sscanf(cpustr, "cpu/%d", &cpu);
309 vcpu_hotplug(cpu);
310 }
311 }
313 static int setup_cpu_watcher(struct notifier_block *notifier,
314 unsigned long event, void *data)
315 {
316 int i;
318 static struct xenbus_watch cpu_watch = {
319 .node = "cpu",
320 .callback = handle_vcpu_hotplug_event };
321 (void)register_xenbus_watch(&cpu_watch);
323 if (!(xen_start_info->flags & SIF_INITDOMAIN)) {
324 for_each_cpu(i)
325 vcpu_hotplug(i);
326 printk(KERN_INFO "Brought up %ld CPUs\n",
327 (long)num_online_cpus());
328 }
330 return NOTIFY_DONE;
331 }
333 static int __init setup_vcpu_hotplug_event(void)
334 {
335 static struct notifier_block xsn_cpu = {
336 .notifier_call = setup_cpu_watcher };
337 register_xenstore_notifier(&xsn_cpu);
338 return 0;
339 }
341 subsys_initcall(setup_vcpu_hotplug_event);
343 int __cpu_disable(void)
344 {
345 cpumask_t map = cpu_online_map;
346 int cpu = smp_processor_id();
348 if (cpu == 0)
349 return -EBUSY;
351 cpu_clear(cpu, map);
352 fixup_irqs(map);
353 cpu_clear(cpu, cpu_online_map);
355 return 0;
356 }
358 void __cpu_die(unsigned int cpu)
359 {
360 while (HYPERVISOR_vcpu_op(VCPUOP_is_up, cpu, NULL)) {
361 current->state = TASK_UNINTERRUPTIBLE;
362 schedule_timeout(HZ/10);
363 }
365 xen_smp_intr_exit(cpu);
367 #ifdef CONFIG_SMP_ALTERNATIVES
368 if (num_online_cpus() == 1)
369 unprepare_for_smp();
370 #endif
371 }
373 #else /* !CONFIG_HOTPLUG_CPU */
375 int __cpu_disable(void)
376 {
377 return -ENOSYS;
378 }
380 void __cpu_die(unsigned int cpu)
381 {
382 BUG();
383 }
385 #endif /* CONFIG_HOTPLUG_CPU */
387 int __devinit __cpu_up(unsigned int cpu)
388 {
389 #ifdef CONFIG_SMP_ALTERNATIVES
390 if (num_online_cpus() == 1)
391 prepare_for_smp();
392 #endif
394 xen_smp_intr_init(cpu);
395 cpu_set(cpu, cpu_online_map);
396 HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL);
398 return 0;
399 }
401 void __init smp_cpus_done(unsigned int max_cpus)
402 {
403 }
405 /*
406 * Local variables:
407 * c-file-style: "linux"
408 * indent-tabs-mode: t
409 * c-indent-level: 8
410 * c-basic-offset: 8
411 * tab-width: 8
412 * End:
413 */