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 <linux/oprofile.h> 14#include <asm/ptrace.h> 15#include <asm/msr.h> 16#include <asm/nmi.h> 17 18#include "op_x86_model.h" 19#include "op_counter.h" 20 21#define NUM_COUNTERS 4 22#define NUM_CONTROLS 4 23 24#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_WRITE(l,msrs,c) do {wrmsr(msrs->counters[(c)].addr, -(unsigned int)(l), -1);} while (0) 27#define CTR_OVERFLOWED(n) (!((n) & (1U<<31))) 28 29#define CTRL_IS_RESERVED(msrs,c) (msrs->controls[(c)].addr ? 1 : 0) 30#define CTRL_READ(l,h,msrs,c) do {rdmsr(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) 32#define CTRL_SET_ACTIVE(n) (n |= (1<<22)) 33#define CTRL_SET_INACTIVE(n) (n &= ~(1<<22)) 34#define CTRL_CLEAR(x) (x &= (1<<21)) 35#define CTRL_SET_ENABLE(val) (val |= 1<<20) 36#define CTRL_SET_USR(val,u) (val |= ((u & 1) << 16)) 37#define CTRL_SET_KERN(val,k) (val |= ((k & 1) << 17)) 38#define CTRL_SET_UM(val, m) (val |= (m << 8)) 39#define CTRL_SET_EVENT(val, e) (val |= e) 40 41static unsigned long reset_value[NUM_COUNTERS]; 42 43static void athlon_fill_in_addresses(struct op_msrs * const msrs) 44{ 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 } 60} 61 62 63static void athlon_setup_ctrs(struct op_msrs const * const msrs) 64{ 65 unsigned int low, high; 66 int i; 67 68 /* clear all counters */ 69 for (i = 0 ; i < NUM_CONTROLS; ++i) { 70 if (unlikely(!CTRL_IS_RESERVED(msrs,i))) 71 continue; 72 CTRL_READ(low, high, msrs, i); 73 CTRL_CLEAR(low); 74 CTRL_WRITE(low, high, msrs, i); 75 } 76 77 /* avoid a false detection of ctr overflows in NMI handler */ 78 for (i = 0; i < NUM_COUNTERS; ++i) { 79 if (unlikely(!CTR_IS_RESERVED(msrs,i))) 80 continue; 81 CTR_WRITE(1, msrs, i); 82 } 83 84 /* enable active counters */ 85 for (i = 0; i < NUM_COUNTERS; ++i) { 86 if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs,i))) { 87 reset_value[i] = counter_config[i].count; 88 89 CTR_WRITE(counter_config[i].count, msrs, i); 90 91 CTRL_READ(low, high, msrs, i); 92 CTRL_CLEAR(low); 93 CTRL_SET_ENABLE(low); 94 CTRL_SET_USR(low, counter_config[i].user); 95 CTRL_SET_KERN(low, counter_config[i].kernel); 96 CTRL_SET_UM(low, counter_config[i].unit_mask); 97 CTRL_SET_EVENT(low, counter_config[i].event); 98 CTRL_WRITE(low, high, msrs, i); 99 } else { 100 reset_value[i] = 0; 101 } 102 } 103} 104 105 106static int athlon_check_ctrs(struct pt_regs * const regs, 107 struct op_msrs const * const msrs) 108{ 109 unsigned int low, high; 110 int i; 111 112 for (i = 0 ; i < NUM_COUNTERS; ++i) { 113 if (!reset_value[i]) 114 continue; 115 CTR_READ(low, high, msrs, i); 116 if (CTR_OVERFLOWED(low)) { 117 oprofile_add_sample(regs, i); 118 CTR_WRITE(reset_value[i], msrs, i); 119 } 120 } 121 122 /* See op_model_ppro.c */ 123 return 1; 124} 125 126 127static void athlon_start(struct op_msrs const * const msrs) 128{ 129 unsigned int low, high; 130 int i; 131 for (i = 0 ; i < NUM_COUNTERS ; ++i) { 132 if (reset_value[i]) { 133 CTRL_READ(low, high, msrs, i); 134 CTRL_SET_ACTIVE(low); 135 CTRL_WRITE(low, high, msrs, i); 136 } 137 } 138} 139 140 141static void athlon_stop(struct op_msrs const * const msrs) 142{ 143 unsigned int low,high; 144 int i; 145 146 /* Subtle: stop on all counters to avoid race with 147 * setting our pm callback */ 148 for (i = 0 ; i < NUM_COUNTERS ; ++i) { 149 if (!reset_value[i]) 150 continue; 151 CTRL_READ(low, high, msrs, i); 152 CTRL_SET_INACTIVE(low); 153 CTRL_WRITE(low, high, msrs, i); 154 } 155} 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} 170 171struct op_x86_model_spec const op_athlon_spec = { 172 .num_counters = NUM_COUNTERS, 173 .num_controls = NUM_CONTROLS, 174 .fill_in_addresses = &athlon_fill_in_addresses, 175 .setup_ctrs = &athlon_setup_ctrs, 176 .check_ctrs = &athlon_check_ctrs, 177 .start = &athlon_start, 178 .stop = &athlon_stop, 179 .shutdown = &athlon_shutdown 180}; 181