smp.c 15.6 KB
Newer Older
J
Jeremy Fitzhardinge 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * Xen SMP support
 *
 * This file implements the Xen versions of smp_ops.  SMP under Xen is
 * very straightforward.  Bringing a CPU up is simply a matter of
 * loading its initial context and setting it running.
 *
 * IPIs are handled through the Xen event mechanism.
 *
 * Because virtual CPUs can be scheduled onto any real CPU, there's no
 * useful topology information for the kernel to make use of.  As a
 * result, all CPUs are treated as if they're single-core and
 * single-threaded.
 */
#include <linux/sched.h>
#include <linux/err.h>
17
#include <linux/slab.h>
J
Jeremy Fitzhardinge 已提交
18
#include <linux/smp.h>
19
#include <linux/irq_work.h>
J
Jeremy Fitzhardinge 已提交
20 21 22 23 24 25 26 27 28 29 30 31

#include <asm/paravirt.h>
#include <asm/desc.h>
#include <asm/pgtable.h>
#include <asm/cpu.h>

#include <xen/interface/xen.h>
#include <xen/interface/vcpu.h>

#include <asm/xen/interface.h>
#include <asm/xen/hypercall.h>

32
#include <xen/xen.h>
J
Jeremy Fitzhardinge 已提交
33 34 35
#include <xen/page.h>
#include <xen/events.h>

36
#include <xen/hvc-console.h>
J
Jeremy Fitzhardinge 已提交
37 38 39
#include "xen-ops.h"
#include "mmu.h"

40
cpumask_var_t xen_cpu_initialized_map;
J
Jeremy Fitzhardinge 已提交
41

42 43 44 45 46 47 48 49 50
struct xen_common_irq {
	int irq;
	char *name;
};
static DEFINE_PER_CPU(struct xen_common_irq, xen_resched_irq);
static DEFINE_PER_CPU(struct xen_common_irq, xen_callfunc_irq);
static DEFINE_PER_CPU(struct xen_common_irq, xen_callfuncsingle_irq);
static DEFINE_PER_CPU(struct xen_common_irq, xen_irq_work);
static DEFINE_PER_CPU(struct xen_common_irq, xen_debug_irq) = { .irq = -1 };
J
Jeremy Fitzhardinge 已提交
51 52

static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id);
53
static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_id);
54
static irqreturn_t xen_irq_work_interrupt(int irq, void *dev_id);
J
Jeremy Fitzhardinge 已提交
55 56

/*
57
 * Reschedule call back.
J
Jeremy Fitzhardinge 已提交
58 59 60
 */
static irqreturn_t xen_reschedule_interrupt(int irq, void *dev_id)
{
61
	inc_irq_stat(irq_resched_count);
62
	scheduler_ipi();
63

J
Jeremy Fitzhardinge 已提交
64 65 66
	return IRQ_HANDLED;
}

67
static void __cpuinit cpu_bringup(void)
J
Jeremy Fitzhardinge 已提交
68
{
69
	int cpu;
J
Jeremy Fitzhardinge 已提交
70 71

	cpu_init();
A
Alex Nixon 已提交
72
	touch_softlockup_watchdog();
73 74
	preempt_disable();

75
	xen_enable_sysenter();
76
	xen_enable_syscall();
J
Jeremy Fitzhardinge 已提交
77

78 79 80 81
	cpu = smp_processor_id();
	smp_store_cpu_info(cpu);
	cpu_data(cpu).x86_max_cores = 1;
	set_cpu_sibling_map(cpu);
J
Jeremy Fitzhardinge 已提交
82 83 84

	xen_setup_cpu_clockevents();

85 86
	notify_cpu_starting(cpu);

87
	set_cpu_online(cpu, true);
88

89
	this_cpu_write(cpu_state, CPU_ONLINE);
90

91 92
	wmb();

J
Jeremy Fitzhardinge 已提交
93 94 95 96
	/* We can take interrupts now: we're officially "up". */
	local_irq_enable();

	wmb();			/* make sure everything is out */
A
Alex Nixon 已提交
97 98
}

