riscv_pmu_incr_ctr() sets OF and LCOFIP on wrap even when Sscofpmf is
disabled. Use the shared overflow helper to require Sscofpmf and suppress
notifications while OF is set without stopping the counter.
Test DTLB overflow with Sscofpmf enabled and disabled, including
notification suppression and continued counting.
Fixes: 14664483457b ("target/riscv: Add sscofpmf extension support")
Signed-off-by: TANG Tiancheng <[email protected]>
---
target/riscv/tcg/pmu.c | 6 +-
tests/tcg/riscv64/sscofpmf-event-overflow.S | 103 ++++++++++++++++++++++++++++
tests/tcg/riscv64/system/meson.build | 15 ++++
3 files changed, 119 insertions(+), 5 deletions(-)
diff --git a/target/riscv/tcg/pmu.c b/target/riscv/tcg/pmu.c
index
16942e53489cd5a2d2dd055fdffef07d04d59465..2f600c5a0fc2d7ba380ef34f89af6366e3e27884
100644
--- a/target/riscv/tcg/pmu.c
+++ b/target/riscv/tcg/pmu.c
@@ -448,11 +448,7 @@ int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum
riscv_pmu_event_idx event_idx)
counter = &env->pmu_ctrs[ctr_idx];
if (counter->mhpmcounter_val == max_val) {
counter->mhpmcounter_val = 0;
- /* Generate interrupt only if OF bit is clear */
- if (!(env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_OF)) {
- env->mhpmevent_val[ctr_idx] |= MHPMEVENT_BIT_OF;
- riscv_cpu_update_mip(env, MIP_LCOFIP, BOOL_TO_MASK(1));
- }
+ riscv_pmu_set_overflow(env, ctr_idx);
} else {
counter->mhpmcounter_val++;
}
diff --git a/tests/tcg/riscv64/sscofpmf-event-overflow.S
b/tests/tcg/riscv64/sscofpmf-event-overflow.S
new file mode 100644
index
0000000000000000000000000000000000000000..cce06da10f9c7c20c18c7863b58b6dd724c45182
--- /dev/null
+++ b/tests/tcg/riscv64/sscofpmf-event-overflow.S
@@ -0,0 +1,103 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/* Non-fixed event overflow with and without Sscofpmf. */
+
+#ifndef EXPECT_SSCOFPMF
+#define EXPECT_SSCOFPMF 1
+#endif
+
+ .option norvc
+ .option norelax
+
+ .text
+ .global _start
+_start:
+ /* Unexpected exceptions report the current check number. */
+ li t4, 1
+ lla t0, exit
+ csrw mtvec, t0
+ csrw mie, zero
+ csrw mip, zero
+ csrw mcountinhibit, zero
+ csrw mhpmevent3, zero
+ li t0, -1
+ csrw mhpmcounter3, t0
+ li t0, 0x10019 /* DTLB read miss */
+ csrw mhpmevent3, t0
+
+ /* One load after flushing the TLB must wrap the counter to zero. */
+ sfence.vma
+ lla t0, first_page
+ lw t1, 0(t0)
+ csrr t0, mhpmcounter3
+ bnez t0, exit
+
+ /* Only Sscofpmf turns that wrap into OF and LCOFIP. */
+ li t4, 2
+ csrr t0, mhpmevent3
+ srli t0, t0, 63
+ li t1, EXPECT_SSCOFPMF
+ bne t0, t1, exit
+ li t4, 3
+ csrr t0, mip
+ srli t0, t0, 13
+ andi t0, t0, 1
+ bne t0, t1, exit
+
+ /* Clearing LCOFIP alone must not re-enable overflow notification. */
+ li t0, 1 << 13
+ csrc mip, t0
+ li t0, -1
+ csrw mhpmcounter3, t0
+ sfence.vma
+ lla t0, second_page
+ lw t1, 0(t0)
+ li t4, 4
+ csrr t0, mhpmcounter3
+ bnez t0, exit
+ li t4, 5
+ csrr t0, mhpmevent3
+ srli t0, t0, 63
+ li t1, EXPECT_SSCOFPMF
+ bne t0, t1, exit
+ li t4, 6
+ csrr t0, mip
+ li t1, 1 << 13
+ and t0, t0, t1
+ bnez t0, exit
+
+ /* Overflow notification must not stop event counting. */
+ sfence.vma
+ lla t0, third_page
+ lw t1, 0(t0)
+ li t4, 7
+ csrr t0, mhpmcounter3
+ li t1, 1
+ bne t0, t1, exit
+ li t4, 0
+
+exit:
+ lla a1, semiargs
+ li t0, 0x20026 /* ADP_Stopped_ApplicationExit */
+ sd t0, 0(a1)
+ sd t4, 8(a1)
+ li a0, 0x20 /* TARGET_SYS_EXIT_EXTENDED */
+ .balign 16
+ slli zero, zero, 0x1f
+ ebreak
+ srai zero, zero, 0x7
+ j .
+
+ .data
+ .balign 4096
+first_page:
+ .word 0
+ .balign 4096
+second_page:
+ .word 0
+ .balign 4096
+third_page:
+ .word 0
+ .balign 16
+semiargs:
+ .space 16
diff --git a/tests/tcg/riscv64/system/meson.build
b/tests/tcg/riscv64/system/meson.build
index
1dd0402631036d0d377bb90d7cb1da2bae34ead4..13ee7954ef4f09559a02a3730fb017ccf2cfd882
100644
--- a/tests/tcg/riscv64/system/meson.build
+++ b/tests/tcg/riscv64/system/meson.build
@@ -99,6 +99,21 @@ tests += {
},
}
+tests += {
+ 'sscofpmf-event-overflow.S': {
+ 'cflags': cflags,
+ 'qemu_args': ['-cpu', 'max', qemu_args],
+ },
+}
+
+tests += {
+ 'sscofpmf-event-overflow.S': {
+ 'exe_name': 'sscofpmf-event-overflow-off',
+ 'cflags': cflags + ['-DEXPECT_SSCOFPMF=0'],
+ 'qemu_args': ['-cpu', 'max,sscofpmf=false', qemu_args],
+ },
+}
+
tests += {
'sscofpmf-cycle-overflow.S': {
'cflags': cflags,
--
2.43.0