feat(notifications): notifications pending interrupt

This patch injects a notification pending interrupt (NPI) into the
vCPU of a receiver with pending notification:
- If notification is global the NPI is injected at context switch from
NWd to the receiver SP, at the vCPU that the scheduler gave CPU cycles
to the receiver.
- If the notification is per-vCPU the notification is injected at the
handling of FFA_NOTIFICATION_SET, into the core that is specified in
arguments of the call. It should be handled when the SP and the
respective vCPU is next executed by the scheduler.

Change-Id: Ic1232581b3861313e11c488be5091bf803a70f6a
Signed-off-by: J-Alves <joao.alves@arm.com>
diff --git a/src/api.c b/src/api.c
index 330dc72..e353bd9 100644
--- a/src/api.c
+++ b/src/api.c
@@ -2809,7 +2809,7 @@
 		goto out;
 	}
 
-	/* Set notifications pending */
+	/* Set notifications pending. */
 	vm_notifications_set(receiver_locked, plat_ffa_is_vm_id(sender_vm_id),
 			     notifications, vcpu_id, is_per_vcpu);
 	dlog_verbose("Set the notifications: %x.\n", notifications);
@@ -2822,6 +2822,22 @@
 		plat_ffa_sri_state_set(DELAYED);
 	}
 
+	/*
+	 * If notifications set are per-vCPU and the receiver is SP, the
+	 * Notifications Pending Interrupt can be injected now.
+	 * If not, it should be injected when the scheduler gives it CPU cycles
+	 * in a specific vCPU.
+	 */
+	if (is_per_vcpu && vm_id_is_current_world(receiver_vm_id)) {
+		struct vcpu *target_vcpu =
+			vm_get_vcpu(receiver_locked.vm, vcpu_id);
+
+		dlog_verbose("Per-vCPU notification, pending NPI.\n");
+		internal_interrupt_inject(
+			target_vcpu, HF_NOTIFICATION_PENDING_INTERRUPT_INTID,
+			current, NULL);
+	}
+
 	ret = (struct ffa_value){.func = FFA_SUCCESS_32};
 out:
 	vm_unlock(&receiver_locked);