fix(ff-a): notification pending interrupt
Currently for S-EL1 partitions, the NPI is injected in two different
moments depending on the type of interrupt:
- For per-vCPU notifications NPI injected at the moment notifications
are set.
- For Global notifications NPI injected at context switch from the NWd
to the receiver SP.
This patch ammends what described above. The injection of the NPI now
happens at handling of FFA_RUN and FFA_MSG_SEND_DIRECT_REQ, when the
vCPU is resumed to running state.
Also, the injection of the NPI is done through the same method/function,
regardless of notifications type. This caters for a better
implementation, as it makes it easier to read and debug (if necessary).
For S-EL0 partitions, the NPI is not used. The S-EL0 partition must be
notified it has pending notifications through an IMPDEF direct messaging
request.
Change-Id: Ib1906c8e5de4be63ca7a7a1cafd25a4675b9b940
Signed-off-by: J-Alves <joao.alves@arm.com>
diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c
index e3dcf2b..bf5d530 100644
--- a/src/arch/aarch64/hypervisor/handler.c
+++ b/src/arch/aarch64/hypervisor/handler.c
@@ -736,8 +736,6 @@
plat_ffa_sri_trigger_if_delayed(vcpu->cpu);
}
#endif
- plat_ffa_inject_notification_pending_interrupt_context_switch(
- *next, vcpu);
arch_regs_set_retval(&vcpu->regs, args);
vcpu_update_virtual_interrupts(*next);
return true;
diff --git a/src/arch/aarch64/plat/ffa/absent.c b/src/arch/aarch64/plat/ffa/absent.c
index 35f3e5a..fe053d1 100644
--- a/src/arch/aarch64/plat/ffa/absent.c
+++ b/src/arch/aarch64/plat/ffa/absent.c
@@ -324,11 +324,15 @@
{
}
-void plat_ffa_inject_notification_pending_interrupt_context_switch(
- struct vcpu *next, struct vcpu *current)
+bool plat_ffa_inject_notification_pending_interrupt(
+ struct vcpu_locked target_locked, struct vcpu *current,
+ struct vm_locked receiver_locked)
{
- (void)next;
+ (void)target_locked;
(void)current;
+ (void)receiver_locked;
+
+ return false;
}
bool plat_ffa_partition_info_get_forward(const struct ffa_uuid *uuid,
diff --git a/src/arch/aarch64/plat/ffa/hypervisor.c b/src/arch/aarch64/plat/ffa/hypervisor.c
index dfb2865..6cd28f2 100644
--- a/src/arch/aarch64/plat/ffa/hypervisor.c
+++ b/src/arch/aarch64/plat/ffa/hypervisor.c
@@ -611,11 +611,15 @@
(void)cpu;
}
-void plat_ffa_inject_notification_pending_interrupt_context_switch(
- struct vcpu *next, struct vcpu *current)
+bool plat_ffa_inject_notification_pending_interrupt(
+ struct vcpu_locked target_locked, struct vcpu *current,
+ struct vm_locked receiver_locked)
{
- (void)next;
+ (void)target_locked;
(void)current;
+ (void)receiver_locked;
+
+ return false;
}
/*
diff --git a/src/arch/aarch64/plat/ffa/spmc.c b/src/arch/aarch64/plat/ffa/spmc.c
index c661cd4..2ffaa25 100644
--- a/src/arch/aarch64/plat/ffa/spmc.c
+++ b/src/arch/aarch64/plat/ffa/spmc.c
@@ -1260,39 +1260,33 @@
plat_interrupts_configure_interrupt(sri_desc);
}
-void plat_ffa_inject_notification_pending_interrupt_context_switch(
- struct vcpu *next, struct vcpu *current)
+bool plat_ffa_inject_notification_pending_interrupt(
+ struct vcpu_locked target_locked, struct vcpu *current,
+ struct vm_locked receiver_locked)
{
- CHECK(current != NULL);
+ struct vm *next_vm = target_locked.vcpu->vm;
+ bool ret = false;
+
/*
- * If NWd is giving CPU cycles to SP, check if it is necessary
- * to inject VI Notifications Pending Interrupt.
+ * Inject the NPI if:
+ * - The targeted VM ID is from this world (i.e. if it is an SP).
+ * - The partition has global pending notifications and an NPI hasn't
+ * been injected yet.
+ * - There are pending per-vCPU notifications in the next vCPU.
*/
- if (current->vm->id == HF_OTHER_WORLD_ID && next != NULL &&
- vm_id_is_current_world(next->vm->id)) {
- struct vm_locked target_vm_locked =
- vm_find_locked(next->vm->id);
- /*
- * If per-vCPU notifications are pending, NPI has been
- * injected at FFA_NOTIFICATION_SET handling in the
- * targeted vCPU. If next SP has pending global
- * notifications, only inject if there are no pending
- * per-vCPU notifications, to avoid injecting spurious
- * interrupt.
- */
- if (!vm_are_per_vcpu_notifications_pending(target_vm_locked,
- vcpu_index(next)) &&
- vm_are_global_notifications_pending(target_vm_locked)) {
- struct vcpu_locked next_locked = vcpu_lock(next);
-
- api_interrupt_inject_locked(
- next_locked, HF_NOTIFICATION_PENDING_INTID,
- current, NULL);
-
- vcpu_unlock(&next_locked);
- }
- vm_unlock(&target_vm_locked);
+ if (vm_id_is_current_world(next_vm->id) &&
+ (vm_are_per_vcpu_notifications_pending(
+ receiver_locked, vcpu_index(target_locked.vcpu)) ||
+ (vm_are_global_notifications_pending(receiver_locked) &&
+ !vm_notifications_is_npi_injected(receiver_locked)))) {
+ api_interrupt_inject_locked(target_locked,
+ HF_NOTIFICATION_PENDING_INTID,
+ current, NULL);
+ vm_notifications_set_npi_injected(receiver_locked, true);
+ ret = true;
}
+
+ return ret;
}
/** Forward helper for FFA_PARTITION_INFO_GET. */
diff --git a/src/arch/fake/hypervisor/ffa.c b/src/arch/fake/hypervisor/ffa.c
index 27ed45a..916aea8 100644
--- a/src/arch/fake/hypervisor/ffa.c
+++ b/src/arch/fake/hypervisor/ffa.c
@@ -307,11 +307,15 @@
(void)cpu;
}
-void plat_ffa_inject_notification_pending_interrupt_context_switch(
- struct vcpu *next, struct vcpu *current)
+bool plat_ffa_inject_notification_pending_interrupt(
+ struct vcpu_locked target_locked, struct vcpu *current,
+ struct vm_locked receiver_locked)
{
- (void)next;
+ (void)target_locked;
(void)current;
+ (void)receiver_locked;
+
+ return false;
}
void plat_ffa_partition_info_get_forward( // NOLINTNEXTLINE