diff options
author | Robert Richter <robert.richter@amd.com> | 2009-05-25 09:10:32 -0400 |
---|---|---|
committer | Robert Richter <robert.richter@amd.com> | 2009-06-11 13:42:14 -0400 |
commit | 3370d358569755625aba4d9a846a040ce691d9ed (patch) | |
tree | 97b712208843a33dd29d1bfd9f90bc8aec30a595 /arch/x86/oprofile | |
parent | ef8828ddf828174785421af67c281144d4b8e796 (diff) |
x86/oprofile: replace macros to calculate control register
This patch introduces op_x86_get_ctrl() to calculate the value of the
performance control register. This is generic code usable for all
models. The event and reserved masks are model specific and stored in
struct op_x86_model_spec. 64 bit MSR functions are used now. The patch
removes many hard to read macros used for ctrl calculation.
The function op_x86_get_ctrl() is common code and the first step to
further merge performance counter implementations for x86 models.
Signed-off-by: Robert Richter <robert.richter@amd.com>
Diffstat (limited to 'arch/x86/oprofile')
-rw-r--r-- | arch/x86/oprofile/nmi_int.c | 20 | ||||
-rw-r--r-- | arch/x86/oprofile/op_model_amd.c | 41 | ||||
-rw-r--r-- | arch/x86/oprofile/op_model_ppro.c | 29 | ||||
-rw-r--r-- | arch/x86/oprofile/op_x86_model.h | 15 |
4 files changed, 60 insertions, 45 deletions
diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index c31f87bbf436..388ee15e0e42 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c | |||
@@ -31,6 +31,26 @@ static DEFINE_PER_CPU(unsigned long, saved_lvtpc); | |||
31 | /* 0 == registered but off, 1 == registered and on */ | 31 | /* 0 == registered but off, 1 == registered and on */ |
32 | static int nmi_enabled = 0; | 32 | static int nmi_enabled = 0; |
33 | 33 | ||
34 | /* common functions */ | ||
35 | |||
36 | u64 op_x86_get_ctrl(struct op_x86_model_spec const *model, | ||
37 | struct op_counter_config *counter_config) | ||
38 | { | ||
39 | u64 val = 0; | ||
40 | u16 event = (u16)counter_config->event; | ||
41 | |||
42 | val |= ARCH_PERFMON_EVENTSEL_INT; | ||
43 | val |= counter_config->user ? ARCH_PERFMON_EVENTSEL_USR : 0; | ||
44 | val |= counter_config->kernel ? ARCH_PERFMON_EVENTSEL_OS : 0; | ||
45 | val |= (counter_config->unit_mask & 0xFF) << 8; | ||
46 | event &= model->event_mask ? model->event_mask : 0xFF; | ||
47 | val |= event & 0xFF; | ||
48 | val |= (event & 0x0F00) << 24; | ||
49 | |||
50 | return val; | ||
51 | } | ||
52 | |||
53 | |||
34 | static int profile_exceptions_notify(struct notifier_block *self, | 54 | static int profile_exceptions_notify(struct notifier_block *self, |
35 | unsigned long val, void *data) | 55 | unsigned long val, void *data) |
36 | { | 56 | { |
diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 86e0a01ba125..2406ab863605 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c | |||
@@ -25,12 +25,11 @@ | |||
25 | 25 | ||
26 | #define NUM_COUNTERS 4 | 26 | #define NUM_COUNTERS 4 |
27 | #define NUM_CONTROLS 4 | 27 | #define NUM_CONTROLS 4 |
28 | #define OP_EVENT_MASK 0x0FFF | ||
29 | |||
30 | #define MSR_AMD_EVENTSEL_RESERVED ((0xFFFFFCF0ULL<<32)|(1ULL<<21)) | ||
28 | 31 | ||
29 | #define CTR_OVERFLOWED(n) (!((n) & (1U<<31))) | 32 | #define CTR_OVERFLOWED(n) (!((n) & (1U<<31))) |
30 | #define CTRL_CLEAR_LO(x) (x &= (1<<21)) | ||
31 | #define CTRL_CLEAR_HI(x) (x &= 0xfffffcf0) | ||
32 | #define CTRL_SET_EVENT_LOW(val, e) (val |= (e & 0xff)) | ||
33 | #define CTRL_SET_EVENT_HIGH(val, e) (val |= ((e >> 8) & 0xf)) | ||
34 | 33 | ||
35 | static unsigned long reset_value[NUM_COUNTERS]; | 34 | static unsigned long reset_value[NUM_COUNTERS]; |
36 | 35 | ||
@@ -84,21 +83,19 @@ static void op_amd_fill_in_addresses(struct op_msrs * const msrs) | |||
84 | } | 83 | } |
85 | } | 84 | } |
86 | 85 | ||
87 | |||
88 | static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, | 86 | static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, |
89 | struct op_msrs const * const msrs) | 87 | struct op_msrs const * const msrs) |
90 | { | 88 | { |
91 | unsigned int low, high; | 89 | u64 val; |
92 | int i; | 90 | int i; |
93 | 91 | ||
94 | /* clear all counters */ | 92 | /* clear all counters */ |
95 | for (i = 0 ; i < NUM_CONTROLS; ++i) { | 93 | for (i = 0 ; i < NUM_CONTROLS; ++i) { |
96 | if (unlikely(!CTRL_IS_RESERVED(msrs, i))) | 94 | if (unlikely(!CTRL_IS_RESERVED(msrs, i))) |
97 | continue; | 95 | continue; |
98 | rdmsr(msrs->controls[i].addr, low, high); | 96 | rdmsrl(msrs->controls[i].addr, val); |
99 | CTRL_CLEAR_LO(low); | 97 | val &= model->reserved; |
100 | CTRL_CLEAR_HI(high); | 98 | wrmsrl(msrs->controls[i].addr, val); |
101 | wrmsr(msrs->controls[i].addr, low, high); | ||
102 | } | 99 | } |
103 | 100 | ||
104 | /* avoid a false detection of ctr overflows in NMI handler */ | 101 | /* avoid a false detection of ctr overflows in NMI handler */ |
@@ -112,19 +109,11 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model, | |||
112 | for (i = 0; i < NUM_COUNTERS; ++i) { | 109 | for (i = 0; i < NUM_COUNTERS; ++i) { |
113 | if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs, i))) { | 110 | if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs, i))) { |
114 | reset_value[i] = counter_config[i].count; | 111 | reset_value[i] = counter_config[i].count; |
115 | |||
116 | wrmsr(msrs->counters[i].addr, -(unsigned int)counter_config[i].count, -1); | 112 | wrmsr(msrs->counters[i].addr, -(unsigned int)counter_config[i].count, -1); |
117 | 113 | rdmsrl(msrs->controls[i].addr, val); | |
118 | rdmsr(msrs->controls[i].addr, low, high); | 114 | val &= model->reserved; |
119 | CTRL_CLEAR_LO(low); | 115 | val |= op_x86_get_ctrl(model, &counter_config[i]); |
120 | CTRL_CLEAR_HI(high); | 116 | wrmsrl(msrs->controls[i].addr, val); |
121 | CTRL_SET_ENABLE(low); | ||
122 | CTRL_SET_USR(low, counter_config[i].user); | ||
123 | CTRL_SET_KERN(low, counter_config[i].kernel); | ||
124 | CTRL_SET_UM(low, counter_config[i].unit_mask); | ||
125 | CTRL_SET_EVENT_LOW(low, counter_config[i].event); | ||
126 | CTRL_SET_EVENT_HIGH(high, counter_config[i].event); | ||
127 | wrmsr(msrs->controls[i].addr, low, high); | ||
128 | } else { | 117 | } else { |
129 | reset_value[i] = 0; | 118 | reset_value[i] = 0; |
130 | } | 119 | } |
@@ -486,14 +475,16 @@ static void op_amd_exit(void) {} | |||
486 | #endif /* CONFIG_OPROFILE_IBS */ | 475 | #endif /* CONFIG_OPROFILE_IBS */ |
487 | 476 | ||
488 | struct op_x86_model_spec const op_amd_spec = { | 477 | struct op_x86_model_spec const op_amd_spec = { |
489 | .init = op_amd_init, | ||
490 | .exit = op_amd_exit, | ||
491 | .num_counters = NUM_COUNTERS, | 478 | .num_counters = NUM_COUNTERS, |
492 | .num_controls = NUM_CONTROLS, | 479 | .num_controls = NUM_CONTROLS, |
480 | .reserved = MSR_AMD_EVENTSEL_RESERVED, | ||
481 | .event_mask = OP_EVENT_MASK, | ||
482 | .init = op_amd_init, | ||
483 | .exit = op_amd_exit, | ||
493 | .fill_in_addresses = &op_amd_fill_in_addresses, | 484 | .fill_in_addresses = &op_amd_fill_in_addresses, |
494 | .setup_ctrs = &op_amd_setup_ctrs, | 485 | .setup_ctrs = &op_amd_setup_ctrs, |
495 | .check_ctrs = &op_amd_check_ctrs, | 486 | .check_ctrs = &op_amd_check_ctrs, |
496 | .start = &op_amd_start, | 487 | .start = &op_amd_start, |
497 | .stop = &op_amd_stop, | 488 | .stop = &op_amd_stop, |
498 | .shutdown = &op_amd_shutdown | 489 | .shutdown = &op_amd_shutdown, |
499 | }; | 490 | }; |
diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 40b44ee521d5..3092f998baf2 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c | |||
@@ -10,6 +10,7 @@ | |||
10 | * @author Philippe Elie | 10 | * @author Philippe Elie |
11 | * @author Graydon Hoare | 11 | * @author Graydon Hoare |
12 | * @author Andi Kleen | 12 | * @author Andi Kleen |
13 | * @author Robert Richter <robert.richter@amd.com> | ||
13 | */ | 14 | */ |
14 | 15 | ||
15 | #include <linux/oprofile.h> | 16 | #include <linux/oprofile.h> |
@@ -26,8 +27,8 @@ static int num_counters = 2; | |||
26 | static int counter_width = 32; | 27 | static int counter_width = 32; |
27 | 28 | ||
28 | #define CTR_OVERFLOWED(n) (!((n) & (1ULL<<(counter_width-1)))) | 29 | #define CTR_OVERFLOWED(n) (!((n) & (1ULL<<(counter_width-1)))) |
29 | #define CTRL_CLEAR(x) (x &= (1<<21)) | 30 | |
30 | #define CTRL_SET_EVENT(val, e) (val |= e) | 31 | #define MSR_PPRO_EVENTSEL_RESERVED ((0xFFFFFFFFULL<<32)|(1ULL<<21)) |
31 | 32 | ||
32 | static u64 *reset_value; | 33 | static u64 *reset_value; |
33 | 34 | ||
@@ -54,7 +55,7 @@ static void ppro_fill_in_addresses(struct op_msrs * const msrs) | |||
54 | static void ppro_setup_ctrs(struct op_x86_model_spec const *model, | 55 | static void ppro_setup_ctrs(struct op_x86_model_spec const *model, |
55 | struct op_msrs const * const msrs) | 56 | struct op_msrs const * const msrs) |
56 | { | 57 | { |
57 | unsigned int low, high; | 58 | u64 val; |
58 | int i; | 59 | int i; |
59 | 60 | ||
60 | if (!reset_value) { | 61 | if (!reset_value) { |
@@ -85,9 +86,9 @@ static void ppro_setup_ctrs(struct op_x86_model_spec const *model, | |||
85 | for (i = 0 ; i < num_counters; ++i) { | 86 | for (i = 0 ; i < num_counters; ++i) { |
86 | if (unlikely(!CTRL_IS_RESERVED(msrs, i))) | 87 | if (unlikely(!CTRL_IS_RESERVED(msrs, i))) |
87 | continue; | 88 | continue; |
88 | rdmsr(msrs->controls[i].addr, low, high); | 89 | rdmsrl(msrs->controls[i].addr, val); |
89 | CTRL_CLEAR(low); | 90 | val &= model->reserved; |
90 | wrmsr(msrs->controls[i].addr, low, high); | 91 | wrmsrl(msrs->controls[i].addr, val); |
91 | } | 92 | } |
92 | 93 | ||
93 | /* avoid a false detection of ctr overflows in NMI handler */ | 94 | /* avoid a false detection of ctr overflows in NMI handler */ |
@@ -101,17 +102,11 @@ static void ppro_setup_ctrs(struct op_x86_model_spec const *model, | |||
101 | for (i = 0; i < num_counters; ++i) { | 102 | for (i = 0; i < num_counters; ++i) { |
102 | if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs, i))) { | 103 | if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs, i))) { |
103 | reset_value[i] = counter_config[i].count; | 104 | reset_value[i] = counter_config[i].count; |
104 | |||
105 | wrmsrl(msrs->counters[i].addr, -reset_value[i]); | 105 | wrmsrl(msrs->counters[i].addr, -reset_value[i]); |
106 | 106 | rdmsrl(msrs->controls[i].addr, val); | |
107 | rdmsr(msrs->controls[i].addr, low, high); | 107 | val &= model->reserved; |
108 | CTRL_CLEAR(low); | 108 | val |= op_x86_get_ctrl(model, &counter_config[i]); |
109 | CTRL_SET_ENABLE(low); | 109 | wrmsrl(msrs->controls[i].addr, val); |
110 | CTRL_SET_USR(low, counter_config[i].user); | ||
111 | CTRL_SET_KERN(low, counter_config[i].kernel); | ||
112 | CTRL_SET_UM(low, counter_config[i].unit_mask); | ||
113 | CTRL_SET_EVENT(low, counter_config[i].event); | ||
114 | wrmsr(msrs->controls[i].addr, low, high); | ||
115 | } else { | 110 | } else { |
116 | reset_value[i] = 0; | 111 | reset_value[i] = 0; |
117 | } | 112 | } |
@@ -205,6 +200,7 @@ static void ppro_shutdown(struct op_msrs const * const msrs) | |||
205 | struct op_x86_model_spec const op_ppro_spec = { | 200 | struct op_x86_model_spec const op_ppro_spec = { |
206 | .num_counters = 2, | 201 | .num_counters = 2, |
207 | .num_controls = 2, | 202 | .num_controls = 2, |
203 | .reserved = MSR_PPRO_EVENTSEL_RESERVED, | ||
208 | .fill_in_addresses = &ppro_fill_in_addresses, | 204 | .fill_in_addresses = &ppro_fill_in_addresses, |
209 | .setup_ctrs = &ppro_setup_ctrs, | 205 | .setup_ctrs = &ppro_setup_ctrs, |
210 | .check_ctrs = &ppro_check_ctrs, | 206 | .check_ctrs = &ppro_check_ctrs, |
@@ -249,6 +245,7 @@ static int arch_perfmon_init(struct oprofile_operations *ignore) | |||
249 | } | 245 | } |
250 | 246 | ||
251 | struct op_x86_model_spec op_arch_perfmon_spec = { | 247 | struct op_x86_model_spec op_arch_perfmon_spec = { |
248 | .reserved = MSR_PPRO_EVENTSEL_RESERVED, | ||
252 | .init = &arch_perfmon_init, | 249 | .init = &arch_perfmon_init, |
253 | /* num_counters/num_controls filled in at runtime */ | 250 | /* num_counters/num_controls filled in at runtime */ |
254 | .fill_in_addresses = &ppro_fill_in_addresses, | 251 | .fill_in_addresses = &ppro_fill_in_addresses, |
diff --git a/arch/x86/oprofile/op_x86_model.h b/arch/x86/oprofile/op_x86_model.h index 6161c7f0e7fb..3220d4ce6322 100644 --- a/arch/x86/oprofile/op_x86_model.h +++ b/arch/x86/oprofile/op_x86_model.h | |||
@@ -6,21 +6,19 @@ | |||
6 | * @remark Read the file COPYING | 6 | * @remark Read the file COPYING |
7 | * | 7 | * |
8 | * @author Graydon Hoare | 8 | * @author Graydon Hoare |
9 | * @author Robert Richter <robert.richter@amd.com> | ||
9 | */ | 10 | */ |
10 | 11 | ||
11 | #ifndef OP_X86_MODEL_H | 12 | #ifndef OP_X86_MODEL_H |
12 | #define OP_X86_MODEL_H | 13 | #define OP_X86_MODEL_H |
13 | 14 | ||
15 | #include <asm/types.h> | ||
14 | #include <asm/intel_arch_perfmon.h> | 16 | #include <asm/intel_arch_perfmon.h> |
15 | 17 | ||
16 | #define CTR_IS_RESERVED(msrs, c) ((msrs)->counters[(c)].addr ? 1 : 0) | 18 | #define CTR_IS_RESERVED(msrs, c) ((msrs)->counters[(c)].addr ? 1 : 0) |
17 | #define CTRL_IS_RESERVED(msrs, c) ((msrs)->controls[(c)].addr ? 1 : 0) | 19 | #define CTRL_IS_RESERVED(msrs, c) ((msrs)->controls[(c)].addr ? 1 : 0) |
18 | #define CTRL_SET_ACTIVE(val) ((val) |= ARCH_PERFMON_EVENTSEL0_ENABLE) | 20 | #define CTRL_SET_ACTIVE(val) ((val) |= ARCH_PERFMON_EVENTSEL0_ENABLE) |
19 | #define CTRL_SET_ENABLE(val) ((val) |= ARCH_PERFMON_EVENTSEL_INT) | ||
20 | #define CTRL_SET_INACTIVE(val) ((val) &= ~ARCH_PERFMON_EVENTSEL0_ENABLE) | 21 | #define CTRL_SET_INACTIVE(val) ((val) &= ~ARCH_PERFMON_EVENTSEL0_ENABLE) |
21 | #define CTRL_SET_KERN(val, k) ((val) |= ((k) ? ARCH_PERFMON_EVENTSEL_OS : 0)) | ||
22 | #define CTRL_SET_USR(val, u) ((val) |= ((u) ? ARCH_PERFMON_EVENTSEL_USR : 0)) | ||
23 | #define CTRL_SET_UM(val, m) ((val) |= ((m) << 8)) | ||
24 | 22 | ||
25 | struct op_saved_msr { | 23 | struct op_saved_msr { |
26 | unsigned int high; | 24 | unsigned int high; |
@@ -39,12 +37,16 @@ struct op_msrs { | |||
39 | 37 | ||
40 | struct pt_regs; | 38 | struct pt_regs; |
41 | 39 | ||
40 | struct oprofile_operations; | ||
41 | |||
42 | /* The model vtable abstracts the differences between | 42 | /* The model vtable abstracts the differences between |
43 | * various x86 CPU models' perfctr support. | 43 | * various x86 CPU models' perfctr support. |
44 | */ | 44 | */ |
45 | struct op_x86_model_spec { | 45 | struct op_x86_model_spec { |
46 | unsigned int num_counters; | 46 | unsigned int num_counters; |
47 | unsigned int num_controls; | 47 | unsigned int num_controls; |
48 | u64 reserved; | ||
49 | u16 event_mask; | ||
48 | int (*init)(struct oprofile_operations *ops); | 50 | int (*init)(struct oprofile_operations *ops); |
49 | void (*exit)(void); | 51 | void (*exit)(void); |
50 | void (*fill_in_addresses)(struct op_msrs * const msrs); | 52 | void (*fill_in_addresses)(struct op_msrs * const msrs); |
@@ -57,6 +59,11 @@ struct op_x86_model_spec { | |||
57 | void (*shutdown)(struct op_msrs const * const msrs); | 59 | void (*shutdown)(struct op_msrs const * const msrs); |
58 | }; | 60 | }; |
59 | 61 | ||
62 | struct op_counter_config; | ||
63 | |||
64 | extern u64 op_x86_get_ctrl(struct op_x86_model_spec const *model, | ||
65 | struct op_counter_config *counter_config); | ||
66 | |||
60 | extern struct op_x86_model_spec const op_ppro_spec; | 67 | extern struct op_x86_model_spec const op_ppro_spec; |
61 | extern struct op_x86_model_spec const op_p4_spec; | 68 | extern struct op_x86_model_spec const op_p4_spec; |
62 | extern struct op_x86_model_spec const op_p4_ht2_spec; | 69 | extern struct op_x86_model_spec const op_p4_ht2_spec; |