1 /** 2 * @file op_model_ppro.h 3 * pentium pro / P6 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 2 18 #define NUM_CONTROLS 2 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), -1);} 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 ppro_fill_in_addresses(struct op_msrs * const msrs) 37 { 38 msrs->counters.addrs[0] = MSR_P6_PERFCTR0; 39 msrs->counters.addrs[1] = MSR_P6_PERFCTR1; 40 41 msrs->controls.addrs[0] = MSR_P6_EVNTSEL0; 42 msrs->controls.addrs[1] = MSR_P6_EVNTSEL1; 43 } 44 45 46 static void ppro_setup_ctrs(struct op_msrs const * const msrs) 47 { 48 uint low, high; 49 int i; 50 51 /* clear all counters */ 52 for (i = 0 ; i < NUM_CONTROLS; ++i) { 53 CTRL_READ(low, high, msrs, i); 54 CTRL_CLEAR(low); 55 CTRL_WRITE(low, high, msrs, i); 56 } 57 58 /* avoid a false detection of ctr overflows in NMI handler */ 59 for (i = 0; i < NUM_COUNTERS; ++i) 60 CTR_WRITE(1, msrs, i); 61 62 /* enable active counters */ 63 for (i = 0; i < NUM_COUNTERS; ++i) { 64 if (sysctl.ctr[i].enabled) { 65 66 CTR_WRITE(sysctl.ctr[i].count, msrs, i); 67 68 CTRL_READ(low, high, msrs, i); 69 CTRL_CLEAR(low); 70 CTRL_SET_ENABLE(low); 71 CTRL_SET_USR(low, sysctl.ctr[i].user); 72 CTRL_SET_KERN(low, sysctl.ctr[i].kernel); 73 CTRL_SET_UM(low, sysctl.ctr[i].unit_mask); 74 CTRL_SET_EVENT(low, sysctl.ctr[i].event); 75 CTRL_WRITE(low, high, msrs, i); 76 } 77 } 78 } 79 80 81 static void ppro_check_ctrs(uint const cpu, 82 struct op_msrs const * const msrs, 83 struct pt_regs * const regs) 84 { 85 ulong low, high; 86 int i; 87 for (i = 0 ; i < NUM_COUNTERS; ++i) { 88 CTR_READ(low, high, msrs, i); 89 if (CTR_OVERFLOWED(low)) { 90 op_do_profile(cpu, instruction_pointer(regs), IRQ_ENABLED(regs), i); 91 CTR_WRITE(oprof_data[cpu].ctr_count[i], msrs, i); 92 } 93 } 94 } 95 96 97 static void ppro_start(struct op_msrs const * const msrs) 98 { 99 uint low, high; 100 CTRL_READ(low, high, msrs, 0); 101 CTRL_SET_ACTIVE(low); 102 CTRL_WRITE(low, high, msrs, 0); 103 } 104 105 106 static void ppro_stop(struct op_msrs const * const msrs) 107 { 108 uint low, high; 109 CTRL_READ(low, high, msrs, 0); 110 CTRL_SET_INACTIVE(low); 111 CTRL_WRITE(low, high, msrs, 0); 112 } 113 114 115 struct op_x86_model_spec const op_ppro_spec = { 116 .num_counters = NUM_COUNTERS, 117 .num_controls = NUM_CONTROLS, 118 .fill_in_addresses = &ppro_fill_in_addresses, 119 .setup_ctrs = &ppro_setup_ctrs, 120 .check_ctrs = &ppro_check_ctrs, 121 .start = &ppro_start, 122 .stop = &ppro_stop 123 }; 124