Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/arch/x86/oprofile/op_model_ppro.c
Line
Count
Source (jump to first uncovered line)
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 <xen/types.h>
14
#include <xen/xenoprof.h>
15
#include <xen/sched.h>
16
#include <asm/msr.h>
17
#include <asm/io.h>
18
#include <asm/apic.h>
19
#include <asm/processor.h>
20
#include <asm/regs.h>
21
#include <asm/current.h>
22
#include <asm/vpmu.h>
23
24
#include "op_x86_model.h"
25
#include "op_counter.h"
26
27
struct arch_msr_pair {
28
    u64 counter;
29
    u64 control;
30
};
31
32
/*
33
 * Intel "Architectural Performance Monitoring" CPUID
34
 * detection/enumeration details:
35
 */
36
union cpuid10_eax {
37
  struct {
38
    unsigned int version_id:8;
39
    unsigned int num_counters:8;
40
    unsigned int bit_width:8;
41
    unsigned int mask_length:8;
42
  } split;
43
  unsigned int full;
44
};
45
46
static int num_counters = 2;
47
static int counter_width = 32;
48
49
0
#define CTR_OVERFLOWED(n) (!((n) & (1ULL<<(counter_width-1))))
50
51
0
#define CTRL_READ(msr_content,msrs,c) do {rdmsrl((msrs->controls[(c)].addr), (msr_content));} while (0)
52
0
#define CTRL_WRITE(msr_content,msrs,c) do {wrmsrl((msrs->controls[(c)].addr), (msr_content));} while (0)
53
0
#define CTRL_SET_ACTIVE(n) (n |= (1ULL<<22))
54
0
#define CTRL_SET_INACTIVE(n) (n &= ~(1ULL<<22))
55
0
#define CTRL_CLEAR(x) (x &= (1ULL<<21))
56
0
#define CTRL_SET_ENABLE(val) (val |= 1ULL<<20)
57
0
#define CTRL_SET_USR(val,u) (val |= ((u & 1ULL) << 16))
58
0
#define CTRL_SET_KERN(val,k) (val |= ((k & 1ULL) << 17))
59
0
#define CTRL_SET_UM(val, m) (val |= (m << 8))
60
0
#define CTRL_SET_EVENT(val, e) (val |= e)
61
0
#define IS_ACTIVE(val) (val & (1ULL << 22) )
62
0
#define IS_ENABLE(val) (val & (1ULL << 20) )
63
static unsigned long reset_value[OP_MAX_COUNTER];
64
int ppro_has_global_ctrl = 0;
65
66
static void ppro_fill_in_addresses(struct op_msrs * const msrs)
67
0
{
68
0
  int i;
69
0
70
0
  for (i = 0; i < num_counters; i++)
71
0
    msrs->counters[i].addr = MSR_P6_PERFCTR(i);
72
0
  for (i = 0; i < num_counters; i++)
73
0
    msrs->controls[i].addr = MSR_P6_EVNTSEL(i);
74
0
}
75
76
77
static void ppro_setup_ctrs(struct op_msrs const * const msrs)
78
0
{
79
0
  uint64_t msr_content;
80
0
  int i;
81
0
82
0
  if (cpu_has_arch_perfmon) {
83
0
    union cpuid10_eax eax;
84
0
    eax.full = cpuid_eax(0xa);
85
0
86
0
    /*
87
0
     * For Core2 (family 6, model 15), don't reset the
88
0
     * counter width:
89
0
     */
90
0
    if (!(eax.split.version_id == 0 &&
91
0
      current_cpu_data.x86 == 6 &&
92
0
        current_cpu_data.x86_model == 15)) {
93
0
94
0
      if (counter_width < eax.split.bit_width)
95
0
        counter_width = eax.split.bit_width;
96
0
    }
97
0
  }
98
0
99
0
  /* clear all counters */
100
0
  for (i = 0 ; i < num_counters; ++i) {
101
0
    CTRL_READ(msr_content, msrs, i);
102
0
    CTRL_CLEAR(msr_content);
103
0
    CTRL_WRITE(msr_content, msrs, i);
104
0
  }
105
0
106
0
  /* avoid a false detection of ctr overflows in NMI handler */
107
0
  for (i = 0; i < num_counters; ++i)
108
0
    wrmsrl(msrs->counters[i].addr, ~0x0ULL);
109
0
110
0
  /* enable active counters */
111
0
  for (i = 0; i < num_counters; ++i) {
112
0
    if (counter_config[i].enabled) {
113
0
      reset_value[i] = counter_config[i].count;
114
0
115
0
      wrmsrl(msrs->counters[i].addr, -reset_value[i]);
116
0
117
0
      CTRL_READ(msr_content, msrs, i);
118
0
      CTRL_CLEAR(msr_content);
119
0
      CTRL_SET_ENABLE(msr_content);
120
0
      CTRL_SET_USR(msr_content, counter_config[i].user);
121
0
      CTRL_SET_KERN(msr_content, counter_config[i].kernel);
122
0
      CTRL_SET_UM(msr_content, counter_config[i].unit_mask);
123
0
      CTRL_SET_EVENT(msr_content, counter_config[i].event);
124
0
      CTRL_WRITE(msr_content, msrs, i);
125
0
    } else {
126
0
      reset_value[i] = 0;
127
0
    }
128
0
  }
129
0
}
130
131
static int ppro_check_ctrs(unsigned int const cpu,
132
                           struct op_msrs const * const msrs,
133
                           struct cpu_user_regs const * const regs)
