Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/arch/x86/oprofile/op_model_athlon.c
Line
Count
Source (jump to first uncovered line)
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 <xen/types.h>
14
#include <asm/msr.h>
15
#include <asm/io.h>
16
#include <asm/apic.h>
17
#include <asm/processor.h>
18
#include <xen/xenoprof.h>
19
#include <asm/regs.h>
20
#include <asm/current.h>
21
#include <asm/hvm/support.h>
22
#include <xen/pci_regs.h>
23
#include <xen/pci_ids.h>
24
25
#include "op_x86_model.h"
26
#include "op_counter.h"
27
28
#define K7_NUM_COUNTERS 4
29
#define K7_NUM_CONTROLS 4
30
31
#define FAM15H_NUM_COUNTERS 6
32
#define FAM15H_NUM_CONTROLS 6
33
34
#define MAX_COUNTERS FAM15H_NUM_COUNTERS
35
36
0
#define CTR_READ(msr_content,msrs,c) do {rdmsrl(msrs->counters[(c)].addr, (msr_content));} while (0)
37
0
#define CTR_WRITE(l,msrs,c) do {wrmsr(msrs->counters[(c)].addr, -(unsigned int)(l), -1);} while (0)
38
0
#define CTR_OVERFLOWED(n) (!((n) & (1ULL<<31)))
39
40
0
#define CTRL_READ(msr_content,msrs,c) do {rdmsrl(msrs->controls[(c)].addr, (msr_content));} while (0)
41
0
#define CTRL_WRITE(msr_content,msrs,c) do {wrmsrl(msrs->controls[(c)].addr, (msr_content));} while (0)
42
0
#define CTRL_SET_ACTIVE(n) (n |= (1ULL<<22))
43
0
#define CTRL_SET_INACTIVE(n) (n &= ~(1ULL<<22))
44
0
#define CTRL_CLEAR(val) (val &= (1ULL<<21))
45
0
#define CTRL_SET_ENABLE(val) (val |= 1ULL<<20)
46
0
#define CTRL_SET_USR(val,u) (val |= ((u & 1) << 16))
47
0
#define CTRL_SET_KERN(val,k) (val |= ((k & 1) << 17))
48
0
#define CTRL_SET_UM(val, m) (val |= ((m & 0xff) << 8))
49
0
#define CTRL_SET_EVENT(val, e) (val |= (((e >> 8) & 0xf) | (e & 0xff)))
50
0
#define CTRL_SET_HOST_ONLY(val, h) (val |= ((h & 0x1ULL) << 41))
51
0
#define CTRL_SET_GUEST_ONLY(val, h) (val |= ((h & 0x1ULL) << 40))
52
53
static unsigned long reset_value[MAX_COUNTERS];
54
55
extern char svm_stgi_label[];
56
57
u32 ibs_caps = 0;
58
static u64 ibs_op_ctl;
59
60
/* IBS cpuid feature detection */
61
0
#define IBS_CPUID_FEATURES              0x8000001b
62
63
/* IBS MSRs */
64
0
#define MSR_AMD64_IBSFETCHCTL           0xc0011030
65
#define MSR_AMD64_IBSFETCHLINAD         0xc0011031
66
#define MSR_AMD64_IBSFETCHPHYSAD        0xc0011032
67
0
#define MSR_AMD64_IBSOPCTL              0xc0011033
68
#define MSR_AMD64_IBSOPRIP              0xc0011034
69
#define MSR_AMD64_IBSOPDATA             0xc0011035
70
#define MSR_AMD64_IBSOPDATA2            0xc0011036
71
#define MSR_AMD64_IBSOPDATA3            0xc0011037
72
#define MSR_AMD64_IBSDCLINAD            0xc0011038
73
#define MSR_AMD64_IBSDCPHYSAD           0xc0011039
74
#define MSR_AMD64_IBSCTL                0xc001103a
75
76
/*
77
 * Same bit mask as for IBS cpuid feature flags (Fn8000_001B_EAX), but
78
 * bit 0 is used to indicate the existence of IBS.
79
 */
