[PATCH RFC 08/10] target/riscv: Update event mapping hashtable for invalid events

Atish Patra posted 10 patches 1 month, 2 weeks ago
[PATCH RFC 08/10] target/riscv: Update event mapping hashtable for invalid events
Posted by Atish Patra 1 month, 2 weeks ago
If the software programs an invalid hpmevent or selects a invalid
counter mapping, the hashtable entry should be updated accordingly.

Otherwise, the user may get stale value from the old mapped counter.

Signed-off-by: Atish Patra <atishp@rivosinc.com>
---
 target/riscv/pmu.c | 39 +++++++++++++++++++++------------------
 1 file changed, 21 insertions(+), 18 deletions(-)

diff --git a/target/riscv/pmu.c b/target/riscv/pmu.c
index 3235388c66e4..24c2fe82c247 100644
--- a/target/riscv/pmu.c
+++ b/target/riscv/pmu.c
@@ -387,39 +387,42 @@ int riscv_pmu_update_event_map(CPURISCVState *env, uint64_t value,
         return -1;
     }
 
-    /*
-     * Expected mhpmevent value is zero for reset case. Remove the current
-     * mapping.
-     */
-    if (!value) {
-        pthread_rwlock_wrlock(&cpu->pmu_map_lock);
-        g_hash_table_foreach_remove(cpu->pmu_event_ctr_map,
-                                    pmu_remove_event_map,
-                                    GUINT_TO_POINTER(ctr_idx));
-        pthread_rwlock_unlock(&cpu->pmu_map_lock);
-        return 0;
-    }
-
     event_idx = value & MHPMEVENT_IDX_MASK;
     if (riscv_pmu_htable_lookup(cpu, event_idx, &mapped_ctr_idx)) {
         return 0;
     }
 
     for (i = 0; i < env->num_pmu_events; i++) {
-        if (event_idx == env->pmu_events[i].event_id) {
+        if ((event_idx == env->pmu_events[i].event_id) &&
+            (BIT(ctr_idx) & env->pmu_events[i].counter_mask)) {
             valid_event = true;
             break;
         }
     }
 
-    if (!valid_event) {
-        return -1;
+    pthread_rwlock_wrlock(&cpu->pmu_map_lock);
+    /*
+     * Remove the current mapping in the following cases:
+     * 1. mhpmevent value is zero which indicates a reset case.
+     * 2. An invalid event is programmed for mapping to a counter.
+     */
+    if (!value || !valid_event) {
+        g_hash_table_foreach_remove(cpu->pmu_event_ctr_map,
+                                    pmu_remove_event_map,
+                                    GUINT_TO_POINTER(ctr_idx));
+        pthread_rwlock_unlock(&cpu->pmu_map_lock);
+        return 0;
     }
+
     eid_ptr = g_new(gint64, 1);
     *eid_ptr = event_idx;
-    pthread_rwlock_wrlock(&cpu->pmu_map_lock);
+    /*
+     * Insert operation will replace the value if the key exists
+     * As per the documentation, it will free the passed key is freed as well.
+     * No special handling is required for replace or key management.
+     */
     g_hash_table_insert(cpu->pmu_event_ctr_map, eid_ptr,
-                        GUINT_TO_POINTER(ctr_idx));
+                GUINT_TO_POINTER(ctr_idx));
     pthread_rwlock_unlock(&cpu->pmu_map_lock);
 
     return 0;

-- 
2.34.1