]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/hwpmc/hwpmc_power8.c
Ensure that the buffer is in nvme_single_map() mapped to single segment.
[FreeBSD/FreeBSD.git] / sys / dev / hwpmc / hwpmc_power8.c
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 }