2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2013 Justin Hibbits
5 * Copyright (c) 2020 Leandro Lupori
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
31 #include <sys/param.h>
33 #include <sys/pmckern.h>
34 #include <sys/systm.h>
36 #include <machine/pmc_mdep.h>
37 #include <machine/spr.h>
38 #include <machine/cpu.h>
40 #include "hwpmc_powerpc.h"
42 #define POWER8_MAX_PMCS 6
44 #define PM_EVENT_CODE(pe) (pe & 0xffff)
45 #define PM_EVENT_COUNTER(pe) ((pe >> 16) & 0xffff)
48 #define PM_INST_CMPL 0x02
51 power8_set_pmc(int cpu, int ri, int config)
61 mmcr = mfspr(SPR_MMCR1);
62 mmcr &= ~SPR_MMCR1_P8_PMCNSEL_MASK(ri);
63 mmcr |= SPR_MMCR1_P8_PMCNSEL(ri, config & ~POWERPC_PMC_ENABLE);
64 mtspr(SPR_MMCR1, mmcr);
69 * By default, freeze counter in all states.
70 * If counter is being started, unfreeze it in selected states.
72 mmcr = mfspr(SPR_MMCR2) | SPR_MMCR2_FCNHSP(ri);
73 if (config != PMCN_NONE) {
74 if (config & POWERPC_PMC_USER_ENABLE)
75 mmcr &= ~(SPR_MMCR2_FCNP0(ri) |
77 if (config & POWERPC_PMC_KERNEL_ENABLE)
78 mmcr &= ~(SPR_MMCR2_FCNH(ri) |
81 mtspr(SPR_MMCR2, mmcr);
85 power8_pcpu_init(struct pmc_mdep *md, int cpu)
90 powerpc_pcpu_init(md, cpu);
92 /* Freeze all counters before modifying PMC registers */
93 mmcr0 = mfspr(SPR_MMCR0) | SPR_MMCR0_FC;
94 mtspr(SPR_MMCR0, mmcr0);
98 * - PMAO=0: clear alerts
99 * - FCPC=0, FCP=0: don't freeze counters in problem state
100 * - FCECE: Freeze Counters on Enabled Condition or Event
101 * - PMC1CE/PMCNCE: PMC1/N Condition Enable
103 mmcr0 &= ~(SPR_MMCR0_PMAO | SPR_MMCR0_FCPC | SPR_MMCR0_FCP);
104 mmcr0 |= SPR_MMCR0_FCECE | SPR_MMCR0_PMC1CE | SPR_MMCR0_PMCNCE;
105 mtspr(SPR_MMCR0, mmcr0);
107 /* Clear all PMCs to prevent enabled condition interrupts */
108 for (i = 0; i < POWER8_MAX_PMCS; i++)
109 powerpc_pmcn_write(i, 0);
111 /* Disable events in PMCs 1-4 */
112 mtspr(SPR_MMCR1, mfspr(SPR_MMCR1) & ~SPR_MMCR1_P8_PMCSEL_ALL);
114 /* Freeze each counter, in all states */
115 mtspr(SPR_MMCR2, mfspr(SPR_MMCR2) |
116 SPR_MMCR2_FCNHSP(0) | SPR_MMCR2_FCNHSP(1) | SPR_MMCR2_FCNHSP(2) |
117 SPR_MMCR2_FCNHSP(3) | SPR_MMCR2_FCNHSP(4) | SPR_MMCR2_FCNHSP(5));
119 /* Enable interrupts, unset global freeze */
120 mmcr0 &= ~SPR_MMCR0_FC;
121 mmcr0 |= SPR_MMCR0_PMAE;
122 mtspr(SPR_MMCR0, mmcr0);
127 power8_pcpu_fini(struct pmc_mdep *md, int cpu)
131 /* Freeze counters, disable interrupts */
132 mmcr0 = mfspr(SPR_MMCR0);
133 mmcr0 &= ~SPR_MMCR0_PMAE;
134 mmcr0 |= SPR_MMCR0_FC;
135 mtspr(SPR_MMCR0, mmcr0);
137 return (powerpc_pcpu_fini(md, cpu));
141 power8_resume_pmc(bool ie)
145 /* Unfreeze counters and re-enable PERF exceptions if requested. */
146 mmcr0 = mfspr(SPR_MMCR0);
147 mmcr0 &= ~(SPR_MMCR0_FC | SPR_MMCR0_PMAO | SPR_MMCR0_PMAE);
149 mmcr0 |= SPR_MMCR0_PMAE;
150 mtspr(SPR_MMCR0, mmcr0);
154 power8_allocate_pmc(int cpu, int ri, struct pmc *pm,
155 const struct pmc_op_pmcallocate *a)
157 uint32_t caps, config, counter, pe;
159 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
160 ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
161 KASSERT(ri >= 0 && ri < ppc_max_pmcs,
162 ("[powerpc,%d] illegal row index %d", __LINE__, ri));
164 pe = a->pm_md.pm_event;
165 counter = PM_EVENT_COUNTER(pe);
166 config = PM_EVENT_CODE(pe);
168 if (a->pm_class != PMC_CLASS_POWER8)
171 if ((a->pm_flags & PMC_F_EV_PMU) == 0)
175 * PMC5 and PMC6 are not programmable and always count instructions
176 * completed and cycles, respectively.
178 * When counter is 0 any of the 4 programmable PMCs may be used for
179 * the specified event, otherwise it must match ri + 1.
181 if (counter == 0 && config == PM_INST_CMPL)
183 else if (counter == 0 && config == PM_CYC)
185 else if (counter > 4)
188 if (counter != 0 && counter != ri + 1)
193 if (caps & PMC_CAP_SYSTEM)
194 config |= POWERPC_PMC_KERNEL_ENABLE;
195 if (caps & PMC_CAP_USER)
196 config |= POWERPC_PMC_USER_ENABLE;
197 if ((caps & (PMC_CAP_USER | PMC_CAP_SYSTEM)) == 0)
198 config |= POWERPC_PMC_ENABLE;
200 pm->pm_md.pm_powerpc.pm_powerpc_evsel = config;
202 PMCDBG3(MDP,ALL,1,"powerpc-allocate cpu=%d ri=%d -> config=0x%x",
208 pmc_power8_initialize(struct pmc_mdep *pmc_mdep)
210 struct pmc_classdep *pcd;
212 pmc_mdep->pmd_cputype = PMC_CPU_PPC_POWER8;
214 pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_POWERPC];
215 pcd->pcd_caps = POWERPC_PMC_CAPS;
216 pcd->pcd_class = PMC_CLASS_POWER8;
217 pcd->pcd_num = POWER8_MAX_PMCS;
218 pcd->pcd_ri = pmc_mdep->pmd_npmc;
221 pcd->pcd_pcpu_init = power8_pcpu_init;
222 pcd->pcd_pcpu_fini = power8_pcpu_fini;
223 pcd->pcd_allocate_pmc = power8_allocate_pmc;
224 pcd->pcd_release_pmc = powerpc_release_pmc;
225 pcd->pcd_start_pmc = powerpc_start_pmc;
226 pcd->pcd_stop_pmc = powerpc_stop_pmc;
227 pcd->pcd_get_config = powerpc_get_config;
228 pcd->pcd_config_pmc = powerpc_config_pmc;
229 pcd->pcd_describe = powerpc_describe;
230 pcd->pcd_read_pmc = powerpc_read_pmc;
231 pcd->pcd_write_pmc = powerpc_write_pmc;
233 pmc_mdep->pmd_npmc += POWER8_MAX_PMCS;
234 pmc_mdep->pmd_intr = powerpc_pmc_intr;
236 ppc_max_pmcs = POWER8_MAX_PMCS;
238 powerpc_set_pmc = power8_set_pmc;
239 powerpc_pmcn_read = powerpc_pmcn_read_default;
240 powerpc_pmcn_write = powerpc_pmcn_write_default;
241 powerpc_resume_pmc = power8_resume_pmc;