Reading DR[0-3]_ADDR_MASK MSRs takes about 250 cycles which is going to be noticeable when the AMD KVM SEV-ES's DebugSwap feature is enabled and KVM needs to store these before switching to a guest; the DebugSwitch hardware support restores them as type B swap. This stores MSR values from set_dr_addr_mask() in percpu values and returns them via new get_dr_addr_mask(). The gain here is about 10x. Signed-off-by: Alexey Kardashevskiy <aik@xxxxxxx> --- arch/x86/include/asm/debugreg.h | 1 + arch/x86/kernel/cpu/amd.c | 32 ++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/arch/x86/include/asm/debugreg.h b/arch/x86/include/asm/debugreg.h index cfdf307ddc01..c4324d0205b5 100644 --- a/arch/x86/include/asm/debugreg.h +++ b/arch/x86/include/asm/debugreg.h @@ -127,6 +127,7 @@ static __always_inline void local_db_restore(unsigned long dr7) #ifdef CONFIG_CPU_SUP_AMD extern void set_dr_addr_mask(unsigned long mask, int dr); +extern unsigned long get_dr_addr_mask(int dr); #else static inline void set_dr_addr_mask(unsigned long mask, int dr) { } #endif diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index c75d75b9f11a..ec7efcef4e14 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -1158,6 +1158,11 @@ static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum) return false; } +DEFINE_PER_CPU_READ_MOSTLY(unsigned long, dr0_addr_mask); +DEFINE_PER_CPU_READ_MOSTLY(unsigned long, dr1_addr_mask); +DEFINE_PER_CPU_READ_MOSTLY(unsigned long, dr2_addr_mask); +DEFINE_PER_CPU_READ_MOSTLY(unsigned long, dr3_addr_mask); + void set_dr_addr_mask(unsigned long mask, int dr) { if (!boot_cpu_has(X86_FEATURE_BPEXT)) @@ -1166,17 +1171,44 @@ void set_dr_addr_mask(unsigned long mask, int dr) switch (dr) { case 0: wrmsr(MSR_F16H_DR0_ADDR_MASK, mask, 0); + per_cpu(dr0_addr_mask, smp_processor_id()) = mask; break; case 1: + wrmsr(MSR_F16H_DR1_ADDR_MASK - 1 + dr, mask, 0); + per_cpu(dr1_addr_mask, smp_processor_id()) = mask; + break; case 2: + wrmsr(MSR_F16H_DR1_ADDR_MASK - 1 + dr, mask, 0); + per_cpu(dr2_addr_mask, smp_processor_id()) = mask; + break; case 3: wrmsr(MSR_F16H_DR1_ADDR_MASK - 1 + dr, mask, 0); + per_cpu(dr3_addr_mask, smp_processor_id()) = mask; break; default: break; } } +unsigned long get_dr_addr_mask(int dr) +{ + if (!boot_cpu_has(X86_FEATURE_BPEXT)) + return 0; + + switch (dr) { + case 0: + return per_cpu(dr0_addr_mask, smp_processor_id()); + case 1: + return per_cpu(dr1_addr_mask, smp_processor_id()); + case 2: + return per_cpu(dr2_addr_mask, smp_processor_id()); + case 3: + return per_cpu(dr3_addr_mask, smp_processor_id()); + } + return 0; +} +EXPORT_SYMBOL_GPL(get_dr_addr_mask); + u32 amd_get_highest_perf(void) { struct cpuinfo_x86 *c = &boot_cpu_data; -- 2.38.1