master
c 491 lines 14.5 KB
Raw
1 /*
2 * RISC-V PMU file.
3 *
4 * Copyright (c) 2021 Western Digital Corporation or its affiliates.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2 or later, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "qemu/osdep.h"
20 #include "qemu/log.h"
21 #include "qemu/error-report.h"
22 #include "qemu/timer.h"
23 #include "cpu.h"
24 #include "pmu.h"
25 #include "exec/icount.h"
26 #include "system/device_tree.h"
27
28 #define RISCV_TIMEBASE_FREQ 1000000000 /* 1Ghz */
29
30 static bool riscv_pmu_counter_valid(RISCVCPU *cpu, uint32_t ctr_idx)
31 {
32 if (ctr_idx < 3 || ctr_idx >= RV_MAX_MHPMCOUNTERS ||
33 !(cpu->pmu_avail_ctrs & BIT(ctr_idx))) {
34 return false;
35 } else {
36 return true;
37 }
38 }
39
40 static bool riscv_pmu_counter_enabled(RISCVCPU *cpu, uint32_t ctr_idx)
41 {
42 CPURISCVState *env = &cpu->env;
43
44 if (riscv_pmu_counter_valid(cpu, ctr_idx) &&
45 !get_field(env->mcountinhibit, BIT(ctr_idx))) {
46 return true;
47 } else {
48 return false;
49 }
50 }
51
52 static bool riscv_pmu_counter_filtered(CPURISCVState *env, uint64_t cfg)
53 {
54 bool virt_on = env->virt_enabled;
55
56 return (env->priv == PRV_M && (cfg & MHPMEVENT_BIT_MINH)) ||
57 (env->priv == PRV_S && virt_on &&
58 (cfg & MHPMEVENT_BIT_VSINH)) ||
59 (env->priv == PRV_U && virt_on &&
60 (cfg & MHPMEVENT_BIT_VUINH)) ||
61 (env->priv == PRV_S && !virt_on &&
62 (cfg & MHPMEVENT_BIT_SINH)) ||
63 (env->priv == PRV_U && !virt_on &&
64 (cfg & MHPMEVENT_BIT_UINH));
65 }
66
67 /*
68 * Information needed to update counters:
69 * new_priv, new_virt: To correctly save starting snapshot for the newly
70 * started mode. Look at array being indexed with newprv.
71 * old_priv, old_virt: To correctly select previous snapshot for old priv
72 * and compute delta. Also to select correct counter
73 * to inc. Look at arrays being indexed with env->priv.
74 *
75 * To avoid the complexity of calling this function, we assume that
76 * env->priv and env->virt_enabled contain old priv and old virt and
77 * new priv and new virt values are passed in as arguments.
78 */
79 static void riscv_pmu_icount_update_priv(CPURISCVState *env,
80 privilege_mode_t newpriv,
81 bool new_virt)
82 {
83 uint64_t *snapshot_prev, *snapshot_new;
84 uint64_t current_icount;
85 uint64_t *counter_arr;
86 uint64_t delta;
87
88 if (icount_enabled()) {
89 current_icount = icount_get_raw();
90 } else {
91 current_icount = cpu_get_host_ticks();
92 }
93
94 if (env->virt_enabled) {
95 g_assert(env->priv <= PRV_S);
96 counter_arr = env->pmu_fixed_ctrs[1].counter_virt;
97 snapshot_prev = env->pmu_fixed_ctrs[1].counter_virt_prev;
98 } else {
99 counter_arr = env->pmu_fixed_ctrs[1].counter;
100 snapshot_prev = env->pmu_fixed_ctrs[1].counter_prev;
101 }
102
103 if (new_virt) {
104 g_assert(newpriv <= PRV_S);
105 snapshot_new = env->pmu_fixed_ctrs[1].counter_virt_prev;
106 } else {
107 snapshot_new = env->pmu_fixed_ctrs[1].counter_prev;
108 }
109
110 /*
111 * new_priv can be same as env->priv. So we need to calculate
112 * delta first before updating snapshot_new[new_priv].
113 */
114 delta = current_icount - snapshot_prev[env->priv];
115 snapshot_new[newpriv] = current_icount;
116
117 counter_arr[env->priv] += delta;
118 }
119
120 static void riscv_pmu_cycle_update_priv(CPURISCVState *env,
121 privilege_mode_t newpriv,
122 bool new_virt)
123 {
124 uint64_t *snapshot_prev, *snapshot_new;
125 uint64_t current_ticks;
126 uint64_t *counter_arr;
127 uint64_t delta;
128
129 if (icount_enabled()) {
130 current_ticks = icount_get();
131 } else {
132 current_ticks = cpu_get_host_ticks();
133 }
134
135 if (env->virt_enabled) {
136 g_assert(env->priv <= PRV_S);
137 counter_arr = env->pmu_fixed_ctrs[0].counter_virt;
138 snapshot_prev = env->pmu_fixed_ctrs[0].counter_virt_prev;
139 } else {
140 counter_arr = env->pmu_fixed_ctrs[0].counter;
141 snapshot_prev = env->pmu_fixed_ctrs[0].counter_prev;
142 }
143
144 if (new_virt) {
145 g_assert(newpriv <= PRV_S);
146 snapshot_new = env->pmu_fixed_ctrs[0].counter_virt_prev;
147 } else {
148 snapshot_new = env->pmu_fixed_ctrs[0].counter_prev;
149 }
150
151 delta = current_ticks - snapshot_prev[env->priv];
152 snapshot_new[newpriv] = current_ticks;
153
154 counter_arr[env->priv] += delta;
155 }
156
157 void riscv_pmu_update_fixed_ctrs(CPURISCVState *env,
158 privilege_mode_t newpriv,
159 bool new_virt)
160 {
161 riscv_pmu_cycle_update_priv(env, newpriv, new_virt);
162 riscv_pmu_icount_update_priv(env, newpriv, new_virt);
163 }
164
165 void riscv_pmu_decr_instret(CPURISCVState *env)
166 {
167 if (!icount_enabled() ||
168 (env->mcountinhibit & COUNTEREN_IR) ||
169 riscv_pmu_counter_filtered(env, env->minstretcfg)) {
170 return;
171 }
172
173 /*
174 * minstret is derived from icount, which includes the current
175 * instruction. Move the baseline forward to exclude an instruction
176 * that raises an exception and therefore does not retire.
177 */
178 env->pmu_ctrs[2].mhpmcounter_prev++;
179 }
180
181 int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx)
182 {
183 uint32_t ctr_idx;
184 CPURISCVState *env = &cpu->env;
185 uint64_t max_val = UINT64_MAX;
186 PMUCTRState *counter;
187 gpointer value;
188
189 if (!cpu->cfg.pmu_mask) {
190 return 0;
191 }
192 value = g_hash_table_lookup(cpu->pmu_event_ctr_map,
193 GUINT_TO_POINTER(event_idx));
194 if (!value) {
195 return -1;
196 }
197
198 ctr_idx = GPOINTER_TO_UINT(value);
199 if (!riscv_pmu_counter_enabled(cpu, ctr_idx)) {
200 return -1;
201 }
202
203 if (riscv_pmu_counter_filtered(env, env->mhpmevent_val[ctr_idx])) {
204 return 0;
205 }
206
207 /* Handle the overflow scenario */
208 counter = &env->pmu_ctrs[ctr_idx];
209 if (counter->mhpmcounter_val == max_val) {
210 counter->mhpmcounter_val = 0;
211 /* Generate interrupt only if OF bit is clear */
212 if (!(env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_OF)) {
213 env->mhpmevent_val[ctr_idx] |= MHPMEVENT_BIT_OF;
214 riscv_cpu_update_mip(env, MIP_LCOFIP, BOOL_TO_MASK(1));
215 }
216 } else {
217 counter->mhpmcounter_val++;
218 }
219
220 return 0;
221 }
222
223 bool riscv_pmu_ctr_monitor_instructions(CPURISCVState *env,
224 uint32_t target_ctr)
225 {
226 RISCVCPU *cpu;
227 uint32_t event_idx;
228 uint32_t ctr_idx;
229
230 /* Fixed instret counter */
231 if (target_ctr == 2) {
232 return true;
233 }
234
235 cpu = env_archcpu(env);
236 if (!cpu->pmu_event_ctr_map) {
237 return false;
238 }
239
240 event_idx = RISCV_PMU_EVENT_HW_INSTRUCTIONS;
241 ctr_idx = GPOINTER_TO_UINT(g_hash_table_lookup(cpu->pmu_event_ctr_map,
242 GUINT_TO_POINTER(event_idx)));
243 if (!ctr_idx) {
244 return false;
245 }
246
247 return target_ctr == ctr_idx ? true : false;
248 }
249
250 bool riscv_pmu_ctr_monitor_cycles(CPURISCVState *env, uint32_t target_ctr)
251 {
252 RISCVCPU *cpu;
253 uint32_t event_idx;
254 uint32_t ctr_idx;
255
256 /* Fixed mcycle counter */
257 if (target_ctr == 0) {
258 return true;
259 }
260
261 cpu = env_archcpu(env);
262 if (!cpu->pmu_event_ctr_map) {
263 return false;
264 }
265
266 event_idx = RISCV_PMU_EVENT_HW_CPU_CYCLES;
267 ctr_idx = GPOINTER_TO_UINT(g_hash_table_lookup(cpu->pmu_event_ctr_map,
268 GUINT_TO_POINTER(event_idx)));
269
270 /* Counter zero is not used for event_ctr_map */
271 if (!ctr_idx) {
272 return false;
273 }
274
275 return (target_ctr == ctr_idx) ? true : false;
276 }
277
278 static gboolean pmu_remove_event_map(gpointer key, gpointer value,
279 gpointer udata)
280 {
281 return (GPOINTER_TO_UINT(value) == GPOINTER_TO_UINT(udata)) ? true : false;
282 }
283
284 static int64_t pmu_icount_ticks_to_ns(int64_t value)
285 {
286 int64_t ret = 0;
287
288 if (icount_enabled()) {
289 ret = icount_to_ns(value);
290 } else {
291 ret = (NANOSECONDS_PER_SECOND / RISCV_TIMEBASE_FREQ) * value;
292 }
293
294 return ret;
295 }
296
297 int riscv_pmu_update_event_map(CPURISCVState *env, uint64_t value,
298 uint32_t ctr_idx)
299 {
300 uint32_t event_idx;
301 RISCVCPU *cpu = env_archcpu(env);
302
303 if (!riscv_pmu_counter_valid(cpu, ctr_idx) || !cpu->pmu_event_ctr_map) {
304 return -1;
305 }
306
307 /*
308 * Expected mhpmevent value is zero for reset case. Remove the current
309 * mapping.
310 */
311 if (!(value & MHPMEVENT_IDX_MASK)) {
312 g_hash_table_foreach_remove(cpu->pmu_event_ctr_map,
313 pmu_remove_event_map,
314 GUINT_TO_POINTER(ctr_idx));
315 return 0;
316 }
317
318 event_idx = value & MHPMEVENT_IDX_MASK;
319 if (g_hash_table_lookup(cpu->pmu_event_ctr_map,
320 GUINT_TO_POINTER(event_idx))) {
321 return 0;
322 }
323
324 switch (event_idx) {
325 case RISCV_PMU_EVENT_HW_CPU_CYCLES:
326 case RISCV_PMU_EVENT_HW_INSTRUCTIONS:
327 case RISCV_PMU_EVENT_CACHE_DTLB_READ_MISS:
328 case RISCV_PMU_EVENT_CACHE_DTLB_WRITE_MISS:
329 case RISCV_PMU_EVENT_CACHE_ITLB_PREFETCH_MISS:
330 break;
331 default:
332 /* We don't support any raw events right now */
333 return -1;
334 }
335 g_hash_table_insert(cpu->pmu_event_ctr_map, GUINT_TO_POINTER(event_idx),
336 GUINT_TO_POINTER(ctr_idx));
337
338 return 0;
339 }
340
341 static bool pmu_hpmevent_set_of_if_clear(CPURISCVState *env, uint32_t ctr_idx)
342 {
343 if (!get_field(env->mhpmevent_val[ctr_idx], MHPMEVENT_BIT_OF)) {
344 env->mhpmevent_val[ctr_idx] |= MHPMEVENT_BIT_OF;
345 return true;
346 } else {
347 return false;
348 }
349 }
350
351 static void pmu_timer_trigger_irq(RISCVCPU *cpu,
352 enum riscv_pmu_event_idx evt_idx)
353 {
354 uint32_t ctr_idx;
355 CPURISCVState *env = &cpu->env;
356 PMUCTRState *counter;
357 int64_t irq_trigger_at;
358 uint64_t curr_ctr_val, curr_ctrh_val;
359 uint64_t ctr_val;
360
361 if (evt_idx != RISCV_PMU_EVENT_HW_CPU_CYCLES &&
362 evt_idx != RISCV_PMU_EVENT_HW_INSTRUCTIONS) {
363 return;
364 }
365
366 ctr_idx = GPOINTER_TO_UINT(g_hash_table_lookup(cpu->pmu_event_ctr_map,
367 GUINT_TO_POINTER(evt_idx)));
368 if (!riscv_pmu_counter_enabled(cpu, ctr_idx)) {
369 return;
370 }
371
372 /* Generate interrupt only if OF bit is clear */
373 if (get_field(env->mhpmevent_val[ctr_idx], MHPMEVENT_BIT_OF)) {
374 return;
375 }
376
377 counter = &env->pmu_ctrs[ctr_idx];
378 if (counter->irq_overflow_left > 0) {
379 irq_trigger_at = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
380 counter->irq_overflow_left;
381 timer_mod_anticipate_ns(cpu->pmu_timer, irq_trigger_at);
382 counter->irq_overflow_left = 0;
383 return;
384 }
385
386 riscv_pmu_read_ctr(env, (target_ulong *)&curr_ctr_val, false, ctr_idx);
387 ctr_val = counter->mhpmcounter_val;
388 if (riscv_cpu_mxl(env) == MXL_RV32) {
389 riscv_pmu_read_ctr(env, (target_ulong *)&curr_ctrh_val, true, ctr_idx);
390 curr_ctr_val = curr_ctr_val | (curr_ctrh_val << 32);
391 }
392
393 /*
394 * We can not accommodate for inhibited modes when setting up timer. Check
395 * if the counter has actually overflowed or not by comparing current
396 * counter value (accommodated for inhibited modes) with software written
397 * counter value.
398 */
399 if (curr_ctr_val >= ctr_val) {
400 riscv_pmu_setup_timer(env, curr_ctr_val, ctr_idx);
401 return;
402 }
403
404 if (cpu->pmu_avail_ctrs & BIT(ctr_idx)) {
405 if (pmu_hpmevent_set_of_if_clear(env, ctr_idx)) {
406 riscv_cpu_update_mip(env, MIP_LCOFIP, BOOL_TO_MASK(1));
407 }
408 }
409 }
410
411 /* Timer callback for instret and cycle counter overflow */
412 void riscv_pmu_timer_cb(void *priv)
413 {
414 RISCVCPU *cpu = priv;
415
416 /* Timer event was triggered only for these events */
417 pmu_timer_trigger_irq(cpu, RISCV_PMU_EVENT_HW_CPU_CYCLES);
418 pmu_timer_trigger_irq(cpu, RISCV_PMU_EVENT_HW_INSTRUCTIONS);
419 }
420
421 int riscv_pmu_setup_timer(CPURISCVState *env, uint64_t value, uint32_t ctr_idx)
422 {
423 uint64_t overflow_delta, overflow_at, curr_ns;
424 int64_t overflow_ns, overflow_left = 0;
425 RISCVCPU *cpu = env_archcpu(env);
426 PMUCTRState *counter = &env->pmu_ctrs[ctr_idx];
427
428 /* No need to setup a timer if LCOFI is disabled when OF is set */
429 if (!riscv_pmu_counter_valid(cpu, ctr_idx) || !cpu->cfg.ext_sscofpmf ||
430 get_field(env->mhpmevent_val[ctr_idx], MHPMEVENT_BIT_OF)) {
431 return -1;
432 }
433
434 if (value) {
435 overflow_delta = UINT64_MAX - value + 1;
436 } else {
437 overflow_delta = UINT64_MAX;
438 }
439
440 /*
441 * QEMU supports only int64_t timers while RISC-V counters are uint64_t.
442 * Compute the leftover and save it so that it can be reprogrammed again
443 * when timer expires.
444 */
445 if (overflow_delta > INT64_MAX) {
446 overflow_left = overflow_delta - INT64_MAX;
447 }
448
449 if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) ||
450 riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) {
451 overflow_ns = pmu_icount_ticks_to_ns((int64_t)overflow_delta);
452 overflow_left = pmu_icount_ticks_to_ns(overflow_left) ;
453 } else {
454 return -1;
455 }
456 curr_ns = (uint64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
457 overflow_at = curr_ns + overflow_ns;
458 if (overflow_at <= curr_ns)
459 overflow_at = UINT64_MAX;
460
461 if (overflow_at > INT64_MAX) {
462 overflow_left += overflow_at - INT64_MAX;
463 counter->irq_overflow_left = overflow_left;
464 overflow_at = INT64_MAX;
465 }
466 timer_mod_anticipate_ns(cpu->pmu_timer, overflow_at);
467
468 return 0;
469 }
470
471
472 void riscv_pmu_init(RISCVCPU *cpu, Error **errp)
473 {
474 if (cpu->cfg.pmu_mask & (COUNTEREN_CY | COUNTEREN_TM | COUNTEREN_IR)) {
475 error_setg(errp, "\"pmu-mask\" contains invalid bits (0-2) set");
476 return;
477 }
478
479 if (ctpop32(cpu->cfg.pmu_mask) > (RV_MAX_MHPMCOUNTERS - 3)) {
480 error_setg(errp, "Number of counters exceeds maximum available");
481 return;
482 }
483
484 cpu->pmu_event_ctr_map = g_hash_table_new(g_direct_hash, g_direct_equal);
485 if (!cpu->pmu_event_ctr_map) {
486 error_setg(errp, "Unable to allocate PMU event hash table");
487 return;
488 }
489
490 cpu->pmu_avail_ctrs = cpu->cfg.pmu_mask;
491 }