fix(ipi): FFA_NOTIFICATION_INFO_GET returns waiting vCPUs for IPIs

Only report the pending IPIs of waiting vCPUs for
FFA_NOTIFICATION_INFO_GET as these are the only ones that need explicit
cycles from the Normal World.

Signed-off-by: Daniel Boulby <daniel.boulby@arm.com>
Change-Id: I48a7f2c9f05e0f91a1627c96a2ab0babf4dcf8fd
diff --git a/src/vm.c b/src/vm.c
index 75392d9..8e4930c 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -931,8 +931,12 @@
 		vcpu_is_virt_interrupt_pending(interrupts, HF_IPI_INTID) &&
 		!vcpu_ipi_is_info_get_retrieved(vcpu_locked);
 
-	/* No notifications pending that haven't been retrieved. */
-	if (!pending_not_retrieved) {
+	/*
+	 * No notifications pending that haven't been retrieved or the vCPU is
+	 * not in the waiting state. Only report waiting vCPUs as this is the
+	 * only state that needs explicit cycles donated from the NWd.
+	 */
+	if (!pending_not_retrieved || vcpu->state != VCPU_STATE_WAITING) {
 		ret = false;
 		goto out;
 	}
diff --git a/src/vm_test.cc b/src/vm_test.cc
index 2fec26d..41db62f 100644
--- a/src/vm_test.cc
+++ b/src/vm_test.cc
@@ -121,7 +121,7 @@
 
 	/* Insertion of two in the middle of the boot list */
 	for (uint32_t i = 0; i < 2; i++) {
-		EXPECT_TRUE(vm_init_next(1, &ppool, &vm_cur, false, 0));
+		EXPECT_TRUE(vm_init_next(MAX_CPUS, &ppool, &vm_cur, false, 0));
 		vm_cur->boot_order = 2;
 		vcpu = vm_get_vcpu(vm_cur, 0);
 		vcpu_update_boot(vcpu);
@@ -805,6 +805,8 @@
 
 /**
  * Validates simple getting of notifications info for pending IPI.
+ * Also checks that vCPUs with pending IPIs are only reported if the
+ * vCPU is in the waiting state.
  */
 TEST_F(vm, vm_notifications_info_get_ipi)
 {
@@ -817,7 +819,7 @@
 	uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
 	uint32_t lists_count = 0;
 	enum notifications_info_get_state current_state = INIT;
-	struct_vm *current_vm = vm_find_index(5);
+	struct_vm *current_vm = vm_find_index(4);
 	struct vcpu *target_vcpu = vm_get_vcpu(current_vm, 1);
 	struct interrupts *interrupts = &target_vcpu->interrupts;
 	const bool is_from_vm = false;
@@ -832,6 +834,16 @@
 					  FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
 					  &current_state);
 
+	EXPECT_EQ(ids_count, 0);
+	EXPECT_EQ(lists_count, 0);
+
+	target_vcpu->state = VCPU_STATE_WAITING;
+
+	vm_notifications_info_get_pending(current_vm_locked, is_from_vm, ids,
+					  &ids_count, lists_sizes, &lists_count,
+					  FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
+					  &current_state);
+
 	EXPECT_EQ(ids_count, 2);
 	EXPECT_EQ(lists_count, 1);
 	EXPECT_EQ(lists_sizes[0], 1);
@@ -873,7 +885,7 @@
 	uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
 	uint32_t lists_count = 0;
 	enum notifications_info_get_state current_state = INIT;
-	struct_vm *current_vm = vm_find_index(5);
+	struct_vm *current_vm = vm_find_index(4);
 	struct vcpu *target_vcpu = vm_get_vcpu(current_vm, 1);
 	struct interrupts *interrupts = &target_vcpu->interrupts;
 	const bool is_from_vm = false;
@@ -922,7 +934,7 @@
  */
 TEST_F(vm, vm_notifications_info_get_per_vcpu_all_vcpus_and_ipi)
 {
-	struct_vm *current_vm = vm_find_index(5);
+	struct_vm *current_vm = vm_find_index(4);
 	ffa_vcpu_count_t vcpu_count = current_vm->vcpu_count;
 	CHECK(vcpu_count > 1);
 
@@ -941,6 +953,8 @@
 	struct vcpu *target_vcpu = vm_get_vcpu(current_vm, 0);
 	struct interrupts *interrupts = &target_vcpu->interrupts;
 
+	target_vcpu->state = VCPU_STATE_WAITING;
+
 	vcpu_virt_interrupt_set_pending(interrupts, HF_IPI_INTID);
 
 	for (unsigned int i = 1; i < vcpu_count; i++) {