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
93struct 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
108static 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};
270static size_t ppc970_event_codes_size = nitems(ppc970_event_codes);
271
272static pmc_value_t
273ppc970_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
309static void
310ppc970_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
342static int
343ppc970_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
365static int
366ppc970_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
399static int
400ppc970_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
427static int
428ppc970_stop_pmc(int cpu, int ri)
429{
430	return ppc970_set_pmc(cpu, ri, PMC970N_NONE);
431}
432
433static int
434ppc970_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
459static int
460ppc970_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
481static int
482ppc970_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
543static int
544ppc970_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
582static int
583ppc970_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
597static int
598ppc970_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
644static int
645ppc970_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
661int
662pmc_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}
692