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