[PATCH v4 3/7] hv: support asyncio request


Conghui Chen
 

In the original IO request flow, User VM need to wait for the completion
of the I/O request before return. But there is a kind of register, such
as the NOTIFY register in virtio devices, is used for FE driver to
notify BE driver, and can be asynchronously processed in BE side. For
that purpose, ACRN hypervisor can easily emulate this register by
sending a notification to vCPU in Service VM side. This way, FE side can
resume to work without waiting for the full completion of BE side
response.

Signed-off-by: Conghui <conghui.chen@...>
---
hypervisor/arch/x86/guest/vm.c | 1 +
hypervisor/common/sbuf.c | 5 ++++-
hypervisor/dm/io_req.c | 17 +++++++++++++++++
hypervisor/include/arch/x86/asm/guest/vm.h | 1 +
hypervisor/include/dm/io_req.h | 2 ++
hypervisor/include/public/acrn_common.h | 1 +
6 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/hypervisor/arch/x86/guest/vm.c b/hypervisor/arch/x86/guest/vm.c
index bdd31d3fa..c103d3a1f 100644
--- a/hypervisor/arch/x86/guest/vm.c
+++ b/hypervisor/arch/x86/guest/vm.c
@@ -758,6 +758,7 @@ int32_t create_vm(uint16_t vm_id, uint64_t pcpu_bitmap, struct acrn_vm_config *v
/* Populate return VM handle */
*rtn_vm = vm;
vm->sw.io_shared_page = NULL;
+ vm->sw.asyncio_sbuf = NULL;
if ((vm_config->load_order == POST_LAUNCHED_VM)
&& ((vm_config->guest_flags & GUEST_FLAG_IO_COMPLETION_POLLING) != 0U)) {
/* enable IO completion polling mode per its guest flags in vm_config. */
diff --git a/hypervisor/common/sbuf.c b/hypervisor/common/sbuf.c
index 36ce9d2fa..73131fd53 100644
--- a/hypervisor/common/sbuf.c
+++ b/hypervisor/common/sbuf.c
@@ -79,7 +79,7 @@ uint32_t sbuf_put(struct shared_buf *sbuf, uint8_t *data)
return ele_size;
}

-int32_t sbuf_setup_common(__unused struct acrn_vm *vm, uint16_t cpu_id, uint32_t sbuf_id, uint64_t *hva)
+int32_t sbuf_setup_common(struct acrn_vm *vm, uint16_t cpu_id, uint32_t sbuf_id, uint64_t *hva)
{
int32_t ret = 0;

@@ -90,6 +90,9 @@ int32_t sbuf_setup_common(__unused struct acrn_vm *vm, uint16_t cpu_id, uint32_t
case ACRN_SOCWATCH:
ret = sbuf_share_setup(cpu_id, sbuf_id, hva);
break;
+ case ACRN_ASYNCIO:
+ ret = init_asyncio(vm, hva);
+ break;
default:
pr_err("%s not support sbuf_id %d", __func__, sbuf_id);
ret = -1;
diff --git a/hypervisor/dm/io_req.c b/hypervisor/dm/io_req.c
index afb695179..2ddecfe37 100644
--- a/hypervisor/dm/io_req.c
+++ b/hypervisor/dm/io_req.c
@@ -177,6 +177,23 @@ void set_io_req_state(struct acrn_vm *vm, uint16_t vcpu_id, uint32_t state)
}
}

+int init_asyncio(struct acrn_vm *vm, uint64_t *hva)
+{
+ struct shared_buf *sbuf = (struct shared_buf *)hva;
+ int ret = -1;
+
+ stac();
+ if (sbuf != NULL) {
+ if (sbuf->magic == SBUF_MAGIC) {
+ vm->sw.asyncio_sbuf = sbuf;
+ ret = 0;
+ }
+ }
+ clac();
+
+ return ret;
+}
+
void set_hsm_notification_vector(uint32_t vector)
{
acrn_hsm_notification_vector = vector;
diff --git a/hypervisor/include/arch/x86/asm/guest/vm.h b/hypervisor/include/arch/x86/asm/guest/vm.h
index 62267af27..8ce702137 100644
--- a/hypervisor/include/arch/x86/asm/guest/vm.h
+++ b/hypervisor/include/arch/x86/asm/guest/vm.h
@@ -69,6 +69,7 @@ struct vm_sw_info {
struct sw_module_info acpi_info;
/* HVA to IO shared page */
void *io_shared_page;
+ void *asyncio_sbuf;
/* If enable IO completion polling mode */
bool is_polling_ioreq;
};
diff --git a/hypervisor/include/dm/io_req.h b/hypervisor/include/dm/io_req.h
index f64abf22c..d5ebd2268 100644
--- a/hypervisor/include/dm/io_req.h
+++ b/hypervisor/include/dm/io_req.h
@@ -291,6 +291,8 @@ void register_mmio_emulation_handler(struct acrn_vm *vm,
void unregister_mmio_emulation_handler(struct acrn_vm *vm,
uint64_t start, uint64_t end);
void deinit_emul_io(struct acrn_vm *vm);
+
+int init_asyncio(struct acrn_vm *vm, uint64_t *hva);
/**
* @}
*/
diff --git a/hypervisor/include/public/acrn_common.h b/hypervisor/include/public/acrn_common.h
index 7c73ca070..2f1674350 100644
--- a/hypervisor/include/public/acrn_common.h
+++ b/hypervisor/include/public/acrn_common.h
@@ -747,6 +747,7 @@ enum {
ACRN_SEP,
ACRN_SOCWATCH,
ACRN_SBUF_ID_MAX,
+ ACRN_ASYNCIO = 64,
};

/* Make sure sizeof(struct shared_buf) == SBUF_HEAD_SIZE */
--
2.25.1


Eddie Dong
 

-----Original Message-----
From: acrn-dev@... <acrn-dev@...> On
Behalf Of Conghui Chen
Sent: Monday, September 12, 2022 8:28 PM
To: acrn-dev@...
Cc: Chen, Conghui <conghui.chen@...>
Subject: [acrn-dev] [PATCH v4 3/7] hv: support asyncio request

In the original IO request flow, User VM need to wait for the completion of the
Current IO emulation is synchronous. The user VM need to wait for ......

I/O request before return. But there is a kind of register, such as the NOTIFY
But VFIO spec introduces asynchronous IO with a new register in MMIO space, named NOTIFY, to be used for FE driver to notify BE driver, ....

register in virtio devices, is used for FE driver to notify BE driver, and can be
asynchronously processed in BE side. For that purpose, ACRN hypervisor can
easily emulate this register by sending a notification to vCPU in Service VM
side. This way, FE side can resume to work without waiting for the full
completion of BE side response.

Signed-off-by: Conghui <conghui.chen@...>
---
hypervisor/arch/x86/guest/vm.c | 1 +
hypervisor/common/sbuf.c | 5 ++++-
hypervisor/dm/io_req.c | 17 +++++++++++++++++
hypervisor/include/arch/x86/asm/guest/vm.h | 1 +
hypervisor/include/dm/io_req.h | 2 ++
hypervisor/include/public/acrn_common.h | 1 +
6 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/hypervisor/arch/x86/guest/vm.c
b/hypervisor/arch/x86/guest/vm.c index bdd31d3fa..c103d3a1f 100644
--- a/hypervisor/arch/x86/guest/vm.c
+++ b/hypervisor/arch/x86/guest/vm.c
@@ -758,6 +758,7 @@ int32_t create_vm(uint16_t vm_id, uint64_t
pcpu_bitmap, struct acrn_vm_config *v
/* Populate return VM handle */
*rtn_vm = vm;
vm->sw.io_shared_page = NULL;
+ vm->sw.asyncio_sbuf = NULL;
if ((vm_config->load_order == POST_LAUNCHED_VM)
&& ((vm_config->guest_flags &
GUEST_FLAG_IO_COMPLETION_POLLING) != 0U)) {
/* enable IO completion polling mode per its
guest flags in vm_config. */ diff --git a/hypervisor/common/sbuf.c
b/hypervisor/common/sbuf.c index 36ce9d2fa..73131fd53 100644
--- a/hypervisor/common/sbuf.c
+++ b/hypervisor/common/sbuf.c
@@ -79,7 +79,7 @@ uint32_t sbuf_put(struct shared_buf *sbuf, uint8_t
*data)
return ele_size;
}

-int32_t sbuf_setup_common(__unused struct acrn_vm *vm, uint16_t cpu_id,
uint32_t sbuf_id, uint64_t *hva)
+int32_t sbuf_setup_common(struct acrn_vm *vm, uint16_t cpu_id, uint32_t
+sbuf_id, uint64_t *hva)
{
int32_t ret = 0;

@@ -90,6 +90,9 @@ int32_t sbuf_setup_common(__unused struct acrn_vm
*vm, uint16_t cpu_id, uint32_t
case ACRN_SOCWATCH:
ret = sbuf_share_setup(cpu_id, sbuf_id, hva);
break;
+ case ACRN_ASYNCIO:
+ ret = init_asyncio(vm, hva);
+ break;
default:
pr_err("%s not support sbuf_id %d", __func__,
sbuf_id);
ret = -1;
diff --git a/hypervisor/dm/io_req.c b/hypervisor/dm/io_req.c index
afb695179..2ddecfe37 100644
--- a/hypervisor/dm/io_req.c
+++ b/hypervisor/dm/io_req.c
@@ -177,6 +177,23 @@ void set_io_req_state(struct acrn_vm *vm, uint16_t
vcpu_id, uint32_t state)
}
}

+int init_asyncio(struct acrn_vm *vm, uint64_t *hva) {
+ struct shared_buf *sbuf = (struct shared_buf *)hva;
+ int ret = -1;
+
+ stac();
+ if (sbuf != NULL) {
+ if (sbuf->magic == SBUF_MAGIC) {
+ vm->sw.asyncio_sbuf = sbuf;
+ ret = 0;
+ }
+ }
+ clac();
+
+ return ret;
+}
+
void set_hsm_notification_vector(uint32_t vector) {
acrn_hsm_notification_vector = vector; diff --git
a/hypervisor/include/arch/x86/asm/guest/vm.h
b/hypervisor/include/arch/x86/asm/guest/vm.h
index 62267af27..8ce702137 100644
--- a/hypervisor/include/arch/x86/asm/guest/vm.h
+++ b/hypervisor/include/arch/x86/asm/guest/vm.h
@@ -69,6 +69,7 @@ struct vm_sw_info {
struct sw_module_info acpi_info;
/* HVA to IO shared page */
void *io_shared_page;
+ void *asyncio_sbuf;
/* If enable IO completion polling mode */
bool is_polling_ioreq;
};
diff --git a/hypervisor/include/dm/io_req.h b/hypervisor/include/dm/io_req.h
index f64abf22c..d5ebd2268 100644
--- a/hypervisor/include/dm/io_req.h
+++ b/hypervisor/include/dm/io_req.h
@@ -291,6 +291,8 @@ void register_mmio_emulation_handler(struct
acrn_vm *vm, void unregister_mmio_emulation_handler(struct acrn_vm *vm,
uint64_t start, uint64_t end);
void deinit_emul_io(struct acrn_vm *vm);
+
+int init_asyncio(struct acrn_vm *vm, uint64_t *hva);
/**
* @}
*/
diff --git a/hypervisor/include/public/acrn_common.h
b/hypervisor/include/public/acrn_common.h
index 7c73ca070..2f1674350 100644
--- a/hypervisor/include/public/acrn_common.h
+++ b/hypervisor/include/public/acrn_common.h
@@ -747,6 +747,7 @@ enum {
ACRN_SEP,
ACRN_SOCWATCH,
ACRN_SBUF_ID_MAX,
+ ACRN_ASYNCIO = 64,
After ACRN_SBUF_ID_MAX?



};

/* Make sure sizeof(struct shared_buf) == SBUF_HEAD_SIZE */
--
2.25.1





Conghui Chen
 

Hi Eddie,

-----Original Message-----
From: acrn-dev@... <acrn-dev@...> On
Behalf Of Conghui Chen
Sent: Monday, September 12, 2022 8:28 PM
To: acrn-dev@...
Cc: Chen, Conghui <conghui.chen@...>
Subject: [acrn-dev] [PATCH v4 3/7] hv: support asyncio request

In the original IO request flow, User VM need to wait for the completion of
the

Current IO emulation is synchronous. The user VM need to wait for ......

I/O request before return. But there is a kind of register, such as the NOTIFY
But VFIO spec introduces asynchronous IO with a new register in MMIO space,
named NOTIFY, to be used for FE driver to notify BE driver, ....
Will change the commit message, thanks.




Signed-off-by: Conghui <conghui.chen@...>
---
hypervisor/arch/x86/guest/vm.c | 1 +
hypervisor/common/sbuf.c | 5 ++++-
hypervisor/dm/io_req.c | 17 +++++++++++++++++
hypervisor/include/arch/x86/asm/guest/vm.h | 1 +
hypervisor/include/dm/io_req.h | 2 ++
hypervisor/include/public/acrn_common.h | 1 +
6 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/hypervisor/arch/x86/guest/vm.c
b/hypervisor/arch/x86/guest/vm.c index bdd31d3fa..c103d3a1f 100644
--- a/hypervisor/arch/x86/guest/vm.c
+++ b/hypervisor/arch/x86/guest/vm.c
@@ -758,6 +758,7 @@ int32_t create_vm(uint16_t vm_id, uint64_t
pcpu_bitmap, struct acrn_vm_config *v
/* Populate return VM handle */
*rtn_vm = vm;
vm->sw.io_shared_page = NULL;
+ vm->sw.asyncio_sbuf = NULL;
if ((vm_config->load_order == POST_LAUNCHED_VM)
&& ((vm_config->guest_flags &
GUEST_FLAG_IO_COMPLETION_POLLING) != 0U)) {
/* enable IO completion polling mode per its
guest flags in vm_config. */ diff --git a/hypervisor/common/sbuf.c
b/hypervisor/common/sbuf.c index 36ce9d2fa..73131fd53 100644
--- a/hypervisor/common/sbuf.c
+++ b/hypervisor/common/sbuf.c
@@ -79,7 +79,7 @@ uint32_t sbuf_put(struct shared_buf *sbuf, uint8_t
*data)
return ele_size;
}

-int32_t sbuf_setup_common(__unused struct acrn_vm *vm, uint16_t
cpu_id,
uint32_t sbuf_id, uint64_t *hva)
+int32_t sbuf_setup_common(struct acrn_vm *vm, uint16_t cpu_id,
uint32_t
+sbuf_id, uint64_t *hva)
{
int32_t ret = 0;

@@ -90,6 +90,9 @@ int32_t sbuf_setup_common(__unused struct
acrn_vm
*vm, uint16_t cpu_id, uint32_t
case ACRN_SOCWATCH:
ret = sbuf_share_setup(cpu_id, sbuf_id, hva);
break;
+ case ACRN_ASYNCIO:
+ ret = init_asyncio(vm, hva);
+ break;
default:
pr_err("%s not support sbuf_id %d", __func__,
sbuf_id);
ret = -1;
diff --git a/hypervisor/dm/io_req.c b/hypervisor/dm/io_req.c index
afb695179..2ddecfe37 100644
--- a/hypervisor/dm/io_req.c
+++ b/hypervisor/dm/io_req.c
@@ -177,6 +177,23 @@ void set_io_req_state(struct acrn_vm *vm,
uint16_t
vcpu_id, uint32_t state)
}
}

+int init_asyncio(struct acrn_vm *vm, uint64_t *hva) {
+ struct shared_buf *sbuf = (struct shared_buf *)hva;
+ int ret = -1;
+
+ stac();
+ if (sbuf != NULL) {
+ if (sbuf->magic == SBUF_MAGIC) {
+ vm->sw.asyncio_sbuf = sbuf;
+ ret = 0;
+ }
+ }
+ clac();
+
+ return ret;
+}
+
void set_hsm_notification_vector(uint32_t vector) {
acrn_hsm_notification_vector = vector; diff --git
a/hypervisor/include/arch/x86/asm/guest/vm.h
b/hypervisor/include/arch/x86/asm/guest/vm.h
index 62267af27..8ce702137 100644
--- a/hypervisor/include/arch/x86/asm/guest/vm.h
+++ b/hypervisor/include/arch/x86/asm/guest/vm.h
@@ -69,6 +69,7 @@ struct vm_sw_info {
struct sw_module_info acpi_info;
/* HVA to IO shared page */
void *io_shared_page;
+ void *asyncio_sbuf;
/* If enable IO completion polling mode */
bool is_polling_ioreq;
};
diff --git a/hypervisor/include/dm/io_req.h
b/hypervisor/include/dm/io_req.h
index f64abf22c..d5ebd2268 100644
--- a/hypervisor/include/dm/io_req.h
+++ b/hypervisor/include/dm/io_req.h
@@ -291,6 +291,8 @@ void register_mmio_emulation_handler(struct
acrn_vm *vm, void unregister_mmio_emulation_handler(struct acrn_vm
*vm,
uint64_t start, uint64_t end);
void deinit_emul_io(struct acrn_vm *vm);
+
+int init_asyncio(struct acrn_vm *vm, uint64_t *hva);
/**
* @}
*/
diff --git a/hypervisor/include/public/acrn_common.h
b/hypervisor/include/public/acrn_common.h
index 7c73ca070..2f1674350 100644
--- a/hypervisor/include/public/acrn_common.h
+++ b/hypervisor/include/public/acrn_common.h
@@ -747,6 +747,7 @@ enum {
ACRN_SEP,
ACRN_SOCWATCH,
ACRN_SBUF_ID_MAX,
+ ACRN_ASYNCIO = 64,
After ACRN_SBUF_ID_MAX?
The ACRN_SBUF_ID_MAX is currently used in per_cpu structure, the sbuf type above ACRN_SBUF_ID_MAX will be created per pcpu.
So, change the name ACRN_SBUF_ID_MAX to ACRN_SBUF_PER_PCPU_ID_MAX is better?

struct per_cpu_region {
...
#ifdef HV_DEBUG
struct shared_buf *sbuf[ACRN_SBUF_ID_MAX]; <------- here.
char logbuf[LOG_MESSAGE_MAX_SIZE];
uint32_t npk_log_ref;
#endif

ACRN_ASYNCIO is per VM, so should put below the ACRN_SBUF_ID_MAX/ACRN_SBUF_PER_PCPU_ID_MAX.


Regards,
Conghui.



};

/* Make sure sizeof(struct shared_buf) == SBUF_HEAD_SIZE */
--
2.25.1





Eddie Dong
 

diff --git a/hypervisor/include/public/acrn_common.h
b/hypervisor/include/public/acrn_common.h
index 7c73ca070..2f1674350 100644
--- a/hypervisor/include/public/acrn_common.h
+++ b/hypervisor/include/public/acrn_common.h
@@ -747,6 +747,7 @@ enum {
ACRN_SEP,
ACRN_SOCWATCH,
ACRN_SBUF_ID_MAX,
+ ACRN_ASYNCIO = 64,
After ACRN_SBUF_ID_MAX?
The ACRN_SBUF_ID_MAX is currently used in per_cpu structure, the sbuf type
above ACRN_SBUF_ID_MAX will be created per pcpu.
So, change the name ACRN_SBUF_ID_MAX to
ACRN_SBUF_PER_PCPU_ID_MAX is better?
OK. Rename it, and add a comment here.
The rest is fine.


struct per_cpu_region {
...
#ifdef HV_DEBUG
struct shared_buf *sbuf[ACRN_SBUF_ID_MAX]; <------- here.
char logbuf[LOG_MESSAGE_MAX_SIZE];
uint32_t npk_log_ref;
#endif

ACRN_ASYNCIO is per VM, so should put below the
ACRN_SBUF_ID_MAX/ACRN_SBUF_PER_PCPU_ID_MAX.


Regards,
Conghui.



};

/* Make sure sizeof(struct shared_buf) == SBUF_HEAD_SIZE */
--
2.25.1