Add Bus Lock Detect (called Bus Lock Trap in AMD docs) support for AMD platforms. Bus Lock Detect is enumerated with CPUID Fn0000_0007_ECX_x0 bit [24 / BUSLOCKTRAP]. It can be enabled through MSR_IA32_DEBUGCTLMSR. When enabled, hardware clears DR6[11] and raises a #DB exception on occurrence of Bus Lock if CPL > 0. More detail about the feature can be found in AMD APM[1]. [1]: AMD64 Architecture Programmer's Manual Pub. 40332, Rev. 4.07 - June 2023, Vol 2, 13.1.3.6 Bus Lock Trap https://bugzilla.kernel.org/attachment.cgi?id=304653 Signed-off-by: Ravi Bangoria <ravi.bangoria@xxxxxxx> --- arch/x86/include/asm/cpu.h | 8 +++++--- arch/x86/kernel/cpu/bus_lock.c | 4 ++-- arch/x86/kernel/cpu/common.c | 2 ++ arch/x86/kernel/cpu/intel.c | 1 - include/linux/sched.h | 2 +- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index 051d872d2faf..c17fdf899835 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -26,14 +26,13 @@ int mwait_usable(const struct cpuinfo_x86 *); unsigned int x86_family(unsigned int sig); unsigned int x86_model(unsigned int sig); unsigned int x86_stepping(unsigned int sig); -#ifdef CONFIG_CPU_SUP_INTEL +#if defined(CONFIG_CPU_SUP_INTEL) || defined(CONFIG_CPU_SUP_AMD) extern void __init sld_setup(struct cpuinfo_x86 *c); extern bool handle_user_split_lock(struct pt_regs *regs, long error_code); extern bool handle_guest_split_lock(unsigned long ip); extern void handle_bus_lock(struct pt_regs *regs); void split_lock_init(void); void bus_lock_init(void); -u8 get_this_hybrid_cpu_type(void); #else static inline void __init sld_setup(struct cpuinfo_x86 *c) {} static inline bool handle_user_split_lock(struct pt_regs *regs, long error_code) @@ -49,7 +48,10 @@ static inline bool handle_guest_split_lock(unsigned long ip) static inline void handle_bus_lock(struct pt_regs *regs) {} static inline void split_lock_init(void) {} static inline void bus_lock_init(void) {} - +#endif +#ifdef CONFIG_CPU_SUP_INTEL +u8 get_this_hybrid_cpu_type(void); +#else static inline u8 get_this_hybrid_cpu_type(void) { return 0; diff --git a/arch/x86/kernel/cpu/bus_lock.c b/arch/x86/kernel/cpu/bus_lock.c index cffb3f2838dc..74c3ae6f1cd2 100644 --- a/arch/x86/kernel/cpu/bus_lock.c +++ b/arch/x86/kernel/cpu/bus_lock.c @@ -11,7 +11,7 @@ #include <asm/traps.h> #include <asm/cpu.h> -#if defined(CONFIG_CPU_SUP_INTEL) +#if defined(CONFIG_CPU_SUP_INTEL) || defined(CONFIG_CPU_SUP_AMD) enum split_lock_detect_state { sld_off = 0, @@ -407,4 +407,4 @@ void __init sld_setup(struct cpuinfo_x86 *c) sld_state_show(); } -#endif /* defined(CONFIG_CPU_SUP_INTEL) */ +#endif /* defined(CONFIG_CPU_SUP_INTEL) || defined(CONFIG_CPU_SUP_AMD) */ diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index d4e539d4e158..a37670e1ab4d 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -1832,6 +1832,8 @@ static void identify_cpu(struct cpuinfo_x86 *c) if (this_cpu->c_init) this_cpu->c_init(c); + bus_lock_init(); + /* Disable the PN if appropriate */ squash_the_stupid_serial_number(c); diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 8a483f4ad026..799f18545c6e 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -610,7 +610,6 @@ static void init_intel(struct cpuinfo_x86 *c) init_intel_misc_features(c); split_lock_init(); - bus_lock_init(); intel_init_thermal(c); } diff --git a/include/linux/sched.h b/include/linux/sched.h index d4cc144f72a3..6d1ff27e2f55 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -991,7 +991,7 @@ struct task_struct { #ifdef CONFIG_ARCH_HAS_CPU_PASID unsigned pasid_activated:1; #endif -#ifdef CONFIG_CPU_SUP_INTEL +#if defined(CONFIG_CPU_SUP_INTEL) || defined(CONFIG_CPU_SUP_AMD) unsigned reported_split_lock:1; #endif #ifdef CONFIG_TASK_DELAY_ACCT -- 2.34.1