1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2013 Justin Hibbits
5 * Copyright (c) 2020 Leandro Lupori
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
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.
16 *
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
27 * SUCH DAMAGE.
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 POWER8_MAX_PMCS 6
45
46 static struct pmc_ppc_event power8_event_codes[] = {
47 {PMC_EV_POWER8_INSTR_COMPLETED,
48 .pe_flags = PMC_FLAG_PMC5,
49 .pe_code = 0x00
50 },
51 /*
52 * PMC1 can also count cycles, but as PMC6 can only count cycles
53 * it's better to always use it and leave PMC1 free to count
54 * other events.
55 */
56 {PMC_EV_POWER8_CYCLES,
57 .pe_flags = PMC_FLAG_PMC6,
58 .pe_code = 0xf0
59 },
60 {PMC_EV_POWER8_CYCLES_WITH_INSTRS_COMPLETED,
61 .pe_flags = PMC_FLAG_PMC1,
62 .pe_code = 0xf2
63 },
64 {PMC_EV_POWER8_FPU_INSTR_COMPLETED,
65 .pe_flags = PMC_FLAG_PMC1,
66 .pe_code = 0xf4
67 },
68 {PMC_EV_POWER8_ERAT_INSTR_MISS,
69 .pe_flags = PMC_FLAG_PMC1,
70 .pe_code = 0xf6
71 },
72 {PMC_EV_POWER8_CYCLES_IDLE,
73 .pe_flags = PMC_FLAG_PMC1,
74 .pe_code = 0xf8
75 },
76 {PMC_EV_POWER8_CYCLES_WITH_ANY_THREAD_RUNNING,
77 .pe_flags = PMC_FLAG_PMC1,
78 .pe_code = 0xfa
79 },
80 {PMC_EV_POWER8_STORE_COMPLETED,
81 .pe_flags = PMC_FLAG_PMC2,
82 .pe_code = 0xf0
83 },
84 {PMC_EV_POWER8_INSTR_DISPATCHED,
85 .pe_flags = PMC_FLAG_PMC2 | PMC_FLAG_PMC3,
86 .pe_code = 0xf2
87 },
88 {PMC_EV_POWER8_CYCLES_RUNNING,
89 .pe_flags = PMC_FLAG_PMC2,
90 .pe_code = 0xf4
91 },
92 {PMC_EV_POWER8_ERAT_DATA_MISS,
93 .pe_flags = PMC_FLAG_PMC2,
94 .pe_code = 0xf6
95 },
96 {PMC_EV_POWER8_EXTERNAL_INTERRUPT,
97 .pe_flags = PMC_FLAG_PMC2,
98 .pe_code = 0xf8
99 },
100 {PMC_EV_POWER8_BRANCH_TAKEN,
101 .pe_flags = PMC_FLAG_PMC2,
102 .pe_code = 0xfa
103 },
104 {PMC_EV_POWER8_L1_INSTR_MISS,
105 .pe_flags = PMC_FLAG_PMC2,
106 .pe_code = 0xfc
107 },
108 {PMC_EV_POWER8_L2_LOAD_MISS,
109 .pe_flags = PMC_FLAG_PMC2,
110 .pe_code = 0xfe
111 },
112 {PMC_EV_POWER8_STORE_NO_REAL_ADDR,
113 .pe_flags = PMC_FLAG_PMC3,
114 .pe_code = 0xf0
115 },
116 {PMC_EV_POWER8_INSTR_COMPLETED_WITH_ALL_THREADS_RUNNING,
117 .pe_flags = PMC_FLAG_PMC3,
118 .pe_code = 0xf4
119 },
120 {PMC_EV_POWER8_L1_LOAD_MISS,
121 .pe_flags = PMC_FLAG_PMC3,
122 .pe_code = 0xf6
123 },
124 {PMC_EV_POWER8_TIMEBASE_EVENT,
125 .pe_flags = PMC_FLAG_PMC3,
126 .pe_code = 0xf8
127 },
128 {PMC_EV_POWER8_L3_INSTR_MISS,
129 .pe_flags = PMC_FLAG_PMC3,
130 .pe_code = 0xfa
131 },
132 {PMC_EV_POWER8_TLB_DATA_MISS,
133 .pe_flags = PMC_FLAG_PMC3,
134 .pe_code = 0xfc
135 },
136 {PMC_EV_POWER8_L3_LOAD_MISS,
137 .pe_flags = PMC_FLAG_PMC3,
138 .pe_code = 0xfe
139 },
140 {PMC_EV_POWER8_LOAD_NO_REAL_ADDR,
141 .pe_flags = PMC_FLAG_PMC4,
142 .pe_code = 0xf0
143 },
144 {PMC_EV_POWER8_CYCLES_WITH_INSTRS_DISPATCHED,
145 .pe_flags = PMC_FLAG_PMC4,
146 .pe_code = 0xf2
147 },
148 {PMC_EV_POWER8_CYCLES_RUNNING_PURR_INC,
149 .pe_flags = PMC_FLAG_PMC4,
150 .pe_code = 0xf4
151 },
152 {PMC_EV_POWER8_BRANCH_MISPREDICTED,
153 .pe_flags = PMC_FLAG_PMC4,
154 .pe_code = 0xf6
155 },
156 {PMC_EV_POWER8_PREFETCHED_INSTRS_DISCARDED,
157 .pe_flags = PMC_FLAG_PMC4,
158 .pe_code = 0xf8
159 },
160 {PMC_EV_POWER8_INSTR_COMPLETED_RUNNING,
161 .pe_flags = PMC_FLAG_PMC4,
162 .pe_code = 0xfa
163 },
164 {PMC_EV_POWER8_TLB_INSTR_MISS,
165 .pe_flags = PMC_FLAG_PMC4,
166 .pe_code = 0xfc
167 },
168 {PMC_EV_POWER8_CACHE_LOAD_MISS,
169 .pe_flags = PMC_FLAG_PMC4,
170 .pe_code = 0xfe
171 }
172 };
173 static size_t power8_event_codes_size = nitems(power8_event_codes);
174
175 static void
power8_set_pmc(int cpu,int ri,int config)176 power8_set_pmc(int cpu, int ri, int config)
177 {
178 register_t mmcr;
179
180 /* Select event */
181 switch (ri) {
182 case 0:
183 case 1:
184 case 2:
185 case 3:
186 mmcr = mfspr(SPR_MMCR1);
187 mmcr &= ~SPR_MMCR1_P8_PMCNSEL_MASK(ri);
188 mmcr |= SPR_MMCR1_P8_PMCNSEL(ri, config & ~POWERPC_PMC_ENABLE);
189 mtspr(SPR_MMCR1, mmcr);
190 break;
191 }
192
193 /*
194 * By default, freeze counter in all states.
195 * If counter is being started, unfreeze it in selected states.
196 */
197 mmcr = mfspr(SPR_MMCR2) | SPR_MMCR2_FCNHSP(ri);
198 if (config != PMCN_NONE) {
199 if (config & POWERPC_PMC_USER_ENABLE)
200 mmcr &= ~(SPR_MMCR2_FCNP0(ri) |
201 SPR_MMCR2_FCNP1(ri));
202 if (config & POWERPC_PMC_KERNEL_ENABLE)
203 mmcr &= ~(SPR_MMCR2_FCNH(ri) |
204 SPR_MMCR2_FCNS(ri));
205 }
206 mtspr(SPR_MMCR2, mmcr);
207 }
208
209 static int
power8_pcpu_init(struct pmc_mdep * md,int cpu)210 power8_pcpu_init(struct pmc_mdep *md, int cpu)
211 {
212 register_t mmcr0;
213 int i;
214
215 powerpc_pcpu_init(md, cpu);
216
217 /* Freeze all counters before modifying PMC registers */
218 mmcr0 = mfspr(SPR_MMCR0) | SPR_MMCR0_FC;
219 mtspr(SPR_MMCR0, mmcr0);
220
221 /*
222 * Now setup MMCR0:
223 * - PMAO=0: clear alerts
224 * - FCPC=0, FCP=0: don't freeze counters in problem state
225 * - FCECE: Freeze Counters on Enabled Condition or Event
226 * - PMC1CE/PMCNCE: PMC1/N Condition Enable
227 */
228 mmcr0 &= ~(SPR_MMCR0_PMAO | SPR_MMCR0_FCPC | SPR_MMCR0_FCP);
229 mmcr0 |= SPR_MMCR0_FCECE | SPR_MMCR0_PMC1CE | SPR_MMCR0_PMCNCE;
230 mtspr(SPR_MMCR0, mmcr0);
231
232 /* Clear all PMCs to prevent enabled condition interrupts */
233 for (i = 0; i < POWER8_MAX_PMCS; i++)
234 powerpc_pmcn_write(i, 0);
235
236 /* Disable events in PMCs 1-4 */
237 mtspr(SPR_MMCR1, mfspr(SPR_MMCR1) & ~SPR_MMCR1_P8_PMCSEL_ALL);
238
239 /* Freeze each counter, in all states */
240 mtspr(SPR_MMCR2, mfspr(SPR_MMCR2) |
241 SPR_MMCR2_FCNHSP(0) | SPR_MMCR2_FCNHSP(1) | SPR_MMCR2_FCNHSP(2) |
242 SPR_MMCR2_FCNHSP(3) | SPR_MMCR2_FCNHSP(4) | SPR_MMCR2_FCNHSP(5));
243
244 /* Enable interrupts, unset global freeze */
245 mmcr0 &= ~SPR_MMCR0_FC;
246 mmcr0 |= SPR_MMCR0_PMAE;
247 mtspr(SPR_MMCR0, mmcr0);
248 return (0);
249 }
250
251 static int
power8_pcpu_fini(struct pmc_mdep * md,int cpu)252 power8_pcpu_fini(struct pmc_mdep *md, int cpu)
253 {
254 register_t mmcr0;
255
256 /* Freeze counters, disable interrupts */
257 mmcr0 = mfspr(SPR_MMCR0);
258 mmcr0 &= ~SPR_MMCR0_PMAE;
259 mmcr0 |= SPR_MMCR0_FC;
260 mtspr(SPR_MMCR0, mmcr0);
261
262 return (powerpc_pcpu_fini(md, cpu));
263 }
264
265 static void
power8_resume_pmc(bool ie)266 power8_resume_pmc(bool ie)
267 {
268 register_t mmcr0;
269
270 /* Unfreeze counters and re-enable PERF exceptions if requested. */
271 mmcr0 = mfspr(SPR_MMCR0);
272 mmcr0 &= ~(SPR_MMCR0_FC | SPR_MMCR0_PMAO | SPR_MMCR0_PMAE);
273 if (ie)
274 mmcr0 |= SPR_MMCR0_PMAE;
275 mtspr(SPR_MMCR0, mmcr0);
276 }
277
278 int
pmc_power8_initialize(struct pmc_mdep * pmc_mdep)279 pmc_power8_initialize(struct pmc_mdep *pmc_mdep)
280 {
281 struct pmc_classdep *pcd;
282
283 pmc_mdep->pmd_cputype = PMC_CPU_PPC_POWER8;
284
285 pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_POWERPC];
286 pcd->pcd_caps = POWERPC_PMC_CAPS;
287 pcd->pcd_class = PMC_CLASS_POWER8;
288 pcd->pcd_num = POWER8_MAX_PMCS;
289 pcd->pcd_ri = pmc_mdep->pmd_npmc;
290 pcd->pcd_width = 32;
291
292 pcd->pcd_pcpu_init = power8_pcpu_init;
293 pcd->pcd_pcpu_fini = power8_pcpu_fini;
294 pcd->pcd_allocate_pmc = powerpc_allocate_pmc;
295 pcd->pcd_release_pmc = powerpc_release_pmc;
296 pcd->pcd_start_pmc = powerpc_start_pmc;
297 pcd->pcd_stop_pmc = powerpc_stop_pmc;
298 pcd->pcd_get_config = powerpc_get_config;
299 pcd->pcd_config_pmc = powerpc_config_pmc;
300 pcd->pcd_describe = powerpc_describe;
301 pcd->pcd_read_pmc = powerpc_read_pmc;
302 pcd->pcd_write_pmc = powerpc_write_pmc;
303
304 pmc_mdep->pmd_npmc += POWER8_MAX_PMCS;
305 pmc_mdep->pmd_intr = powerpc_pmc_intr;
306
307 ppc_event_codes = power8_event_codes;
308 ppc_event_codes_size = power8_event_codes_size;
309 ppc_event_first = PMC_EV_POWER8_FIRST;
310 ppc_event_last = PMC_EV_POWER8_LAST;
311 ppc_max_pmcs = POWER8_MAX_PMCS;
312
313 powerpc_set_pmc = power8_set_pmc;
314 powerpc_pmcn_read = powerpc_pmcn_read_default;
315 powerpc_pmcn_write = powerpc_pmcn_write_default;
316 powerpc_resume_pmc = power8_resume_pmc;
317
318 return (0);
319 }
320