diff options
Diffstat (limited to 'arch/powerpc/kvm/book3s_hv_builtin.c')
-rw-r--r-- | arch/powerpc/kvm/book3s_hv_builtin.c | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c index 275425142bb7..c42aa55b885f 100644 --- a/arch/powerpc/kvm/book3s_hv_builtin.c +++ b/arch/powerpc/kvm/book3s_hv_builtin.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <asm/kvm_ppc.h> | 22 | #include <asm/kvm_ppc.h> |
23 | #include <asm/kvm_book3s.h> | 23 | #include <asm/kvm_book3s.h> |
24 | #include <asm/archrandom.h> | 24 | #include <asm/archrandom.h> |
25 | #include <asm/xics.h> | ||
25 | 26 | ||
26 | #define KVM_CMA_CHUNK_ORDER 18 | 27 | #define KVM_CMA_CHUNK_ORDER 18 |
27 | 28 | ||
@@ -184,3 +185,65 @@ long kvmppc_h_random(struct kvm_vcpu *vcpu) | |||
184 | 185 | ||
185 | return H_HARDWARE; | 186 | return H_HARDWARE; |
186 | } | 187 | } |
188 | |||
189 | static inline void rm_writeb(unsigned long paddr, u8 val) | ||
190 | { | ||
191 | __asm__ __volatile__("stbcix %0,0,%1" | ||
192 | : : "r" (val), "r" (paddr) : "memory"); | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * Send an interrupt to another CPU. | ||
197 | * This can only be called in real mode. | ||
198 | * The caller needs to include any barrier needed to order writes | ||
199 | * to memory vs. the IPI/message. | ||
200 | */ | ||
201 | void kvmhv_rm_send_ipi(int cpu) | ||
202 | { | ||
203 | unsigned long xics_phys; | ||
204 | |||
205 | /* Poke the target */ | ||
206 | xics_phys = paca[cpu].kvm_hstate.xics_phys; | ||
207 | rm_writeb(xics_phys + XICS_MFRR, IPI_PRIORITY); | ||
208 | } | ||
209 | |||
210 | /* | ||
211 | * The following functions are called from the assembly code | ||
212 | * in book3s_hv_rmhandlers.S. | ||
213 | */ | ||
214 | static void kvmhv_interrupt_vcore(struct kvmppc_vcore *vc, int active) | ||
215 | { | ||
216 | int cpu = vc->pcpu; | ||
217 | |||
218 | /* Order setting of exit map vs. msgsnd/IPI */ | ||
219 | smp_mb(); | ||
220 | for (; active; active >>= 1, ++cpu) | ||
221 | if (active & 1) | ||
222 | kvmhv_rm_send_ipi(cpu); | ||
223 | } | ||
224 | |||
225 | void kvmhv_commence_exit(int trap) | ||
226 | { | ||
227 | struct kvmppc_vcore *vc = local_paca->kvm_hstate.kvm_vcore; | ||
228 | int ptid = local_paca->kvm_hstate.ptid; | ||
229 | int me, ee; | ||
230 | |||
231 | /* Set our bit in the threads-exiting-guest map in the 0xff00 | ||
232 | bits of vcore->entry_exit_map */ | ||
233 | me = 0x100 << ptid; | ||
234 | do { | ||
235 | ee = vc->entry_exit_map; | ||
236 | } while (cmpxchg(&vc->entry_exit_map, ee, ee | me) != ee); | ||
237 | |||
238 | /* Are we the first here? */ | ||
239 | if ((ee >> 8) != 0) | ||
240 | return; | ||
241 | |||
242 | /* | ||
243 | * Trigger the other threads in this vcore to exit the guest. | ||
244 | * If this is a hypervisor decrementer interrupt then they | ||
245 | * will be already on their way out of the guest. | ||
246 | */ | ||
247 | if (trap != BOOK3S_INTERRUPT_HV_DECREMENTER) | ||
248 | kvmhv_interrupt_vcore(vc, ee & ~(1 << ptid)); | ||
249 | } | ||