1
2
3
4
5
6
7
8
9
10
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/main-loop.h"
20#include "hw/ppc/ppc.h"
21#include "power8-pmu.h"
22
23#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
24
25static 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
34void pmu_update_summaries(CPUPPCState *env)
35{
36 target_ulong mmcr0 = env->spr[SPR_POWER_MMCR0];
37 target_ulong mmcr1 = env->spr[SPR_POWER_MMCR1];
38 int ins_cnt = 0;
39 int cyc_cnt = 0;
40
41 if (mmcr0 & MMCR0_FC) {
42 goto hflags_calc;
43 }
44
45 if (!(mmcr0 & MMCR0_FC14) && mmcr1 != 0) {
46 target_ulong sel;
47
48 sel = extract64(mmcr1, MMCR1_PMC1EVT_EXTR, MMCR1_EVT_SIZE);
49 switch (sel) {
50 case 0x02:
51 case 0xfe:
52 ins_cnt |= 1 << 1;
53 break;
54 case 0x1e:
55 case 0xf0:
56 cyc_cnt |= 1 << 1;
57 break;
58 }
59
60 sel = extract64(mmcr1, MMCR1_PMC2EVT_EXTR, MMCR1_EVT_SIZE);
61 ins_cnt |= (sel == 0x02) << 2;
62 cyc_cnt |= (sel == 0x1e) << 2;
63
64 sel = extract64(mmcr1, MMCR1_PMC3EVT_EXTR, MMCR1_EVT_SIZE);
65 ins_cnt |= (sel == 0x02) << 3;
66 cyc_cnt |= (sel == 0x1e) << 3;
67
68 sel = extract64(mmcr1, MMCR1_PMC4EVT_EXTR, MMCR1_EVT_SIZE);
69 ins_cnt |= ((sel == 0xfa) || (sel == 0x2)) << 4;
70 cyc_cnt |= (sel == 0x1e) << 4;
71 }
72
73 ins_cnt |= !(mmcr0 & MMCR0_FC56) << 5;
74 cyc_cnt |= !(mmcr0 & MMCR0_FC56) << 6;
75
76 hflags_calc:
77 env->pmc_ins_cnt = ins_cnt;
78 env->pmc_cyc_cnt = cyc_cnt;
79 env->hflags = deposit32(env->hflags, HFLAGS_INSN_CNT, 1, ins_cnt != 0);
80}
81
82static bool pmu_increment_insns(CPUPPCState *env, uint32_t num_insns)
83{
84 target_ulong mmcr0 = env->spr[SPR_POWER_MMCR0];
85 unsigned ins_cnt = env->pmc_ins_cnt;
86 bool overflow_triggered = false;
87 target_ulong tmp;
88
89 if (ins_cnt & (1 << 1)) {
90 tmp = env->spr[SPR_POWER_PMC1];
91 tmp += num_insns;
92 if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMC1CE)) {
93 tmp = PMC_COUNTER_NEGATIVE_VAL;
94 overflow_triggered = true;
95 }
96 env->spr[SPR_POWER_PMC1] = tmp;
97 }
98
99 if (ins_cnt & (1 << 2)) {
100 tmp = env->spr[SPR_POWER_PMC2];
101 tmp += num_insns;
102 if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMCjCE)) {
103 tmp = PMC_COUNTER_NEGATIVE_VAL;
104 overflow_triggered = true;
105 }
106 env->spr[SPR_POWER_PMC2] = tmp;
107 }
108
109 if (ins_cnt & (1 << 3)) {
110 tmp = env->spr[SPR_POWER_PMC3];
111 tmp += num_insns;
112 if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMCjCE)) {
113 tmp = PMC_COUNTER_NEGATIVE_VAL;
114 overflow_triggered = true;
115 }
116 env->spr[SPR_POWER_PMC3] = tmp;
117 }
118
119 if (ins_cnt & (1 << 4)) {
120 target_ulong mmcr1 = env->spr[SPR_POWER_MMCR1];
121 int sel = extract64(mmcr1, MMCR1_PMC4EVT_EXTR, MMCR1_EVT_SIZE);
122 if (sel == 0x02 || (env->spr[SPR_CTRL] & CTRL_RUN)) {
123 tmp = env->spr[SPR_POWER_PMC4];
124 tmp += num_insns;
125 if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMCjCE)) {
126 tmp = PMC_COUNTER_NEGATIVE_VAL;
127 overflow_triggered = true;
128 }
129 env->spr[SPR_POWER_PMC4] = tmp;
130 }
131 }
132
133 if (ins_cnt & (1 << 5)) {
134 tmp = env->spr[SPR_POWER_PMC5];
135 tmp += num_insns;
136 if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMCjCE)) {
137 tmp = PMC_COUNTER_NEGATIVE_VAL;
138 overflow_triggered = true;
139 }
140 env->spr[SPR_POWER_PMC5] = tmp;
141 }
142
143 return overflow_triggered;
144}
145
146static void pmu_update_cycles(CPUPPCState *env)
147{
148 uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
149 uint64_t time_delta = now - env->pmu_base_time;
150 int sprn, cyc_cnt = env->pmc_cyc_cnt;
151
152 for (sprn = SPR_POWER_PMC1; sprn <= SPR_POWER_PMC6; sprn++) {
153 if (cyc_cnt & (1 << (sprn - SPR_POWER_PMC1 + 1))) {
154
155
156
157
158 env->spr[sprn] += time_delta;
159 }
160 }
161
162
163 env->pmu_base_time = now;
164}
165
166
167
168
169
170static QEMUTimer *get_cyc_overflow_timer(CPUPPCState *env, int sprn)
171{
172 return env->pmu_cyc_overflow_timers[sprn - SPR_POWER_PMC1];
173}
174
175static void pmc_update_overflow_timer(CPUPPCState *env, int sprn)
176{
177 QEMUTimer *pmc_overflow_timer = get_cyc_overflow_timer(env, sprn);
178 int64_t timeout;
179
180
181
182
183
184 if (!pmc_overflow_timer) {
185 return;
186 }
187
188 if (!(env->pmc_cyc_cnt & (1 << (sprn - SPR_POWER_PMC1 + 1))) ||
189 !pmc_has_overflow_enabled(env, sprn)) {
190
191 timer_del(pmc_overflow_timer);
192 return;
193 }
194
195 if (env->spr[sprn] >= PMC_COUNTER_NEGATIVE_VAL) {
196 timeout = 0;
197 } else {
198 timeout = PMC_COUNTER_NEGATIVE_VAL - env->spr[sprn];
199 }
200
201
202
203
204
205 timer_mod_anticipate(pmc_overflow_timer, env->pmu_base_time + timeout);
206}
207
208static void pmu_update_overflow_timers(CPUPPCState *env)
209{
210 int sprn;
211
212
213
214
215
216 for (sprn = SPR_POWER_PMC1; sprn <= SPR_POWER_PMC6; sprn++) {
217 pmc_update_overflow_timer(env, sprn);
218 }
219}
220
221static void pmu_delete_timers(CPUPPCState *env)
222{
223 QEMUTimer *pmc_overflow_timer;
224 int sprn;
225
226 for (sprn = SPR_POWER_PMC1; sprn <= SPR_POWER_PMC6; sprn++) {
227 pmc_overflow_timer = get_cyc_overflow_timer(env, sprn);
228
229 if (pmc_overflow_timer) {
230 timer_del(pmc_overflow_timer);
231 }
232 }
233}
234
235void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
236{
237 bool hflags_pmcc0 = (value & MMCR0_PMCC0) != 0;
238 bool hflags_pmcc1 = (value & MMCR0_PMCC1) != 0;
239
240 pmu_update_cycles(env);
241
242 env->spr[SPR_POWER_MMCR0] = value;
243
244
245 env->hflags = deposit32(env->hflags, HFLAGS_PMCC0, 1, hflags_pmcc0);
246 env->hflags = deposit32(env->hflags, HFLAGS_PMCC1, 1, hflags_pmcc1);
247
248 pmu_update_summaries(env);
249
250
251 pmu_update_overflow_timers(env);
252}
253
254void helper_store_mmcr1(CPUPPCState *env, uint64_t value)
255{
256 pmu_update_cycles(env);
257
258 env->spr[SPR_POWER_MMCR1] = value;
259
260
261 pmu_update_summaries(env);
262}
263
264target_ulong helper_read_pmc(CPUPPCState *env, uint32_t sprn)
265{
266 pmu_update_cycles(env);
267
268 return env->spr[sprn];
269}
270
271void helper_store_pmc(CPUPPCState *env, uint32_t sprn, uint64_t value)
272{
273 pmu_update_cycles(env);
274
275 env->spr[sprn] = value;
276
277 pmc_update_overflow_timer(env, sprn);
278}
279
280static void fire_PMC_interrupt(PowerPCCPU *cpu)
281{
282 CPUPPCState *env = &cpu->env;
283
284 pmu_update_cycles(env);
285
286 if (env->spr[SPR_POWER_MMCR0] & MMCR0_FCECE) {
287 env->spr[SPR_POWER_MMCR0] &= ~MMCR0_FCECE;
288 env->spr[SPR_POWER_MMCR0] |= MMCR0_FC;
289
290
291 pmu_update_summaries(env);
292
293
294
295
296
297
298 pmu_delete_timers(env);
299 }
300
301 if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMAE) {
302 env->spr[SPR_POWER_MMCR0] &= ~MMCR0_PMAE;
303 env->spr[SPR_POWER_MMCR0] |= MMCR0_PMAO;
304 }
305
306 raise_ebb_perfm_exception(env);
307}
308
309void helper_handle_pmc5_overflow(CPUPPCState *env)
310{
311 env->spr[SPR_POWER_PMC5] = PMC_COUNTER_NEGATIVE_VAL;
312 fire_PMC_interrupt(env_archcpu(env));
313}
314
315
316void helper_insns_inc(CPUPPCState *env, uint32_t num_insns)
317{
318 bool overflow_triggered;
319 PowerPCCPU *cpu;
320
321 overflow_triggered = pmu_increment_insns(env, num_insns);
322
323 if (overflow_triggered) {
324 cpu = env_archcpu(env);
325 fire_PMC_interrupt(cpu);
326 }
327}
328
329static void cpu_ppc_pmu_timer_cb(void *opaque)
330{
331 PowerPCCPU *cpu = opaque;
332
333 fire_PMC_interrupt(cpu);
334}
335
336void cpu_ppc_pmu_init(CPUPPCState *env)
337{
338 PowerPCCPU *cpu = env_archcpu(env);
339 int i, sprn;
340
341 for (sprn = SPR_POWER_PMC1; sprn <= SPR_POWER_PMC6; sprn++) {
342 if (sprn == SPR_POWER_PMC5) {
343 continue;
344 }
345
346 i = sprn - SPR_POWER_PMC1;
347
348 env->pmu_cyc_overflow_timers[i] = timer_new_ns(QEMU_CLOCK_VIRTUAL,
349 &cpu_ppc_pmu_timer_cb,
350 cpu);
351 }
352}
353#endif
354