ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/core/smpboot.c @ 11109:c09d6e997f05

[LINUX] Oney 'nosmp' and 'max_cpus=' command line options.
Based on a patch from Jan Beulich.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Mon Aug 14 16:12:43 2006 +0100 (2006-08-14)
parents d8338b28bcd6
children ff5f976191a5
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 #ifdef CONFIG_SMP_ALTERNATIVES
30 #include <asm/smp_alt.h>
31 #endif
33 extern irqreturn_t smp_reschedule_interrupt(int, void *, struct pt_regs *);
34 extern irqreturn_t smp_call_function_interrupt(int, void *, struct pt_regs *);
36 extern void local_setup_timer(unsigned int cpu);
37 extern void local_teardown_timer(unsigned int cpu);
39 extern void hypervisor_callback(void);
40 extern void failsafe_callback(void);
41 extern void system_call(void);
42 extern void smp_trap_init(trap_info_t *);
44 /* Number of siblings per CPU package */
45 int smp_num_siblings = 1;
46 int phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */
47 EXPORT_SYMBOL(phys_proc_id);
48 int cpu_core_id[NR_CPUS]; /* Core ID of each logical CPU */
49 EXPORT_SYMBOL(cpu_core_id);
51 cpumask_t cpu_online_map;
52 EXPORT_SYMBOL(cpu_online_map);
53 cpumask_t cpu_possible_map;
54 EXPORT_SYMBOL(cpu_possible_map);
56 struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned;
57 EXPORT_SYMBOL(cpu_data);
59 #ifdef CONFIG_HOTPLUG_CPU
60 DEFINE_PER_CPU(int, cpu_state) = { 0 };
61 #endif
63 static DEFINE_PER_CPU(int, resched_irq);
64 static DEFINE_PER_CPU(int, callfunc_irq);
65 static char resched_name[NR_CPUS][15];
66 static char callfunc_name[NR_CPUS][15];
68 u8 cpu_2_logical_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
70 void *xquad_portio;
72 cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned;
73 cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned;
74 EXPORT_SYMBOL(cpu_core_map);
76 #if defined(__i386__)
77 u8 x86_cpu_to_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = 0xff };
78 EXPORT_SYMBOL(x86_cpu_to_apicid);
79 #elif !defined(CONFIG_X86_IO_APIC)
80 unsigned int maxcpus = NR_CPUS;
81 #endif
83 void __init prefill_possible_map(void)
84 {
85 int i, rc;
87 if (!cpus_empty(cpu_possible_map))
88 return;
90 for (i = 0; i < NR_CPUS; i++) {
91 rc = HYPERVISOR_vcpu_op(VCPUOP_is_up, i, NULL);
92 if (rc >= 0)
93 cpu_set(i, cpu_possible_map);
94 }
95 }
97 void __init smp_alloc_memory(void)
98 {
99 }
101 static inline void
102 set_cpu_sibling_map(int cpu)
103 {
104 phys_proc_id[cpu] = cpu;
105 cpu_core_id[cpu] = 0;
107 cpu_sibling_map[cpu] = cpumask_of_cpu(cpu);
108 cpu_core_map[cpu] = cpumask_of_cpu(cpu);
110 cpu_data[cpu].booted_cores = 1;
111 }
113 static void xen_smp_intr_init(unsigned int cpu)
114 {
115 sprintf(resched_name[cpu], "resched%d", cpu);
116 per_cpu(resched_irq, cpu) =
117 bind_ipi_to_irqhandler(
118 RESCHEDULE_VECTOR,
119 cpu,
120 smp_reschedule_interrupt,
121 SA_INTERRUPT,
122 resched_name[cpu],
123 NULL);
124 BUG_ON(per_cpu(resched_irq, cpu) < 0);
126 sprintf(callfunc_name[cpu], "callfunc%d", cpu);
127 per_cpu(callfunc_irq, cpu) =
128 bind_ipi_to_irqhandler(
129 CALL_FUNCTION_VECTOR,
130 cpu,
131 smp_call_function_interrupt,
132 SA_INTERRUPT,
133 callfunc_name[cpu],
134 NULL);
135 BUG_ON(per_cpu(callfunc_irq, cpu) < 0);
137 if (cpu != 0)
138 local_setup_timer(cpu);
139 }
141 #ifdef CONFIG_HOTPLUG_CPU
142 static void xen_smp_intr_exit(unsigned int cpu)
143 {
144 if (cpu != 0)
145 local_teardown_timer(cpu);
147 unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL);
148 unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL);
149 }
150 #endif
152 void cpu_bringup(void)
153 {
154 cpu_init();
155 touch_softlockup_watchdog();
156 preempt_disable();
157 local_irq_enable();
158 }
160 static void cpu_bringup_and_idle(void)
161 {
162 cpu_bringup();
163 cpu_idle();
164 }
166 void cpu_initialize_context(unsigned int cpu)
167 {
168 vcpu_guest_context_t ctxt;
169 struct task_struct *idle = idle_task(cpu);
170 #ifdef __x86_64__
171 struct desc_ptr *gdt_descr = &cpu_gdt_descr[cpu];
172 #else
173 struct Xgt_desc_struct *gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
174 #endif
176 if (cpu == 0)
177 return;
179 memset(&ctxt, 0, sizeof(ctxt));
181 ctxt.flags = VGCF_IN_KERNEL;
182 ctxt.user_regs.ds = __USER_DS;
183 ctxt.user_regs.es = __USER_DS;
184 ctxt.user_regs.fs = 0;
185 ctxt.user_regs.gs = 0;
186 ctxt.user_regs.ss = __KERNEL_DS;
187 ctxt.user_regs.eip = (unsigned long)cpu_bringup_and_idle;
188 ctxt.user_regs.eflags = X86_EFLAGS_IF | 0x1000; /* IOPL_RING1 */
190 memset(&ctxt.fpu_ctxt, 0, sizeof(ctxt.fpu_ctxt));
192 smp_trap_init(ctxt.trap_ctxt);
194 ctxt.ldt_ents = 0;
196 ctxt.gdt_frames[0] = virt_to_mfn(gdt_descr->address);
197 ctxt.gdt_ents = gdt_descr->size / 8;
199 #ifdef __i386__
200 ctxt.user_regs.cs = __KERNEL_CS;
201 ctxt.user_regs.esp = idle->thread.esp0 - sizeof(struct pt_regs);
203 ctxt.kernel_ss = __KERNEL_DS;
204 ctxt.kernel_sp = idle->thread.esp0;
206 ctxt.event_callback_cs = __KERNEL_CS;
207 ctxt.event_callback_eip = (unsigned long)hypervisor_callback;
208 ctxt.failsafe_callback_cs = __KERNEL_CS;
209 ctxt.failsafe_callback_eip = (unsigned long)failsafe_callback;
211 ctxt.ctrlreg[3] = xen_pfn_to_cr3(virt_to_mfn(swapper_pg_dir));
212 #else /* __x86_64__ */
213 ctxt.user_regs.cs = __KERNEL_CS;
214 ctxt.user_regs.esp = idle->thread.rsp0 - sizeof(struct pt_regs);
216 ctxt.kernel_ss = __KERNEL_DS;
217 ctxt.kernel_sp = idle->thread.rsp0;
219 ctxt.event_callback_eip = (unsigned long)hypervisor_callback;
220 ctxt.failsafe_callback_eip = (unsigned long)failsafe_callback;
221 ctxt.syscall_callback_eip = (unsigned long)system_call;
223 ctxt.ctrlreg[3] = xen_pfn_to_cr3(virt_to_mfn(init_level4_pgt));
225 ctxt.gs_base_kernel = (unsigned long)(cpu_pda(cpu));
226 #endif
228 BUG_ON(HYPERVISOR_vcpu_op(VCPUOP_initialise, cpu, &ctxt));
229 }
231 void __init smp_prepare_cpus(unsigned int max_cpus)
232 {
233 int cpu;
234 struct task_struct *idle;
235 #ifdef __x86_64__
236 struct desc_ptr *gdt_descr;
237 #else
238 struct Xgt_desc_struct *gdt_descr;
239 #endif
241 boot_cpu_data.apicid = 0;
242 cpu_data[0] = boot_cpu_data;
244 cpu_2_logical_apicid[0] = 0;
245 x86_cpu_to_apicid[0] = 0;
247 current_thread_info()->cpu = 0;
249 for (cpu = 0; cpu < NR_CPUS; cpu++) {
250 cpus_clear(cpu_sibling_map[cpu]);
251 cpus_clear(cpu_core_map[cpu]);
252 }
254 set_cpu_sibling_map(0);
256 xen_smp_intr_init(0);
258 /* Restrict the possible_map according to max_cpus. */
259 while ((num_possible_cpus() > 1) && (num_possible_cpus() > max_cpus)) {
260 for (cpu = NR_CPUS-1; !cpu_isset(cpu, cpu_possible_map); cpu--)
261 continue;
262 cpu_clear(cpu, cpu_possible_map);
263 }
265 for_each_cpu (cpu) {
266 if (cpu == 0)
267 continue;
269 #ifdef __x86_64__
270 gdt_descr = &cpu_gdt_descr[cpu];
271 #else
272 gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
273 #endif
274 gdt_descr->address = get_zeroed_page(GFP_KERNEL);
275 if (unlikely(!gdt_descr->address)) {
276 printk(KERN_CRIT "CPU%d failed to allocate GDT\n",
277 cpu);
278 continue;
279 }
280 gdt_descr->size = GDT_SIZE;
281 memcpy((void *)gdt_descr->address, cpu_gdt_table, GDT_SIZE);
282 make_page_readonly(
283 (void *)gdt_descr->address,
284 XENFEAT_writable_descriptor_tables);
286 cpu_data[cpu] = boot_cpu_data;
287 cpu_data[cpu].apicid = cpu;
289 cpu_2_logical_apicid[cpu] = cpu;
290 x86_cpu_to_apicid[cpu] = cpu;
292 idle = fork_idle(cpu);
293 if (IS_ERR(idle))
294 panic("failed fork for CPU %d", cpu);
296 #ifdef __x86_64__
297 cpu_pda(cpu)->pcurrent = idle;
298 cpu_pda(cpu)->cpunumber = cpu;
299 clear_ti_thread_flag(idle->thread_info, TIF_FORK);
300 #endif
302 irq_ctx_init(cpu);
304 #ifdef CONFIG_HOTPLUG_CPU
305 if (is_initial_xendomain())
306 cpu_set(cpu, cpu_present_map);
307 #else
308 cpu_set(cpu, cpu_present_map);
309 #endif
311 cpu_initialize_context(cpu);
312 }
314 init_xenbus_allowed_cpumask();
316 #ifdef CONFIG_X86_IO_APIC
317 /*
318 * Here we can be sure that there is an IO-APIC in the system. Let's
319 * go and set it up:
320 */
321 if (!skip_ioapic_setup && nr_ioapics)
322 setup_IO_APIC();
323 #endif
324 }
326 void __devinit smp_prepare_boot_cpu(void)
327 {
328 prefill_possible_map();
329 cpu_present_map = cpumask_of_cpu(0);
330 cpu_online_map = cpumask_of_cpu(0);
331 }
333 #ifdef CONFIG_HOTPLUG_CPU
335 /*
336 * Initialize cpu_present_map late to skip SMP boot code in init/main.c.
337 * But do it early enough to catch critical for_each_present_cpu() loops
338 * in i386-specific code.
339 */
340 static int __init initialize_cpu_present_map(void)
341 {
342 cpu_present_map = cpu_possible_map;
343 return 0;
344 }
345 core_initcall(initialize_cpu_present_map);
347 static void
348 remove_siblinginfo(int cpu)
349 {
350 phys_proc_id[cpu] = BAD_APICID;
351 cpu_core_id[cpu] = BAD_APICID;
353 cpus_clear(cpu_sibling_map[cpu]);
354 cpus_clear(cpu_core_map[cpu]);
356 cpu_data[cpu].booted_cores = 0;
357 }
359 int __cpu_disable(void)
360 {
361 cpumask_t map = cpu_online_map;
362 int cpu = smp_processor_id();
364 if (cpu == 0)
365 return -EBUSY;
367 remove_siblinginfo(cpu);
369 cpu_clear(cpu, map);
370 fixup_irqs(map);
371 cpu_clear(cpu, cpu_online_map);
373 return 0;
374 }
376 void __cpu_die(unsigned int cpu)
377 {
378 while (HYPERVISOR_vcpu_op(VCPUOP_is_up, cpu, NULL)) {
379 current->state = TASK_UNINTERRUPTIBLE;
380 schedule_timeout(HZ/10);
381 }
383 xen_smp_intr_exit(cpu);
385 #ifdef CONFIG_SMP_ALTERNATIVES
386 if (num_online_cpus() == 1)
387 unprepare_for_smp();
388 #endif
389 }
391 #else /* !CONFIG_HOTPLUG_CPU */
393 int __cpu_disable(void)
394 {
395 return -ENOSYS;
396 }
398 void __cpu_die(unsigned int cpu)
399 {
400 BUG();
401 }
403 #endif /* CONFIG_HOTPLUG_CPU */
405 int __devinit __cpu_up(unsigned int cpu)
406 {
407 int rc;
409 rc = cpu_up_check(cpu);
410 if (rc)
411 return rc;
413 #ifdef CONFIG_SMP_ALTERNATIVES
414 if (num_online_cpus() == 1)
415 prepare_for_smp();
416 #endif
418 /* This must be done before setting cpu_online_map */
419 set_cpu_sibling_map(cpu);
420 wmb();
422 xen_smp_intr_init(cpu);
423 cpu_set(cpu, cpu_online_map);
425 rc = HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL);
426 BUG_ON(rc);
428 return 0;
429 }
431 void __init smp_cpus_done(unsigned int max_cpus)
432 {
433 }
435 #ifndef CONFIG_X86_LOCAL_APIC
436 int setup_profiling_timer(unsigned int multiplier)
437 {
438 return -EINVAL;
439 }
440 #endif