fix(realm): fix realm PMU tests

- FEATURE_PMU_NUM_CTRS field in feature_flag was used
to pass number of PMU event counters in realm creation.
The width of this field was set to 4, which was not
enough to pass numbers > 15 and was causing PMU tests
failures in FVP configuration with more than 15 event
counters implemented.
- This patch removes all FEATURE_XXX macros for setting
feature_flag and replaces them with the corresponding
RMI_FEATURE_REGISTER_0_XXX to match feature register 0.
- In host_set_pmu_state() function was setting PMSELR_EL0
to incorrect value 0 instead of 31 to select PMU cycle
counter for configurations with no event counters implemented.
- Test host_realm_pmuv3_mul_rec() was running incorrectly
with number of event counters set to 0 or 31.
- Reads and writes of PMXEVCNTR_EL0 and PMXEVTYPER_EL0
can be constrained unpredictable depending on the
value of PMSELR_EL0.SEL and number of accessible event
counters. See corresponding TF-RMM patch
https://review.trustedfirmware.org/c/TF-RMM/tf-rmm/+/34573
This patch fixes host_set_pmu_state() and
host_check_pmu_state() functions to avoid unpredictable access
to these registers.
This patch makes Realm PMU tests pass for all possible FVP
configurations clusterN.pmu-num_counters=[0...31].

Change-Id: I07cc0c14d5705338cb946ddbeddf4c2bad93abe8
Signed-off-by: AlexeiFedorov <Alexei.Fedorov@arm.com>
diff --git a/realm/include/realm_tests.h b/realm/include/realm_tests.h
index 2c1d3a1..9abbb4a 100644
--- a/realm/include/realm_tests.h
+++ b/realm/include/realm_tests.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2023-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -12,7 +12,7 @@
 bool test_pmuv3_counter(void);
 bool test_pmuv3_event_works_realm(void);
 bool test_pmuv3_rmm_preserves(void);
-bool test_pmuv3_overflow_interrupt(void);
+bool test_pmuv3_overflow_interrupt(bool cycle_cnt);
 bool test_realm_pauth_set_cmd(void);
 bool test_realm_pauth_check_cmd(void);
 bool test_realm_pauth_fault(void);
diff --git a/realm/realm_payload_main.c b/realm/realm_payload_main.c
index aeadb9e..5bc1ef4 100644
--- a/realm/realm_payload_main.c
+++ b/realm/realm_payload_main.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -433,8 +433,11 @@
 		case REALM_PMU_PRESERVE:
 			test_succeed = test_pmuv3_rmm_preserves();
 			break;
-		case REALM_PMU_INTERRUPT:
-			test_succeed = test_pmuv3_overflow_interrupt();
+		case REALM_PMU_CYCLE_INTERRUPT:
+			test_succeed = test_pmuv3_overflow_interrupt(true);
+			break;
+		case REALM_PMU_EVENT_INTERRUPT:
+			test_succeed = test_pmuv3_overflow_interrupt(false);
 			break;
 		case REALM_REQ_FPU_FILL_CMD:
 			fpu_state_write_rand(&rl_fpu_state_write);
