Skip to content

Commit 37f55d3

Browse files
Suresh Warrierpaulusmack
authored andcommitted
KVM: PPC: Book3S HV: Convert kvmppc_read_intr to a C function
Modify kvmppc_read_intr to make it a C function. Because it is called from kvmppc_check_wake_reason, any of the assembler code that calls either kvmppc_read_intr or kvmppc_check_wake_reason now has to assume that the volatile registers might have been modified. This also adds in the optimization of clearing saved_xirr in the case where we completely handle and EOI an IPI. Without this, the next device interrupt will require two trips through the host interrupt handling code. [paulus@ozlabs.org - made kvmppc_check_wake_reason create a stack frame when it is calling kvmppc_read_intr, which means we can set r12 to the trap number (0x500) after the call to kvmppc_read_intr, instead of using r31. Also moved the deliver_guest_interrupt label so as to restore XER and CTR, plus other minor tweaks.] Signed-off-by: Suresh Warrier <warrier@linux.vnet.ibm.com> Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
1 parent 99212c8 commit 37f55d3

File tree

2 files changed

+158
-84
lines changed

2 files changed

+158
-84
lines changed

arch/powerpc/kvm/book3s_hv_builtin.c

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <asm/xics.h>
2626
#include <asm/dbell.h>
2727
#include <asm/cputhreads.h>
28+
#include <asm/io.h>
2829

2930
#define KVM_CMA_CHUNK_ORDER 18
3031

@@ -286,3 +287,86 @@ void kvmhv_commence_exit(int trap)
286287

287288
struct kvmppc_host_rm_ops *kvmppc_host_rm_ops_hv;
288289
EXPORT_SYMBOL_GPL(kvmppc_host_rm_ops_hv);
290+
291+
/*
292+
* Determine what sort of external interrupt is pending (if any).
293+
* Returns:
294+
* 0 if no interrupt is pending
295+
* 1 if an interrupt is pending that needs to be handled by the host
296+
* -1 if there was a guest wakeup IPI (which has now been cleared)
297+
*/
298+
299+
long kvmppc_read_intr(void)
300+
{
301+
unsigned long xics_phys;
302+
u32 h_xirr;
303+
__be32 xirr;
304+
u32 xisr;
305+
u8 host_ipi;
306+
307+
/* see if a host IPI is pending */
308+
host_ipi = local_paca->kvm_hstate.host_ipi;
309+
if (host_ipi)
310+
return 1;
311+
312+
/* Now read the interrupt from the ICP */
313+
xics_phys = local_paca->kvm_hstate.xics_phys;
314+
if (unlikely(!xics_phys))
315+
return 1;
316+
317+
/*
318+
* Save XIRR for later. Since we get control in reverse endian
319+
* on LE systems, save it byte reversed and fetch it back in
320+
* host endian. Note that xirr is the value read from the
321+
* XIRR register, while h_xirr is the host endian version.
322+
*/
323+
xirr = _lwzcix(xics_phys + XICS_XIRR);
324+
h_xirr = be32_to_cpu(xirr);
325+
local_paca->kvm_hstate.saved_xirr = h_xirr;
326+
xisr = h_xirr & 0xffffff;
327+
/*
328+
* Ensure that the store/load complete to guarantee all side
329+
* effects of loading from XIRR has completed
330+
*/
331+
smp_mb();
332+
333+
/* if nothing pending in the ICP */
334+
if (!xisr)
335+
return 0;
336+
337+
/* We found something in the ICP...
338+
*
339+
* If it is an IPI, clear the MFRR and EOI it.
340+
*/
341+
if (xisr == XICS_IPI) {
342+
_stbcix(xics_phys + XICS_MFRR, 0xff);
343+
_stwcix(xics_phys + XICS_XIRR, xirr);
344+
/*
345+
* Need to ensure side effects of above stores
346+
* complete before proceeding.
347+
*/
348+
smp_mb();
349+
350+
/*
351+
* We need to re-check host IPI now in case it got set in the
352+
* meantime. If it's clear, we bounce the interrupt to the
353+
* guest
354+
*/
355+
host_ipi = local_paca->kvm_hstate.host_ipi;
356+
if (unlikely(host_ipi != 0)) {
357+
/* We raced with the host,
358+
* we need to resend that IPI, bummer
359+
*/
360+
_stbcix(xics_phys + XICS_MFRR, IPI_PRIORITY);
361+
/* Let side effects complete */
362+
smp_mb();
363+
return 1;
364+
}
365+
366+
/* OK, it's an IPI for us */
367+
local_paca->kvm_hstate.saved_xirr = 0;
368+
return -1;
369+
}
370+
371+
return 1;
372+
}

arch/powerpc/kvm/book3s_hv_rmhandlers.S

Lines changed: 74 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,13 @@ kvmppc_primary_no_guest:
221221
li r3, 0 /* Don't wake on privileged (OS) doorbell */
222222
b kvm_do_nap
223223

