ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/core/smpboot.c @ 13978:477a3bde3b61

linux: miscellaneous changes after upgrade through 2.6.17.
Signed-off-by: Jan Beulich <jbeulich@novell.com>
author kfraser@localhost.localdomain
date Thu Feb 15 14:12:32 2007 +0000 (2007-02-15)
parents 5e3b47bcc311
children e47738923a05
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 <xen/evtchn.h>
25 #include <xen/interface/vcpu.h>
26 #include <xen/cpu_hotplug.h>
27 #include <xen/xenbus.h>
29 extern irqreturn_t smp_reschedule_interrupt(int, void *, struct pt_regs *);
30 extern irqreturn_t smp_call_function_interrupt(int, void *, struct pt_regs *);
32 extern int local_setup_timer(unsigned int cpu);
33 extern void local_teardown_timer(unsigned int cpu);
35 extern void hypervisor_callback(void);
36 extern void failsafe_callback(void);
37 extern void system_call(void);
38 extern void smp_trap_init(trap_info_t *);
40 /* Number of siblings per CPU package */
41 int smp_num_siblings = 1;
42 int phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */
43 EXPORT_SYMBOL(phys_proc_id);
44 int cpu_core_id[NR_CPUS]; /* Core ID of each logical CPU */
45 EXPORT_SYMBOL(cpu_core_id);
47 cpumask_t cpu_online_map;
48 EXPORT_SYMBOL(cpu_online_map);
49 cpumask_t cpu_possible_map;
50 EXPORT_SYMBOL(cpu_possible_map);
51 static cpumask_t cpu_initialized_map;
53 struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned;
54 EXPORT_SYMBOL(cpu_data);
56 #ifdef CONFIG_HOTPLUG_CPU
57 DEFINE_PER_CPU(int, cpu_state) = { 0 };
58 #endif
60 static DEFINE_PER_CPU(int, resched_irq);
61 static DEFINE_PER_CPU(int, callfunc_irq);
62 static char resched_name[NR_CPUS][15];
63 static char callfunc_name[NR_CPUS][15];
65 u8 cpu_2_logical_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
67 void *xquad_portio;
69 cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned;
70 cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned;
71 EXPORT_SYMBOL(cpu_core_map);
73 #if defined(__i386__)
74 u8 x86_cpu_to_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = 0xff };
75 EXPORT_SYMBOL(x86_cpu_to_apicid);
76 #elif !defined(CONFIG_X86_IO_APIC)
77 unsigned int maxcpus = NR_CPUS;
78 #endif
80 void __init prefill_possible_map(void)
81 {
82 int i, rc;
84 for_each_possible_cpu(i)
85 if (i != smp_processor_id())
86 return;
88 for (i = 0; i < NR_CPUS; i++) {
89 rc = HYPERVISOR_vcpu_op(VCPUOP_is_up, i, NULL);
90 if (rc >= 0)
91 cpu_set(i, cpu_possible_map);
92 }
93 }
95 void __init smp_alloc_memory(void)
96 {
97 }
99 static inline void
100 set_cpu_sibling_map(int cpu)
101 {
102 phys_proc_id[cpu] = cpu;
103 cpu_core_id[cpu] = 0;
105 cpu_sibling_map[cpu] = cpumask_of_cpu(cpu);
106 cpu_core_map[cpu] = cpumask_of_cpu(cpu);
108 cpu_data[cpu].booted_cores = 1;
109 }
111 static void
112 remove_siblinginfo(int cpu)
113 {
114 phys_proc_id[cpu] = BAD_APICID;
115 cpu_core_id[cpu] = BAD_APICID;
117 cpus_clear(cpu_sibling_map[cpu]);
118 cpus_clear(cpu_core_map[cpu]);
120 cpu_data[cpu].booted_cores = 0;
121 }
123 static int xen_smp_intr_init(unsigned int cpu)
124 {
125 int rc;
127 per_cpu(resched_irq, cpu) = per_cpu(callfunc_irq, cpu) = -1;
129 sprintf(resched_name[cpu], "resched%d", cpu);
130 rc = bind_ipi_to_irqhandler(RESCHEDULE_VECTOR,
131 cpu,
132 smp_reschedule_interrupt,
133 SA_INTERRUPT,
134 resched_name[cpu],
135 NULL);
136 if (rc < 0)
137 goto fail;
138 per_cpu(resched_irq, cpu) = rc;
140 sprintf(callfunc_name[cpu], "callfunc%d", cpu);
141 rc = bind_ipi_to_irqhandler(CALL_FUNCTION_VECTOR,
142 cpu,
143 smp_call_function_interrupt,
144 SA_INTERRUPT,
145 callfunc_name[cpu],
146 NULL);
147 if (rc < 0)
148 goto fail;
149 per_cpu(callfunc_irq, cpu) = rc;
151 if ((cpu != 0) && ((rc = local_setup_timer(cpu)) != 0))
152 goto fail;
154 return 0;
156 fail:
157 if (per_cpu(resched_irq, cpu) >= 0)
158 unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL);
159 if (per_cpu(callfunc_irq, cpu) >= 0)
160 unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL);
161 return rc;
162 }
164 #ifdef CONFIG_HOTPLUG_CPU
165 static void xen_smp_intr_exit(unsigned int cpu)
166 {
167 if (cpu != 0)
168 local_teardown_timer(cpu);
170 unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL);
171 unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL);
172 }
173 #endif
175 void cpu_bringup(void)
176 {
177 cpu_init();
178 touch_softlockup_watchdog();
179 preempt_disable();
180 local_irq_enable();
181 }
183 static void cpu_bringup_and_idle(void)
184 {
185 cpu_bringup();
186 cpu_idle();
187 }
189 void cpu_initialize_context(unsigned int cpu)
190 {
191 vcpu_guest_context_t ctxt;
192 struct task_struct *idle = idle_task(cpu);
193 #ifdef __x86_64__
194 struct desc_ptr *gdt_descr = &cpu_gdt_descr[cpu];
195 #else
196 struct Xgt_desc_struct *gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
197 #endif
199 if (cpu == 0)
200 return;
202 memset(&ctxt, 0, sizeof(ctxt));
204 ctxt.flags = VGCF_IN_KERNEL;
205 ctxt.user_regs.ds = __USER_DS;
206 ctxt.user_regs.es = __USER_DS;
207 ctxt.user_regs.fs = 0;
208 ctxt.user_regs.gs = 0;
209 ctxt.user_regs.ss = __KERNEL_DS;
210 ctxt.user_regs.eip = (unsigned long)cpu_bringup_and_idle;
211 ctxt.user_regs.eflags = X86_EFLAGS_IF | 0x1000; /* IOPL_RING1 */
213 memset(&ctxt.fpu_ctxt, 0, sizeof(ctxt.fpu_ctxt));
215 smp_trap_init(ctxt.trap_ctxt);
217 ctxt.ldt_ents = 0;
219 ctxt.gdt_frames[0] = virt_to_mfn(gdt_descr->address);
220 ctxt.gdt_ents = gdt_descr->size / 8;
222 #ifdef __i386__
223 ctxt.user_regs.cs = __KERNEL_CS;
224 ctxt.user_regs.esp = idle->thread.esp0 - sizeof(struct pt_regs);
226 ctxt.kernel_ss = __KERNEL_DS;
227 ctxt.kernel_sp = idle->thread.esp0;
229 ctxt.event_callback_cs = __KERNEL_CS;
230 ctxt.event_callback_eip = (unsigned long)hypervisor_callback;
231 ctxt.failsafe_callback_cs = __KERNEL_CS;
232 ctxt.failsafe_callback_eip = (unsigned long)failsafe_callback;
234 ctxt.ctrlreg[3] = xen_pfn_to_cr3(virt_to_mfn(swapper_pg_dir));
235 #else /* __x86_64__ */
236 ctxt.user_regs.cs = __KERNEL_CS;
237 ctxt.user_regs.esp = idle->thread.rsp0 - sizeof(struct pt_regs);
239 ctxt.kernel_ss = __KERNEL_DS;
240 ctxt.kernel_sp = idle->thread.rsp0;
242 ctxt.event_callback_eip = (unsigned long)hypervisor_callback;
243 ctxt.failsafe_callback_eip = (unsigned long)failsafe_callback;
244 ctxt.syscall_callback_eip = (unsigned long)system_call;
246 ctxt.ctrlreg[3] = xen_pfn_to_cr3(virt_to_mfn(init_level4_pgt));
248 ctxt.gs_base_kernel = (unsigned long)(cpu_pda(cpu));
249 #endif
251 BUG_ON(HYPERVISOR_vcpu_op(VCPUOP_initialise, cpu, &ctxt));
252 }
254 void __init smp_prepare_cpus(unsigned int max_cpus)
255 {
256 int cpu;
257 struct task_struct *idle;
258 #ifdef __x86_64__
259 struct desc_ptr *gdt_descr;
260 #else
261 struct Xgt_desc_struct *gdt_descr;
262 #endif
264 boot_cpu_data.apicid = 0;
265 cpu_data[0] = boot_cpu_data;
267 cpu_2_logical_apicid[0] = 0;
268 x86_cpu_to_apicid[0] = 0;
270 current_thread_info()->cpu = 0;
272 for (cpu = 0; cpu < NR_CPUS; cpu++) {
273 cpus_clear(cpu_sibling_map[cpu]);
274 cpus_clear(cpu_core_map[cpu]);
275 }
277 set_cpu_sibling_map(0);
279 if (xen_smp_intr_init(0))
280 BUG();
282 cpu_initialized_map = cpumask_of_cpu(0);
284 /* Restrict the possible_map according to max_cpus. */
285 while ((num_possible_cpus() > 1) && (num_possible_cpus() > max_cpus)) {
286 for (cpu = NR_CPUS-1; !cpu_isset(cpu, cpu_possible_map); cpu--)
287 continue;
288 cpu_clear(cpu, cpu_possible_map);
289 }
291 for_each_possible_cpu (cpu) {
292 if (cpu == 0)
293 continue;
295 #ifdef __x86_64__
296 gdt_descr = &cpu_gdt_descr[cpu];
297 #else
298 gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
299 #endif
300 gdt_descr->address = get_zeroed_page(GFP_KERNEL);
301 if (unlikely(!gdt_descr->address)) {
302 printk(KERN_CRIT "CPU%d failed to allocate GDT\n",
303 cpu);
304 continue;
305 }
306 gdt_descr->size = GDT_SIZE;
307 memcpy((void *)gdt_descr->address, cpu_gdt_table, GDT_SIZE);
308 make_page_readonly(
309 (void *)gdt_descr->address,
310 XENFEAT_writable_descriptor_tables);
312 cpu_data[cpu] = boot_cpu_data;
313 cpu_data[cpu].apicid = cpu;
315 cpu_2_logical_apicid[cpu] = cpu;
316 x86_cpu_to_apicid[cpu] = cpu;
318 idle = fork_idle(cpu);
319 if (IS_ERR(idle))
320 panic("failed fork for CPU %d", cpu);
322 #ifdef __x86_64__
323 cpu_pda(cpu)->pcurrent = idle;
324 cpu_pda(cpu)->cpunumber = cpu;
325 clear_ti_thread_flag(idle->thread_info, TIF_FORK);
326 #endif
328 irq_ctx_init(cpu);
330 #ifdef CONFIG_HOTPLUG_CPU
331 if (is_initial_xendomain())
332 cpu_set(cpu, cpu_present_map);
333 #else
334 cpu_set(cpu, cpu_present_map);
335 #endif
336 }
338 init_xenbus_allowed_cpumask();
340 #ifdef CONFIG_X86_IO_APIC
341 /*
342 * Here we can be sure that there is an IO-APIC in the system. Let's
343 * go and set it up:
344 */
345 if (!skip_ioapic_setup && nr_ioapics)
346 setup_IO_APIC();
347 #endif
348 }
350 void __devinit smp_prepare_boot_cpu(void)
351 {
352 prefill_possible_map();
353 }
355 #ifdef CONFIG_HOTPLUG_CPU
357 /*
358 * Initialize cpu_present_map late to skip SMP boot code in init/main.c.
359 * But do it early enough to catch critical for_each_present_cpu() loops
360 * in i386-specific code.
361 */
362 static int __init initialize_cpu_present_map(void)
363 {
364 cpu_present_map = cpu_possible_map;
365 return 0;
366 }
367 core_initcall(initialize_cpu_present_map);
369 int __cpu_disable(void)
370 {
371 cpumask_t map = cpu_online_map;
372 int cpu = smp_processor_id();
374 if (cpu == 0)
375 return -EBUSY;
377 remove_siblinginfo(cpu);
379 cpu_clear(cpu, map);
380 fixup_irqs(map);
381 cpu_clear(cpu, cpu_online_map);
383 return 0;
384 }
386 void __cpu_die(unsigned int cpu)
387 {
388 while (HYPERVISOR_vcpu_op(VCPUOP_is_up, cpu, NULL)) {
389 current->state = TASK_UNINTERRUPTIBLE;
390 schedule_timeout(HZ/10);
391 }
393 xen_smp_intr_exit(cpu);
395 if (num_online_cpus() == 1)
396 alternatives_smp_switch(0);
397 }
399 #else /* !CONFIG_HOTPLUG_CPU */
401 int __cpu_disable(void)
402 {
403 return -ENOSYS;
404 }
406 void __cpu_die(unsigned int cpu)
407 {
408 BUG();
409 }
411 #endif /* CONFIG_HOTPLUG_CPU */
413 int __devinit __cpu_up(unsigned int cpu)
414 {
415 int rc;
417 rc = cpu_up_check(cpu);
418 if (rc)
419 return rc;
421 if (!cpu_isset(cpu, cpu_initialized_map)) {
422 cpu_set(cpu, cpu_initialized_map);
423 cpu_initialize_context(cpu);
424 }
426 if (num_online_cpus() == 1)
427 alternatives_smp_switch(1);
429 /* This must be done before setting cpu_online_map */
430 set_cpu_sibling_map(cpu);
431 wmb();
433 rc = xen_smp_intr_init(cpu);
434 if (rc) {
435 remove_siblinginfo(cpu);
436 return rc;
437 }
439 cpu_set(cpu, cpu_online_map);
441 rc = HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL);
442 BUG_ON(rc);
444 return 0;
445 }
447 void __init smp_cpus_done(unsigned int max_cpus)
448 {
449 }
451 #ifndef CONFIG_X86_LOCAL_APIC
452 int setup_profiling_timer(unsigned int multiplier)
453 {
454 return -EINVAL;
455 }
456 #endif