aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/cpu/perf_event_amd_ibs.c
diff options
context:
space:
mode:
authorRobert Richter <robert.richter@amd.com>2011-12-15 11:56:36 -0500
committerIngo Molnar <mingo@elte.hu>2012-03-08 05:35:21 -0500
commit510419435c6948fb32959d691bf84eaba41ca474 (patch)
tree7ef449eebb611a41bdcbd987926fce9f33af7792 /arch/x86/kernel/cpu/perf_event_amd_ibs.c
parent3f33ab1c0c741bfab2138c14ba1918a7905a1e8b (diff)
perf/x86: Implement IBS event configuration
This patch implements perf configuration for AMD IBS. The IBS pmu is selected using the type attribute in sysfs. There are two types of ibs pmus, for instruction fetch (IBS_FETCH) and for instruction execution (IBS_OP): /sys/bus/event_source/devices/ibs_fetch/type /sys/bus/event_source/devices/ibs_op/type Except for the sample period IBS can only be set up with raw config values and raw data samples. The event attributes for the syscall should be programmed like this (IBS_FETCH): type = get_pmu_type("/sys/bus/event_source/devices/ibs_fetch/type"); memset(&attr, 0, sizeof(attr)); attr.type = type; attr.sample_type = PERF_SAMPLE_CPU | PERF_SAMPLE_RAW; attr.config = IBS_FETCH_CONFIG_DEFAULT; This implementation does not yet support 64 bit counters. It is limited to the hardware counter bit width which is 20 bits. 64 bit support can be added later. Signed-off-by: Robert Richter <robert.richter@amd.com> Acked-by: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Link: http://lkml.kernel.org/r/1323968199-9326-2-git-send-email-robert.richter@amd.com Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/cpu/perf_event_amd_ibs.c')
-rw-r--r--arch/x86/kernel/cpu/perf_event_amd_ibs.c92
1 files changed, 85 insertions, 7 deletions
diff --git a/arch/x86/kernel/cpu/perf_event_amd_ibs.c b/arch/x86/kernel/cpu/perf_event_amd_ibs.c
index 3b8a2d30d14e..36684eb248de 100644
--- a/arch/x86/kernel/cpu/perf_event_amd_ibs.c
+++ b/arch/x86/kernel/cpu/perf_event_amd_ibs.c
@@ -16,12 +16,67 @@ static u32 ibs_caps;
16 16
17#if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_AMD) 17#if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_AMD)
18 18
19static struct pmu perf_ibs; 19#define IBS_FETCH_CONFIG_MASK (IBS_FETCH_RAND_EN | IBS_FETCH_MAX_CNT)
20#define IBS_OP_CONFIG_MASK IBS_OP_MAX_CNT
21
22struct perf_ibs {
23 struct pmu pmu;
24 unsigned int msr;
25 u64 config_mask;
26 u64 cnt_mask;
27 u64 enable_mask;
28};
29
30static struct perf_ibs perf_ibs_fetch;
31static struct perf_ibs perf_ibs_op;
32
33static struct perf_ibs *get_ibs_pmu(int type)
34{
35 if (perf_ibs_fetch.pmu.type == type)
36 return &perf_ibs_fetch;
37 if (perf_ibs_op.pmu.type == type)
38 return &perf_ibs_op;
39 return NULL;
40}
20 41
21static int perf_ibs_init(struct perf_event *event) 42static int perf_ibs_init(struct perf_event *event)
22{ 43{
23 if (perf_ibs.type != event->attr.type) 44 struct hw_perf_event *hwc = &event->hw;
45 struct perf_ibs *perf_ibs;
46 u64 max_cnt, config;
47
48 perf_ibs = get_ibs_pmu(event->attr.type);
49 if (!perf_ibs)
24 return -ENOENT; 50 return -ENOENT;
51
52 config = event->attr.config;
53 if (config & ~perf_ibs->config_mask)
54 return -EINVAL;
55
56 if (hwc->sample_period) {
57 if (config & perf_ibs->cnt_mask)
58 /* raw max_cnt may not be set */
59 return -EINVAL;
60 if (hwc->sample_period & 0x0f)
61 /* lower 4 bits can not be set in ibs max cnt */
62 return -EINVAL;
63 max_cnt = hwc->sample_period >> 4;
64 if (max_cnt & ~perf_ibs->cnt_mask)
65 /* out of range */
66 return -EINVAL;
67 config |= max_cnt;
68 } else {
69 max_cnt = config & perf_ibs->cnt_mask;
70 event->attr.sample_period = max_cnt << 4;
71 hwc->sample_period = event->attr.sample_period;
72 }
73
74 if (!max_cnt)
75 return -EINVAL;
76
77 hwc->config_base = perf_ibs->msr;
78 hwc->config = config;
79
25 return 0; 80 return 0;
26} 81}
27 82
@@ -34,10 +89,32 @@ static void perf_ibs_del(struct perf_event *event, int flags)
34{ 89{
35} 90}
36 91
37static struct pmu perf_ibs = { 92static struct perf_ibs perf_ibs_fetch = {
38 .event_init= perf_ibs_init, 93 .pmu = {
39 .add= perf_ibs_add, 94 .task_ctx_nr = perf_invalid_context,
40 .del= perf_ibs_del, 95
96 .event_init = perf_ibs_init,
97 .add = perf_ibs_add,
98 .del = perf_ibs_del,
99 },
100 .msr = MSR_AMD64_IBSFETCHCTL,
101 .config_mask = IBS_FETCH_CONFIG_MASK,
102 .cnt_mask = IBS_FETCH_MAX_CNT,
103 .enable_mask = IBS_FETCH_ENABLE,
104};
105
106static struct perf_ibs perf_ibs_op = {
107 .pmu = {
108 .task_ctx_nr = perf_invalid_context,
109
110 .event_init = perf_ibs_init,
111 .add = perf_ibs_add,
112 .del = perf_ibs_del,
113 },
114 .msr = MSR_AMD64_IBSOPCTL,
115 .config_mask = IBS_OP_CONFIG_MASK,
116 .cnt_mask = IBS_OP_MAX_CNT,
117 .enable_mask = IBS_OP_ENABLE,
41}; 118};
42 119
43static __init int perf_event_ibs_init(void) 120static __init int perf_event_ibs_init(void)
@@ -45,7 +122,8 @@ static __init int perf_event_ibs_init(void)
45 if (!ibs_caps) 122 if (!ibs_caps)
46 return -ENODEV; /* ibs not supported by the cpu */ 123 return -ENODEV; /* ibs not supported by the cpu */
47 124
48 perf_pmu_register(&perf_ibs, "ibs", -1); 125 perf_pmu_register(&perf_ibs_fetch.pmu, "ibs_fetch", -1);
126 perf_pmu_register(&perf_ibs_op.pmu, "ibs_op", -1);
49 printk(KERN_INFO "perf: AMD IBS detected (0x%08x)\n", ibs_caps); 127 printk(KERN_INFO "perf: AMD IBS detected (0x%08x)\n", ibs_caps);
50 128
51 return 0; 129 return 0;