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