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;