aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJacob Shin <jacob.w.shin@gmail.com>2014-05-29 11:26:50 -0400
committerFrederic Weisbecker <fweisbec@gmail.com>2014-12-03 09:14:26 -0500
commitd6d55f0b9d900673548515614b56ab55aa2c51f8 (patch)
tree2c5d9bdff4444fec201a014e071e718a0f34d8aa
parent4e6e311e596eadba30d4f56f64eae7d45611a01c (diff)
perf/x86/amd: AMD support for bp_len > HW_BREAKPOINT_LEN_8
Implement hardware breakpoint address mask for AMD Family 16h and above processors. CPUID feature bit indicates hardware support for DRn_ADDR_MASK MSRs. These masks further qualify DRn/DR7 hardware breakpoint addresses to allow matching of larger addresses ranges. Valuable advice and pseudo code from Oleg Nesterov <oleg@redhat.com> Signed-off-by: Jacob Shin <jacob.w.shin@gmail.com> Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com> Acked-by: Jiri Olsa <jolsa@kernel.org> Reviewed-by: Oleg Nesterov <oleg@redhat.com> Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net> Cc: Ingo Molnar <mingo@kernel.org> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: xiakaixu <xiakaixu@huawei.com> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
-rw-r--r--arch/x86/include/asm/cpufeature.h2
-rw-r--r--arch/x86/include/asm/debugreg.h5
-rw-r--r--arch/x86/include/asm/hw_breakpoint.h1
-rw-r--r--arch/x86/include/uapi/asm/msr-index.h4
-rw-r--r--arch/x86/kernel/cpu/amd.c19
-rw-r--r--arch/x86/kernel/hw_breakpoint.c20
6 files changed, 47 insertions, 4 deletions
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index 0bb1335313b2..53966d65591e 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -174,6 +174,7 @@
174#define X86_FEATURE_TOPOEXT ( 6*32+22) /* topology extensions CPUID leafs */ 174#define X86_FEATURE_TOPOEXT ( 6*32+22) /* topology extensions CPUID leafs */
175#define X86_FEATURE_PERFCTR_CORE ( 6*32+23) /* core performance counter extensions */ 175#define X86_FEATURE_PERFCTR_CORE ( 6*32+23) /* core performance counter extensions */
176#define X86_FEATURE_PERFCTR_NB ( 6*32+24) /* NB performance counter extensions */ 176#define X86_FEATURE_PERFCTR_NB ( 6*32+24) /* NB performance counter extensions */
177#define X86_FEATURE_BPEXT (6*32+26) /* data breakpoint extension */
177#define X86_FEATURE_PERFCTR_L2 ( 6*32+28) /* L2 performance counter extensions */ 178#define X86_FEATURE_PERFCTR_L2 ( 6*32+28) /* L2 performance counter extensions */
178 179
179/* 180/*
@@ -383,6 +384,7 @@ extern const char * const x86_bug_flags[NBUGINTS*32];
383#define cpu_has_cx16 boot_cpu_has(X86_FEATURE_CX16) 384#define cpu_has_cx16 boot_cpu_has(X86_FEATURE_CX16)
384#define cpu_has_eager_fpu boot_cpu_has(X86_FEATURE_EAGER_FPU) 385#define cpu_has_eager_fpu boot_cpu_has(X86_FEATURE_EAGER_FPU)
385#define cpu_has_topoext boot_cpu_has(X86_FEATURE_TOPOEXT) 386#define cpu_has_topoext boot_cpu_has(X86_FEATURE_TOPOEXT)
387#define cpu_has_bpext boot_cpu_has(X86_FEATURE_BPEXT)
386 388
387#if __GNUC__ >= 4 389#if __GNUC__ >= 4
388extern void warn_pre_alternatives(void); 390extern void warn_pre_alternatives(void);
diff --git a/arch/x86/include/asm/debugreg.h b/arch/x86/include/asm/debugreg.h
index 61fd18b83b6c..12cb66f6d3a5 100644
--- a/arch/x86/include/asm/debugreg.h
+++ b/arch/x86/include/asm/debugreg.h
@@ -114,5 +114,10 @@ static inline void debug_stack_usage_inc(void) { }
114static inline void debug_stack_usage_dec(void) { } 114static inline void debug_stack_usage_dec(void) { }
115#endif /* X86_64 */ 115#endif /* X86_64 */
116 116
117#ifdef CONFIG_CPU_SUP_AMD
118extern void set_dr_addr_mask(unsigned long mask, int dr);
119#else
120static inline void set_dr_addr_mask(unsigned long mask, int dr) { }
121#endif
117 122
118#endif /* _ASM_X86_DEBUGREG_H */ 123#endif /* _ASM_X86_DEBUGREG_H */
diff --git a/arch/x86/include/asm/hw_breakpoint.h b/arch/x86/include/asm/hw_breakpoint.h
index ef1c4d2d41ec..6c98be864a75 100644
--- a/arch/x86/include/asm/hw_breakpoint.h
+++ b/arch/x86/include/asm/hw_breakpoint.h
@@ -12,6 +12,7 @@
12 */ 12 */
13struct arch_hw_breakpoint { 13struct arch_hw_breakpoint {
14 unsigned long address; 14 unsigned long address;
15 unsigned long mask;
15 u8 len; 16 u8 len;
16 u8 type; 17 u8 type;
17}; 18};
diff --git a/arch/x86/include/uapi/asm/msr-index.h b/arch/x86/include/uapi/asm/msr-index.h
index 8f02f6990759..b1fb4fae03d3 100644
--- a/arch/x86/include/uapi/asm/msr-index.h
+++ b/arch/x86/include/uapi/asm/msr-index.h
@@ -212,6 +212,10 @@
212/* Fam 16h MSRs */ 212/* Fam 16h MSRs */
213#define MSR_F16H_L2I_PERF_CTL 0xc0010230 213#define MSR_F16H_L2I_PERF_CTL 0xc0010230
214#define MSR_F16H_L2I_PERF_CTR 0xc0010231 214#define MSR_F16H_L2I_PERF_CTR 0xc0010231
215#define MSR_F16H_DR1_ADDR_MASK 0xc0011019
216#define MSR_F16H_DR2_ADDR_MASK 0xc001101a
217#define MSR_F16H_DR3_ADDR_MASK 0xc001101b
218#define MSR_F16H_DR0_ADDR_MASK 0xc0011027
215 219
216/* Fam 15h MSRs */ 220/* Fam 15h MSRs */
217#define MSR_F15H_PERF_CTL 0xc0010200 221#define MSR_F15H_PERF_CTL 0xc0010200
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index 813d29d00a17..abe4ec760db3 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -870,3 +870,22 @@ static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum)
870 870
871 return false; 871 return false;
872} 872}
873
874void set_dr_addr_mask(unsigned long mask, int dr)
875{
876 if (!cpu_has_bpext)
877 return;
878
879 switch (dr) {
880 case 0:
881 wrmsr(MSR_F16H_DR0_ADDR_MASK, mask, 0);
882 break;
883 case 1:
884 case 2:
885 case 3:
886 wrmsr(MSR_F16H_DR1_ADDR_MASK - 1 + dr, mask, 0);
887 break;
888 default:
889 break;
890 }
891}
diff --git a/arch/x86/kernel/hw_breakpoint.c b/arch/x86/kernel/hw_breakpoint.c
index 3d5fb509bdeb..b5cb0c59ea87 100644
--- a/arch/x86/kernel/hw_breakpoint.c
+++ b/arch/x86/kernel/hw_breakpoint.c
@@ -126,6 +126,8 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
126 *dr7 |= encode_dr7(i, info->len, info->type); 126 *dr7 |= encode_dr7(i, info->len, info->type);
127 127
128 set_debugreg(*dr7, 7); 128 set_debugreg(*dr7, 7);
129 if (info->mask)
130 set_dr_addr_mask(info->mask, i);
129 131
130 return 0; 132 return 0;
131} 133}
@@ -161,6 +163,8 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp)
161 *dr7 &= ~__encode_dr7(i, info->len, info->type); 163 *dr7 &= ~__encode_dr7(i, info->len, info->type);
162 164
163 set_debugreg(*dr7, 7); 165 set_debugreg(*dr7, 7);
166 if (info->mask)
167 set_dr_addr_mask(0, i);
164} 168}
165 169
166static int get_hbp_len(u8 hbp_len) 170static int get_hbp_len(u8 hbp_len)
@@ -277,6 +281,8 @@ static int arch_build_bp_info(struct perf_event *bp)
277 } 281 }
278 282
279 /* Len */ 283 /* Len */
284 info->mask = 0;
285
280 switch (bp->attr.bp_len) { 286 switch (bp->attr.bp_len) {
281 case HW_BREAKPOINT_LEN_1: 287 case HW_BREAKPOINT_LEN_1:
282 info->len = X86_BREAKPOINT_LEN_1; 288 info->len = X86_BREAKPOINT_LEN_1;
@@ -293,11 +299,17 @@ static int arch_build_bp_info(struct perf_event *bp)
293 break; 299 break;
294#endif 300#endif
295 default: 301 default:
296 return -EINVAL; 302 if (!is_power_of_2(bp->attr.bp_len))
303 return -EINVAL;
304 if (!cpu_has_bpext)
305 return -EOPNOTSUPP;
306 info->mask = bp->attr.bp_len - 1;
307 info->len = X86_BREAKPOINT_LEN_1;
297 } 308 }
298 309
299 return 0; 310 return 0;
300} 311}
312
301/* 313/*
302 * Validate the arch-specific HW Breakpoint register settings 314 * Validate the arch-specific HW Breakpoint register settings
303 */ 315 */
@@ -312,11 +324,11 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
312 if (ret) 324 if (ret)
313 return ret; 325 return ret;
314 326
315 ret = -EINVAL;
316
317 switch (info->len) { 327 switch (info->len) {
318 case X86_BREAKPOINT_LEN_1: 328 case X86_BREAKPOINT_LEN_1:
319 align = 0; 329 align = 0;
330 if (info->mask)
331 align = info->mask;
320 break; 332 break;
321 case X86_BREAKPOINT_LEN_2: 333 case X86_BREAKPOINT_LEN_2:
322 align = 1; 334 align = 1;
@@ -330,7 +342,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
330 break; 342 break;
331#endif 343#endif
332 default: 344 default:
333 return ret; 345 WARN_ON_ONCE(1);
334 } 346 }
335 347
336 /* 348 /*