2 * PMU emulation helpers for TCG IBM POWER chips
4 * Copyright IBM Corp. 2021
7 * Daniel Henrique Barboza <danielhb413@gmail.com>
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.
13 #include "qemu/osdep.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"
23 #if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
25 #define PMC_COUNTER_NEGATIVE_VAL 0x80000000UL
27 static bool pmc_has_overflow_enabled(CPUPPCState
*env
, int sprn
)
29 if (sprn
== SPR_POWER_PMC1
) {
30 return env
->spr
[SPR_POWER_MMCR0
] & MMCR0_PMC1CE
;
33 return env
->spr
[SPR_POWER_MMCR0
] & MMCR0_PMCjCE
;
36 void pmu_update_summaries(CPUPPCState
*env
)
38 target_ulong mmcr0
= env
->spr
[SPR_POWER_MMCR0
];
39 target_ulong mmcr1
= env
->spr
[SPR_POWER_MMCR1
];
43 if (mmcr0
& MMCR0_FC
) {
47 if (!(mmcr0
& MMCR0_FC14
) && mmcr1
!= 0) {
50 sel
= extract64(mmcr1
, MMCR1_PMC1EVT_EXTR
, MMCR1_EVT_SIZE
);
62 sel
= extract64(mmcr1
, MMCR1_PMC2EVT_EXTR
, MMCR1_EVT_SIZE
);
63 ins_cnt
|= (sel
== 0x02) << 2;
64 cyc_cnt
|= (sel
== 0x1e) << 2;
66 sel
= extract64(mmcr1
, MMCR1_PMC3EVT_EXTR
, MMCR1_EVT_SIZE
);
67 ins_cnt
|= (sel
== 0x02) << 3;
68 cyc_cnt
|= (sel
== 0x1e) << 3;
70 sel
= extract64(mmcr1
, MMCR1_PMC4EVT_EXTR
, MMCR1_EVT_SIZE
);
71 ins_cnt
|= ((sel
== 0xfa) || (sel
== 0x2)) << 4;
72 cyc_cnt
|= (sel
== 0x1e) << 4;
75 ins_cnt
|= !(mmcr0
& MMCR0_FC56
) << 5;
76 cyc_cnt
|= !(mmcr0
& MMCR0_FC56
) << 6;
79 env
->pmc_ins_cnt
= ins_cnt
;
80 env
->pmc_cyc_cnt
= cyc_cnt
;
81 env
->hflags
= deposit32(env
->hflags
, HFLAGS_INSN_CNT
, 1, ins_cnt
!= 0);
84 static bool pmu_increment_insns(CPUPPCState
*env
, uint32_t num_insns
)
86 target_ulong mmcr0
= env
->spr
[SPR_POWER_MMCR0
];
87 unsigned ins_cnt
= env
->pmc_ins_cnt
;
88 bool overflow_triggered
= false;
91 if (unlikely(ins_cnt
& 0x1e)) {
92 if (ins_cnt
& (1 << 1)) {
93 tmp
= env
->spr
[SPR_POWER_PMC1
];
95 if (tmp
>= PMC_COUNTER_NEGATIVE_VAL
&& (mmcr0
& MMCR0_PMC1CE
)) {
96 tmp
= PMC_COUNTER_NEGATIVE_VAL
;
97 overflow_triggered
= true;
99 env
->spr
[SPR_POWER_PMC1
] = tmp
;
102 if (ins_cnt
& (1 << 2)) {
103 tmp
= env
->spr
[SPR_POWER_PMC2
];
105 if (tmp
>= PMC_COUNTER_NEGATIVE_VAL
&& (mmcr0
& MMCR0_PMCjCE
)) {
106 tmp
= PMC_COUNTER_NEGATIVE_VAL
;
107 overflow_triggered
= true;
109 env
->spr
[SPR_POWER_PMC2
] = tmp
;
112 if (ins_cnt
& (1 << 3)) {
113 tmp
= env
->spr
[SPR_POWER_PMC3
];
115 if (tmp
>= PMC_COUNTER_NEGATIVE_VAL
&& (mmcr0
& MMCR0_PMCjCE
)) {
116 tmp
= PMC_COUNTER_NEGATIVE_VAL
;
117 overflow_triggered
= true;
119 env
->spr
[SPR_POWER_PMC3
] = tmp
;
122 if (ins_cnt
& (1 << 4)) {
123 target_ulong mmcr1
= env
->spr
[SPR_POWER_MMCR1
];
124 int sel
= extract64(mmcr1
, MMCR1_PMC4EVT_EXTR
, MMCR1_EVT_SIZE
);
125 if (sel
== 0x02 || (env
->spr
[SPR_CTRL
] & CTRL_RUN
)) {
126 tmp
= env
->spr
[SPR_POWER_PMC4
];
128 if (tmp
>= PMC_COUNTER_NEGATIVE_VAL
&& (mmcr0
& MMCR0_PMCjCE
)) {
129 tmp
= PMC_COUNTER_NEGATIVE_VAL
;
130 overflow_triggered
= true;
132 env
->spr
[SPR_POWER_PMC4
] = tmp
;
137 if (ins_cnt
& (1 << 5)) {
138 tmp
= env
->spr
[SPR_POWER_PMC5
];
140 if (tmp
>= PMC_COUNTER_NEGATIVE_VAL
&& (mmcr0
& MMCR0_PMCjCE
)) {
141 tmp
= PMC_COUNTER_NEGATIVE_VAL
;
142 overflow_triggered
= true;
144 env
->spr
[SPR_POWER_PMC5
] = tmp
;
147 return overflow_triggered
;
150 static void pmu_update_cycles(CPUPPCState
*env
)
152 uint64_t now
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
153 uint64_t time_delta
= now
- env
->pmu_base_time
;
154 int sprn
, cyc_cnt
= env
->pmc_cyc_cnt
;
156 for (sprn
= SPR_POWER_PMC1
; sprn
<= SPR_POWER_PMC6
; sprn
++) {
157 if (cyc_cnt
& (1 << (sprn
- SPR_POWER_PMC1
+ 1))) {
159 * The pseries and powernv clock runs at 1Ghz, meaning
160 * that 1 nanosec equals 1 cycle.
162 env
->spr
[sprn
] += time_delta
;
166 /* Update base_time for future calculations */
167 env
->pmu_base_time
= now
;
171 * Helper function to retrieve the cycle overflow timer of the
174 static QEMUTimer
*get_cyc_overflow_timer(CPUPPCState
*env
, int sprn
)
176 return env
->pmu_cyc_overflow_timers
[sprn
- SPR_POWER_PMC1
];
179 static void pmc_update_overflow_timer(CPUPPCState
*env
, int sprn
)
181 QEMUTimer
*pmc_overflow_timer
= get_cyc_overflow_timer(env
, sprn
);
185 * PMC5 does not have an overflow timer and this pointer
188 if (!pmc_overflow_timer
) {
192 if (!(env
->pmc_cyc_cnt
& (1 << (sprn
- SPR_POWER_PMC1
+ 1))) ||
193 !pmc_has_overflow_enabled(env
, sprn
)) {
194 /* Overflow timer is not needed for this counter */
195 timer_del(pmc_overflow_timer
);
199 if (env
->spr
[sprn
] >= PMC_COUNTER_NEGATIVE_VAL
) {
202 timeout
= PMC_COUNTER_NEGATIVE_VAL
- env
->spr
[sprn
];
206 * Use timer_mod_anticipate() because an overflow timer might
207 * be already running for this PMC.
209 timer_mod_anticipate(pmc_overflow_timer
, env
->pmu_base_time
+ timeout
);
212 static void pmu_update_overflow_timers(CPUPPCState
*env
)
217 * Scroll through all PMCs and start counter overflow timers for
218 * PM_CYC events, if needed.
220 for (sprn
= SPR_POWER_PMC1
; sprn
<= SPR_POWER_PMC6
; sprn
++) {
221 pmc_update_overflow_timer(env
, sprn
);
225 void helper_store_mmcr0(CPUPPCState
*env
, target_ulong value
)
227 bool hflags_pmcc0
= (value
& MMCR0_PMCC0
) != 0;
228 bool hflags_pmcc1
= (value
& MMCR0_PMCC1
) != 0;
230 pmu_update_cycles(env
);
232 env
->spr
[SPR_POWER_MMCR0
] = value
;
234 /* MMCR0 writes can change HFLAGS_PMCC[01] and HFLAGS_INSN_CNT */
235 env
->hflags
= deposit32(env
->hflags
, HFLAGS_PMCC0
, 1, hflags_pmcc0
);
236 env
->hflags
= deposit32(env
->hflags
, HFLAGS_PMCC1
, 1, hflags_pmcc1
);
238 pmu_update_summaries(env
);
240 /* Update cycle overflow timers with the current MMCR0 state */
241 pmu_update_overflow_timers(env
);
244 void helper_store_mmcr1(CPUPPCState
*env
, uint64_t value
)
246 pmu_update_cycles(env
);
248 env
->spr
[SPR_POWER_MMCR1
] = value
;
250 /* MMCR1 writes can change HFLAGS_INSN_CNT */
251 pmu_update_summaries(env
);
254 target_ulong
helper_read_pmc(CPUPPCState
*env
, uint32_t sprn
)
256 pmu_update_cycles(env
);
258 return env
->spr
[sprn
];
261 void helper_store_pmc(CPUPPCState
*env
, uint32_t sprn
, uint64_t value
)
263 pmu_update_cycles(env
);
265 env
->spr
[sprn
] = value
;
267 pmc_update_overflow_timer(env
, sprn
);
270 static void fire_PMC_interrupt(PowerPCCPU
*cpu
)
272 CPUPPCState
*env
= &cpu
->env
;
274 if (!(env
->spr
[SPR_POWER_MMCR0
] & MMCR0_EBE
)) {
278 /* PMC interrupt not implemented yet */
282 /* This helper assumes that the PMC is running. */
283 void helper_insns_inc(CPUPPCState
*env
, uint32_t num_insns
)
285 bool overflow_triggered
;
288 overflow_triggered
= pmu_increment_insns(env
, num_insns
);
290 if (overflow_triggered
) {
291 cpu
= env_archcpu(env
);
292 fire_PMC_interrupt(cpu
);
296 static void cpu_ppc_pmu_timer_cb(void *opaque
)
298 PowerPCCPU
*cpu
= opaque
;
300 fire_PMC_interrupt(cpu
);
303 void cpu_ppc_pmu_init(CPUPPCState
*env
)
305 PowerPCCPU
*cpu
= env_archcpu(env
);
308 for (sprn
= SPR_POWER_PMC1
; sprn
<= SPR_POWER_PMC6
; sprn
++) {
309 if (sprn
== SPR_POWER_PMC5
) {
313 i
= sprn
- SPR_POWER_PMC1
;
315 env
->pmu_cyc_overflow_timers
[i
] = timer_new_ns(QEMU_CLOCK_VIRTUAL
,
316 &cpu_ppc_pmu_timer_cb
,
320 #endif /* defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) */