diff options
| author | Jacob Shin <jacob.shin@amd.com> | 2013-02-06 12:26:27 -0500 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2013-02-06 13:45:24 -0500 |
| commit | 4c1fd17a1cb32bc4f429c7a5ff9a91a3bffdb8fa (patch) | |
| tree | d6de83c171dba118665d840c0d8ead5f482c3ea7 | |
| parent | 9f19010af8c651879ac2c36f1a808a3a4419cd40 (diff) | |
perf/x86: Move MSR address offset calculation to architecture specific files
Move counter index to MSR address offset calculation to
architecture specific files. This prepares the way for
perf_event_amd to enable counter addresses that are not
contiguous -- for example AMD Family 15h processors have 6 core
performance counters starting at 0xc0010200 and 4 northbridge
performance counters starting at 0xc0010240.
Signed-off-by: Jacob Shin <jacob.shin@amd.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Cc: Stephane Eranian <eranian@google.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1360171589-6381-5-git-send-email-jacob.shin@amd.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event.h | 21 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event_amd.c | 42 |
2 files changed, 47 insertions, 16 deletions
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index 115c1ea97746..a7f06a90d2e7 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h | |||
| @@ -325,6 +325,7 @@ struct x86_pmu { | |||
| 325 | int (*schedule_events)(struct cpu_hw_events *cpuc, int n, int *assign); | 325 | int (*schedule_events)(struct cpu_hw_events *cpuc, int n, int *assign); |
| 326 | unsigned eventsel; | 326 | unsigned eventsel; |
| 327 | unsigned perfctr; | 327 | unsigned perfctr; |
| 328 | int (*addr_offset)(int index, bool eventsel); | ||
| 328 | u64 (*event_map)(int); | 329 | u64 (*event_map)(int); |
| 329 | int max_events; | 330 | int max_events; |
| 330 | int num_counters; | 331 | int num_counters; |
| @@ -446,28 +447,16 @@ extern u64 __read_mostly hw_cache_extra_regs | |||
| 446 | 447 | ||
| 447 | u64 x86_perf_event_update(struct perf_event *event); | 448 | u64 x86_perf_event_update(struct perf_event *event); |
| 448 | 449 | ||
| 449 | static inline int x86_pmu_addr_offset(int index) | ||
| 450 | { | ||
| 451 | int offset; | ||
| 452 | |||
| 453 | /* offset = X86_FEATURE_PERFCTR_CORE ? index << 1 : index */ | ||
| 454 | alternative_io(ASM_NOP2, | ||
| 455 | "shll $1, %%eax", | ||
| 456 | X86_FEATURE_PERFCTR_CORE, | ||
| 457 | "=a" (offset), | ||
| 458 | "a" (index)); | ||
| 459 | |||
| 460 | return offset; | ||
| 461 | } | ||
| 462 | |||
| 463 | static inline unsigned int x86_pmu_config_addr(int index) | 450 | static inline unsigned int x86_pmu_config_addr(int index) |
| 464 | { | 451 | { |
| 465 | return x86_pmu.eventsel + x86_pmu_addr_offset(index); | 452 | return x86_pmu.eventsel + (x86_pmu.addr_offset ? |
| 453 | x86_pmu.addr_offset(index, true) : index); | ||
| 466 | } | 454 | } |
| 467 | 455 | ||
| 468 | static inline unsigned int x86_pmu_event_addr(int index) | 456 | static inline unsigned int x86_pmu_event_addr(int index) |
| 469 | { | 457 | { |
| 470 | return x86_pmu.perfctr + x86_pmu_addr_offset(index); | 458 | return x86_pmu.perfctr + (x86_pmu.addr_offset ? |
| 459 | x86_pmu.addr_offset(index, false) : index); | ||
| 471 | } | 460 | } |
| 472 | 461 | ||
| 473 | int x86_setup_perfctr(struct perf_event *event); | 462 | int x86_setup_perfctr(struct perf_event *event); |
diff --git a/arch/x86/kernel/cpu/perf_event_amd.c b/arch/x86/kernel/cpu/perf_event_amd.c index aea8c2021f78..b60f31caeda0 100644 --- a/arch/x86/kernel/cpu/perf_event_amd.c +++ b/arch/x86/kernel/cpu/perf_event_amd.c | |||
| @@ -132,6 +132,47 @@ static u64 amd_pmu_event_map(int hw_event) | |||
| 132 | return amd_perfmon_event_map[hw_event]; | 132 | return amd_perfmon_event_map[hw_event]; |
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | /* | ||
| 136 | * Previously calculated offsets | ||
| 137 | */ | ||
| 138 | static unsigned int event_offsets[X86_PMC_IDX_MAX] __read_mostly; | ||
| 139 | static unsigned int count_offsets[X86_PMC_IDX_MAX] __read_mostly; | ||
| 140 | |||
| 141 | /* | ||
| 142 | * Legacy CPUs: | ||
| 143 | * 4 counters starting at 0xc0010000 each offset by 1 | ||
| 144 | * | ||
| 145 | * CPUs with core performance counter extensions: | ||
| 146 | * 6 counters starting at 0xc0010200 each offset by 2 | ||
| 147 | */ | ||
| 148 | static inline int amd_pmu_addr_offset(int index, bool eventsel) | ||
| 149 | { | ||
| 150 | int offset; | ||
| 151 | |||
| 152 | if (!index) | ||
| 153 | return index; | ||
| 154 | |||
| 155 | if (eventsel) | ||
| 156 | offset = event_offsets[index]; | ||
| 157 | else | ||
| 158 | offset = count_offsets[index]; | ||
| 159 | |||
| 160 | if (offset) | ||
| 161 | return offset; | ||
| 162 | |||
| 163 | if (!cpu_has_perfctr_core) | ||
| 164 | offset = index; | ||
| 165 | else | ||
| 166 | offset = index << 1; | ||
| 167 | |||
| 168 | if (eventsel) | ||
| 169 | event_offsets[index] = offset; | ||
| 170 | else | ||
| 171 | count_offsets[index] = offset; | ||
| 172 | |||
| 173 | return offset; | ||
| 174 | } | ||
| 175 | |||
| 135 | static int amd_pmu_hw_config(struct perf_event *event) | 176 | static int amd_pmu_hw_config(struct perf_event *event) |
| 136 | { | 177 | { |
| 137 | int ret; | 178 | int ret; |
| @@ -578,6 +619,7 @@ static __initconst const struct x86_pmu amd_pmu = { | |||
| 578 | .schedule_events = x86_schedule_events, | 619 | .schedule_events = x86_schedule_events, |
| 579 | .eventsel = MSR_K7_EVNTSEL0, | 620 | .eventsel = MSR_K7_EVNTSEL0, |
| 580 | .perfctr = MSR_K7_PERFCTR0, | 621 | .perfctr = MSR_K7_PERFCTR0, |
| 622 | .addr_offset = amd_pmu_addr_offset, | ||
| 581 | .event_map = amd_pmu_event_map, | 623 | .event_map = amd_pmu_event_map, |
| 582 | .max_events = ARRAY_SIZE(amd_perfmon_event_map), | 624 | .max_events = ARRAY_SIZE(amd_perfmon_event_map), |
| 583 | .num_counters = AMD64_NUM_COUNTERS, | 625 | .num_counters = AMD64_NUM_COUNTERS, |
