diff mbox series

[v7,09/11] target/riscv: Start counters from both mhpmcounter and mcountinhibit

Message ID 20240626-smcntrpmf_v7-v7-9-bb0f10af7fa9@rivosinc.com
State New
Headers show
Series Add RISC-V ISA extension smcntrpmf support | expand

Commit Message

Atish Kumar Patra June 26, 2024, 11:57 p.m. UTC
From: Rajnesh Kanwal <rkanwal@rivosinc.com>

Currently we start timer counter from write_mhpmcounter path only
without checking for mcountinhibit bit. This changes adds mcountinhibit
check and also programs the counter from write_mcountinhibit as well.

When a counter is stopped using mcountinhibit we simply update
the value of the counter based on current host ticks and save
it for future reads.

We don't need to disable running timer as pmu_timer_trigger_irq
will discard the interrupt if the counter has been inhibited.

Signed-off-by: Rajnesh Kanwal <rkanwal@rivosinc.com>
---
 target/riscv/csr.c | 75 ++++++++++++++++++++++++++++++++++++++----------------
 target/riscv/pmu.c |  3 +--
 2 files changed, 54 insertions(+), 24 deletions(-)

Comments

Daniel Henrique Barboza July 1, 2024, 7:37 p.m. UTC | #1
On 6/26/24 8:57 PM, Atish Patra wrote:
> From: Rajnesh Kanwal <rkanwal@rivosinc.com>
> 
> Currently we start timer counter from write_mhpmcounter path only
> without checking for mcountinhibit bit. This changes adds mcountinhibit
> check and also programs the counter from write_mcountinhibit as well.
> 
> When a counter is stopped using mcountinhibit we simply update
> the value of the counter based on current host ticks and save
> it for future reads.
> 
> We don't need to disable running timer as pmu_timer_trigger_irq
> will discard the interrupt if the counter has been inhibited.
> 
> Signed-off-by: Rajnesh Kanwal <rkanwal@rivosinc.com>
> ---

Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>

