aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCyrill Gorcunov <gorcunov@gmail.com>2011-06-23 08:49:18 -0400
committerIngo Molnar <mingo@elte.hu>2011-07-01 05:06:34 -0400
commit1880c4ae182afb5650c5678949ecfe7ff66a724e (patch)
tree57306c05aca1e2a2ce5d07e8c29ad76b6b403879
parent0d6412085b7ff58612af52e51ffa864f0df4b8fd (diff)
perf, x86: Add hw_watchdog_set_attr() in a sake of nmi-watchdog on P4
Due to restriction and specifics of Netburst PMU we need a separated event for NMI watchdog. In particular every Netburst event consumes not just a counter and a config register, but also an additional ESCR register. Since ESCR registers are grouped upon counters (i.e. if ESCR is occupied for some event there is no room for another event to enter until its released) we need to pick up the "least" used ESCR (or the most available one) for nmi-watchdog purposes -- so MSR_P4_CRU_ESCR2/3 was chosen. With this patch nmi-watchdog and perf top should be able to run simultaneously. Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org> CC: Lin Ming <ming.m.lin@intel.com> CC: Arnaldo Carvalho de Melo <acme@redhat.com> CC: Frederic Weisbecker <fweisbec@gmail.com> Tested-and-reviewed-by: Don Zickus <dzickus@redhat.com> Tested-and-reviewed-by: Stephane Eranian <eranian@google.com> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/20110623124918.GC13050@sun Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--arch/x86/kernel/cpu/perf_event.c7
-rw-r--r--arch/x86/kernel/cpu/perf_event_p4.c26
-rw-r--r--kernel/watchdog.c6
3 files changed, 38 insertions, 1 deletions
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index 3a0338b4b179..8a57f9aa8e36 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -233,6 +233,7 @@ struct x86_pmu {
233 void (*enable_all)(int added); 233 void (*enable_all)(int added);
234 void (*enable)(struct perf_event *); 234 void (*enable)(struct perf_event *);
235 void (*disable)(struct perf_event *); 235 void (*disable)(struct perf_event *);
236 void (*hw_watchdog_set_attr)(struct perf_event_attr *attr);
236 int (*hw_config)(struct perf_event *event); 237 int (*hw_config)(struct perf_event *event);
237 int (*schedule_events)(struct cpu_hw_events *cpuc, int n, int *assign); 238 int (*schedule_events)(struct cpu_hw_events *cpuc, int n, int *assign);
238 unsigned eventsel; 239 unsigned eventsel;
@@ -315,6 +316,12 @@ static u64 __read_mostly hw_cache_extra_regs
315 [PERF_COUNT_HW_CACHE_OP_MAX] 316 [PERF_COUNT_HW_CACHE_OP_MAX]
316 [PERF_COUNT_HW_CACHE_RESULT_MAX]; 317 [PERF_COUNT_HW_CACHE_RESULT_MAX];
317 318
319void hw_nmi_watchdog_set_attr(struct perf_event_attr *wd_attr)
320{
321 if (x86_pmu.hw_watchdog_set_attr)
322 x86_pmu.hw_watchdog_set_attr(wd_attr);
323}
324
318/* 325/*
319 * Propagate event elapsed time into the generic event. 326 * Propagate event elapsed time into the generic event.
320 * Can only be executed on the CPU where the event is active. 327 * Can only be executed on the CPU where the event is active.
diff --git a/arch/x86/kernel/cpu/perf_event_p4.c b/arch/x86/kernel/cpu/perf_event_p4.c
index ead584fb6a7d..f76fddf63381 100644
--- a/arch/x86/kernel/cpu/perf_event_p4.c
+++ b/arch/x86/kernel/cpu/perf_event_p4.c
@@ -705,6 +705,31 @@ static int p4_validate_raw_event(struct perf_event *event)
705 return 0; 705 return 0;
706} 706}
707 707
708static void p4_hw_watchdog_set_attr(struct perf_event_attr *wd_attr)
709{
710 /*
711 * Watchdog ticks are special on Netburst, we use
712 * that named "non-sleeping" ticks as recommended
713 * by Intel SDM Vol3b.
714 */
715 WARN_ON_ONCE(wd_attr->type != PERF_TYPE_HARDWARE ||
716 wd_attr->config != PERF_COUNT_HW_CPU_CYCLES);
717
718 wd_attr->type = PERF_TYPE_RAW;
719 wd_attr->config =
720 p4_config_pack_escr(P4_ESCR_EVENT(P4_EVENT_EXECUTION_EVENT) |
721 P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, NBOGUS0) |
722 P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, NBOGUS1) |
723 P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, NBOGUS2) |
724 P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, NBOGUS3) |
725 P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, BOGUS0) |
726 P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, BOGUS1) |
727 P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, BOGUS2) |
728 P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, BOGUS3)) |
729 p4_config_pack_cccr(P4_CCCR_THRESHOLD(15) | P4_CCCR_COMPLEMENT |
730 P4_CCCR_COMPARE);
731}
732
708static int p4_hw_config(struct perf_event *event) 733static int p4_hw_config(struct perf_event *event)
709{ 734{
710 int cpu = get_cpu(); 735 int cpu = get_cpu();
@@ -1179,6 +1204,7 @@ static __initconst const struct x86_pmu p4_pmu = {
1179 .cntval_bits = ARCH_P4_CNTRVAL_BITS, 1204 .cntval_bits = ARCH_P4_CNTRVAL_BITS,
1180 .cntval_mask = ARCH_P4_CNTRVAL_MASK, 1205 .cntval_mask = ARCH_P4_CNTRVAL_MASK,
1181 .max_period = (1ULL << (ARCH_P4_CNTRVAL_BITS - 1)) - 1, 1206 .max_period = (1ULL << (ARCH_P4_CNTRVAL_BITS - 1)) - 1,
1207 .hw_watchdog_set_attr = p4_hw_watchdog_set_attr,
1182 .hw_config = p4_hw_config, 1208 .hw_config = p4_hw_config,
1183 .schedule_events = p4_pmu_schedule_events, 1209 .schedule_events = p4_pmu_schedule_events,
1184 /* 1210 /*
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index 3d0c56ad4792..752b75ba662b 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -200,6 +200,8 @@ static int is_softlockup(unsigned long touch_ts)
200} 200}
201 201
202#ifdef CONFIG_HARDLOCKUP_DETECTOR 202#ifdef CONFIG_HARDLOCKUP_DETECTOR
203void __weak hw_nmi_watchdog_set_attr(struct perf_event_attr *wd_attr) { }
204
203static struct perf_event_attr wd_hw_attr = { 205static struct perf_event_attr wd_hw_attr = {
204 .type = PERF_TYPE_HARDWARE, 206 .type = PERF_TYPE_HARDWARE,
205 .config = PERF_COUNT_HW_CPU_CYCLES, 207 .config = PERF_COUNT_HW_CPU_CYCLES,
@@ -368,9 +370,11 @@ static int watchdog_nmi_enable(int cpu)
368 if (event != NULL) 370 if (event != NULL)
369 goto out_enable; 371 goto out_enable;
370 372
371 /* Try to register using hardware perf events */
372 wd_attr = &wd_hw_attr; 373 wd_attr = &wd_hw_attr;
373 wd_attr->sample_period = hw_nmi_get_sample_period(watchdog_thresh); 374 wd_attr->sample_period = hw_nmi_get_sample_period(watchdog_thresh);
375 hw_nmi_watchdog_set_attr(wd_attr);
376
377 /* Try to register using hardware perf events */
374 event = perf_event_create_kernel_counter(wd_attr, cpu, NULL, watchdog_overflow_callback); 378 event = perf_event_create_kernel_counter(wd_attr, cpu, NULL, watchdog_overflow_callback);
375 if (!IS_ERR(event)) { 379 if (!IS_ERR(event)) {
376 printk(KERN_INFO "NMI watchdog enabled, takes one hw-pmu counter.\n"); 380 printk(KERN_INFO "NMI watchdog enabled, takes one hw-pmu counter.\n");