Merge branch 'oprofile-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[pandora-kernel.git] / arch / x86 / oprofile / op_model_p4.c
1 /**
2  * @file op_model_p4.c
3  * P4 model-specific MSR operations
4  *
5  * @remark Copyright 2002 OProfile authors
6  * @remark Read the file COPYING
7  *
8  * @author Graydon Hoare
9  */
10
11 #include <linux/oprofile.h>
12 #include <linux/smp.h>
13 #include <linux/ptrace.h>
14 #include <linux/nmi.h>
15 #include <asm/msr.h>
16 #include <asm/fixmap.h>
17 #include <asm/apic.h>
18
19
20 #include "op_x86_model.h"
21 #include "op_counter.h"
22
23 #define NUM_EVENTS 39
24
25 #define NUM_COUNTERS_NON_HT 8
26 #define NUM_ESCRS_NON_HT 45
27 #define NUM_CCCRS_NON_HT 18
28 #define NUM_CONTROLS_NON_HT (NUM_ESCRS_NON_HT + NUM_CCCRS_NON_HT)
29
30 #define NUM_COUNTERS_HT2 4
31 #define NUM_ESCRS_HT2 23
32 #define NUM_CCCRS_HT2 9
33 #define NUM_CONTROLS_HT2 (NUM_ESCRS_HT2 + NUM_CCCRS_HT2)
34
35 #define OP_CTR_OVERFLOW                 (1ULL<<31)
36
37 static unsigned int num_counters = NUM_COUNTERS_NON_HT;
38 static unsigned int num_controls = NUM_CONTROLS_NON_HT;
39
40 /* this has to be checked dynamically since the
41    hyper-threadedness of a chip is discovered at
42    kernel boot-time. */
43 static inline void setup_num_counters(void)
44 {
45 #ifdef CONFIG_SMP
46         if (smp_num_siblings == 2) {
47                 num_counters = NUM_COUNTERS_HT2;
48                 num_controls = NUM_CONTROLS_HT2;
49         }
50 #endif
51 }
52
53 static int inline addr_increment(void)
54 {
55 #ifdef CONFIG_SMP
56         return smp_num_siblings == 2 ? 2 : 1;
57 #else
58         return 1;
59 #endif
60 }
61
62
63 /* tables to simulate simplified hardware view of p4 registers */
64 struct p4_counter_binding {
65         int virt_counter;
66         int counter_address;
67         int cccr_address;
68 };
69
70 struct p4_event_binding {
71         int escr_select;  /* value to put in CCCR */
72         int event_select; /* value to put in ESCR */
73         struct {
74                 int virt_counter; /* for this counter... */
75                 int escr_address; /* use this ESCR       */
76         } bindings[2];
77 };
78
79 /* nb: these CTR_* defines are a duplicate of defines in
80    event/i386.p4*events. */
81
82
83 #define CTR_BPU_0      (1 << 0)
84 #define CTR_MS_0       (1 << 1)
85 #define CTR_FLAME_0    (1 << 2)
86 #define CTR_IQ_4       (1 << 3)
87 #define CTR_BPU_2      (1 << 4)
88 #define CTR_MS_2       (1 << 5)
89 #define CTR_FLAME_2    (1 << 6)
90 #define CTR_IQ_5       (1 << 7)
91
92 static struct p4_counter_binding p4_counters[NUM_COUNTERS_NON_HT] = {
93         { CTR_BPU_0,   MSR_P4_BPU_PERFCTR0,   MSR_P4_BPU_CCCR0 },
94         { CTR_MS_0,    MSR_P4_MS_PERFCTR0,    MSR_P4_MS_CCCR0 },
95         { CTR_FLAME_0, MSR_P4_FLAME_PERFCTR0, MSR_P4_FLAME_CCCR0 },
96         { CTR_IQ_4,    MSR_P4_IQ_PERFCTR4,    MSR_P4_IQ_CCCR4 },
97         { CTR_BPU_2,   MSR_P4_BPU_PERFCTR2,   MSR_P4_BPU_CCCR2 },
98         { CTR_MS_2,    MSR_P4_MS_PERFCTR2,    MSR_P4_MS_CCCR2 },
99         { CTR_FLAME_2, MSR_P4_FLAME_PERFCTR2, MSR_P4_FLAME_CCCR2 },
100         { CTR_IQ_5,    MSR_P4_IQ_PERFCTR5,    MSR_P4_IQ_CCCR5 }
101 };
102
103 #define NUM_UNUSED_CCCRS (NUM_CCCRS_NON_HT - NUM_COUNTERS_NON_HT)
104
105 /* p4 event codes in libop/op_event.h are indices into this table. */
106
107 static struct p4_event_binding p4_events[NUM_EVENTS] = {
108
109         { /* BRANCH_RETIRED */
110                 0x05, 0x06,
111                 { {CTR_IQ_4, MSR_P4_CRU_ESCR2},
112                   {CTR_IQ_5, MSR_P4_CRU_ESCR3} }
113         },
114
115         { /* MISPRED_BRANCH_RETIRED */
116                 0x04, 0x03,
117                 { { CTR_IQ_4, MSR_P4_CRU_ESCR0},
118                   { CTR_IQ_5, MSR_P4_CRU_ESCR1} }
119         },
120
121         { /* TC_DELIVER_MODE */
122                 0x01, 0x01,
123                 { { CTR_MS_0, MSR_P4_TC_ESCR0},
124                   { CTR_MS_2, MSR_P4_TC_ESCR1} }
125         },
126
127         { /* BPU_FETCH_REQUEST */
128                 0x00, 0x03,
129                 { { CTR_BPU_0, MSR_P4_BPU_ESCR0},
130                   { CTR_BPU_2, MSR_P4_BPU_ESCR1} }
131         },
132
133         { /* ITLB_REFERENCE */
134                 0x03, 0x18,
135                 { { CTR_BPU_0, MSR_P4_ITLB_ESCR0},
136                   { CTR_BPU_2, MSR_P4_ITLB_ESCR1} }
137         },
138
139         { /* MEMORY_CANCEL */
140                 0x05, 0x02,
141                 { { CTR_FLAME_0, MSR_P4_DAC_ESCR0},
142                   { CTR_FLAME_2, MSR_P4_DAC_ESCR1} }
143         },
144
145         { /* MEMORY_COMPLETE */
146                 0x02, 0x08,
147                 { { CTR_FLAME_0, MSR_P4_SAAT_ESCR0},
148                   { CTR_FLAME_2, MSR_P4_SAAT_ESCR1} }
149         },
150
151         { /* LOAD_PORT_REPLAY */
152                 0x02, 0x04,
153                 { { CTR_FLAME_0, MSR_P4_SAAT_ESCR0},
154                   { CTR_FLAME_2, MSR_P4_SAAT_ESCR1} }
155         },
156
157         { /* STORE_PORT_REPLAY */
158                 0x02, 0x05,
159                 { { CTR_FLAME_0, MSR_P4_SAAT_ESCR0},
160                   { CTR_FLAME_2, MSR_P4_SAAT_ESCR1} }
161         },
162
163         { /* MOB_LOAD_REPLAY */
164                 0x02, 0x03,
165                 { { CTR_BPU_0, MSR_P4_MOB_ESCR0},
166                   { CTR_BPU_2, MSR_P4_MOB_ESCR1} }
167         },
168
169         { /* PAGE_WALK_TYPE */
170                 0x04, 0x01,
171                 { { CTR_BPU_0, MSR_P4_PMH_ESCR0},
172                   { CTR_BPU_2, MSR_P4_PMH_ESCR1} }
173         },
174
175         { /* BSQ_CACHE_REFERENCE */
176                 0x07, 0x0c,
177                 { { CTR_BPU_0, MSR_P4_BSU_ESCR0},
178                   { CTR_BPU_2, MSR_P4_BSU_ESCR1} }
179         },
180
181         { /* IOQ_ALLOCATION */
182                 0x06, 0x03,
183                 { { CTR_BPU_0, MSR_P4_FSB_ESCR0},
184                   { 0, 0 } }
185         },
186
187         { /* IOQ_ACTIVE_ENTRIES */
188                 0x06, 0x1a,
189                 { { CTR_BPU_2, MSR_P4_FSB_ESCR1},
190                   { 0, 0 } }
191         },
192
193         { /* FSB_DATA_ACTIVITY */
194                 0x06, 0x17,
195                 { { CTR_BPU_0, MSR_P4_FSB_ESCR0},
196                   { CTR_BPU_2, MSR_P4_FSB_ESCR1} }
197         },
198
199         { /* BSQ_ALLOCATION */
200                 0x07, 0x05,
201                 { { CTR_BPU_0, MSR_P4_BSU_ESCR0},
202                   { 0, 0 } }
203         },
204
205         { /* BSQ_ACTIVE_ENTRIES */
206                 0x07, 0x06,
207                 { { CTR_BPU_2, MSR_P4_BSU_ESCR1 /* guess */},
208                   { 0, 0 } }
209         },
210
211         { /* X87_ASSIST */
212                 0x05, 0x03,
213                 { { CTR_IQ_4, MSR_P4_CRU_ESCR2},
214                   { CTR_IQ_5, MSR_P4_CRU_ESCR3} }
215         },
216
217         { /* SSE_INPUT_ASSIST */
218                 0x01, 0x34,
219                 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
220                   { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
221         },
222
223         { /* PACKED_SP_UOP */
224                 0x01, 0x08,
225                 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
226                   { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
227         },
228
229         { /* PACKED_DP_UOP */
230                 0x01, 0x0c,
231                 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
232                   { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
233         },
234
235         { /* SCALAR_SP_UOP */
236                 0x01, 0x0a,
237                 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
238                   { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
239         },
240
241         { /* SCALAR_DP_UOP */
242                 0x01, 0x0e,
243                 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
244                   { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
245         },
246
247         { /* 64BIT_MMX_UOP */
248                 0x01, 0x02,
249                 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
250                   { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
251         },
252
253         { /* 128BIT_MMX_UOP */
254                 0x01, 0x1a,
255                 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
256                   { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
257         },
258
259         { /* X87_FP_UOP */
260                 0x01, 0x04,
261                 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
262                   { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
263         },
264
265         { /* X87_SIMD_MOVES_UOP */
266                 0x01, 0x2e,
267                 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
268                   { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
269         },
270
271         { /* MACHINE_CLEAR */
272                 0x05, 0x02,
273                 { { CTR_IQ_4, MSR_P4_CRU_ESCR2},
274                   { CTR_IQ_5, MSR_P4_CRU_ESCR3} }
275         },
276
277         { /* GLOBAL_POWER_EVENTS */
278                 0x06, 0x13 /* older manual says 0x05, newer 0x13 */,
279                 { { CTR_BPU_0, MSR_P4_FSB_ESCR0},
280                   { CTR_BPU_2, MSR_P4_FSB_ESCR1} }
281         },
282
283         { /* TC_MS_XFER */
284                 0x00, 0x05,
285                 { { CTR_MS_0, MSR_P4_MS_ESCR0},
286                   { CTR_MS_2, MSR_P4_MS_ESCR1} }
287         },
288
289         { /* UOP_QUEUE_WRITES */
290                 0x00, 0x09,
291                 { { CTR_MS_0, MSR_P4_MS_ESCR0},
292                   { CTR_MS_2, MSR_P4_MS_ESCR1} }
293         },
294
295         { /* FRONT_END_EVENT */
296                 0x05, 0x08,
297                 { { CTR_IQ_4, MSR_P4_CRU_ESCR2},
298                   { CTR_IQ_5, MSR_P4_CRU_ESCR3} }
299         },
300
301         { /* EXECUTION_EVENT */
302                 0x05, 0x0c,
303                 { { CTR_IQ_4, MSR_P4_CRU_ESCR2},
304                   { CTR_IQ_5, MSR_P4_CRU_ESCR3} }
305         },
306
307         { /* REPLAY_EVENT */
308                 0x05, 0x09,
309                 { { CTR_IQ_4, MSR_P4_CRU_ESCR2},
310                   { CTR_IQ_5, MSR_P4_CRU_ESCR3} }
311         },
312
313         { /* INSTR_RETIRED */
314                 0x04, 0x02,
315                 { { CTR_IQ_4, MSR_P4_CRU_ESCR0},
316                   { CTR_IQ_5, MSR_P4_CRU_ESCR1} }
317         },
318
319         { /* UOPS_RETIRED */
320                 0x04, 0x01,
321                 { { CTR_IQ_4, MSR_P4_CRU_ESCR0},
322                   { CTR_IQ_5, MSR_P4_CRU_ESCR1} }
323         },
324
325         { /* UOP_TYPE */
326                 0x02, 0x02,
327                 { { CTR_IQ_4, MSR_P4_RAT_ESCR0},
328                   { CTR_IQ_5, MSR_P4_RAT_ESCR1} }
329         },
330
331         { /* RETIRED_MISPRED_BRANCH_TYPE */
332                 0x02, 0x05,
333                 { { CTR_MS_0, MSR_P4_TBPU_ESCR0},
334                   { CTR_MS_2, MSR_P4_TBPU_ESCR1} }
335         },
336
337         { /* RETIRED_BRANCH_TYPE */
338                 0x02, 0x04,
339                 { { CTR_MS_0, MSR_P4_TBPU_ESCR0},
340                   { CTR_MS_2, MSR_P4_TBPU_ESCR1} }
341         }
342 };
343
344
345 #define MISC_PMC_ENABLED_P(x) ((x) & 1 << 7)
346
347 #define ESCR_RESERVED_BITS 0x80000003
348 #define ESCR_CLEAR(escr) ((escr) &= ESCR_RESERVED_BITS)
349 #define ESCR_SET_USR_0(escr, usr) ((escr) |= (((usr) & 1) << 2))
350 #define ESCR_SET_OS_0(escr, os) ((escr) |= (((os) & 1) << 3))
351 #define ESCR_SET_USR_1(escr, usr) ((escr) |= (((usr) & 1)))
352 #define ESCR_SET_OS_1(escr, os) ((escr) |= (((os) & 1) << 1))
353 #define ESCR_SET_EVENT_SELECT(escr, sel) ((escr) |= (((sel) & 0x3f) << 25))
354 #define ESCR_SET_EVENT_MASK(escr, mask) ((escr) |= (((mask) & 0xffff) << 9))
355
356 #define CCCR_RESERVED_BITS 0x38030FFF
357 #define CCCR_CLEAR(cccr) ((cccr) &= CCCR_RESERVED_BITS)
358 #define CCCR_SET_REQUIRED_BITS(cccr) ((cccr) |= 0x00030000)
359 #define CCCR_SET_ESCR_SELECT(cccr, sel) ((cccr) |= (((sel) & 0x07) << 13))
360 #define CCCR_SET_PMI_OVF_0(cccr) ((cccr) |= (1<<26))
361 #define CCCR_SET_PMI_OVF_1(cccr) ((cccr) |= (1<<27))
362 #define CCCR_SET_ENABLE(cccr) ((cccr) |= (1<<12))
363 #define CCCR_SET_DISABLE(cccr) ((cccr) &= ~(1<<12))
364 #define CCCR_OVF_P(cccr) ((cccr) & (1U<<31))
365 #define CCCR_CLEAR_OVF(cccr) ((cccr) &= (~(1U<<31)))
366
367
368 /* this assigns a "stagger" to the current CPU, which is used throughout
369    the code in this module as an extra array offset, to select the "even"
370    or "odd" part of all the divided resources. */
371 static unsigned int get_stagger(void)
372 {
373 #ifdef CONFIG_SMP
374         int cpu = smp_processor_id();
375         return cpu != cpumask_first(__get_cpu_var(cpu_sibling_map));
376 #endif
377         return 0;
378 }
379
380
381 /* finally, mediate access to a real hardware counter
382    by passing a "virtual" counter numer to this macro,
383    along with your stagger setting. */
384 #define VIRT_CTR(stagger, i) ((i) + ((num_counters) * (stagger)))
385
386 static unsigned long reset_value[NUM_COUNTERS_NON_HT];
387
388
389 static void p4_fill_in_addresses(struct op_msrs * const msrs)
390 {
391         unsigned int i;
392         unsigned int addr, cccraddr, stag;
393
394         setup_num_counters();
395         stag = get_stagger();
396
397         /* initialize some registers */
398         for (i = 0; i < num_counters; ++i)
399                 msrs->counters[i].addr = 0;
400         for (i = 0; i < num_controls; ++i)
401                 msrs->controls[i].addr = 0;
402
403         /* the counter & cccr registers we pay attention to */
404         for (i = 0; i < num_counters; ++i) {
405                 addr = p4_counters[VIRT_CTR(stag, i)].counter_address;
406                 cccraddr = p4_counters[VIRT_CTR(stag, i)].cccr_address;
407                 if (reserve_perfctr_nmi(addr)) {
408                         msrs->counters[i].addr = addr;
409                         msrs->controls[i].addr = cccraddr;
410                 }
411         }
412
413         /* 43 ESCR registers in three or four discontiguous group */
414         for (addr = MSR_P4_BSU_ESCR0 + stag;
415              addr < MSR_P4_IQ_ESCR0; ++i, addr += addr_increment()) {
416                 if (reserve_evntsel_nmi(addr))
417                         msrs->controls[i].addr = addr;
418         }
419
420         /* no IQ_ESCR0/1 on some models, we save a seconde time BSU_ESCR0/1
421          * to avoid special case in nmi_{save|restore}_registers() */
422         if (boot_cpu_data.x86_model >= 0x3) {
423                 for (addr = MSR_P4_BSU_ESCR0 + stag;
424                      addr <= MSR_P4_BSU_ESCR1; ++i, addr += addr_increment()) {
425                         if (reserve_evntsel_nmi(addr))
426                                 msrs->controls[i].addr = addr;
427                 }
428         } else {
429                 for (addr = MSR_P4_IQ_ESCR0 + stag;
430                      addr <= MSR_P4_IQ_ESCR1; ++i, addr += addr_increment()) {
431                         if (reserve_evntsel_nmi(addr))
432                                 msrs->controls[i].addr = addr;
433                 }
434         }
435
436         for (addr = MSR_P4_RAT_ESCR0 + stag;
437              addr <= MSR_P4_SSU_ESCR0; ++i, addr += addr_increment()) {
438                 if (reserve_evntsel_nmi(addr))
439                         msrs->controls[i].addr = addr;
440         }
441
442         for (addr = MSR_P4_MS_ESCR0 + stag;
443              addr <= MSR_P4_TC_ESCR1; ++i, addr += addr_increment()) {
444                 if (reserve_evntsel_nmi(addr))
445                         msrs->controls[i].addr = addr;
446         }
447
448         for (addr = MSR_P4_IX_ESCR0 + stag;
449              addr <= MSR_P4_CRU_ESCR3; ++i, addr += addr_increment()) {
450                 if (reserve_evntsel_nmi(addr))
451                         msrs->controls[i].addr = addr;
452         }
453
454         /* there are 2 remaining non-contiguously located ESCRs */
455
456         if (num_counters == NUM_COUNTERS_NON_HT) {
457                 /* standard non-HT CPUs handle both remaining ESCRs*/
458                 if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR5))
459                         msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
460                 if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR4))
461                         msrs->controls[i++].addr = MSR_P4_CRU_ESCR4;
462
463         } else if (stag == 0) {
464                 /* HT CPUs give the first remainder to the even thread, as
465                    the 32nd control register */
466                 if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR4))
467                         msrs->controls[i++].addr = MSR_P4_CRU_ESCR4;
468
469         } else {
470                 /* and two copies of the second to the odd thread,
471                    for the 22st and 23nd control registers */
472                 if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR5)) {
473                         msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
474                         msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
475                 }
476         }
477 }
478
479
480 static void pmc_setup_one_p4_counter(unsigned int ctr)
481 {
482         int i;
483         int const maxbind = 2;
484         unsigned int cccr = 0;
485         unsigned int escr = 0;
486         unsigned int high = 0;
487         unsigned int counter_bit;
488         struct p4_event_binding *ev = NULL;
489         unsigned int stag;
490
491         stag = get_stagger();
492
493         /* convert from counter *number* to counter *bit* */
494         counter_bit = 1 << VIRT_CTR(stag, ctr);
495
496         /* find our event binding structure. */
497         if (counter_config[ctr].event <= 0 || counter_config[ctr].event > NUM_EVENTS) {
498                 printk(KERN_ERR
499                        "oprofile: P4 event code 0x%lx out of range\n",
500                        counter_config[ctr].event);
501                 return;
502         }
503
504         ev = &(p4_events[counter_config[ctr].event - 1]);
505
506         for (i = 0; i < maxbind; i++) {
507                 if (ev->bindings[i].virt_counter & counter_bit) {
508
509                         /* modify ESCR */
510                         rdmsr(ev->bindings[i].escr_address, escr, high);
511                         ESCR_CLEAR(escr);
512                         if (stag == 0) {
513                                 ESCR_SET_USR_0(escr, counter_config[ctr].user);
514                                 ESCR_SET_OS_0(escr, counter_config[ctr].kernel);
515                         } else {
516                                 ESCR_SET_USR_1(escr, counter_config[ctr].user);
517                                 ESCR_SET_OS_1(escr, counter_config[ctr].kernel);
518                         }
519                         ESCR_SET_EVENT_SELECT(escr, ev->event_select);
520                         ESCR_SET_EVENT_MASK(escr, counter_config[ctr].unit_mask);
521                         wrmsr(ev->bindings[i].escr_address, escr, high);
522
523                         /* modify CCCR */
524                         rdmsr(p4_counters[VIRT_CTR(stag, ctr)].cccr_address,
525                               cccr, high);
526                         CCCR_CLEAR(cccr);
527                         CCCR_SET_REQUIRED_BITS(cccr);
528                         CCCR_SET_ESCR_SELECT(cccr, ev->escr_select);
529                         if (stag == 0)
530                                 CCCR_SET_PMI_OVF_0(cccr);
531                         else
532                                 CCCR_SET_PMI_OVF_1(cccr);
533                         wrmsr(p4_counters[VIRT_CTR(stag, ctr)].cccr_address,
534                               cccr, high);
535                         return;
536                 }
537         }
538
539         printk(KERN_ERR
540                "oprofile: P4 event code 0x%lx no binding, stag %d ctr %d\n",
541                counter_config[ctr].event, stag, ctr);
542 }
543
544
545 static void p4_setup_ctrs(struct op_x86_model_spec const *model,
546                           struct op_msrs const * const msrs)
547 {
548         unsigned int i;
549         unsigned int low, high;
550         unsigned int stag;
551
552         stag = get_stagger();
553
554         rdmsr(MSR_IA32_MISC_ENABLE, low, high);
555         if (!MISC_PMC_ENABLED_P(low)) {
556                 printk(KERN_ERR "oprofile: P4 PMC not available\n");
557                 return;
558         }
559
560         /* clear the cccrs we will use */
561         for (i = 0; i < num_counters; i++) {
562                 if (unlikely(!msrs->controls[i].addr))
563                         continue;
564                 rdmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
565                 CCCR_CLEAR(low);
566                 CCCR_SET_REQUIRED_BITS(low);
567                 wrmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
568         }
569
570         /* clear all escrs (including those outside our concern) */
571         for (i = num_counters; i < num_controls; i++) {
572                 if (unlikely(!msrs->controls[i].addr))
573                         continue;
574                 wrmsr(msrs->controls[i].addr, 0, 0);
575         }
576
577         /* setup all counters */
578         for (i = 0; i < num_counters; ++i) {
579                 if (counter_config[i].enabled && msrs->controls[i].addr) {
580                         reset_value[i] = counter_config[i].count;
581                         pmc_setup_one_p4_counter(i);
582                         wrmsrl(p4_counters[VIRT_CTR(stag, i)].counter_address,
583                                -(u64)counter_config[i].count);
584                 } else {
585                         reset_value[i] = 0;
586                 }
587         }
588 }
589
590
591 static int p4_check_ctrs(struct pt_regs * const regs,
592                          struct op_msrs const * const msrs)
593 {
594         unsigned long ctr, low, high, stag, real;
595         int i;
596
597         stag = get_stagger();
598
599         for (i = 0; i < num_counters; ++i) {
600
601                 if (!reset_value[i])
602                         continue;
603
604                 /*
605                  * there is some eccentricity in the hardware which
606                  * requires that we perform 2 extra corrections:
607                  *
608                  * - check both the CCCR:OVF flag for overflow and the
609                  *   counter high bit for un-flagged overflows.
610                  *
611                  * - write the counter back twice to ensure it gets
612                  *   updated properly.
613                  *
614                  * the former seems to be related to extra NMIs happening
615                  * during the current NMI; the latter is reported as errata
616                  * N15 in intel doc 249199-029, pentium 4 specification
617                  * update, though their suggested work-around does not
618                  * appear to solve the problem.
619                  */
620
621                 real = VIRT_CTR(stag, i);
622
623                 rdmsr(p4_counters[real].cccr_address, low, high);
624                 rdmsr(p4_counters[real].counter_address, ctr, high);
625                 if (CCCR_OVF_P(low) || !(ctr & OP_CTR_OVERFLOW)) {
626                         oprofile_add_sample(regs, i);
627                         wrmsrl(p4_counters[real].counter_address,
628                                -(u64)reset_value[i]);
629                         CCCR_CLEAR_OVF(low);
630                         wrmsr(p4_counters[real].cccr_address, low, high);
631                         wrmsrl(p4_counters[real].counter_address,
632                                -(u64)reset_value[i]);
633                 }
634         }
635
636         /* P4 quirk: you have to re-unmask the apic vector */
637         apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED);
638
639         /* See op_model_ppro.c */
640         return 1;
641 }
642
643
644 static void p4_start(struct op_msrs const * const msrs)
645 {
646         unsigned int low, high, stag;
647         int i;
648
649         stag = get_stagger();
650
651         for (i = 0; i < num_counters; ++i) {
652                 if (!reset_value[i])
653                         continue;
654                 rdmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
655                 CCCR_SET_ENABLE(low);
656                 wrmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
657         }
658 }
659
660
661 static void p4_stop(struct op_msrs const * const msrs)
662 {
663         unsigned int low, high, stag;
664         int i;
665
666         stag = get_stagger();
667
668         for (i = 0; i < num_counters; ++i) {
669                 if (!reset_value[i])
670                         continue;
671                 rdmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
672                 CCCR_SET_DISABLE(low);
673                 wrmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
674         }
675 }
676
677 static void p4_shutdown(struct op_msrs const * const msrs)
678 {
679         int i;
680
681         for (i = 0; i < num_counters; ++i) {
682                 if (msrs->counters[i].addr)
683                         release_perfctr_nmi(msrs->counters[i].addr);
684         }
685         /*
686          * some of the control registers are specially reserved in
687          * conjunction with the counter registers (hence the starting offset).
688          * This saves a few bits.
689          */
690         for (i = num_counters; i < num_controls; ++i) {
691                 if (msrs->controls[i].addr)
692                         release_evntsel_nmi(msrs->controls[i].addr);
693         }
694 }
695
696
697 #ifdef CONFIG_SMP
698 struct op_x86_model_spec op_p4_ht2_spec = {
699         .num_counters           = NUM_COUNTERS_HT2,
700         .num_controls           = NUM_CONTROLS_HT2,
701         .fill_in_addresses      = &p4_fill_in_addresses,
702         .setup_ctrs             = &p4_setup_ctrs,
703         .check_ctrs             = &p4_check_ctrs,
704         .start                  = &p4_start,
705         .stop                   = &p4_stop,
706         .shutdown               = &p4_shutdown
707 };
708 #endif
709
710 struct op_x86_model_spec op_p4_spec = {
711         .num_counters           = NUM_COUNTERS_NON_HT,
712         .num_controls           = NUM_CONTROLS_NON_HT,
713         .fill_in_addresses      = &p4_fill_in_addresses,
714         .setup_ctrs             = &p4_setup_ctrs,
715         .check_ctrs             = &p4_check_ctrs,
716         .start                  = &p4_start,
717         .stop                   = &p4_stop,
718         .shutdown               = &p4_shutdown
719 };