99
static void __cpuinit cpu_bringup_and_idle(void)
A
Alex Nixon 已提交
100 101
{
	cpu_bringup();
T
Thomas Gleixner 已提交
102
	cpu_startup_entry(CPUHP_ONLINE);
J
Jeremy Fitzhardinge 已提交
103 104
}

105 106
static void xen_smp_intr_free(unsigned int cpu)
{
107 108 109 110 111 112 113 114
	if (per_cpu(xen_resched_irq, cpu).irq >= 0)
		unbind_from_irqhandler(per_cpu(xen_resched_irq, cpu).irq, NULL);
	if (per_cpu(xen_callfunc_irq, cpu).irq >= 0)
		unbind_from_irqhandler(per_cpu(xen_callfunc_irq, cpu).irq, NULL);
	if (per_cpu(xen_debug_irq, cpu).irq >= 0)
		unbind_from_irqhandler(per_cpu(xen_debug_irq, cpu).irq, NULL);
	if (per_cpu(xen_callfuncsingle_irq, cpu).irq >= 0)
		unbind_from_irqhandler(per_cpu(xen_callfuncsingle_irq, cpu).irq,
115 116 117 118
				       NULL);
	if (xen_hvm_domain())
		return;

119 120
	if (per_cpu(xen_irq_work, cpu).irq >= 0)
		unbind_from_irqhandler(per_cpu(xen_irq_work, cpu).irq, NULL);
121
};
J
Jeremy Fitzhardinge 已提交
122 123 124
static int xen_smp_intr_init(unsigned int cpu)
{
	int rc;
125
	const char *resched_name, *callfunc_name, *debug_name;
J
Jeremy Fitzhardinge 已提交
126 127 128 129 130 131 132 133 134 135

	resched_name = kasprintf(GFP_KERNEL, "resched%d", cpu);
	rc = bind_ipi_to_irqhandler(XEN_RESCHEDULE_VECTOR,
				    cpu,
				    xen_reschedule_interrupt,
				    IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
				    resched_name,
				    NULL);
	if (rc < 0)
		goto fail;
136
	per_cpu(xen_resched_irq, cpu).irq = rc;
J
Jeremy Fitzhardinge 已提交
137 138 139 140 141 142 143 144 145 146

	callfunc_name = kasprintf(GFP_KERNEL, "callfunc%d", cpu);
	rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_VECTOR,
				    cpu,
				    xen_call_function_interrupt,
				    IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
				    callfunc_name,
				    NULL);
	if (rc < 0)
		goto fail;
147
	per_cpu(xen_callfunc_irq, cpu).irq = rc;
J
Jeremy Fitzhardinge 已提交
148

149 150 151 152 153 154
	debug_name = kasprintf(GFP_KERNEL, "debug%d", cpu);
	rc = bind_virq_to_irqhandler(VIRQ_DEBUG, cpu, xen_debug_interrupt,
				     IRQF_DISABLED | IRQF_PERCPU | IRQF_NOBALANCING,
				     debug_name, NULL);
	if (rc < 0)
		goto fail;
155
	per_cpu(xen_debug_irq, cpu).irq = rc;
156

157 158 159 160 161 162 163 164 165
	callfunc_name = kasprintf(GFP_KERNEL, "callfuncsingle%d", cpu);
	rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_SINGLE_VECTOR,
				    cpu,
				    xen_call_function_single_interrupt,
				    IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
				    callfunc_name,
				    NULL);
	if (rc < 0)
		goto fail;
166
	per_cpu(xen_callfuncsingle_irq, cpu).irq = rc;
167

168 169 170 171 172 173 174
	/*
	 * The IRQ worker on PVHVM goes through the native path and uses the
	 * IPI mechanism.
	 */
	if (xen_hvm_domain())
		return 0;

175 176 177 178 179 180 181 182 183
	callfunc_name = kasprintf(GFP_KERNEL, "irqwork%d", cpu);
	rc = bind_ipi_to_irqhandler(XEN_IRQ_WORK_VECTOR,
				    cpu,
				    xen_irq_work_interrupt,
				    IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
				    callfunc_name,
				    NULL);
	if (rc < 0)
		goto fail;
184
	per_cpu(xen_irq_work, cpu).irq = rc;
185

J
Jeremy Fitzhardinge 已提交
186 187 188
	return 0;

 fail:
