]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/hwpmc/hwpmc_xscale.c
Bump version information and add UPDATING entries.
[FreeBSD/FreeBSD.git] / sys / dev / hwpmc / hwpmc_xscale.c
1 /*-
2  * Copyright (c) 2009 Rui Paulo <rpaulo@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/pmc.h>
34 #include <sys/pmckern.h>
35
36 #include <machine/pmc_mdep.h>
37 /*
38  * Support for the Intel XScale network processors
39  *
40  * XScale processors have up to now three generations.
41  *
42  * The first generation has two PMC; the event selection, interrupt config
43  * and overflow flag setup are done by writing to the PMNC register.
44  * It also has less monitoring events than the latter generations.
45  *
46  * The second and third generatiosn have four PMCs, one register for the event
47  * selection, one register for the interrupt config and one register for
48  * the overflow flags.
49  */
50 static int xscale_npmcs;
51 static int xscale_gen;  /* XScale Core generation */
52
53 struct xscale_event_code_map {
54         enum pmc_event  pe_ev;
55         uint8_t         pe_code;
56 };
57
58 const struct xscale_event_code_map xscale_event_codes[] = {
59         /* 1st and 2nd Generation XScale cores */
60         { PMC_EV_XSCALE_IC_FETCH,               0x00 },
61         { PMC_EV_XSCALE_IC_MISS,                0x01 },
62         { PMC_EV_XSCALE_DATA_DEPENDENCY_STALLED,0x02 },
63         { PMC_EV_XSCALE_ITLB_MISS,              0x03 },
64         { PMC_EV_XSCALE_DTLB_MISS,              0x04 },
65         { PMC_EV_XSCALE_BRANCH_RETIRED,         0x05 },
66         { PMC_EV_XSCALE_BRANCH_MISPRED,         0x06 },
67         { PMC_EV_XSCALE_INSTR_RETIRED,          0x07 },
68         { PMC_EV_XSCALE_DC_FULL_CYCLE,          0x08 },
69         { PMC_EV_XSCALE_DC_FULL_CONTIG,         0x09 },
70         { PMC_EV_XSCALE_DC_ACCESS,              0x0a },
71         { PMC_EV_XSCALE_DC_MISS,                0x0b },
72         { PMC_EV_XSCALE_DC_WRITEBACK,           0x0c },
73         { PMC_EV_XSCALE_PC_CHANGE,              0x0d },
74         /* 3rd Generation XScale cores */
75         { PMC_EV_XSCALE_BRANCH_RETIRED_ALL,     0x0e },
76         { PMC_EV_XSCALE_INSTR_CYCLE,            0x0f },
77         { PMC_EV_XSCALE_CP_STALL,               0x17 },
78         { PMC_EV_XSCALE_PC_CHANGE_ALL,          0x18 },
79         { PMC_EV_XSCALE_PIPELINE_FLUSH,         0x19 },
80         { PMC_EV_XSCALE_BACKEND_STALL,          0x1a },
81         { PMC_EV_XSCALE_MULTIPLIER_USE,         0x1b },
82         { PMC_EV_XSCALE_MULTIPLIER_STALLED,     0x1c },
83         { PMC_EV_XSCALE_DATA_CACHE_STALLED,     0x1e },
84         { PMC_EV_XSCALE_L2_CACHE_REQ,           0x20 },
85         { PMC_EV_XSCALE_L2_CACHE_MISS,          0x23 },
86         { PMC_EV_XSCALE_ADDRESS_BUS_TRANS,      0x40 },
87         { PMC_EV_XSCALE_SELF_ADDRESS_BUS_TRANS, 0x41 },
88         { PMC_EV_XSCALE_DATA_BUS_TRANS,         0x48 },
89 };
90
91 /*
92  * Per-processor information.
93  */
94 struct xscale_cpu {
95         struct pmc_hw   *pc_xscalepmcs;
96 };
97
98 static struct xscale_cpu **xscale_pcpu;
99
100 /*
101  * Performance Monitor Control Register
102  */
103 static __inline uint32_t
104 xscale_pmnc_read(void)
105 {
106         uint32_t reg;
107
108         __asm __volatile("mrc p14, 0, %0, c0, c1, 0" : "=r" (reg));
109
110         return (reg);
111 }
112
113 static __inline void
114 xscale_pmnc_write(uint32_t reg)
115 {
116         __asm __volatile("mcr p14, 0, %0, c0, c1, 0" : : "r" (reg));
117 }
118
119 /*
120  * Clock Counter Register
121  */
122 static __inline uint32_t
123 xscale_ccnt_read(void)
124 {
125         uint32_t reg;
126
127         __asm __volatile("mrc p14, 0, %0, c1, c1, 0" : "=r" (reg));
128         
129         return (reg);
130 }
131
132 static __inline void
133 xscale_ccnt_write(uint32_t reg)
134 {
135         __asm __volatile("mcr p14, 0, %0, c1, c1, 0" : : "r" (reg));
136 }
137
138 /*
139  * Interrupt Enable Register
140  */
141 static __inline uint32_t
142 xscale_inten_read(void)
143 {
144         uint32_t reg;
145
146         __asm __volatile("mrc p14, 0, %0, c4, c1, 0" : "=r" (reg));
147
148         return (reg);
149 }
150
151 static __inline void
152 xscale_inten_write(uint32_t reg)
153 {
154         __asm __volatile("mcr p14, 0, %0, c4, c1, 0" : : "r" (reg));
155 }
156
157 /*
158  * Overflow Flag Register
159  */
160 static __inline uint32_t
161 xscale_flag_read(void)
162 {
163         uint32_t reg;
164
165         __asm __volatile("mrc p14, 0, %0, c5, c1, 0" : "=r" (reg));
166
167         return (reg);
168 }
169
170 static __inline void
171 xscale_flag_write(uint32_t reg)
172 {
173         __asm __volatile("mcr p14, 0, %0, c5, c1, 0" : : "r" (reg));
174 }
175
176 /*
177  * Event Selection Register
178  */
179 static __inline uint32_t
180 xscale_evtsel_read(void)
181 {
182         uint32_t reg;
183
184         __asm __volatile("mrc p14, 0, %0, c8, c1, 0" : "=r" (reg));
185
186         return (reg);
187 }
188
189 static __inline void
190 xscale_evtsel_write(uint32_t reg)
191 {
192         __asm __volatile("mcr p14, 0, %0, c8, c1, 0" : : "r" (reg));
193 }
194
195 /*
196  * Performance Count Register N
197  */
198 static uint32_t
199 xscale_pmcn_read(unsigned int pmc)
200 {
201         uint32_t reg = 0;
202
203         KASSERT(pmc < 4, ("[xscale,%d] illegal PMC number %d", __LINE__, pmc));
204
205         switch (pmc) {
206         case 0:
207                 __asm __volatile("mrc p14, 0, %0, c0, c2, 0" : "=r" (reg));
208                 break;
209         case 1:
210                 __asm __volatile("mrc p14, 0, %0, c1, c2, 0" : "=r" (reg));
211                 break;
212         case 2:
213                 __asm __volatile("mrc p14, 0, %0, c2, c2, 0" : "=r" (reg));
214                 break;
215         case 3:
216                 __asm __volatile("mrc p14, 0, %0, c3, c2, 0" : "=r" (reg));
217                 break;
218         }
219
220         return (reg);
221 }
222
223 static uint32_t
224 xscale_pmcn_write(unsigned int pmc, uint32_t reg)
225 {
226
227         KASSERT(pmc < 4, ("[xscale,%d] illegal PMC number %d", __LINE__, pmc));
228
229         switch (pmc) {
230         case 0:
231                 __asm __volatile("mcr p14, 0, %0, c0, c2, 0" : : "r" (reg));
232                 break;
233         case 1:
234                 __asm __volatile("mcr p14, 0, %0, c1, c2, 0" : : "r" (reg));
235                 break;
236         case 2:
237                 __asm __volatile("mcr p14, 0, %0, c2, c2, 0" : : "r" (reg));
238                 break;
239         case 3:
240                 __asm __volatile("mcr p14, 0, %0, c3, c2, 0" : : "r" (reg));
241                 break;
242         }
243
244         return (reg);
245 }
246
247 static int
248 xscale_allocate_pmc(int cpu, int ri, struct pmc *pm,
249   const struct pmc_op_pmcallocate *a)
250 {
251         enum pmc_event pe;
252         uint32_t caps, config;
253         int i;
254
255         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
256             ("[xscale,%d] illegal CPU value %d", __LINE__, cpu));
257         KASSERT(ri >= 0 && ri < xscale_npmcs,
258             ("[xscale,%d] illegal row index %d", __LINE__, ri));
259
260         caps = a->pm_caps;
261         if (a->pm_class != PMC_CLASS_XSCALE)
262                 return (EINVAL);
263         pe = a->pm_ev;
264         for (i = 0; i < nitems(xscale_event_codes); i++) {
265                 if (xscale_event_codes[i].pe_ev == pe) {
266                         config = xscale_event_codes[i].pe_code;
267                         break;
268                 }
269         }
270         if (i == nitems(xscale_event_codes))
271                 return EINVAL;
272         /* Generation 1 has fewer events */
273         if (xscale_gen == 1 && i > PMC_EV_XSCALE_PC_CHANGE)
274                 return EINVAL;
275         pm->pm_md.pm_xscale.pm_xscale_evsel = config;
276
277         PMCDBG2(MDP,ALL,2,"xscale-allocate ri=%d -> config=0x%x", ri, config);
278
279         return 0;
280 }
281
282
283 static int
284 xscale_read_pmc(int cpu, int ri, pmc_value_t *v)
285 {
286         struct pmc *pm;
287         pmc_value_t tmp;
288
289         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
290             ("[xscale,%d] illegal CPU value %d", __LINE__, cpu));
291         KASSERT(ri >= 0 && ri < xscale_npmcs,
292             ("[xscale,%d] illegal row index %d", __LINE__, ri));
293
294         pm  = xscale_pcpu[cpu]->pc_xscalepmcs[ri].phw_pmc;
295         tmp = xscale_pmcn_read(ri);
296         PMCDBG2(MDP,REA,2,"xscale-read id=%d -> %jd", ri, tmp);
297         if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
298                 *v = XSCALE_PERFCTR_VALUE_TO_RELOAD_COUNT(tmp);
299         else
300                 *v = tmp;
301
302         return 0;
303 }
304
305 static int
306 xscale_write_pmc(int cpu, int ri, pmc_value_t v)
307 {
308         struct pmc *pm;
309
310         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
311             ("[xscale,%d] illegal CPU value %d", __LINE__, cpu));
312         KASSERT(ri >= 0 && ri < xscale_npmcs,
313             ("[xscale,%d] illegal row-index %d", __LINE__, ri));
314
315         pm  = xscale_pcpu[cpu]->pc_xscalepmcs[ri].phw_pmc;
316
317         if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
318                 v = XSCALE_RELOAD_COUNT_TO_PERFCTR_VALUE(v);
319         
320         PMCDBG3(MDP,WRI,1,"xscale-write cpu=%d ri=%d v=%jx", cpu, ri, v);
321
322         xscale_pmcn_write(ri, v);
323
324         return 0;
325 }
326
327 static int
328 xscale_config_pmc(int cpu, int ri, struct pmc *pm)
329 {
330         struct pmc_hw *phw;
331
332         PMCDBG3(MDP,CFG,1, "cpu=%d ri=%d pm=%p", cpu, ri, pm);
333
334         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
335             ("[xscale,%d] illegal CPU value %d", __LINE__, cpu));
336         KASSERT(ri >= 0 && ri < xscale_npmcs,
337             ("[xscale,%d] illegal row-index %d", __LINE__, ri));
338
339         phw = &xscale_pcpu[cpu]->pc_xscalepmcs[ri];
340
341         KASSERT(pm == NULL || phw->phw_pmc == NULL,
342             ("[xscale,%d] pm=%p phw->pm=%p hwpmc not unconfigured",
343             __LINE__, pm, phw->phw_pmc));
344
345         phw->phw_pmc = pm;
346
347         return 0;
348 }
349
350 static int
351 xscale_start_pmc(int cpu, int ri)
352 {
353         uint32_t pmnc, config, evtsel;
354         struct pmc *pm;
355         struct pmc_hw *phw;
356
357         phw    = &xscale_pcpu[cpu]->pc_xscalepmcs[ri];
358         pm     = phw->phw_pmc;
359         config = pm->pm_md.pm_xscale.pm_xscale_evsel;
360
361         /*
362          * Configure the event selection.
363          *
364          * On the XScale 2nd Generation there's no EVTSEL register.
365          */
366         if (xscale_npmcs == 2) {
367                 pmnc = xscale_pmnc_read();
368                 switch (ri) {
369                 case 0:
370                         pmnc &= ~XSCALE_PMNC_EVT0_MASK;
371                         pmnc |= (config << 12) & XSCALE_PMNC_EVT0_MASK;
372                         break;
373                 case 1:
374                         pmnc &= ~XSCALE_PMNC_EVT1_MASK;
375                         pmnc |= (config << 20) & XSCALE_PMNC_EVT1_MASK;
376                         break;
377                 default:
378                         /* XXX */
379                         break;
380                 }
381                 xscale_pmnc_write(pmnc);
382         } else {
383                 evtsel = xscale_evtsel_read();
384                 switch (ri) {
385                 case 0:
386                         evtsel &= ~XSCALE_EVTSEL_EVT0_MASK;
387                         evtsel |= config & XSCALE_EVTSEL_EVT0_MASK;
388                         break;
389                 case 1:
390                         evtsel &= ~XSCALE_EVTSEL_EVT1_MASK;
391                         evtsel |= (config << 8) & XSCALE_EVTSEL_EVT1_MASK;
392                         break;
393                 case 2:
394                         evtsel &= ~XSCALE_EVTSEL_EVT2_MASK;
395                         evtsel |= (config << 16) & XSCALE_EVTSEL_EVT2_MASK;
396                         break;
397                 case 3:
398                         evtsel &= ~XSCALE_EVTSEL_EVT3_MASK;
399                         evtsel |= (config << 24) & XSCALE_EVTSEL_EVT3_MASK;
400                         break;
401                 default:
402                         /* XXX */
403                         break;
404                 }
405                 xscale_evtsel_write(evtsel);
406         }
407         /*
408          * Enable the PMC.
409          *
410          * Note that XScale provides only one bit to enable/disable _all_
411          * performance monitoring units.
412          */
413         pmnc = xscale_pmnc_read();
414         pmnc |= XSCALE_PMNC_ENABLE;
415         xscale_pmnc_write(pmnc);
416
417         return 0;
418 }
419
420 static int
421 xscale_stop_pmc(int cpu, int ri)
422 {
423         uint32_t pmnc, evtsel;
424         struct pmc *pm;
425         struct pmc_hw *phw;
426
427         phw    = &xscale_pcpu[cpu]->pc_xscalepmcs[ri];
428         pm     = phw->phw_pmc;
429
430         /*
431          * Disable the PMCs.
432          *
433          * Note that XScale provides only one bit to enable/disable _all_
434          * performance monitoring units.
435          */
436         pmnc = xscale_pmnc_read();
437         pmnc &= ~XSCALE_PMNC_ENABLE;
438         xscale_pmnc_write(pmnc);
439         /*
440          * A value of 0xff makes the corresponding PMU go into
441          * power saving mode.
442          */
443         if (xscale_npmcs == 2) {
444                 pmnc = xscale_pmnc_read();
445                 switch (ri) {
446                 case 0:
447                         pmnc |= XSCALE_PMNC_EVT0_MASK;
448                         break;
449                 case 1:
450                         pmnc |= XSCALE_PMNC_EVT1_MASK;
451                         break;
452                 default:
453                         /* XXX */
454                         break;
455                 }
456                 xscale_pmnc_write(pmnc);
457         } else {
458                 evtsel = xscale_evtsel_read();
459                 switch (ri) {
460                 case 0:
461                         evtsel |= XSCALE_EVTSEL_EVT0_MASK;
462                         break;
463                 case 1:
464                         evtsel |= XSCALE_EVTSEL_EVT1_MASK;
465                         break;
466                 case 2:
467                         evtsel |= XSCALE_EVTSEL_EVT2_MASK;
468                         break;
469                 case 3:
470                         evtsel |= XSCALE_EVTSEL_EVT3_MASK;
471                         break;
472                 default:
473                         /* XXX */
474                         break;
475                 }
476                 xscale_evtsel_write(evtsel);
477         }
478
479         return 0;
480 }
481
482 static int
483 xscale_release_pmc(int cpu, int ri, struct pmc *pmc)
484 {
485         struct pmc_hw *phw;
486
487         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
488             ("[xscale,%d] illegal CPU value %d", __LINE__, cpu));
489         KASSERT(ri >= 0 && ri < xscale_npmcs,
490             ("[xscale,%d] illegal row-index %d", __LINE__, ri));
491
492         phw = &xscale_pcpu[cpu]->pc_xscalepmcs[ri];
493         KASSERT(phw->phw_pmc == NULL,
494             ("[xscale,%d] PHW pmc %p non-NULL", __LINE__, phw->phw_pmc));
495
496         return 0;
497 }
498
499 static int
500 xscale_intr(int cpu, struct trapframe *tf)
501 {
502         printf("intr\n");
503         return 0;
504 }
505
506 static int
507 xscale_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc)
508 {
509         int error;
510         struct pmc_hw *phw;
511         char xscale_name[PMC_NAME_MAX];
512
513         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
514             ("[xscale,%d], illegal CPU %d", __LINE__, cpu));
515         KASSERT(ri >= 0 && ri < xscale_npmcs,
516             ("[xscale,%d] row-index %d out of range", __LINE__, ri));
517
518         phw = &xscale_pcpu[cpu]->pc_xscalepmcs[ri];
519         snprintf(xscale_name, sizeof(xscale_name), "XSCALE-%d", ri);
520         if ((error = copystr(xscale_name, pi->pm_name, PMC_NAME_MAX,
521             NULL)) != 0)
522                 return error;
523         pi->pm_class = PMC_CLASS_XSCALE;
524         if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) {
525                 pi->pm_enabled = TRUE;
526                 *ppmc          = phw->phw_pmc;
527         } else {
528                 pi->pm_enabled = FALSE;
529                 *ppmc          = NULL;
530         }
531
532         return (0);
533 }
534
535 static int
536 xscale_get_config(int cpu, int ri, struct pmc **ppm)
537 {
538         *ppm = xscale_pcpu[cpu]->pc_xscalepmcs[ri].phw_pmc;
539
540         return 0;
541 }
542
543 /*
544  * XXX don't know what we should do here.
545  */
546 static int
547 xscale_switch_in(struct pmc_cpu *pc, struct pmc_process *pp)
548 {
549         return 0;
550 }
551
552 static int
553 xscale_switch_out(struct pmc_cpu *pc, struct pmc_process *pp)
554 {
555         return 0;
556 }
557
558 static int
559 xscale_pcpu_init(struct pmc_mdep *md, int cpu)
560 {
561         int first_ri, i;
562         struct pmc_cpu *pc;
563         struct xscale_cpu *pac;
564         struct pmc_hw  *phw;
565
566         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
567             ("[xscale,%d] wrong cpu number %d", __LINE__, cpu));
568         PMCDBG1(MDP,INI,1,"xscale-init cpu=%d", cpu);
569
570         xscale_pcpu[cpu] = pac = malloc(sizeof(struct xscale_cpu), M_PMC,
571             M_WAITOK|M_ZERO);
572         pac->pc_xscalepmcs = malloc(sizeof(struct pmc_hw) * xscale_npmcs,
573             M_PMC, M_WAITOK|M_ZERO);
574         pc = pmc_pcpu[cpu];
575         first_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_XSCALE].pcd_ri;
576         KASSERT(pc != NULL, ("[xscale,%d] NULL per-cpu pointer", __LINE__));
577
578         for (i = 0, phw = pac->pc_xscalepmcs; i < xscale_npmcs; i++, phw++) {
579                 phw->phw_state    = PMC_PHW_FLAG_IS_ENABLED |
580                     PMC_PHW_CPU_TO_STATE(cpu) | PMC_PHW_INDEX_TO_STATE(i);
581                 phw->phw_pmc      = NULL;
582                 pc->pc_hwpmcs[i + first_ri] = phw;
583         }
584
585         /*
586          * Disable and put the PMUs into power save mode.
587          */
588         if (xscale_npmcs == 2) {
589                 xscale_pmnc_write(XSCALE_PMNC_EVT1_MASK |
590                     XSCALE_PMNC_EVT0_MASK);
591         } else {
592                 xscale_evtsel_write(XSCALE_EVTSEL_EVT3_MASK |
593                     XSCALE_EVTSEL_EVT2_MASK | XSCALE_EVTSEL_EVT1_MASK |
594                     XSCALE_EVTSEL_EVT0_MASK);
595         }
596
597         return 0;
598 }
599
600 static int
601 xscale_pcpu_fini(struct pmc_mdep *md, int cpu)
602 {
603         return 0;
604 }
605
606 struct pmc_mdep *
607 pmc_xscale_initialize()
608 {
609         struct pmc_mdep *pmc_mdep;
610         struct pmc_classdep *pcd;
611         uint32_t idreg;
612
613         /* Get the Core Generation from CP15 */
614         __asm __volatile("mrc p15, 0, %0, c0, c0, 0" : "=r" (idreg));
615         xscale_gen = (idreg >> 13) & 0x3;
616         switch (xscale_gen) {
617         case 1:
618                 xscale_npmcs = 2;
619                 break;
620         case 2:
621         case 3:
622                 xscale_npmcs = 4;
623                 break;
624         default:
625                 printf("%s: unknown XScale core generation\n", __func__);
626                 return (NULL);
627         }
628         PMCDBG1(MDP,INI,1,"xscale-init npmcs=%d", xscale_npmcs);
629         
630         /*
631          * Allocate space for pointers to PMC HW descriptors and for
632          * the MDEP structure used by MI code.
633          */
634         xscale_pcpu = malloc(sizeof(struct xscale_cpu *) * pmc_cpu_max(), M_PMC,
635             M_WAITOK|M_ZERO);
636
637         /* Just one class */
638         pmc_mdep = pmc_mdep_alloc(1);
639
640         pmc_mdep->pmd_cputype = PMC_CPU_INTEL_XSCALE;
641
642         pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_XSCALE];
643         pcd->pcd_caps  = XSCALE_PMC_CAPS;
644         pcd->pcd_class = PMC_CLASS_XSCALE;
645         pcd->pcd_num   = xscale_npmcs;
646         pcd->pcd_ri    = pmc_mdep->pmd_npmc;
647         pcd->pcd_width = 32;
648
649         pcd->pcd_allocate_pmc   = xscale_allocate_pmc;
650         pcd->pcd_config_pmc     = xscale_config_pmc;
651         pcd->pcd_pcpu_fini      = xscale_pcpu_fini;
652         pcd->pcd_pcpu_init      = xscale_pcpu_init;
653         pcd->pcd_describe       = xscale_describe;
654         pcd->pcd_get_config     = xscale_get_config;
655         pcd->pcd_read_pmc       = xscale_read_pmc;
656         pcd->pcd_release_pmc    = xscale_release_pmc;
657         pcd->pcd_start_pmc      = xscale_start_pmc;
658         pcd->pcd_stop_pmc       = xscale_stop_pmc;
659         pcd->pcd_write_pmc      = xscale_write_pmc;
660
661         pmc_mdep->pmd_intr       = xscale_intr;
662         pmc_mdep->pmd_switch_in  = xscale_switch_in;
663         pmc_mdep->pmd_switch_out = xscale_switch_out;
664         
665         pmc_mdep->pmd_npmc   += xscale_npmcs;
666
667         return (pmc_mdep);
668 }
669
670 void
671 pmc_xscale_finalize(struct pmc_mdep *md)
672 {
673 }