From: Nicholas Piggin <npiggin@gmail.com> Date: 2017-08-05 17:03:00
The first 9 patches are a bunch of independent small cleanups
and improvements I've collected. The next 4 are improvements to
POWER9 idle state entry and exit. They significantly change how
we enter idle, now in virtual mode and without ptesync. EC=0 idle
is significantly simplified from there, and does not save anything.
This runs fine on a DD1 test machine, but the hardware has some
problem with performance all over the place, so I'm not able to get
anything meaningful there yet.
Thanks,
Nick
Nicholas Piggin (13):
powerpc/64s: masked interrupt avoid branch
powerpc/64s: masked interrupt avoid instruction
powerpc/64s: masked interrupt returns to kernel so avoid r13 restore
powerpc/64: cleanup __check_irq_replay
powerpc/64s: irq replay merge HV and non-HV paths for doorbell replay
powerpc/64s: irq replay external use the HV handler in HV mode on
POWER9
powerpc/64: remove redundant instruction in interrupt replay
powerpc/64s: irq replay remove spurious irq reason
powerpc/64: runlatch CTRL[RUN] set optimisation
powerpc/64s: idle simplify KVM idle on POWER9
powerpc/64s: idle POWER9 can execute stop without ptesync
powerpc/64s: idle POWER9 can execute stop in virtual mode
powerpc/64s: idle ESL=0 stop can avoid all save/restore overhead
arch/powerpc/include/asm/kvm_book3s_asm.h | 4 +++
arch/powerpc/kernel/entry_64.S | 7 +---
arch/powerpc/kernel/exceptions-64s.S | 19 +++++-----
arch/powerpc/kernel/idle_book3s.S | 60 ++++++++++++++-----------------
arch/powerpc/kernel/irq.c | 47 ++++++++++++------------
arch/powerpc/kernel/process.c | 35 +++++++++++++-----
arch/powerpc/kvm/book3s_hv.c | 37 ++++++++++++++++---
arch/powerpc/kvm/book3s_hv_rmhandlers.S | 32 ++++++++++-------
8 files changed, 143 insertions(+), 98 deletions(-)
--
2.11.0
From: Nicholas Piggin <npiggin@gmail.com> Date: 2017-08-05 17:03:03
Interrupts which do not require EE to be cleared can all
be tested with a single bitwise test.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/kernel/exceptions-64s.S | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
From: Nicholas Piggin <npiggin@gmail.com> Date: 2017-08-05 17:03:06
EE is always enabled in SRR1 for masked interrupts, so clearing
it can use xor.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/kernel/exceptions-64s.S | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
From: Nicholas Piggin <npiggin@gmail.com> Date: 2017-08-05 17:03:08
Places in the kernel where r13 is not the PACA pointer must have
maskable interrupts disabled, so r13 does not have to be restored
when returning from a soft-masked interrupt.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/kernel/exceptions-64s.S | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Nicholas Piggin <npiggin@gmail.com> Date: 2017-08-05 17:03:11
Move the clearing of irq_happened bits into the condition where
they were found to be set. This reduces instruction count slightly,
and reduces stores into irq_happened.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/kernel/irq.c | 45 +++++++++++++++++++++++----------------------
1 file changed, 23 insertions(+), 22 deletions(-)
@@ -143,9 +143,10 @@ notrace unsigned int __check_irq_replay(void)*/unsignedcharhappened=local_paca->irq_happened;-/* Clear bit 0 which we wouldn't clear otherwise */-local_paca->irq_happened&=~PACA_IRQ_HARD_DIS;if(happened&PACA_IRQ_HARD_DIS){+/* Clear bit 0 which we wouldn't clear otherwise */+local_paca->irq_happened&=~PACA_IRQ_HARD_DIS;+/**Wemayhavemissedadecrementerinterruptifharddisabled.*Checkthedecrementerregisterincasewehadarollover
@@ -173,39 +174,39 @@ notrace unsigned int __check_irq_replay(void)*Thisisahigherpriorityinterruptthantheothers,so*replayitfirst.*/-local_paca->irq_happened&=~PACA_IRQ_HMI;-if(happened&PACA_IRQ_HMI)+if(happened&PACA_IRQ_HMI){+local_paca->irq_happened&=~PACA_IRQ_HMI;return0xe60;+}-/*-*Wemayhavemissedadecrementerinterrupt.Wecheckthe-*decrementeritselfratherthanthepacairq_happenedfield-*incasewealsohadarolloverwhileharddisabled-*/-local_paca->irq_happened&=~PACA_IRQ_DEC;-if(happened&PACA_IRQ_DEC)+if(happened&PACA_IRQ_DEC){+local_paca->irq_happened&=~PACA_IRQ_DEC;return0x900;+}-/* Finally check if an external interrupt happened */-local_paca->irq_happened&=~PACA_IRQ_EE;-if(happened&PACA_IRQ_EE)+if(happened&PACA_IRQ_EE){+local_paca->irq_happened&=~PACA_IRQ_EE;return0x500;+}#ifdef CONFIG_PPC_BOOK3E-/* Finally check if an EPR external interrupt happened-*thisbitistypicallysetifweneedtohandleanother-*"edge"interruptfromwithintheMPIC"EPR"handler+/*+*CheckifanEPRexternalinterrupthappenedthisbitistypically+*setifweneedtohandleanother"edge"interruptfromwithinthe+*MPIC"EPR"handler.*/-local_paca->irq_happened&=~PACA_IRQ_EE_EDGE;-if(happened&PACA_IRQ_EE_EDGE)+if(happened&PACA_IRQ_EE_EDGE){+local_paca->irq_happened&=~PACA_IRQ_EE_EDGE;return0x500;+}-local_paca->irq_happened&=~PACA_IRQ_DBELL;-if(happened&PACA_IRQ_DBELL)+if(happened&PACA_IRQ_DBELL){+local_paca->irq_happened&=~PACA_IRQ_DBELL;return0x280;+}#else-local_paca->irq_happened&=~PACA_IRQ_DBELL;if(happened&PACA_IRQ_DBELL){+local_paca->irq_happened&=~PACA_IRQ_DBELL;if(cpu_has_feature(CPU_FTR_HVMODE))return0xe80;return0xa00;
From: Nicholas Piggin <npiggin@gmail.com> Date: 2017-08-05 17:03:16
POWER9 host external interrupts use the h_virt_irq_common handler, so
use that to replay them rather than using the hardware_interrupt_common
handler. Both call do_IRQ, but using the correct handler reduces i-cache
footprint.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/kernel/exceptions-64s.S | 4 ++++
1 file changed, 4 insertions(+)
From: Nicholas Piggin <npiggin@gmail.com> Date: 2017-08-05 17:03:22
HVI interrupts have always used 0x500, so remove the dead branch.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/kernel/exceptions-64s.S | 2 --
1 file changed, 2 deletions(-)
From: Nicholas Piggin <npiggin@gmail.com> Date: 2017-08-05 17:03:25
The CTRL register is read-only except bit 63 which is the run latch
control. This means it can be updated with a mtspr rather than
mfspr/mtspr.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/kernel/process.c | 35 +++++++++++++++++++++++++++--------
1 file changed, 27 insertions(+), 8 deletions(-)
From: Nicholas Piggin <npiggin@gmail.com> Date: 2017-08-05 17:03:29
POWER9 CPUs have independent MMU contexts per thread so KVM
does not have to bring sibling threads into real-mode when
switching MMU mode to guest. This can simplify POWER9 sleep/wake
paths and avoids hwsyncs.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/include/asm/kvm_book3s_asm.h | 4 ++++
arch/powerpc/kernel/idle_book3s.S | 8 ++-----
arch/powerpc/kvm/book3s_hv.c | 37 ++++++++++++++++++++++++++-----
arch/powerpc/kvm/book3s_hv_rmhandlers.S | 8 +++++++
4 files changed, 46 insertions(+), 11 deletions(-)
@@ -2111,6 +2111,16 @@ static int kvmppc_grab_hwthread(int cpu)structpaca_struct*tpaca;longtimeout=10000;+/*+*ISAv3.0idleroutinesdonotsethwthread_stateortest+*hwthread_req,sotheycannotgrabidlethreads.+*/+if(cpu_has_feature(CPU_FTR_ARCH_300)){+WARN_ON(1);+pr_err("KVM: can not control sibling threads\n");+return-EBUSY;+}+tpaca=&paca[cpu];/* Ensure the thread won't go into the kernel if it wakes */
@@ -2274,7 +2298,7 @@ static int on_primary_thread(void)if(kvmppc_grab_hwthread(cpu+thr)){/* Couldn't grab one; let the others go */do{-kvmppc_release_hwthread(cpu+thr);+kvmppc_release_hwthread_secondary(cpu+thr);}while(--thr>0);return0;}
@@ -2858,11 +2883,13 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)/* Let secondaries go back to the offline loop */for(i=0;i<controlled_threads;++i){-kvmppc_release_hwthread(pcpu+i);if(sip&&sip->napped[i])kvmppc_ipi_thread(pcpu+i);cpumask_clear_cpu(pcpu+i,&vc->kvm->arch.cpu_in_guest);}+for(i=1;i<controlled_threads;++i)+kvmppc_release_hwthread_secondary(pcpu+i);+kvmppc_release_hwthread(pcpu);spin_unlock(&vc->lock);
From: Nicholas Piggin <npiggin@gmail.com> Date: 2017-08-05 17:03:36
The hardware can execute stop in any context, and KVM does not
require real mode. This saves a switch to real-mode when going
idle.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/kernel/idle_book3s.S | 9 +++++++++
1 file changed, 9 insertions(+)
From: Nicholas Piggin <npiggin@gmail.com> Date: 2017-08-05 17:03:39
When stop is executed with EC=ESL=0, it appears to execute like a
normal instruction (resuming from NIP when woken by interrupt).
So all the save/restore handling can be avoided completely. In
particular NV GPRs do not have to be saved, and MSR does not have
to be switched back to kernel MSR.
So move the test for "lite" sleep states out to power9_idle_stop.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/kernel/idle_book3s.S | 38 +++++++++++++-------------------------
1 file changed, 13 insertions(+), 25 deletions(-)
From: Nicholas Piggin <npiggin@gmail.com> Date: 2017-08-05 17:11:58
On Sun, 6 Aug 2017 03:02:41 +1000
Nicholas Piggin [off-list ref] wrote:
When stop is executed with EC=ESL=0, it appears to execute like a
normal instruction (resuming from NIP when woken by interrupt).
So all the save/restore handling can be avoided completely. In
particular NV GPRs do not have to be saved, and MSR does not have
to be switched back to kernel MSR.
So move the test for "lite" sleep states out to power9_idle_stop.
I forgot to mention this actually breaks in the simulator because
it sets MSR as though it's taken a system reset interrupt when
resuming from EC=0 stop. It works on real hardware.
This might have to be quirked away by firmware or something, but
I've reported the bug so waiting to hear back first.
Thanks,
Nick
From: Benjamin Herrenschmidt <hidden> Date: 2017-08-05 23:00:44
On Sun, 2017-08-06 at 03:02 +1000, Nicholas Piggin wrote:
HVI interrupts have always used 0x500, so remove the dead branch.
Maybe we should fix that and "catch" in incorrect entry via 0x500
which would mean the XIVE is trying to deliver guest irqs to the OS...
That can happen if some LPCR bits aren't set properly and/or KVM
doesn't pull the guest in time. I had bugs like that in my early
dev so I've been running with a b . at 0x500 for a while :-)
From: Nicholas Piggin <npiggin@gmail.com> Date: 2017-08-06 00:51:23
On Sun, 06 Aug 2017 09:00:32 +1000
Benjamin Herrenschmidt [off-list ref] wrote:
On Sun, 2017-08-06 at 03:02 +1000, Nicholas Piggin wrote:
quoted
HVI interrupts have always used 0x500, so remove the dead branch.
Maybe we should fix that and "catch" in incorrect entry via 0x500
which would mean the XIVE is trying to deliver guest irqs to the OS...
I should be more clear, when I say 0x500, it is only in reference to
the constant used by the soft-irq replay. After patch 6 the replay is
sent to the 0xea0 common handler.
That can happen if some LPCR bits aren't set properly and/or KVM
doesn't pull the guest in time. I had bugs like that in my early
dev so I've been running with a b . at 0x500 for a while :-)
From: Gautham R Shenoy <hidden> Date: 2017-08-08 10:36:52
Hi Nicholas,
On Sun, Aug 06, 2017 at 03:02:38AM +1000, Nicholas Piggin wrote:
quoted hunk
POWER9 CPUs have independent MMU contexts per thread so KVM
does not have to bring sibling threads into real-mode when
switching MMU mode to guest. This can simplify POWER9 sleep/wake
paths and avoids hwsyncs.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/include/asm/kvm_book3s_asm.h | 4 ++++
arch/powerpc/kernel/idle_book3s.S | 8 ++-----
arch/powerpc/kvm/book3s_hv.c | 37 ++++++++++++++++++++++++++-----
arch/powerpc/kvm/book3s_hv_rmhandlers.S | 8 +++++++
4 files changed, 46 insertions(+), 11 deletions(-)
@@ -2111,6 +2111,16 @@ static int kvmppc_grab_hwthread(int cpu)structpaca_struct*tpaca;longtimeout=10000;+/*+*ISAv3.0idleroutinesdonotsethwthread_stateortest+*hwthread_req,sotheycannotgrabidlethreads.+*/+if(cpu_has_feature(CPU_FTR_ARCH_300)){+WARN_ON(1);+pr_err("KVM: can not control sibling threads\n");+return-EBUSY;+}+tpaca=&paca[cpu];/* Ensure the thread won't go into the kernel if it wakes */
static void radix_flush_cpu(struct kvm *kvm, int cpu, struct kvm_vcpu *vcpu)
{
int i;
@@ -2274,7 +2298,7 @@ static int on_primary_thread(void) if (kvmppc_grab_hwthread(cpu + thr)) { /* Couldn't grab one; let the others go */ do {- kvmppc_release_hwthread(cpu + thr);+ kvmppc_release_hwthread_secondary(cpu + thr); } while (--thr > 0); return 0; }
@@ -2702,8 +2726,9 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) kvmppc_vcore_preempt(pvc); spin_unlock(&pvc->lock); }- for (i = 0; i < controlled_threads; ++i)- kvmppc_release_hwthread(pcpu + i);+ for (i = 1; i < controlled_threads; ++i)+ kvmppc_release_hwthread_secondary(pcpu + i);+ kvmppc_release_hwthread(pcpu); return; }
@@ -2858,11 +2883,13 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) /* Let secondaries go back to the offline loop */ for (i = 0; i < controlled_threads; ++i) {- kvmppc_release_hwthread(pcpu + i); if (sip && sip->napped[i]) kvmppc_ipi_thread(pcpu + i); cpumask_clear_cpu(pcpu + i, &vc->kvm->arch.cpu_in_guest); }
We are sending an IPI to the thread that has exited the guest and is
currently napping. The IPI wakes it up so that it can executes
offline loop. But we haven't released the hwthread yet, which means
that hwthread_req for this thread is still set.
The thread wakes up from nap, executes the pnv_powersave_wakeup code
where it can enter kvm_start_guest. Is this a legitimate race or am I
missing something?
quoted hunk
+ for (i = 1; i < controlled_threads; ++i)
+ kvmppc_release_hwthread_secondary(pcpu + i);
+ kvmppc_release_hwthread(pcpu);
spin_unlock(&vc->lock);
From: Gautham R Shenoy <hidden> Date: 2017-08-08 10:45:42
On Sun, Aug 06, 2017 at 03:02:40AM +1000, Nicholas Piggin wrote:
The hardware can execute stop in any context, and KVM does not
require real mode. This saves a switch to real-mode when going
idle.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
From: Gautham R Shenoy <hidden> Date: 2017-08-08 10:49:43
On Sun, Aug 06, 2017 at 03:02:41AM +1000, Nicholas Piggin wrote:
When stop is executed with EC=ESL=0, it appears to execute like a
normal instruction (resuming from NIP when woken by interrupt).
So all the save/restore handling can be avoided completely. In
particular NV GPRs do not have to be saved, and MSR does not have
to be switched back to kernel MSR.
So move the test for "lite" sleep states out to power9_idle_stop.
Nice optimization!
Reviewed-by: Gautham R. Shenoy <redacted>
From: Nicholas Piggin <npiggin@gmail.com> Date: 2017-08-08 12:43:16
On Tue, 8 Aug 2017 16:06:43 +0530
Gautham R Shenoy [off-list ref] wrote:
Hi Nicholas,
On Sun, Aug 06, 2017 at 03:02:38AM +1000, Nicholas Piggin wrote:
quoted
POWER9 CPUs have independent MMU contexts per thread so KVM
does not have to bring sibling threads into real-mode when
switching MMU mode to guest. This can simplify POWER9 sleep/wake
paths and avoids hwsyncs.
quoted
@@ -444,6 +439,7 @@ ALT_FTR_SECTION_END_IFSET(CPU_FTR_ARCH_300) beq 1f b kvm_start_guest 1:+END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
This would be 7 nops on power9. Should we move this to a different
function and do a bl to that?
@@ -2858,11 +2883,13 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) /* Let secondaries go back to the offline loop */ for (i = 0; i < controlled_threads; ++i) {- kvmppc_release_hwthread(pcpu + i); if (sip && sip->napped[i]) kvmppc_ipi_thread(pcpu + i); cpumask_clear_cpu(pcpu + i, &vc->kvm->arch.cpu_in_guest); }
We are sending an IPI to the thread that has exited the guest and is
currently napping. The IPI wakes it up so that it can executes
offline loop. But we haven't released the hwthread yet, which means
that hwthread_req for this thread is still set.
The thread wakes up from nap, executes the pnv_powersave_wakeup code
where it can enter kvm_start_guest. Is this a legitimate race or am I
missing something?
Oh I think it's just a silly mistake in my patch, good catch.
Would moving this loop below the one below solve it? I wasn't
completely happy with uglifying these loops by making the
primary release different than secondary... maybe I will just
move the difference into kvmppc_release_hwthread and which is
less intrusive to callers.
Thanks,
Nick
From: Gautham R Shenoy <hidden> Date: 2017-08-10 06:24:26
On Tue, Aug 08, 2017 at 10:42:57PM +1000, Nicholas Piggin wrote:
On Tue, 8 Aug 2017 16:06:43 +0530
Gautham R Shenoy [off-list ref] wrote:
quoted
Hi Nicholas,
On Sun, Aug 06, 2017 at 03:02:38AM +1000, Nicholas Piggin wrote:
quoted
POWER9 CPUs have independent MMU contexts per thread so KVM
does not have to bring sibling threads into real-mode when
switching MMU mode to guest. This can simplify POWER9 sleep/wake
paths and avoids hwsyncs.
@@ -2858,11 +2883,13 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) /* Let secondaries go back to the offline loop */ for (i = 0; i < controlled_threads; ++i) {- kvmppc_release_hwthread(pcpu + i); if (sip && sip->napped[i]) kvmppc_ipi_thread(pcpu + i); cpumask_clear_cpu(pcpu + i, &vc->kvm->arch.cpu_in_guest); }
We are sending an IPI to the thread that has exited the guest and is
currently napping. The IPI wakes it up so that it can executes
offline loop. But we haven't released the hwthread yet, which means
that hwthread_req for this thread is still set.
The thread wakes up from nap, executes the pnv_powersave_wakeup code
where it can enter kvm_start_guest. Is this a legitimate race or am I
missing something?
Oh I think it's just a silly mistake in my patch, good catch.
Ah,np!
Would moving this loop below the one below solve it? I wasn't
completely happy with uglifying these loops by making the
primary release different than secondary... maybe I will just
move the difference into kvmppc_release_hwthread and which is
less intrusive to callers.
I think moving it to kvmppc_release_hwthread is a good idea.
From: Michael Ellerman <mpe@ellerman.id.au> Date: 2017-08-10 13:13:01
Nicholas Piggin [off-list ref] writes:
On Sun, 06 Aug 2017 09:00:32 +1000
Benjamin Herrenschmidt [off-list ref] wrote:
quoted
On Sun, 2017-08-06 at 03:02 +1000, Nicholas Piggin wrote:
quoted
HVI interrupts have always used 0x500, so remove the dead branch.
Maybe we should fix that and "catch" in incorrect entry via 0x500
which would mean the XIVE is trying to deliver guest irqs to the OS...
I should be more clear, when I say 0x500, it is only in reference to
the constant used by the soft-irq replay. After patch 6 the replay is
sent to the 0xea0 common handler.
quoted
That can happen if some LPCR bits aren't set properly and/or KVM
doesn't pull the guest in time. I had bugs like that in my early
dev so I've been running with a b . at 0x500 for a while :-)
Hmm, yeah I was going to merge that.
But I got side tracked by HVICE, ie. the "interrupts don't go to 0x500"
is only true if we set HVICE.
Which we currently always do, in __setup_cpu_power9(), but then we have
a DT CPU feature for it, so we really shouldn't be always enabling
HVICE, we should leave it up to the DT CPU feature code.
And then it becomes controlled by the device tree, which makes your
patch potentially wrong depending on the device tree CPU features.
Ugh.
cheers
From: Michael Ellerman <mpe@ellerman.id.au> Date: 2017-08-10 13:14:47
Nicholas Piggin [off-list ref] writes:
POWER9 CPUs have independent MMU contexts per thread so KVM
does not have to bring sibling threads into real-mode when
switching MMU mode to guest. This can simplify POWER9 sleep/wake
paths and avoids hwsyncs.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/include/asm/kvm_book3s_asm.h | 4 ++++
arch/powerpc/kernel/idle_book3s.S | 8 ++-----
arch/powerpc/kvm/book3s_hv.c | 37 ++++++++++++++++++++++++++-----
arch/powerpc/kvm/book3s_hv_rmhandlers.S | 8 +++++++
This will need to go via, or at least be shared with Paul's tree.
So if it's possible, splitting it out of this series would be easier.
cheers
From: Nicholas Piggin <npiggin@gmail.com> Date: 2017-08-10 13:53:23
On Thu, 10 Aug 2017 23:14:46 +1000
Michael Ellerman [off-list ref] wrote:
Nicholas Piggin [off-list ref] writes:
quoted
POWER9 CPUs have independent MMU contexts per thread so KVM
does not have to bring sibling threads into real-mode when
switching MMU mode to guest. This can simplify POWER9 sleep/wake
paths and avoids hwsyncs.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/include/asm/kvm_book3s_asm.h | 4 ++++
arch/powerpc/kernel/idle_book3s.S | 8 ++-----
arch/powerpc/kvm/book3s_hv.c | 37 ++++++++++++++++++++++++++-----
arch/powerpc/kvm/book3s_hv_rmhandlers.S | 8 +++++++
This will need to go via, or at least be shared with Paul's tree.
So if it's possible, splitting it out of this series would be easier.
I agree it's really a KVM patch, but patch 12 depends on this,
it is a Linux patch. Not sure how you want to handle that?
Thanks,
Nick