aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/i386/oprofile/nmi_int.c41
-rw-r--r--arch/i386/oprofile/op_model_athlon.c54
-rw-r--r--arch/i386/oprofile/op_model_p4.c152
-rw-r--r--arch/i386/oprofile/op_model_ppro.c65
-rw-r--r--arch/i386/oprofile/op_x86_model.h1
5 files changed, 199 insertions, 114 deletions
diff --git a/arch/i386/oprofile/nmi_int.c b/arch/i386/oprofile/nmi_int.c
index 5f8dc8a21bd..8710ca081b1 100644
--- a/arch/i386/oprofile/nmi_int.c
+++ b/arch/i386/oprofile/nmi_int.c
@@ -98,15 +98,19 @@ static void nmi_cpu_save_registers(struct op_msrs * msrs)
98 unsigned int i; 98 unsigned int i;
99 99
100 for (i = 0; i < nr_ctrs; ++i) { 100 for (i = 0; i < nr_ctrs; ++i) {
101 rdmsr(counters[i].addr, 101 if (counters[i].addr){
102 counters[i].saved.low, 102 rdmsr(counters[i].addr,
103 counters[i].saved.high); 103 counters[i].saved.low,
104 counters[i].saved.high);
105 }
104 } 106 }
105 107
106 for (i = 0; i < nr_ctrls; ++i) { 108 for (i = 0; i < nr_ctrls; ++i) {
107 rdmsr(controls[i].addr, 109 if (controls[i].addr){
108 controls[i].saved.low, 110 rdmsr(controls[i].addr,
109 controls[i].saved.high); 111 controls[i].saved.low,
112 controls[i].saved.high);
113 }
110 } 114 }
111} 115}
112 116
@@ -205,15 +209,19 @@ static void nmi_restore_registers(struct op_msrs * msrs)
205 unsigned int i; 209 unsigned int i;
206 210
207 for (i = 0; i < nr_ctrls; ++i) { 211 for (i = 0; i < nr_ctrls; ++i) {
208 wrmsr(controls[i].addr, 212 if (controls[i].addr){
209 controls[i].saved.low, 213 wrmsr(controls[i].addr,
210 controls[i].saved.high); 214 controls[i].saved.low,
215 controls[i].saved.high);
216 }
211 } 217 }
212 218
213 for (i = 0; i < nr_ctrs; ++i) { 219 for (i = 0; i < nr_ctrs; ++i) {
214 wrmsr(counters[i].addr, 220 if (counters[i].addr){
215 counters[i].saved.low, 221 wrmsr(counters[i].addr,
216 counters[i].saved.high); 222 counters[i].saved.low,
223 counters[i].saved.high);
224 }
217 } 225 }
218} 226}
219 227
@@ -234,6 +242,7 @@ static void nmi_cpu_shutdown(void * dummy)
234 apic_write(APIC_LVTPC, saved_lvtpc[cpu]); 242 apic_write(APIC_LVTPC, saved_lvtpc[cpu]);
235 apic_write(APIC_LVTERR, v); 243 apic_write(APIC_LVTERR, v);
236 nmi_restore_registers(msrs); 244 nmi_restore_registers(msrs);
245 model->shutdown(msrs);
237} 246}
238 247
239 248
@@ -284,6 +293,14 @@ static int nmi_create_files(struct super_block * sb, struct dentry * root)
284 struct dentry * dir; 293 struct dentry * dir;
285 char buf[4]; 294 char buf[4];
286 295
296 /* quick little hack to _not_ expose a counter if it is not
297 * available for use. This should protect userspace app.
298 * NOTE: assumes 1:1 mapping here (that counters are organized
299 * sequentially in their struct assignment).
300 */
301 if (unlikely(!avail_to_resrv_perfctr_nmi_bit(i)))
302 continue;
303
287 snprintf(buf, sizeof(buf), "%d", i); 304 snprintf(buf, sizeof(buf), "%d", i);
288 dir = oprofilefs_mkdir(sb, root, buf); 305 dir = oprofilefs_mkdir(sb, root, buf);
289 oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled); 306 oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled);
diff --git a/arch/i386/oprofile/op_model_athlon.c b/arch/i386/oprofile/op_model_athlon.c
index 693bdea4a52..3057a19e464 100644
--- a/arch/i386/oprofile/op_model_athlon.c
+++ b/arch/i386/oprofile/op_model_athlon.c
@@ -21,10 +21,12 @@
21#define NUM_COUNTERS 4 21#define NUM_COUNTERS 4
22#define NUM_CONTROLS 4 22#define NUM_CONTROLS 4
23 23
24#define CTR_IS_RESERVED(msrs,c) (msrs->counters[(c)].addr ? 1 : 0)
24#define CTR_READ(l,h,msrs,c) do {rdmsr(msrs->counters[(c)].addr, (l), (h));} while (0) 25#define CTR_READ(l,h,msrs,c) do {rdmsr(msrs->counters[(c)].addr, (l), (h));} while (0)
25#define CTR_WRITE(l,msrs,c) do {wrmsr(msrs->counters[(c)].addr, -(unsigned int)(l), -1);} while (0) 26#define CTR_WRITE(l,msrs,c) do {wrmsr(msrs->counters[(c)].addr, -(unsigned int)(l), -1);} while (0)
26#define CTR_OVERFLOWED(n) (!((n) & (1U<<31))) 27#define CTR_OVERFLOWED(n) (!((n) & (1U<<31)))
27 28
29#define CTRL_IS_RESERVED(msrs,c) (msrs->controls[(c)].addr ? 1 : 0)
28#define CTRL_READ(l,h,msrs,c) do {rdmsr(msrs->controls[(c)].addr, (l), (h));} while (0) 30#define CTRL_READ(l,h,msrs,c) do {rdmsr(msrs->controls[(c)].addr, (l), (h));} while (0)
29#define CTRL_WRITE(l,h,msrs,c) do {wrmsr(msrs->controls[(c)].addr, (l), (h));} while (0) 31#define CTRL_WRITE(l,h,msrs,c) do {wrmsr(msrs->controls[(c)].addr, (l), (h));} while (0)
30#define CTRL_SET_ACTIVE(n) (n |= (1<<22)) 32#define CTRL_SET_ACTIVE(n) (n |= (1<<22))
@@ -40,15 +42,21 @@ static unsigned long reset_value[NUM_COUNTERS];
40 42
41static void athlon_fill_in_addresses(struct op_msrs * const msrs) 43static void athlon_fill_in_addresses(struct op_msrs * const msrs)
42{ 44{
43 msrs->counters[0].addr = MSR_K7_PERFCTR0; 45 int i;
44 msrs->counters[1].addr = MSR_K7_PERFCTR1; 46
45 msrs->counters[2].addr = MSR_K7_PERFCTR2; 47 for (i=0; i < NUM_COUNTERS; i++) {
46 msrs->counters[3].addr = MSR_K7_PERFCTR3; 48 if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i))
47 49 msrs->counters[i].addr = MSR_K7_PERFCTR0 + i;
48 msrs->controls[0].addr = MSR_K7_EVNTSEL0; 50 else
49 msrs->controls[1].addr = MSR_K7_EVNTSEL1; 51 msrs->counters[i].addr = 0;
50 msrs->controls[2].addr = MSR_K7_EVNTSEL2; 52 }
51 msrs->controls[3].addr = MSR_K7_EVNTSEL3; 53
54 for (i=0; i < NUM_CONTROLS; i++) {
55 if (reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i))
56 msrs->controls[i].addr = MSR_K7_EVNTSEL0 + i;
57 else
58 msrs->controls[i].addr = 0;
59 }
52} 60}
53 61
54 62
@@ -59,19 +67,23 @@ static void athlon_setup_ctrs(struct op_msrs const * const msrs)
59 67
60 /* clear all counters */ 68 /* clear all counters */
61 for (i = 0 ; i < NUM_CONTROLS; ++i) { 69 for (i = 0 ; i < NUM_CONTROLS; ++i) {
70 if (unlikely(!CTRL_IS_RESERVED(msrs,i)))
71 continue;
62 CTRL_READ(low, high, msrs, i); 72 CTRL_READ(low, high, msrs, i);
63 CTRL_CLEAR(low); 73 CTRL_CLEAR(low);
64 CTRL_WRITE(low, high, msrs, i); 74 CTRL_WRITE(low, high, msrs, i);
65 } 75 }
66 76
67 /* avoid a false detection of ctr overflows in NMI handler */ 77 /* avoid a false detection of ctr overflows in NMI handler */
68 for (i = 0; i < NUM_COUNTERS; ++i) { 78 for (i = 0; i < NUM_COUNTERS; ++i) {
79 if (unlikely(!CTR_IS_RESERVED(msrs,i)))
80 continue;
69 CTR_WRITE(1, msrs, i); 81 CTR_WRITE(1, msrs, i);
70 } 82 }
71 83
72 /* enable active counters */ 84 /* enable active counters */
73 for (i = 0; i < NUM_COUNTERS; ++i) { 85 for (i = 0; i < NUM_COUNTERS; ++i) {
74 if (counter_config[i].enabled) { 86 if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs,i))) {
75 reset_value[i] = counter_config[i].count; 87 reset_value[i] = counter_config[i].count;
76 88
77 CTR_WRITE(counter_config[i].count, msrs, i); 89 CTR_WRITE(counter_config[i].count, msrs, i);
@@ -98,6 +110,8 @@ static int athlon_check_ctrs(struct pt_regs * const regs,
98 int i; 110 int i;
99 111
100 for (i = 0 ; i < NUM_COUNTERS; ++i) { 112 for (i = 0 ; i < NUM_COUNTERS; ++i) {
113 if (!reset_value[i])
114 continue;
101 CTR_READ(low, high, msrs, i); 115 CTR_READ(low, high, msrs, i);
102 if (CTR_OVERFLOWED(low)) { 116 if (CTR_OVERFLOWED(low)) {
103 oprofile_add_sample(regs, i); 117 oprofile_add_sample(regs, i);
@@ -132,12 +146,27 @@ static void athlon_stop(struct op_msrs const * const msrs)
132 /* Subtle: stop on all counters to avoid race with 146 /* Subtle: stop on all counters to avoid race with
133 * setting our pm callback */ 147 * setting our pm callback */
134 for (i = 0 ; i < NUM_COUNTERS ; ++i) { 148 for (i = 0 ; i < NUM_COUNTERS ; ++i) {
149 if (!reset_value[i])
150 continue;
135 CTRL_READ(low, high, msrs, i); 151 CTRL_READ(low, high, msrs, i);
136 CTRL_SET_INACTIVE(low); 152 CTRL_SET_INACTIVE(low);
137 CTRL_WRITE(low, high, msrs, i); 153 CTRL_WRITE(low, high, msrs, i);
138 } 154 }
139} 155}
140 156
157static void athlon_shutdown(struct op_msrs const * const msrs)
158{
159 int i;
160
161 for (i = 0 ; i < NUM_COUNTERS ; ++i) {
162 if (CTR_IS_RESERVED(msrs,i))
163 release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
164 }
165 for (i = 0 ; i < NUM_CONTROLS ; ++i) {
166 if (CTRL_IS_RESERVED(msrs,i))
167 release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
168 }
169}
141 170
142struct op_x86_model_spec const op_athlon_spec = { 171struct op_x86_model_spec const op_athlon_spec = {
143 .num_counters = NUM_COUNTERS, 172 .num_counters = NUM_COUNTERS,
@@ -146,5 +175,6 @@ struct op_x86_model_spec const op_athlon_spec = {
146 .setup_ctrs = &athlon_setup_ctrs, 175 .setup_ctrs = &athlon_setup_ctrs,
147 .check_ctrs = &athlon_check_ctrs, 176 .check_ctrs = &athlon_check_ctrs,
148 .start = &athlon_start, 177 .start = &athlon_start,
149 .stop = &athlon_stop 178 .stop = &athlon_stop,
179 .shutdown = &athlon_shutdown
150}; 180};
diff --git a/arch/i386/oprofile/op_model_p4.c b/arch/i386/oprofile/op_model_p4.c
index 7c61d357b82..47925927b12 100644
--- a/arch/i386/oprofile/op_model_p4.c
+++ b/arch/i386/oprofile/op_model_p4.c
@@ -32,7 +32,7 @@
32#define NUM_CONTROLS_HT2 (NUM_ESCRS_HT2 + NUM_CCCRS_HT2) 32#define NUM_CONTROLS_HT2 (NUM_ESCRS_HT2 + NUM_CCCRS_HT2)
33 33
34static unsigned int num_counters = NUM_COUNTERS_NON_HT; 34static unsigned int num_counters = NUM_COUNTERS_NON_HT;
35 35static unsigned int num_controls = NUM_CONTROLS_NON_HT;
36 36
37/* this has to be checked dynamically since the 37/* this has to be checked dynamically since the
38 hyper-threadedness of a chip is discovered at 38 hyper-threadedness of a chip is discovered at
@@ -40,8 +40,10 @@ static unsigned int num_counters = NUM_COUNTERS_NON_HT;
40static inline void setup_num_counters(void) 40static inline void setup_num_counters(void)
41{ 41{
42#ifdef CONFIG_SMP 42#ifdef CONFIG_SMP
43 if (smp_num_siblings == 2) 43 if (smp_num_siblings == 2){
44 num_counters = NUM_COUNTERS_HT2; 44 num_counters = NUM_COUNTERS_HT2;
45 num_controls = NUM_CONTROLS_HT2;
46 }
45#endif 47#endif
46} 48}
47 49
@@ -97,15 +99,6 @@ static struct p4_counter_binding p4_counters [NUM_COUNTERS_NON_HT] = {
97 99
98#define NUM_UNUSED_CCCRS NUM_CCCRS_NON_HT - NUM_COUNTERS_NON_HT 100#define NUM_UNUSED_CCCRS NUM_CCCRS_NON_HT - NUM_COUNTERS_NON_HT
99 101
100/* All cccr we don't use. */
101static int p4_unused_cccr[NUM_UNUSED_CCCRS] = {
102 MSR_P4_BPU_CCCR1, MSR_P4_BPU_CCCR3,
103 MSR_P4_MS_CCCR1, MSR_P4_MS_CCCR3,
104 MSR_P4_FLAME_CCCR1, MSR_P4_FLAME_CCCR3,
105 MSR_P4_IQ_CCCR0, MSR_P4_IQ_CCCR1,
106 MSR_P4_IQ_CCCR2, MSR_P4_IQ_CCCR3
107};
108
109/* p4 event codes in libop/op_event.h are indices into this table. */ 102/* p4 event codes in libop/op_event.h are indices into this table. */
110 103
111static struct p4_event_binding p4_events[NUM_EVENTS] = { 104static struct p4_event_binding p4_events[NUM_EVENTS] = {
@@ -372,6 +365,8 @@ static struct p4_event_binding p4_events[NUM_EVENTS] = {
372#define CCCR_OVF_P(cccr) ((cccr) & (1U<<31)) 365#define CCCR_OVF_P(cccr) ((cccr) & (1U<<31))
373#define CCCR_CLEAR_OVF(cccr) ((cccr) &= (~(1U<<31))) 366#define CCCR_CLEAR_OVF(cccr) ((cccr) &= (~(1U<<31)))
374 367
368#define CTRL_IS_RESERVED(msrs,c) (msrs->controls[(c)].addr ? 1 : 0)
369#define CTR_IS_RESERVED(msrs,c) (msrs->counters[(c)].addr ? 1 : 0)
375#define CTR_READ(l,h,i) do {rdmsr(p4_counters[(i)].counter_address, (l), (h));} while (0) 370#define CTR_READ(l,h,i) do {rdmsr(p4_counters[(i)].counter_address, (l), (h));} while (0)
376#define CTR_WRITE(l,i) do {wrmsr(p4_counters[(i)].counter_address, -(u32)(l), -1);} while (0) 371#define CTR_WRITE(l,i) do {wrmsr(p4_counters[(i)].counter_address, -(u32)(l), -1);} while (0)
377#define CTR_OVERFLOW_P(ctr) (!((ctr) & 0x80000000)) 372#define CTR_OVERFLOW_P(ctr) (!((ctr) & 0x80000000))
@@ -401,29 +396,34 @@ static unsigned long reset_value[NUM_COUNTERS_NON_HT];
401static void p4_fill_in_addresses(struct op_msrs * const msrs) 396static void p4_fill_in_addresses(struct op_msrs * const msrs)
402{ 397{
403 unsigned int i; 398 unsigned int i;
404 unsigned int addr, stag; 399 unsigned int addr, cccraddr, stag;
405 400
406 setup_num_counters(); 401 setup_num_counters();
407 stag = get_stagger(); 402 stag = get_stagger();
408 403
409 /* the counter registers we pay attention to */ 404 /* initialize some registers */
410 for (i = 0; i < num_counters; ++i) { 405 for (i = 0; i < num_counters; ++i) {
411 msrs->counters[i].addr = 406 msrs->counters[i].addr = 0;
412 p4_counters[VIRT_CTR(stag, i)].counter_address;
413 } 407 }
414 408 for (i = 0; i < num_controls; ++i) {
415 /* FIXME: bad feeling, we don't save the 10 counters we don't use. */ 409 msrs->controls[i].addr = 0;
416
417 /* 18 CCCR registers */
418 for (i = 0, addr = MSR_P4_BPU_CCCR0 + stag;
419 addr <= MSR_P4_IQ_CCCR5; ++i, addr += addr_increment()) {
420 msrs->controls[i].addr = addr;
421 } 410 }
422 411
412 /* the counter & cccr registers we pay attention to */
413 for (i = 0; i < num_counters; ++i) {
414 addr = p4_counters[VIRT_CTR(stag, i)].counter_address;
415 cccraddr = p4_counters[VIRT_CTR(stag, i)].cccr_address;
416 if (reserve_perfctr_nmi(addr)){
417 msrs->counters[i].addr = addr;
418 msrs->controls[i].addr = cccraddr;
419 }
420 }
421
423 /* 43 ESCR registers in three or four discontiguous group */ 422 /* 43 ESCR registers in three or four discontiguous group */
424 for (addr = MSR_P4_BSU_ESCR0 + stag; 423 for (addr = MSR_P4_BSU_ESCR0 + stag;
425 addr < MSR_P4_IQ_ESCR0; ++i, addr += addr_increment()) { 424 addr < MSR_P4_IQ_ESCR0; ++i, addr += addr_increment()) {
426 msrs->controls[i].addr = addr; 425 if (reserve_evntsel_nmi(addr))
426 msrs->controls[i].addr = addr;
427 } 427 }
428 428
429 /* no IQ_ESCR0/1 on some models, we save a seconde time BSU_ESCR0/1 429 /* no IQ_ESCR0/1 on some models, we save a seconde time BSU_ESCR0/1
@@ -431,47 +431,57 @@ static void p4_fill_in_addresses(struct op_msrs * const msrs)
431 if (boot_cpu_data.x86_model >= 0x3) { 431 if (boot_cpu_data.x86_model >= 0x3) {
432 for (addr = MSR_P4_BSU_ESCR0 + stag; 432 for (addr = MSR_P4_BSU_ESCR0 + stag;
433 addr <= MSR_P4_BSU_ESCR1; ++i, addr += addr_increment()) { 433 addr <= MSR_P4_BSU_ESCR1; ++i, addr += addr_increment()) {
434 msrs->controls[i].addr = addr; 434 if (reserve_evntsel_nmi(addr))
435 msrs->controls[i].addr = addr;
435 } 436 }
436 } else { 437 } else {
437 for (addr = MSR_P4_IQ_ESCR0 + stag; 438 for (addr = MSR_P4_IQ_ESCR0 + stag;
438 addr <= MSR_P4_IQ_ESCR1; ++i, addr += addr_increment()) { 439 addr <= MSR_P4_IQ_ESCR1; ++i, addr += addr_increment()) {
439 msrs->controls[i].addr = addr; 440 if (reserve_evntsel_nmi(addr))
441 msrs->controls[i].addr = addr;
440 } 442 }
441 } 443 }
442 444
443 for (addr = MSR_P4_RAT_ESCR0 + stag; 445 for (addr = MSR_P4_RAT_ESCR0 + stag;
444 addr <= MSR_P4_SSU_ESCR0; ++i, addr += addr_increment()) { 446 addr <= MSR_P4_SSU_ESCR0; ++i, addr += addr_increment()) {
445 msrs->controls[i].addr = addr; 447 if (reserve_evntsel_nmi(addr))
448 msrs->controls[i].addr = addr;
446 } 449 }
447 450
448 for (addr = MSR_P4_MS_ESCR0 + stag; 451 for (addr = MSR_P4_MS_ESCR0 + stag;
449 addr <= MSR_P4_TC_ESCR1; ++i, addr += addr_increment()) { 452 addr <= MSR_P4_TC_ESCR1; ++i, addr += addr_increment()) {
450 msrs->controls[i].addr = addr; 453 if (reserve_evntsel_nmi(addr))
454 msrs->controls[i].addr = addr;
451 } 455 }
452 456
453 for (addr = MSR_P4_IX_ESCR0 + stag; 457 for (addr = MSR_P4_IX_ESCR0 + stag;
454 addr <= MSR_P4_CRU_ESCR3; ++i, addr += addr_increment()) { 458 addr <= MSR_P4_CRU_ESCR3; ++i, addr += addr_increment()) {
455 msrs->controls[i].addr = addr; 459 if (reserve_evntsel_nmi(addr))
460 msrs->controls[i].addr = addr;
456 } 461 }
457 462
458 /* there are 2 remaining non-contiguously located ESCRs */ 463 /* there are 2 remaining non-contiguously located ESCRs */
459 464
460 if (num_counters == NUM_COUNTERS_NON_HT) { 465 if (num_counters == NUM_COUNTERS_NON_HT) {
461 /* standard non-HT CPUs handle both remaining ESCRs*/ 466 /* standard non-HT CPUs handle both remaining ESCRs*/
462 msrs->controls[i++].addr = MSR_P4_CRU_ESCR5; 467 if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR5))
463 msrs->controls[i++].addr = MSR_P4_CRU_ESCR4; 468 msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
469 if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR4))
470 msrs->controls[i++].addr = MSR_P4_CRU_ESCR4;
464 471
465 } else if (stag == 0) { 472 } else if (stag == 0) {
466 /* HT CPUs give the first remainder to the even thread, as 473 /* HT CPUs give the first remainder to the even thread, as
467 the 32nd control register */ 474 the 32nd control register */
468 msrs->controls[i++].addr = MSR_P4_CRU_ESCR4; 475 if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR4))
476 msrs->controls[i++].addr = MSR_P4_CRU_ESCR4;
469 477
470 } else { 478 } else {
471 /* and two copies of the second to the odd thread, 479 /* and two copies of the second to the odd thread,
472 for the 22st and 23nd control registers */ 480 for the 22st and 23nd control registers */
473 msrs->controls[i++].addr = MSR_P4_CRU_ESCR5; 481 if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR5)) {
474 msrs->controls[i++].addr = MSR_P4_CRU_ESCR5; 482 msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
483 msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
484 }
475 } 485 }
476} 486}
477 487
@@ -544,7 +554,6 @@ static void p4_setup_ctrs(struct op_msrs const * const msrs)
544{ 554{
545 unsigned int i; 555 unsigned int i;
546 unsigned int low, high; 556 unsigned int low, high;
547 unsigned int addr;
548 unsigned int stag; 557 unsigned int stag;
549 558
550 stag = get_stagger(); 559 stag = get_stagger();
@@ -557,59 +566,24 @@ static void p4_setup_ctrs(struct op_msrs const * const msrs)
557 566
558 /* clear the cccrs we will use */ 567 /* clear the cccrs we will use */
559 for (i = 0 ; i < num_counters ; i++) { 568 for (i = 0 ; i < num_counters ; i++) {
569 if (unlikely(!CTRL_IS_RESERVED(msrs,i)))
570 continue;
560 rdmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high); 571 rdmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
561 CCCR_CLEAR(low); 572 CCCR_CLEAR(low);
562 CCCR_SET_REQUIRED_BITS(low); 573 CCCR_SET_REQUIRED_BITS(low);
563 wrmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high); 574 wrmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
564 } 575 }
565 576
566 /* clear cccrs outside our concern */
567 for (i = stag ; i < NUM_UNUSED_CCCRS ; i += addr_increment()) {
568 rdmsr(p4_unused_cccr[i], low, high);
569 CCCR_CLEAR(low);
570 CCCR_SET_REQUIRED_BITS(low);
571 wrmsr(p4_unused_cccr[i], low, high);
572 }
573
574 /* clear all escrs (including those outside our concern) */ 577 /* clear all escrs (including those outside our concern) */
575 for (addr = MSR_P4_BSU_ESCR0 + stag; 578 for (i = num_counters; i < num_controls; i++) {
576 addr < MSR_P4_IQ_ESCR0; addr += addr_increment()) { 579 if (unlikely(!CTRL_IS_RESERVED(msrs,i)))
577 wrmsr(addr, 0, 0); 580 continue;
578 } 581 wrmsr(msrs->controls[i].addr, 0, 0);
579
580 /* On older models clear also MSR_P4_IQ_ESCR0/1 */
581 if (boot_cpu_data.x86_model < 0x3) {
582 wrmsr(MSR_P4_IQ_ESCR0, 0, 0);
583 wrmsr(MSR_P4_IQ_ESCR1, 0, 0);
584 }
585
586 for (addr = MSR_P4_RAT_ESCR0 + stag;
587 addr <= MSR_P4_SSU_ESCR0; ++i, addr += addr_increment()) {
588 wrmsr(addr, 0, 0);
589 }
590
591 for (addr = MSR_P4_MS_ESCR0 + stag;
592 addr <= MSR_P4_TC_ESCR1; addr += addr_increment()){
593 wrmsr(addr, 0, 0);
594 }
595
596 for (addr = MSR_P4_IX_ESCR0 + stag;
597 addr <= MSR_P4_CRU_ESCR3; addr += addr_increment()){
598 wrmsr(addr, 0, 0);
599 } 582 }
600 583
601 if (num_counters == NUM_COUNTERS_NON_HT) {
602 wrmsr(MSR_P4_CRU_ESCR4, 0, 0);
603 wrmsr(MSR_P4_CRU_ESCR5, 0, 0);
604 } else if (stag == 0) {
605 wrmsr(MSR_P4_CRU_ESCR4, 0, 0);
606 } else {
607 wrmsr(MSR_P4_CRU_ESCR5, 0, 0);
608 }
609
610 /* setup all counters */ 584 /* setup all counters */
611 for (i = 0 ; i < num_counters ; ++i) { 585 for (i = 0 ; i < num_counters ; ++i) {
612 if (counter_config[i].enabled) { 586 if ((counter_config[i].enabled) && (CTRL_IS_RESERVED(msrs,i))) {
613 reset_value[i] = counter_config[i].count; 587 reset_value[i] = counter_config[i].count;
614 pmc_setup_one_p4_counter(i); 588 pmc_setup_one_p4_counter(i);
615 CTR_WRITE(counter_config[i].count, VIRT_CTR(stag, i)); 589 CTR_WRITE(counter_config[i].count, VIRT_CTR(stag, i));
@@ -696,12 +670,32 @@ static void p4_stop(struct op_msrs const * const msrs)
696 stag = get_stagger(); 670 stag = get_stagger();
697 671
698 for (i = 0; i < num_counters; ++i) { 672 for (i = 0; i < num_counters; ++i) {
673 if (!reset_value[i])
674 continue;
699 CCCR_READ(low, high, VIRT_CTR(stag, i)); 675 CCCR_READ(low, high, VIRT_CTR(stag, i));
700 CCCR_SET_DISABLE(low); 676 CCCR_SET_DISABLE(low);
701 CCCR_WRITE(low, high, VIRT_CTR(stag, i)); 677 CCCR_WRITE(low, high, VIRT_CTR(stag, i));
702 } 678 }
703} 679}
704 680
681static void p4_shutdown(struct op_msrs const * const msrs)
682{
683 int i;
684
685 for (i = 0 ; i < num_counters ; ++i) {
686 if (CTR_IS_RESERVED(msrs,i))
687 release_perfctr_nmi(msrs->counters[i].addr);
688 }
689 /* some of the control registers are specially reserved in
690 * conjunction with the counter registers (hence the starting offset).
691 * This saves a few bits.
692 */
693 for (i = num_counters ; i < num_controls ; ++i) {
694 if (CTRL_IS_RESERVED(msrs,i))
695 release_evntsel_nmi(msrs->controls[i].addr);
696 }
697}
698
705 699
706#ifdef CONFIG_SMP 700#ifdef CONFIG_SMP
707struct op_x86_model_spec const op_p4_ht2_spec = { 701struct op_x86_model_spec const op_p4_ht2_spec = {
@@ -711,7 +705,8 @@ struct op_x86_model_spec const op_p4_ht2_spec = {
711 .setup_ctrs = &p4_setup_ctrs, 705 .setup_ctrs = &p4_setup_ctrs,
712 .check_ctrs = &p4_check_ctrs, 706 .check_ctrs = &p4_check_ctrs,
713 .start = &p4_start, 707 .start = &p4_start,
714 .stop = &p4_stop 708 .stop = &p4_stop,
709 .shutdown = &p4_shutdown
715}; 710};
716#endif 711#endif
717 712
@@ -722,5 +717,6 @@ struct op_x86_model_spec const op_p4_spec = {
722 .setup_ctrs = &p4_setup_ctrs, 717 .setup_ctrs = &p4_setup_ctrs,
723 .check_ctrs = &p4_check_ctrs, 718 .check_ctrs = &p4_check_ctrs,
724 .start = &p4_start, 719 .start = &p4_start,
725 .stop = &p4_stop 720 .stop = &p4_stop,
721 .shutdown = &p4_shutdown
726}; 722};
diff --git a/arch/i386/oprofile/op_model_ppro.c b/arch/i386/oprofile/op_model_ppro.c
index 5c3ab4b027a..f88e05ba8eb 100644
--- a/arch/i386/oprofile/op_model_ppro.c
+++ b/arch/i386/oprofile/op_model_ppro.c
@@ -22,10 +22,12 @@
22#define NUM_COUNTERS 2 22#define NUM_COUNTERS 2
23#define NUM_CONTROLS 2 23#define NUM_CONTROLS 2
24 24
25#define CTR_IS_RESERVED(msrs,c) (msrs->counters[(c)].addr ? 1 : 0)
25#define CTR_READ(l,h,msrs,c) do {rdmsr(msrs->counters[(c)].addr, (l), (h));} while (0) 26#define CTR_READ(l,h,msrs,c) do {rdmsr(msrs->counters[(c)].addr, (l), (h));} while (0)
26#define CTR_WRITE(l,msrs,c) do {wrmsr(msrs->counters[(c)].addr, -(u32)(l), -1);} while (0) 27#define CTR_WRITE(l,msrs,c) do {wrmsr(msrs->counters[(c)].addr, -(u32)(l), -1);} while (0)
27#define CTR_OVERFLOWED(n) (!((n) & (1U<<31))) 28#define CTR_OVERFLOWED(n) (!((n) & (1U<<31)))
28 29
30#define CTRL_IS_RESERVED(msrs,c) (msrs->controls[(c)].addr ? 1 : 0)
29#define CTRL_READ(l,h,msrs,c) do {rdmsr((msrs->controls[(c)].addr), (l), (h));} while (0) 31#define CTRL_READ(l,h,msrs,c) do {rdmsr((msrs->controls[(c)].addr), (l), (h));} while (0)
30#define CTRL_WRITE(l,h,msrs,c) do {wrmsr((msrs->controls[(c)].addr), (l), (h));} while (0) 32#define CTRL_WRITE(l,h,msrs,c) do {wrmsr((msrs->controls[(c)].addr), (l), (h));} while (0)
31#define CTRL_SET_ACTIVE(n) (n |= (1<<22)) 33#define CTRL_SET_ACTIVE(n) (n |= (1<<22))
@@ -41,11 +43,21 @@ static unsigned long reset_value[NUM_COUNTERS];
41 43
42static void ppro_fill_in_addresses(struct op_msrs * const msrs) 44static void ppro_fill_in_addresses(struct op_msrs * const msrs)
43{ 45{
44 msrs->counters[0].addr = MSR_P6_PERFCTR0; 46 int i;
45 msrs->counters[1].addr = MSR_P6_PERFCTR1; 47
48 for (i=0; i < NUM_COUNTERS; i++) {
49 if (reserve_perfctr_nmi(MSR_P6_PERFCTR0 + i))
50 msrs->counters[i].addr = MSR_P6_PERFCTR0 + i;
51 else
52 msrs->counters[i].addr = 0;
53 }
46 54
47 msrs->controls[0].addr = MSR_P6_EVNTSEL0; 55 for (i=0; i < NUM_CONTROLS; i++) {
48 msrs->controls[1].addr = MSR_P6_EVNTSEL1; 56 if (reserve_evntsel_nmi(MSR_P6_EVNTSEL0 + i))
57 msrs->controls[i].addr = MSR_P6_EVNTSEL0 + i;
58 else
59 msrs->controls[i].addr = 0;
60 }
49} 61}
50 62
51 63
@@ -56,6 +68,8 @@ static void ppro_setup_ctrs(struct op_msrs const * const msrs)
56 68
57 /* clear all counters */ 69 /* clear all counters */
58 for (i = 0 ; i < NUM_CONTROLS; ++i) { 70 for (i = 0 ; i < NUM_CONTROLS; ++i) {
71 if (unlikely(!CTRL_IS_RESERVED(msrs,i)))
72 continue;
59 CTRL_READ(low, high, msrs, i); 73 CTRL_READ(low, high, msrs, i);
60 CTRL_CLEAR(low); 74 CTRL_CLEAR(low);
61 CTRL_WRITE(low, high, msrs, i); 75 CTRL_WRITE(low, high, msrs, i);
@@ -63,12 +77,14 @@ static void ppro_setup_ctrs(struct op_msrs const * const msrs)
63 77
64 /* avoid a false detection of ctr overflows in NMI handler */ 78 /* avoid a false detection of ctr overflows in NMI handler */
65 for (i = 0; i < NUM_COUNTERS; ++i) { 79 for (i = 0; i < NUM_COUNTERS; ++i) {
80 if (unlikely(!CTR_IS_RESERVED(msrs,i)))
81 continue;
66 CTR_WRITE(1, msrs, i); 82 CTR_WRITE(1, msrs, i);
67 } 83 }
68 84
69 /* enable active counters */ 85 /* enable active counters */
70 for (i = 0; i < NUM_COUNTERS; ++i) { 86 for (i = 0; i < NUM_COUNTERS; ++i) {
71 if (counter_config[i].enabled) { 87 if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs,i))) {
72 reset_value[i] = counter_config[i].count; 88 reset_value[i] = counter_config[i].count;
73 89
74 CTR_WRITE(counter_config[i].count, msrs, i); 90 CTR_WRITE(counter_config[i].count, msrs, i);
@@ -81,6 +97,8 @@ static void ppro_setup_ctrs(struct op_msrs const * const msrs)
81 CTRL_SET_UM(low, counter_config[i].unit_mask); 97 CTRL_SET_UM(low, counter_config[i].unit_mask);
82 CTRL_SET_EVENT(low, counter_config[i].event); 98 CTRL_SET_EVENT(low, counter_config[i].event);
83 CTRL_WRITE(low, high, msrs, i); 99 CTRL_WRITE(low, high, msrs, i);
100 } else {
101 reset_value[i] = 0;
84 } 102 }
85 } 103 }
86} 104}
@@ -93,6 +111,8 @@ static int ppro_check_ctrs(struct pt_regs * const regs,
93 int i; 111 int i;
94 112
95 for (i = 0 ; i < NUM_COUNTERS; ++i) { 113 for (i = 0 ; i < NUM_COUNTERS; ++i) {
114 if (!reset_value[i])
115 continue;
96 CTR_READ(low, high, msrs, i); 116 CTR_READ(low, high, msrs, i);
97 if (CTR_OVERFLOWED(low)) { 117 if (CTR_OVERFLOWED(low)) {
98 oprofile_add_sample(regs, i); 118 oprofile_add_sample(regs, i);
@@ -118,18 +138,38 @@ static int ppro_check_ctrs(struct pt_regs * const regs,
118static void ppro_start(struct op_msrs const * const msrs) 138static void ppro_start(struct op_msrs const * const msrs)
119{ 139{
120 unsigned int low,high; 140 unsigned int low,high;
121 CTRL_READ(low, high, msrs, 0); 141
122 CTRL_SET_ACTIVE(low); 142 if (reset_value[0]) {
123 CTRL_WRITE(low, high, msrs, 0); 143 CTRL_READ(low, high, msrs, 0);
144 CTRL_SET_ACTIVE(low);
145 CTRL_WRITE(low, high, msrs, 0);
146 }
124} 147}
125 148
126 149
127static void ppro_stop(struct op_msrs const * const msrs) 150static void ppro_stop(struct op_msrs const * const msrs)
128{ 151{
129 unsigned int low,high; 152 unsigned int low,high;
130 CTRL_READ(low, high, msrs, 0); 153
131 CTRL_SET_INACTIVE(low); 154 if (reset_value[0]) {
132 CTRL_WRITE(low, high, msrs, 0); 155 CTRL_READ(low, high, msrs, 0);
156 CTRL_SET_INACTIVE(low);
157 CTRL_WRITE(low, high, msrs, 0);
158 }
159}
160
161static void ppro_shutdown(struct op_msrs const * const msrs)
162{
163 int i;
164
165 for (i = 0 ; i < NUM_COUNTERS ; ++i) {
166 if (CTR_IS_RESERVED(msrs,i))
167 release_perfctr_nmi(MSR_P6_PERFCTR0 + i);
168 }
169 for (i = 0 ; i < NUM_CONTROLS ; ++i) {
170 if (CTRL_IS_RESERVED(msrs,i))
171 release_evntsel_nmi(MSR_P6_EVNTSEL0 + i);
172 }
133} 173}
134 174
135 175
@@ -140,5 +180,6 @@ struct op_x86_model_spec const op_ppro_spec = {
140 .setup_ctrs = &ppro_setup_ctrs, 180 .setup_ctrs = &ppro_setup_ctrs,
141 .check_ctrs = &ppro_check_ctrs, 181 .check_ctrs = &ppro_check_ctrs,
142 .start = &ppro_start, 182 .start = &ppro_start,
143 .stop = &ppro_stop 183 .stop = &ppro_stop,
184 .shutdown = &ppro_shutdown
144}; 185};
diff --git a/arch/i386/oprofile/op_x86_model.h b/arch/i386/oprofile/op_x86_model.h
index 123b7e90a9e..abb1aa95b97 100644
--- a/arch/i386/oprofile/op_x86_model.h
+++ b/arch/i386/oprofile/op_x86_model.h
@@ -40,6 +40,7 @@ struct op_x86_model_spec {
40 struct op_msrs const * const msrs); 40 struct op_msrs const * const msrs);
41 void (*start)(struct op_msrs const * const msrs); 41 void (*start)(struct op_msrs const * const msrs);
42 void (*stop)(struct op_msrs const * const msrs); 42 void (*stop)(struct op_msrs const * const msrs);
43 void (*shutdown)(struct op_msrs const * const msrs);
43}; 44};
44 45
45extern struct op_x86_model_spec const op_ppro_spec; 46extern struct op_x86_model_spec const op_ppro_spec;