diff --git a/realm/realm_pmuv3.c b/realm/realm_pmuv3.c
index 214f6df..620daf3 100644
--- a/realm/realm_pmuv3.c
+++ b/realm/realm_pmuv3.c
@@ -1,9 +1,11 @@
 /*
- * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <stdlib.h>
+
 #include <arch_helpers.h>
 #include <arm_arch_svc.h>
 #include <debug.h>
@@ -22,20 +24,20 @@
 
 #define PRE_OVERFLOW		~(0xF)
 
-#define	DELAY_MS		3000ULL
+#define	DELAY_MS		3000UL
 
-static inline void read_all_counters(u_register_t *array, int impl_ev_ctrs)
+static inline void read_all_counters(u_register_t *array, unsigned int num_cnts)
 {
 	array[0] = read_pmccntr_el0();
-	for (unsigned int i = 0U; i < impl_ev_ctrs; i++) {
+	for (unsigned int i = 0U; i < num_cnts; i++) {
 		array[i + 1] = read_pmevcntrn_el0(i);
 	}
 }
 
-static inline void read_all_counter_configs(u_register_t *array, int impl_ev_ctrs)
+static inline void read_all_counter_configs(u_register_t *array, unsigned int num_cnts)
 {
 	array[0] = read_pmccfiltr_el0();
-	for (unsigned int i = 0U; i < impl_ev_ctrs; i++) {
+	for (unsigned int i = 0U; i < num_cnts; i++) {
 		array[i + 1] = read_pmevtypern_el0(i);
 	}
 }
@@ -106,7 +108,7 @@
 	isb();
 }
 
-static inline void enable_event_counter(int ctr_num)
+static inline void enable_event_counter(unsigned int ctr_num)
 {
 	/*
 	 * Set PMEVTYPER_EL0.U != PMEVTYPER_EL0.RLU
@@ -153,27 +155,21 @@
 	disable_counting();
 	clear_counters();
 
-	realm_printf("counted from %lu to %lu\n",
-		ccounter_start, ccounter_end);
-	if (ccounter_start != ccounter_end) {
-		return true;
-	}
-	return false;
+	realm_printf("cycle counter counted from %lu to %lu\n",
+			ccounter_start, ccounter_end);
+	return (ccounter_start != ccounter_end);
 }
 
 /* Test if max counter available is same as that programmed by host */
 bool test_pmuv3_counter(void)
 {
-	uint64_t num_cnts, num_cnts_host;
+	unsigned int num_cnts, num_cnts_host;
 
 	num_cnts_host = realm_shared_data_get_my_host_val(HOST_ARG1_INDEX);
 	num_cnts = GET_PMU_CNT;
-	realm_printf("CPU=%u num_cnts=%lu num_cnts_host=%lu\n", read_mpidr_el1() & MPID_MASK,
+	realm_printf("CPU=%u num_cnts=%u num_cnts_host=%u\n", read_mpidr_el1() & MPID_MASK,
 			num_cnts, num_cnts_host);
-	if (num_cnts == num_cnts_host) {
-		return true;
-	}
-	return false;
+	return (num_cnts == num_cnts_host);
 }
 
 /*
@@ -183,28 +179,31 @@
 {
 	u_register_t evcounter_start;
 	u_register_t evcounter_end;
+	unsigned int num_cnts = GET_PMU_CNT;
+	unsigned int ctr_num;
 
-	if (GET_PMU_CNT == 0) {
-		realm_printf("no event counters implemented\n");
-		return false;
-	}
+	/* Seed the random number generator */
+	srand((unsigned int)read_cntpct_el0());
+
+	/* Select a random number of event counter */
+	ctr_num = (unsigned int)rand() % num_cnts;
 
 	pmu_reset();
 
-	enable_event_counter(0);
+	enable_event_counter(ctr_num);
 	enable_counting();
 
 	/*
 	 * If any is enabled it will be in the first range.
 	 */
-	evcounter_start = read_pmevcntrn_el0(0);
+	evcounter_start = read_pmevcntrn_el0(ctr_num);
 	execute_nops();
 	disable_counting();
-	evcounter_end = read_pmevcntrn_el0(0);
+	evcounter_end = read_pmevcntrn_el0(ctr_num);
 	clear_counters();
 
-	realm_printf("counted from %lu to %lu\n",
-		evcounter_start, evcounter_end);
+	realm_printf("event counter #%u counted from %lu to %lu\n",
+			ctr_num, evcounter_start, evcounter_end);
 	if (evcounter_start != evcounter_end) {
 		return true;
 	}
@@ -222,30 +221,38 @@
 	u_register_t ctr_end[MAX_COUNTERS] = {0};
 	u_register_t ctr_cfg_end[MAX_COUNTERS] = {0};
 	u_register_t pmu_cfg_end[3];
-	unsigned int impl_ev_ctrs = GET_PMU_CNT;
+	unsigned int num_cnts = GET_PMU_CNT;
 
-	realm_printf("testing %u event counters\n", impl_ev_ctrs);
+	if (num_cnts  == 0U) {
+		realm_printf("testing cycle counter\n");
+	} else {
+		realm_printf("testing %u event counters\n", num_cnts);
+	}
 
 	pmu_reset();
 
-	/* Pretend counters have just been used */
+	/* Pretend all counters have just been used */
 	enable_cycle_counter();
-	enable_event_counter(0);
+
+	for (unsigned int i = 0U; i < num_cnts; i++) {
+		enable_event_counter(i);
+	}
+
 	enable_counting();
 	execute_nops();
 	disable_counting();
 
 	/* Get before reading */
-	read_all_counters(ctr_start, impl_ev_ctrs);
-	read_all_counter_configs(ctr_cfg_start, impl_ev_ctrs);
+	read_all_counters(ctr_start, num_cnts);
+	read_all_counter_configs(ctr_cfg_start, num_cnts);
 	read_all_pmu_configs(pmu_cfg_start);
 
 	/* Give RMM a chance to scramble everything */
 	(void)rsi_get_version(RSI_ABI_VERSION_VAL);
 
 	/* Get after reading */
-	read_all_counters(ctr_end, impl_ev_ctrs);
-	read_all_counter_configs(ctr_cfg_end, impl_ev_ctrs);
+	read_all_counters(ctr_end, num_cnts);
+	read_all_counter_configs(ctr_cfg_end, num_cnts);
 	read_all_pmu_configs(pmu_cfg_end);
 
 	if (memcmp(ctr_start, ctr_end, sizeof(ctr_start)) != 0) {
@@ -269,10 +276,11 @@
 	return true;
 }
 
-bool test_pmuv3_overflow_interrupt(void)
+bool test_pmuv3_overflow_interrupt(bool cycle_cnt)
 {
 	unsigned long priority_bits, priority;
-	uint64_t delay_time = DELAY_MS;
+	unsigned long delay_time = DELAY_MS;
+	unsigned int num_cnts, ctr_num;
 
 	pmu_reset();
 
@@ -292,13 +300,30 @@
 	/* Enable IRQ */
 	enable_irq();
 
-	write_pmevcntrn_el0(0, PRE_OVERFLOW);
-	enable_event_counter(0);
+	if (cycle_cnt) {
+		write_pmccntr_el0(PRE_OVERFLOW);
+		enable_cycle_counter();
 
-	/* Enable interrupt on event counter #0 */
-	write_pmintenset_el1((1UL << 0));
+		/* Enable interrupt on cycle counter */
+		write_pmintenset_el1(PMINTENSET_EL1_C_BIT);
+		realm_printf("waiting for PMU cycle counter vIRQ...\n");
+	} else {
+		num_cnts = GET_PMU_CNT;
 
-	realm_printf("waiting for PMU vIRQ...\n");
+		/* Seed the random number generator */
+		srand((unsigned int)read_cntpct_el0());
+
+		/* Select a random number of event counter */
+		ctr_num = (unsigned int)rand() % num_cnts;
+
+		write_pmevcntrn_el0(ctr_num, PRE_OVERFLOW);
+		enable_event_counter(ctr_num);
+
+		/* Enable interrupt on event counter */
+		write_pmintenset_el1(PMINTENSET_EL1_P_BIT(ctr_num));
+		realm_printf("waiting for PMU event counter #%u vIRQ...\n",
+				ctr_num);
+	}
 
 	enable_counting();
 	execute_nops();
@@ -308,7 +333,7 @@
 	 * Performance Monitors Interrupt Enable Set register
 	 * as part of handling the overflow interrupt.
 	 */
-	while ((read_pmintenset_el1() != 0UL) && (delay_time != 0ULL)) {
+	while ((read_pmintenset_el1() != 0UL) && (delay_time != 0UL)) {
 		--delay_time;
 	}
 
@@ -317,14 +342,13 @@
 
 	pmu_reset();
 
-	if (delay_time == 0ULL) {
-		realm_printf("PMU vIRQ %sreceived in %llums\n",	"not ",
+	if (delay_time == 0UL) {
+		realm_printf("PMU vIRQ %sreceived in %lums\n",	"not ",
 				DELAY_MS);
 		return false;
 	}
 
-	realm_printf("PMU vIRQ %sreceived in %llums\n", "",
+	realm_printf("PMU vIRQ %sreceived in %lums\n", "",
 			DELAY_MS - delay_time);
-
 	return true;
 }