]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/dev/hwpmc/hwpmc_mips24k.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / dev / hwpmc / hwpmc_mips24k.c
1 /*-
2  * Copyright (c) 2010 George V. Neville-Neil <gnn@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/cpu.h>
37 #include <machine/cpufunc.h>
38 #include <machine/cputypes.h>
39 #include <machine/pmc_mdep.h>
40
41 /*
42  * Support for MIPS CPUs
43  *
44  */
45 static int mips24k_npmcs;
46
47 struct mips24k_event_code_map {
48         enum pmc_event  pe_ev;       /* enum value */
49         uint8_t         pe_counter;  /* Which counter this can be counted in. */
50         uint8_t         pe_code;     /* numeric code */
51 };
52
53 /*
54  * MIPS event codes are encoded with a select bit.  The
55  * select bit is used when writing to CP0 so that we 
56  * can select either counter 0/2 or 1/3.  The cycle
57  * and instruction counters are special in that they
58  * can be counted on either 0/2 or 1/3.
59  */
60
61 #define MIPS24K_ALL 255 /* Count events in any counter. */
62 #define MIPS24K_CTR_0 0 /* Counter 0 Event */
63 #define MIPS24K_CTR_1 1 /* Counter 1 Event */
64
65 const struct mips24k_event_code_map mips24k_event_codes[] = {
66         { PMC_EV_MIPS24K_CYCLE, MIPS24K_ALL, 0},
67         { PMC_EV_MIPS24K_INSTR_EXECUTED, MIPS24K_ALL, 1},
68         { PMC_EV_MIPS24K_BRANCH_COMPLETED, MIPS24K_CTR_0, 2},
69         { PMC_EV_MIPS24K_BRANCH_MISPRED, MIPS24K_CTR_1, 2},
70         { PMC_EV_MIPS24K_RETURN, MIPS24K_CTR_0, 3},
71         { PMC_EV_MIPS24K_RETURN_MISPRED, MIPS24K_CTR_1, 3},
72         { PMC_EV_MIPS24K_RETURN_NOT_31, MIPS24K_CTR_0, 4},
73         { PMC_EV_MIPS24K_RETURN_NOTPRED, MIPS24K_CTR_1, 4},
74         { PMC_EV_MIPS24K_ITLB_ACCESS, MIPS24K_CTR_0, 5},
75         { PMC_EV_MIPS24K_ITLB_MISS, MIPS24K_CTR_1, 5},
76         { PMC_EV_MIPS24K_DTLB_ACCESS, MIPS24K_CTR_0, 6},
77         { PMC_EV_MIPS24K_DTLB_MISS, MIPS24K_CTR_1, 6},
78         { PMC_EV_MIPS24K_JTLB_IACCESS, MIPS24K_CTR_0, 7},
79         { PMC_EV_MIPS24K_JTLB_IMISS, MIPS24K_CTR_1, 7},
80         { PMC_EV_MIPS24K_JTLB_DACCESS, MIPS24K_CTR_0, 8},
81         { PMC_EV_MIPS24K_JTLB_DMISS, MIPS24K_CTR_1, 8},
82         { PMC_EV_MIPS24K_IC_FETCH, MIPS24K_CTR_0, 9},
83         { PMC_EV_MIPS24K_IC_MISS, MIPS24K_CTR_1, 9},
84         { PMC_EV_MIPS24K_DC_LOADSTORE, MIPS24K_CTR_0, 10},
85         { PMC_EV_MIPS24K_DC_WRITEBACK, MIPS24K_CTR_1, 10},
86         { PMC_EV_MIPS24K_DC_MISS, MIPS24K_ALL, 11},  
87         /* 12 reserved */
88         { PMC_EV_MIPS24K_STORE_MISS, MIPS24K_CTR_0, 13},
89         { PMC_EV_MIPS24K_LOAD_MISS, MIPS24K_CTR_1, 13},
90         { PMC_EV_MIPS24K_INTEGER_COMPLETED, MIPS24K_CTR_0, 14},
91         { PMC_EV_MIPS24K_FP_COMPLETED, MIPS24K_CTR_1, 14},
92         { PMC_EV_MIPS24K_LOAD_COMPLETED, MIPS24K_CTR_0, 15},
93         { PMC_EV_MIPS24K_STORE_COMPLETED, MIPS24K_CTR_1, 15},
94         { PMC_EV_MIPS24K_BARRIER_COMPLETED, MIPS24K_CTR_0, 16},
95         { PMC_EV_MIPS24K_MIPS16_COMPLETED, MIPS24K_CTR_1, 16},
96         { PMC_EV_MIPS24K_NOP_COMPLETED, MIPS24K_CTR_0, 17},
97         { PMC_EV_MIPS24K_INTEGER_MULDIV_COMPLETED, MIPS24K_CTR_1, 17},
98         { PMC_EV_MIPS24K_RF_STALL, MIPS24K_CTR_0, 18},
99         { PMC_EV_MIPS24K_INSTR_REFETCH, MIPS24K_CTR_1, 18},
100         { PMC_EV_MIPS24K_STORE_COND_COMPLETED, MIPS24K_CTR_0, 19},
101         { PMC_EV_MIPS24K_STORE_COND_FAILED, MIPS24K_CTR_1, 19},
102         { PMC_EV_MIPS24K_ICACHE_REQUESTS, MIPS24K_CTR_0, 20},
103         { PMC_EV_MIPS24K_ICACHE_HIT, MIPS24K_CTR_1, 20},
104         { PMC_EV_MIPS24K_L2_WRITEBACK, MIPS24K_CTR_0, 21},
105         { PMC_EV_MIPS24K_L2_ACCESS, MIPS24K_CTR_1, 21},
106         { PMC_EV_MIPS24K_L2_MISS, MIPS24K_CTR_0, 22},
107         { PMC_EV_MIPS24K_L2_ERR_CORRECTED, MIPS24K_CTR_1, 22},
108         { PMC_EV_MIPS24K_EXCEPTIONS, MIPS24K_CTR_0, 23},
109         /* Event 23 on COP0 1/3 is undefined */
110         { PMC_EV_MIPS24K_RF_CYCLES_STALLED, MIPS24K_CTR_0, 24},
111         { PMC_EV_MIPS24K_IFU_CYCLES_STALLED, MIPS24K_CTR_0, 25},
112         { PMC_EV_MIPS24K_ALU_CYCLES_STALLED, MIPS24K_CTR_1, 25},
113         /* Events 26 through 32 undefined or reserved to customers */
114         { PMC_EV_MIPS24K_UNCACHED_LOAD, MIPS24K_CTR_0, 33},
115         { PMC_EV_MIPS24K_UNCACHED_STORE, MIPS24K_CTR_1, 33},
116         { PMC_EV_MIPS24K_CP2_REG_TO_REG_COMPLETED, MIPS24K_CTR_0, 35},
117         { PMC_EV_MIPS24K_MFTC_COMPLETED, MIPS24K_CTR_1, 35},
118         /* Event 36 reserved */
119         { PMC_EV_MIPS24K_IC_BLOCKED_CYCLES, MIPS24K_CTR_0, 37},
120         { PMC_EV_MIPS24K_DC_BLOCKED_CYCLES, MIPS24K_CTR_1, 37},
121         { PMC_EV_MIPS24K_L2_IMISS_STALL_CYCLES, MIPS24K_CTR_0, 38},
122         { PMC_EV_MIPS24K_L2_DMISS_STALL_CYCLES, MIPS24K_CTR_1, 38},
123         { PMC_EV_MIPS24K_DMISS_CYCLES, MIPS24K_CTR_0, 39},
124         { PMC_EV_MIPS24K_L2_MISS_CYCLES, MIPS24K_CTR_1, 39},
125         { PMC_EV_MIPS24K_UNCACHED_BLOCK_CYCLES, MIPS24K_CTR_0, 40},
126         { PMC_EV_MIPS24K_MDU_STALL_CYCLES, MIPS24K_CTR_0, 41},
127         { PMC_EV_MIPS24K_FPU_STALL_CYCLES, MIPS24K_CTR_1, 41},
128         { PMC_EV_MIPS24K_CP2_STALL_CYCLES, MIPS24K_CTR_0, 42},
129         { PMC_EV_MIPS24K_COREXTEND_STALL_CYCLES, MIPS24K_CTR_1, 42},
130         { PMC_EV_MIPS24K_ISPRAM_STALL_CYCLES, MIPS24K_CTR_0, 43},
131         { PMC_EV_MIPS24K_DSPRAM_STALL_CYCLES, MIPS24K_CTR_1, 43},
132         { PMC_EV_MIPS24K_CACHE_STALL_CYCLES, MIPS24K_CTR_0, 44},
133         /* Event 44 undefined on 1/3 */
134         { PMC_EV_MIPS24K_LOAD_TO_USE_STALLS, MIPS24K_CTR_0, 45},
135         { PMC_EV_MIPS24K_BASE_MISPRED_STALLS, MIPS24K_CTR_1, 45},
136         { PMC_EV_MIPS24K_CPO_READ_STALLS, MIPS24K_CTR_0, 46},
137         { PMC_EV_MIPS24K_BRANCH_MISPRED_CYCLES, MIPS24K_CTR_1, 46},
138         /* Event 47 reserved */
139         { PMC_EV_MIPS24K_IFETCH_BUFFER_FULL, MIPS24K_CTR_0, 48},
140         { PMC_EV_MIPS24K_FETCH_BUFFER_ALLOCATED, MIPS24K_CTR_1, 48},
141         { PMC_EV_MIPS24K_EJTAG_ITRIGGER, MIPS24K_CTR_0, 49},
142         { PMC_EV_MIPS24K_EJTAG_DTRIGGER, MIPS24K_CTR_1, 49},
143         { PMC_EV_MIPS24K_FSB_LT_QUARTER, MIPS24K_CTR_0, 50},
144         { PMC_EV_MIPS24K_FSB_QUARTER_TO_HALF, MIPS24K_CTR_1, 50},
145         { PMC_EV_MIPS24K_FSB_GT_HALF, MIPS24K_CTR_0, 51},
146         { PMC_EV_MIPS24K_FSB_FULL_PIPELINE_STALLS, MIPS24K_CTR_1, 51},
147         { PMC_EV_MIPS24K_LDQ_LT_QUARTER, MIPS24K_CTR_0, 52},
148         { PMC_EV_MIPS24K_LDQ_QUARTER_TO_HALF, MIPS24K_CTR_1, 52},
149         { PMC_EV_MIPS24K_LDQ_GT_HALF, MIPS24K_CTR_0, 53},
150         { PMC_EV_MIPS24K_LDQ_FULL_PIPELINE_STALLS, MIPS24K_CTR_1, 53},
151         { PMC_EV_MIPS24K_WBB_LT_QUARTER, MIPS24K_CTR_0, 54},
152         { PMC_EV_MIPS24K_WBB_QUARTER_TO_HALF, MIPS24K_CTR_1, 54},
153         { PMC_EV_MIPS24K_WBB_GT_HALF, MIPS24K_CTR_0, 55},
154         { PMC_EV_MIPS24K_WBB_FULL_PIPELINE_STALLS, MIPS24K_CTR_1, 55},
155         /* Events 56-63 reserved */
156         { PMC_EV_MIPS24K_REQUEST_LATENCY, MIPS24K_CTR_0, 61},
157         { PMC_EV_MIPS24K_REQUEST_COUNT, MIPS24K_CTR_1, 61}
158
159 };
160
161 const int mips24k_event_codes_size =
162         sizeof(mips24k_event_codes) / sizeof(mips24k_event_codes[0]);
163
164 /*
165  * Per-processor information.
166  */
167 struct mips24k_cpu {
168         struct pmc_hw   *pc_mipspmcs;
169 };
170
171 static struct mips24k_cpu **mips24k_pcpu;
172
173 /*
174  * Performance Count Register N
175  */
176 static uint32_t
177 mips24k_pmcn_read(unsigned int pmc)
178 {
179         uint32_t reg = 0;
180
181         KASSERT(pmc < mips24k_npmcs, ("[mips,%d] illegal PMC number %d", 
182                                    __LINE__, pmc));
183
184         /* The counter value is the next value after the control register. */
185         switch (pmc) {
186         case 0:
187                 reg = mips_rd_perfcnt1();
188                 break;
189         case 1:
190                 reg = mips_rd_perfcnt3();
191                 break;
192         default:
193                 return 0;
194         }
195         return (reg);
196 }
197
198 static uint32_t
199 mips24k_pmcn_write(unsigned int pmc, uint32_t reg)
200 {
201
202         KASSERT(pmc < mips24k_npmcs, ("[mips,%d] illegal PMC number %d", 
203                                    __LINE__, pmc));
204         
205         switch (pmc) {
206         case 0:
207                 mips_wr_perfcnt1(reg);
208                 break;
209         case 1:
210                 mips_wr_perfcnt3(reg);
211                 break;
212         default:
213                 return 0;
214         }
215         return (reg);
216 }
217
218 static int
219 mips24k_allocate_pmc(int cpu, int ri, struct pmc *pm,
220   const struct pmc_op_pmcallocate *a)
221 {
222         enum pmc_event pe;
223         uint32_t caps, config, counter;
224         int i;
225
226         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
227             ("[mips,%d] illegal CPU value %d", __LINE__, cpu));
228         KASSERT(ri >= 0 && ri < mips24k_npmcs,
229             ("[mips,%d] illegal row index %d", __LINE__, ri));
230
231         caps = a->pm_caps;
232         if (a->pm_class != PMC_CLASS_MIPS24K)
233                 return (EINVAL);
234         pe = a->pm_ev;
235         for (i = 0; i < mips24k_event_codes_size; i++) {
236                 if (mips24k_event_codes[i].pe_ev == pe) {
237                         config = mips24k_event_codes[i].pe_code;
238                         counter =  mips24k_event_codes[i].pe_counter;
239                         break;
240                 }
241         }
242         if (i == mips24k_event_codes_size)
243                 return (EINVAL);
244
245         if ((counter != MIPS24K_ALL) && (counter != ri))
246                 return (EINVAL);
247
248         config <<= MIPS24K_PMC_SELECT;
249
250         if (caps & PMC_CAP_SYSTEM)
251                 config |= (MIPS24K_PMC_SUPER_ENABLE | 
252                            MIPS24K_PMC_KERNEL_ENABLE);
253         if (caps & PMC_CAP_USER)
254                 config |= MIPS24K_PMC_USER_ENABLE;
255         if ((caps & (PMC_CAP_USER | PMC_CAP_SYSTEM)) == 0)
256                 config |= MIPS24K_PMC_ENABLE;
257
258         pm->pm_md.pm_mips24k.pm_mips24k_evsel = config;
259
260         PMCDBG(MDP,ALL,2,"mips-allocate ri=%d -> config=0x%x", ri, config);
261
262         return 0;
263 }
264
265
266 static int
267 mips24k_read_pmc(int cpu, int ri, pmc_value_t *v)
268 {
269         struct pmc *pm;
270         pmc_value_t tmp;
271
272         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
273             ("[mips,%d] illegal CPU value %d", __LINE__, cpu));
274         KASSERT(ri >= 0 && ri < mips24k_npmcs,
275             ("[mips,%d] illegal row index %d", __LINE__, ri));
276
277         pm  = mips24k_pcpu[cpu]->pc_mipspmcs[ri].phw_pmc;
278         tmp = mips24k_pmcn_read(ri);
279         PMCDBG(MDP,REA,2,"mips-read id=%d -> %jd", ri, tmp);
280         if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
281                 *v = MIPS24K_PERFCTR_VALUE_TO_RELOAD_COUNT(tmp);
282         else
283                 *v = tmp;
284
285         return 0;
286 }
287
288 static int
289 mips24k_write_pmc(int cpu, int ri, pmc_value_t v)
290 {
291         struct pmc *pm;
292
293         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
294             ("[mips,%d] illegal CPU value %d", __LINE__, cpu));
295         KASSERT(ri >= 0 && ri < mips24k_npmcs,
296             ("[mips,%d] illegal row-index %d", __LINE__, ri));
297
298         pm  = mips24k_pcpu[cpu]->pc_mipspmcs[ri].phw_pmc;
299
300         if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
301                 v = MIPS24K_RELOAD_COUNT_TO_PERFCTR_VALUE(v);
302         
303         PMCDBG(MDP,WRI,1,"mips-write cpu=%d ri=%d v=%jx", cpu, ri, v);
304
305         mips24k_pmcn_write(ri, v);
306
307         return 0;
308 }
309
310 static int
311 mips24k_config_pmc(int cpu, int ri, struct pmc *pm)
312 {
313         struct pmc_hw *phw;
314
315         PMCDBG(MDP,CFG,1, "cpu=%d ri=%d pm=%p", cpu, ri, pm);
316
317         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
318             ("[mips,%d] illegal CPU value %d", __LINE__, cpu));
319         KASSERT(ri >= 0 && ri < mips24k_npmcs,
320             ("[mips,%d] illegal row-index %d", __LINE__, ri));
321
322         phw = &mips24k_pcpu[cpu]->pc_mipspmcs[ri];
323
324         KASSERT(pm == NULL || phw->phw_pmc == NULL,
325             ("[mips,%d] pm=%p phw->pm=%p hwpmc not unconfigured",
326             __LINE__, pm, phw->phw_pmc));
327
328         phw->phw_pmc = pm;
329
330         return 0;
331 }
332
333 static int
334 mips24k_start_pmc(int cpu, int ri)
335 {
336         uint32_t config;
337         struct pmc *pm;
338         struct pmc_hw *phw;
339
340         phw    = &mips24k_pcpu[cpu]->pc_mipspmcs[ri];
341         pm     = phw->phw_pmc;
342         config = pm->pm_md.pm_mips24k.pm_mips24k_evsel;
343
344         /* Enable the PMC. */
345         switch (ri) {
346         case 0:
347                 mips_wr_perfcnt0(config);
348                 break;
349         case 1:
350                 mips_wr_perfcnt2(config);
351                 break;
352         default:
353                 break;
354         }
355
356         return 0;
357 }
358
359 static int
360 mips24k_stop_pmc(int cpu, int ri)
361 {
362         struct pmc *pm;
363         struct pmc_hw *phw;
364
365         phw    = &mips24k_pcpu[cpu]->pc_mipspmcs[ri];
366         pm     = phw->phw_pmc;
367
368         /*
369          * Disable the PMCs.
370          *
371          * Clearing the entire register turns the counter off as well
372          * as removes the previously sampled event.
373          */
374         switch (ri) {
375         case 0:
376                 mips_wr_perfcnt0(0);
377                 break;
378         case 1:
379                 mips_wr_perfcnt2(0);
380                 break;
381         default:
382                 break;
383         }
384         return 0;
385 }
386
387 static int
388 mips24k_release_pmc(int cpu, int ri, struct pmc *pmc)
389 {
390         struct pmc_hw *phw;
391
392         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
393             ("[mips,%d] illegal CPU value %d", __LINE__, cpu));
394         KASSERT(ri >= 0 && ri < mips24k_npmcs,
395             ("[mips,%d] illegal row-index %d", __LINE__, ri));
396
397         phw = &mips24k_pcpu[cpu]->pc_mipspmcs[ri];
398         KASSERT(phw->phw_pmc == NULL,
399             ("[mips,%d] PHW pmc %p non-NULL", __LINE__, phw->phw_pmc));
400
401         return 0;
402 }
403
404 static int
405 mips24k_intr(int cpu, struct trapframe *tf)
406 {
407         return 0;
408 }
409
410 static int
411 mips24k_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc)
412 {
413         int error;
414         struct pmc_hw *phw;
415         char mips24k_name[PMC_NAME_MAX];
416
417         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
418             ("[mips,%d], illegal CPU %d", __LINE__, cpu));
419         KASSERT(ri >= 0 && ri < mips24k_npmcs,
420             ("[mips,%d] row-index %d out of range", __LINE__, ri));
421
422         phw = &mips24k_pcpu[cpu]->pc_mipspmcs[ri];
423         snprintf(mips24k_name, sizeof(mips24k_name), "MIPS-%d", ri);
424         if ((error = copystr(mips24k_name, pi->pm_name, PMC_NAME_MAX,
425             NULL)) != 0)
426                 return error;
427         pi->pm_class = PMC_CLASS_MIPS24K;
428         if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) {
429                 pi->pm_enabled = TRUE;
430                 *ppmc          = phw->phw_pmc;
431         } else {
432                 pi->pm_enabled = FALSE;
433                 *ppmc          = NULL;
434         }
435
436         return (0);
437 }
438
439 static int
440 mips24k_get_config(int cpu, int ri, struct pmc **ppm)
441 {
442         *ppm = mips24k_pcpu[cpu]->pc_mipspmcs[ri].phw_pmc;
443
444         return 0;
445 }
446
447 /*
448  * XXX don't know what we should do here.
449  */
450 static int
451 mips24k_switch_in(struct pmc_cpu *pc, struct pmc_process *pp)
452 {
453         return 0;
454 }
455
456 static int
457 mips24k_switch_out(struct pmc_cpu *pc, struct pmc_process *pp)
458 {
459         return 0;
460 }
461
462 static int
463 mips24k_pcpu_init(struct pmc_mdep *md, int cpu)
464 {
465         int first_ri, i;
466         struct pmc_cpu *pc;
467         struct mips24k_cpu *pac;
468         struct pmc_hw  *phw;
469
470         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
471             ("[mips,%d] wrong cpu number %d", __LINE__, cpu));
472         PMCDBG(MDP,INI,1,"mips-init cpu=%d", cpu);
473
474         mips24k_pcpu[cpu] = pac = malloc(sizeof(struct mips24k_cpu), M_PMC,
475             M_WAITOK|M_ZERO);
476         pac->pc_mipspmcs = malloc(sizeof(struct pmc_hw) * mips24k_npmcs,
477             M_PMC, M_WAITOK|M_ZERO);
478         pc = pmc_pcpu[cpu];
479         first_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_MIPS24K].pcd_ri;
480         KASSERT(pc != NULL, ("[mips,%d] NULL per-cpu pointer", __LINE__));
481
482         for (i = 0, phw = pac->pc_mipspmcs; i < mips24k_npmcs; i++, phw++) {
483                 phw->phw_state    = PMC_PHW_FLAG_IS_ENABLED |
484                     PMC_PHW_CPU_TO_STATE(cpu) | PMC_PHW_INDEX_TO_STATE(i);
485                 phw->phw_pmc      = NULL;
486                 pc->pc_hwpmcs[i + first_ri] = phw;
487         }
488
489         /*
490          * Clear the counter control register which has the effect
491          * of disabling counting.
492          */
493         for (i = 0; i < mips24k_npmcs; i++)
494                 mips24k_pmcn_write(i, 0);
495
496         return 0;
497 }
498
499 static int
500 mips24k_pcpu_fini(struct pmc_mdep *md, int cpu)
501 {
502         return 0;
503 }
504
505 struct pmc_mdep *
506 pmc_mips24k_initialize()
507 {
508         struct pmc_mdep *pmc_mdep;
509         struct pmc_classdep *pcd;
510         
511         /* 
512          * Read the counter control registers from CP0 
513          * to determine the number of available PMCs.
514          * The control registers use bit 31 as a "more" bit.
515          *
516          * XXX: With the current macros it is hard to read the
517          * CP0 registers in any varied way.  
518          */
519         mips24k_npmcs = 2;
520         
521         PMCDBG(MDP,INI,1,"mips-init npmcs=%d", mips24k_npmcs);
522
523         /*
524          * Allocate space for pointers to PMC HW descriptors and for
525          * the MDEP structure used by MI code.
526          */
527         mips24k_pcpu = malloc(sizeof(struct mips24k_cpu *) * pmc_cpu_max(), M_PMC,
528                            M_WAITOK|M_ZERO);
529
530         /* Just one class */
531         pmc_mdep = malloc(sizeof(struct pmc_mdep) + sizeof(struct pmc_classdep),
532                           M_PMC, M_WAITOK|M_ZERO);
533
534         pmc_mdep->pmd_cputype = PMC_CPU_MIPS_24K;
535         pmc_mdep->pmd_nclass  = 1;
536
537         pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_MIPS24K];
538         pcd->pcd_caps  = MIPS24K_PMC_CAPS;
539         pcd->pcd_class = PMC_CLASS_MIPS24K;
540         pcd->pcd_num   = mips24k_npmcs;
541         pcd->pcd_ri    = pmc_mdep->pmd_npmc;
542         pcd->pcd_width = 32; /* XXX: Fix for 64 bit MIPS */
543
544         pcd->pcd_allocate_pmc   = mips24k_allocate_pmc;
545         pcd->pcd_config_pmc     = mips24k_config_pmc;
546         pcd->pcd_pcpu_fini      = mips24k_pcpu_fini;
547         pcd->pcd_pcpu_init      = mips24k_pcpu_init;
548         pcd->pcd_describe       = mips24k_describe;
549         pcd->pcd_get_config     = mips24k_get_config;
550         pcd->pcd_read_pmc       = mips24k_read_pmc;
551         pcd->pcd_release_pmc    = mips24k_release_pmc;
552         pcd->pcd_start_pmc      = mips24k_start_pmc;
553         pcd->pcd_stop_pmc       = mips24k_stop_pmc;
554         pcd->pcd_write_pmc      = mips24k_write_pmc;
555
556         pmc_mdep->pmd_intr       = mips24k_intr;
557         pmc_mdep->pmd_switch_in  = mips24k_switch_in;
558         pmc_mdep->pmd_switch_out = mips24k_switch_out;
559         
560         pmc_mdep->pmd_npmc   += mips24k_npmcs;
561
562         return (pmc_mdep);
563 }
564
565 void
566 pmc_mips24k_finalize(struct pmc_mdep *md)
567 {
568         (void) md;
569 }
570