80
0
#define IBS_CAPS_AVAIL                  (1LL<<0)
81
0
#define IBS_CAPS_RDWROPCNT              (1LL<<3)
82
0
#define IBS_CAPS_OPCNT                  (1LL<<4)
83
84
/* IBS randomization macros */
85
0
#define IBS_RANDOM_BITS                 12
86
0
#define IBS_RANDOM_MASK                 ((1ULL << IBS_RANDOM_BITS) - 1)
87
#define IBS_RANDOM_MAXCNT_OFFSET        (1ULL << (IBS_RANDOM_BITS - 5))
88
89
/* IbsFetchCtl bits/masks */
90
0
#define IBS_FETCH_RAND_EN               (1ULL<<57)
91
0
#define IBS_FETCH_VAL                   (1ULL<<49)
92
0
#define IBS_FETCH_ENABLE                (1ULL<<48)
93
0
#define IBS_FETCH_CNT                   0xFFFF0000ULL
94
0
#define IBS_FETCH_MAX_CNT               0x0000FFFFULL
95
96
/* IbsOpCtl bits */
97
0
#define IBS_OP_CNT_CTL                  (1ULL<<19)
98
0
#define IBS_OP_VAL                      (1ULL<<18)
99
0
#define IBS_OP_ENABLE                   (1ULL<<17)
100
#define IBS_OP_MAX_CNT                  0x0000FFFFULL
101
102
/* IBS sample identifier */
103
0
#define IBS_FETCH_CODE                  13
104
0
#define IBS_OP_CODE                     14
105
106
0
#define clamp(val, min, max) ({      \
107
0
  typeof(val) __val = (val);    \
108
0
  typeof(min) __min = (min);    \
109
0
  typeof(max) __max = (max);    \
110
0
  (void) (&__val == &__min);    \
111
0
  (void) (&__val == &__max);    \
112
0
  __val = __val < __min ? __min: __val; \
113
0
  __val > __max ? __max: __val; })
114
115
/*
116
 * 16-bit Linear Feedback Shift Register (LFSR)
117
 */
118
static unsigned int lfsr_random(void)
119
0
{
120
0
    static unsigned int lfsr_value = 0xF00D;
121
0
    unsigned int bit;
122
0
123
0
    /* Compute next bit to shift in */
124
0
    bit = ((lfsr_value >> 0) ^
125
0
           (lfsr_value >> 2) ^
126
0
           (lfsr_value >> 3) ^
127
0
           (lfsr_value >> 5)) & 0x0001;
128
0
129
0
    /* Advance to next register value */
130
0
    lfsr_value = (lfsr_value >> 1) | (bit << 15);
131
0
132
0
    return lfsr_value;
133
0
}
134
135
/*
136
 * IBS software randomization
137
 *
138
 * The IBS periodic op counter is randomized in software. The lower 12
139
 * bits of the 20 bit counter are randomized. IbsOpCurCnt is
140
 * initialized with a 12 bit random value.
141
 */
