3 * P4 model-specific MSR operations
5 * @remark Copyright 2002 OProfile authors
6 * @remark Read the file COPYING
8 * @author Graydon Hoare
11 #include <linux/oprofile.h>
12 #include <linux/smp.h>
13 #include <linux/ptrace.h>
16 #include <asm/fixmap.h>
20 #include "op_x86_model.h"
21 #include "op_counter.h"
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)
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)
35 #define OP_CTR_OVERFLOW (1ULL<<31)
37 static unsigned int num_counters
= NUM_COUNTERS_NON_HT
;
38 static unsigned int num_controls
= NUM_CONTROLS_NON_HT
;
40 /* this has to be checked dynamically since the
41 hyper-threadedness of a chip is discovered at
43 static inline void setup_num_counters(void)
46 if (smp_num_siblings
== 2) {
47 num_counters
= NUM_COUNTERS_HT2
;
48 num_controls
= NUM_CONTROLS_HT2
;
53 static inline int addr_increment(void)
56 return smp_num_siblings
== 2 ? 2 : 1;
63 /* tables to simulate simplified hardware view of p4 registers */
64 struct p4_counter_binding
{
70 struct p4_event_binding
{
71 int escr_select
; /* value to put in CCCR */
72 int event_select
; /* value to put in ESCR */
74 int virt_counter
; /* for this counter... */
75 int escr_address
; /* use this ESCR */
79 /* nb: these CTR_* defines are a duplicate of defines in
80 event/i386.p4*events. */
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)
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
}
103 #define NUM_UNUSED_CCCRS (NUM_CCCRS_NON_HT - NUM_COUNTERS_NON_HT)
105 /* p4 event codes in libop/op_event.h are indices into this table. */
107 static struct p4_event_binding p4_events
[NUM_EVENTS
] = {
109 { /* BRANCH_RETIRED */
111 { {CTR_IQ_4
, MSR_P4_CRU_ESCR2
},
112 {CTR_IQ_5
, MSR_P4_CRU_ESCR3
} }
115 { /* MISPRED_BRANCH_RETIRED */
117 { { CTR_IQ_4
, MSR_P4_CRU_ESCR0
},
118 { CTR_IQ_5
, MSR_P4_CRU_ESCR1
} }
121 { /* TC_DELIVER_MODE */
123 { { CTR_MS_0
, MSR_P4_TC_ESCR0
},
124 { CTR_MS_2
, MSR_P4_TC_ESCR1
} }
127 { /* BPU_FETCH_REQUEST */
129 { { CTR_BPU_0
, MSR_P4_BPU_ESCR0
},
130 { CTR_BPU_2
, MSR_P4_BPU_ESCR1
} }
133 { /* ITLB_REFERENCE */
135 { { CTR_BPU_0
, MSR_P4_ITLB_ESCR0
},
136 { CTR_BPU_2
, MSR_P4_ITLB_ESCR1
} }
139 { /* MEMORY_CANCEL */
141 { { CTR_FLAME_0
, MSR_P4_DAC_ESCR0
},
142 { CTR_FLAME_2
, MSR_P4_DAC_ESCR1
} }
145 { /* MEMORY_COMPLETE */
147 { { CTR_FLAME_0
, MSR_P4_SAAT_ESCR0
},
148 { CTR_FLAME_2
, MSR_P4_SAAT_ESCR1
} }
151 { /* LOAD_PORT_REPLAY */
153 { { CTR_FLAME_0
, MSR_P4_SAAT_ESCR0
},
154 { CTR_FLAME_2
, MSR_P4_SAAT_ESCR1
} }
157 { /* STORE_PORT_REPLAY */
159 { { CTR_FLAME_0
, MSR_P4_SAAT_ESCR0
},
160 { CTR_FLAME_2
, MSR_P4_SAAT_ESCR1
} }
163 { /* MOB_LOAD_REPLAY */
165 { { CTR_BPU_0
, MSR_P4_MOB_ESCR0
},
166 { CTR_BPU_2
, MSR_P4_MOB_ESCR1
} }
169 { /* PAGE_WALK_TYPE */
171 { { CTR_BPU_0
, MSR_P4_PMH_ESCR0
},
172 { CTR_BPU_2
, MSR_P4_PMH_ESCR1
} }
175 { /* BSQ_CACHE_REFERENCE */
177 { { CTR_BPU_0
, MSR_P4_BSU_ESCR0
},
178 { CTR_BPU_2
, MSR_P4_BSU_ESCR1
} }
181 { /* IOQ_ALLOCATION */
183 { { CTR_BPU_0
, MSR_P4_FSB_ESCR0
},
187 { /* IOQ_ACTIVE_ENTRIES */
189 { { CTR_BPU_2
, MSR_P4_FSB_ESCR1
},
193 { /* FSB_DATA_ACTIVITY */
195 { { CTR_BPU_0
, MSR_P4_FSB_ESCR0
},
196 { CTR_BPU_2
, MSR_P4_FSB_ESCR1
} }
199 { /* BSQ_ALLOCATION */
201 { { CTR_BPU_0
, MSR_P4_BSU_ESCR0
},
205 { /* BSQ_ACTIVE_ENTRIES */
207 { { CTR_BPU_2
, MSR_P4_BSU_ESCR1
/* guess */},
213 { { CTR_IQ_4
, MSR_P4_CRU_ESCR2
},
214 { CTR_IQ_5
, MSR_P4_CRU_ESCR3
} }
217 { /* SSE_INPUT_ASSIST */
219 { { CTR_FLAME_0
, MSR_P4_FIRM_ESCR0
},
220 { CTR_FLAME_2
, MSR_P4_FIRM_ESCR1
} }
223 { /* PACKED_SP_UOP */
225 { { CTR_FLAME_0
, MSR_P4_FIRM_ESCR0
},
226 { CTR_FLAME_2
, MSR_P4_FIRM_ESCR1
} }
229 { /* PACKED_DP_UOP */
231 { { CTR_FLAME_0
, MSR_P4_FIRM_ESCR0
},
232 { CTR_FLAME_2
, MSR_P4_FIRM_ESCR1
} }
235 { /* SCALAR_SP_UOP */
237 { { CTR_FLAME_0
, MSR_P4_FIRM_ESCR0
},
238 { CTR_FLAME_2
, MSR_P4_FIRM_ESCR1
} }
241 { /* SCALAR_DP_UOP */
243 { { CTR_FLAME_0
, MSR_P4_FIRM_ESCR0
},
244 { CTR_FLAME_2
, MSR_P4_FIRM_ESCR1
} }
247 { /* 64BIT_MMX_UOP */
249 { { CTR_FLAME_0
, MSR_P4_FIRM_ESCR0
},
250 { CTR_FLAME_2
, MSR_P4_FIRM_ESCR1
} }
253 { /* 128BIT_MMX_UOP */
255 { { CTR_FLAME_0
, MSR_P4_FIRM_ESCR0
},
256 { CTR_FLAME_2
, MSR_P4_FIRM_ESCR1
} }
261 { { CTR_FLAME_0
, MSR_P4_FIRM_ESCR0
},
262 { CTR_FLAME_2
, MSR_P4_FIRM_ESCR1
} }
265 { /* X87_SIMD_MOVES_UOP */
267 { { CTR_FLAME_0
, MSR_P4_FIRM_ESCR0
},
268 { CTR_FLAME_2
, MSR_P4_FIRM_ESCR1
} }
271 { /* MACHINE_CLEAR */
273 { { CTR_IQ_4
, MSR_P4_CRU_ESCR2
},
274 { CTR_IQ_5
, MSR_P4_CRU_ESCR3
} }
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
} }
285 { { CTR_MS_0
, MSR_P4_MS_ESCR0
},
286 { CTR_MS_2
, MSR_P4_MS_ESCR1
} }
289 { /* UOP_QUEUE_WRITES */
291 { { CTR_MS_0
, MSR_P4_MS_ESCR0
},
292 { CTR_MS_2
, MSR_P4_MS_ESCR1
} }
295 { /* FRONT_END_EVENT */
297 { { CTR_IQ_4
, MSR_P4_CRU_ESCR2
},
298 { CTR_IQ_5
, MSR_P4_CRU_ESCR3
} }
301 { /* EXECUTION_EVENT */
303 { { CTR_IQ_4
, MSR_P4_CRU_ESCR2
},
304 { CTR_IQ_5
, MSR_P4_CRU_ESCR3
} }
309 { { CTR_IQ_4
, MSR_P4_CRU_ESCR2
},
310 { CTR_IQ_5
, MSR_P4_CRU_ESCR3
} }
313 { /* INSTR_RETIRED */
315 { { CTR_IQ_4
, MSR_P4_CRU_ESCR0
},
316 { CTR_IQ_5
, MSR_P4_CRU_ESCR1
} }
321 { { CTR_IQ_4
, MSR_P4_CRU_ESCR0
},
322 { CTR_IQ_5
, MSR_P4_CRU_ESCR1
} }
327 { { CTR_IQ_4
, MSR_P4_RAT_ESCR0
},
328 { CTR_IQ_5
, MSR_P4_RAT_ESCR1
} }
331 { /* RETIRED_MISPRED_BRANCH_TYPE */
333 { { CTR_MS_0
, MSR_P4_TBPU_ESCR0
},
334 { CTR_MS_2
, MSR_P4_TBPU_ESCR1
} }
337 { /* RETIRED_BRANCH_TYPE */
339 { { CTR_MS_0
, MSR_P4_TBPU_ESCR0
},
340 { CTR_MS_2
, MSR_P4_TBPU_ESCR1
} }
345 #define MISC_PMC_ENABLED_P(x) ((x) & 1 << 7)
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))
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)))
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)
374 int cpu
= smp_processor_id();
375 return cpu
!= cpumask_first(this_cpu_cpumask_var_ptr(cpu_sibling_map
));
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)))
386 static unsigned long reset_value
[NUM_COUNTERS_NON_HT
];
388 static void p4_shutdown(struct op_msrs
const * const msrs
)
392 for (i
= 0; i
< num_counters
; ++i
) {
393 if (msrs
->counters
[i
].addr
)
394 release_perfctr_nmi(msrs
->counters
[i
].addr
);
397 * some of the control registers are specially reserved in
398 * conjunction with the counter registers (hence the starting offset).
399 * This saves a few bits.
401 for (i
= num_counters
; i
< num_controls
; ++i
) {
402 if (msrs
->controls
[i
].addr
)
403 release_evntsel_nmi(msrs
->controls
[i
].addr
);
407 static int p4_fill_in_addresses(struct op_msrs
* const msrs
)
410 unsigned int addr
, cccraddr
, stag
;
412 setup_num_counters();
413 stag
= get_stagger();
415 /* the counter & cccr registers we pay attention to */
416 for (i
= 0; i
< num_counters
; ++i
) {
417 addr
= p4_counters
[VIRT_CTR(stag
, i
)].counter_address
;
418 cccraddr
= p4_counters
[VIRT_CTR(stag
, i
)].cccr_address
;
419 if (reserve_perfctr_nmi(addr
)) {
420 msrs
->counters
[i
].addr
= addr
;
421 msrs
->controls
[i
].addr
= cccraddr
;
425 /* 43 ESCR registers in three or four discontiguous group */
426 for (addr
= MSR_P4_BSU_ESCR0
+ stag
;
427 addr
< MSR_P4_IQ_ESCR0
; ++i
, addr
+= addr_increment()) {
428 if (reserve_evntsel_nmi(addr
))
429 msrs
->controls
[i
].addr
= addr
;
432 /* no IQ_ESCR0/1 on some models, we save a seconde time BSU_ESCR0/1
433 * to avoid special case in nmi_{save|restore}_registers() */
434 if (boot_cpu_data
.x86_model
>= 0x3) {
435 for (addr
= MSR_P4_BSU_ESCR0
+ stag
;
436 addr
<= MSR_P4_BSU_ESCR1
; ++i
, addr
+= addr_increment()) {
437 if (reserve_evntsel_nmi(addr
))
438 msrs
->controls
[i
].addr
= addr
;
441 for (addr
= MSR_P4_IQ_ESCR0
+ stag
;
442 addr
<= MSR_P4_IQ_ESCR1
; ++i
, addr
+= addr_increment()) {
443 if (reserve_evntsel_nmi(addr
))
444 msrs
->controls
[i
].addr
= addr
;
448 for (addr
= MSR_P4_RAT_ESCR0
+ stag
;
449 addr
<= MSR_P4_SSU_ESCR0
; ++i
, addr
+= addr_increment()) {
450 if (reserve_evntsel_nmi(addr
))
451 msrs
->controls
[i
].addr
= addr
;
454 for (addr
= MSR_P4_MS_ESCR0
+ stag
;
455 addr
<= MSR_P4_TC_ESCR1
; ++i
, addr
+= addr_increment()) {
456 if (reserve_evntsel_nmi(addr
))
457 msrs
->controls
[i
].addr
= addr
;
460 for (addr
= MSR_P4_IX_ESCR0
+ stag
;
461 addr
<= MSR_P4_CRU_ESCR3
; ++i
, addr
+= addr_increment()) {
462 if (reserve_evntsel_nmi(addr
))
463 msrs
->controls
[i
].addr
= addr
;
466 /* there are 2 remaining non-contiguously located ESCRs */
468 if (num_counters
== NUM_COUNTERS_NON_HT
) {
469 /* standard non-HT CPUs handle both remaining ESCRs*/
470 if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR5
))
471 msrs
->controls
[i
++].addr
= MSR_P4_CRU_ESCR5
;
472 if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR4
))
473 msrs
->controls
[i
++].addr
= MSR_P4_CRU_ESCR4
;
475 } else if (stag
== 0) {
476 /* HT CPUs give the first remainder to the even thread, as
477 the 32nd control register */
478 if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR4
))
479 msrs
->controls
[i
++].addr
= MSR_P4_CRU_ESCR4
;
482 /* and two copies of the second to the odd thread,
483 for the 22st and 23nd control registers */
484 if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR5
)) {
485 msrs
->controls
[i
++].addr
= MSR_P4_CRU_ESCR5
;
486 msrs
->controls
[i
++].addr
= MSR_P4_CRU_ESCR5
;
490 for (i
= 0; i
< num_counters
; ++i
) {
491 if (!counter_config
[i
].enabled
)
493 if (msrs
->controls
[i
].addr
)
495 op_x86_warn_reserved(i
);
504 static void pmc_setup_one_p4_counter(unsigned int ctr
)
507 int const maxbind
= 2;
508 unsigned int cccr
= 0;
509 unsigned int escr
= 0;
510 unsigned int high
= 0;
511 unsigned int counter_bit
;
512 struct p4_event_binding
*ev
= NULL
;
515 stag
= get_stagger();
517 /* convert from counter *number* to counter *bit* */
518 counter_bit
= 1 << VIRT_CTR(stag
, ctr
);
520 /* find our event binding structure. */
521 if (counter_config
[ctr
].event
<= 0 || counter_config
[ctr
].event
> NUM_EVENTS
) {
523 "oprofile: P4 event code 0x%lx out of range\n",
524 counter_config
[ctr
].event
);
528 ev
= &(p4_events
[counter_config
[ctr
].event
- 1]);
530 for (i
= 0; i
< maxbind
; i
++) {
531 if (ev
->bindings
[i
].virt_counter
& counter_bit
) {
534 rdmsr(ev
->bindings
[i
].escr_address
, escr
, high
);
537 ESCR_SET_USR_0(escr
, counter_config
[ctr
].user
);
538 ESCR_SET_OS_0(escr
, counter_config
[ctr
].kernel
);
540 ESCR_SET_USR_1(escr
, counter_config
[ctr
].user
);
541 ESCR_SET_OS_1(escr
, counter_config
[ctr
].kernel
);
543 ESCR_SET_EVENT_SELECT(escr
, ev
->event_select
);
544 ESCR_SET_EVENT_MASK(escr
, counter_config
[ctr
].unit_mask
);
545 wrmsr(ev
->bindings
[i
].escr_address
, escr
, high
);
548 rdmsr(p4_counters
[VIRT_CTR(stag
, ctr
)].cccr_address
,
551 CCCR_SET_REQUIRED_BITS(cccr
);
552 CCCR_SET_ESCR_SELECT(cccr
, ev
->escr_select
);
554 CCCR_SET_PMI_OVF_0(cccr
);
556 CCCR_SET_PMI_OVF_1(cccr
);
557 wrmsr(p4_counters
[VIRT_CTR(stag
, ctr
)].cccr_address
,
564 "oprofile: P4 event code 0x%lx no binding, stag %d ctr %d\n",
565 counter_config
[ctr
].event
, stag
, ctr
);
569 static void p4_setup_ctrs(struct op_x86_model_spec
const *model
,
570 struct op_msrs
const * const msrs
)
573 unsigned int low
, high
;
576 stag
= get_stagger();
578 rdmsr(MSR_IA32_MISC_ENABLE
, low
, high
);
579 if (!MISC_PMC_ENABLED_P(low
)) {
580 printk(KERN_ERR
"oprofile: P4 PMC not available\n");
584 /* clear the cccrs we will use */
585 for (i
= 0; i
< num_counters
; i
++) {
586 if (unlikely(!msrs
->controls
[i
].addr
))
588 rdmsr(p4_counters
[VIRT_CTR(stag
, i
)].cccr_address
, low
, high
);
590 CCCR_SET_REQUIRED_BITS(low
);
591 wrmsr(p4_counters
[VIRT_CTR(stag
, i
)].cccr_address
, low
, high
);
594 /* clear all escrs (including those outside our concern) */
595 for (i
= num_counters
; i
< num_controls
; i
++) {
596 if (unlikely(!msrs
->controls
[i
].addr
))
598 wrmsr(msrs
->controls
[i
].addr
, 0, 0);
601 /* setup all counters */
602 for (i
= 0; i
< num_counters
; ++i
) {
603 if (counter_config
[i
].enabled
&& msrs
->controls
[i
].addr
) {
604 reset_value
[i
] = counter_config
[i
].count
;
605 pmc_setup_one_p4_counter(i
);
606 wrmsrl(p4_counters
[VIRT_CTR(stag
, i
)].counter_address
,
607 -(u64
)counter_config
[i
].count
);
615 static int p4_check_ctrs(struct pt_regs
* const regs
,
616 struct op_msrs
const * const msrs
)
618 unsigned long ctr
, low
, high
, stag
, real
;
621 stag
= get_stagger();
623 for (i
= 0; i
< num_counters
; ++i
) {
629 * there is some eccentricity in the hardware which
630 * requires that we perform 2 extra corrections:
632 * - check both the CCCR:OVF flag for overflow and the
633 * counter high bit for un-flagged overflows.
635 * - write the counter back twice to ensure it gets
638 * the former seems to be related to extra NMIs happening
639 * during the current NMI; the latter is reported as errata
640 * N15 in intel doc 249199-029, pentium 4 specification
641 * update, though their suggested work-around does not
642 * appear to solve the problem.
645 real
= VIRT_CTR(stag
, i
);
647 rdmsr(p4_counters
[real
].cccr_address
, low
, high
);
648 rdmsr(p4_counters
[real
].counter_address
, ctr
, high
);
649 if (CCCR_OVF_P(low
) || !(ctr
& OP_CTR_OVERFLOW
)) {
650 oprofile_add_sample(regs
, i
);
651 wrmsrl(p4_counters
[real
].counter_address
,
652 -(u64
)reset_value
[i
]);
654 wrmsr(p4_counters
[real
].cccr_address
, low
, high
);
655 wrmsrl(p4_counters
[real
].counter_address
,
656 -(u64
)reset_value
[i
]);
660 /* P4 quirk: you have to re-unmask the apic vector */
661 apic_write(APIC_LVTPC
, apic_read(APIC_LVTPC
) & ~APIC_LVT_MASKED
);
663 /* See op_model_ppro.c */
668 static void p4_start(struct op_msrs
const * const msrs
)
670 unsigned int low
, high
, stag
;
673 stag
= get_stagger();
675 for (i
= 0; i
< num_counters
; ++i
) {
678 rdmsr(p4_counters
[VIRT_CTR(stag
, i
)].cccr_address
, low
, high
);
679 CCCR_SET_ENABLE(low
);
680 wrmsr(p4_counters
[VIRT_CTR(stag
, i
)].cccr_address
, low
, high
);
685 static void p4_stop(struct op_msrs
const * const msrs
)
687 unsigned int low
, high
, stag
;
690 stag
= get_stagger();
692 for (i
= 0; i
< num_counters
; ++i
) {
695 rdmsr(p4_counters
[VIRT_CTR(stag
, i
)].cccr_address
, low
, high
);
696 CCCR_SET_DISABLE(low
);
697 wrmsr(p4_counters
[VIRT_CTR(stag
, i
)].cccr_address
, low
, high
);
702 struct op_x86_model_spec op_p4_ht2_spec
= {
703 .num_counters
= NUM_COUNTERS_HT2
,
704 .num_controls
= NUM_CONTROLS_HT2
,
705 .fill_in_addresses
= &p4_fill_in_addresses
,
706 .setup_ctrs
= &p4_setup_ctrs
,
707 .check_ctrs
= &p4_check_ctrs
,
710 .shutdown
= &p4_shutdown
714 struct op_x86_model_spec op_p4_spec
= {
715 .num_counters
= NUM_COUNTERS_NON_HT
,
716 .num_controls
= NUM_CONTROLS_NON_HT
,
717 .fill_in_addresses
= &p4_fill_in_addresses
,
718 .setup_ctrs
= &p4_setup_ctrs
,
719 .check_ctrs
= &p4_check_ctrs
,
722 .shutdown
= &p4_shutdown