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


Reply via email to