134
0
{
135
0
  u64 val;
136
0
  int i;
137
0
  int ovf = 0;
138
0
  unsigned long eip = regs->rip;
139
0
  int mode = xenoprofile_get_mode(current, regs);
140
0
  struct arch_msr_pair *msrs_content = vcpu_vpmu(current)->context;
141
0
142
0
  for (i = 0 ; i < num_counters; ++i) {
143
0
    if (!reset_value[i])
144
0
      continue;
145
0
    rdmsrl(msrs->counters[i].addr, val);
146
0
    if (CTR_OVERFLOWED(val)) {
147
0
      xenoprof_log_event(current, regs, eip, mode, i);
148
0
      wrmsrl(msrs->counters[i].addr, -reset_value[i]);
149
0
      if ( is_passive(current->domain) && (mode != 2) &&
150
0
        vpmu_is_set(vcpu_vpmu(current),
151
0
                                            VPMU_PASSIVE_DOMAIN_ALLOCATED) )
152
0
      {
153
0
        if ( IS_ACTIVE(msrs_content[i].control) )
154
0
        {
155
0
          msrs_content[i].counter = val;
156
0
          if ( IS_ENABLE(msrs_content[i].control) )
157
0
            ovf = 2;
158
0
        }
159
0
      }
160
0
      if ( !ovf )
161
0
        ovf = 1;
162
0
    }
163
0
  }
164
0
165
0
  /* Only P6 based Pentium M need to re-unmask the apic vector but it
166
0
   * doesn't hurt other P6 variant */
167
0
  apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED);
168
0
169
0
  return ovf;
170
0
}
171
172
173
static void ppro_start(struct op_msrs const * const msrs)
174
0
{
175
0
  uint64_t msr_content;
176
0
  int i;
177
0
178
0
  for (i = 0; i < num_counters; ++i) {
179
0
    if (reset_value[i]) {
180
0
      CTRL_READ(msr_content, msrs, i);
181
0
      CTRL_SET_ACTIVE(msr_content);
182
0
      CTRL_WRITE(msr_content, msrs, i);
183
0
    }
184
0
  }
185
0
    /* Global Control MSR is enabled by default when system power on.
186
0
     * However, this may not hold true when xenoprof starts to run.
187
0
     */
188
0
    if ( ppro_has_global_ctrl )
189
0
        wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, (1ULL<<num_counters) - 1);
190
0
}
191
192
193
static void ppro_stop(struct op_msrs const * const msrs)
194
0
{
195
0
  uint64_t msr_content;
196
0
  int i;
197
0
198
0
  for (i = 0; i < num_counters; ++i) {
199
0
    if (!reset_value[i])
200
0
      continue;
201
0
    CTRL_READ(msr_content, msrs, i);
202
0
    CTRL_SET_INACTIVE(msr_content);
203
0
    CTRL_WRITE(msr_content, msrs, i);
204
0
  }
205
0
    if ( ppro_has_global_ctrl )
206
0
        wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0x0ULL);