189
	xen_smp_intr_free(cpu);
J
Jeremy Fitzhardinge 已提交
190 191 192
	return rc;
}

193
static void __init xen_fill_possible_map(void)
J
Jeremy Fitzhardinge 已提交
194 195 196
{
	int i, rc;

197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
	if (xen_initial_domain())
		return;

	for (i = 0; i < nr_cpu_ids; i++) {
		rc = HYPERVISOR_vcpu_op(VCPUOP_is_up, i, NULL);
		if (rc >= 0) {
			num_processors++;
			set_cpu_possible(i, true);
		}
	}
}

static void __init xen_filter_cpu_maps(void)
{
	int i, rc;
212
	unsigned int subtract = 0;
213 214 215 216

	if (!xen_initial_domain())
		return;

217 218
	num_processors = 0;
	disabled_cpus = 0;
219
	for (i = 0; i < nr_cpu_ids; i++) {
J
Jeremy Fitzhardinge 已提交
220
		rc = HYPERVISOR_vcpu_op(VCPUOP_is_up, i, NULL);
J
Jeremy Fitzhardinge 已提交
221 222
		if (rc >= 0) {
			num_processors++;
223
			set_cpu_possible(i, true);
224 225 226
		} else {
			set_cpu_possible(i, false);
			set_cpu_present(i, false);
227
			subtract++;
J
Jeremy Fitzhardinge 已提交
228
		}
J
Jeremy Fitzhardinge 已提交
229
	}
230 231 232 233 234 235 236 237 238 239 240 241 242
#ifdef CONFIG_HOTPLUG_CPU
	/* This is akin to using 'nr_cpus' on the Linux command line.
	 * Which is OK as when we use 'dom0_max_vcpus=X' we can only
	 * have up to X, while nr_cpu_ids is greater than X. This
	 * normally is not a problem, except when CPU hotplugging
	 * is involved and then there might be more than X CPUs
	 * in the guest - which will not work as there is no
	 * hypercall to expand the max number of VCPUs an already
	 * running guest has. So cap it up to X. */
	if (subtract)
		nr_cpu_ids = nr_cpu_ids - subtract;
#endif

J
Jeremy Fitzhardinge 已提交
243 244
}

245
static void __init xen_smp_prepare_boot_cpu(void)
J
Jeremy Fitzhardinge 已提交
246 247 248 249 250 251
{
	BUG_ON(smp_processor_id() != 0);
	native_smp_prepare_boot_cpu();

	/* We've switched to the "real" per-cpu gdt, so make sure the
	   old memory can be recycled */
252
	make_lowmem_page_readwrite(xen_initial_gdt);
253

254
	xen_filter_cpu_maps();
255
	xen_setup_vcpu_info_placement();
J
Jeremy Fitzhardinge 已提交
256 257
}

258
static void __init xen_smp_prepare_cpus(unsigned int max_cpus)
J
Jeremy Fitzhardinge 已提交
259 260
{
	unsigned cpu;
A
Andrew Jones 已提交
261
	unsigned int i;
J
Jeremy Fitzhardinge 已提交
262

263 264 265 266 267 268 269 270 271
	if (skip_ioapic_setup) {
		char *m = (max_cpus == 0) ?
			"The nosmp parameter is incompatible with Xen; " \
			"use Xen dom0_max_vcpus=1 parameter" :
			"The noapic parameter is incompatible with Xen";

		xen_raw_printk(m);
		panic(m);
	}
272 273
	xen_init_lock_cpu(0);

274
	smp_store_boot_cpu_info();
275
	cpu_data(0).x86_max_cores = 1;
A
Andrew Jones 已提交
276 277 278 279 280 281

	for_each_possible_cpu(i) {
		zalloc_cpumask_var(&per_cpu(cpu_sibling_map, i), GFP_KERNEL);
		zalloc_cpumask_var(&per_cpu(cpu_core_map, i), GFP_KERNEL);
		zalloc_cpumask_var(&per_cpu(cpu_llc_shared_map, i), GFP_KERNEL);
	}
J
Jeremy Fitzhardinge 已提交
282 283 284 285 286
	set_cpu_sibling_map(0);

	if (xen_smp_intr_init(0))
		BUG();

287 288 289 290
	if (!alloc_cpumask_var(&xen_cpu_initialized_map, GFP_KERNEL))
		panic("could not allocate xen_cpu_initialized_map\n");

	cpumask_copy(xen_cpu_initialized_map, cpumask_of(0));
J
Jeremy Fitzhardinge 已提交
291 292 293

	/* Restrict the possible_map according to max_cpus. */
	while ((num_possible_cpus() > 1) && (num_possible_cpus() > max_cpus)) {
294
		for (cpu = nr_cpu_ids - 1; !cpu_possible(cpu); cpu--)
J
Jeremy Fitzhardinge 已提交
295
			continue;
296
		set_cpu_possible(cpu, false);
J
Jeremy Fitzhardinge 已提交
297 298
	}

299
	for_each_possible_cpu(cpu)
300
		set_cpu_present(cpu, true);
J
Jeremy Fitzhardinge 已提交
301 302
}

