[PATCH v4 2/5] virt: acrn: add new share page for AsyncIo


Conghui Chen
 

AsyncIo is a new mechanism in acrn, which is special for these devices
which need high IO performance. acrn hypervisor would process the IO
request from User VM in an async mode.

For this kind of I/O reqeusts, a new share page is created by device
model in userspace, and register to kernel with ioctl. ACRN hsm driver
will pin the page to avoid page swapping. Use hypercall to pass the base
addresses to hypervisor, so that hypervisor can access the page and change
request status.

Signed-off-by: Conghui <conghui.chen@...>
---
change.sh | 18 ++++++++++
drivers/virt/acrn/acrn_drv.h | 8 +++++
drivers/virt/acrn/hsm.c | 8 +++++
drivers/virt/acrn/hypercall.h | 13 +++++++
drivers/virt/acrn/ioreq.c | 28 +++++++++++++++
drivers/virt/acrn/sbuf.c | 65 +++++++++++++++++++++++++++++++++++
drivers/virt/acrn/sbuf.h | 3 ++
drivers/virt/acrn/vm.c | 2 ++
include/uapi/linux/acrn.h | 31 +++++++++++++++++
9 files changed, 176 insertions(+)
create mode 100755 change.sh

diff --git a/change.sh b/change.sh
new file mode 100755
index 000000000000..4946c089ee8a
--- /dev/null
+++ b/change.sh
@@ -0,0 +1,18 @@
+set -x
+
+ip=$1
+linux=$2
+SOS=root@${ip}
+
+echo $linux
+echo $ip
+
+
+ssh $SOS "rm ~/acrn-work/* -r"
+scp $linux ${SOS}:~/acrn-work/
+ssh $SOS "tar -xf ~/acrn-work/${linux} -C ~/acrn-work/"
+ssh $SOS "cp ~/acrn-work/boot/* /boot/"
+ssh $SOS "cp ~/acrn-work/lib/modules/* /lib/modules/ -r"
+ssh $SOS "sync"
+
+
diff --git a/drivers/virt/acrn/acrn_drv.h b/drivers/virt/acrn/acrn_drv.h
index 5663c17ad37c..5532baaaaa62 100644
--- a/drivers/virt/acrn/acrn_drv.h
+++ b/drivers/virt/acrn/acrn_drv.h
@@ -9,6 +9,7 @@
#include <linux/types.h>

#include "hypercall.h"
+#include "sbuf.h"

extern struct miscdevice acrn_dev;

@@ -134,6 +135,7 @@ struct acrn_ioreq_client {
};

#define ACRN_INVALID_VMID (0xffffU)
+#define ACRN_INVALID_CPUID (0xffffU)

