Home | History | Annotate | Download | only in x86
      1 /**
      2  * @file op_model_athlon.h
      3  * athlon / K7 model-specific MSR operations
      4  *
      5  * @remark Copyright 2002 OProfile authors
      6  * @remark Read the file COPYING
      7  *
      8  * @author John Levon
      9  * @author Philippe Elie
     10  * @author Graydon Hoare
     11  */
     12 
     13 #include "op_x86_model.h"
     14 #include "op_arch.h"
     15 #include "op_msr.h"
     16 
     17 #define NUM_COUNTERS 4
     18 #define NUM_CONTROLS 4
     19 
     20 #define CTR_READ(l, h, msrs, c) do {rdmsr(msrs->counters.addrs[(c)], (l), (h));} while (0)
     21 #define CTR_WRITE(l, msrs, c) do {wrmsr(msrs->counters.addrs[(c)], -(u32)(l), 0xffff);} while (0)
     22 #define CTR_OVERFLOWED(n) (!((n) & (1U << 31)))
     23 
     24 #define CTRL_READ(l, h, msrs, c) do {rdmsr(msrs->controls.addrs[(c)], (l), (h));} while (0)
     25 #define CTRL_WRITE(l, h, msrs, c) do {wrmsr(msrs->controls.addrs[(c)], (l), (h));} while (0)
     26 #define CTRL_SET_ACTIVE(n) (n |= (1 << 22))
     27 #define CTRL_SET_INACTIVE(n) (n &= ~(1 << 22))
     28 #define CTRL_CLEAR(x) (x &= (1 << 21))
     29 #define CTRL_SET_ENABLE(val) (val |= 1 << 20)
     30 #define CTRL_SET_USR(val, u) (val |= ((u & 1) << 16))
     31 #define CTRL_SET_KERN(val, k) (val |= ((k & 1) << 17))
     32 #define CTRL_SET_UM(val, m) (val |= (m << 8))
     33 #define CTRL_SET_EVENT(val, e) (val |= e)
     34 
     35 
     36 static void athlon_fill_in_addresses(struct op_msrs * const msrs)
     37 {
     38 	msrs->counters.addrs[0] = MSR_K7_PERFCTR0;
     39 	msrs->counters.addrs[1] = MSR_K7_PERFCTR1;
     40 	msrs->counters.addrs[2] = MSR_K7_PERFCTR2;
     41 	msrs->counters.addrs[3] = MSR_K7_PERFCTR3;
     42 
     43 	msrs->controls.addrs[0] = MSR_K7_EVNTSEL0;
     44 	msrs->controls.addrs[1] = MSR_K7_EVNTSEL1;
     45 	msrs->controls.addrs[2] = MSR_K7_EVNTSEL2;
     46 	msrs->controls.addrs[3] = MSR_K7_EVNTSEL3;
     47 }
     48 
     49 
     50 static void athlon_setup_ctrs(struct op_msrs const * const msrs)
     51 {
     52 	uint low, high;
     53 	int i;
     54 
     55 	/* clear all counters */
     56 	for (i = 0 ; i < NUM_CONTROLS; ++i) {
     57 		CTRL_READ(low, high, msrs, i);
     58 		CTRL_CLEAR(low);
     59 		CTRL_WRITE(low, high, msrs, i);
     60 	}
     61 
     62 	/* avoid a false detection of ctr overflows in NMI handler */
     63 	for (i = 0; i < NUM_COUNTERS; ++i)
     64 		CTR_WRITE(1, msrs, i);
     65 
     66 	/* enable active counters */
     67 	for (i = 0; i < NUM_COUNTERS; ++i) {
     68 		if (sysctl.ctr[i].enabled) {
     69 
     70 			CTR_WRITE(sysctl.ctr[i].count, msrs, i);
     71 
     72 			CTRL_READ(low, high, msrs, i);
     73 			CTRL_CLEAR(low);
     74 			CTRL_SET_ENABLE(low);
     75 			CTRL_SET_USR(low, sysctl.ctr[i].user);
     76 			CTRL_SET_KERN(low, sysctl.ctr[i].kernel);
     77 			CTRL_SET_UM(low, sysctl.ctr[i].unit_mask);
     78 			CTRL_SET_EVENT(low, sysctl.ctr[i].event);
     79 			CTRL_WRITE(low, high, msrs, i);
     80 		}
     81 	}
     82 }
     83 
     84 
     85 static void athlon_check_ctrs(uint const cpu,
     86 			      struct op_msrs const * const msrs,
     87 			      struct pt_regs * const regs)
     88 {
     89 	uint low, high;
     90 	int i;
     91 	for (i = 0 ; i < NUM_COUNTERS; ++i) {
     92 		if (sysctl.ctr[i].enabled) {
     93 			CTR_READ(low, high, msrs, i);
     94 			if (CTR_OVERFLOWED(low)) {
     95 				op_do_profile(cpu, instruction_pointer(regs), IRQ_ENABLED(regs), i);
     96 				CTR_WRITE(oprof_data[cpu].ctr_count[i], msrs, i);
     97 			}
     98 		}
     99 	}
    100 }
    101 
    102 
    103 static void athlon_start(struct op_msrs const * const msrs)
    104 {
    105 	uint low, high;
    106 	int i;
    107 	for (i = 0 ; i < NUM_COUNTERS ; ++i) {
    108 		if (sysctl.ctr[i].enabled) {
    109 			CTRL_READ(low, high, msrs, i);
    110 			CTRL_SET_ACTIVE(low);
    111 			CTRL_WRITE(low, high, msrs, i);
    112 		}
    113 	}
    114 }
    115 
    116 
    117 static void athlon_stop(struct op_msrs const * const msrs)
    118 {
    119 	uint low, high;
    120 	int i;
    121 	for (i = 0 ; i < NUM_COUNTERS ; ++i) {
    122 		if (sysctl.ctr[i].enabled) {
    123 			CTRL_READ(low, high, msrs, i);
    124 			CTRL_SET_INACTIVE(low);
    125 			CTRL_WRITE(low, high, msrs, i);
    126 		}
    127 	}
    128 }
    129 
    130 
    131 struct op_x86_model_spec const op_athlon_spec = {
    132 	.num_counters = NUM_COUNTERS,
    133 	.num_controls = NUM_CONTROLS,
    134 	.fill_in_addresses = &athlon_fill_in_addresses,
    135 	.setup_ctrs = &athlon_setup_ctrs,
    136 	.check_ctrs = &athlon_check_ctrs,
    137 	.start = &athlon_start,
    138 	.stop = &athlon_stop
    139 };
    140