303
static int __cpuinit
J
Jeremy Fitzhardinge 已提交
304 305 306
cpu_initialize_context(unsigned int cpu, struct task_struct *idle)
{
	struct vcpu_guest_context *ctxt;
307
	struct desc_struct *gdt;
308
	unsigned long gdt_mfn;
J
Jeremy Fitzhardinge 已提交
309

310
	if (cpumask_test_and_set_cpu(cpu, xen_cpu_initialized_map))
J
Jeremy Fitzhardinge 已提交
311 312 313 314 315 316
		return 0;

	ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
	if (ctxt == NULL)
		return -ENOMEM;

317 318
	gdt = get_cpu_gdt_table(cpu);

J
Jeremy Fitzhardinge 已提交
319 320
	ctxt->flags = VGCF_IN_KERNEL;
	ctxt->user_regs.ss = __KERNEL_DS;
321 322
#ifdef CONFIG_X86_32
	ctxt->user_regs.fs = __KERNEL_PERCPU;
323
	ctxt->user_regs.gs = __KERNEL_STACK_CANARY;
324 325
#else
	ctxt->gs_base_kernel = per_cpu_offset(cpu);
326
#endif
J
Jeremy Fitzhardinge 已提交
327 328 329 330
	ctxt->user_regs.eip = (unsigned long)cpu_bringup_and_idle;

	memset(&ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt));

331 332 333 334
	{
		ctxt->user_regs.eflags = 0x1000; /* IOPL_RING1 */
		ctxt->user_regs.ds = __USER_DS;
		ctxt->user_regs.es = __USER_DS;
J
Jeremy Fitzhardinge 已提交
335

336
		xen_copy_trap_info(ctxt->trap_ctxt);
J
Jeremy Fitzhardinge 已提交
337

338
		ctxt->ldt_ents = 0;
339

340
		BUG_ON((unsigned long)gdt & ~PAGE_MASK);
J
Jeremy Fitzhardinge 已提交
341

342 343 344
		gdt_mfn = arbitrary_virt_to_mfn(gdt);
		make_lowmem_page_readonly(gdt);
		make_lowmem_page_readonly(mfn_to_virt(gdt_mfn));
J
Jeremy Fitzhardinge 已提交
345

346 347
		ctxt->gdt_frames[0] = gdt_mfn;
		ctxt->gdt_ents      = GDT_ENTRIES;
J
Jeremy Fitzhardinge 已提交
348

349 350
		ctxt->kernel_ss = __KERNEL_DS;
		ctxt->kernel_sp = idle->thread.sp0;
J
Jeremy Fitzhardinge 已提交
351

352
#ifdef CONFIG_X86_32
353 354
		ctxt->event_callback_cs     = __KERNEL_CS;
		ctxt->failsafe_callback_cs  = __KERNEL_CS;
355
#endif
356 357 358 359 360 361 362
		ctxt->event_callback_eip    =
					(unsigned long)xen_hypervisor_callback;
		ctxt->failsafe_callback_eip =
					(unsigned long)xen_failsafe_callback;
	}
	ctxt->user_regs.cs = __KERNEL_CS;
	ctxt->user_regs.esp = idle->thread.sp0 - sizeof(struct pt_regs);
