mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-01 16:14:13 +08:00
powerpc/64s/interrupt: avoid saving CFAR in some asynchronous interrupts
Reading the CFAR register is quite costly (~20 cycles on POWER9). It is a good idea to have for most synchronous interrupts, but for async ones it is much less important. Doorbell, external, and decrementer interrupts are the important asynchronous ones. HV interrupts can't skip CFAR if KVM HV is possible, because it might be a guest exit that requires CFAR preserved. But the important pseries interrupts can avoid loading CFAR. Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/20210922145452.352571-7-npiggin@gmail.com
This commit is contained in:
parent
ecb1057c0f
commit
af47d79b04
@ -111,6 +111,8 @@ name:
|
||||
#define IAREA .L_IAREA_\name\() /* PACA save area */
|
||||
#define IVIRT .L_IVIRT_\name\() /* Has virt mode entry point */
|
||||
#define IISIDE .L_IISIDE_\name\() /* Uses SRR0/1 not DAR/DSISR */
|
||||
#define ICFAR .L_ICFAR_\name\() /* Uses CFAR */
|
||||
#define ICFAR_IF_HVMODE .L_ICFAR_IF_HVMODE_\name\() /* Uses CFAR if HV */
|
||||
#define IDAR .L_IDAR_\name\() /* Uses DAR (or SRR0) */
|
||||
#define IDSISR .L_IDSISR_\name\() /* Uses DSISR (or SRR1) */
|
||||
#define IBRANCH_TO_COMMON .L_IBRANCH_TO_COMMON_\name\() /* ENTRY branch to common */
|
||||
@ -150,6 +152,12 @@ do_define_int n
|
||||
.ifndef IISIDE
|
||||
IISIDE=0
|
||||
.endif
|
||||
.ifndef ICFAR
|
||||
ICFAR=1
|
||||
.endif
|
||||
.ifndef ICFAR_IF_HVMODE
|
||||
ICFAR_IF_HVMODE=0
|
||||
.endif
|
||||
.ifndef IDAR
|
||||
IDAR=0
|
||||
.endif
|
||||
@ -287,9 +295,21 @@ BEGIN_FTR_SECTION
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
|
||||
HMT_MEDIUM
|
||||
std r10,IAREA+EX_R10(r13) /* save r10 - r12 */
|
||||
.if ICFAR
|
||||
BEGIN_FTR_SECTION
|
||||
mfspr r10,SPRN_CFAR
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
|
||||
.elseif ICFAR_IF_HVMODE
|
||||
BEGIN_FTR_SECTION
|
||||
BEGIN_FTR_SECTION_NESTED(69)
|
||||
mfspr r10,SPRN_CFAR
|
||||
END_FTR_SECTION_NESTED(CPU_FTR_CFAR, CPU_FTR_CFAR, 69)
|
||||
FTR_SECTION_ELSE
|
||||
BEGIN_FTR_SECTION_NESTED(69)
|
||||
li r10,0
|
||||
END_FTR_SECTION_NESTED(CPU_FTR_CFAR, CPU_FTR_CFAR, 69)
|
||||
ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
|
||||
.endif
|
||||
.if \ool
|
||||
.if !\virt
|
||||
b tramp_real_\name
|
||||
@ -305,9 +325,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
|
||||
BEGIN_FTR_SECTION
|
||||
std r9,IAREA+EX_PPR(r13)
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
|
||||
.if ICFAR || ICFAR_IF_HVMODE
|
||||
BEGIN_FTR_SECTION
|
||||
std r10,IAREA+EX_CFAR(r13)
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
|
||||
.endif
|
||||
INTERRUPT_TO_KERNEL
|
||||
mfctr r10
|
||||
std r10,IAREA+EX_CTR(r13)
|
||||
@ -559,7 +581,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
|
||||
.endif
|
||||
|
||||
BEGIN_FTR_SECTION
|
||||
.if ICFAR || ICFAR_IF_HVMODE
|
||||
ld r10,IAREA+EX_CFAR(r13)
|
||||
.else
|
||||
li r10,0
|
||||
.endif
|
||||
std r10,ORIG_GPR3(r1)
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
|
||||
ld r10,IAREA+EX_CTR(r13)
|
||||
@ -1520,6 +1546,12 @@ ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX)
|
||||
*
|
||||
* If soft masked, the masked handler will note the pending interrupt for
|
||||
* replay, and clear MSR[EE] in the interrupted context.
|
||||
*
|
||||
* CFAR is not required because this is an asynchronous interrupt that in
|
||||
* general won't have much bearing on the state of the CPU, with the possible
|
||||
* exception of crash/debug IPIs, but those are generally moving to use SRESET
|
||||
* IPIs. Unless this is an HV interrupt and KVM HV is possible, in which case
|
||||
* it may be exiting the guest and need CFAR to be saved.
|
||||
*/
|
||||
INT_DEFINE_BEGIN(hardware_interrupt)
|
||||
IVEC=0x500
|
||||
@ -1527,6 +1559,10 @@ INT_DEFINE_BEGIN(hardware_interrupt)
|
||||
IMASK=IRQS_DISABLED
|
||||
IKVM_REAL=1
|
||||
IKVM_VIRT=1
|
||||
ICFAR=0
|
||||
#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
|
||||
ICFAR_IF_HVMODE=1
|
||||
#endif
|
||||
INT_DEFINE_END(hardware_interrupt)
|
||||
|
||||
EXC_REAL_BEGIN(hardware_interrupt, 0x500, 0x100)
|
||||
@ -1748,6 +1784,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_TM)
|
||||
* If PPC_WATCHDOG is configured, the soft masked handler will actually set
|
||||
* things back up to run soft_nmi_interrupt as a regular interrupt handler
|
||||
* on the emergency stack.
|
||||
*
|
||||
* CFAR is not required because this is asynchronous (see hardware_interrupt).
|
||||
* A watchdog interrupt may like to have CFAR, but usually the interesting
|
||||
* branch is long gone by that point (e.g., infinite loop).
|
||||
*/
|
||||
INT_DEFINE_BEGIN(decrementer)
|
||||
IVEC=0x900
|
||||
@ -1755,6 +1795,7 @@ INT_DEFINE_BEGIN(decrementer)
|
||||
#ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
|
||||
IKVM_REAL=1
|
||||
#endif
|
||||
ICFAR=0
|
||||
INT_DEFINE_END(decrementer)
|
||||
|
||||
EXC_REAL_BEGIN(decrementer, 0x900, 0x80)
|
||||
@ -1830,6 +1871,8 @@ EXC_COMMON_BEGIN(hdecrementer_common)
|
||||
* If soft masked, the masked handler will note the pending interrupt for
|
||||
* replay, leaving MSR[EE] enabled in the interrupted context because the
|
||||
* doorbells are edge triggered.
|
||||
*
|
||||
* CFAR is not required, similarly to hardware_interrupt.
|
||||
*/
|
||||
INT_DEFINE_BEGIN(doorbell_super)
|
||||
IVEC=0xa00
|
||||
@ -1837,6 +1880,7 @@ INT_DEFINE_BEGIN(doorbell_super)
|
||||
#ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
|
||||
IKVM_REAL=1
|
||||
#endif
|
||||
ICFAR=0
|
||||
INT_DEFINE_END(doorbell_super)
|
||||
|
||||
EXC_REAL_BEGIN(doorbell_super, 0xa00, 0x100)
|
||||
@ -1888,6 +1932,7 @@ INT_DEFINE_BEGIN(system_call)
|
||||
IVEC=0xc00
|
||||
IKVM_REAL=1
|
||||
IKVM_VIRT=1
|
||||
ICFAR=0
|
||||
INT_DEFINE_END(system_call)
|
||||
|
||||
.macro SYSTEM_CALL virt
|
||||
@ -2186,6 +2231,11 @@ EXC_COMMON_BEGIN(hmi_exception_common)
|
||||
* Interrupt 0xe80 - Directed Hypervisor Doorbell Interrupt.
|
||||
* This is an asynchronous interrupt in response to a msgsnd doorbell.
|
||||
* Similar to the 0xa00 doorbell but for host rather than guest.
|
||||
*
|
||||
* CFAR is not required (similar to doorbell_interrupt), unless KVM HV
|
||||
* is enabled, in which case it may be a guest exit. Most PowerNV kernels
|
||||
* include KVM support so it would be nice if this could be dynamically
|
||||
* patched out if KVM was not currently running any guests.
|
||||
*/
|
||||
INT_DEFINE_BEGIN(h_doorbell)
|
||||
IVEC=0xe80
|
||||
@ -2193,6 +2243,9 @@ INT_DEFINE_BEGIN(h_doorbell)
|
||||
IMASK=IRQS_DISABLED
|
||||
IKVM_REAL=1
|
||||
IKVM_VIRT=1
|
||||
#ifndef CONFIG_KVM_BOOK3S_HV_POSSIBLE
|
||||
ICFAR=0
|
||||
#endif
|
||||
INT_DEFINE_END(h_doorbell)
|
||||
|
||||
EXC_REAL_BEGIN(h_doorbell, 0xe80, 0x20)
|
||||
@ -2216,6 +2269,9 @@ EXC_COMMON_BEGIN(h_doorbell_common)
|
||||
* Interrupt 0xea0 - Hypervisor Virtualization Interrupt.
|
||||
* This is an asynchronous interrupt in response to an "external exception".
|
||||
* Similar to 0x500 but for host only.
|
||||
*
|
||||
* Like h_doorbell, CFAR is only required for KVM HV because this can be
|
||||
* a guest exit.
|
||||
*/
|
||||
INT_DEFINE_BEGIN(h_virt_irq)
|
||||
IVEC=0xea0
|
||||
@ -2223,6 +2279,9 @@ INT_DEFINE_BEGIN(h_virt_irq)
|
||||
IMASK=IRQS_DISABLED
|
||||
IKVM_REAL=1
|
||||
IKVM_VIRT=1
|
||||
#ifndef CONFIG_KVM_BOOK3S_HV_POSSIBLE
|
||||
ICFAR=0
|
||||
#endif
|
||||
INT_DEFINE_END(h_virt_irq)
|
||||
|
||||
EXC_REAL_BEGIN(h_virt_irq, 0xea0, 0x20)
|
||||
@ -2259,6 +2318,8 @@ EXC_VIRT_NONE(0x4ee0, 0x20)
|
||||
*
|
||||
* If soft masked, the masked handler will note the pending interrupt for
|
||||
* replay, and clear MSR[EE] in the interrupted context.
|
||||
*
|
||||
* CFAR is not used by perf interrupts so not required.
|
||||
*/
|
||||
INT_DEFINE_BEGIN(performance_monitor)
|
||||
IVEC=0xf00
|
||||
@ -2266,6 +2327,7 @@ INT_DEFINE_BEGIN(performance_monitor)
|
||||
#ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
|
||||
IKVM_REAL=1
|
||||
#endif
|
||||
ICFAR=0
|
||||
INT_DEFINE_END(performance_monitor)
|
||||
|
||||
EXC_REAL_BEGIN(performance_monitor, 0xf00, 0x20)
|
||||
@ -2690,6 +2752,7 @@ EXC_VIRT_NONE(0x5800, 0x100)
|
||||
INT_DEFINE_BEGIN(soft_nmi)
|
||||
IVEC=0x900
|
||||
ISTACK=0
|
||||
ICFAR=0
|
||||
INT_DEFINE_END(soft_nmi)
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user