xref: /freebsd/sys/dev/hwpmc/hwpmc_power8.c (revision c66ec88fed842fbaad62c30d510644ceb7bd2d71)
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
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
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
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
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
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