J
Jeremy Fitzhardinge 已提交
363 364 365 366 367 368 369 370 371 372 373

	per_cpu(xen_cr3, cpu) = __pa(swapper_pg_dir);
	ctxt->ctrlreg[3] = xen_pfn_to_cr3(virt_to_mfn(swapper_pg_dir));

	if (HYPERVISOR_vcpu_op(VCPUOP_initialise, cpu, ctxt))
		BUG();

	kfree(ctxt);
	return 0;
}

374
static int __cpuinit xen_cpu_up(unsigned int cpu, struct task_struct *idle)
J
Jeremy Fitzhardinge 已提交
375 376 377
{
	int rc;

378
	per_cpu(current_task, cpu) = idle;
379
#ifdef CONFIG_X86_32
J
Jeremy Fitzhardinge 已提交
380
	irq_ctx_init(cpu);
381 382
#else
	clear_tsk_thread_flag(idle, TIF_FORK);
383 384 385
	per_cpu(kernel_stack, cpu) =
		(unsigned long)task_stack_page(idle) -
		KERNEL_STACK_OFFSET + THREAD_SIZE;
386
#endif
387
	xen_setup_runstate_info(cpu);
J
Jeremy Fitzhardinge 已提交
388
	xen_setup_timer(cpu);
389
	xen_init_lock_cpu(cpu);
J
Jeremy Fitzhardinge 已提交
390

391 392
	per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;

J
Jeremy Fitzhardinge 已提交
393 394 395 396 397 398 399 400
	/* make sure interrupts start blocked */
	per_cpu(xen_vcpu, cpu)->evtchn_upcall_mask = 1;

	rc = cpu_initialize_context(cpu, idle);
	if (rc)
		return rc;

	if (num_online_cpus() == 1)
401 402
		/* Just in case we booted with a single CPU. */
		alternatives_enable_smp();
J
Jeremy Fitzhardinge 已提交
403 404 405 406 407 408 409 410

	rc = xen_smp_intr_init(cpu);
	if (rc)
		return rc;

	rc = HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL);
	BUG_ON(rc);

411
	while(per_cpu(cpu_state, cpu) != CPU_ONLINE) {
H
Hannes Eder 已提交
412
		HYPERVISOR_sched_op(SCHEDOP_yield, NULL);
413 414 415
		barrier();
	}

J
Jeremy Fitzhardinge 已提交
416 417 418
	return 0;
}

419
static void xen_smp_cpus_done(unsigned int max_cpus)
J
Jeremy Fitzhardinge 已提交
420 421 422
{
}

423
#ifdef CONFIG_HOTPLUG_CPU
424
static int xen_cpu_disable(void)
A
Alex Nixon 已提交
425 426 427 428 429 430 431 432 433 434 435
{
	unsigned int cpu = smp_processor_id();
	if (cpu == 0)
		return -EBUSY;

	cpu_disable_common();

	load_cr3(swapper_pg_dir);
	return 0;
}

436
static void xen_cpu_die(unsigned int cpu)
A
Alex Nixon 已提交
437
{
438
	while (xen_pv_domain() && HYPERVISOR_vcpu_op(VCPUOP_is_up, cpu, NULL)) {
A
Alex Nixon 已提交
439 440 441
		current->state = TASK_UNINTERRUPTIBLE;
		schedule_timeout(HZ/10);
	}
442
	xen_smp_intr_free(cpu);
A
Alex Nixon 已提交
443 444 445 446
	xen_uninit_lock_cpu(cpu);
	xen_teardown_timer(cpu);
}

447
static void __cpuinit xen_play_dead(void) /* used only with HOTPLUG_CPU */
A
Alex Nixon 已提交
448 449 450 451 452 453
{
	play_dead_common();
	HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
	cpu_bringup();
}

454
#else /* !CONFIG_HOTPLUG_CPU */
455
static int xen_cpu_disable(void)
456 457 458 459
{
	return -ENOSYS;
}

460
static void xen_cpu_die(unsigned int cpu)
461 462 463 464
{
	BUG();
}

465
static void xen_play_dead(void)
466 467 468 469 470
{
	BUG();
}