207
0
}
208
209
static int ppro_is_arch_pmu_msr(u64 msr_index, int *type, int *index)
210
50
{
211
50
  if ( (msr_index >= MSR_IA32_PERFCTR0) &&
212
50
            (msr_index < (MSR_IA32_PERFCTR0 + num_counters)) )
213
0
  {
214
0
    *type = MSR_TYPE_ARCH_COUNTER;
215
0
    *index = msr_index - MSR_IA32_PERFCTR0;
216
0
    return 1;
217
0
        }
218
50
        if ( (msr_index >= MSR_P6_EVNTSEL(0)) &&
219
50
            (msr_index < (MSR_P6_EVNTSEL(num_counters))) )
220
0
        {
221
0
    *type = MSR_TYPE_ARCH_CTRL;
222
0
    *index = msr_index - MSR_P6_EVNTSEL(0);
223
0
    return 1;
224
0
        }
225
50
226
50
        return 0;
227
50
}
228
229
static int ppro_allocate_msr(struct vcpu *v)
230
0
{
231
0
  struct vpmu_struct *vpmu = vcpu_vpmu(v);
232
0
  struct arch_msr_pair *msr_content;
233
0
234
0
  msr_content = xzalloc_array(struct arch_msr_pair, num_counters);
235
0
  if ( !msr_content )
236
0
    goto out;
237
0
  vpmu->context = (void *)msr_content;
238
0
  vpmu_clear(vpmu);
239
0
  vpmu_set(vpmu, VPMU_PASSIVE_DOMAIN_ALLOCATED);
240
0
  return 1;
241
0
out:
242
0
  printk(XENLOG_G_WARNING "Insufficient memory for oprofile,"
243
0
         " oprofile is unavailable on dom%d vcpu%d\n",
244
0
         v->vcpu_id, v->domain->domain_id);
245
0
  return 0;
246
0
}
247
248
static void ppro_free_msr(struct vcpu *v)
249
0
{
250
0
  struct vpmu_struct *vpmu = vcpu_vpmu(v);
251
0
252
0
  if ( !vpmu_is_set(vpmu, VPMU_PASSIVE_DOMAIN_ALLOCATED) )
253
0
    return;
254
0
  xfree(vpmu->context);
255
0
  vpmu_reset(vpmu, VPMU_PASSIVE_DOMAIN_ALLOCATED);
256
0
}
257
258
static void ppro_load_msr(struct vcpu *v, int type, int index, u64 *msr_content)
259
0
{
260
0
  struct arch_msr_pair *msrs = vcpu_vpmu(v)->context;
261
0
  switch ( type )
262
0
  {
263
0
  case MSR_TYPE_ARCH_COUNTER:
264
0
    *msr_content = msrs[index].counter;
265
0
    break;
266
0
  case MSR_TYPE_ARCH_CTRL:
267
0
    *msr_content = msrs[index].control;
268
0
    break;
269
0
  }
270
0
}
271
272
static void ppro_save_msr(struct vcpu *v, int type, int index, u64 msr_content)
273
0
{
274
0
  struct arch_msr_pair *msrs = vcpu_vpmu(v)->context;
275
0
276
0
  switch ( type )
277
0
  {
278
0
  case MSR_TYPE_ARCH_COUNTER:
279
0
    msrs[index].counter = msr_content;
280
0
    break;
281
0
  case MSR_TYPE_ARCH_CTRL:
282
0
    msrs[index].control = msr_content;
283
0
    break;
284
0
  }
285
0
}
286
287
/*
288
 * Architectural performance monitoring.
289
 *
290
 * Newer Intel CPUs (Core1+) have support for architectural
291
 * events described in CPUID 0xA. See the IA32 SDM Vol3b.18 for details.
292
 * The advantage of this is that it can be done without knowing about
293
 * the specific CPU.
294
 */
295
void arch_perfmon_setup_counters(void)
296
1
{
297
1
  union cpuid10_eax eax;
298
1
299
1
  eax.full = cpuid_eax(0xa);
300
1
301
1
  /* Workaround for BIOS bugs in 6/15. Taken from perfmon2 */
302
1
  if (eax.split.version_id == 0 && current_cpu_data.x86 == 6 &&
303
0
      current_cpu_data.x86_model == 15) {
304
0
    eax.split.version_id = 2;
305
0
    eax.split.num_counters = 2;
306
0
    eax.split.bit_width = 40;
307
0
  }
308
1
309
1
  num_counters = min_t(u8, eax.split.num_counters, OP_MAX_COUNTER);
310
1
311
1
  op_arch_perfmon_spec.num_counters = num_counters;
312
1
  op_arch_perfmon_spec.num_controls = num_counters;
313
1
  op_ppro_spec.num_counters = num_counters;
314
1
  op_ppro_spec.num_controls = num_counters;
315
1
}
316
317
struct op_x86_model_spec __read_mostly op_ppro_spec = {
318
  .num_counters = 2,
319
  .num_controls = 2,
320
  .fill_in_addresses = &ppro_fill_in_addresses,
321
  .setup_ctrs = &ppro_setup_ctrs,
322
  .check_ctrs = &ppro_check_ctrs,
323
  .start = &ppro_start,
324
  .stop = &ppro_stop,
325
  .is_arch_pmu_msr = &ppro_is_arch_pmu_msr,
326
  .allocated_msr = &ppro_allocate_msr,
327
  .free_msr = &ppro_free_msr,
328
  .load_msr = &ppro_load_msr,
329
  .save_msr = &ppro_save_msr
330
};
331
332
struct op_x86_model_spec __read_mostly op_arch_perfmon_spec = {
333
  /* num_counters/num_controls filled in at runtime */
334
  .fill_in_addresses = &ppro_fill_in_addresses,
335
  .setup_ctrs = &ppro_setup_ctrs,
336
  .check_ctrs = &ppro_check_ctrs,
337
  .start = &ppro_start,
338
  .stop = &ppro_stop,
339
  .is_arch_pmu_msr = &ppro_is_arch_pmu_msr,
340
  .allocated_msr = &ppro_allocate_msr,
341
  .free_msr = &ppro_free_msr,
342
  .load_msr = &ppro_load_msr,
343
  .save_msr = &ppro_save_msr
344
};