Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
perf_event_p6.c
Go to the documentation of this file.
1 #include <linux/perf_event.h>
2 #include <linux/types.h>
3 
4 #include "perf_event.h"
5 
6 /*
7  * Not sure about some of these
8  */
9 static const u64 p6_perfmon_event_map[] =
10 {
11  [PERF_COUNT_HW_CPU_CYCLES] = 0x0079, /* CPU_CLK_UNHALTED */
12  [PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0, /* INST_RETIRED */
13  [PERF_COUNT_HW_CACHE_REFERENCES] = 0x0f2e, /* L2_RQSTS:M:E:S:I */
14  [PERF_COUNT_HW_CACHE_MISSES] = 0x012e, /* L2_RQSTS:I */
15  [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x00c4, /* BR_INST_RETIRED */
16  [PERF_COUNT_HW_BRANCH_MISSES] = 0x00c5, /* BR_MISS_PRED_RETIRED */
17  [PERF_COUNT_HW_BUS_CYCLES] = 0x0062, /* BUS_DRDY_CLOCKS */
18  [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x00a2, /* RESOURCE_STALLS */
19 
20 };
21 
22 static __initconst u64 p6_hw_cache_event_ids
26 {
27  [ C(L1D) ] = {
28  [ C(OP_READ) ] = {
29  [ C(RESULT_ACCESS) ] = 0x0043, /* DATA_MEM_REFS */
30  [ C(RESULT_MISS) ] = 0x0045, /* DCU_LINES_IN */
31  },
32  [ C(OP_WRITE) ] = {
33  [ C(RESULT_ACCESS) ] = 0,
34  [ C(RESULT_MISS) ] = 0x0f29, /* L2_LD:M:E:S:I */
35  },
36  [ C(OP_PREFETCH) ] = {
37  [ C(RESULT_ACCESS) ] = 0,
38  [ C(RESULT_MISS) ] = 0,
39  },
40  },
41  [ C(L1I ) ] = {
42  [ C(OP_READ) ] = {
43  [ C(RESULT_ACCESS) ] = 0x0080, /* IFU_IFETCH */
44  [ C(RESULT_MISS) ] = 0x0f28, /* L2_IFETCH:M:E:S:I */
45  },
46  [ C(OP_WRITE) ] = {
47  [ C(RESULT_ACCESS) ] = -1,
48  [ C(RESULT_MISS) ] = -1,
49  },
50  [ C(OP_PREFETCH) ] = {
51  [ C(RESULT_ACCESS) ] = 0,
52  [ C(RESULT_MISS) ] = 0,
53  },
54  },
55  [ C(LL ) ] = {
56  [ C(OP_READ) ] = {
57  [ C(RESULT_ACCESS) ] = 0,
58  [ C(RESULT_MISS) ] = 0,
59  },
60  [ C(OP_WRITE) ] = {
61  [ C(RESULT_ACCESS) ] = 0,
62  [ C(RESULT_MISS) ] = 0x0025, /* L2_M_LINES_INM */
63  },
64  [ C(OP_PREFETCH) ] = {
65  [ C(RESULT_ACCESS) ] = 0,
66  [ C(RESULT_MISS) ] = 0,
67  },
68  },
69  [ C(DTLB) ] = {
70  [ C(OP_READ) ] = {
71  [ C(RESULT_ACCESS) ] = 0x0043, /* DATA_MEM_REFS */
72  [ C(RESULT_MISS) ] = 0,
73  },
74  [ C(OP_WRITE) ] = {
75  [ C(RESULT_ACCESS) ] = 0,
76  [ C(RESULT_MISS) ] = 0,
77  },
78  [ C(OP_PREFETCH) ] = {
79  [ C(RESULT_ACCESS) ] = 0,
80  [ C(RESULT_MISS) ] = 0,
81  },
82  },
83  [ C(ITLB) ] = {
84  [ C(OP_READ) ] = {
85  [ C(RESULT_ACCESS) ] = 0x0080, /* IFU_IFETCH */
86  [ C(RESULT_MISS) ] = 0x0085, /* ITLB_MISS */
87  },
88  [ C(OP_WRITE) ] = {
89  [ C(RESULT_ACCESS) ] = -1,
90  [ C(RESULT_MISS) ] = -1,
91  },
92  [ C(OP_PREFETCH) ] = {
93  [ C(RESULT_ACCESS) ] = -1,
94  [ C(RESULT_MISS) ] = -1,
95  },
96  },
97  [ C(BPU ) ] = {
98  [ C(OP_READ) ] = {
99  [ C(RESULT_ACCESS) ] = 0x00c4, /* BR_INST_RETIRED */
100  [ C(RESULT_MISS) ] = 0x00c5, /* BR_MISS_PRED_RETIRED */
101  },
102  [ C(OP_WRITE) ] = {
103  [ C(RESULT_ACCESS) ] = -1,
104  [ C(RESULT_MISS) ] = -1,
105  },
106  [ C(OP_PREFETCH) ] = {
107  [ C(RESULT_ACCESS) ] = -1,
108  [ C(RESULT_MISS) ] = -1,
109  },
110  },
111 };
112 
113 static u64 p6_pmu_event_map(int hw_event)
114 {
115  return p6_perfmon_event_map[hw_event];
116 }
117 
118 /*
119  * Event setting that is specified not to count anything.
120  * We use this to effectively disable a counter.
121  *
122  * L2_RQSTS with 0 MESI unit mask.
123  */
124 #define P6_NOP_EVENT 0x0000002EULL
125 
126 static struct event_constraint p6_event_constraints[] =
127 {
128  INTEL_EVENT_CONSTRAINT(0xc1, 0x1), /* FLOPS */
129  INTEL_EVENT_CONSTRAINT(0x10, 0x1), /* FP_COMP_OPS_EXE */
130  INTEL_EVENT_CONSTRAINT(0x11, 0x2), /* FP_ASSIST */
131  INTEL_EVENT_CONSTRAINT(0x12, 0x2), /* MUL */
132  INTEL_EVENT_CONSTRAINT(0x13, 0x2), /* DIV */
133  INTEL_EVENT_CONSTRAINT(0x14, 0x1), /* CYCLES_DIV_BUSY */
135 };
136 
137 static void p6_pmu_disable_all(void)
138 {
139  u64 val;
140 
141  /* p6 only has one enable register */
142  rdmsrl(MSR_P6_EVNTSEL0, val);
144  wrmsrl(MSR_P6_EVNTSEL0, val);
145 }
146 
147 static void p6_pmu_enable_all(int added)
148 {
149  unsigned long val;
150 
151  /* p6 only has one enable register */
152  rdmsrl(MSR_P6_EVNTSEL0, val);
154  wrmsrl(MSR_P6_EVNTSEL0, val);
155 }
156 
157 static inline void
158 p6_pmu_disable_event(struct perf_event *event)
159 {
160  struct hw_perf_event *hwc = &event->hw;
161  u64 val = P6_NOP_EVENT;
162 
163  (void)wrmsrl_safe(hwc->config_base, val);
164 }
165 
166 static void p6_pmu_enable_event(struct perf_event *event)
167 {
168  struct hw_perf_event *hwc = &event->hw;
169  u64 val;
170 
171  val = hwc->config;
172 
173  /*
174  * p6 only has a global event enable, set on PerfEvtSel0
175  * We "disable" events by programming P6_NOP_EVENT
176  * and we rely on p6_pmu_enable_all() being called
177  * to actually enable the events.
178  */
179 
180  (void)wrmsrl_safe(hwc->config_base, val);
181 }
182 
183 PMU_FORMAT_ATTR(event, "config:0-7" );
184 PMU_FORMAT_ATTR(umask, "config:8-15" );
185 PMU_FORMAT_ATTR(edge, "config:18" );
186 PMU_FORMAT_ATTR(pc, "config:19" );
187 PMU_FORMAT_ATTR(inv, "config:23" );
188 PMU_FORMAT_ATTR(cmask, "config:24-31" );
189 
190 static struct attribute *intel_p6_formats_attr[] = {
191  &format_attr_event.attr,
192  &format_attr_umask.attr,
193  &format_attr_edge.attr,
194  &format_attr_pc.attr,
195  &format_attr_inv.attr,
196  &format_attr_cmask.attr,
197  NULL,
198 };
199 
200 static __initconst const struct x86_pmu p6_pmu = {
201  .name = "p6",
202  .handle_irq = x86_pmu_handle_irq,
203  .disable_all = p6_pmu_disable_all,
204  .enable_all = p6_pmu_enable_all,
205  .enable = p6_pmu_enable_event,
206  .disable = p6_pmu_disable_event,
207  .hw_config = x86_pmu_hw_config,
208  .schedule_events = x86_schedule_events,
209  .eventsel = MSR_P6_EVNTSEL0,
210  .perfctr = MSR_P6_PERFCTR0,
211  .event_map = p6_pmu_event_map,
212  .max_events = ARRAY_SIZE(p6_perfmon_event_map),
213  .apic = 1,
214  .max_period = (1ULL << 31) - 1,
215  .version = 0,
216  .num_counters = 2,
217  /*
218  * Events have 40 bits implemented. However they are designed such
219  * that bits [32-39] are sign extensions of bit 31. As such the
220  * effective width of a event for P6-like PMU is 32 bits only.
221  *
222  * See IA-32 Intel Architecture Software developer manual Vol 3B
223  */
224  .cntval_bits = 32,
225  .cntval_mask = (1ULL << 32) - 1,
226  .get_event_constraints = x86_get_event_constraints,
227  .event_constraints = p6_event_constraints,
228 
229  .format_attrs = intel_p6_formats_attr,
230 };
231 
233 {
234  switch (boot_cpu_data.x86_model) {
235  case 1:
236  case 3: /* Pentium Pro */
237  case 5:
238  case 6: /* Pentium II */
239  case 7:
240  case 8:
241  case 11: /* Pentium III */
242  case 9:
243  case 13:
244  /* Pentium M */
245  break;
246  default:
247  pr_cont("unsupported p6 CPU model %d ",
248  boot_cpu_data.x86_model);
249  return -ENODEV;
250  }
251 
252  x86_pmu = p6_pmu;
253 
254  memcpy(hw_cache_event_ids, p6_hw_cache_event_ids,
255  sizeof(hw_cache_event_ids));
256 
257 
258  return 0;
259 }