xref: /qemu/target/ppc/power8-pmu.c (revision 91e01270)
1 /*
2  * PMU emulation helpers for TCG IBM POWER chips
3  *
4  *  Copyright IBM Corp. 2021
5  *
6  * Authors:
7  *  Daniel Henrique Barboza      <danielhb413@gmail.com>
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10  * See the COPYING file in the top-level directory.
11  */
12 
13 #include "qemu/osdep.h"
14 #include "cpu.h"
15 #include "helper_regs.h"
16 #include "exec/exec-all.h"
17 #include "exec/helper-proto.h"
18 #include "qemu/error-report.h"
19 #include "qemu/timer.h"
20 #include "hw/ppc/ppc.h"
21 #include "power8-pmu.h"
22 
23 #if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
24 
25 static bool pmc_has_overflow_enabled(CPUPPCState *env, int sprn)
26 {
27     if (sprn == SPR_POWER_PMC1) {
28         return env->spr[SPR_POWER_MMCR0] & MMCR0_PMC1CE;
29     }
30 
31     return env->spr[SPR_POWER_MMCR0] & MMCR0_PMCjCE;
32 }
33 
34 /*
35  * Called after MMCR0 or MMCR1 changes to update pmc_ins_cnt and pmc_cyc_cnt.
36  * hflags must subsequently be updated.
37  */
38 static void pmu_update_summaries(CPUPPCState *env)
39 {
40     target_ulong mmcr0 = env->spr[SPR_POWER_MMCR0];
41     target_ulong mmcr1 = env->spr[SPR_POWER_MMCR1];
42     int ins_cnt = 0;
43     int cyc_cnt = 0;
44 
45     if (mmcr0 & MMCR0_FC) {
46         goto out;
47     }
48 
49     if (!(mmcr0 & MMCR0_FC14) && mmcr1 != 0) {
50         target_ulong sel;
51 
52         sel = extract64(mmcr1, MMCR1_PMC1EVT_EXTR, MMCR1_EVT_SIZE);
53         switch (sel) {
54         case 0x02:
55         case 0xfe:
56             ins_cnt |= 1 << 1;
57             break;
58         case 0x1e:
59         case 0xf0:
60             cyc_cnt |= 1 << 1;
61             break;
62         }
63 
64         sel = extract64(mmcr1, MMCR1_PMC2EVT_EXTR, MMCR1_EVT_SIZE);
65         ins_cnt |= (sel == 0x02) << 2;
66         cyc_cnt |= (sel == 0x1e) << 2;
67 
68         sel = extract64(mmcr1, MMCR1_PMC3EVT_EXTR, MMCR1_EVT_SIZE);
69         ins_cnt |= (sel == 0x02) << 3;
70         cyc_cnt |= (sel == 0x1e) << 3;
71 
72         sel = extract64(mmcr1, MMCR1_PMC4EVT_EXTR, MMCR1_EVT_SIZE);
73         ins_cnt |= ((sel == 0xfa) || (sel == 0x2)) << 4;
74         cyc_cnt |= (sel == 0x1e) << 4;
75     }
76 
77     ins_cnt |= !(mmcr0 & MMCR0_FC56) << 5;
78     cyc_cnt |= !(mmcr0 & MMCR0_FC56) << 6;
79 
80  out:
81     env->pmc_ins_cnt = ins_cnt;
82     env->pmc_cyc_cnt = cyc_cnt;
83 }
84 
85 void pmu_mmcr01_updated(CPUPPCState *env)
86 {
87     PowerPCCPU *cpu = env_archcpu(env);
88 
89     pmu_update_summaries(env);
90     hreg_update_pmu_hflags(env);
91 
92     if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMAO) {
93         ppc_set_irq(cpu, PPC_INTERRUPT_PERFM, 1);
94     } else {
95         ppc_set_irq(cpu, PPC_INTERRUPT_PERFM, 0);
96     }
97 
98     /*
99      * Should this update overflow timers (if mmcr0 is updated) so they
100      * get set in cpu_post_load?
101      */
102 }
103 
104 static bool pmu_increment_insns(CPUPPCState *env, uint32_t num_insns)
105 {
106     target_ulong mmcr0 = env->spr[SPR_POWER_MMCR0];
107     unsigned ins_cnt = env->pmc_ins_cnt;
108     bool overflow_triggered = false;
109     target_ulong tmp;
110 
111     if (ins_cnt & (1 << 1)) {
112         tmp = env->spr[SPR_POWER_PMC1];
113         tmp += num_insns;
114         if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMC1CE)) {
115             tmp = PMC_COUNTER_NEGATIVE_VAL;
116             overflow_triggered = true;
117         }
118         env->spr[SPR_POWER_PMC1] = tmp;
119     }
120 
121     if (ins_cnt & (1 << 2)) {
122         tmp = env->spr[SPR_POWER_PMC2];
123         tmp += num_insns;
124         if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMCjCE)) {
125             tmp = PMC_COUNTER_NEGATIVE_VAL;
126             overflow_triggered = true;
127         }
128         env->spr[SPR_POWER_PMC2] = tmp;
129     }
130 
131     if (ins_cnt & (1 << 3)) {
132         tmp = env->spr[SPR_POWER_PMC3];
133         tmp += num_insns;
134         if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMCjCE)) {
135             tmp = PMC_COUNTER_NEGATIVE_VAL;
136             overflow_triggered = true;
137         }
138         env->spr[SPR_POWER_PMC3] = tmp;
139     }
140 
141     if (ins_cnt & (1 << 4)) {
142         target_ulong mmcr1 = env->spr[SPR_POWER_MMCR1];
143         int sel = extract64(mmcr1, MMCR1_PMC4EVT_EXTR, MMCR1_EVT_SIZE);
144         if (sel == 0x02 || (env->spr[SPR_CTRL] & CTRL_RUN)) {
145             tmp = env->spr[SPR_POWER_PMC4];
146             tmp += num_insns;
147             if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMCjCE)) {
148                 tmp = PMC_COUNTER_NEGATIVE_VAL;
149                 overflow_triggered = true;
150             }
151             env->spr[SPR_POWER_PMC4] = tmp;
152         }
153     }
154 
155     if (ins_cnt & (1 << 5)) {
156         tmp = env->spr[SPR_POWER_PMC5];
157         tmp += num_insns;
158         if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMCjCE)) {
159             tmp = PMC_COUNTER_NEGATIVE_VAL;
160             overflow_triggered = true;
161         }
162         env->spr[SPR_POWER_PMC5] = tmp;
163     }
164 
165     return overflow_triggered;
166 }
167 
168 static void pmu_update_cycles(CPUPPCState *env)
169 {
170     uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
171     uint64_t time_delta = now - env->pmu_base_time;
172     int sprn, cyc_cnt = env->pmc_cyc_cnt;
173 
174     for (sprn = SPR_POWER_PMC1; sprn <= SPR_POWER_PMC6; sprn++) {
175         if (cyc_cnt & (1 << (sprn - SPR_POWER_PMC1 + 1))) {
176             /*
177              * The pseries and powernv clock runs at 1Ghz, meaning
178              * that 1 nanosec equals 1 cycle.
179              */
180             env->spr[sprn] += time_delta;
181         }
182     }
183 
184     /* Update base_time for future calculations */
185     env->pmu_base_time = now;
186 }
187 
188 /*
189  * Helper function to retrieve the cycle overflow timer of the
190  * 'sprn' counter.
191  */
192 static QEMUTimer *get_cyc_overflow_timer(CPUPPCState *env, int sprn)
193 {
194     return env->pmu_cyc_overflow_timers[sprn - SPR_POWER_PMC1];
195 }
196 
197 static void pmc_update_overflow_timer(CPUPPCState *env, int sprn)
198 {
199     QEMUTimer *pmc_overflow_timer = get_cyc_overflow_timer(env, sprn);
200     int64_t timeout;
201 
202     /*
203      * PMC5 does not have an overflow timer and this pointer
204      * will be NULL.
205      */
206     if (!pmc_overflow_timer) {
207         return;
208     }
209 
210     if (!(env->pmc_cyc_cnt & (1 << (sprn - SPR_POWER_PMC1 + 1))) ||
211         !pmc_has_overflow_enabled(env, sprn)) {
212         /* Overflow timer is not needed for this counter */
213         timer_del(pmc_overflow_timer);
214         return;
215     }
216 
217     if (env->spr[sprn] >= PMC_COUNTER_NEGATIVE_VAL) {
218         timeout = 0;
219     } else {
220         timeout = PMC_COUNTER_NEGATIVE_VAL - env->spr[sprn];
221     }
222 
223     /*
224      * Use timer_mod_anticipate() because an overflow timer might
225      * be already running for this PMC.
226      */
227     timer_mod_anticipate(pmc_overflow_timer, env->pmu_base_time + timeout);
228 }
229 
230 static void pmu_update_overflow_timers(CPUPPCState *env)
231 {
232     int sprn;
233 
234     /*
235      * Scroll through all PMCs and start counter overflow timers for
236      * PM_CYC events, if needed.
237      */
238     for (sprn = SPR_POWER_PMC1; sprn <= SPR_POWER_PMC6; sprn++) {
239         pmc_update_overflow_timer(env, sprn);
240     }
241 }
242 
243 static void pmu_delete_timers(CPUPPCState *env)
244 {
245     QEMUTimer *pmc_overflow_timer;
246     int sprn;
247 
248     for (sprn = SPR_POWER_PMC1; sprn <= SPR_POWER_PMC6; sprn++) {
249         pmc_overflow_timer = get_cyc_overflow_timer(env, sprn);
250 
251         if (pmc_overflow_timer) {
252             timer_del(pmc_overflow_timer);
253         }
254     }
255 }
256 
257 void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
258 {
259     pmu_update_cycles(env);
260 
261     env->spr[SPR_POWER_MMCR0] = value;
262 
263     pmu_mmcr01_updated(env);
264 
265     /* Update cycle overflow timers with the current MMCR0 state */
266     pmu_update_overflow_timers(env);
267 }
268 
269 void helper_store_mmcr1(CPUPPCState *env, uint64_t value)
270 {
271     pmu_update_cycles(env);
272 
273     env->spr[SPR_POWER_MMCR1] = value;
274 
275     pmu_mmcr01_updated(env);
276 }
277 
278 target_ulong helper_read_pmc(CPUPPCState *env, uint32_t sprn)
279 {
280     pmu_update_cycles(env);
281 
282     return env->spr[sprn];
283 }
284 
285 void helper_store_pmc(CPUPPCState *env, uint32_t sprn, uint64_t value)
286 {
287     pmu_update_cycles(env);
288 
289     env->spr[sprn] = (uint32_t)value;
290 
291     pmc_update_overflow_timer(env, sprn);
292 }
293 
294 static void perfm_alert(PowerPCCPU *cpu)
295 {
296     CPUPPCState *env = &cpu->env;
297 
298     pmu_update_cycles(env);
299 
300     if (env->spr[SPR_POWER_MMCR0] & MMCR0_FCECE) {
301         env->spr[SPR_POWER_MMCR0] |= MMCR0_FC;
302 
303         /* Changing MMCR0_FC requires summaries and hflags update */
304         pmu_mmcr01_updated(env);
305 
306         /*
307          * Delete all pending timers if we need to freeze
308          * the PMC. We'll restart them when the PMC starts
309          * running again.
310          */
311         pmu_delete_timers(env);
312     }
313 
314     if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMAE) {
315         /* These MMCR0 bits do not require summaries or hflags update. */
316         env->spr[SPR_POWER_MMCR0] &= ~MMCR0_PMAE;
317         env->spr[SPR_POWER_MMCR0] |= MMCR0_PMAO;
318         ppc_set_irq(cpu, PPC_INTERRUPT_PERFM, 1);
319     }
320 
321     raise_ebb_perfm_exception(env);
322 }
323 
324 void helper_handle_pmc5_overflow(CPUPPCState *env)
325 {
326     env->spr[SPR_POWER_PMC5] = PMC_COUNTER_NEGATIVE_VAL;
327     perfm_alert(env_archcpu(env));
328 }
329 
330 /* This helper assumes that the PMC is running. */
331 void helper_insns_inc(CPUPPCState *env, uint32_t num_insns)
332 {
333     bool overflow_triggered;
334 
335     overflow_triggered = pmu_increment_insns(env, num_insns);
336     if (overflow_triggered) {
337         perfm_alert(env_archcpu(env));
338     }
339 }
340 
341 static void cpu_ppc_pmu_timer_cb(void *opaque)
342 {
343     PowerPCCPU *cpu = opaque;
344 
345     perfm_alert(cpu);
346 }
347 
348 void cpu_ppc_pmu_init(CPUPPCState *env)
349 {
350     PowerPCCPU *cpu = env_archcpu(env);
351     int i, sprn;
352 
353     for (sprn = SPR_POWER_PMC1; sprn <= SPR_POWER_PMC6; sprn++) {
354         if (sprn == SPR_POWER_PMC5) {
355             continue;
356         }
357 
358         i = sprn - SPR_POWER_PMC1;
359 
360         env->pmu_cyc_overflow_timers[i] = timer_new_ns(QEMU_CLOCK_VIRTUAL,
361                                                        &cpu_ppc_pmu_timer_cb,
362                                                        cpu);
363     }
364 }
365 #endif /* defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) */
366