142
static inline u64 op_amd_randomize_ibs_op(u64 val)
143
0
{
144
0
    unsigned int random = lfsr_random();
145
0
146
0
    if (!(ibs_caps & IBS_CAPS_RDWROPCNT))
147
0
        /*
148
0
         * Work around if the hw can not write to IbsOpCurCnt
149
0
         *
150
0
         * Randomize the lower 8 bits of the 16 bit
151
0
         * IbsOpMaxCnt [15:0] value in the range of -128 to
152
0
         * +127 by adding/subtracting an offset to the
153
0
         * maximum count (IbsOpMaxCnt).
154
0
         *
155
0
         * To avoid over or underflows and protect upper bits
156
0
         * starting at bit 16, the initial value for
157
0
         * IbsOpMaxCnt must fit in the range from 0x0081 to
158
0
         * 0xff80.
159
0
         */
160
0
        val += (s8)(random >> 4);
161
0
    else
162
0
        val |= (u64)(random & IBS_RANDOM_MASK) << 32;
163
0
164
0
    return val;
165
0
}
166
167
static void athlon_fill_in_addresses(struct op_msrs * const msrs)
168
0
{
169
0
  msrs->counters[0].addr = MSR_K7_PERFCTR0;
170
0
  msrs->counters[1].addr = MSR_K7_PERFCTR1;
171
0
  msrs->counters[2].addr = MSR_K7_PERFCTR2;
172
0
  msrs->counters[3].addr = MSR_K7_PERFCTR3;
173
0
174
0
  msrs->controls[0].addr = MSR_K7_EVNTSEL0;
175
0
  msrs->controls[1].addr = MSR_K7_EVNTSEL1;
176
0
  msrs->controls[2].addr = MSR_K7_EVNTSEL2;
177
0
  msrs->controls[3].addr = MSR_K7_EVNTSEL3;
178
0
}
179
180
static void fam15h_fill_in_addresses(struct op_msrs * const msrs)
181
0
{
182
0
  msrs->counters[0].addr = MSR_AMD_FAM15H_PERFCTR0;
183
0
  msrs->counters[1].addr = MSR_AMD_FAM15H_PERFCTR1;
184
0
  msrs->counters[2].addr = MSR_AMD_FAM15H_PERFCTR2;
185
0
  msrs->counters[3].addr = MSR_AMD_FAM15H_PERFCTR3;
186
0
  msrs->counters[4].addr = MSR_AMD_FAM15H_PERFCTR4;
187
0
  msrs->counters[5].addr = MSR_AMD_FAM15H_PERFCTR5;
188
0
189
0
  msrs->controls[0].addr = MSR_AMD_FAM15H_EVNTSEL0;
190
0
  msrs->controls[1].addr = MSR_AMD_FAM15H_EVNTSEL1;
191
0
  msrs->controls[2].addr = MSR_AMD_FAM15H_EVNTSEL2;
192
0
  msrs->controls[3].addr = MSR_AMD_FAM15H_EVNTSEL3;
193
0
  msrs->controls[4].addr = MSR_AMD_FAM15H_EVNTSEL4;
194
0
  msrs->controls[5].addr = MSR_AMD_FAM15H_EVNTSEL5;
195
0
}
196
197
static void athlon_setup_ctrs(struct op_msrs const * const msrs)
198
0
{
199
0
  uint64_t msr_content;
200
0
  int i;
201
0
  unsigned int const nr_ctrs = model->num_counters;
202
0
  unsigned int const nr_ctrls = model->num_controls;
203
0
 
204
0
  /* clear all counters */
205
0
  for (i = 0 ; i < nr_ctrls; ++i) {
206
0
    CTRL_READ(msr_content, msrs, i);
207
0
    CTRL_CLEAR(msr_content);
208
0
    CTRL_WRITE(msr_content, msrs, i);
209
0
  }
210
0
  
211
0
  /* avoid a false detection of ctr overflows in NMI handler */
212
0
  for (i = 0; i < nr_ctrs; ++i) {
213
0
    CTR_WRITE(1, msrs, i);
214
0
  }
215
0
216
0
  /* enable active counters */
217
0
  for (i = 0; i < nr_ctrs; ++i) {
218
0
    if (counter_config[i].enabled) {
219
0
      reset_value[i] = counter_config[i].count;
220
0
221
0
      CTR_WRITE(counter_config[i].count, msrs, i);
222
0
223
0
      CTRL_READ(msr_content, msrs, i);
224
0
      CTRL_CLEAR(msr_content);
225
0
      CTRL_SET_ENABLE(msr_content);
226
0
      CTRL_SET_USR(msr_content, counter_config[i].user);
227
0
      CTRL_SET_KERN(msr_content, counter_config[i].kernel);
228
0
      CTRL_SET_UM(msr_content, counter_config[i].unit_mask);
229
0
      CTRL_SET_EVENT(msr_content, counter_config[i].event);
230
0
      CTRL_SET_HOST_ONLY(msr_content, 0);
231
0
      CTRL_SET_GUEST_ONLY(msr_content, 0);
232
0
      CTRL_WRITE(msr_content, msrs, i);
233
0
    } else {
234
0
      reset_value[i] = 0;
235
0
    }
236
0
  }
237
0
}
238
239
static inline void
240
ibs_log_event(u64 data, struct cpu_user_regs const * const regs, int mode)
241
0
{
242
0
  struct vcpu *v = current;
243
0
  u32 temp = 0;
244
0
245
0
  temp = data & 0xFFFFFFFF;
246
0
  xenoprof_log_event(v, regs, temp, mode, 0);
247
0
  
248
0
  temp = (data >> 32) & 0xFFFFFFFF;
249
0
  xenoprof_log_event(v, regs, temp, mode, 0);
250
0
  
251
0
}
252
253
static inline int handle_ibs(int mode, struct cpu_user_regs const * const regs)
254
0
{
255
0
  u64 val, ctl;
256
0
  struct vcpu *v = current;
257
0
258
0
  if (!ibs_caps)
259
0
    return 1;
260
0
261
0
  if (ibs_config.fetch_enabled) {
262
0
    rdmsrl(MSR_AMD64_IBSFETCHCTL, ctl);
263
0
    if (ctl & IBS_FETCH_VAL) {
264
0
      rdmsrl(MSR_AMD64_IBSFETCHLINAD, val);
265
0
      xenoprof_log_event(v, regs, IBS_FETCH_CODE, mode, 0);
266
0
      xenoprof_log_event(v, regs, val, mode, 0);
267
0
268
0
      ibs_log_event(val, regs, mode);
269
0
      ibs_log_event(ctl, regs, mode);
270
0
271
0
      rdmsrl(MSR_AMD64_IBSFETCHPHYSAD, val);
272
0
      ibs_log_event(val, regs, mode);
273
0
    
274
0
      /* reenable the IRQ */
275
0
      ctl &= ~(IBS_FETCH_VAL | IBS_FETCH_CNT);
276
0
      ctl |= IBS_FETCH_ENABLE;
277
0
      wrmsrl(MSR_AMD64_IBSFETCHCTL, ctl);
278
0
    }
279
0
  }
280
0
281
0
  if (ibs_config.op_enabled) {
282
0
    rdmsrl(MSR_AMD64_IBSOPCTL, ctl);
283
0
    if (ctl & IBS_OP_VAL) {
284
0
285
0
      rdmsrl(MSR_AMD64_IBSOPRIP, val);
286
0
      xenoprof_log_event(v, regs, IBS_OP_CODE, mode, 0);
287
0
      xenoprof_log_event(v, regs, val, mode, 0);
288
0
      
289
0
      ibs_log_event(val, regs, mode);
290
0
291
0
      rdmsrl(MSR_AMD64_IBSOPDATA, val);
292
0
      ibs_log_event(val, regs, mode);
293
0
      rdmsrl(MSR_AMD64_IBSOPDATA2, val);
294
0
      ibs_log_event(val, regs, mode);
295
0
      rdmsrl(MSR_AMD64_IBSOPDATA3, val);
296
0
      ibs_log_event(val, regs, mode);
297
0
      rdmsrl(MSR_AMD64_IBSDCLINAD, val);
298
0
      ibs_log_event(val, regs, mode);
299
0
      rdmsrl(MSR_AMD64_IBSDCPHYSAD, val);
300
0
      ibs_log_event(val, regs, mode);
301
0
302
0
      /* reenable the IRQ */
303
0
      ctl = op_amd_randomize_ibs_op(ibs_op_ctl);
304
0
      wrmsrl(MSR_AMD64_IBSOPCTL, ctl);
305
0
    }
306
0
  }
307
0
308
0
    return 1;
309
0
}
310
311
static int athlon_check_ctrs(unsigned int const cpu,
312
           struct op_msrs const * const msrs,
313
           struct cpu_user_regs const * const regs)
