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