xref: /freebsd/sys/dev/hwpmc/hwpmc_power8.c (revision b48a2770d48b9f9aa61788704897e9a2e9e10c09)
168dd7182SLeandro Lupori /*-
268dd7182SLeandro Lupori  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
368dd7182SLeandro Lupori  *
468dd7182SLeandro Lupori  * Copyright (c) 2013 Justin Hibbits
568dd7182SLeandro Lupori  * Copyright (c) 2020 Leandro Lupori
668dd7182SLeandro Lupori  * All rights reserved.
768dd7182SLeandro Lupori  *
868dd7182SLeandro Lupori  * Redistribution and use in source and binary forms, with or without
968dd7182SLeandro Lupori  * modification, are permitted provided that the following conditions
1068dd7182SLeandro Lupori  * are met:
1168dd7182SLeandro Lupori  * 1. Redistributions of source code must retain the above copyright
1268dd7182SLeandro Lupori  *    notice, this list of conditions and the following disclaimer.
1368dd7182SLeandro Lupori  * 2. Redistributions in binary form must reproduce the above copyright
1468dd7182SLeandro Lupori  *    notice, this list of conditions and the following disclaimer in the
1568dd7182SLeandro Lupori  *    documentation and/or other materials provided with the distribution.
1668dd7182SLeandro Lupori  *
1768dd7182SLeandro Lupori  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1868dd7182SLeandro Lupori  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1968dd7182SLeandro Lupori  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2068dd7182SLeandro Lupori  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2168dd7182SLeandro Lupori  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2268dd7182SLeandro Lupori  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2368dd7182SLeandro Lupori  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2468dd7182SLeandro Lupori  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2568dd7182SLeandro Lupori  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2668dd7182SLeandro Lupori  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2768dd7182SLeandro Lupori  * SUCH DAMAGE.
2868dd7182SLeandro Lupori  */
2968dd7182SLeandro Lupori 
3068dd7182SLeandro Lupori #include <sys/cdefs.h>
3168dd7182SLeandro Lupori __FBSDID("$FreeBSD$");
3268dd7182SLeandro Lupori 
3368dd7182SLeandro Lupori #include <sys/param.h>
3468dd7182SLeandro Lupori #include <sys/pmc.h>
3568dd7182SLeandro Lupori #include <sys/pmckern.h>
3668dd7182SLeandro Lupori #include <sys/systm.h>
3768dd7182SLeandro Lupori 
3868dd7182SLeandro Lupori #include <machine/pmc_mdep.h>
3968dd7182SLeandro Lupori #include <machine/spr.h>
4068dd7182SLeandro Lupori #include <machine/cpu.h>
4168dd7182SLeandro Lupori 
4268dd7182SLeandro Lupori #include "hwpmc_powerpc.h"
4368dd7182SLeandro Lupori 
4468dd7182SLeandro Lupori #define	POWER8_MAX_PMCS		6
4568dd7182SLeandro Lupori 
46*b48a2770SLeandro Lupori #define PM_EVENT_CODE(pe)	(pe & 0xffff)
47*b48a2770SLeandro Lupori #define PM_EVENT_COUNTER(pe)	((pe >> 16) & 0xffff)
48*b48a2770SLeandro Lupori 
49*b48a2770SLeandro Lupori #define PM_CYC			0x1e
50*b48a2770SLeandro Lupori #define PM_INST_CMPL		0x02
51*b48a2770SLeandro Lupori 
5268dd7182SLeandro Lupori static struct pmc_ppc_event power8_event_codes[] = {
5368dd7182SLeandro Lupori 	{PMC_EV_POWER8_INSTR_COMPLETED,
5468dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC5,
5568dd7182SLeandro Lupori 	    .pe_code = 0x00
5668dd7182SLeandro Lupori 	},
5768dd7182SLeandro Lupori 	/*
5868dd7182SLeandro Lupori 	 * PMC1 can also count cycles, but as PMC6 can only count cycles
5968dd7182SLeandro Lupori 	 * it's better to always use it and leave PMC1 free to count
6068dd7182SLeandro Lupori 	 * other events.
6168dd7182SLeandro Lupori 	 */
6268dd7182SLeandro Lupori 	{PMC_EV_POWER8_CYCLES,
6368dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC6,
6468dd7182SLeandro Lupori 	    .pe_code = 0xf0
6568dd7182SLeandro Lupori 	},
6668dd7182SLeandro Lupori 	{PMC_EV_POWER8_CYCLES_WITH_INSTRS_COMPLETED,
6768dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC1,
6868dd7182SLeandro Lupori 	    .pe_code = 0xf2
6968dd7182SLeandro Lupori 	},
7068dd7182SLeandro Lupori 	{PMC_EV_POWER8_FPU_INSTR_COMPLETED,
7168dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC1,
7268dd7182SLeandro Lupori 	    .pe_code = 0xf4
7368dd7182SLeandro Lupori 	},
7468dd7182SLeandro Lupori 	{PMC_EV_POWER8_ERAT_INSTR_MISS,
7568dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC1,
7668dd7182SLeandro Lupori 	    .pe_code = 0xf6
7768dd7182SLeandro Lupori 	},
7868dd7182SLeandro Lupori 	{PMC_EV_POWER8_CYCLES_IDLE,
7968dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC1,
8068dd7182SLeandro Lupori 	    .pe_code = 0xf8
8168dd7182SLeandro Lupori 	},
8268dd7182SLeandro Lupori 	{PMC_EV_POWER8_CYCLES_WITH_ANY_THREAD_RUNNING,
8368dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC1,
8468dd7182SLeandro Lupori 	    .pe_code = 0xfa
8568dd7182SLeandro Lupori 	},
8668dd7182SLeandro Lupori 	{PMC_EV_POWER8_STORE_COMPLETED,
8768dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC2,
8868dd7182SLeandro Lupori 	    .pe_code = 0xf0
8968dd7182SLeandro Lupori 	},
9068dd7182SLeandro Lupori 	{PMC_EV_POWER8_INSTR_DISPATCHED,
9168dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC2 | PMC_FLAG_PMC3,
9268dd7182SLeandro Lupori 	    .pe_code = 0xf2
9368dd7182SLeandro Lupori 	},
9468dd7182SLeandro Lupori 	{PMC_EV_POWER8_CYCLES_RUNNING,
9568dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC2,
9668dd7182SLeandro Lupori 	    .pe_code = 0xf4
9768dd7182SLeandro Lupori 	},
9868dd7182SLeandro Lupori 	{PMC_EV_POWER8_ERAT_DATA_MISS,
9968dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC2,
10068dd7182SLeandro Lupori 	    .pe_code = 0xf6
10168dd7182SLeandro Lupori 	},
10268dd7182SLeandro Lupori 	{PMC_EV_POWER8_EXTERNAL_INTERRUPT,
10368dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC2,
10468dd7182SLeandro Lupori 	    .pe_code = 0xf8
10568dd7182SLeandro Lupori 	},
10668dd7182SLeandro Lupori 	{PMC_EV_POWER8_BRANCH_TAKEN,
10768dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC2,
10868dd7182SLeandro Lupori 	    .pe_code = 0xfa
10968dd7182SLeandro Lupori 	},
11068dd7182SLeandro Lupori 	{PMC_EV_POWER8_L1_INSTR_MISS,
11168dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC2,
11268dd7182SLeandro Lupori 	    .pe_code = 0xfc
11368dd7182SLeandro Lupori 	},
11468dd7182SLeandro Lupori 	{PMC_EV_POWER8_L2_LOAD_MISS,
11568dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC2,
11668dd7182SLeandro Lupori 	    .pe_code = 0xfe
11768dd7182SLeandro Lupori 	},
11868dd7182SLeandro Lupori 	{PMC_EV_POWER8_STORE_NO_REAL_ADDR,
11968dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC3,
12068dd7182SLeandro Lupori 	    .pe_code = 0xf0
12168dd7182SLeandro Lupori 	},
12268dd7182SLeandro Lupori 	{PMC_EV_POWER8_INSTR_COMPLETED_WITH_ALL_THREADS_RUNNING,
12368dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC3,
12468dd7182SLeandro Lupori 	    .pe_code = 0xf4
12568dd7182SLeandro Lupori 	},
12668dd7182SLeandro Lupori 	{PMC_EV_POWER8_L1_LOAD_MISS,
12768dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC3,
12868dd7182SLeandro Lupori 	    .pe_code = 0xf6
12968dd7182SLeandro Lupori 	},
13068dd7182SLeandro Lupori 	{PMC_EV_POWER8_TIMEBASE_EVENT,
13168dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC3,
13268dd7182SLeandro Lupori 	    .pe_code = 0xf8
13368dd7182SLeandro Lupori 	},
13468dd7182SLeandro Lupori 	{PMC_EV_POWER8_L3_INSTR_MISS,
13568dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC3,
13668dd7182SLeandro Lupori 	    .pe_code = 0xfa
13768dd7182SLeandro Lupori 	},
13868dd7182SLeandro Lupori 	{PMC_EV_POWER8_TLB_DATA_MISS,
13968dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC3,
14068dd7182SLeandro Lupori 	    .pe_code = 0xfc
14168dd7182SLeandro Lupori 	},
14268dd7182SLeandro Lupori 	{PMC_EV_POWER8_L3_LOAD_MISS,
14368dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC3,
14468dd7182SLeandro Lupori 	    .pe_code = 0xfe
14568dd7182SLeandro Lupori 	},
14668dd7182SLeandro Lupori 	{PMC_EV_POWER8_LOAD_NO_REAL_ADDR,
14768dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC4,
14868dd7182SLeandro Lupori 	    .pe_code = 0xf0
14968dd7182SLeandro Lupori 	},
15068dd7182SLeandro Lupori 	{PMC_EV_POWER8_CYCLES_WITH_INSTRS_DISPATCHED,
15168dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC4,
15268dd7182SLeandro Lupori 	    .pe_code = 0xf2
15368dd7182SLeandro Lupori 	},
15468dd7182SLeandro Lupori 	{PMC_EV_POWER8_CYCLES_RUNNING_PURR_INC,
15568dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC4,
15668dd7182SLeandro Lupori 	    .pe_code = 0xf4
15768dd7182SLeandro Lupori 	},
15868dd7182SLeandro Lupori 	{PMC_EV_POWER8_BRANCH_MISPREDICTED,
15968dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC4,
16068dd7182SLeandro Lupori 	    .pe_code = 0xf6
16168dd7182SLeandro Lupori 	},
16268dd7182SLeandro Lupori 	{PMC_EV_POWER8_PREFETCHED_INSTRS_DISCARDED,
16368dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC4,
16468dd7182SLeandro Lupori 	    .pe_code = 0xf8
16568dd7182SLeandro Lupori 	},
16668dd7182SLeandro Lupori 	{PMC_EV_POWER8_INSTR_COMPLETED_RUNNING,
16768dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC4,
16868dd7182SLeandro Lupori 	    .pe_code = 0xfa
16968dd7182SLeandro Lupori 	},
17068dd7182SLeandro Lupori 	{PMC_EV_POWER8_TLB_INSTR_MISS,
17168dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC4,
17268dd7182SLeandro Lupori 	    .pe_code = 0xfc
17368dd7182SLeandro Lupori 	},
17468dd7182SLeandro Lupori 	{PMC_EV_POWER8_CACHE_LOAD_MISS,
17568dd7182SLeandro Lupori 	    .pe_flags = PMC_FLAG_PMC4,
17668dd7182SLeandro Lupori 	    .pe_code = 0xfe
17768dd7182SLeandro Lupori 	}
17868dd7182SLeandro Lupori };
17968dd7182SLeandro Lupori static size_t power8_event_codes_size = nitems(power8_event_codes);
18068dd7182SLeandro Lupori 
18168dd7182SLeandro Lupori static void
18268dd7182SLeandro Lupori power8_set_pmc(int cpu, int ri, int config)
18368dd7182SLeandro Lupori {
18468dd7182SLeandro Lupori 	register_t mmcr;
18568dd7182SLeandro Lupori 
18668dd7182SLeandro Lupori 	/* Select event */
18768dd7182SLeandro Lupori 	switch (ri) {
18868dd7182SLeandro Lupori 	case 0:
18968dd7182SLeandro Lupori 	case 1:
19068dd7182SLeandro Lupori 	case 2:
19168dd7182SLeandro Lupori 	case 3:
19268dd7182SLeandro Lupori 		mmcr = mfspr(SPR_MMCR1);
19368dd7182SLeandro Lupori 		mmcr &= ~SPR_MMCR1_P8_PMCNSEL_MASK(ri);
19468dd7182SLeandro Lupori 		mmcr |= SPR_MMCR1_P8_PMCNSEL(ri, config & ~POWERPC_PMC_ENABLE);
19568dd7182SLeandro Lupori 		mtspr(SPR_MMCR1, mmcr);
19668dd7182SLeandro Lupori 		break;
19768dd7182SLeandro Lupori 	}
19868dd7182SLeandro Lupori 
19968dd7182SLeandro Lupori 	/*
20068dd7182SLeandro Lupori 	 * By default, freeze counter in all states.
20168dd7182SLeandro Lupori 	 * If counter is being started, unfreeze it in selected states.
20268dd7182SLeandro Lupori 	 */
20368dd7182SLeandro Lupori 	mmcr = mfspr(SPR_MMCR2) | SPR_MMCR2_FCNHSP(ri);
20468dd7182SLeandro Lupori 	if (config != PMCN_NONE) {
20568dd7182SLeandro Lupori 		if (config & POWERPC_PMC_USER_ENABLE)
20668dd7182SLeandro Lupori 			mmcr &= ~(SPR_MMCR2_FCNP0(ri) |
20768dd7182SLeandro Lupori 			    SPR_MMCR2_FCNP1(ri));
20868dd7182SLeandro Lupori 		if (config & POWERPC_PMC_KERNEL_ENABLE)
20968dd7182SLeandro Lupori 			mmcr &= ~(SPR_MMCR2_FCNH(ri) |
21068dd7182SLeandro Lupori 			    SPR_MMCR2_FCNS(ri));
21168dd7182SLeandro Lupori 	}
21268dd7182SLeandro Lupori 	mtspr(SPR_MMCR2, mmcr);
21368dd7182SLeandro Lupori }
21468dd7182SLeandro Lupori 
21568dd7182SLeandro Lupori static int
21668dd7182SLeandro Lupori power8_pcpu_init(struct pmc_mdep *md, int cpu)
21768dd7182SLeandro Lupori {
21868dd7182SLeandro Lupori 	register_t mmcr0;
21968dd7182SLeandro Lupori 	int i;
22068dd7182SLeandro Lupori 
22168dd7182SLeandro Lupori 	powerpc_pcpu_init(md, cpu);
22268dd7182SLeandro Lupori 
22368dd7182SLeandro Lupori 	/* Freeze all counters before modifying PMC registers */
22468dd7182SLeandro Lupori 	mmcr0 = mfspr(SPR_MMCR0) | SPR_MMCR0_FC;
22568dd7182SLeandro Lupori 	mtspr(SPR_MMCR0, mmcr0);
22668dd7182SLeandro Lupori 
22768dd7182SLeandro Lupori 	/*
22868dd7182SLeandro Lupori 	 * Now setup MMCR0:
22968dd7182SLeandro Lupori 	 *  - PMAO=0: clear alerts
23068dd7182SLeandro Lupori 	 *  - FCPC=0, FCP=0: don't freeze counters in problem state
23168dd7182SLeandro Lupori 	 *  - FCECE: Freeze Counters on Enabled Condition or Event
23268dd7182SLeandro Lupori 	 *  - PMC1CE/PMCNCE: PMC1/N Condition Enable
23368dd7182SLeandro Lupori 	 */
23468dd7182SLeandro Lupori 	mmcr0 &= ~(SPR_MMCR0_PMAO | SPR_MMCR0_FCPC | SPR_MMCR0_FCP);
23568dd7182SLeandro Lupori 	mmcr0 |= SPR_MMCR0_FCECE | SPR_MMCR0_PMC1CE | SPR_MMCR0_PMCNCE;
23668dd7182SLeandro Lupori 	mtspr(SPR_MMCR0, mmcr0);
23768dd7182SLeandro Lupori 
23868dd7182SLeandro Lupori 	/* Clear all PMCs to prevent enabled condition interrupts */
23968dd7182SLeandro Lupori 	for (i = 0; i < POWER8_MAX_PMCS; i++)
24068dd7182SLeandro Lupori 		powerpc_pmcn_write(i, 0);
24168dd7182SLeandro Lupori 
24268dd7182SLeandro Lupori 	/* Disable events in PMCs 1-4 */
24368dd7182SLeandro Lupori 	mtspr(SPR_MMCR1, mfspr(SPR_MMCR1) & ~SPR_MMCR1_P8_PMCSEL_ALL);
24468dd7182SLeandro Lupori 
24568dd7182SLeandro Lupori 	/* Freeze each counter, in all states */
24668dd7182SLeandro Lupori 	mtspr(SPR_MMCR2, mfspr(SPR_MMCR2) |
24768dd7182SLeandro Lupori 	    SPR_MMCR2_FCNHSP(0) | SPR_MMCR2_FCNHSP(1) | SPR_MMCR2_FCNHSP(2) |
24868dd7182SLeandro Lupori 	    SPR_MMCR2_FCNHSP(3) | SPR_MMCR2_FCNHSP(4) | SPR_MMCR2_FCNHSP(5));
24968dd7182SLeandro Lupori 
25068dd7182SLeandro Lupori 	/* Enable interrupts, unset global freeze */
25168dd7182SLeandro Lupori 	mmcr0 &= ~SPR_MMCR0_FC;
25268dd7182SLeandro Lupori 	mmcr0 |= SPR_MMCR0_PMAE;
25368dd7182SLeandro Lupori 	mtspr(SPR_MMCR0, mmcr0);
25468dd7182SLeandro Lupori 	return (0);
25568dd7182SLeandro Lupori }
25668dd7182SLeandro Lupori 
25768dd7182SLeandro Lupori static int
25868dd7182SLeandro Lupori power8_pcpu_fini(struct pmc_mdep *md, int cpu)
25968dd7182SLeandro Lupori {
26068dd7182SLeandro Lupori 	register_t mmcr0;
26168dd7182SLeandro Lupori 
26268dd7182SLeandro Lupori 	/* Freeze counters, disable interrupts */
26368dd7182SLeandro Lupori 	mmcr0 = mfspr(SPR_MMCR0);
26468dd7182SLeandro Lupori 	mmcr0 &= ~SPR_MMCR0_PMAE;
26568dd7182SLeandro Lupori 	mmcr0 |= SPR_MMCR0_FC;
26668dd7182SLeandro Lupori 	mtspr(SPR_MMCR0, mmcr0);
26768dd7182SLeandro Lupori 
26868dd7182SLeandro Lupori 	return (powerpc_pcpu_fini(md, cpu));
26968dd7182SLeandro Lupori }
27068dd7182SLeandro Lupori 
27168dd7182SLeandro Lupori static void
27268dd7182SLeandro Lupori power8_resume_pmc(bool ie)
27368dd7182SLeandro Lupori {
27468dd7182SLeandro Lupori 	register_t mmcr0;
27568dd7182SLeandro Lupori 
27668dd7182SLeandro Lupori 	/* Unfreeze counters and re-enable PERF exceptions if requested. */
27768dd7182SLeandro Lupori 	mmcr0 = mfspr(SPR_MMCR0);
27868dd7182SLeandro Lupori 	mmcr0 &= ~(SPR_MMCR0_FC | SPR_MMCR0_PMAO | SPR_MMCR0_PMAE);
27968dd7182SLeandro Lupori 	if (ie)
28068dd7182SLeandro Lupori 		mmcr0 |= SPR_MMCR0_PMAE;
28168dd7182SLeandro Lupori 	mtspr(SPR_MMCR0, mmcr0);
28268dd7182SLeandro Lupori }
28368dd7182SLeandro Lupori 
284*b48a2770SLeandro Lupori static int
285*b48a2770SLeandro Lupori power8_allocate_pmc(int cpu, int ri, struct pmc *pm,
286*b48a2770SLeandro Lupori 	const struct pmc_op_pmcallocate *a)
287*b48a2770SLeandro Lupori {
288*b48a2770SLeandro Lupori 	uint32_t caps, config, counter, pe;
289*b48a2770SLeandro Lupori 
290*b48a2770SLeandro Lupori 	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
291*b48a2770SLeandro Lupori 	    ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
292*b48a2770SLeandro Lupori 	KASSERT(ri >= 0 && ri < ppc_max_pmcs,
293*b48a2770SLeandro Lupori 	    ("[powerpc,%d] illegal row index %d", __LINE__, ri));
294*b48a2770SLeandro Lupori 
295*b48a2770SLeandro Lupori 	pe = a->pm_md.pm_event;
296*b48a2770SLeandro Lupori 	counter = PM_EVENT_COUNTER(pe);
297*b48a2770SLeandro Lupori 	config = PM_EVENT_CODE(pe);
298*b48a2770SLeandro Lupori 
299*b48a2770SLeandro Lupori 	/*
300*b48a2770SLeandro Lupori 	 * PMC5 and PMC6 are not programmable and always count instructions
301*b48a2770SLeandro Lupori 	 * completed and cycles, respectively.
302*b48a2770SLeandro Lupori 	 *
303*b48a2770SLeandro Lupori 	 * When counter is 0 any of the 4 programmable PMCs may be used for
304*b48a2770SLeandro Lupori 	 * the specified event, otherwise it must match ri + 1.
305*b48a2770SLeandro Lupori 	 */
306*b48a2770SLeandro Lupori 	if (counter == 0 && config == PM_INST_CMPL)
307*b48a2770SLeandro Lupori 		counter = 5;
308*b48a2770SLeandro Lupori 	else if (counter == 0 && config == PM_CYC)
309*b48a2770SLeandro Lupori 		counter = 6;
310*b48a2770SLeandro Lupori 	else if (counter > 4)
311*b48a2770SLeandro Lupori 		return (EINVAL);
312*b48a2770SLeandro Lupori 
313*b48a2770SLeandro Lupori 	if (counter != 0 && counter != ri + 1)
314*b48a2770SLeandro Lupori 		return (EINVAL);
315*b48a2770SLeandro Lupori 
316*b48a2770SLeandro Lupori 	caps = a->pm_caps;
317*b48a2770SLeandro Lupori 
318*b48a2770SLeandro Lupori 	if (caps & PMC_CAP_SYSTEM)
319*b48a2770SLeandro Lupori 		config |= POWERPC_PMC_KERNEL_ENABLE;
320*b48a2770SLeandro Lupori 	if (caps & PMC_CAP_USER)
321*b48a2770SLeandro Lupori 		config |= POWERPC_PMC_USER_ENABLE;
322*b48a2770SLeandro Lupori 	if ((caps & (PMC_CAP_USER | PMC_CAP_SYSTEM)) == 0)
323*b48a2770SLeandro Lupori 		config |= POWERPC_PMC_ENABLE;
324*b48a2770SLeandro Lupori 
325*b48a2770SLeandro Lupori 	pm->pm_md.pm_powerpc.pm_powerpc_evsel = config;
326*b48a2770SLeandro Lupori 
327*b48a2770SLeandro Lupori 	PMCDBG3(MDP,ALL,1,"powerpc-allocate cpu=%d ri=%d -> config=0x%x",
328*b48a2770SLeandro Lupori 	    cpu, ri, config);
329*b48a2770SLeandro Lupori 	return (0);
330*b48a2770SLeandro Lupori }
331*b48a2770SLeandro Lupori 
33268dd7182SLeandro Lupori int
33368dd7182SLeandro Lupori pmc_power8_initialize(struct pmc_mdep *pmc_mdep)
33468dd7182SLeandro Lupori {
33568dd7182SLeandro Lupori 	struct pmc_classdep *pcd;
33668dd7182SLeandro Lupori 
33768dd7182SLeandro Lupori 	pmc_mdep->pmd_cputype = PMC_CPU_PPC_POWER8;
33868dd7182SLeandro Lupori 
33968dd7182SLeandro Lupori 	pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_POWERPC];
34068dd7182SLeandro Lupori 	pcd->pcd_caps  = POWERPC_PMC_CAPS;
34168dd7182SLeandro Lupori 	pcd->pcd_class = PMC_CLASS_POWER8;
34268dd7182SLeandro Lupori 	pcd->pcd_num   = POWER8_MAX_PMCS;
34368dd7182SLeandro Lupori 	pcd->pcd_ri    = pmc_mdep->pmd_npmc;
34468dd7182SLeandro Lupori 	pcd->pcd_width = 32;
34568dd7182SLeandro Lupori 
34668dd7182SLeandro Lupori 	pcd->pcd_pcpu_init      = power8_pcpu_init;
34768dd7182SLeandro Lupori 	pcd->pcd_pcpu_fini      = power8_pcpu_fini;
348*b48a2770SLeandro Lupori 	pcd->pcd_allocate_pmc   = power8_allocate_pmc;
34968dd7182SLeandro Lupori 	pcd->pcd_release_pmc    = powerpc_release_pmc;
35068dd7182SLeandro Lupori 	pcd->pcd_start_pmc      = powerpc_start_pmc;
35168dd7182SLeandro Lupori 	pcd->pcd_stop_pmc       = powerpc_stop_pmc;
35268dd7182SLeandro Lupori 	pcd->pcd_get_config     = powerpc_get_config;
35368dd7182SLeandro Lupori 	pcd->pcd_config_pmc     = powerpc_config_pmc;
35468dd7182SLeandro Lupori 	pcd->pcd_describe       = powerpc_describe;
35568dd7182SLeandro Lupori 	pcd->pcd_read_pmc       = powerpc_read_pmc;
35668dd7182SLeandro Lupori 	pcd->pcd_write_pmc      = powerpc_write_pmc;
35768dd7182SLeandro Lupori 
35868dd7182SLeandro Lupori 	pmc_mdep->pmd_npmc     += POWER8_MAX_PMCS;
35968dd7182SLeandro Lupori 	pmc_mdep->pmd_intr      = powerpc_pmc_intr;
36068dd7182SLeandro Lupori 
36168dd7182SLeandro Lupori 	ppc_event_codes_size = power8_event_codes_size;
36268dd7182SLeandro Lupori 	ppc_max_pmcs = POWER8_MAX_PMCS;
36368dd7182SLeandro Lupori 
36468dd7182SLeandro Lupori 	powerpc_set_pmc = power8_set_pmc;
36568dd7182SLeandro Lupori 	powerpc_pmcn_read = powerpc_pmcn_read_default;
36668dd7182SLeandro Lupori 	powerpc_pmcn_write = powerpc_pmcn_write_default;
36768dd7182SLeandro Lupori 	powerpc_resume_pmc = power8_resume_pmc;
36868dd7182SLeandro Lupori 
36968dd7182SLeandro Lupori 	return (0);
37068dd7182SLeandro Lupori }
371