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