#endif
J
Jeremy Fitzhardinge 已提交
471 472 473 474 475 476 477 478
static void stop_self(void *v)
{
	int cpu = smp_processor_id();

	/* make sure we're not pinning something down */
	load_cr3(swapper_pg_dir);
	/* should set up a minimal gdt */

479 480
	set_cpu_online(cpu, false);

J
Jeremy Fitzhardinge 已提交
481 482 483 484
	HYPERVISOR_vcpu_op(VCPUOP_down, cpu, NULL);
	BUG();
}

485
static void xen_stop_other_cpus(int wait)
J
Jeremy Fitzhardinge 已提交
486
{
487
	smp_call_function(stop_self, NULL, wait);
J
Jeremy Fitzhardinge 已提交
488 489
}

490
static void xen_smp_send_reschedule(int cpu)
J
Jeremy Fitzhardinge 已提交
491 492 493 494
{
	xen_send_IPI_one(cpu, XEN_RESCHEDULE_VECTOR);
}

B
Ben Guthro 已提交
495 496
static void __xen_send_IPI_mask(const struct cpumask *mask,
			      int vector)
J
Jeremy Fitzhardinge 已提交
497 498 499
{
	unsigned cpu;

500
	for_each_cpu_and(cpu, mask, cpu_online_mask)
J
Jeremy Fitzhardinge 已提交
501 502 503
		xen_send_IPI_one(cpu, vector);
}

504
static void xen_smp_send_call_function_ipi(const struct cpumask *mask)
505 506 507
{
	int cpu;

B
Ben Guthro 已提交
508
	__xen_send_IPI_mask(mask, XEN_CALL_FUNCTION_VECTOR);
509 510

	/* Make sure other vcpus get a chance to run if they need to. */
511
	for_each_cpu(cpu, mask) {
512
		if (xen_vcpu_stolen(cpu)) {
H
Hannes Eder 已提交
513
			HYPERVISOR_sched_op(SCHEDOP_yield, NULL);
514 515 516 517 518
			break;
		}
	}
}

519
static void xen_smp_send_call_function_single_ipi(int cpu)
520
{
B
Ben Guthro 已提交
521
	__xen_send_IPI_mask(cpumask_of(cpu),
522
			  XEN_CALL_FUNCTION_SINGLE_VECTOR);
523 524
}

B
Ben Guthro 已提交
525 526 527 528 529 530 531 532 533 534 535 536 537 538
static inline int xen_map_vector(int vector)
{
	int xen_vector;

	switch (vector) {
	case RESCHEDULE_VECTOR:
		xen_vector = XEN_RESCHEDULE_VECTOR;
		break;
	case CALL_FUNCTION_VECTOR:
		xen_vector = XEN_CALL_FUNCTION_VECTOR;
		break;
	case CALL_FUNCTION_SINGLE_VECTOR:
		xen_vector = XEN_CALL_FUNCTION_SINGLE_VECTOR;
		break;
539 540 541
	case IRQ_WORK_VECTOR:
		xen_vector = XEN_IRQ_WORK_VECTOR;
		break;
B
Ben Guthro 已提交
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
	default:
		xen_vector = -1;
		printk(KERN_ERR "xen: vector 0x%x is not implemented\n",
			vector);
	}

	return xen_vector;
}

void xen_send_IPI_mask(const struct cpumask *mask,
			      int vector)
{
	int xen_vector = xen_map_vector(vector);

	if (xen_vector >= 0)
		__xen_send_IPI_mask(mask, xen_vector);
}

void xen_send_IPI_all(int vector)
{
	int xen_vector = xen_map_vector(vector);

	if (xen_vector >= 0)
		__xen_send_IPI_mask(cpu_online_mask, xen_vector);
}

void xen_send_IPI_self(int vector)
{
	int xen_vector = xen_map_vector(vector);

	if (xen_vector >= 0)
		xen_send_IPI_one(smp_processor_id(), xen_vector);
}

