[PATCH v2 30/52] powerpc/64s/exception: optimise system_reset for idle, clean up non-idle case
Nicholas Piggin
npiggin at gmail.com
Thu Jun 20 15:41:22 AEST 2019
Nicholas Piggin's on June 20, 2019 3:14 pm:
> The idle wake up code in the system reset interrupt is not very
> optimal. There are two requirements: perform idle wake up quickly;
> and save everything including CFAR for non-idle interrupts, with
> no performance requirement.
>
> The problem with placing the idle test in the middle of the handler
> and using the normal handler code to save CFAR, is that it's quite
> costly (e.g., mfcfar is serialising, speculative workarounds get
> applied, SRR1 has to be reloaded, etc). It also prevents the standard
> interrupt handler boilerplate being used.
>
> This pain can be avoided by using a dedicated idle interrupt handler
> at the start of the interrupt handler, which restores all registers
> back to the way they were in case it was not an idle wake up. CFAR
> is preserved without saving it before the non-idle case by making that
> the fall-through, and idle is a taken branch.
>
> Performance seems to be in the noise, but possibly around 0.5% faster,
> the executed instructions certainly look better. The bigger benefit is
> being able to drop in standard interrupt handlers after the idle code,
> which helps with subsequent cleanup and consolidation.
>
> Signed-off-by: Nicholas Piggin <npiggin at gmail.com>
> ---
> arch/powerpc/kernel/exceptions-64s.S | 89 ++++++++++++++--------------
> 1 file changed, 44 insertions(+), 45 deletions(-)
>
> diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
> index e0492912ea79..f582ae30f3f7 100644
> --- a/arch/powerpc/kernel/exceptions-64s.S
> +++ b/arch/powerpc/kernel/exceptions-64s.S
> @@ -241,7 +241,7 @@ END_FTR_SECTION_NESTED(ftr,ftr,943)
> * load KBASE for a slight optimisation.
> */
> #define BRANCH_TO_C000(reg, label) \
> - __LOAD_HANDLER(reg, label); \
> + __LOAD_FAR_HANDLER(reg, label); \
> mtctr reg; \
> bctr
>
> @@ -784,16 +784,6 @@ EXC_VIRT_NONE(0x4000, 0x100)
>
>
> EXC_REAL_BEGIN(system_reset, 0x100, 0x100)
> - SET_SCRATCH0(r13)
> - EXCEPTION_PROLOG_0 PACA_EXNMI
> -
> - /* This is EXCEPTION_PROLOG_1 with the idle feature section added */
> - OPT_SAVE_REG_TO_PACA(PACA_EXNMI+EX_PPR, r9, CPU_FTR_HAS_PPR)
> - OPT_SAVE_REG_TO_PACA(PACA_EXNMI+EX_CFAR, r10, CPU_FTR_CFAR)
> - INTERRUPT_TO_KERNEL
> - SAVE_CTR(r10, PACA_EXNMI)
> - mfcr r9
> -
> #ifdef CONFIG_PPC_P7_NAP
> /*
> * If running native on arch 2.06 or later, check if we are waking up
> @@ -801,45 +791,67 @@ EXC_REAL_BEGIN(system_reset, 0x100, 0x100)
> * bits 46:47. A non-0 value indicates that we are coming from a power
> * saving state. The idle wakeup handler initially runs in real mode,
> * but we branch to the 0xc000... address so we can turn on relocation
> - * with mtmsr.
> + * with mtmsrd later, after SPRs are restored.
> + *
> + * Careful to minimise cost for the fast path (idle wakeup) while
> + * also avoiding clobbering CFAR for the non-idle case. Once we know
> + * it is an idle wake, volatiles don't matter, which is why we use
> + * those here, and then re-do the entry in case of non-idle (without
> + * branching for the non-idle case, to keep CFAR).
> */
> BEGIN_FTR_SECTION
> - mfspr r10,SPRN_SRR1
> - rlwinm. r10,r10,47-31,30,31
> - beq- 1f
> - cmpwi cr1,r10,2
> + SET_SCRATCH0(r13)
> + GET_PACA(r13)
> + std r3,PACA_EXNMI+0*8(r13)
> + std r4,PACA_EXNMI+1*8(r13)
> + std r5,PACA_EXNMI+2*8(r13)
> mfspr r3,SPRN_SRR1
> - bltlr cr1 /* no state loss, return to idle caller */
> - BRANCH_TO_C000(r10, system_reset_idle_common)
> -1:
> + mfocrf r4,0x80
> + rlwinm. r5,r3,47-31,30,31
> + bne+ system_reset_idle_wake
> + /* Not powersave wakeup. Restore regs for regular interrupt handler. */
> + mtocrf 0x80,r4
> + ld r12,PACA_EXNMI+0*8(r13)
> + ld r4,PACA_EXNMI+1*8(r13)
> + ld r5,PACA_EXNMI+2*8(r13)
> + GET_SCRATCH0(r13)
For the love of... that should be 'ld r3', not 'ld r12', sorry.
Thanks,
Nick
More information about the Linuxppc-dev
mailing list