Linux-2.6.12-rc2
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / arch / i386 / oprofile / op_model_p4.c
blobac8a066035c24a1f9a9cc3f3d63e57ce29eee33d
1 /**
2 * @file op_model_p4.c
3 * P4 model-specific MSR operations
5 * @remark Copyright 2002 OProfile authors
6 * @remark Read the file COPYING
8 * @author Graydon Hoare
9 */
11 #include <linux/oprofile.h>
12 #include <linux/smp.h>
13 #include <asm/msr.h>
14 #include <asm/ptrace.h>
15 #include <asm/fixmap.h>
16 #include <asm/apic.h>
18 #include "op_x86_model.h"
19 #include "op_counter.h"
21 #define NUM_EVENTS 39
23 #define NUM_COUNTERS_NON_HT 8
24 #define NUM_ESCRS_NON_HT 45
25 #define NUM_CCCRS_NON_HT 18
26 #define NUM_CONTROLS_NON_HT (NUM_ESCRS_NON_HT + NUM_CCCRS_NON_HT)
28 #define NUM_COUNTERS_HT2 4
29 #define NUM_ESCRS_HT2 23
30 #define NUM_CCCRS_HT2 9
31 #define NUM_CONTROLS_HT2 (NUM_ESCRS_HT2 + NUM_CCCRS_HT2)
33 static unsigned int num_counters = NUM_COUNTERS_NON_HT;
36 /* this has to be checked dynamically since the
37 hyper-threadedness of a chip is discovered at
38 kernel boot-time. */
39 static inline void setup_num_counters(void)
41 #ifdef CONFIG_SMP
42 if (smp_num_siblings == 2)
43 num_counters = NUM_COUNTERS_HT2;
44 #endif
47 static int inline addr_increment(void)
49 #ifdef CONFIG_SMP
50 return smp_num_siblings == 2 ? 2 : 1;
51 #else
52 return 1;
53 #endif
57 /* tables to simulate simplified hardware view of p4 registers */
58 struct p4_counter_binding {
59 int virt_counter;
60 int counter_address;
61 int cccr_address;
64 struct p4_event_binding {
65 int escr_select; /* value to put in CCCR */
66 int event_select; /* value to put in ESCR */
67 struct {
68 int virt_counter; /* for this counter... */
69 int escr_address; /* use this ESCR */
70 } bindings[2];
73 /* nb: these CTR_* defines are a duplicate of defines in
74 event/i386.p4*events. */
77 #define CTR_BPU_0 (1 << 0)
78 #define CTR_MS_0 (1 << 1)
79 #define CTR_FLAME_0 (1 << 2)
80 #define CTR_IQ_4 (1 << 3)
81 #define CTR_BPU_2 (1 << 4)
82 #define CTR_MS_2 (1 << 5)
83 #define CTR_FLAME_2 (1 << 6)
84 #define CTR_IQ_5 (1 << 7)
86 static struct p4_counter_binding p4_counters [NUM_COUNTERS_NON_HT] = {
87 { CTR_BPU_0, MSR_P4_BPU_PERFCTR0, MSR_P4_BPU_CCCR0 },
88 { CTR_MS_0, MSR_P4_MS_PERFCTR0, MSR_P4_MS_CCCR0 },
89 { CTR_FLAME_0, MSR_P4_FLAME_PERFCTR0, MSR_P4_FLAME_CCCR0 },
90 { CTR_IQ_4, MSR_P4_IQ_PERFCTR4, MSR_P4_IQ_CCCR4 },
91 { CTR_BPU_2, MSR_P4_BPU_PERFCTR2, MSR_P4_BPU_CCCR2 },
92 { CTR_MS_2, MSR_P4_MS_PERFCTR2, MSR_P4_MS_CCCR2 },
93 { CTR_FLAME_2, MSR_P4_FLAME_PERFCTR2, MSR_P4_FLAME_CCCR2 },
94 { CTR_IQ_5, MSR_P4_IQ_PERFCTR5, MSR_P4_IQ_CCCR5 }
97 #define NUM_UNUSED_CCCRS NUM_CCCRS_NON_HT - NUM_COUNTERS_NON_HT
99 /* All cccr we don't use. */
100 static int p4_unused_cccr[NUM_UNUSED_CCCRS] = {
101 MSR_P4_BPU_CCCR1, MSR_P4_BPU_CCCR3,
102 MSR_P4_MS_CCCR1, MSR_P4_MS_CCCR3,
103 MSR_P4_FLAME_CCCR1, MSR_P4_FLAME_CCCR3,
104 MSR_P4_IQ_CCCR0, MSR_P4_IQ_CCCR1,
105 MSR_P4_IQ_CCCR2, MSR_P4_IQ_CCCR3
108 /* p4 event codes in libop/op_event.h are indices into this table. */
110 static struct p4_event_binding p4_events[NUM_EVENTS] = {
112 { /* BRANCH_RETIRED */
113 0x05, 0x06,
114 { {CTR_IQ_4, MSR_P4_CRU_ESCR2},
115 {CTR_IQ_5, MSR_P4_CRU_ESCR3} }
118 { /* MISPRED_BRANCH_RETIRED */
119 0x04, 0x03,
120 { { CTR_IQ_4, MSR_P4_CRU_ESCR0},
121 { CTR_IQ_5, MSR_P4_CRU_ESCR1} }
124 { /* TC_DELIVER_MODE */
125 0x01, 0x01,
126 { { CTR_MS_0, MSR_P4_TC_ESCR0},
127 { CTR_MS_2, MSR_P4_TC_ESCR1} }
130 { /* BPU_FETCH_REQUEST */
131 0x00, 0x03,
132 { { CTR_BPU_0, MSR_P4_BPU_ESCR0},
133 { CTR_BPU_2, MSR_P4_BPU_ESCR1} }
136 { /* ITLB_REFERENCE */
137 0x03, 0x18,
138 { { CTR_BPU_0, MSR_P4_ITLB_ESCR0},
139 { CTR_BPU_2, MSR_P4_ITLB_ESCR1} }
142 { /* MEMORY_CANCEL */
143 0x05, 0x02,
144 { { CTR_FLAME_0, MSR_P4_DAC_ESCR0},
145 { CTR_FLAME_2, MSR_P4_DAC_ESCR1} }
148 { /* MEMORY_COMPLETE */
149 0x02, 0x08,
150 { { CTR_FLAME_0, MSR_P4_SAAT_ESCR0},
151 { CTR_FLAME_2, MSR_P4_SAAT_ESCR1} }
154 { /* LOAD_PORT_REPLAY */
155 0x02, 0x04,
156 { { CTR_FLAME_0, MSR_P4_SAAT_ESCR0},
157 { CTR_FLAME_2, MSR_P4_SAAT_ESCR1} }
160 { /* STORE_PORT_REPLAY */
161 0x02, 0x05,
162 { { CTR_FLAME_0, MSR_P4_SAAT_ESCR0},
163 { CTR_FLAME_2, MSR_P4_SAAT_ESCR1} }
166 { /* MOB_LOAD_REPLAY */
167 0x02, 0x03,
168 { { CTR_BPU_0, MSR_P4_MOB_ESCR0},
169 { CTR_BPU_2, MSR_P4_MOB_ESCR1} }
172 { /* PAGE_WALK_TYPE */
173 0x04, 0x01,
174 { { CTR_BPU_0, MSR_P4_PMH_ESCR0},
175 { CTR_BPU_2, MSR_P4_PMH_ESCR1} }
178 { /* BSQ_CACHE_REFERENCE */
179 0x07, 0x0c,
180 { { CTR_BPU_0, MSR_P4_BSU_ESCR0},
181 { CTR_BPU_2, MSR_P4_BSU_ESCR1} }
184 { /* IOQ_ALLOCATION */
185 0x06, 0x03,
186 { { CTR_BPU_0, MSR_P4_FSB_ESCR0},
187 { 0, 0 } }
190 { /* IOQ_ACTIVE_ENTRIES */
191 0x06, 0x1a,
192 { { CTR_BPU_2, MSR_P4_FSB_ESCR1},
193 { 0, 0 } }
196 { /* FSB_DATA_ACTIVITY */
197 0x06, 0x17,
198 { { CTR_BPU_0, MSR_P4_FSB_ESCR0},
199 { CTR_BPU_2, MSR_P4_FSB_ESCR1} }
202 { /* BSQ_ALLOCATION */
203 0x07, 0x05,
204 { { CTR_BPU_0, MSR_P4_BSU_ESCR0},
205 { 0, 0 } }
208 { /* BSQ_ACTIVE_ENTRIES */
209 0x07, 0x06,
210 { { CTR_BPU_2, MSR_P4_BSU_ESCR1 /* guess */},
211 { 0, 0 } }
214 { /* X87_ASSIST */
215 0x05, 0x03,
216 { { CTR_IQ_4, MSR_P4_CRU_ESCR2},
217 { CTR_IQ_5, MSR_P4_CRU_ESCR3} }
220 { /* SSE_INPUT_ASSIST */
221 0x01, 0x34,
222 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
223 { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
226 { /* PACKED_SP_UOP */
227 0x01, 0x08,
228 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
229 { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
232 { /* PACKED_DP_UOP */
233 0x01, 0x0c,
234 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
235 { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
238 { /* SCALAR_SP_UOP */
239 0x01, 0x0a,
240 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
241 { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
244 { /* SCALAR_DP_UOP */
245 0x01, 0x0e,
246 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
247 { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
250 { /* 64BIT_MMX_UOP */
251 0x01, 0x02,
252 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
253 { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
256 { /* 128BIT_MMX_UOP */
257 0x01, 0x1a,
258 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
259 { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
262 { /* X87_FP_UOP */
263 0x01, 0x04,
264 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
265 { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
268 { /* X87_SIMD_MOVES_UOP */
269 0x01, 0x2e,
270 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
271 { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
274 { /* MACHINE_CLEAR */
275 0x05, 0x02,
276 { { CTR_IQ_4, MSR_P4_CRU_ESCR2},
277 { CTR_IQ_5, MSR_P4_CRU_ESCR3} }
280 { /* GLOBAL_POWER_EVENTS */
281 0x06, 0x13 /* older manual says 0x05, newer 0x13 */,
282 { { CTR_BPU_0, MSR_P4_FSB_ESCR0},
283 { CTR_BPU_2, MSR_P4_FSB_ESCR1} }
286 { /* TC_MS_XFER */
287 0x00, 0x05,
288 { { CTR_MS_0, MSR_P4_MS_ESCR0},
289 { CTR_MS_2, MSR_P4_MS_ESCR1} }
292 { /* UOP_QUEUE_WRITES */
293 0x00, 0x09,
294 { { CTR_MS_0, MSR_P4_MS_ESCR0},
295 { CTR_MS_2, MSR_P4_MS_ESCR1} }
298 { /* FRONT_END_EVENT */
299 0x05, 0x08,
300 { { CTR_IQ_4, MSR_P4_CRU_ESCR2},
301 { CTR_IQ_5, MSR_P4_CRU_ESCR3} }
304 { /* EXECUTION_EVENT */
305 0x05, 0x0c,
306 { { CTR_IQ_4, MSR_P4_CRU_ESCR2},
307 { CTR_IQ_5, MSR_P4_CRU_ESCR3} }
310 { /* REPLAY_EVENT */
311 0x05, 0x09,
312 { { CTR_IQ_4, MSR_P4_CRU_ESCR2},
313 { CTR_IQ_5, MSR_P4_CRU_ESCR3} }
316 { /* INSTR_RETIRED */
317 0x04, 0x02,
318 { { CTR_IQ_4, MSR_P4_CRU_ESCR0},
319 { CTR_IQ_5, MSR_P4_CRU_ESCR1} }
322 { /* UOPS_RETIRED */
323 0x04, 0x01,
324 { { CTR_IQ_4, MSR_P4_CRU_ESCR0},
325 { CTR_IQ_5, MSR_P4_CRU_ESCR1} }
328 { /* UOP_TYPE */
329 0x02, 0x02,
330 { { CTR_IQ_4, MSR_P4_RAT_ESCR0},
331 { CTR_IQ_5, MSR_P4_RAT_ESCR1} }
334 { /* RETIRED_MISPRED_BRANCH_TYPE */
335 0x02, 0x05,
336 { { CTR_MS_0, MSR_P4_TBPU_ESCR0},
337 { CTR_MS_2, MSR_P4_TBPU_ESCR1} }
340 { /* RETIRED_BRANCH_TYPE */
341 0x02, 0x04,
342 { { CTR_MS_0, MSR_P4_TBPU_ESCR0},
343 { CTR_MS_2, MSR_P4_TBPU_ESCR1} }
348 #define MISC_PMC_ENABLED_P(x) ((x) & 1 << 7)
350 #define ESCR_RESERVED_BITS 0x80000003
351 #define ESCR_CLEAR(escr) ((escr) &= ESCR_RESERVED_BITS)
352 #define ESCR_SET_USR_0(escr, usr) ((escr) |= (((usr) & 1) << 2))
353 #define ESCR_SET_OS_0(escr, os) ((escr) |= (((os) & 1) << 3))
354 #define ESCR_SET_USR_1(escr, usr) ((escr) |= (((usr) & 1)))
355 #define ESCR_SET_OS_1(escr, os) ((escr) |= (((os) & 1) << 1))
356 #define ESCR_SET_EVENT_SELECT(escr, sel) ((escr) |= (((sel) & 0x3f) << 25))
357 #define ESCR_SET_EVENT_MASK(escr, mask) ((escr) |= (((mask) & 0xffff) << 9))
358 #define ESCR_READ(escr,high,ev,i) do {rdmsr(ev->bindings[(i)].escr_address, (escr), (high));} while (0)
359 #define ESCR_WRITE(escr,high,ev,i) do {wrmsr(ev->bindings[(i)].escr_address, (escr), (high));} while (0)
361 #define CCCR_RESERVED_BITS 0x38030FFF
362 #define CCCR_CLEAR(cccr) ((cccr) &= CCCR_RESERVED_BITS)
363 #define CCCR_SET_REQUIRED_BITS(cccr) ((cccr) |= 0x00030000)
364 #define CCCR_SET_ESCR_SELECT(cccr, sel) ((cccr) |= (((sel) & 0x07) << 13))
365 #define CCCR_SET_PMI_OVF_0(cccr) ((cccr) |= (1<<26))
366 #define CCCR_SET_PMI_OVF_1(cccr) ((cccr) |= (1<<27))
367 #define CCCR_SET_ENABLE(cccr) ((cccr) |= (1<<12))
368 #define CCCR_SET_DISABLE(cccr) ((cccr) &= ~(1<<12))
369 #define CCCR_READ(low, high, i) do {rdmsr(p4_counters[(i)].cccr_address, (low), (high));} while (0)
370 #define CCCR_WRITE(low, high, i) do {wrmsr(p4_counters[(i)].cccr_address, (low), (high));} while (0)
371 #define CCCR_OVF_P(cccr) ((cccr) & (1U<<31))
372 #define CCCR_CLEAR_OVF(cccr) ((cccr) &= (~(1U<<31)))
374 #define CTR_READ(l,h,i) do {rdmsr(p4_counters[(i)].counter_address, (l), (h));} while (0)
375 #define CTR_WRITE(l,i) do {wrmsr(p4_counters[(i)].counter_address, -(u32)(l), -1);} while (0)
376 #define CTR_OVERFLOW_P(ctr) (!((ctr) & 0x80000000))
379 /* this assigns a "stagger" to the current CPU, which is used throughout
380 the code in this module as an extra array offset, to select the "even"
381 or "odd" part of all the divided resources. */
382 static unsigned int get_stagger(void)
384 #ifdef CONFIG_SMP
385 int cpu = smp_processor_id();
386 return (cpu != first_cpu(cpu_sibling_map[cpu]));
387 #endif
388 return 0;
392 /* finally, mediate access to a real hardware counter
393 by passing a "virtual" counter numer to this macro,
394 along with your stagger setting. */
395 #define VIRT_CTR(stagger, i) ((i) + ((num_counters) * (stagger)))
397 static unsigned long reset_value[NUM_COUNTERS_NON_HT];
400 static void p4_fill_in_addresses(struct op_msrs * const msrs)
402 unsigned int i;
403 unsigned int addr, stag;
405 setup_num_counters();
406 stag = get_stagger();
408 /* the counter registers we pay attention to */
409 for (i = 0; i < num_counters; ++i) {
410 msrs->counters[i].addr =
411 p4_counters[VIRT_CTR(stag, i)].counter_address;
414 /* FIXME: bad feeling, we don't save the 10 counters we don't use. */
416 /* 18 CCCR registers */
417 for (i = 0, addr = MSR_P4_BPU_CCCR0 + stag;
418 addr <= MSR_P4_IQ_CCCR5; ++i, addr += addr_increment()) {
419 msrs->controls[i].addr = addr;
422 /* 43 ESCR registers in three or four discontiguous group */
423 for (addr = MSR_P4_BSU_ESCR0 + stag;
424 addr < MSR_P4_IQ_ESCR0; ++i, addr += addr_increment()) {
425 msrs->controls[i].addr = addr;
428 /* no IQ_ESCR0/1 on some models, we save a seconde time BSU_ESCR0/1
429 * to avoid special case in nmi_{save|restore}_registers() */
430 if (boot_cpu_data.x86_model >= 0x3) {
431 for (addr = MSR_P4_BSU_ESCR0 + stag;
432 addr <= MSR_P4_BSU_ESCR1; ++i, addr += addr_increment()) {
433 msrs->controls[i].addr = addr;
435 } else {
436 for (addr = MSR_P4_IQ_ESCR0 + stag;
437 addr <= MSR_P4_IQ_ESCR1; ++i, addr += addr_increment()) {
438 msrs->controls[i].addr = addr;
442 for (addr = MSR_P4_RAT_ESCR0 + stag;
443 addr <= MSR_P4_SSU_ESCR0; ++i, addr += addr_increment()) {
444 msrs->controls[i].addr = addr;
447 for (addr = MSR_P4_MS_ESCR0 + stag;
448 addr <= MSR_P4_TC_ESCR1; ++i, addr += addr_increment()) {
449 msrs->controls[i].addr = addr;
452 for (addr = MSR_P4_IX_ESCR0 + stag;
453 addr <= MSR_P4_CRU_ESCR3; ++i, addr += addr_increment()) {
454 msrs->controls[i].addr = addr;
457 /* there are 2 remaining non-contiguously located ESCRs */
459 if (num_counters == NUM_COUNTERS_NON_HT) {
460 /* standard non-HT CPUs handle both remaining ESCRs*/
461 msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
462 msrs->controls[i++].addr = MSR_P4_CRU_ESCR4;
464 } else if (stag == 0) {
465 /* HT CPUs give the first remainder to the even thread, as
466 the 32nd control register */
467 msrs->controls[i++].addr = MSR_P4_CRU_ESCR4;
469 } else {
470 /* and two copies of the second to the odd thread,
471 for the 22st and 23nd control registers */
472 msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
473 msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
478 static void pmc_setup_one_p4_counter(unsigned int ctr)
480 int i;
481 int const maxbind = 2;
482 unsigned int cccr = 0;
483 unsigned int escr = 0;
484 unsigned int high = 0;
485 unsigned int counter_bit;
486 struct p4_event_binding *ev = NULL;
487 unsigned int stag;
489 stag = get_stagger();
491 /* convert from counter *number* to counter *bit* */
492 counter_bit = 1 << VIRT_CTR(stag, ctr);
494 /* find our event binding structure. */
495 if (counter_config[ctr].event <= 0 || counter_config[ctr].event > NUM_EVENTS) {
496 printk(KERN_ERR
497 "oprofile: P4 event code 0x%lx out of range\n",
498 counter_config[ctr].event);
499 return;
502 ev = &(p4_events[counter_config[ctr].event - 1]);
504 for (i = 0; i < maxbind; i++) {
505 if (ev->bindings[i].virt_counter & counter_bit) {
507 /* modify ESCR */
508 ESCR_READ(escr, high, ev, i);
509 ESCR_CLEAR(escr);
510 if (stag == 0) {
511 ESCR_SET_USR_0(escr, counter_config[ctr].user);
512 ESCR_SET_OS_0(escr, counter_config[ctr].kernel);
513 } else {
514 ESCR_SET_USR_1(escr, counter_config[ctr].user);
515 ESCR_SET_OS_1(escr, counter_config[ctr].kernel);
517 ESCR_SET_EVENT_SELECT(escr, ev->event_select);
518 ESCR_SET_EVENT_MASK(escr, counter_config[ctr].unit_mask);
519 ESCR_WRITE(escr, high, ev, i);
521 /* modify CCCR */
522 CCCR_READ(cccr, high, VIRT_CTR(stag, ctr));
523 CCCR_CLEAR(cccr);
524 CCCR_SET_REQUIRED_BITS(cccr);
525 CCCR_SET_ESCR_SELECT(cccr, ev->escr_select);
526 if (stag == 0) {
527 CCCR_SET_PMI_OVF_0(cccr);
528 } else {
529 CCCR_SET_PMI_OVF_1(cccr);
531 CCCR_WRITE(cccr, high, VIRT_CTR(stag, ctr));
532 return;
536 printk(KERN_ERR
537 "oprofile: P4 event code 0x%lx no binding, stag %d ctr %d\n",
538 counter_config[ctr].event, stag, ctr);
542 static void p4_setup_ctrs(struct op_msrs const * const msrs)
544 unsigned int i;
545 unsigned int low, high;
546 unsigned int addr;
547 unsigned int stag;
549 stag = get_stagger();
551 rdmsr(MSR_IA32_MISC_ENABLE, low, high);
552 if (! MISC_PMC_ENABLED_P(low)) {
553 printk(KERN_ERR "oprofile: P4 PMC not available\n");
554 return;
557 /* clear the cccrs we will use */
558 for (i = 0 ; i < num_counters ; i++) {
559 rdmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
560 CCCR_CLEAR(low);
561 CCCR_SET_REQUIRED_BITS(low);
562 wrmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
565 /* clear cccrs outside our concern */
566 for (i = stag ; i < NUM_UNUSED_CCCRS ; i += addr_increment()) {
567 rdmsr(p4_unused_cccr[i], low, high);
568 CCCR_CLEAR(low);
569 CCCR_SET_REQUIRED_BITS(low);
570 wrmsr(p4_unused_cccr[i], low, high);
573 /* clear all escrs (including those outside our concern) */
574 for (addr = MSR_P4_BSU_ESCR0 + stag;
575 addr < MSR_P4_IQ_ESCR0; addr += addr_increment()) {
576 wrmsr(addr, 0, 0);
579 /* On older models clear also MSR_P4_IQ_ESCR0/1 */
580 if (boot_cpu_data.x86_model < 0x3) {
581 wrmsr(MSR_P4_IQ_ESCR0, 0, 0);
582 wrmsr(MSR_P4_IQ_ESCR1, 0, 0);
585 for (addr = MSR_P4_RAT_ESCR0 + stag;
586 addr <= MSR_P4_SSU_ESCR0; ++i, addr += addr_increment()) {
587 wrmsr(addr, 0, 0);
590 for (addr = MSR_P4_MS_ESCR0 + stag;
591 addr <= MSR_P4_TC_ESCR1; addr += addr_increment()){
592 wrmsr(addr, 0, 0);
595 for (addr = MSR_P4_IX_ESCR0 + stag;
596 addr <= MSR_P4_CRU_ESCR3; addr += addr_increment()){
597 wrmsr(addr, 0, 0);
600 if (num_counters == NUM_COUNTERS_NON_HT) {
601 wrmsr(MSR_P4_CRU_ESCR4, 0, 0);
602 wrmsr(MSR_P4_CRU_ESCR5, 0, 0);
603 } else if (stag == 0) {
604 wrmsr(MSR_P4_CRU_ESCR4, 0, 0);
605 } else {
606 wrmsr(MSR_P4_CRU_ESCR5, 0, 0);
609 /* setup all counters */
610 for (i = 0 ; i < num_counters ; ++i) {
611 if (counter_config[i].enabled) {
612 reset_value[i] = counter_config[i].count;
613 pmc_setup_one_p4_counter(i);
614 CTR_WRITE(counter_config[i].count, VIRT_CTR(stag, i));
615 } else {
616 reset_value[i] = 0;
622 static int p4_check_ctrs(struct pt_regs * const regs,
623 struct op_msrs const * const msrs)
625 unsigned long ctr, low, high, stag, real;
626 int i;
628 stag = get_stagger();
630 for (i = 0; i < num_counters; ++i) {
632 if (!reset_value[i])
633 continue;
636 * there is some eccentricity in the hardware which
637 * requires that we perform 2 extra corrections:
639 * - check both the CCCR:OVF flag for overflow and the
640 * counter high bit for un-flagged overflows.
642 * - write the counter back twice to ensure it gets
643 * updated properly.
645 * the former seems to be related to extra NMIs happening
646 * during the current NMI; the latter is reported as errata
647 * N15 in intel doc 249199-029, pentium 4 specification
648 * update, though their suggested work-around does not
649 * appear to solve the problem.
652 real = VIRT_CTR(stag, i);
654 CCCR_READ(low, high, real);
655 CTR_READ(ctr, high, real);
656 if (CCCR_OVF_P(low) || CTR_OVERFLOW_P(ctr)) {
657 oprofile_add_sample(regs, i);
658 CTR_WRITE(reset_value[i], real);
659 CCCR_CLEAR_OVF(low);
660 CCCR_WRITE(low, high, real);
661 CTR_WRITE(reset_value[i], real);
665 /* P4 quirk: you have to re-unmask the apic vector */
666 apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED);
668 /* See op_model_ppro.c */
669 return 1;
673 static void p4_start(struct op_msrs const * const msrs)
675 unsigned int low, high, stag;
676 int i;
678 stag = get_stagger();
680 for (i = 0; i < num_counters; ++i) {
681 if (!reset_value[i])
682 continue;
683 CCCR_READ(low, high, VIRT_CTR(stag, i));
684 CCCR_SET_ENABLE(low);
685 CCCR_WRITE(low, high, VIRT_CTR(stag, i));
690 static void p4_stop(struct op_msrs const * const msrs)
692 unsigned int low, high, stag;
693 int i;
695 stag = get_stagger();
697 for (i = 0; i < num_counters; ++i) {
698 CCCR_READ(low, high, VIRT_CTR(stag, i));
699 CCCR_SET_DISABLE(low);
700 CCCR_WRITE(low, high, VIRT_CTR(stag, i));
705 #ifdef CONFIG_SMP
706 struct op_x86_model_spec const op_p4_ht2_spec = {
707 .num_counters = NUM_COUNTERS_HT2,
708 .num_controls = NUM_CONTROLS_HT2,
709 .fill_in_addresses = &p4_fill_in_addresses,
710 .setup_ctrs = &p4_setup_ctrs,
711 .check_ctrs = &p4_check_ctrs,
712 .start = &p4_start,
713 .stop = &p4_stop
715 #endif
717 struct op_x86_model_spec const op_p4_spec = {
718 .num_counters = NUM_COUNTERS_NON_HT,
719 .num_controls = NUM_CONTROLS_NON_HT,
720 .fill_in_addresses = &p4_fill_in_addresses,
721 .setup_ctrs = &p4_setup_ctrs,
722 .check_ctrs = &p4_check_ctrs,
723 .start = &p4_start,
724 .stop = &p4_stop