Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Merge branch 'devel'
[palacios.git] / kitten / arch / x86_64 / kernel / xcall.c
1 #include <lwk/kernel.h>
2 #include <lwk/spinlock.h>
3 #include <lwk/xcall.h>
4 #include <arch/apic.h>
5 #include <arch/idt_vectors.h>
6 #include <arch/processor.h>
7
8 /**
9  * Used to pass data to and synchronize the CPUs targeted by a cross-call.
10  */
11 struct xcall_data_struct {
12         void            (*func)(void *info);
13         void *          info;
14         atomic_t        started;
15         atomic_t        finished;
16         bool            wait;
17 };
18
19 /**
20  * Global cross-call data pointer, protected by xcall_data_lock.
21  */
22 static struct xcall_data_struct *xcall_data;
23 static DEFINE_SPINLOCK(xcall_data_lock);
24
25 /**
26  * x86_64 specific code for carrying out inter-CPU function calls. 
27  * This function should not be called directly. Call xcall_function() instead.
28  *
29  * Arguments:
30  *       [IN] cpu_mask: The target CPUs of the cross-call.
31  *       [IN] func:     The function to execute on each target CPU.
32  *       [IN] info:     Argument to pass to func().
33  *       [IN] wait:     true = wait for cross-call to fully complete.
34  *
35  * Returns:
36  *       Success: 0
37  *       Failure: Error code
38  */
39 int
40 arch_xcall_function(
41         cpumask_t       cpu_mask,
42         void            (*func)(void *info),
43         void *          info,
44         bool            wait
45 )
46 {
47         struct xcall_data_struct data;
48         unsigned int num_cpus;
49         unsigned int cpu;
50
51         BUG_ON(irqs_disabled());
52
53         /* Count how many CPUs are being targeted */
54         num_cpus = cpus_weight(cpu_mask);
55         if (!num_cpus)
56                 return 0;
57
58         /* Fill in the xcall data structure on our stack */
59         data.func = func;
60         data.info = info;
61         atomic_set(&data.started, 0);
62         if (wait)
63                 atomic_set(&data.finished, 0);
64         data.wait = wait;
65
66         /* Spin with IRQs enabled */
67         while (!spin_trylock_irq(&xcall_data_lock))
68                 ;
69         /* IRQs are now disabled */
70
71         /* Set the global xcall data pointer */
72         xcall_data = &data;
73         wmb();
74
75         /* Send inter-processor interrupts to the target CPUs */
76         for_each_cpu_mask(cpu, cpu_mask)
77                 lapic_send_ipi(cpu, XCALL_FUNCTION_VECTOR);
78
79         /* Wait for initiation responses */
80         while (atomic_read(&data.started) != num_cpus)
81                 cpu_relax();
82
83         /* If requested, wait for completion responses */
84         if (wait) {
85                 while (atomic_read(&data.finished) != num_cpus)
86                         cpu_relax();
87         }
88         spin_unlock_irq(&xcall_data_lock);
89
90         return 0;
91 }
92
93 /**
94  * The interrupt handler for inter-CPU function calls.
95  */
96 void
97 arch_xcall_function_interrupt(struct pt_regs *regs, unsigned int vector)
98 {
99         void (*func)(void *info) = xcall_data->func;
100         void *info               = xcall_data->info;
101         int wait                 = xcall_data->wait;
102
103         /* Notify initiating CPU that we've started */
104         mb();
105         atomic_inc(&xcall_data->started);
106
107         /* Execute the cross-call function */
108         (*func)(info);
109
110         /* Notify initiating CPU that the cross-call function has completed */
111         if (wait) {
112                 mb();
113                 atomic_inc(&xcall_data->finished);
114         }
115 }
116
117 /**
118  * Sends a reschedule inter-processor interrupt to the target CPU.
119  * This causes the target CPU to call schedule().
120  */
121 void
122 arch_xcall_reschedule(id_t cpu)
123 {
124         lapic_send_ipi(cpu, XCALL_RESCHEDULE_VECTOR);
125 }
126
127 /**
128  * The interrupt handler for inter-CPU reschedule calls.
129  */
130 void
131 arch_xcall_reschedule_interrupt(struct pt_regs *regs, unsigned int vector)
132 {
133         /*
134          * Nothing to do, schedule() will be automatically
135          * called before returning to user-space
136          */
137 }