1 /*
2 * xen/common/smp.c
3 *
4 * Generic SMP function
5 *
6 * Copyright (c) 2013 Citrix Systems.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18
19 #include <asm/hardirq.h>
20 #include <asm/processor.h>
21 #include <xen/spinlock.h>
22 #include <xen/smp.h>
23
24 /*
25 * Structure and data for smp_call_function()/on_selected_cpus().
26 */
27 static DEFINE_SPINLOCK(call_lock);
28 static struct call_data_struct {
29 void (*func) (void *info);
30 void *info;
31 int wait;
32 cpumask_t selected;
33 } call_data;
34
smp_call_function(void (* func)(void * info),void * info,int wait)35 void smp_call_function(
36 void (*func) (void *info),
37 void *info,
38 int wait)
39 {
40 cpumask_t allbutself;
41
42 cpumask_andnot(&allbutself, &cpu_online_map,
43 cpumask_of(smp_processor_id()));
44 on_selected_cpus(&allbutself, func, info, wait);
45 }
46
on_selected_cpus(const cpumask_t * selected,void (* func)(void * info),void * info,int wait)47 void on_selected_cpus(
48 const cpumask_t *selected,
49 void (*func) (void *info),
50 void *info,
51 int wait)
52 {
53 ASSERT(local_irq_is_enabled());
54 ASSERT(cpumask_subset(selected, &cpu_online_map));
55
56 spin_lock(&call_lock);
57
58 cpumask_copy(&call_data.selected, selected);
59
60 if ( cpumask_empty(&call_data.selected) )
61 goto out;
62
63 call_data.func = func;
64 call_data.info = info;
65 call_data.wait = wait;
66
67 smp_send_call_function_mask(&call_data.selected);
68
69 while ( !cpumask_empty(&call_data.selected) )
70 cpu_relax();
71
72 out:
73 spin_unlock(&call_lock);
74 }
75
smp_call_function_interrupt(void)76 void smp_call_function_interrupt(void)
77 {
78 void (*func)(void *info) = call_data.func;
79 void *info = call_data.info;
80 unsigned int cpu = smp_processor_id();
81
82 if ( !cpumask_test_cpu(cpu, &call_data.selected) )
83 return;
84
85 irq_enter();
86
87 if ( unlikely(!func) )
88 {
89 cpumask_clear_cpu(cpu, &call_data.selected);
90 }
91 else if ( call_data.wait )
92 {
93 (*func)(info);
94 smp_mb();
95 cpumask_clear_cpu(cpu, &call_data.selected);
96 }
97 else
98 {
99 smp_mb();
100 cpumask_clear_cpu(cpu, &call_data.selected);
101 (*func)(info);
102 }
103
104 irq_exit();
105 }
106
107 /*
108 * Local variables:
109 * mode: C
110 * c-file-style: "BSD"
111 * c-basic-offset: 4
112 * indent-tabs-mode: nil
113 * End:
114 */
115