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 unsigned int nr_cpus;
54
55 ASSERT(local_irq_is_enabled());
56 ASSERT(cpumask_subset(selected, &cpu_online_map));
57
58 spin_lock(&call_lock);
59
60 cpumask_copy(&call_data.selected, selected);
61
62 nr_cpus = cpumask_weight(&call_data.selected);
63 if ( nr_cpus == 0 )
64 goto out;
65
66 call_data.func = func;
67 call_data.info = info;
68 call_data.wait = wait;
69
70 smp_send_call_function_mask(&call_data.selected);
71
72 while ( !cpumask_empty(&call_data.selected) )
73 cpu_relax();
74
75 out:
76 spin_unlock(&call_lock);
77 }
78
smp_call_function_interrupt(void)79 void smp_call_function_interrupt(void)
80 {
81 void (*func)(void *info) = call_data.func;
82 void *info = call_data.info;
83 unsigned int cpu = smp_processor_id();
84
85 if ( !cpumask_test_cpu(cpu, &call_data.selected) )
86 return;
87
88 irq_enter();
89
90 if ( call_data.wait )
91 {
92 (*func)(info);
93 smp_mb();
94 cpumask_clear_cpu(cpu, &call_data.selected);
95 }
96 else
97 {
98 smp_mb();
99 cpumask_clear_cpu(cpu, &call_data.selected);
100 (*func)(info);
101 }
102
103 irq_exit();
104 }
105
106 /*
107 * Local variables:
108 * mode: C
109 * c-file-style: "BSD"
110 * c-basic-offset: 4
111 * indent-tabs-mode: nil
112 * End:
113 */
114