224+
/*
225+
* kvm_novcpu_wakeup
226+
* Entered from kvm_start_guest if kvm_hstate.napping is set
227+
* to NAPPING_NOVCPU
228+
* r2 = kernel TOC
229+
* r13 = paca
230+
*/
224231
kvm_novcpu_wakeup:
225232
ld r1, HSTATE_HOST_R1(r13)
226233
ld r5, HSTATE_KVM_VCORE(r13)
@@ -230,6 +237,13 @@ kvm_novcpu_wakeup:
230237
/* check the wake reason */
231238
bl kvmppc_check_wake_reason
232239

240+
/*
241+
* Restore volatile registers since we could have called
242+
* a C routine in kvmppc_check_wake_reason.
243+
* r5 = VCORE
244+
*/
245+
ld r5, HSTATE_KVM_VCORE(r13)
246+
233247
/* see if any other thread is already exiting */
234248
lwz r0, VCORE_ENTRY_EXIT(r5)
235249
cmpwi r0, 0x100
@@ -322,6 +336,11 @@ kvm_start_guest:
322336

323337
/* Check the wake reason in SRR1 to see why we got here */
324338
bl kvmppc_check_wake_reason
339+
/*
340+
* kvmppc_check_wake_reason could invoke a C routine, but we
341+
* have no volatile registers to restore when we return.
342+
*/
343+
325344
cmpdi r3, 0
326345
bge kvm_no_guest
327346

@@ -881,6 +900,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
881900
cmpwi r3, 512 /* 1 microsecond */
882901
blt hdec_soon
883902

903+
deliver_guest_interrupt:
884904
ld r6, VCPU_CTR(r4)
885905
ld r7, VCPU_XER(r4)
886906

@@ -895,7 +915,6 @@ kvmppc_cede_reentry: /* r4 = vcpu, r13 = paca */
895915
mtspr SPRN_SRR0, r6
896916
mtspr SPRN_SRR1, r7
897917

898-
deliver_guest_interrupt:
899918
/* r11 = vcpu->arch.msr & ~MSR_HV */
900919
rldicl r11, r11, 63 - MSR_HV_LG, 1
901920
rotldi r11, r11, 1 + MSR_HV_LG
@@ -1155,10 +1174,36 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
11551174
* set, we know the host wants us out so let's do it now
11561175
*/
11571176
bl kvmppc_read_intr
1177+
1178+
/*
1179+
* Restore the active volatile registers after returning from
1180+
* a C function.
1181+
*/
1182+
ld r9, HSTATE_KVM_VCPU(r13)
1183+
li r12, BOOK3S_INTERRUPT_EXTERNAL
1184+
1185+
/*
1186+
* kvmppc_read_intr return codes:
1187+
*
1188+
* Exit to host (r3 > 0)
1189+
* 1 An interrupt is pending that needs to be handled by the host
1190+
* Exit guest and return to host by branching to guest_exit_cont
1191+
*
1192+
* Before returning to guest, we check if any CPU is heading out
1193+
* to the host and if so, we head out also. If no CPUs are heading
1194+
* check return values <= 0.
1195+
*
1196+
* Return to guest (r3 <= 0)
1197+
* 0 No external interrupt is pending
1198+
* -1 A guest wakeup IPI (which has now been cleared)
1199+
* In either case, we return to guest to deliver any pending
1200+
* guest interrupts.
1201+
*/
1202+
11581203
cmpdi r3, 0
11591204
bgt guest_exit_cont
11601205

1161-
/* Check if any CPU is heading out to the host, if so head out too */
1206+
/* Return code <= 0 */
11621207
4: ld r5, HSTATE_KVM_VCORE(r13)
11631208
lwz r0, VCORE_ENTRY_EXIT(r5)
11641209
cmpwi r0, 0x100
@@ -2213,10 +2258,20 @@ END_FTR_SECTION_IFSET(CPU_FTR_TM)
22132258
ld r29, VCPU_GPR(R29)(r4)
22142259
ld r30, VCPU_GPR(R30)(r4)
22152260
ld r31, VCPU_GPR(R31)(r4)
2216-
2261+
22172262
/* Check the wake reason in SRR1 to see why we got here */
22182263
bl kvmppc_check_wake_reason
22192264

2265+
/*
2266+
* Restore volatile registers since we could have called a
2267+
* C routine in kvmppc_check_wake_reason
2268+
* r4 = VCPU
2269+
* r3 tells us whether we need to return to host or not
2270+
* WARNING: it gets checked further down:
2271+
* should not modify r3 until this check is done.
2272+
*/
2273+
ld r4, HSTATE_KVM_VCPU(r13)
2274+
22202275
/* clear our bit in vcore->napping_threads */
22212276
34: ld r5,HSTATE_KVM_VCORE(r13)
22222277
lbz r7,HSTATE_PTID(r13)
@@ -2230,7 +2285,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_TM)
22302285
li r0,0
22312286
stb r0,HSTATE_NAPPING(r13)
22322287

