]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/hwpmc/hwpmc_ppc970.c
MFV r351075: 10406 large_dnode changes broke zfs recv of legacy stream
[FreeBSD/FreeBSD.git] / sys / dev / hwpmc / hwpmc_ppc970.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2013 Justin Hibbits
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/pmc.h>
35 #include <sys/pmckern.h>
36 #include <sys/systm.h>
37
38 #include <machine/pmc_mdep.h>
39 #include <machine/spr.h>
40 #include <machine/cpu.h>
41
42 #include "hwpmc_powerpc.h"
43
44 #define PPC970_MAX_PMCS 8
45
46 /* MMCR0, PMC1 is 8 bytes in, PMC2 is 1 byte in. */
47 #define PPC970_SET_MMCR0_PMCSEL(r, x, i) \
48         ((r & ~(0x1f << (7 * (1 - i) + 1))) | (x << (7 * (1 - i) + 1)))
49 /* MMCR1 has 6 PMC*SEL items (PMC3->PMC8), in sequence. */
50 #define PPC970_SET_MMCR1_PMCSEL(r, x, i) \
51         ((r & ~(0x1f << (5 * (7 - i) + 2))) | (x << (5 * (7 - i) + 2)))
52
53 #define PPC970_PMC_HAS_OVERFLOWED(x) (ppc970_pmcn_read(x) & (0x1 << 31))
54
55 /* How PMC works on PPC970:
56  *
57  * Any PMC can count a direct event.  Indirect events are handled specially.
58  * Direct events: As published.
59  *
60  * Encoding 00 000 -- Add byte lane bit counters
61  *   MMCR1[24:31] -- select bit matching PMC being an adder.
62  * Bus events:
63  * PMCxSEL: 1x -- select from byte lane: 10 == lower lane (0/1), 11 == upper
64  * lane (2/3).
65  * PMCxSEL[2:4] -- bit in the byte lane selected.
66  *
67  * PMC[1,2,5,6] == lane 0/lane 2
68  * PMC[3,4,7,8] == lane 1,3
69  *
70  *
71  * Lanes:
72  * Lane 0 -- TTM0(FPU,ISU,IFU,VPU)
73  *           TTM1(IDU,ISU,STS)
74  *           LSU0 byte 0
75  *           LSU1 byte 0
76  * Lane 1 -- TTM0
77  *           TTM1
78  *           LSU0 byte 1
79  *           LSU1 byte 1
80  * Lane 2 -- TTM0
81  *           TTM1
82  *           LSU0 byte 2
83  *           LSU1 byte 2 or byte 6
84  * Lane 3 -- TTM0
85  *           TTM1
86  *           LSU0 byte 3
87  *           LSU1 byte 3 or byte 7
88  *
89  * Adders:
90  *  Add byte lane for PMC (above), bit 0+4, 1+5, 2+6, 3+7
91  */
92
93 struct pmc_ppc970_event {
94         enum pmc_event pe_event;
95         uint32_t pe_flags;
96 #define PMC_PPC970_FLAG_PMCS    0x000000ff
97 #define  PMC_PPC970_FLAG_PMC1   0x01
98 #define  PMC_PPC970_FLAG_PMC2   0x02
99 #define  PMC_PPC970_FLAG_PMC3   0x04
100 #define  PMC_PPC970_FLAG_PMC4   0x08
101 #define  PMC_PPC970_FLAG_PMC5   0x10
102 #define  PMC_PPC970_FLAG_PMC6   0x20
103 #define  PMC_PPC970_FLAG_PMC7   0x40
104 #define  PMC_PPC970_FLAG_PMC8   0x80
105         uint32_t pe_code;
106 };
107
108 static struct pmc_ppc970_event ppc970_event_codes[] = {
109         {PMC_EV_PPC970_INSTR_COMPLETED,
110             .pe_flags = PMC_PPC970_FLAG_PMCS,
111             .pe_code = 0x09
112         },
113         {PMC_EV_PPC970_MARKED_GROUP_DISPATCH,
114                 .pe_flags = PMC_PPC970_FLAG_PMC1,
115                 .pe_code = 0x2
116         },
117         {PMC_EV_PPC970_MARKED_STORE_COMPLETED,
118                 .pe_flags = PMC_PPC970_FLAG_PMC1,
119                 .pe_code = 0x03
120         },
121         {PMC_EV_PPC970_GCT_EMPTY,
122                 .pe_flags = PMC_PPC970_FLAG_PMC1,
123                 .pe_code = 0x04
124         },
125         {PMC_EV_PPC970_RUN_CYCLES,
126                 .pe_flags = PMC_PPC970_FLAG_PMC1,
127                 .pe_code = 0x05
128         },
129         {PMC_EV_PPC970_OVERFLOW,
130                 .pe_flags = PMC_PPC970_FLAG_PMCS,
131                 .pe_code = 0x0a
132         },
133         {PMC_EV_PPC970_CYCLES,
134                 .pe_flags = PMC_PPC970_FLAG_PMCS,
135                 .pe_code = 0x0f
136         },
137         {PMC_EV_PPC970_THRESHOLD_TIMEOUT,
138                 .pe_flags = PMC_PPC970_FLAG_PMC2,
139                 .pe_code = 0x3
140         },
141         {PMC_EV_PPC970_GROUP_DISPATCH,
142                 .pe_flags = PMC_PPC970_FLAG_PMC2,
143                 .pe_code = 0x4
144         },
145         {PMC_EV_PPC970_BR_MARKED_INSTR_FINISH,
146                 .pe_flags = PMC_PPC970_FLAG_PMC2,
147                 .pe_code = 0x5
148         },
149         {PMC_EV_PPC970_GCT_EMPTY_BY_SRQ_FULL,
150                 .pe_flags = PMC_PPC970_FLAG_PMC2,
151                 .pe_code = 0xb
152         },
153         {PMC_EV_PPC970_STOP_COMPLETION,
154                 .pe_flags = PMC_PPC970_FLAG_PMC3,
155                 .pe_code = 0x1
156         },
157         {PMC_EV_PPC970_LSU_EMPTY,
158                 .pe_flags = PMC_PPC970_FLAG_PMC3,
159                 .pe_code = 0x2
160         },
161         {PMC_EV_PPC970_MARKED_STORE_WITH_INTR,
162                 .pe_flags = PMC_PPC970_FLAG_PMC3,
163                 .pe_code = 0x3
164         },
165         {PMC_EV_PPC970_CYCLES_IN_SUPER,
166                 .pe_flags = PMC_PPC970_FLAG_PMC3,
167                 .pe_code = 0x4
168         },
169         {PMC_EV_PPC970_VPU_MARKED_INSTR_COMPLETED,
170                 .pe_flags = PMC_PPC970_FLAG_PMC3,
171                 .pe_code = 0x5
172         },
173         {PMC_EV_PPC970_FXU0_IDLE_FXU1_BUSY,
174                 .pe_flags = PMC_PPC970_FLAG_PMC4,
175                 .pe_code = 0x2
176         },
177         {PMC_EV_PPC970_SRQ_EMPTY,
178                 .pe_flags = PMC_PPC970_FLAG_PMC4,
179                 .pe_code = 0x3
180         },
181         {PMC_EV_PPC970_MARKED_GROUP_COMPLETED,
182                 .pe_flags = PMC_PPC970_FLAG_PMC4,
183                 .pe_code = 0x4
184         },
185         {PMC_EV_PPC970_CR_MARKED_INSTR_FINISH,
186                 .pe_flags = PMC_PPC970_FLAG_PMC4,
187                 .pe_code = 0x5
188         },
189         {PMC_EV_PPC970_DISPATCH_SUCCESS,
190                 .pe_flags = PMC_PPC970_FLAG_PMC5,
191                 .pe_code = 0x1
192         },
193         {PMC_EV_PPC970_FXU0_IDLE_FXU1_IDLE,
194                 .pe_flags = PMC_PPC970_FLAG_PMC5,
195                 .pe_code = 0x2
196         },
197         {PMC_EV_PPC970_ONE_PLUS_INSTR_COMPLETED,
198                 .pe_flags = PMC_PPC970_FLAG_PMC5,
199                 .pe_code = 0x3
200         },
201         {PMC_EV_PPC970_GROUP_MARKED_IDU,
202                 .pe_flags = PMC_PPC970_FLAG_PMC5,
203                 .pe_code = 0x4
204         },
205         {PMC_EV_PPC970_MARKED_GROUP_COMPLETE_TIMEOUT,
206                 .pe_flags = PMC_PPC970_FLAG_PMC5,
207                 .pe_code = 0x5
208         },
209         {PMC_EV_PPC970_FXU0_BUSY_FXU1_BUSY,
210                 .pe_flags = PMC_PPC970_FLAG_PMC6,
211                 .pe_code = 0x2
212         },
213         {PMC_EV_PPC970_MARKED_STORE_SENT_TO_STS,
214                 .pe_flags = PMC_PPC970_FLAG_PMC6,
215                 .pe_code = 0x3
216         },
217         {PMC_EV_PPC970_FXU_MARKED_INSTR_FINISHED,
218                 .pe_flags = PMC_PPC970_FLAG_PMC6,
219                 .pe_code = 0x4
220         },
221         {PMC_EV_PPC970_MARKED_GROUP_ISSUED,
222                 .pe_flags = PMC_PPC970_FLAG_PMC6,
223                 .pe_code = 0x5
224         },
225         {PMC_EV_PPC970_FXU0_BUSY_FXU1_IDLE,
226                 .pe_flags = PMC_PPC970_FLAG_PMC7,
227                 .pe_code = 0x2
228         },
229         {PMC_EV_PPC970_GROUP_COMPLETED,
230                 .pe_flags = PMC_PPC970_FLAG_PMC7,
231                 .pe_code = 0x3
232         },
233         {PMC_EV_PPC970_FPU_MARKED_INSTR_COMPLETED,
234                 .pe_flags = PMC_PPC970_FLAG_PMC7,
235                 .pe_code = 0x4
236         },
237         {PMC_EV_PPC970_MARKED_INSTR_FINISH_ANY_UNIT,
238                 .pe_flags = PMC_PPC970_FLAG_PMC7,
239                 .pe_code = 0x5
240         },
241         {PMC_EV_PPC970_EXTERNAL_INTERRUPT,
242                 .pe_flags = PMC_PPC970_FLAG_PMC8,
243                 .pe_code = 0x2
244         },
245         {PMC_EV_PPC970_GROUP_DISPATCH_REJECT,
246                 .pe_flags = PMC_PPC970_FLAG_PMC8,
247                 .pe_code = 0x3
248         },
249         {PMC_EV_PPC970_LSU_MARKED_INSTR_FINISH,
250                 .pe_flags = PMC_PPC970_FLAG_PMC8,
251                 .pe_code = 0x4
252         },
253         {PMC_EV_PPC970_TIMEBASE_EVENT,
254                 .pe_flags = PMC_PPC970_FLAG_PMC8,
255                 .pe_code = 0x5
256         },
257 #if 0
258         {PMC_EV_PPC970_LSU_COMPLETION_STALL, },
259         {PMC_EV_PPC970_FXU_COMPLETION_STALL, },
260         {PMC_EV_PPC970_DCACHE_MISS_COMPLETION_STALL, },
261         {PMC_EV_PPC970_FPU_COMPLETION_STALL, },
262         {PMC_EV_PPC970_FXU_LONG_INSTR_COMPLETION_STALL, },
263         {PMC_EV_PPC970_REJECT_COMPLETION_STALL, },
264         {PMC_EV_PPC970_FPU_LONG_INSTR_COMPLETION_STALL, },
265         {PMC_EV_PPC970_GCT_EMPTY_BY_ICACHE_MISS, },
266         {PMC_EV_PPC970_REJECT_COMPLETION_STALL_ERAT_MISS, },
267         {PMC_EV_PPC970_GCT_EMPTY_BY_BRANCH_MISS_PREDICT, },
268 #endif
269 };
270 static size_t ppc970_event_codes_size = nitems(ppc970_event_codes);
271
272 static pmc_value_t
273 ppc970_pmcn_read(unsigned int pmc)
274 {
275         pmc_value_t val;
276
277         switch (pmc) {
278                 case 0:
279                         val = mfspr(SPR_970PMC1);
280                         break;
281                 case 1:
282                         val = mfspr(SPR_970PMC2);
283                         break;
284                 case 2:
285                         val = mfspr(SPR_970PMC3);
286                         break;
287                 case 3:
288                         val = mfspr(SPR_970PMC4);
289                         break;
290                 case 4:
291                         val = mfspr(SPR_970PMC5);
292                         break;
293                 case 5:
294                         val = mfspr(SPR_970PMC6);
295                         break;
296                 case 6:
297                         val = mfspr(SPR_970PMC7);
298                         break;
299                 case 7:
300                         val = mfspr(SPR_970PMC8);
301                         break;
302                 default:
303                         panic("Invalid PMC number: %d\n", pmc);
304         }
305
306         return (val);
307 }
308
309 static void
310 ppc970_pmcn_write(unsigned int pmc, uint32_t val)
311 {
312         switch (pmc) {
313                 case 0:
314                         mtspr(SPR_970PMC1, val);
315                         break;
316                 case 1:
317                         mtspr(SPR_970PMC2, val);
318                         break;
319                 case 2:
320                         mtspr(SPR_970PMC3, val);
321                         break;
322                 case 3:
323                         mtspr(SPR_970PMC4, val);
324                         break;
325                 case 4:
326                         mtspr(SPR_970PMC5, val);
327                         break;
328                 case 5:
329                         mtspr(SPR_970PMC6, val);
330                         break;
331                 case 6:
332                         mtspr(SPR_970PMC7, val);
333                         break;
334                 case 7:
335                         mtspr(SPR_970PMC8, val);
336                         break;
337                 default:
338                         panic("Invalid PMC number: %d\n", pmc);
339         }
340 }
341
342 static int
343 ppc970_config_pmc(int cpu, int ri, struct pmc *pm)
344 {
345         struct pmc_hw *phw;
346
347         PMCDBG3(MDP,CFG,1, "cpu=%d ri=%d pm=%p", cpu, ri, pm);
348
349         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
350             ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
351         KASSERT(ri >= 0 && ri < PPC970_MAX_PMCS,
352             ("[powerpc,%d] illegal row-index %d", __LINE__, ri));
353
354         phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
355
356         KASSERT(pm == NULL || phw->phw_pmc == NULL,
357             ("[powerpc,%d] pm=%p phw->pm=%p hwpmc not unconfigured",
358             __LINE__, pm, phw->phw_pmc));
359
360         phw->phw_pmc = pm;
361
362         return 0;
363 }
364
365 static int
366 ppc970_set_pmc(int cpu, int ri, int config)
367 {
368         struct pmc *pm;
369         struct pmc_hw *phw;
370         register_t pmc_mmcr;
371
372         phw    = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
373         pm     = phw->phw_pmc;
374
375         /*
376          * Disable the PMCs.
377          */
378         switch (ri) {
379         case 0:
380         case 1:
381                 pmc_mmcr = mfspr(SPR_970MMCR0);
382                 pmc_mmcr = PPC970_SET_MMCR0_PMCSEL(pmc_mmcr, config, ri);
383                 mtspr(SPR_970MMCR0, pmc_mmcr);
384                 break;
385         case 2:
386         case 3:
387         case 4:
388         case 5:
389         case 6:
390         case 7:
391                 pmc_mmcr = mfspr(SPR_970MMCR1);
392                 pmc_mmcr = PPC970_SET_MMCR1_PMCSEL(pmc_mmcr, config, ri);
393                 mtspr(SPR_970MMCR1, pmc_mmcr);
394                 break;
395         }
396         return 0;
397 }
398
399 static int
400 ppc970_start_pmc(int cpu, int ri)
401 {
402         struct pmc *pm;
403         struct pmc_hw *phw;
404         register_t pmc_mmcr;
405         uint32_t config;
406         int error;
407
408         phw    = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
409         pm     = phw->phw_pmc;
410         config = pm->pm_md.pm_powerpc.pm_powerpc_evsel & ~POWERPC_PMC_ENABLE;
411
412         error = ppc970_set_pmc(cpu, ri, config);
413         
414         /* The mask is inverted (enable is 1) compared to the flags in MMCR0, which
415          * are Freeze flags.
416          */
417         config = ~pm->pm_md.pm_powerpc.pm_powerpc_evsel & POWERPC_PMC_ENABLE;
418
419         pmc_mmcr = mfspr(SPR_970MMCR0);
420         pmc_mmcr &= ~SPR_MMCR0_FC;
421         pmc_mmcr |= config;
422         mtspr(SPR_970MMCR0, pmc_mmcr);
423
424         return 0;
425 }
426
427 static int
428 ppc970_stop_pmc(int cpu, int ri)
429 {
430         return ppc970_set_pmc(cpu, ri, PMC970N_NONE);
431 }
432
433 static int
434 ppc970_read_pmc(int cpu, int ri, pmc_value_t *v)
435 {
436         struct pmc *pm;
437         pmc_value_t tmp;
438
439         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
440             ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
441         KASSERT(ri >= 0 && ri < PPC970_MAX_PMCS,
442             ("[powerpc,%d] illegal row index %d", __LINE__, ri));
443
444         pm  = powerpc_pcpu[cpu]->pc_ppcpmcs[ri].phw_pmc;
445         KASSERT(pm,
446             ("[core,%d] cpu %d ri %d pmc not configured", __LINE__, cpu,
447                 ri));
448
449         tmp = ppc970_pmcn_read(ri);
450         PMCDBG2(MDP,REA,2,"ppc-read id=%d -> %jd", ri, tmp);
451         if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
452                 *v = POWERPC_PERFCTR_VALUE_TO_RELOAD_COUNT(tmp);
453         else
454                 *v = tmp;
455
456         return 0;
457 }
458
459 static int
460 ppc970_write_pmc(int cpu, int ri, pmc_value_t v)
461 {
462         struct pmc *pm;
463
464         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
465             ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
466         KASSERT(ri >= 0 && ri < PPC970_MAX_PMCS,
467             ("[powerpc,%d] illegal row-index %d", __LINE__, ri));
468
469         pm  = powerpc_pcpu[cpu]->pc_ppcpmcs[ri].phw_pmc;
470
471         if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
472                 v = POWERPC_RELOAD_COUNT_TO_PERFCTR_VALUE(v);
473         
474         PMCDBG3(MDP,WRI,1,"powerpc-write cpu=%d ri=%d v=%jx", cpu, ri, v);
475
476         ppc970_pmcn_write(ri, v);
477
478         return 0;
479 }
480
481 static int
482 ppc970_intr(struct trapframe *tf)
483 {
484         struct pmc *pm;
485         struct powerpc_cpu *pac;
486         uint32_t config;
487         int i, error, retval, cpu;
488
489         cpu = curcpu;
490         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
491             ("[powerpc,%d] out of range CPU %d", __LINE__, cpu));
492
493         PMCDBG3(MDP,INT,1, "cpu=%d tf=%p um=%d", cpu, (void *) tf,
494             TRAPF_USERMODE(tf));
495
496         retval = 0;
497
498         pac = powerpc_pcpu[cpu];
499
500         /*
501          * look for all PMCs that have interrupted:
502          * - look for a running, sampling PMC which has overflowed
503          *   and which has a valid 'struct pmc' association
504          *
505          * If found, we call a helper to process the interrupt.
506          */
507
508         config  = mfspr(SPR_970MMCR0) & ~SPR_MMCR0_FC;
509         for (i = 0; i < PPC970_MAX_PMCS; i++) {
510                 if ((pm = pac->pc_ppcpmcs[i].phw_pmc) == NULL ||
511                     !PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) {
512                         continue;
513                 }
514
515                 if (!PPC970_PMC_HAS_OVERFLOWED(i))
516                         continue;
517
518                 retval = 1;     /* Found an interrupting PMC. */
519
520                 if (pm->pm_state != PMC_STATE_RUNNING)
521                         continue;
522
523                 error = pmc_process_interrupt(PMC_HR, pm, tf);
524                 if (error != 0)
525                         ppc970_stop_pmc(cpu, i);
526
527                 /* reload sampling count. */
528                 ppc970_write_pmc(cpu, i, pm->pm_sc.pm_reloadcount);
529         }
530
531         if (retval)
532                 counter_u64_add(pmc_stats.pm_intr_processed, 1);
533         else
534                 counter_u64_add(pmc_stats.pm_intr_ignored, 1);
535
536         /* Re-enable PERF exceptions. */
537         if (retval)
538                 mtspr(SPR_970MMCR0, config | SPR_MMCR0_PMXE);
539
540         return (retval);
541 }
542
543 static int
544 ppc970_pcpu_init(struct pmc_mdep *md, int cpu)
545 {
546         struct pmc_cpu *pc;
547         struct powerpc_cpu *pac;
548         struct pmc_hw  *phw;
549         int first_ri, i;
550
551         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
552             ("[powerpc,%d] wrong cpu number %d", __LINE__, cpu));
553         PMCDBG1(MDP,INI,1,"powerpc-init cpu=%d", cpu);
554
555         powerpc_pcpu[cpu] = pac = malloc(sizeof(struct powerpc_cpu), M_PMC,
556             M_WAITOK|M_ZERO);
557         pac->pc_ppcpmcs = malloc(sizeof(struct pmc_hw) * PPC970_MAX_PMCS,
558             M_PMC, M_WAITOK|M_ZERO);
559         pac->pc_class = PMC_CLASS_PPC970;
560
561         pc = pmc_pcpu[cpu];
562         first_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_POWERPC].pcd_ri;
563         KASSERT(pc != NULL, ("[powerpc,%d] NULL per-cpu pointer", __LINE__));
564
565         for (i = 0, phw = pac->pc_ppcpmcs; i < PPC970_MAX_PMCS; i++, phw++) {
566                 phw->phw_state    = PMC_PHW_FLAG_IS_ENABLED |
567                     PMC_PHW_CPU_TO_STATE(cpu) | PMC_PHW_INDEX_TO_STATE(i);
568                 phw->phw_pmc      = NULL;
569                 pc->pc_hwpmcs[i + first_ri] = phw;
570         }
571
572         /* Clear the MMCRs, and set FC, to disable all PMCs. */
573         /* 970 PMC is not counted when set to 0x08 */
574         mtspr(SPR_970MMCR0, SPR_MMCR0_FC | SPR_MMCR0_PMXE |
575             SPR_MMCR0_FCECE | SPR_MMCR0_PMC1CE | SPR_MMCR0_PMCNCE |
576             SPR_970MMCR0_PMC1SEL(0x8) | SPR_970MMCR0_PMC2SEL(0x8));
577         mtspr(SPR_970MMCR1, 0x4218420);
578
579         return 0;
580 }
581
582 static int
583 ppc970_pcpu_fini(struct pmc_mdep *md, int cpu)
584 {
585         register_t mmcr0 = mfspr(SPR_MMCR0);
586
587         mmcr0 |= SPR_MMCR0_FC;
588         mmcr0 &= ~SPR_MMCR0_PMXE;
589         mtspr(SPR_MMCR0, mmcr0);
590
591         free(powerpc_pcpu[cpu]->pc_ppcpmcs, M_PMC);
592         free(powerpc_pcpu[cpu], M_PMC);
593
594         return 0;
595 }
596
597 static int
598 ppc970_allocate_pmc(int cpu, int ri, struct pmc *pm,
599   const struct pmc_op_pmcallocate *a)
600 {
601         enum pmc_event pe;
602         uint32_t caps, config = 0, counter = 0;
603         int i;
604
605         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
606             ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
607         KASSERT(ri >= 0 && ri < PPC970_MAX_PMCS,
608             ("[powerpc,%d] illegal row index %d", __LINE__, ri));
609
610         caps = a->pm_caps;
611
612         pe = a->pm_ev;
613
614         if (pe < PMC_EV_PPC970_FIRST || pe > PMC_EV_PPC970_LAST)
615                 return (EINVAL);
616
617         for (i = 0; i < ppc970_event_codes_size; i++) {
618                 if (ppc970_event_codes[i].pe_event == pe) {
619                         config = ppc970_event_codes[i].pe_code;
620                         counter =  ppc970_event_codes[i].pe_flags;
621                         break;
622                 }
623         }
624         if (i == ppc970_event_codes_size)
625                 return (EINVAL);
626
627         if ((counter & (1 << ri)) == 0)
628                 return (EINVAL);
629
630         if (caps & PMC_CAP_SYSTEM)
631                 config |= POWERPC_PMC_KERNEL_ENABLE;
632         if (caps & PMC_CAP_USER)
633                 config |= POWERPC_PMC_USER_ENABLE;
634         if ((caps & (PMC_CAP_USER | PMC_CAP_SYSTEM)) == 0)
635                 config |= POWERPC_PMC_ENABLE;
636
637         pm->pm_md.pm_powerpc.pm_powerpc_evsel = config;
638
639         PMCDBG2(MDP,ALL,2,"powerpc-allocate ri=%d -> config=0x%x", ri, config);
640
641         return 0;
642 }
643
644 static int
645 ppc970_release_pmc(int cpu, int ri, struct pmc *pmc)
646 {
647         struct pmc_hw *phw;
648
649         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
650             ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
651         KASSERT(ri >= 0 && ri < PPC970_MAX_PMCS,
652             ("[powerpc,%d] illegal row-index %d", __LINE__, ri));
653
654         phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
655         KASSERT(phw->phw_pmc == NULL,
656             ("[powerpc,%d] PHW pmc %p non-NULL", __LINE__, phw->phw_pmc));
657
658         return 0;
659 }
660
661 int
662 pmc_ppc970_initialize(struct pmc_mdep *pmc_mdep)
663 {
664         struct pmc_classdep *pcd;
665         
666         pmc_mdep->pmd_cputype = PMC_CPU_PPC_970;
667
668         pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_POWERPC];
669         pcd->pcd_caps  = POWERPC_PMC_CAPS;
670         pcd->pcd_class = PMC_CLASS_PPC970;
671         pcd->pcd_num   = PPC970_MAX_PMCS;
672         pcd->pcd_ri    = pmc_mdep->pmd_npmc;
673         pcd->pcd_width = 32;
674
675         pcd->pcd_allocate_pmc   = ppc970_allocate_pmc;
676         pcd->pcd_config_pmc     = ppc970_config_pmc;
677         pcd->pcd_pcpu_fini      = ppc970_pcpu_fini;
678         pcd->pcd_pcpu_init      = ppc970_pcpu_init;
679         pcd->pcd_describe       = powerpc_describe;
680         pcd->pcd_get_config     = powerpc_get_config;
681         pcd->pcd_read_pmc       = ppc970_read_pmc;
682         pcd->pcd_release_pmc    = ppc970_release_pmc;
683         pcd->pcd_start_pmc      = ppc970_start_pmc;
684         pcd->pcd_stop_pmc       = ppc970_stop_pmc;
685         pcd->pcd_write_pmc      = ppc970_write_pmc;
686
687         pmc_mdep->pmd_npmc     += PPC970_MAX_PMCS;
688         pmc_mdep->pmd_intr      = ppc970_intr;
689
690         return (0);
691 }