1
2
3
4
5
6
7
8
9
10
11#include <linux/oprofile.h>
12#include <linux/smp.h>
13#include <linux/ptrace.h>
14#include <linux/nmi.h>
15#include <asm/msr.h>
16#include <asm/fixmap.h>
17#include <asm/apic.h>
18
19
20#include "op_x86_model.h"
21#include "op_counter.h"
22
23#define NUM_EVENTS 39
24
25#define NUM_COUNTERS_NON_HT 8
26#define NUM_ESCRS_NON_HT 45
27#define NUM_CCCRS_NON_HT 18
28#define NUM_CONTROLS_NON_HT (NUM_ESCRS_NON_HT + NUM_CCCRS_NON_HT)
29
30#define NUM_COUNTERS_HT2 4
31#define NUM_ESCRS_HT2 23
32#define NUM_CCCRS_HT2 9
33#define NUM_CONTROLS_HT2 (NUM_ESCRS_HT2 + NUM_CCCRS_HT2)
34
35static unsigned int num_counters = NUM_COUNTERS_NON_HT;
36static unsigned int num_controls = NUM_CONTROLS_NON_HT;
37
38
39
40
41static inline void setup_num_counters(void)
42{
43#ifdef CONFIG_SMP
44 if (smp_num_siblings == 2) {
45 num_counters = NUM_COUNTERS_HT2;
46 num_controls = NUM_CONTROLS_HT2;
47 }
48#endif
49}
50
51static int inline addr_increment(void)
52{
53#ifdef CONFIG_SMP
54 return smp_num_siblings == 2 ? 2 : 1;
55#else
56 return 1;
57#endif
58}
59
60
61
62struct p4_counter_binding {
63 int virt_counter;
64 int counter_address;
65 int cccr_address;
66};
67
68struct p4_event_binding {
69 int escr_select;
70 int event_select;
71 struct {
72 int virt_counter;
73 int escr_address;
74 } bindings[2];
75};
76
77
78
79
80
81#define CTR_BPU_0 (1 << 0)
82#define CTR_MS_0 (1 << 1)
83#define CTR_FLAME_0 (1 << 2)
84#define CTR_IQ_4 (1 << 3)
85#define CTR_BPU_2 (1 << 4)
86#define CTR_MS_2 (1 << 5)
87#define CTR_FLAME_2 (1 << 6)
88#define CTR_IQ_5 (1 << 7)
89
90static struct p4_counter_binding p4_counters[NUM_COUNTERS_NON_HT] = {
91 { CTR_BPU_0, MSR_P4_BPU_PERFCTR0, MSR_P4_BPU_CCCR0 },
92 { CTR_MS_0, MSR_P4_MS_PERFCTR0, MSR_P4_MS_CCCR0 },
93 { CTR_FLAME_0, MSR_P4_FLAME_PERFCTR0, MSR_P4_FLAME_CCCR0 },
94 { CTR_IQ_4, MSR_P4_IQ_PERFCTR4, MSR_P4_IQ_CCCR4 },
95 { CTR_BPU_2, MSR_P4_BPU_PERFCTR2, MSR_P4_BPU_CCCR2 },
96 { CTR_MS_2, MSR_P4_MS_PERFCTR2, MSR_P4_MS_CCCR2 },
97 { CTR_FLAME_2, MSR_P4_FLAME_PERFCTR2, MSR_P4_FLAME_CCCR2 },
98 { CTR_IQ_5, MSR_P4_IQ_PERFCTR5, MSR_P4_IQ_CCCR5 }
99};
100
101#define NUM_UNUSED_CCCRS (NUM_CCCRS_NON_HT - NUM_COUNTERS_NON_HT)
102
103
104
105static struct p4_event_binding p4_events[NUM_EVENTS] = {
106
107 {
108 0x05, 0x06,
109 { {CTR_IQ_4, MSR_P4_CRU_ESCR2},
110 {CTR_IQ_5, MSR_P4_CRU_ESCR3} }
111 },
112
113 {
114 0x04, 0x03,
115 { { CTR_IQ_4, MSR_P4_CRU_ESCR0},
116 { CTR_IQ_5, MSR_P4_CRU_ESCR1} }
117 },
118
119 {
120 0x01, 0x01,
121 { { CTR_MS_0, MSR_P4_TC_ESCR0},
122 { CTR_MS_2, MSR_P4_TC_ESCR1} }
123 },
124
125 {
126 0x00, 0x03,
127 { { CTR_BPU_0, MSR_P4_BPU_ESCR0},
128 { CTR_BPU_2, MSR_P4_BPU_ESCR1} }
129 },
130
131 {
132 0x03, 0x18,
133 { { CTR_BPU_0, MSR_P4_ITLB_ESCR0},
134 { CTR_BPU_2, MSR_P4_ITLB_ESCR1} }
135 },
136
137 {
138 0x05, 0x02,
139 { { CTR_FLAME_0, MSR_P4_DAC_ESCR0},
140 { CTR_FLAME_2, MSR_P4_DAC_ESCR1} }
141 },
142
143 {
144 0x02, 0x08,
145 { { CTR_FLAME_0, MSR_P4_SAAT_ESCR0},
146 { CTR_FLAME_2, MSR_P4_SAAT_ESCR1} }
147 },
148
149 {
150 0x02, 0x04,
151 { { CTR_FLAME_0, MSR_P4_SAAT_ESCR0},
152 { CTR_FLAME_2, MSR_P4_SAAT_ESCR1} }
153 },
154
155 {
156 0x02, 0x05,
157 { { CTR_FLAME_0, MSR_P4_SAAT_ESCR0},
158 { CTR_FLAME_2, MSR_P4_SAAT_ESCR1} }
159 },
160
161 {
162 0x02, 0x03,
163 { { CTR_BPU_0, MSR_P4_MOB_ESCR0},
164 { CTR_BPU_2, MSR_P4_MOB_ESCR1} }
165 },
166
167 {
168 0x04, 0x01,
169 { { CTR_BPU_0, MSR_P4_PMH_ESCR0},
170 { CTR_BPU_2, MSR_P4_PMH_ESCR1} }
171 },
172
173 {
174 0x07, 0x0c,
175 { { CTR_BPU_0, MSR_P4_BSU_ESCR0},
176 { CTR_BPU_2, MSR_P4_BSU_ESCR1} }
177 },
178
179 {
180 0x06, 0x03,
181 { { CTR_BPU_0, MSR_P4_FSB_ESCR0},
182 { 0, 0 } }
183 },
184
185 {
186 0x06, 0x1a,
187 { { CTR_BPU_2, MSR_P4_FSB_ESCR1},
188 { 0, 0 } }
189 },
190
191 {
192 0x06, 0x17,
193 { { CTR_BPU_0, MSR_P4_FSB_ESCR0},
194 { CTR_BPU_2, MSR_P4_FSB_ESCR1} }
195 },
196
197 {
198 0x07, 0x05,
199 { { CTR_BPU_0, MSR_P4_BSU_ESCR0},
200 { 0, 0 } }
201 },
202
203 {
204 0x07, 0x06,
205 { { CTR_BPU_2, MSR_P4_BSU_ESCR1 },
206 { 0, 0 } }
207 },
208
209 {
210 0x05, 0x03,
211 { { CTR_IQ_4, MSR_P4_CRU_ESCR2},
212 { CTR_IQ_5, MSR_P4_CRU_ESCR3} }
213 },
214
215 {
216 0x01, 0x34,
217 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
218 { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
219 },
220
221 {
222 0x01, 0x08,
223 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
224 { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
225 },
226
227 {
228 0x01, 0x0c,
229 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
230 { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
231 },
232
233 {
234 0x01, 0x0a,
235 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
236 { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
237 },
238
239 {
240 0x01, 0x0e,
241 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
242 { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
243 },
244
245 {
246 0x01, 0x02,
247 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
248 { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
249 },
250
251 {
252 0x01, 0x1a,
253 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
254 { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
255 },
256
257 {
258 0x01, 0x04,
259 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
260 { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
261 },
262
263 {
264 0x01, 0x2e,
265 { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
266 { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
267 },
268
269 {
270 0x05, 0x02,
271 { { CTR_IQ_4, MSR_P4_CRU_ESCR2},
272 { CTR_IQ_5, MSR_P4_CRU_ESCR3} }
273 },
274
275 {
276 0x06, 0x13 ,
277 { { CTR_BPU_0, MSR_P4_FSB_ESCR0},
278 { CTR_BPU_2, MSR_P4_FSB_ESCR1} }
279 },
280
281 {
282 0x00, 0x05,
283 { { CTR_MS_0, MSR_P4_MS_ESCR0},
284 { CTR_MS_2, MSR_P4_MS_ESCR1} }
285 },
286
287 {
288 0x00, 0x09,
289 { { CTR_MS_0, MSR_P4_MS_ESCR0},
290 { CTR_MS_2, MSR_P4_MS_ESCR1} }
291 },
292
293 {
294 0x05, 0x08,
295 { { CTR_IQ_4, MSR_P4_CRU_ESCR2},
296 { CTR_IQ_5, MSR_P4_CRU_ESCR3} }
297 },
298
299 {
300 0x05, 0x0c,
301 { { CTR_IQ_4, MSR_P4_CRU_ESCR2},
302 { CTR_IQ_5, MSR_P4_CRU_ESCR3} }
303 },
304
305 {
306 0x05, 0x09,
307 { { CTR_IQ_4, MSR_P4_CRU_ESCR2},
308 { CTR_IQ_5, MSR_P4_CRU_ESCR3} }
309 },
310
311 {
312 0x04, 0x02,
313 { { CTR_IQ_4, MSR_P4_CRU_ESCR0},
314 { CTR_IQ_5, MSR_P4_CRU_ESCR1} }
315 },
316
317 {
318 0x04, 0x01,
319 { { CTR_IQ_4, MSR_P4_CRU_ESCR0},
320 { CTR_IQ_5, MSR_P4_CRU_ESCR1} }
321 },
322
323 {
324 0x02, 0x02,
325 { { CTR_IQ_4, MSR_P4_RAT_ESCR0},
326 { CTR_IQ_5, MSR_P4_RAT_ESCR1} }
327 },
328
329 {
330 0x02, 0x05,
331 { { CTR_MS_0, MSR_P4_TBPU_ESCR0},
332 { CTR_MS_2, MSR_P4_TBPU_ESCR1} }
333 },
334
335 {
336 0x02, 0x04,
337 { { CTR_MS_0, MSR_P4_TBPU_ESCR0},
338 { CTR_MS_2, MSR_P4_TBPU_ESCR1} }
339 }
340};
341
342
343#define MISC_PMC_ENABLED_P(x) ((x) & 1 << 7)
344
345#define ESCR_RESERVED_BITS 0x80000003
346#define ESCR_CLEAR(escr) ((escr) &= ESCR_RESERVED_BITS)
347#define ESCR_SET_USR_0(escr, usr) ((escr) |= (((usr) & 1) << 2))
348#define ESCR_SET_OS_0(escr, os) ((escr) |= (((os) & 1) << 3))
349#define ESCR_SET_USR_1(escr, usr) ((escr) |= (((usr) & 1)))
350#define ESCR_SET_OS_1(escr, os) ((escr) |= (((os) & 1) << 1))
351#define ESCR_SET_EVENT_SELECT(escr, sel) ((escr) |= (((sel) & 0x3f) << 25))
352#define ESCR_SET_EVENT_MASK(escr, mask) ((escr) |= (((mask) & 0xffff) << 9))
353#define ESCR_READ(escr, high, ev, i) do {rdmsr(ev->bindings[(i)].escr_address, (escr), (high)); } while (0)
354#define ESCR_WRITE(escr, high, ev, i) do {wrmsr(ev->bindings[(i)].escr_address, (escr), (high)); } while (0)
355
356#define CCCR_RESERVED_BITS 0x38030FFF
357#define CCCR_CLEAR(cccr) ((cccr) &= CCCR_RESERVED_BITS)
358#define CCCR_SET_REQUIRED_BITS(cccr) ((cccr) |= 0x00030000)
359#define CCCR_SET_ESCR_SELECT(cccr, sel) ((cccr) |= (((sel) & 0x07) << 13))
360#define CCCR_SET_PMI_OVF_0(cccr) ((cccr) |= (1<<26))
361#define CCCR_SET_PMI_OVF_1(cccr) ((cccr) |= (1<<27))
362#define CCCR_SET_ENABLE(cccr) ((cccr) |= (1<<12))
363#define CCCR_SET_DISABLE(cccr) ((cccr) &= ~(1<<12))
364#define CCCR_READ(low, high, i) do {rdmsr(p4_counters[(i)].cccr_address, (low), (high)); } while (0)
365#define CCCR_WRITE(low, high, i) do {wrmsr(p4_counters[(i)].cccr_address, (low), (high)); } while (0)
366#define CCCR_OVF_P(cccr) ((cccr) & (1U<<31))
367#define CCCR_CLEAR_OVF(cccr) ((cccr) &= (~(1U<<31)))
368
369#define CTRL_IS_RESERVED(msrs, c) (msrs->controls[(c)].addr ? 1 : 0)
370#define CTR_IS_RESERVED(msrs, c) (msrs->counters[(c)].addr ? 1 : 0)
371#define CTR_READ(l, h, i) do {rdmsr(p4_counters[(i)].counter_address, (l), (h)); } while (0)
372#define CTR_WRITE(l, i) do {wrmsr(p4_counters[(i)].counter_address, -(u32)(l), -1); } while (0)
373#define CTR_OVERFLOW_P(ctr) (!((ctr) & 0x80000000))
374
375
376
377
378
379static unsigned int get_stagger(void)
380{
381#ifdef CONFIG_SMP
382 int cpu = smp_processor_id();
383 return (cpu != first_cpu(per_cpu(cpu_sibling_map, cpu)));
384#endif
385 return 0;
386}
387
388
389
390
391
392#define VIRT_CTR(stagger, i) ((i) + ((num_counters) * (stagger)))
393
394static unsigned long reset_value[NUM_COUNTERS_NON_HT];
395
396
397static void p4_fill_in_addresses(struct op_msrs * const msrs)
398{
399 unsigned int i;
400 unsigned int addr, cccraddr, stag;
401
402 setup_num_counters();
403 stag = get_stagger();
404
405
406 for (i = 0; i < num_counters; ++i)
407 msrs->counters[i].addr = 0;
408 for (i = 0; i < num_controls; ++i)
409 msrs->controls[i].addr = 0;
410
411
412 for (i = 0; i < num_counters; ++i) {
413 addr = p4_counters[VIRT_CTR(stag, i)].counter_address;
414 cccraddr = p4_counters[VIRT_CTR(stag, i)].cccr_address;
415 if (reserve_perfctr_nmi(addr)) {
416 msrs->counters[i].addr = addr;
417 msrs->controls[i].addr = cccraddr;
418 }
419 }
420
421
422 for (addr = MSR_P4_BSU_ESCR0 + stag;
423 addr < MSR_P4_IQ_ESCR0; ++i, addr += addr_increment()) {
424 if (reserve_evntsel_nmi(addr))
425 msrs->controls[i].addr = addr;
426 }
427
428
429
430 if (boot_cpu_data.x86_model >= 0x3) {
431 for (addr = MSR_P4_BSU_ESCR0 + stag;
432 addr <= MSR_P4_BSU_ESCR1; ++i, addr += addr_increment()) {
433 if (reserve_evntsel_nmi(addr))
434 msrs->controls[i].addr = addr;
435 }
436 } else {
437 for (addr = MSR_P4_IQ_ESCR0 + stag;
438 addr <= MSR_P4_IQ_ESCR1; ++i, addr += addr_increment()) {
439 if (reserve_evntsel_nmi(addr))
440 msrs->controls[i].addr = addr;
441 }
442 }
443
444 for (addr = MSR_P4_RAT_ESCR0 + stag;
445 addr <= MSR_P4_SSU_ESCR0; ++i, addr += addr_increment()) {
446 if (reserve_evntsel_nmi(addr))
447 msrs->controls[i].addr = addr;
448 }
449
450 for (addr = MSR_P4_MS_ESCR0 + stag;
451 addr <= MSR_P4_TC_ESCR1; ++i, addr += addr_increment()) {
452 if (reserve_evntsel_nmi(addr))
453 msrs->controls[i].addr = addr;
454 }
455
456 for (addr = MSR_P4_IX_ESCR0 + stag;
457 addr <= MSR_P4_CRU_ESCR3; ++i, addr += addr_increment()) {
458 if (reserve_evntsel_nmi(addr))
459 msrs->controls[i].addr = addr;
460 }
461
462
463
464 if (num_counters == NUM_COUNTERS_NON_HT) {
465
466 if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR5))
467 msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
468 if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR4))
469 msrs->controls[i++].addr = MSR_P4_CRU_ESCR4;
470
471 } else if (stag == 0) {
472
473
474 if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR4))
475 msrs->controls[i++].addr = MSR_P4_CRU_ESCR4;
476
477 } else {
478
479
480 if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR5)) {
481 msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
482 msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
483 }
484 }
485}
486
487
488static void pmc_setup_one_p4_counter(unsigned int ctr)
489{
490 int i;
491 int const maxbind = 2;
492 unsigned int cccr = 0;
493 unsigned int escr = 0;
494 unsigned int high = 0;
495 unsigned int counter_bit;
496 struct p4_event_binding *ev = NULL;
497 unsigned int stag;
498
499 stag = get_stagger();
500
501
502 counter_bit = 1 << VIRT_CTR(stag, ctr);
503
504
505 if (counter_config[ctr].event <= 0 || counter_config[ctr].event > NUM_EVENTS) {
506 printk(KERN_ERR
507 "oprofile: P4 event code 0x%lx out of range\n",
508 counter_config[ctr].event);
509 return;
510 }
511
512 ev = &(p4_events[counter_config[ctr].event - 1]);
513
514 for (i = 0; i < maxbind; i++) {
515 if (ev->bindings[i].virt_counter & counter_bit) {
516
517
518 ESCR_READ(escr, high, ev, i);
519 ESCR_CLEAR(escr);
520 if (stag == 0) {
521 ESCR_SET_USR_0(escr, counter_config[ctr].user);
522 ESCR_SET_OS_0(escr, counter_config[ctr].kernel);
523 } else {
524 ESCR_SET_USR_1(escr, counter_config[ctr].user);
525 ESCR_SET_OS_1(escr, counter_config[ctr].kernel);
526 }
527 ESCR_SET_EVENT_SELECT(escr, ev->event_select);
528 ESCR_SET_EVENT_MASK(escr, counter_config[ctr].unit_mask);
529 ESCR_WRITE(escr, high, ev, i);
530
531
532 CCCR_READ(cccr, high, VIRT_CTR(stag, ctr));
533 CCCR_CLEAR(cccr);
534 CCCR_SET_REQUIRED_BITS(cccr);
535 CCCR_SET_ESCR_SELECT(cccr, ev->escr_select);
536 if (stag == 0)
537 CCCR_SET_PMI_OVF_0(cccr);
538 else
539 CCCR_SET_PMI_OVF_1(cccr);
540 CCCR_WRITE(cccr, high, VIRT_CTR(stag, ctr));
541 return;
542 }
543 }
544
545 printk(KERN_ERR
546 "oprofile: P4 event code 0x%lx no binding, stag %d ctr %d\n",
547 counter_config[ctr].event, stag, ctr);
548}
549
550
551static void p4_setup_ctrs(struct op_msrs const * const msrs)
552{
553 unsigned int i;
554 unsigned int low, high;
555 unsigned int stag;
556
557 stag = get_stagger();
558
559 rdmsr(MSR_IA32_MISC_ENABLE, low, high);
560 if (!MISC_PMC_ENABLED_P(low)) {
561 printk(KERN_ERR "oprofile: P4 PMC not available\n");
562 return;
563 }
564
565
566 for (i = 0 ; i < num_counters ; i++) {
567 if (unlikely(!CTRL_IS_RESERVED(msrs, i)))
568 continue;
569 rdmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
570 CCCR_CLEAR(low);
571 CCCR_SET_REQUIRED_BITS(low);
572 wrmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
573 }
574
575
576 for (i = num_counters; i < num_controls; i++) {
577 if (unlikely(!CTRL_IS_RESERVED(msrs, i)))
578 continue;
579 wrmsr(msrs->controls[i].addr, 0, 0);
580 }
581
582
583 for (i = 0 ; i < num_counters ; ++i) {
584 if ((counter_config[i].enabled) && (CTRL_IS_RESERVED(msrs, i))) {
585 reset_value[i] = counter_config[i].count;
586 pmc_setup_one_p4_counter(i);
587 CTR_WRITE(counter_config[i].count, VIRT_CTR(stag, i));
588 } else {
589 reset_value[i] = 0;
590 }
591 }
592}
593
594
595static int p4_check_ctrs(struct pt_regs * const regs,
596 struct op_msrs const * const msrs)
597{
598 unsigned long ctr, low, high, stag, real;
599 int i;
600
601 stag = get_stagger();
602
603 for (i = 0; i < num_counters; ++i) {
604
605 if (!reset_value[i])
606 continue;
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625 real = VIRT_CTR(stag, i);
626
627 CCCR_READ(low, high, real);
628 CTR_READ(ctr, high, real);
629 if (CCCR_OVF_P(low) || CTR_OVERFLOW_P(ctr)) {
630 oprofile_add_sample(regs, i);
631 CTR_WRITE(reset_value[i], real);
632 CCCR_CLEAR_OVF(low);
633 CCCR_WRITE(low, high, real);
634 CTR_WRITE(reset_value[i], real);
635 }
636 }
637
638
639 apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED);
640
641
642 return 1;
643}
644
645
646static void p4_start(struct op_msrs const * const msrs)
647{
648 unsigned int low, high, stag;
649 int i;
650
651 stag = get_stagger();
652
653 for (i = 0; i < num_counters; ++i) {
654 if (!reset_value[i])
655 continue;
656 CCCR_READ(low, high, VIRT_CTR(stag, i));
657 CCCR_SET_ENABLE(low);
658 CCCR_WRITE(low, high, VIRT_CTR(stag, i));
659 }
660}
661
662
663static void p4_stop(struct op_msrs const * const msrs)
664{
665 unsigned int low, high, stag;
666 int i;
667
668 stag = get_stagger();
669
670 for (i = 0; i < num_counters; ++i) {
671 if (!reset_value[i])
672 continue;
673 CCCR_READ(low, high, VIRT_CTR(stag, i));
674 CCCR_SET_DISABLE(low);
675 CCCR_WRITE(low, high, VIRT_CTR(stag, i));
676 }
677}
678
679static void p4_shutdown(struct op_msrs const * const msrs)
680{
681 int i;
682
683 for (i = 0 ; i < num_counters ; ++i) {
684 if (CTR_IS_RESERVED(msrs, i))
685 release_perfctr_nmi(msrs->counters[i].addr);
686 }
687
688
689
690
691
692 for (i = num_counters ; i < num_controls ; ++i) {
693 if (CTRL_IS_RESERVED(msrs, i))
694 release_evntsel_nmi(msrs->controls[i].addr);
695 }
696}
697
698
699#ifdef CONFIG_SMP
700struct op_x86_model_spec const op_p4_ht2_spec = {
701 .num_counters = NUM_COUNTERS_HT2,
702 .num_controls = NUM_CONTROLS_HT2,
703 .fill_in_addresses = &p4_fill_in_addresses,
704 .setup_ctrs = &p4_setup_ctrs,
705 .check_ctrs = &p4_check_ctrs,
706 .start = &p4_start,
707 .stop = &p4_stop,
708 .shutdown = &p4_shutdown
709};
710#endif
711
712struct op_x86_model_spec const op_p4_spec = {
713 .num_counters = NUM_COUNTERS_NON_HT,
714 .num_controls = NUM_CONTROLS_NON_HT,
715 .fill_in_addresses = &p4_fill_in_addresses,
716 .setup_ctrs = &p4_setup_ctrs,
717 .check_ctrs = &p4_check_ctrs,
718 .start = &p4_start,
719 .stop = &p4_stop,
720 .shutdown = &p4_shutdown
721};
722