314
315
0
{
316
0
  uint64_t msr_content;
317
0
  int i;
318
0
  int ovf = 0;
319
0
  unsigned long eip = regs->rip;
320
0
  int mode = 0;
321
0
  struct vcpu *v = current;
322
0
  struct cpu_user_regs *guest_regs = guest_cpu_user_regs();
323
0
  unsigned int const nr_ctrs = model->num_counters;
324
0
325
0
  if (!guest_mode(regs) &&
326
0
      (eip == (unsigned long)svm_stgi_label)) {
327
0
    /* SVM guest was running when NMI occurred */
328
0
    ASSERT(is_hvm_vcpu(v));
329
0
    eip = guest_regs->rip;
330
0
    mode = xenoprofile_get_mode(v, guest_regs);
331
0
  } else
332
0
    mode = xenoprofile_get_mode(v, regs);
333
0
334
0
  for (i = 0 ; i < nr_ctrs; ++i) {
335
0
    CTR_READ(msr_content, msrs, i);
336
0
    if (CTR_OVERFLOWED(msr_content)) {
337
0
      xenoprof_log_event(current, regs, eip, mode, i);
338
0
      CTR_WRITE(reset_value[i], msrs, i);
339
0
      ovf = 1;
340
0
    }
341
0
  }
342
0
343
0
  ovf = handle_ibs(mode, regs);
344
0
  /* See op_model_ppro.c */
345
0
  return ovf;
346
0
}
347
348
static inline void start_ibs(void)
349
0
{
350
0
  u64 val = 0;
351
0
352
0
  if (!ibs_caps)
353
0
    return;
354
0
355
0
  if (ibs_config.fetch_enabled) {
356
0
    val = (ibs_config.max_cnt_fetch >> 4) & IBS_FETCH_MAX_CNT;
357
0
    val |= ibs_config.rand_en ? IBS_FETCH_RAND_EN : 0;
358
0
    val |= IBS_FETCH_ENABLE;
359
0
    wrmsrl(MSR_AMD64_IBSFETCHCTL, val);
360
0
  }
361
0
362
0
  if (ibs_config.op_enabled) {
363
0
    ibs_op_ctl = ibs_config.max_cnt_op >> 4;
364
0
    if (!(ibs_caps & IBS_CAPS_RDWROPCNT)) {
365
0
      /*
366
0
       * IbsOpCurCnt not supported.  See
367
0
       * op_amd_randomize_ibs_op() for details.
368
0
       */
369
0
      ibs_op_ctl = clamp((unsigned long long)ibs_op_ctl, 
370
0
              0x0081ULL, 0xFF80ULL);
371
0
    } else {
372
0
      /*
373
0
       * The start value is randomized with a
374
0
       * positive offset, we need to compensate it
375
0
       * with the half of the randomized range. Also
376
0
       * avoid underflows.
377
0
       */
378
0
    ibs_op_ctl = min(ibs_op_ctl + IBS_RANDOM_MAXCNT_OFFSET,
379
0
          IBS_OP_MAX_CNT);
380
0
    }
381
0
    if (ibs_caps & IBS_CAPS_OPCNT && ibs_config.dispatched_ops)
382
0
      ibs_op_ctl |= IBS_OP_CNT_CTL;
383
0
    ibs_op_ctl |= IBS_OP_ENABLE;
384
0
    val = op_amd_randomize_ibs_op(ibs_op_ctl);
385
0
    wrmsrl(MSR_AMD64_IBSOPCTL, val);
386
0
  }
387
0
}
388
 
