feat: support for cpu cycle allocation modes

This patch adds initial support for modeling call chains in
SPMC and Normal World scheduled modes.

As per FF-A v1.1 EAC0 section 8.2.3, a call chain represents all SPs
in a sequence of invocations of direct message request. When
execution on a PE is in the secure state, only a single call chain
that runs in the Normal World scheduled mode can exist. However, any
number of call chains that run in the SPMC scheduled mode can exist.

Change-Id: Ic409abd90345d7972e33e42679e53ed8dffb14e7
Signed-off-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
diff --git a/inc/hf/vcpu.h b/inc/hf/vcpu.h
index 28938e1..9dec951 100644
--- a/inc/hf/vcpu.h
+++ b/inc/hf/vcpu.h
@@ -53,6 +53,15 @@
 	RTM_SP_INIT,
 };
 
+/** Refer to section 8.2.3 of the FF-A EAC0 spec. */
+enum schedule_mode {
+	NONE,
+	/** Normal world scheduled mode. */
+	NWD_MODE,
+	/** SPMC scheduled mode. */
+	SPMC_MODE,
+};
+
 struct interrupts {
 	/** Bitfield keeping track of which interrupts are enabled. */
 	struct interrupt_bitmap interrupt_enabled;
@@ -77,6 +86,14 @@
 	uint32_t mode;
 };
 
+struct call_chain {
+	/** Previous node in the SP call chain. */
+	struct vcpu *prev_node;
+
+	/** Next node in the SP call chain. */
+	struct vcpu *next_node;
+};
+
 struct vcpu {
 	struct spinlock lock;
 
@@ -151,6 +168,15 @@
 	 */
 	bool implicit_completion_signal;
 
+	/** SP call chain. */
+	struct call_chain call_chain;
+
+	/**
+	 * Indicates if the current vCPU is running in SPMC scheduled
+	 * mode or Normal World scheduled mode.
+	 */
+	enum schedule_mode scheduling_mode;
+
 	/** Partition Runtime Model. */
 	enum partition_runtime_model rt_model;
 };
@@ -301,3 +327,17 @@
 	return vcpu_locked.vcpu->interrupts.enabled_and_pending_irq_count +
 	       vcpu_locked.vcpu->interrupts.enabled_and_pending_fiq_count;
 }
+
+static inline void vcpu_call_chain_extend(struct vcpu *vcpu1,
+					  struct vcpu *vcpu2)
+{
+	vcpu1->call_chain.next_node = vcpu2;
+	vcpu2->call_chain.prev_node = vcpu1;
+}
+
+static inline void vcpu_call_chain_remove_node(struct vcpu *vcpu1,
+					       struct vcpu *vcpu2)
+{
+	vcpu1->call_chain.prev_node = NULL;
+	vcpu2->call_chain.next_node = NULL;
+}