void xen_send_IPI_mask_allbutself(const struct cpumask *mask,
				int vector)
{
	unsigned cpu;
	unsigned int this_cpu = smp_processor_id();
S
Stefan Bader 已提交
581
	int xen_vector = xen_map_vector(vector);
B
Ben Guthro 已提交
582

S
Stefan Bader 已提交
583
	if (!(num_online_cpus() > 1) || (xen_vector < 0))
B
Ben Guthro 已提交
584 585 586 587 588 589
		return;

	for_each_cpu_and(cpu, mask, cpu_online_mask) {
		if (this_cpu == cpu)
			continue;

S
Stefan Bader 已提交
590
		xen_send_IPI_one(cpu, xen_vector);
B
Ben Guthro 已提交
591 592 593 594 595
	}
}

void xen_send_IPI_allbutself(int vector)
{
S
Stefan Bader 已提交
596
	xen_send_IPI_mask_allbutself(cpu_online_mask, vector);
B
Ben Guthro 已提交
597 598
}

J
Jeremy Fitzhardinge 已提交
599 600 601
static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id)
{
	irq_enter();
602
	generic_smp_call_function_interrupt();
603
	inc_irq_stat(irq_call_count);
J
Jeremy Fitzhardinge 已提交
604 605 606 607 608
	irq_exit();

	return IRQ_HANDLED;
}

609
static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_id)
J
Jeremy Fitzhardinge 已提交
610
{
611 612
	irq_enter();
	generic_smp_call_function_single_interrupt();
613
	inc_irq_stat(irq_call_count);
614
	irq_exit();
J
Jeremy Fitzhardinge 已提交
615

616
	return IRQ_HANDLED;
J
Jeremy Fitzhardinge 已提交
617
}
618

619 620 621 622 623 624 625 626 627 628
static irqreturn_t xen_irq_work_interrupt(int irq, void *dev_id)
{
	irq_enter();
	irq_work_run();
	inc_irq_stat(apic_irq_work_irqs);
	irq_exit();

	return IRQ_HANDLED;
}

629
static const struct smp_ops xen_smp_ops __initconst = {
630 631 632 633
	.smp_prepare_boot_cpu = xen_smp_prepare_boot_cpu,
	.smp_prepare_cpus = xen_smp_prepare_cpus,
	.smp_cpus_done = xen_smp_cpus_done,

A
Alex Nixon 已提交
634 635 636 637 638
	.cpu_up = xen_cpu_up,
	.cpu_die = xen_cpu_die,
	.cpu_disable = xen_cpu_disable,
	.play_dead = xen_play_dead,

639
	.stop_other_cpus = xen_stop_other_cpus,
640 641 642 643 644 645 646 647 648
	.smp_send_reschedule = xen_smp_send_reschedule,

	.send_call_func_ipi = xen_smp_send_call_function_ipi,
	.send_call_func_single_ipi = xen_smp_send_call_function_single_ipi,
};

void __init xen_smp_init(void)
{
	smp_ops = xen_smp_ops;
649
	xen_fill_possible_map();
650
	xen_init_spinlocks();
651
}
652 653 654 655 656 657 658 659 660

static void __init xen_hvm_smp_prepare_cpus(unsigned int max_cpus)
{
	native_smp_prepare_cpus(max_cpus);
	WARN_ON(xen_smp_intr_init(0));

	xen_init_lock_cpu(0);
}

661
static int __cpuinit xen_hvm_cpu_up(unsigned int cpu, struct task_struct *tidle)
662 663
{
	int rc;
664
	rc = native_cpu_up(cpu, tidle);
665 666 667 668 669 670
	WARN_ON (xen_smp_intr_init(cpu));
	return rc;
}

static void xen_hvm_cpu_die(unsigned int cpu)
{
671
	xen_cpu_die(cpu);
672 673 674 675 676
	native_cpu_die(cpu);
}

void __init xen_hvm_smp_init(void)
{
677 678
	if (!xen_have_vector_callback)
		return;
679 680 681 682 683 684 685
	smp_ops.smp_prepare_cpus = xen_hvm_smp_prepare_cpus;
	smp_ops.smp_send_reschedule = xen_smp_send_reschedule;
	smp_ops.cpu_up = xen_hvm_cpu_up;
	smp_ops.cpu_die = xen_hvm_cpu_die;
	smp_ops.send_call_func_ipi = xen_smp_send_call_function_ipi;
	smp_ops.send_call_func_single_ipi = xen_smp_send_call_function_single_ipi;
}