389
static void athlon_start(struct op_msrs const * const msrs)
390
0
{
391
0
  uint64_t msr_content;
392
0
  int i;
393
0
  unsigned int const nr_ctrs = model->num_counters;
394
0
  for (i = 0 ; i < nr_ctrs ; ++i) {
395
0
    if (reset_value[i]) {
396
0
      CTRL_READ(msr_content, msrs, i);
397
0
      CTRL_SET_ACTIVE(msr_content);
398
0
      CTRL_WRITE(msr_content, msrs, i);
399
0
    }
400
0
  }
401
0
  start_ibs();
402
0
}
403
404
static void stop_ibs(void)
405
0
{
406
0
  if (!ibs_caps)
407
0
    return;
408
0
409
0
  if (ibs_config.fetch_enabled)
410
0
    /* clear max count and enable */
411
0
    wrmsrl(MSR_AMD64_IBSFETCHCTL, 0);
412
0
413
0
  if (ibs_config.op_enabled)
414
0
    /* clear max count and enable */
415
0
    wrmsrl(MSR_AMD64_IBSOPCTL, 0);
416
0
}
417
418
static void athlon_stop(struct op_msrs const * const msrs)
419
0
{
420
0
  uint64_t msr_content;
421
0
  int i;
422
0
  unsigned int const nr_ctrs = model->num_counters;
423
0
424
0
  /* Subtle: stop on all counters to avoid race with
425
0
   * setting our pm callback */
426
0
  for (i = 0 ; i < nr_ctrs ; ++i) {
427
0
    CTRL_READ(msr_content, msrs, i);
428
0
    CTRL_SET_INACTIVE(msr_content);
429
0
    CTRL_WRITE(msr_content, msrs, i);
430
0
  }
431
0
432
0
  stop_ibs();
433
0
}
434
435
0
#define IBSCTL_LVTOFFSETVAL             (1 << 8)
436
0
#define APIC_EILVT_MSG_NMI              0x4
437
0
#define APIC_EILVT_LVTOFF_IBS           1
438
0
#define APIC_EILVTn(n)                  (0x500 + 0x10 * n)
439
static inline void __init init_ibs_nmi_per_cpu(void *arg)
440
0
{
441
0
  unsigned long reg;
442
0
443
0
  reg = (APIC_EILVT_LVTOFF_IBS << 4) + APIC_EILVTn(0);
444
0
  apic_write(reg, APIC_EILVT_MSG_NMI << 8);
445
0
}
446
447
0
#define PCI_DEVICE_ID_AMD_10H_NB_MISC   0x1203
448
0
#define IBSCTL                          0x1cc
449
static int __init init_ibs_nmi(void)
450
0
{
451
0
  int bus, dev, func;
452
0
  u32 id, value;
453
0
  u16 vendor_id, dev_id;
454
0
  int nodes;
455
0
456
0
  /* per CPU setup */
457
0
  on_each_cpu(init_ibs_nmi_per_cpu, NULL, 1);
458
0
459
0
  nodes = 0;
460
0
  for (bus = 0; bus < 256; bus++) {
461
0
    for (dev = 0; dev < 32; dev++) {
462
0
      for (func = 0; func < 8; func++) {
463
0
        id = pci_conf_read32(0, bus, dev, func, PCI_VENDOR_ID);
464
0
465
0
        vendor_id = id & 0xffff;
466
0
        dev_id = (id >> 16) & 0xffff;
467
0
468
0
        if ((vendor_id == PCI_VENDOR_ID_AMD) &&
469
0
          (dev_id == PCI_DEVICE_ID_AMD_10H_NB_MISC)) {
470
0
471
0
          pci_conf_write32(0, bus, dev, func, IBSCTL,
472
0
            IBSCTL_LVTOFFSETVAL | APIC_EILVT_LVTOFF_IBS);
473
0
474
0
          value = pci_conf_read32(0, bus, dev, func, IBSCTL);
475
0
476
0
          if (value != (IBSCTL_LVTOFFSETVAL |
477
0
            APIC_EILVT_LVTOFF_IBS)) {
478
0
            printk("Xenoprofile: Failed to setup IBS LVT offset, "
479
0
              "IBSCTL = %#x\n", value);
480
0
            return 1;
481
0
          }
482
0
          nodes++;
483
0
        }
484
0
      }
485
0
    }
486
0
  }
487
0
488
0
  if (!nodes) {
489
0
    printk("Xenoprofile: No CPU node configured for IBS\n");
490
0
    return 1;
491
0
  }
492
0
493
0
  return 0;
494
0
}
495
496
static void __init get_ibs_caps(void)
497
0
{
498
0
  if (!boot_cpu_has(X86_FEATURE_IBS))
499
0
    return;
500
0
501
0
    /* check IBS cpuid feature flags */
502
0
  if (current_cpu_data.extended_cpuid_level >= IBS_CPUID_FEATURES)
503
0
    ibs_caps = cpuid_eax(IBS_CPUID_FEATURES);
504
0
  if (!(ibs_caps & IBS_CAPS_AVAIL))
505
0
    /* cpuid flags not valid */
506
0
    ibs_caps = 0;
507
0
}
508
509
void __init ibs_init(void)
510
0
{
511
0
  get_ibs_caps();
512
0
513
0
  if ( !ibs_caps )
514
0
    return;
515
0
516
0
  if (init_ibs_nmi()) {
517
0
    ibs_caps = 0;
518
0
    return;
519
0
  }
520
0
521
0
  printk("Xenoprofile: AMD IBS detected (%#x)\n",
522
0
    (unsigned)ibs_caps);
523
0
}
524
525
struct op_x86_model_spec const op_athlon_spec = {
526
  .num_counters = K7_NUM_COUNTERS,
527
  .num_controls = K7_NUM_CONTROLS,
528
  .fill_in_addresses = &athlon_fill_in_addresses,
529
  .setup_ctrs = &athlon_setup_ctrs,
530
  .check_ctrs = &athlon_check_ctrs,
531
  .start = &athlon_start,
532
  .stop = &athlon_stop
533
};
534
535
struct op_x86_model_spec const op_amd_fam15h_spec = {
536
  .num_counters = FAM15H_NUM_COUNTERS,
537
  .num_controls = FAM15H_NUM_CONTROLS,
538
  .fill_in_addresses = &fam15h_fill_in_addresses,
539
  .setup_ctrs = &athlon_setup_ctrs,
540
  .check_ctrs = &athlon_check_ctrs,
541
  .start = &athlon_start,
542
  .stop = &athlon_stop
543
};