Add hypercall to donate CPU time to a vCPU.
Signed-off-by: Elliot Berman <quic_eberman@quicinc.com>
---
arch/arm64/gunyah/gunyah_hypercall.c | 37 ++++++++++++++++++++++++++++++++++++
include/linux/gunyah.h | 35 ++++++++++++++++++++++++++++++++++
2 files changed, 72 insertions(+)
diff --git a/arch/arm64/gunyah/gunyah_hypercall.c b/arch/arm64/gunyah/gunyah_hypercall.c
index 1302e128be6e9..fee21df42c176 100644
--- a/arch/arm64/gunyah/gunyah_hypercall.c
+++ b/arch/arm64/gunyah/gunyah_hypercall.c
@@ -39,6 +39,7 @@ EXPORT_SYMBOL_GPL(arch_is_gunyah_guest);
#define GUNYAH_HYPERCALL_HYP_IDENTIFY GUNYAH_HYPERCALL(0x8000)
#define GUNYAH_HYPERCALL_MSGQ_SEND GUNYAH_HYPERCALL(0x801B)
#define GUNYAH_HYPERCALL_MSGQ_RECV GUNYAH_HYPERCALL(0x801C)
+#define GUNYAH_HYPERCALL_VCPU_RUN GUNYAH_HYPERCALL(0x8065)
/* clang-format on */
/**
@@ -113,5 +114,41 @@ enum gunyah_error gunyah_hypercall_msgq_recv(u64 capid, void *buff, size_t size,
}
EXPORT_SYMBOL_GPL(gunyah_hypercall_msgq_recv);
+/**
+ * gunyah_hypercall_vcpu_run() - Donate CPU time to a vcpu
+ * @capid: capability ID of the vCPU to run
+ * @resume_data: Array of 3 state-specific resume data
+ * @resp: Filled reason why vCPU exited when return value is GUNYAH_ERROR_OK
+ *
+ * See also:
+ * https://github.com/quic/gunyah-hypervisor/blob/develop/docs/api/gunyah_api.md#run-a-proxy-scheduled-vcpu-thread
+ */
+enum gunyah_error
+gunyah_hypercall_vcpu_run(u64 capid, unsigned long *resume_data,
+ struct gunyah_hypercall_vcpu_run_resp *resp)
+{
+ struct arm_smccc_1_2_regs args = {
+ .a0 = GUNYAH_HYPERCALL_VCPU_RUN,
+ .a1 = capid,
+ .a2 = resume_data[0],
+ .a3 = resume_data[1],
+ .a4 = resume_data[2],
+ /* C language says this will be implictly zero. Gunyah requires 0, so be explicit */
+ .a5 = 0,
+ };
+ struct arm_smccc_1_2_regs res;
+
+ arm_smccc_1_2_hvc(&args, &res);
+ if (res.a0 == GUNYAH_ERROR_OK) {
+ resp->sized_state = res.a1;
+ resp->state_data[0] = res.a2;
+ resp->state_data[1] = res.a3;
+ resp->state_data[2] = res.a4;
+ }
+
+ return res.a0;
+}
+EXPORT_SYMBOL_GPL(gunyah_hypercall_vcpu_run);
+
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Gunyah Hypervisor Hypercalls");
diff --git a/include/linux/gunyah.h b/include/linux/gunyah.h
index 18ecebf41a3ff..6c24544f38dc9 100644
--- a/include/linux/gunyah.h
+++ b/include/linux/gunyah.h
@@ -273,4 +273,39 @@ enum gunyah_error gunyah_hypercall_msgq_send(u64 capid, size_t size, void *buff,
enum gunyah_error gunyah_hypercall_msgq_recv(u64 capid, void *buff, size_t size,
size_t *recv_size, bool *ready);
+struct gunyah_hypercall_vcpu_run_resp {
+ union {
+ enum {
+ /* clang-format off */
+ /* VCPU is ready to run */
+ GUNYAH_VCPU_STATE_READY = 0,
+ /* VCPU is sleeping until an interrupt arrives */
+ GUNYAH_VCPU_STATE_EXPECTS_WAKEUP = 1,
+ /* VCPU is powered off */
+ GUNYAH_VCPU_STATE_POWERED_OFF = 2,
+ /* VCPU is blocked in EL2 for unspecified reason */
+ GUNYAH_VCPU_STATE_BLOCKED = 3,
+ /* VCPU has returned for MMIO READ */
+ GUNYAH_VCPU_ADDRSPACE_VMMIO_READ = 4,
+ /* VCPU has returned for MMIO WRITE */
+ GUNYAH_VCPU_ADDRSPACE_VMMIO_WRITE = 5,
+ /* VCPU blocked on fault where we can demand page */
+ GUNYAH_VCPU_ADDRSPACE_PAGE_FAULT = 7,
+ /* clang-format on */
+ } state;
+ u64 sized_state;
+ };
+ u64 state_data[3];
+};
+
+enum {
+ GUNYAH_ADDRSPACE_VMMIO_ACTION_EMULATE = 0,
+ GUNYAH_ADDRSPACE_VMMIO_ACTION_RETRY = 1,
+ GUNYAH_ADDRSPACE_VMMIO_ACTION_FAULT = 2,
+};
+
+enum gunyah_error
+gunyah_hypercall_vcpu_run(u64 capid, unsigned long *resume_data,
+ struct gunyah_hypercall_vcpu_run_resp *resp);
+
#endif
--
2.34.1