History

[PATCH] i386: Utilize performance counter reservation framework in oprofile

Incorporates the new performance counter reservation system in oprofile. Also cleans up a lot of the initialization code. The code original zero'd out every register associated with performance counters regardless if those registers were used or not. This causes issues with the nmi watchdog. Now oprofile tries to reserve registers and gives up if it can't get them. Cc: levon@movementarian.org Cc: oprofile-list@lists.sf.net

Don Zickus committed 20 years ago

Commit cb9c4481 parent 828f0af5 files · +199 −114Browse files

Unified · Split

5 files
  1. arch/i386/oprofile/nmi_int.c +29 −12
  2. arch/i386/oprofile/op_model_athlon.c +42 −12
  3. arch/i386/oprofile/op_model_p4.c +74 −78
  4. arch/i386/oprofile/op_model_ppro.c +53 −12
  5. arch/i386/oprofile/op_x86_model.h +1 −0
arch/i386/oprofile/nmi_int.c+29−12
@@ -98,15 +98,19 @@ static void nmi_cpu_save_registers(struct op_msrs * msrs) · 97 unmodified lines
9898 unsigned int i;
9999
100100 for (i = 0; i < nr_ctrs; ++i) {
101− rdmsr(counters[i].addr,
102− counters[i].saved.low,
103− counters[i].saved.high);
101+ if (counters[i].addr){
102+ rdmsr(counters[i].addr,
103+ counters[i].saved.low,
104+ counters[i].saved.high);
105+ }
104106 }
105107
106108 for (i = 0; i < nr_ctrls; ++i) {
107− rdmsr(controls[i].addr,
108− controls[i].saved.low,
109− controls[i].saved.high);
109+ if (controls[i].addr){
110+ rdmsr(controls[i].addr,
111+ controls[i].saved.low,
112+ controls[i].saved.high);
113+ }
110114 }
111115 }
112116
@@ -205,15 +209,19 @@ static void nmi_restore_registers(struct op_msrs * msrs) · 92 unmodified lines
205209 unsigned int i;
206210
207211 for (i = 0; i < nr_ctrls; ++i) {
208− wrmsr(controls[i].addr,
209− controls[i].saved.low,
210− controls[i].saved.high);
212+ if (controls[i].addr){
213+ wrmsr(controls[i].addr,
214+ controls[i].saved.low,
215+ controls[i].saved.high);
216+ }
211217 }
212218
213219 for (i = 0; i < nr_ctrs; ++i) {
214− wrmsr(counters[i].addr,
215− counters[i].saved.low,
216− counters[i].saved.high);
220+ if (counters[i].addr){
221+ wrmsr(counters[i].addr,
222+ counters[i].saved.low,
223+ counters[i].saved.high);
224+ }
217225 }
218226 }
219227
@@ -234,6 +242,7 @@ static void nmi_cpu_shutdown(void * dummy) · 14 unmodified lines
234242 apic_write(APIC_LVTPC, saved_lvtpc[cpu]);
235243 apic_write(APIC_LVTERR, v);
236244 nmi_restore_registers(msrs);
245+ model->shutdown(msrs);
237246 }
238247
239248
@@ -284,6 +293,14 @@ static int nmi_create_files(struct super_block * sb, struct dentry * root) · 44 unmodified lines
284293 struct dentry * dir;
285294 char buf[4];
286295
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+
287304 snprintf(buf, sizeof(buf), "%d", i);
288305 dir = oprofilefs_mkdir(sb, root, buf);
289306 oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled);
arch/i386/oprofile/op_model_athlon.c+42−12
@@ -21,10 +21,12 @@ · 20 unmodified lines
2121 #define NUM_COUNTERS 4
2222 #define NUM_CONTROLS 4
2323
24+#define CTR_IS_RESERVED(msrs,c) (msrs->counters[(c)].addr ? 1 : 0)
2425 #define CTR_READ(l,h,msrs,c) do {rdmsr(msrs->counters[(c)].addr, (l), (h));} while (0)
2526 #define CTR_WRITE(l,msrs,c) do {wrmsr(msrs->counters[(c)].addr, -(unsigned int)(l), -1);} while (0)
2627 #define CTR_OVERFLOWED(n) (!((n) & (1U<<31)))
2728
29+#define CTRL_IS_RESERVED(msrs,c) (msrs->controls[(c)].addr ? 1 : 0)
2830 #define CTRL_READ(l,h,msrs,c) do {rdmsr(msrs->controls[(c)].addr, (l), (h));} while (0)
2931 #define CTRL_WRITE(l,h,msrs,c) do {wrmsr(msrs->controls[(c)].addr, (l), (h));} while (0)
3032 #define CTRL_SET_ACTIVE(n) (n |= (1<<22))
@@ -40,15 +42,21 @@ static unsigned long reset_value[NUM_COUNTERS]; · 9 unmodified lines
4042
4143 static void athlon_fill_in_addresses(struct op_msrs * const msrs)
4244 {
43− msrs->counters[0].addr = MSR_K7_PERFCTR0;
44− msrs->counters[1].addr = MSR_K7_PERFCTR1;
45− msrs->counters[2].addr = MSR_K7_PERFCTR2;
46− msrs->counters[3].addr = MSR_K7_PERFCTR3;
47−
48− msrs->controls[0].addr = MSR_K7_EVNTSEL0;
49− msrs->controls[1].addr = MSR_K7_EVNTSEL1;
50− msrs->controls[2].addr = MSR_K7_EVNTSEL2;
51− msrs->controls[3].addr = MSR_K7_EVNTSEL3;
45+ int i;
46+
47+ for (i=0; i < NUM_COUNTERS; i++) {
48+ if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i))
49+ msrs->counters[i].addr = MSR_K7_PERFCTR0 + i;
50+ else
51+ msrs->counters[i].addr = 0;
52+ }
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+ }
5260 }
5361
5462
@@ -59,19 +67,23 @@ static void athlon_setup_ctrs(struct op_msrs const * const msrs) · 4 unmodified lines
5967
6068 /* clear all counters */
6169 for (i = 0 ; i < NUM_CONTROLS; ++i) {
70+ if (unlikely(!CTRL_IS_RESERVED(msrs,i)))
71+ continue;
6272 CTRL_READ(low, high, msrs, i);
6373 CTRL_CLEAR(low);
6474 CTRL_WRITE(low, high, msrs, i);
6575 }
66−
76+
6777 /* avoid a false detection of ctr overflows in NMI handler */
6878 for (i = 0; i < NUM_COUNTERS; ++i) {
79+ if (unlikely(!CTR_IS_RESERVED(msrs,i)))
80+ continue;
6981 CTR_WRITE(1, msrs, i);
7082 }
7183
7284 /* enable active counters */
7385 for (i = 0; i < NUM_COUNTERS; ++i) {
74− if (counter_config[i].enabled) {
86+ if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs,i))) {
7587 reset_value[i] = counter_config[i].count;
7688
7789 CTR_WRITE(counter_config[i].count, msrs, i);
@@ -98,6 +110,8 @@ static int athlon_check_ctrs(struct pt_regs * const regs, · 20 unmodified lines
98110 int i;
99111
100112 for (i = 0 ; i < NUM_COUNTERS; ++i) {
113+ if (!reset_value[i])
114+ continue;
101115 CTR_READ(low, high, msrs, i);
102116 if (CTR_OVERFLOWED(low)) {
103117 oprofile_add_sample(regs, i);
@@ -132,12 +146,27 @@ static void athlon_stop(struct op_msrs const * const msrs) · 28 unmodified lines
132146 /* Subtle: stop on all counters to avoid race with
133147 * setting our pm callback */
134148 for (i = 0 ; i < NUM_COUNTERS ; ++i) {
149+ if (!reset_value[i])
150+ continue;
135151 CTRL_READ(low, high, msrs, i);
136152 CTRL_SET_INACTIVE(low);
137153 CTRL_WRITE(low, high, msrs, i);
138154 }
139155 }
140156
157+static 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+}
141170
142171 struct op_x86_model_spec const op_athlon_spec = {
143172 .num_counters = NUM_COUNTERS,
@@ -146,5 +175,6 @@ struct op_x86_model_spec const op_athlon_spec = { · 2 unmodified lines
146175 .setup_ctrs = &athlon_setup_ctrs,
147176 .check_ctrs = &athlon_check_ctrs,
148177 .start = &athlon_start,
149− .stop = &athlon_stop
178+ .stop = &athlon_stop,
179+ .shutdown = &athlon_shutdown
150180 };
arch/i386/oprofile/op_model_p4.c+74−78
@@ -32,7 +32,7 @@ · 31 unmodified lines
3232 #define NUM_CONTROLS_HT2 (NUM_ESCRS_HT2 + NUM_CCCRS_HT2)
3333
3434 static unsigned int num_counters = NUM_COUNTERS_NON_HT;
35−
35+static unsigned int num_controls = NUM_CONTROLS_NON_HT;
3636
3737 /* this has to be checked dynamically since the
3838 hyper-threadedness of a chip is discovered at
@@ -40,8 +40,10 @@ static unsigned int num_counters = NUM_COUNTERS_NON_HT; · 1 unmodified line
4040 static inline void setup_num_counters(void)
4141 {
4242 #ifdef CONFIG_SMP
43− if (smp_num_siblings == 2)
43+ if (smp_num_siblings == 2){
4444 num_counters = NUM_COUNTERS_HT2;
45+ num_controls = NUM_CONTROLS_HT2;
46+ }
4547 #endif
4648 }
4749
@@ -97,15 +99,6 @@ static struct p4_counter_binding p4_counters [NUM_COUNTERS_NON_HT] = { · 49 unmodified lines
9799
98100 #define NUM_UNUSED_CCCRS NUM_CCCRS_NON_HT - NUM_COUNTERS_NON_HT
99101
100−/* All cccr we don't use. */
101−static 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−
109102 /* p4 event codes in libop/op_event.h are indices into this table. */
110103
111104 static struct p4_event_binding p4_events[NUM_EVENTS] = {
@@ -372,6 +365,8 @@ static struct p4_event_binding p4_events[NUM_EVENTS] = { · 260 unmodified lines
372365 #define CCCR_OVF_P(cccr) ((cccr) & (1U<<31))
373366 #define CCCR_CLEAR_OVF(cccr) ((cccr) &= (~(1U<<31)))
374367
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)
375370 #define CTR_READ(l,h,i) do {rdmsr(p4_counters[(i)].counter_address, (l), (h));} while (0)
376371 #define CTR_WRITE(l,i) do {wrmsr(p4_counters[(i)].counter_address, -(u32)(l), -1);} while (0)
377372 #define CTR_OVERFLOW_P(ctr) (!((ctr) & 0x80000000))
@@ -401,29 +396,34 @@ static unsigned long reset_value[NUM_COUNTERS_NON_HT]; · 23 unmodified lines
401396 static void p4_fill_in_addresses(struct op_msrs * const msrs)
402397 {
403398 unsigned int i;
404− unsigned int addr, stag;
399+ unsigned int addr, cccraddr, stag;
405400
406401 setup_num_counters();
407402 stag = get_stagger();
408403
409− /* the counter registers we pay attention to */
404+ /* initialize some registers */
410405 for (i = 0; i < num_counters; ++i) {
411− msrs->counters[i].addr =
412− p4_counters[VIRT_CTR(stag, i)].counter_address;
406+ msrs->counters[i].addr = 0;
413407 }
414−
415− /* FIXME: bad feeling, we don't save the 10 counters we don't use. */
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;
408+ for (i = 0; i < num_controls; ++i) {
409+ msrs->controls[i].addr = 0;
421410 }
422411
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+
423422 /* 43 ESCR registers in three or four discontiguous group */
424423 for (addr = MSR_P4_BSU_ESCR0 + stag;
425424 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;
427427 }
428428
429429 /* 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) · 1 unmodified line
431431 if (boot_cpu_data.x86_model >= 0x3) {
432432 for (addr = MSR_P4_BSU_ESCR0 + stag;
433433 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;
435436 }
436437 } else {
437438 for (addr = MSR_P4_IQ_ESCR0 + stag;
438439 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;
440442 }
441443 }
442444
443445 for (addr = MSR_P4_RAT_ESCR0 + stag;
444446 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;
446449 }
447450
448451 for (addr = MSR_P4_MS_ESCR0 + stag;
449452 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;
451455 }
452456
453457 for (addr = MSR_P4_IX_ESCR0 + stag;
454458 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;
456461 }
457462
458463 /* there are 2 remaining non-contiguously located ESCRs */
459464
460465 if (num_counters == NUM_COUNTERS_NON_HT) {
461466 /* standard non-HT CPUs handle both remaining ESCRs*/
462− msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
463− msrs->controls[i++].addr = MSR_P4_CRU_ESCR4;
467+ if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR5))
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;
464471
465472 } else if (stag == 0) {
466473 /* HT CPUs give the first remainder to the even thread, as
467474 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;
469477
470478 } else {
471479 /* and two copies of the second to the odd thread,
472480 for the 22st and 23nd control registers */
473− msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
474− msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
481+ if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR5)) {
482+ msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
483+ msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
484+ }
475485 }
476486 }
477487
@@ -544,7 +554,6 @@ static void p4_setup_ctrs(struct op_msrs const * const msrs) · 66 unmodified lines
544554 {
545555 unsigned int i;
546556 unsigned int low, high;
547− unsigned int addr;
548557 unsigned int stag;
549558
550559 stag = get_stagger();
@@ -557,59 +566,24 @@ static void p4_setup_ctrs(struct op_msrs const * const msrs) · 6 unmodified lines
557566
558567 /* clear the cccrs we will use */
559568 for (i = 0 ; i < num_counters ; i++) {
569+ if (unlikely(!CTRL_IS_RESERVED(msrs,i)))
570+ continue;
560571 rdmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
561572 CCCR_CLEAR(low);
562573 CCCR_SET_REQUIRED_BITS(low);
563574 wrmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
564575 }
565576
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−
574577 /* clear all escrs (including those outside our concern) */
575− for (addr = MSR_P4_BSU_ESCR0 + stag;
576− addr < MSR_P4_IQ_ESCR0; addr += addr_increment()) {
577− wrmsr(addr, 0, 0);
578− }
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);
578+ for (i = num_counters; i < num_controls; i++) {
579+ if (unlikely(!CTRL_IS_RESERVED(msrs,i)))
580+ continue;
581+ wrmsr(msrs->controls[i].addr, 0, 0);
599582 }
600583
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−
610584 /* setup all counters */
611585 for (i = 0 ; i < num_counters ; ++i) {
612− if (counter_config[i].enabled) {
586+ if ((counter_config[i].enabled) && (CTRL_IS_RESERVED(msrs,i))) {
613587 reset_value[i] = counter_config[i].count;
614588 pmc_setup_one_p4_counter(i);
615589 CTR_WRITE(counter_config[i].count, VIRT_CTR(stag, i));
@@ -696,12 +670,32 @@ static void p4_stop(struct op_msrs const * const msrs) · 80 unmodified lines
696670 stag = get_stagger();
697671
698672 for (i = 0; i < num_counters; ++i) {
673+ if (!reset_value[i])
674+ continue;
699675 CCCR_READ(low, high, VIRT_CTR(stag, i));
700676 CCCR_SET_DISABLE(low);
701677 CCCR_WRITE(low, high, VIRT_CTR(stag, i));
702678 }
703679 }
704680
681+static 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+
705699
706700 #ifdef CONFIG_SMP
707701 struct op_x86_model_spec const op_p4_ht2_spec = {
@@ -711,7 +705,8 @@ struct op_x86_model_spec const op_p4_ht2_spec = { · 3 unmodified lines
711705 .setup_ctrs = &p4_setup_ctrs,
712706 .check_ctrs = &p4_check_ctrs,
713707 .start = &p4_start,
714− .stop = &p4_stop
708+ .stop = &p4_stop,
709+ .shutdown = &p4_shutdown
715710 };
716711 #endif
717712
@@ -722,5 +717,6 @@ struct op_x86_model_spec const op_p4_spec = { · 4 unmodified lines
722717 .setup_ctrs = &p4_setup_ctrs,
723718 .check_ctrs = &p4_check_ctrs,
724719 .start = &p4_start,
725− .stop = &p4_stop
720+ .stop = &p4_stop,
721+ .shutdown = &p4_shutdown
726722 };
arch/i386/oprofile/op_model_ppro.c+53−12
@@ -22,10 +22,12 @@ · 21 unmodified lines
2222 #define NUM_COUNTERS 2
2323 #define NUM_CONTROLS 2
2424
25+#define CTR_IS_RESERVED(msrs,c) (msrs->counters[(c)].addr ? 1 : 0)
2526 #define CTR_READ(l,h,msrs,c) do {rdmsr(msrs->counters[(c)].addr, (l), (h));} while (0)
2627 #define CTR_WRITE(l,msrs,c) do {wrmsr(msrs->counters[(c)].addr, -(u32)(l), -1);} while (0)
2728 #define CTR_OVERFLOWED(n) (!((n) & (1U<<31)))
2829
30+#define CTRL_IS_RESERVED(msrs,c) (msrs->controls[(c)].addr ? 1 : 0)
2931 #define CTRL_READ(l,h,msrs,c) do {rdmsr((msrs->controls[(c)].addr), (l), (h));} while (0)
3032 #define CTRL_WRITE(l,h,msrs,c) do {wrmsr((msrs->controls[(c)].addr), (l), (h));} while (0)
3133 #define CTRL_SET_ACTIVE(n) (n |= (1<<22))
@@ -41,11 +43,21 @@ static unsigned long reset_value[NUM_COUNTERS]; · 9 unmodified lines
4143
4244 static void ppro_fill_in_addresses(struct op_msrs * const msrs)
4345 {
44− msrs->counters[0].addr = MSR_P6_PERFCTR0;
45− msrs->counters[1].addr = MSR_P6_PERFCTR1;
46+ int i;
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+ }
4654
47− msrs->controls[0].addr = MSR_P6_EVNTSEL0;
48− msrs->controls[1].addr = MSR_P6_EVNTSEL1;
55+ for (i=0; i < NUM_CONTROLS; i++) {
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+ }
4961 }
5062
5163
@@ -56,6 +68,8 @@ static void ppro_setup_ctrs(struct op_msrs const * const msrs) · 4 unmodified lines
5668
5769 /* clear all counters */
5870 for (i = 0 ; i < NUM_CONTROLS; ++i) {
71+ if (unlikely(!CTRL_IS_RESERVED(msrs,i)))
72+ continue;
5973 CTRL_READ(low, high, msrs, i);
6074 CTRL_CLEAR(low);
6175 CTRL_WRITE(low, high, msrs, i);
@@ -63,12 +77,14 @@ static void ppro_setup_ctrs(struct op_msrs const * const msrs) · 1 unmodified line
6377
6478 /* avoid a false detection of ctr overflows in NMI handler */
6579 for (i = 0; i < NUM_COUNTERS; ++i) {
80+ if (unlikely(!CTR_IS_RESERVED(msrs,i)))
81+ continue;
6682 CTR_WRITE(1, msrs, i);
6783 }
6884
6985 /* enable active counters */
7086 for (i = 0; i < NUM_COUNTERS; ++i) {
71− if (counter_config[i].enabled) {
87+ if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs,i))) {
7288 reset_value[i] = counter_config[i].count;
7389
7490 CTR_WRITE(counter_config[i].count, msrs, i);
@@ -81,6 +97,8 @@ static void ppro_setup_ctrs(struct op_msrs const * const msrs) · 6 unmodified lines
8197 CTRL_SET_UM(low, counter_config[i].unit_mask);
8298 CTRL_SET_EVENT(low, counter_config[i].event);
8399 CTRL_WRITE(low, high, msrs, i);
100+ } else {
101+ reset_value[i] = 0;
84102 }
85103 }
86104 }
@@ -93,6 +111,8 @@ static int ppro_check_ctrs(struct pt_regs * const regs, · 6 unmodified lines
93111 int i;
94112
95113 for (i = 0 ; i < NUM_COUNTERS; ++i) {
114+ if (!reset_value[i])
115+ continue;
96116 CTR_READ(low, high, msrs, i);
97117 if (CTR_OVERFLOWED(low)) {
98118 oprofile_add_sample(regs, i);
@@ -118,18 +138,38 @@ static int ppro_check_ctrs(struct pt_regs * const regs, · 19 unmodified lines
118138 static void ppro_start(struct op_msrs const * const msrs)
119139 {
120140 unsigned int low,high;
121− CTRL_READ(low, high, msrs, 0);
122− CTRL_SET_ACTIVE(low);
123− CTRL_WRITE(low, high, msrs, 0);
141+
142+ if (reset_value[0]) {
143+ CTRL_READ(low, high, msrs, 0);
144+ CTRL_SET_ACTIVE(low);
145+ CTRL_WRITE(low, high, msrs, 0);
146+ }
124147 }
125148
126149
127150 static void ppro_stop(struct op_msrs const * const msrs)
128151 {
129152 unsigned int low,high;
130− CTRL_READ(low, high, msrs, 0);
131− CTRL_SET_INACTIVE(low);
132− CTRL_WRITE(low, high, msrs, 0);
153+
154+ if (reset_value[0]) {
155+ CTRL_READ(low, high, msrs, 0);
156+ CTRL_SET_INACTIVE(low);
157+ CTRL_WRITE(low, high, msrs, 0);
158+ }
159+}
160+
161+static 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+ }
133173 }
134174
135175
@@ -140,5 +180,6 @@ struct op_x86_model_spec const op_ppro_spec = { · 4 unmodified lines
140180 .setup_ctrs = &ppro_setup_ctrs,
141181 .check_ctrs = &ppro_check_ctrs,
142182 .start = &ppro_start,
143− .stop = &ppro_stop
183+ .stop = &ppro_stop,
184+ .shutdown = &ppro_shutdown
144185 };
arch/i386/oprofile/op_x86_model.h+1−0
@@ -40,6 +40,7 @@ struct op_x86_model_spec { · 39 unmodified lines
4040 struct op_msrs const * const msrs);
4141 void (*start)(struct op_msrs const * const msrs);
4242 void (*stop)(struct op_msrs const * const msrs);
43+ void (*shutdown)(struct op_msrs const * const msrs);
4344 };
4445
4546 extern struct op_x86_model_spec const op_ppro_spec;