feat(notifications): schedule receiver interrupt
Configuring Schedule Receiver Interrupt for each CPU, and send
respective SGI to the NWd. If flag FFA_NOTIFICATIONS_FLAG_DELAY_SRI
is set, the SGI will be sent upon context switch from the SWd to the NWd
else it will be sent immediately, the sender SP execution will be
preempted.
A state machine was implemented to coordinate handling and sending of
the SRI.
Change-Id: If05a6535094f5da7189d8dbb55b04e7c1a1f80d7
Signed-off-by: J-Alves <joao.alves@arm.com>
diff --git a/inc/hf/api.h b/inc/hf/api.h
index bfbc646..b31d7b5 100644
--- a/inc/hf/api.h
+++ b/inc/hf/api.h
@@ -37,6 +37,7 @@
int64_t api_interrupt_inject_locked(struct vcpu_locked target_locked,
uint32_t intid, struct vcpu *current,
struct vcpu **next);
+void api_sri_send_if_delayed(struct vcpu *current);
struct ffa_value api_ffa_msg_send(ffa_vm_id_t sender_vm_id,
ffa_vm_id_t receiver_vm_id, uint32_t size,
diff --git a/inc/hf/arch/plat/ffa.h b/inc/hf/arch/plat/ffa.h
index aa7c26e..8ee0602 100644
--- a/inc/hf/arch/plat/ffa.h
+++ b/inc/hf/arch/plat/ffa.h
@@ -12,6 +12,44 @@
#include "hf/vcpu.h"
#include "hf/vm.h"
+/**
+ * The following enum relates to a state machine to guide the handling of the
+ * Scheduler Receiver Interrupt.
+ * The SRI is used to signal the receiver scheduler that there are pending
+ * notifications for the receiver, and it is sent when there is a valid call to
+ * FFA_NOTIFICATION_SET.
+ * The FFA_NOTIFICATION_INFO_GET interface must be called in the SRI handler,
+ * after which the FF-A driver should process the returned list, and request
+ * the receiver scheduler to give the receiver CPU cycles to process the
+ * notification.
+ * The use of the following state machine allows for synchronized sending
+ * and handling of the SRI, as well as avoiding the occurrence of spurious
+ * SRI. A spurious SRI would be one such that upon handling a call to
+ * FFA_NOTIFICATION_INFO_GET would return error FFA_NO_DATA, which is plausible
+ * in an MP system.
+ * The state machine also aims at resolving the delay of the SRI by setting
+ * flag FFA_NOTIFICATIONS_FLAG_DELAY_SRI in the arguments of the set call. By
+ * delaying, the SRI is sent in context switching to the primary endpoint.
+ * The SPMC is implemented under the assumption the receiver scheduler is a
+ * NWd endpoint, hence the SRI is triggered at the world switch.
+ * If concurrently another notification is set that requires immediate action,
+ * the SRI is triggered immediately within that same execution context.
+ *
+ * HANDLED is the initial state, and means a new SRI can be sent. The following
+ * state transitions are possible:
+ * * HANDLED => DELAYED: Setting notification, and requesting SRI delay.
+ * * HANDLED => TRIGGERED: Setting notification, and not requesting SRI delay.
+ * * DELAYED => TRIGGERED: SRI was delayed, and the context switch to the
+ * receiver scheduler is being done.
+ * * DELAYED => HANDLED: the scheduler called FFA_NOTIFICATION_INFO_GET.
+ * * TRIGGERED => HANDLED: the scheduler called FFA_NOTIFICATION_INFO_GET.
+ */
+enum plat_ffa_sri_state {
+ HANDLED = 0,
+ DELAYED,
+ TRIGGERED,
+};
+
/** Returns information on features that are specific to the platform. */
struct ffa_value plat_ffa_features(uint32_t function_id);
/** Returns the SPMC ID. */
@@ -129,6 +167,28 @@
uint32_t *lists_count,
const uint32_t ids_count_max);
+/** Helper to set SRI current state. */
+void plat_ffa_sri_state_set(enum plat_ffa_sri_state state);
+
+/**
+ * Helper to send SRI and safely update `ffa_sri_state`, if there has been
+ * a call to FFA_NOTIFICATION_SET, and the SRI has been delayed.
+ * To be called at a context switch to the NWd.
+ */
+void plat_ffa_sri_trigger_if_delayed(struct cpu *cpu);
+
+/**
+ * Helper to send SRI and safely update `ffa_sri_state`, if it hasn't been
+ * delayed in call to FFA_NOTIFICATION_SET.
+ */
+void plat_ffa_sri_trigger_not_delayed(struct cpu *cpu);
+
+/**
+ * Initialize Schedule Receiver Interrupts needed in the context of
+ * notifications support.
+ */
+void plat_ffa_sri_init(struct cpu *cpu);
+
void plat_ffa_notification_info_get_forward(uint16_t *ids, uint32_t *ids_count,
uint32_t *lists_sizes,
uint32_t *lists_count,
diff --git a/inc/vmapi/hf/ffa.h b/inc/vmapi/hf/ffa.h
index cc87c42..f3d9d15 100644
--- a/inc/vmapi/hf/ffa.h
+++ b/inc/vmapi/hf/ffa.h
@@ -405,6 +405,8 @@
#define MAX_FFA_NOTIFICATIONS 64U
+#define FFA_SCHEDULE_RECEIVER_INTERRUPT_ID 8
+
/**
* Flag for notification bind and set, to specify call is about per-vCPU
* notifications.
@@ -443,6 +445,9 @@
#define FFA_NOTIFICATION_FLAG_BITMAP_SPM UINT32_C(0x1 << 2)
#define FFA_NOTIFICATION_FLAG_BITMAP_HYP UINT32_C(0x1 << 3)
+/** Flag for FFA_NOTIFICATION_SET to delay Schedule Receiver Interrupt */
+#define FFA_NOTIFICATIONS_FLAG_DELAY_SRI UINT32_C(0x1 << 1)
+
static inline ffa_vm_id_t ffa_notifications_get_receiver(struct ffa_value args)
{
return (args.arg1 >> 16) & 0xffffU;