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
46static 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};
173static size_t power8_event_codes_size = nitems(power8_event_codes);
174
175static void
176power8_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
209static int
210power8_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
251static int
252power8_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
265static void
266power8_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
278int
279pmc_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