feat: allow an endpoint to specify optional timeout with FFA_YIELD
An endpoint can yield execution back to the VM that allocated it CPU
cycles rather than busy waiting (such as for an IO operation to
complete). FF-A v1.2 spec allows the endpoint to specify an optional
64-bit timeout.
Signed-off-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
Change-Id: I5481c5483f4edd71b95c15a11a118498c71e3fa1
diff --git a/src/api.c b/src/api.c
index 073e011..89c0332 100644
--- a/src/api.c
+++ b/src/api.c
@@ -274,12 +274,27 @@
* control back to the execution context of the endpoint that originally
* allocated cycles to it.
*/
-struct ffa_value api_yield(struct vcpu *current, struct vcpu **next)
+struct ffa_value api_yield(struct vcpu *current, struct vcpu **next,
+ struct ffa_value *args)
{
struct ffa_value ret = (struct ffa_value){.func = FFA_SUCCESS_32};
struct vcpu_locked current_locked;
bool transition_allowed;
enum vcpu_state next_state = VCPU_STATE_BLOCKED;
+ uint32_t timeout_low = 0;
+ uint32_t timeout_high = 0;
+
+ if (args != NULL) {
+ if (args->arg4 != 0U || args->arg5 != 0U || args->arg6 != 0U ||
+ args->arg7 != 0U) {
+ dlog_error(
+ "Parameters passed through registers X4-X7 "
+ "must be zero\n");
+ return ffa_error(FFA_INVALID_PARAMETERS);
+ }
+ timeout_low = (uint32_t)args->arg2 & 0xFFFFFFFF;
+ timeout_high = (uint32_t)args->arg3 & 0xFFFFFFFF;
+ }
if (current->vm->id == HF_PRIMARY_VM_ID) {
/* NOOP on the primary as it makes the scheduling decisions. */
@@ -298,7 +313,7 @@
assert(next_state == VCPU_STATE_BLOCKED);
- return plat_ffa_yield_prepare(current, next);
+ return plat_ffa_yield_prepare(current, next, timeout_low, timeout_high);
}
/**
diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c
index cdc9697..1ee1f3d 100644
--- a/src/arch/aarch64/hypervisor/handler.c
+++ b/src/arch/aarch64/hypervisor/handler.c
@@ -576,7 +576,7 @@
*args = api_ffa_rx_acquire(ffa_receiver(*args), current);
return true;
case FFA_YIELD_32:
- *args = api_yield(current, next);
+ *args = api_yield(current, next, args);
return true;
case FFA_MSG_SEND_32:
*args = plat_ffa_msg_send(
@@ -1236,7 +1236,7 @@
* interrupts into EL0 partitions.
*/
if (is_el0_partition) {
- api_yield(vcpu, &new_vcpu);
+ api_yield(vcpu, &new_vcpu, NULL);
return new_vcpu;
}
@@ -1247,7 +1247,7 @@
* TODO: consider giving the scheduler more context,
* somehow.
*/
- api_yield(vcpu, &new_vcpu);
+ api_yield(vcpu, &new_vcpu, NULL);
return new_vcpu;
}
/* WFI */
diff --git a/src/arch/aarch64/plat/ffa/absent.c b/src/arch/aarch64/plat/ffa/absent.c
index 91b8b5a..212e33c 100644
--- a/src/arch/aarch64/plat/ffa/absent.c
+++ b/src/arch/aarch64/plat/ffa/absent.c
@@ -597,10 +597,14 @@
}
struct ffa_value plat_ffa_yield_prepare(struct vcpu *current,
- struct vcpu **next)
+ struct vcpu **next,
+ uint32_t timeout_low,
+ uint32_t timeout_high)
{
(void)current;
(void)next;
+ (void)timeout_low;
+ (void)timeout_high;
return ffa_error(FFA_NOT_SUPPORTED);
}
diff --git a/src/arch/aarch64/plat/ffa/hypervisor.c b/src/arch/aarch64/plat/ffa/hypervisor.c
index 575acf2..0c4a39b 100644
--- a/src/arch/aarch64/plat/ffa/hypervisor.c
+++ b/src/arch/aarch64/plat/ffa/hypervisor.c
@@ -2269,11 +2269,15 @@
* to BLOCKED state.
*/
struct ffa_value plat_ffa_yield_prepare(struct vcpu *current,
- struct vcpu **next)
+ struct vcpu **next,
+ uint32_t timeout_low,
+ uint32_t timeout_high)
{
struct ffa_value ret = {
.func = FFA_YIELD_32,
.arg1 = ffa_vm_vcpu(current->vm->id, vcpu_index(current)),
+ .arg2 = timeout_low,
+ .arg3 = timeout_high,
};
/*
diff --git a/src/arch/aarch64/plat/ffa/spmc.c b/src/arch/aarch64/plat/ffa/spmc.c
index 468772c..3f5fa90 100644
--- a/src/arch/aarch64/plat/ffa/spmc.c
+++ b/src/arch/aarch64/plat/ffa/spmc.c
@@ -2677,12 +2677,16 @@
* move to BLOCKED state.
*/
struct ffa_value plat_ffa_yield_prepare(struct vcpu *current,
- struct vcpu **next)
+ struct vcpu **next,
+ uint32_t timeout_low,
+ uint32_t timeout_high)
{
struct ffa_value ret_args = (struct ffa_value){.func = FFA_SUCCESS_32};
struct ffa_value ret = {
.func = FFA_YIELD_32,
.arg1 = ffa_vm_vcpu(current->vm->id, vcpu_index(current)),
+ .arg2 = timeout_low,
+ .arg3 = timeout_high,
};
switch (current->rt_model) {
diff --git a/src/arch/fake/hypervisor/ffa.c b/src/arch/fake/hypervisor/ffa.c
index 4747a73..bee008c 100644
--- a/src/arch/fake/hypervisor/ffa.c
+++ b/src/arch/fake/hypervisor/ffa.c
@@ -566,10 +566,14 @@
}
struct ffa_value plat_ffa_yield_prepare(struct vcpu *current,
- struct vcpu **next)
+ struct vcpu **next,
+ uint32_t timeout_low,
+ uint32_t timeout_high)
{
(void)current;
(void)next;
+ (void)timeout_low;
+ (void)timeout_high;
return ffa_error(FFA_NOT_SUPPORTED);
}