>   target/riscv/csr.c | 75 ++++++++++++++++++++++++++++++++++++++----------------
>   target/riscv/pmu.c |  3 +--
>   2 files changed, 54 insertions(+), 24 deletions(-)
> 
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index 6c1a884eec82..150e02f080ec 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -1008,8 +1008,9 @@ static RISCVException write_mhpmcounter(CPURISCVState *env, int csrno,
>       uint64_t mhpmctr_val = val;
>   
>       counter->mhpmcounter_val = val;
> -    if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) ||
> -        riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) {
> +    if (!get_field(env->mcountinhibit, BIT(ctr_idx)) &&
> +        (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) ||
> +         riscv_pmu_ctr_monitor_instructions(env, ctr_idx))) {
>           counter->mhpmcounter_prev = riscv_pmu_ctr_get_fixed_counters_val(env,
>                                                                   ctr_idx, false);
>           if (ctr_idx > 2) {
> @@ -1037,8 +1038,9 @@ static RISCVException write_mhpmcounterh(CPURISCVState *env, int csrno,
>   
>       counter->mhpmcounterh_val = val;
>       mhpmctr_val = mhpmctr_val | (mhpmctrh_val << 32);
> -    if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) ||
> -        riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) {
> +    if (!get_field(env->mcountinhibit, BIT(ctr_idx)) &&
> +        (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) ||
> +         riscv_pmu_ctr_monitor_instructions(env, ctr_idx))) {
>           counter->mhpmcounterh_prev = riscv_pmu_ctr_get_fixed_counters_val(env,
>                                                                    ctr_idx, true);
>           if (ctr_idx > 2) {
> @@ -2101,31 +2103,60 @@ static RISCVException write_mcountinhibit(CPURISCVState *env, int csrno,
>       int cidx;
>       PMUCTRState *counter;
>       RISCVCPU *cpu = env_archcpu(env);
> +    uint32_t present_ctrs = cpu->pmu_avail_ctrs | COUNTEREN_CY | COUNTEREN_IR;
> +    target_ulong updated_ctrs = (env->mcountinhibit ^ val) & present_ctrs;
> +    uint64_t mhpmctr_val, prev_count, curr_count;
>   
>       /* WARL register - disable unavailable counters; TM bit is always 0 */
> -    env->mcountinhibit =
> -        val & (cpu->pmu_avail_ctrs | COUNTEREN_CY | COUNTEREN_IR);
> +    env->mcountinhibit = val & present_ctrs;
>   
>       /* Check if any other counter is also monitoring cycles/instructions */
>       for (cidx = 0; cidx < RV_MAX_MHPMCOUNTERS; cidx++) {
> -            counter = &env->pmu_ctrs[cidx];
> -        if (get_field(env->mcountinhibit, BIT(cidx)) && (val & BIT(cidx))) {
> -            /*
> -             * Update the counter value for cycle/instret as we can't stop the
> -             * host ticks. But we should show the current value at this moment.
> -             */
> -            if (riscv_pmu_ctr_monitor_cycles(env, cidx) ||
> -                riscv_pmu_ctr_monitor_instructions(env, cidx)) {
> -                counter->mhpmcounter_val =
> -                    riscv_pmu_ctr_get_fixed_counters_val(env, cidx, false) -
> -                                           counter->mhpmcounter_prev +
> -                                           counter->mhpmcounter_val;
> +        if (!(updated_ctrs & BIT(cidx)) ||
> +            (!riscv_pmu_ctr_monitor_cycles(env, cidx) &&
> +            !riscv_pmu_ctr_monitor_instructions(env, cidx))) {
> +            continue;
> +        }
> +
> +        counter = &env->pmu_ctrs[cidx];
> +
> +        if (!get_field(env->mcountinhibit, BIT(cidx))) {
> +            counter->mhpmcounter_prev =
> +                riscv_pmu_ctr_get_fixed_counters_val(env, cidx, false);
> +            if (riscv_cpu_mxl(env) == MXL_RV32) {
> +                counter->mhpmcounterh_prev =
> +                    riscv_pmu_ctr_get_fixed_counters_val(env, cidx, true);
> +            }
> +
> +            if (cidx > 2) {
> +                mhpmctr_val = counter->mhpmcounter_val;
>                   if (riscv_cpu_mxl(env) == MXL_RV32) {
> -                    counter->mhpmcounterh_val =
> -                        riscv_pmu_ctr_get_fixed_counters_val(env, cidx, true) -
> -                                                counter->mhpmcounterh_prev +
> -                                                counter->mhpmcounterh_val;
> +                    mhpmctr_val = mhpmctr_val |
> +                            ((uint64_t)counter->mhpmcounterh_val << 32);
>                   }
> +                riscv_pmu_setup_timer(env, mhpmctr_val, cidx);
> +            }
> +        } else {
> +            curr_count = riscv_pmu_ctr_get_fixed_counters_val(env, cidx, false);
> +
> +            mhpmctr_val = counter->mhpmcounter_val;
> +            prev_count = counter->mhpmcounter_prev;
> +            if (riscv_cpu_mxl(env) == MXL_RV32) {
> +                uint64_t tmp =
> +                    riscv_pmu_ctr_get_fixed_counters_val(env, cidx, true);
> +
> +                curr_count = curr_count | (tmp << 32);
> +                mhpmctr_val = mhpmctr_val |
> +                    ((uint64_t)counter->mhpmcounterh_val << 32);
> +                prev_count = prev_count |
> +                    ((uint64_t)counter->mhpmcounterh_prev << 32);
> +            }
> +
> +            /* Adjust the counter for later reads. */
> +            mhpmctr_val = curr_count - prev_count + mhpmctr_val;
> +            counter->mhpmcounter_val = mhpmctr_val;
> +            if (riscv_cpu_mxl(env) == MXL_RV32) {
> +                counter->mhpmcounterh_val = mhpmctr_val >> 32;
>               }
>           }
>       }
> diff --git a/target/riscv/pmu.c b/target/riscv/pmu.c
> index ac648cff8d7c..63420d9f3679 100644
> --- a/target/riscv/pmu.c
> +++ b/target/riscv/pmu.c
> @@ -285,8 +285,7 @@ int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx)
>       }
>   
>       ctr_idx = GPOINTER_TO_UINT(value);
> -    if (!riscv_pmu_counter_enabled(cpu, ctr_idx) ||
> -        get_field(env->mcountinhibit, BIT(ctr_idx))) {
> +    if (!riscv_pmu_counter_enabled(cpu, ctr_idx)) {
>           return -1;
>       }
>   
>
diff mbox series

Patch

diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 6c1a884eec82..150e02f080ec 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -1008,8 +1008,9 @@  static RISCVException write_mhpmcounter(CPURISCVState *env, int csrno,
     uint64_t mhpmctr_val = val;
 
     counter->mhpmcounter_val = val;
-    if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) ||
-        riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) {
+    if (!get_field(env->mcountinhibit, BIT(ctr_idx)) &&
+        (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) ||
+         riscv_pmu_ctr_monitor_instructions(env, ctr_idx))) {
         counter->mhpmcounter_prev = riscv_pmu_ctr_get_fixed_counters_val(env,
                                                                 ctr_idx, false);
         if (ctr_idx > 2) {
@@ -1037,8 +1038,9 @@  static RISCVException write_mhpmcounterh(CPURISCVState *env, int csrno,
 
     counter->mhpmcounterh_val = val;
     mhpmctr_val = mhpmctr_val | (mhpmctrh_val << 32);
-    if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) ||
-        riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) {
+    if (!get_field(env->mcountinhibit, BIT(ctr_idx)) &&
+        (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) ||
+         riscv_pmu_ctr_monitor_instructions(env, ctr_idx))) {
         counter->mhpmcounterh_prev = riscv_pmu_ctr_get_fixed_counters_val(env,
                                                                  ctr_idx, true);
         if (ctr_idx > 2) {
@@ -2101,31 +2103,60 @@  static RISCVException write_mcountinhibit(CPURISCVState *env, int csrno,
     int cidx;
     PMUCTRState *counter;
     RISCVCPU *cpu = env_archcpu(env);
+    uint32_t present_ctrs = cpu->pmu_avail_ctrs | COUNTEREN_CY | COUNTEREN_IR;
+    target_ulong updated_ctrs = (env->mcountinhibit ^ val) & present_ctrs;
+    uint64_t mhpmctr_val, prev_count, curr_count;
 
     /* WARL register - disable unavailable counters; TM bit is always 0 */
-    env->mcountinhibit =
-        val & (cpu->pmu_avail_ctrs | COUNTEREN_CY | COUNTEREN_IR);
+    env->mcountinhibit = val & present_ctrs;
 
     /* Check if any other counter is also monitoring cycles/instructions */
     for (cidx = 0; cidx < RV_MAX_MHPMCOUNTERS; cidx++) {
-            counter = &env->pmu_ctrs[cidx];
-        if (get_field(env->mcountinhibit, BIT(cidx)) && (val & BIT(cidx))) {
-            /*
-             * Update the counter value for cycle/instret as we can't stop the
-             * host ticks. But we should show the current value at this moment.
-             */
-            if (riscv_pmu_ctr_monitor_cycles(env, cidx) ||
-                riscv_pmu_ctr_monitor_instructions(env, cidx)) {
-                counter->mhpmcounter_val =
-                    riscv_pmu_ctr_get_fixed_counters_val(env, cidx, false) -
-                                           counter->mhpmcounter_prev +
-                                           counter->mhpmcounter_val;
+        if (!(updated_ctrs & BIT(cidx)) ||
+            (!riscv_pmu_ctr_monitor_cycles(env, cidx) &&
+            !riscv_pmu_ctr_monitor_instructions(env, cidx))) {
+            continue;
+        }
+
+        counter = &env->pmu_ctrs[cidx];
+
+        if (!get_field(env->mcountinhibit, BIT(cidx))) {
+            counter->mhpmcounter_prev =
+                riscv_pmu_ctr_get_fixed_counters_val(env, cidx, false);
+            if (riscv_cpu_mxl(env) == MXL_RV32) {
+                counter->mhpmcounterh_prev =
+                    riscv_pmu_ctr_get_fixed_counters_val(env, cidx, true);
+            }
+
+            if (cidx > 2) {
+                mhpmctr_val = counter->mhpmcounter_val;
                 if (riscv_cpu_mxl(env) == MXL_RV32) {
-                    counter->mhpmcounterh_val =
-                        riscv_pmu_ctr_get_fixed_counters_val(env, cidx, true) -
-                                                counter->mhpmcounterh_prev +
-                                                counter->mhpmcounterh_val;
+                    mhpmctr_val = mhpmctr_val |
+                            ((uint64_t)counter->mhpmcounterh_val << 32);
                 }
+                riscv_pmu_setup_timer(env, mhpmctr_val, cidx);
+            }
+        } else {
+            curr_count = riscv_pmu_ctr_get_fixed_counters_val(env, cidx, false);
+
+            mhpmctr_val = counter->mhpmcounter_val;
+            prev_count = counter->mhpmcounter_prev;
+            if (riscv_cpu_mxl(env) == MXL_RV32) {
+                uint64_t tmp =
+                    riscv_pmu_ctr_get_fixed_counters_val(env, cidx, true);
+
+                curr_count = curr_count | (tmp << 32);
+                mhpmctr_val = mhpmctr_val |
+                    ((uint64_t)counter->mhpmcounterh_val << 32);
+                prev_count = prev_count |
+                    ((uint64_t)counter->mhpmcounterh_prev << 32);
+            }
+
+            /* Adjust the counter for later reads. */
+            mhpmctr_val = curr_count - prev_count + mhpmctr_val;
+            counter->mhpmcounter_val = mhpmctr_val;
+            if (riscv_cpu_mxl(env) == MXL_RV32) {
+                counter->mhpmcounterh_val = mhpmctr_val >> 32;
             }
         }
     }
diff --git a/target/riscv/pmu.c b/target/riscv/pmu.c
index ac648cff8d7c..63420d9f3679 100644
--- a/target/riscv/pmu.c
+++ b/target/riscv/pmu.c
@@ -285,8 +285,7 @@  int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx)
     }
 
     ctr_idx = GPOINTER_TO_UINT(value);
-    if (!riscv_pmu_counter_enabled(cpu, ctr_idx) ||
-        get_field(env->mcountinhibit, BIT(ctr_idx))) {
+    if (!riscv_pmu_counter_enabled(cpu, ctr_idx)) {
         return -1;
     }