2233-
/* See if the wake reason means we need to exit */
2288+
/* See if the wake reason saved in r3 means we need to exit */
22342289
stw r12, VCPU_TRAP(r4)
22352290
mr r9, r4
22362291
cmpdi r3, 0
@@ -2300,7 +2355,9 @@ machine_check_realmode:
23002355
*
23012356
* Also sets r12 to the interrupt vector for any interrupt that needs
23022357
* to be handled now by the host (0x500 for external interrupt), or zero.
2303-
* Modifies r0, r6, r7, r8.
2358+
* Modifies all volatile registers (since it may call a C function).
2359+
* This routine calls kvmppc_read_intr, a C function, if an external
2360+
* interrupt is pending.
23042361
*/
23052362
kvmppc_check_wake_reason:
23062363
mfspr r6, SPRN_SRR1
@@ -2310,8 +2367,7 @@ FTR_SECTION_ELSE
23102367
rlwinm r6, r6, 45-31, 0xe /* P7 wake reason field is 3 bits */
23112368
ALT_FTR_SECTION_END_IFSET(CPU_FTR_ARCH_207S)
23122369
cmpwi r6, 8 /* was it an external interrupt? */
2313-
li r12, BOOK3S_INTERRUPT_EXTERNAL
2314-
beq kvmppc_read_intr /* if so, see what it was */
2370+
beq 7f /* if so, see what it was */
23152371
li r3, 0
23162372
li r12, 0
23172373
cmpwi r6, 6 /* was it the decrementer? */
@@ -2350,83 +2406,17 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
23502406
li r3, 1
23512407
blr
23522408

2353-
/*
2354-
* Determine what sort of external interrupt is pending (if any).
2355-
* Returns:
2356-
* 0 if no interrupt is pending
2357-
* 1 if an interrupt is pending that needs to be handled by the host
2358-
* -1 if there was a guest wakeup IPI (which has now been cleared)
2359-
* Modifies r0, r6, r7, r8, returns value in r3.
2360-
*/
2361-
kvmppc_read_intr:
2362-
/* see if a host IPI is pending */
2363-
li r3, 1
2364-
lbz r0, HSTATE_HOST_IPI(r13)
2365-
cmpwi r0, 0
2366-
bne 1f
2367-
2368-
/* Now read the interrupt from the ICP */
2369-
ld r6, HSTATE_XICS_PHYS(r13)
2370-
li r7, XICS_XIRR
2371-
cmpdi r6, 0
2372-
beq- 1f
2373-
lwzcix r0, r6, r7
2374-
/*
2375-
* Save XIRR for later. Since we get in in reverse endian on LE
2376-
* systems, save it byte reversed and fetch it back in host endian.
2377-
*/
2378-
li r3, HSTATE_SAVED_XIRR
2379-
STWX_BE r0, r3, r13
2380-
#ifdef __LITTLE_ENDIAN__
2381-
lwz r3, HSTATE_SAVED_XIRR(r13)
2382-
#else
2383-
mr r3, r0
2384-
#endif
2385-
rlwinm. r3, r3, 0, 0xffffff
2386-
sync
2387-
beq 1f /* if nothing pending in the ICP */
2388-
2389-
/* We found something in the ICP...
2390-
*
2391-
* If it's not an IPI, stash it in the PACA and return to
2392-
* the host, we don't (yet) handle directing real external
2393-
* interrupts directly to the guest
2394-
*/
2395-
cmpwi r3, XICS_IPI /* if there is, is it an IPI? */
2396-
bne 42f
2397-
2398-
/* It's an IPI, clear the MFRR and EOI it */
2399-
li r3, 0xff
2400-
li r8, XICS_MFRR
2401-
stbcix r3, r6, r8 /* clear the IPI */
2402-
stwcix r0, r6, r7 /* EOI it */
2403-
sync
2404-
2405-
/* We need to re-check host IPI now in case it got set in the
2406-
* meantime. If it's clear, we bounce the interrupt to the
2407-
* guest
2408-
*/
2409-
lbz r0, HSTATE_HOST_IPI(r13)
2410-
cmpwi r0, 0
2411-
bne- 43f
2412-
2413-
/* OK, it's an IPI for us */
2414-
li r12, 0
2415-
li r3, -1
2416-
1: blr
2417-
2418-
42: /* It's not an IPI and it's for the host. We saved a copy of XIRR in
2419-
* the PACA earlier, it will be picked up by the host ICP driver
2420-
*/
2421-
li r3, 1
2422-
b 1b
2423-
2424-
43: /* We raced with the host, we need to resend that IPI, bummer */
2425-
li r0, IPI_PRIORITY
2426-
stbcix r0, r6, r8 /* set the IPI */
2427-
sync
2428-
li r3, 1
2429-
b 1b
2409+
/* external interrupt - create a stack frame so we can call C */
2410+
7: mflr r0
2411+
std r0, PPC_LR_STKOFF(r1)
2412+
stdu r1, -PPC_MIN_STKFRM(r1)
2413+
bl kvmppc_read_intr
2414+
nop
2415+
li r12, BOOK3S_INTERRUPT_EXTERNAL
2416+
ld r0, PPC_MIN_STKFRM+PPC_LR_STKOFF(r1)
2417+
addi r1, r1, PPC_MIN_STKFRM
2418+
mtlr r0
2419+
blr
24302420

24312421
/*
24322422
* Save away FP, VMX and VSX registers.

0 commit comments

Comments
 (0)