#define ACRN_VM_FLAG_DESTROYED 0U
#define ACRN_VM_FLAG_CLEARING_IOREQ 1U
@@ -178,6 +180,10 @@ struct acrn_vm {
struct acrn_ioreq_client *default_client;
struct acrn_io_request_buffer *ioreq_buf;
struct page *ioreq_page;
+
+ shared_buf_t *asyncio_sbuf;
+ struct page *asyncio_page;
+ struct mutex asyncio_lock;
u32 pci_conf_addr;
struct page *monitor_page;
struct mutex ioeventfds_lock;
@@ -201,6 +207,8 @@ void acrn_vm_all_ram_unmap(struct acrn_vm *vm);

int acrn_ioreq_init(struct acrn_vm *vm, u64 buf_vma);
void acrn_ioreq_deinit(struct acrn_vm *vm);
+int acrn_asyncio_init(struct acrn_vm *vm, shared_buf_t *sbuf, struct page *page);
+void acrn_asyncio_deinit(struct acrn_vm *vm);
int acrn_ioreq_intr_setup(void);
void acrn_ioreq_intr_remove(void);
void acrn_ioreq_request_clear(struct acrn_vm *vm);
diff --git a/drivers/virt/acrn/hsm.c b/drivers/virt/acrn/hsm.c
index 423ea888d79a..a71f34a0f53e 100644
--- a/drivers/virt/acrn/hsm.c
+++ b/drivers/virt/acrn/hsm.c
@@ -19,6 +19,7 @@
#include <asm/hypervisor.h>

#include "acrn_drv.h"
+#include "sbuf.h"

/*
* When /dev/acrn_hsm is opened, a 'struct acrn_vm' object is created to
@@ -108,6 +109,7 @@ static long acrn_dev_ioctl(struct file *filp, unsigned int cmd,
unsigned long ioctl_param)
{
struct acrn_vm *vm = filp->private_data;
+ struct acrn_sbuf sbuf_param;
struct acrn_vm_creation *vm_param;
struct acrn_vcpu_regs *cpu_regs;
struct acrn_ioreq_notify notify;
@@ -177,6 +179,12 @@ static long acrn_dev_ioctl(struct file *filp, unsigned int cmd,
case ACRN_IOCTL_DESTROY_VM:
ret = acrn_vm_destroy(vm);
break;
+ case ACRN_IOCTL_SETUP_SBUF:
+ if (copy_from_user(&sbuf_param, (void __user *)ioctl_param,
+ sizeof(sbuf_param)))
+ return -EFAULT;
+ ret = acrn_sbuf_init(vm, sbuf_param.sbuf_id, sbuf_param.base);
+ break;
case ACRN_IOCTL_SET_VCPU_REGS:
cpu_regs = memdup_user((void __user *)ioctl_param,
sizeof(struct acrn_vcpu_regs));
diff --git a/drivers/virt/acrn/hypercall.h b/drivers/virt/acrn/hypercall.h
index 71d300821a18..4811003289ba 100644
--- a/drivers/virt/acrn/hypercall.h
+++ b/drivers/virt/acrn/hypercall.h
@@ -35,6 +35,7 @@

#define HC_ID_MEM_BASE 0x40UL
#define HC_VM_SET_MEMORY_REGIONS _HC_ID(HC_ID, HC_ID_MEM_BASE + 0x02)
+#define HC_SET_SBUF _HC_ID(HC_ID, HC_ID_MEM_BASE + 0x04)

#define HC_ID_PCI_BASE 0x50UL
#define HC_SET_PTDEV_INTR _HC_ID(HC_ID, HC_ID_PCI_BASE + 0x03)
@@ -175,6 +176,18 @@ static inline long hcall_set_ioreq_buffer(u64 vmid, u64 buffer)
return acrn_hypercall2(HC_SET_IOREQ_BUFFER, vmid, buffer);
}

+/**
+ * hcall_set_asyncio_buffer() - Set up the shared buffer.
+ * @vmid: User VM ID
+ * @buffer: Service VM GPA of the shared buffer
+ *
+ * Return: 0 on success, <0 on failure
+ */
+static inline long hcall_set_sbuf(u64 vmid, u64 buffer)
+{
+ return acrn_hypercall2(HC_SET_SBUF, vmid, buffer);
+}
+
/**
* hcall_notify_req_finish() - Notify ACRN Hypervisor of I/O request completion.
* @vmid: User VM ID
diff --git a/drivers/virt/acrn/ioreq.c b/drivers/virt/acrn/ioreq.c
index d75ab3f66da4..c047771712d1 100644
--- a/drivers/virt/acrn/ioreq.c
+++ b/drivers/virt/acrn/ioreq.c
@@ -633,6 +633,18 @@ int acrn_ioreq_init(struct acrn_vm *vm, u64 buf_vma)
return ret;
}

+int acrn_asyncio_init(struct acrn_vm *vm, shared_buf_t *sbuf, struct page *page)
+{
+ if (!sbuf || !page)
+ return -EEXIST;
+ vm->asyncio_sbuf = sbuf;
+ vm->asyncio_page = page;
+ mutex_init(&vm->asyncio_lock);
+ dev_dbg(acrn_dev.this_device,
+ "Init asyncio buffer %p\n", vm->asyncio_sbuf);
+ return 0;
+}
+
void acrn_ioreq_deinit(struct acrn_vm *vm)
{
struct acrn_ioreq_client *client, *next;
@@ -650,3 +662,19 @@ void acrn_ioreq_deinit(struct acrn_vm *vm)
vm->ioreq_buf = NULL;
}
}
+
+void acrn_asyncio_deinit(struct acrn_vm *vm)
+{
+ if (!vm) {
+ dev_err(acrn_dev.this_device,
+ "Failed to deinit asyncio buffer as vm is null!");
+ return;
+ }
+ dev_dbg(acrn_dev.this_device,
+ "Deinit asyncio buffer 0x%p\n", vm->asyncio_sbuf);
+ if (vm->asyncio_sbuf && vm->asyncio_page) {
+ unpin_user_page(vm->asyncio_page);
+ vm->asyncio_sbuf = NULL;
+ mutex_destroy(&vm->asyncio_lock);
+ }
+}
diff --git a/drivers/virt/acrn/sbuf.c b/drivers/virt/acrn/sbuf.c
index 2fc0149849b5..eb0fded28afd 100644
--- a/drivers/virt/acrn/sbuf.c
+++ b/drivers/virt/acrn/sbuf.c
@@ -48,3 +48,68 @@ void acrn_sbuf_move_next(shared_buf_t *sbuf)
{
sbuf->head = sbuf_next_ptr(sbuf->head, sbuf->ele_size, sbuf->size);
}
+
+int acrn_sbuf_setup(uint32_t vm_id, uint32_t cpu_id, uint32_t sbuf_id, uint64_t gpa)
+{
+ struct acrn_sbuf_param *asp;
+ int ret;
+
+ if (x86_hyper_type != X86_HYPER_ACRN)
+ return -ENODEV;
+
+ asp = kzalloc(sizeof(*asp), GFP_KERNEL);
+ if (!asp)
+ return -ENOMEM;
+ asp->cpu_id = cpu_id;
+ asp->sbuf_id = sbuf_id;
+ asp->gpa = gpa;
+
+ ret = hcall_set_sbuf(vm_id, virt_to_phys(asp));
+ kfree(asp);
+ return ret;
+}
+
+int acrn_sbuf_init(struct acrn_vm *vm, uint32_t sbuf_id, uint64_t base)
+{
+ shared_buf_t *sbuf;
+ struct page *page;
+ int ret;
+
+ switch (sbuf_id) {
+ case ACRN_ASYNCIO:
+ /* asyncio is created per vm, so vm should not be null */
+ ret = pin_user_pages_fast(base, 1,
+ FOLL_WRITE | FOLL_LONGTERM, &page);
+
+ if (unlikely(ret != 1) || !page) {
+ dev_err(acrn_dev.this_device, "Failed to pin asyncio page!\n");
+ return -EFAULT;
+ }
+
+ sbuf = page_address(page);
+ if (sbuf->magic != SBUF_MAGIC || ((sbuf->size + SBUF_HEAD_SIZE) > SBUF_MAX_SIZE)) {
+ dev_err(acrn_dev.this_device, "MAGIC is not correct or size is too large!\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = acrn_asyncio_init(vm, sbuf, page);
+ if (ret < 0) {
+ dev_err(acrn_dev.this_device, "Failed to init asyncio!\n");
+ goto err;
+ }
+ ret = acrn_sbuf_setup(vm->vmid, ACRN_INVALID_CPUID, sbuf_id, page_to_phys(page));
+ break;
+ default:
+ dev_err(acrn_dev.this_device, "sbuf_id %d is not supported!", sbuf_id);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (!ret)
+ return 0;
+
+err:
+ unpin_user_page(page);
+ return ret;
+}
diff --git a/drivers/virt/acrn/sbuf.h b/drivers/virt/acrn/sbuf.h
index e83845a39a37..b39438ae8144 100644
--- a/drivers/virt/acrn/sbuf.h
+++ b/drivers/virt/acrn/sbuf.h
@@ -59,6 +59,9 @@
#include <asm/acrn.h>
#include "acrn_drv.h"

+struct acrn_vm;
+int acrn_sbuf_init(struct acrn_vm *vm, uint32_t sbuf_id, uint64_t base);
+int acrn_sbuf_setup(uint32_t vm_id, uint32_t cpu_id, uint32_t sbuf_id, uint64_t gpa);
void *acrn_sbuf_get_data_ptr(shared_buf_t *sbuf);
void acrn_sbuf_move_next(struct shared_buf *sbuf);
#endif /* SHARED_BUF_H */
diff --git a/drivers/virt/acrn/vm.c b/drivers/virt/acrn/vm.c
index fbc9f1042000..0a7ee8bf6f81 100644
--- a/drivers/virt/acrn/vm.c
+++ b/drivers/virt/acrn/vm.c
@@ -13,6 +13,7 @@
#include <linux/slab.h>

#include "acrn_drv.h"
+#include "sbuf.h"

/* List of VMs */
LIST_HEAD(acrn_vm_list);
@@ -80,6 +81,7 @@ int acrn_vm_destroy(struct acrn_vm *vm)
acrn_ioeventfd_deinit(vm);
acrn_irqfd_deinit(vm);
acrn_ioreq_deinit(vm);
+ acrn_asyncio_deinit(vm);

if (vm->monitor_page) {
put_page(vm->monitor_page);
diff --git a/include/uapi/linux/acrn.h b/include/uapi/linux/acrn.h
index 32f03a85646c..5a0120afa5ef 100644
--- a/include/uapi/linux/acrn.h
+++ b/include/uapi/linux/acrn.h
@@ -487,6 +487,10 @@ struct acrn_vdev {
#define OVERRUN_CNT_EN (1ULL << 0) /* whether overrun counting is enabled */
#define OVERWRITE_EN (1ULL << 1) /* whether overwrite is enabled */

+ enum sbuf_type {
+ ACRN_ASYNCIO = 64,
+};
+
/**
* (sbuf) head + buf (store (ele_num - 1) elements at most)
* buffer empty: tail == head
@@ -617,6 +621,31 @@ struct acrn_irqfd {
struct acrn_msi_entry msi;
};

+/**
+ * struct acrn_sbuf - Data to register a share buffer by ioctl
+ * @sbuf_id: Type of the sbuf.
+ * @base: gva of the sbuf.
+ */
+struct acrn_sbuf {
+ __u32 sbuf_id;
+ __u64 base;
+};
+
+/**
+ * struct acrn_sbuf_param - Data to register a share buffer by hypercall
+ * @cpu_id: Id of the cpu which own this sbuf.
+ * ACRN_INVALID_CPUID means the sbuf is belong to a VM.
+ * @reserved: Reserved field.
+ * @sbuf_id: Type of the sbuf.
+ * @gpa: physcial address of the sbuf.
+ */
+struct acrn_sbuf_param {
+ __u16 cpu_id;
+ __u16 reserved;
+ __u32 sbuf_id;
+ __u64 gpa;
+};
+
/* The ioctl type, documented in ioctl-number.rst */
#define ACRN_IOCTL_TYPE 0xA2

@@ -658,6 +687,8 @@ struct acrn_irqfd {
_IOW(ACRN_IOCTL_TYPE, 0x41, struct acrn_vm_memmap)
#define ACRN_IOCTL_UNSET_MEMSEG \
_IOW(ACRN_IOCTL_TYPE, 0x42, struct acrn_vm_memmap)
+#define ACRN_IOCTL_SETUP_SBUF \
+ _IOW(ACRN_IOCTL_TYPE, 0x43, struct acrn_sbuf)

#define ACRN_IOCTL_SET_PTDEV_INTR \
_IOW(ACRN_IOCTL_TYPE, 0x53, struct acrn_ptdev_irq)
--
2.25.1


Li, Fei1
 

On 2022-09-13 at 11:29:11 +0800, Conghui Chen wrote:
AsyncIo is a new mechanism in acrn, which is special for these devices
which need high IO performance. acrn hypervisor would process the IO
request from User VM in an async mode.

For this kind of I/O reqeusts, a new share page is created by device
model in userspace, and register to kernel with ioctl. ACRN hsm driver
will pin the page to avoid page swapping. Use hypercall to pass the base
addresses to hypervisor, so that hypervisor can access the page and change
request status.
Please split this patch into:
1) Add Sbuf hypercall
2) Add AsyncIo hypercall
3) Move others into "support asyncio in ioeventfd" and clrify why it needs Sbuf

Signed-off-by: Conghui <conghui.chen@...>
---
change.sh | 18 ++++++++++
drivers/virt/acrn/acrn_drv.h | 8 +++++
drivers/virt/acrn/hsm.c | 8 +++++
drivers/virt/acrn/hypercall.h | 13 +++++++
drivers/virt/acrn/ioreq.c | 28 +++++++++++++++
drivers/virt/acrn/sbuf.c | 65 +++++++++++++++++++++++++++++++++++
drivers/virt/acrn/sbuf.h | 3 ++
drivers/virt/acrn/vm.c | 2 ++
include/uapi/linux/acrn.h | 31 +++++++++++++++++
9 files changed, 176 insertions(+)
create mode 100755 change.sh

diff --git a/change.sh b/change.sh
new file mode 100755
index 000000000000..4946c089ee8a
--- /dev/null
+++ b/change.sh
@@ -0,0 +1,18 @@
+set -x
+
+ip=$1
+linux=$2
+SOS=root@${ip}
+
+echo $linux
+echo $ip
+
+
+ssh $SOS "rm ~/acrn-work/* -r"
+scp $linux ${SOS}:~/acrn-work/
+ssh $SOS "tar -xf ~/acrn-work/${linux} -C ~/acrn-work/"
+ssh $SOS "cp ~/acrn-work/boot/* /boot/"
+ssh $SOS "cp ~/acrn-work/lib/modules/* /lib/modules/ -r"
+ssh $SOS "sync"
+
+
diff --git a/drivers/virt/acrn/acrn_drv.h b/drivers/virt/acrn/acrn_drv.h
index 5663c17ad37c..5532baaaaa62 100644
--- a/drivers/virt/acrn/acrn_drv.h
+++ b/drivers/virt/acrn/acrn_drv.h
@@ -9,6 +9,7 @@
#include <linux/types.h>

#include "hypercall.h"
+#include "sbuf.h"

extern struct miscdevice acrn_dev;

@@ -134,6 +135,7 @@ struct acrn_ioreq_client {
};

#define ACRN_INVALID_VMID (0xffffU)
+#define ACRN_INVALID_CPUID (0xffffU)

#define ACRN_VM_FLAG_DESTROYED 0U
#define ACRN_VM_FLAG_CLEARING_IOREQ 1U
@@ -178,6 +180,10 @@ struct acrn_vm {
struct acrn_ioreq_client *default_client;
struct acrn_io_request_buffer *ioreq_buf;
struct page *ioreq_page;
+
+ shared_buf_t *asyncio_sbuf;
+ struct page *asyncio_page;
+ struct mutex asyncio_lock;
u32 pci_conf_addr;
struct page *monitor_page;
struct mutex ioeventfds_lock;
@@ -201,6 +207,8 @@ void acrn_vm_all_ram_unmap(struct acrn_vm *vm);

int acrn_ioreq_init(struct acrn_vm *vm, u64 buf_vma);
void acrn_ioreq_deinit(struct acrn_vm *vm);
+int acrn_asyncio_init(struct acrn_vm *vm, shared_buf_t *sbuf, struct page *page);
+void acrn_asyncio_deinit(struct acrn_vm *vm);
int acrn_ioreq_intr_setup(void);
void acrn_ioreq_intr_remove(void);
void acrn_ioreq_request_clear(struct acrn_vm *vm);
diff --git a/drivers/virt/acrn/hsm.c b/drivers/virt/acrn/hsm.c
index 423ea888d79a..a71f34a0f53e 100644
--- a/drivers/virt/acrn/hsm.c
+++ b/drivers/virt/acrn/hsm.c
@@ -19,6 +19,7 @@
#include <asm/hypervisor.h>

#include "acrn_drv.h"
+#include "sbuf.h"

/*
* When /dev/acrn_hsm is opened, a 'struct acrn_vm' object is created to
@@ -108,6 +109,7 @@ static long acrn_dev_ioctl(struct file *filp, unsigned int cmd,
unsigned long ioctl_param)
{
struct acrn_vm *vm = filp->private_data;
+ struct acrn_sbuf sbuf_param;
struct acrn_vm_creation *vm_param;
struct acrn_vcpu_regs *cpu_regs;
struct acrn_ioreq_notify notify;
@@ -177,6 +179,12 @@ static long acrn_dev_ioctl(struct file *filp, unsigned int cmd,
case ACRN_IOCTL_DESTROY_VM:
ret = acrn_vm_destroy(vm);
break;
+ case ACRN_IOCTL_SETUP_SBUF:
Would you think it's better to define asyncio special IOCTL ?
+ if (copy_from_user(&sbuf_param, (void __user *)ioctl_param,
+ sizeof(sbuf_param)))
+ return -EFAULT;
+ ret = acrn_sbuf_init(vm, sbuf_param.sbuf_id, sbuf_param.base);
+ break;
case ACRN_IOCTL_SET_VCPU_REGS:
cpu_regs = memdup_user((void __user *)ioctl_param,
sizeof(struct acrn_vcpu_regs));
diff --git a/drivers/virt/acrn/hypercall.h b/drivers/virt/acrn/hypercall.h
index 71d300821a18..4811003289ba 100644
--- a/drivers/virt/acrn/hypercall.h
+++ b/drivers/virt/acrn/hypercall.h
@@ -35,6 +35,7 @@

#define HC_ID_MEM_BASE 0x40UL
#define HC_VM_SET_MEMORY_REGIONS _HC_ID(HC_ID, HC_ID_MEM_BASE + 0x02)
+#define HC_SET_SBUF _HC_ID(HC_ID, HC_ID_MEM_BASE + 0x04)

#define HC_ID_PCI_BASE 0x50UL
#define HC_SET_PTDEV_INTR _HC_ID(HC_ID, HC_ID_PCI_BASE + 0x03)
@@ -175,6 +176,18 @@ static inline long hcall_set_ioreq_buffer(u64 vmid, u64 buffer)
return acrn_hypercall2(HC_SET_IOREQ_BUFFER, vmid, buffer);
}

+/**
+ * hcall_set_asyncio_buffer() - Set up the shared buffer.
+ * @vmid: User VM ID
+ * @buffer: Service VM GPA of the shared buffer
+ *
+ * Return: 0 on success, <0 on failure
+ */
+static inline long hcall_set_sbuf(u64 vmid, u64 buffer)
+{
+ return acrn_hypercall2(HC_SET_SBUF, vmid, buffer);
+}
+
/**
* hcall_notify_req_finish() - Notify ACRN Hypervisor of I/O request completion.
* @vmid: User VM ID
diff --git a/drivers/virt/acrn/ioreq.c b/drivers/virt/acrn/ioreq.c
index d75ab3f66da4..c047771712d1 100644
--- a/drivers/virt/acrn/ioreq.c
+++ b/drivers/virt/acrn/ioreq.c
@@ -633,6 +633,18 @@ int acrn_ioreq_init(struct acrn_vm *vm, u64 buf_vma)
return ret;
}

+int acrn_asyncio_init(struct acrn_vm *vm, shared_buf_t *sbuf, struct page *page)
+{
+ if (!sbuf || !page)
+ return -EEXIST;
+ vm->asyncio_sbuf = sbuf;
+ vm->asyncio_page = page;
+ mutex_init(&vm->asyncio_lock);
+ dev_dbg(acrn_dev.this_device,
+ "Init asyncio buffer %p\n", vm->asyncio_sbuf);
+ return 0;
+}
+
void acrn_ioreq_deinit(struct acrn_vm *vm)
{
struct acrn_ioreq_client *client, *next;
@@ -650,3 +662,19 @@ void acrn_ioreq_deinit(struct acrn_vm *vm)
vm->ioreq_buf = NULL;
}
}
+
+void acrn_asyncio_deinit(struct acrn_vm *vm)
+{
+ if (!vm) {
+ dev_err(acrn_dev.this_device,
+ "Failed to deinit asyncio buffer as vm is null!");
+ return;
+ }
+ dev_dbg(acrn_dev.this_device,
+ "Deinit asyncio buffer 0x%p\n", vm->asyncio_sbuf);
+ if (vm->asyncio_sbuf && vm->asyncio_page) {
+ unpin_user_page(vm->asyncio_page);
+ vm->asyncio_sbuf = NULL;
+ mutex_destroy(&vm->asyncio_lock);
+ }
+}
diff --git a/drivers/virt/acrn/sbuf.c b/drivers/virt/acrn/sbuf.c
index 2fc0149849b5..eb0fded28afd 100644
--- a/drivers/virt/acrn/sbuf.c
+++ b/drivers/virt/acrn/sbuf.c
@@ -48,3 +48,68 @@ void acrn_sbuf_move_next(shared_buf_t *sbuf)
{
sbuf->head = sbuf_next_ptr(sbuf->head, sbuf->ele_size, sbuf->size);
}
+
+int acrn_sbuf_setup(uint32_t vm_id, uint32_t cpu_id, uint32_t sbuf_id, uint64_t gpa)
+{
+ struct acrn_sbuf_param *asp;
+ int ret;
+
+ if (x86_hyper_type != X86_HYPER_ACRN)
+ return -ENODEV;
+
+ asp = kzalloc(sizeof(*asp), GFP_KERNEL);
+ if (!asp)
+ return -ENOMEM;
+ asp->cpu_id = cpu_id;
+ asp->sbuf_id = sbuf_id;
+ asp->gpa = gpa;
+
+ ret = hcall_set_sbuf(vm_id, virt_to_phys(asp));
+ kfree(asp);
+ return ret;
+}
+
+int acrn_sbuf_init(struct acrn_vm *vm, uint32_t sbuf_id, uint64_t base)
+{
+ shared_buf_t *sbuf;
+ struct page *page;
+ int ret;
+
+ switch (sbuf_id) {
+ case ACRN_ASYNCIO:
+ /* asyncio is created per vm, so vm should not be null */
+ ret = pin_user_pages_fast(base, 1,
+ FOLL_WRITE | FOLL_LONGTERM, &page);
+
+ if (unlikely(ret != 1) || !page) {
+ dev_err(acrn_dev.this_device, "Failed to pin asyncio page!\n");
+ return -EFAULT;
+ }
+
+ sbuf = page_address(page);
+ if (sbuf->magic != SBUF_MAGIC || ((sbuf->size + SBUF_HEAD_SIZE) > SBUF_MAX_SIZE)) {
+ dev_err(acrn_dev.this_device, "MAGIC is not correct or size is too large!\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = acrn_asyncio_init(vm, sbuf, page);
+ if (ret < 0) {
+ dev_err(acrn_dev.this_device, "Failed to init asyncio!\n");
+ goto err;
+ }
+ ret = acrn_sbuf_setup(vm->vmid, ACRN_INVALID_CPUID, sbuf_id, page_to_phys(page));
+ break;
+ default:
+ dev_err(acrn_dev.this_device, "sbuf_id %d is not supported!", sbuf_id);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (!ret)
+ return 0;
+
+err:
+ unpin_user_page(page);
+ return ret;
+}
diff --git a/drivers/virt/acrn/sbuf.h b/drivers/virt/acrn/sbuf.h
index e83845a39a37..b39438ae8144 100644
--- a/drivers/virt/acrn/sbuf.h
+++ b/drivers/virt/acrn/sbuf.h
@@ -59,6 +59,9 @@
#include <asm/acrn.h>
#include "acrn_drv.h"

+struct acrn_vm;
+int acrn_sbuf_init(struct acrn_vm *vm, uint32_t sbuf_id, uint64_t base);
+int acrn_sbuf_setup(uint32_t vm_id, uint32_t cpu_id, uint32_t sbuf_id, uint64_t gpa);
void *acrn_sbuf_get_data_ptr(shared_buf_t *sbuf);
void acrn_sbuf_move_next(struct shared_buf *sbuf);
#endif /* SHARED_BUF_H */
diff --git a/drivers/virt/acrn/vm.c b/drivers/virt/acrn/vm.c
index fbc9f1042000..0a7ee8bf6f81 100644
--- a/drivers/virt/acrn/vm.c
+++ b/drivers/virt/acrn/vm.c
@@ -13,6 +13,7 @@
#include <linux/slab.h>

#include "acrn_drv.h"
+#include "sbuf.h"

/* List of VMs */
LIST_HEAD(acrn_vm_list);
@@ -80,6 +81,7 @@ int acrn_vm_destroy(struct acrn_vm *vm)
acrn_ioeventfd_deinit(vm);
acrn_irqfd_deinit(vm);
acrn_ioreq_deinit(vm);
+ acrn_asyncio_deinit(vm);

if (vm->monitor_page) {
put_page(vm->monitor_page);
diff --git a/include/uapi/linux/acrn.h b/include/uapi/linux/acrn.h
index 32f03a85646c..5a0120afa5ef 100644
--- a/include/uapi/linux/acrn.h
+++ b/include/uapi/linux/acrn.h
@@ -487,6 +487,10 @@ struct acrn_vdev {
#define OVERRUN_CNT_EN (1ULL << 0) /* whether overrun counting is enabled */
#define OVERWRITE_EN (1ULL << 1) /* whether overwrite is enabled */

+ enum sbuf_type {
+ ACRN_ASYNCIO = 64,
+};
+
/**
* (sbuf) head + buf (store (ele_num - 1) elements at most)
* buffer empty: tail == head
@@ -617,6 +621,31 @@ struct acrn_irqfd {
struct acrn_msi_entry msi;
};

+/**
+ * struct acrn_sbuf - Data to register a share buffer by ioctl
+ * @sbuf_id: Type of the sbuf.
+ * @base: gva of the sbuf.
+ */
+struct acrn_sbuf {
+ __u32 sbuf_id;
+ __u64 base;
+};
+
+/**
+ * struct acrn_sbuf_param - Data to register a share buffer by hypercall
+ * @cpu_id: Id of the cpu which own this sbuf.
+ * ACRN_INVALID_CPUID means the sbuf is belong to a VM.
+ * @reserved: Reserved field.
+ * @sbuf_id: Type of the sbuf.
+ * @gpa: physcial address of the sbuf.
+ */
+struct acrn_sbuf_param {
+ __u16 cpu_id;
+ __u16 reserved;
+ __u32 sbuf_id;
+ __u64 gpa;
+};
+
/* The ioctl type, documented in ioctl-number.rst */
#define ACRN_IOCTL_TYPE 0xA2

@@ -658,6 +687,8 @@ struct acrn_irqfd {
_IOW(ACRN_IOCTL_TYPE, 0x41, struct acrn_vm_memmap)
#define ACRN_IOCTL_UNSET_MEMSEG \
_IOW(ACRN_IOCTL_TYPE, 0x42, struct acrn_vm_memmap)
+#define ACRN_IOCTL_SETUP_SBUF \
+ _IOW(ACRN_IOCTL_TYPE, 0x43, struct acrn_sbuf)

#define ACRN_IOCTL_SET_PTDEV_INTR \
_IOW(ACRN_IOCTL_TYPE, 0x53, struct acrn_ptdev_irq)
--
2.25.1