diff --git a/devicemodel/include/public/acrn_common.h b/devicemodel/include/public/acrn_common.h index e30f9f312..f857f1993 100644 --- a/devicemodel/include/public/acrn_common.h +++ b/devicemodel/include/public/acrn_common.h @@ -173,11 +173,18 @@ struct vhm_request { uint32_t type; /** - * @brief Reserved. + * @brief Hypervisor will poll completion if set. * * Byte offset: 4. */ - uint32_t reserved0[15]; + uint32_t completion_polling; + + /** + * @brief Reserved. + * + * Byte offset: 8. + */ + uint32_t reserved0[14]; /** * @brief Details about this request. diff --git a/hypervisor/arch/x86/Kconfig b/hypervisor/arch/x86/Kconfig index 32dbbc6f0..ade1ce277 100644 --- a/hypervisor/arch/x86/Kconfig +++ b/hypervisor/arch/x86/Kconfig @@ -40,6 +40,28 @@ config PARTITION_MODE endchoice +choice + prompt "I/O emulation completion mode" + default IOREQ_NOTIFICATION + help + Select the mode of I/O emulation completion + +config IOREQ_NOTIFICATION + bool "Notification mode" + help + When I/O request is completed, SOS will mark the completion status and + notify hypervisor via hypercall. Hypervisor will finish the post work + when notification is received. + +config IOREQ_POLLING + bool "Polling mode" + help + When I/O request is completed, SOS will only mark completion status + without notifying hypervisor. Hypervisor will poll the completion + status and finish the post work. + +endchoice + config PLATFORM string default "uefi" if PLATFORM_UEFI diff --git a/hypervisor/arch/x86/guest/vm.c b/hypervisor/arch/x86/guest/vm.c index 4bf09f023..b2a8965cb 100644 --- a/hypervisor/arch/x86/guest/vm.c +++ b/hypervisor/arch/x86/guest/vm.c @@ -162,6 +162,10 @@ int create_vm(struct vm_description *vm_desc, struct acrn_vm **rtn_vm) /* Populate return VM handle */ *rtn_vm = vm; vm->sw.io_shared_page = NULL; +#ifdef CONFIG_IOREQ_POLLING + /* Now, enable IO completion polling mode for all VMs with CONFIG_IOREQ_POLLING. */ + vm->sw.is_completion_polling = true; +#endif status = set_vcpuid_entries(vm); if (status != 0) { diff --git a/hypervisor/common/io_request.c b/hypervisor/common/io_request.c index a6c50142d..92aaaf386 100644 --- a/hypervisor/common/io_request.c +++ b/hypervisor/common/io_request.c @@ -74,6 +74,50 @@ void reset_vm_ioreqs(struct acrn_vm *vm) } } +static bool has_complete_ioreq(struct acrn_vcpu *vcpu) +{ + union vhm_request_buffer *req_buf = NULL; + struct vhm_request *vhm_req; + struct acrn_vm *vm; + + vm = vcpu->vm; + req_buf = (union vhm_request_buffer *)vm->sw.io_shared_page; + if (req_buf != NULL) { + vhm_req = &req_buf->req_queue[vcpu->vcpu_id]; + if (vhm_req->valid && + atomic_load32(&vhm_req->processed) + == REQ_STATE_COMPLETE) { + return true; + + } + } + + return false; +} + +/** + * @brief Handle completed ioreq if any one pending + * + * @param pcpu_id The physical cpu id of vcpu whose IO request to be checked + * + * @return N/A + */ +void handle_complete_ioreq(uint16_t pcpu_id) +{ + struct acrn_vcpu *vcpu = get_ever_run_vcpu(pcpu_id); + struct acrn_vm *vm; + + if (vcpu != NULL) { + vm = vcpu->vm; + if (vm->sw.is_completion_polling) { + if (has_complete_ioreq(vcpu)) { + /* we have completed ioreq pending */ + emulate_io_post(vcpu); + } + } + } +} + /** * @brief Deliver \p io_req to SOS and suspend \p vcpu till its completion * @@ -103,6 +147,9 @@ int32_t acrn_insert_request_wait(struct acrn_vcpu *vcpu, const struct io_request vhm_req->type = io_req->type; (void)memcpy_s(&vhm_req->reqs, sizeof(union vhm_io_request), &io_req->reqs, sizeof(union vhm_io_request)); + if (vcpu->vm->sw.is_completion_polling) { + vhm_req->completion_polling = 1U; + } /* pause vcpu, wait for VHM to handle the MMIO request. * TODO: when pause_vcpu changed to switch vcpu out directlly, we diff --git a/hypervisor/common/schedule.c b/hypervisor/common/schedule.c index 5c6832588..baa71bab9 100644 --- a/hypervisor/common/schedule.c +++ b/hypervisor/common/schedule.c @@ -178,6 +178,7 @@ void default_idle(void) cpu_dead(pcpu_id); } else { CPU_IRQ_ENABLE(); + handle_complete_ioreq(pcpu_id); cpu_do_idle(); CPU_IRQ_DISABLE(); } diff --git a/hypervisor/include/arch/x86/guest/vm.h b/hypervisor/include/arch/x86/guest/vm.h index 8d8e73c47..fa68ff853 100644 --- a/hypervisor/include/arch/x86/guest/vm.h +++ b/hypervisor/include/arch/x86/guest/vm.h @@ -55,6 +55,8 @@ struct vm_sw_info { struct sw_linux linux_info; /* HVA to IO shared page */ void *io_shared_page; + /* If enable IO completion polling mode */ + bool is_completion_polling; }; struct vm_pm_info { diff --git a/hypervisor/include/arch/x86/ioreq.h b/hypervisor/include/arch/x86/ioreq.h index dd1328987..f158d4eba 100644 --- a/hypervisor/include/arch/x86/ioreq.h +++ b/hypervisor/include/arch/x86/ioreq.h @@ -296,6 +296,15 @@ int32_t acrn_insert_request_wait(struct acrn_vcpu *vcpu, const struct io_request */ void reset_vm_ioreqs(struct acrn_vm *vm); +/** + * @brief Handle completed ioreq if any one pending + * + * @param pcpu_id The physical cpu id of vcpu whose IO request to be checked + * + * @return N/A + */ +void handle_complete_ioreq(uint16_t pcpu_id); + /** * @} */ diff --git a/hypervisor/include/public/acrn_common.h b/hypervisor/include/public/acrn_common.h index 68d2106d9..073a155df 100644 --- a/hypervisor/include/public/acrn_common.h +++ b/hypervisor/include/public/acrn_common.h @@ -268,11 +268,18 @@ struct vhm_request { uint32_t type; /** - * Reserved. + * @brief Hypervisor will poll completion if set. * * Byte offset: 4. */ - uint32_t reserved0[15]; + uint32_t completion_polling; + + /** + * Reserved. + * + * Byte offset: 8. + */ + uint32_t reserved0[14]; /** * Details about this request. For REQ_PORTIO, this has type