Date
1 - 2 of 2
[PATCH v2 1/4] virt: acrn: add new share page for fast I/O
Conghui Chen
Fastio 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@...>
---
drivers/virt/acrn/acrn_drv.h | 10 +++++++
drivers/virt/acrn/hsm.c | 7 +++++
drivers/virt/acrn/hypercall.h | 13 +++++++++
drivers/virt/acrn/ioreq.c | 53 +++++++++++++++++++++++++++++++++++
drivers/virt/acrn/vm.c | 1 +
include/uapi/linux/acrn.h | 27 ++++++++++++++++++
6 files changed, 111 insertions(+)
diff --git a/drivers/virt/acrn/acrn_drv.h b/drivers/virt/acrn/acrn_drv.h
index 106b2f0e6bac..b00b00c76f84 100644
--- a/drivers/virt/acrn/acrn_drv.h
+++ b/drivers/virt/acrn/acrn_drv.h
@@ -91,6 +91,10 @@ struct acrn_ioreq_buffer {
u64 ioreq_buf;
};
+struct acrn_fastio_buffer {
+ u64 fastio_buf;
+};
+
struct acrn_ioreq_range {
struct list_head list;
u32 type;
@@ -176,6 +180,10 @@ struct acrn_vm {
struct acrn_ioreq_client *default_client;
struct acrn_io_request_buffer *ioreq_buf;
struct page *ioreq_page;
+
+ struct acrn_fastio_req_buffer *fastio_buf;
+ struct page *fastio_page;
+ struct mutex fastio_lock;
u32 pci_conf_addr;
struct page *monitor_page;
struct mutex ioeventfds_lock;
@@ -199,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_fastio_init(struct acrn_vm *vm, u64 fastio_base);
+void acrn_fastio_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 acd8e9c9a296..0dadfb3cfeaf 100644
--- a/drivers/virt/acrn/hsm.c
+++ b/drivers/virt/acrn/hsm.c
@@ -121,6 +121,7 @@ static long acrn_dev_ioctl(struct file *filp, unsigned int cmd,
struct acrn_vdev *vdev;
struct page *page;
u64 cstate_cmd;
+ u64 fastio_base;
int i, ret = 0;
if (vm->vmid == ACRN_INVALID_VMID && cmd != ACRN_IOCTL_CREATE_VM) {
@@ -177,6 +178,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_FASTIO_BASE:
+ if (copy_from_user(&fastio_base, (void __user *)ioctl_param,
+ sizeof(fastio_base)))
+ return -EFAULT;
+ ret = acrn_fastio_init(vm, fastio_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 d410cfa16d2e..f30ff01c0bee 100644
--- a/drivers/virt/acrn/hypercall.h
+++ b/drivers/virt/acrn/hypercall.h
@@ -32,6 +32,7 @@
#define HC_ID_IOREQ_BASE 0x30UL
#define HC_SET_IOREQ_BUFFER _HC_ID(HC_ID, HC_ID_IOREQ_BASE + 0x00)
#define HC_NOTIFY_REQUEST_FINISH _HC_ID(HC_ID, HC_ID_IOREQ_BASE + 0x01)
+#define HC_SET_FASTIO_BUFFER _HC_ID(HC_ID, HC_ID_IOREQ_BASE + 0x02)
#define HC_ID_MEM_BASE 0x40UL
#define HC_VM_SET_MEMORY_REGIONS _HC_ID(HC_ID, HC_ID_MEM_BASE + 0x02)
@@ -178,6 +179,18 @@ static inline long hcall_set_ioreq_buffer(u64 vmid, u64 buffer)
return acrn_hypercall2(HC_SET_IOREQ_BUFFER, vmid, buffer);
}
+/**
+ * hcall_set_fastio_buffer() - Set up the shared buffer for fast I/O Requests.
+ * @vmid: User VM ID
+ * @buffer: Service VM GPA of the shared buffer
+ *
+ * Return: 0 on success, <0 on failure
+ */
+static inline long hcall_set_fastio_buffer(u64 vmid, u64 buffer)
+{
+ return acrn_hypercall2(HC_SET_FASTIO_BUFFER, 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 80b2e3f0e276..7821317f4032 100644
--- a/drivers/virt/acrn/ioreq.c
+++ b/drivers/virt/acrn/ioreq.c
@@ -638,6 +638,47 @@ int acrn_ioreq_init(struct acrn_vm *vm, u64 buf_vma)
return ret;
}
+int acrn_fastio_init(struct acrn_vm *vm, u64 fastio_base)
+{
+ struct acrn_fastio_buffer *fastio_buffer;
+ struct page *page;
+ int ret;
+
+ if (vm->fastio_buf)
+ return -EEXIST;
+
+ fastio_buffer = kzalloc(sizeof(*fastio_buffer), GFP_KERNEL);
+ if (!fastio_buffer)
+ return -ENOMEM;
+
+ ret = pin_user_pages_fast(fastio_base, 1,
+ FOLL_WRITE | FOLL_LONGTERM, &page);
+ if (unlikely(ret != 1) || !page) {
+ dev_err(acrn_dev.this_device, "Failed to pin fastio page!\n");
+ ret = -EFAULT;
+ goto free_buf;
+ }
+
+ vm->fastio_buf = page_address(page);
+ vm->fastio_page = page;
+ fastio_buffer->fastio_buf = page_to_phys(page);
+ ret = hcall_set_fastio_buffer(vm->vmid, virt_to_phys(fastio_buffer));
+ if (ret < 0) {
+ dev_err(acrn_dev.this_device, "Failed to init fastio buffer!\n");
+ unpin_user_page(page);
+ vm->fastio_buf = NULL;
+ goto free_buf;
+ }
+
+ mutex_init(&vm->fastio_lock);
+ dev_dbg(acrn_dev.this_device,
+ "Init fastio buffer %p\n", vm->fastio_buf);
+ ret = 0;
+free_buf:
+ kfree(fastio_buffer);
+ return ret;
+}
+
void acrn_ioreq_deinit(struct acrn_vm *vm)
{
struct acrn_ioreq_client *client, *next;
@@ -655,3 +696,15 @@ void acrn_ioreq_deinit(struct acrn_vm *vm)
vm->ioreq_buf = NULL;
}
}
+
+void acrn_fastio_deinit(struct acrn_vm *vm)
+{
+ struct acrn_ioreq_client *client, *next;
+
+ dev_dbg(acrn_dev.this_device,
+ "Deinit fastio buffer 0x%p\n", vm->fastio_buf);
+ if (vm->fastio_buf && vm->fastio_page) {
+ unpin_user_page(vm->fastio_page);
+ vm->fastio_buf = NULL;
+ }
+}
diff --git a/drivers/virt/acrn/vm.c b/drivers/virt/acrn/vm.c
index fbc9f1042000..0a97ec0fdbbb 100644
--- a/drivers/virt/acrn/vm.c
+++ b/drivers/virt/acrn/vm.c
@@ -80,6 +80,7 @@ int acrn_vm_destroy(struct acrn_vm *vm)
acrn_ioeventfd_deinit(vm);
acrn_irqfd_deinit(vm);
acrn_ioreq_deinit(vm);
+ acrn_fastio_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 2b00db2c14bd..255aa4aed4a8 100644
--- a/include/uapi/linux/acrn.h
+++ b/include/uapi/linux/acrn.h
@@ -15,6 +15,7 @@
#include <linux/uuid.h>
#define ACRN_IO_REQUEST_MAX 16
+#define ACRN_FASTIO_REQUEST_MAX 128
#define ACRN_IOREQ_STATE_PENDING 0
#define ACRN_IOREQ_STATE_COMPLETE 1
@@ -168,6 +169,30 @@ struct acrn_io_request_buffer {
};
};
+/**
+ * struct acrn_fastio_request - 32-byte ACRN Fast I/O request
+ * @addr: Base address of the I/O request
+ * @req_nums: The accumulated request numbers.
+ * @processed: The request processed by kernel.
+ * @fd: The eventfd corresponding to the I/O address.
+ * @reserved: Reserved fields.
+ */
+
+struct acrn_fastio_request {
+ __u64 addr;
+ __u32 req_nums;
+ __u32 processed;
+ void *fd;
+ __u64 reserved[1];
+} __attribute__((aligned(32)));
+
+struct acrn_fastio_req_buffer {
+ union {
+ struct acrn_fastio_request req_slot[ACRN_FASTIO_REQUEST_MAX];
+ __u8 reserved[4096];
+ };
+};
+
/**
* struct acrn_ioreq_notify - The structure of ioreq completion notification
* @vmid: User VM ID
@@ -652,5 +677,7 @@ struct sbuf_setup_param {
_IOW(ACRN_IOCTL_TYPE, 0x70, struct acrn_ioeventfd)
#define ACRN_IOCTL_IRQFD \
_IOW(ACRN_IOCTL_TYPE, 0x71, struct acrn_irqfd)
+#define ACRN_IOCTL_SETUP_FASTIO_BASE \
+ _IOW(ACRN_IOCTL_TYPE, 0x72, __u64)
#endif /* _UAPI_ACRN_H */
--
2.25.1
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@...>
---
drivers/virt/acrn/acrn_drv.h | 10 +++++++
drivers/virt/acrn/hsm.c | 7 +++++
drivers/virt/acrn/hypercall.h | 13 +++++++++
drivers/virt/acrn/ioreq.c | 53 +++++++++++++++++++++++++++++++++++
drivers/virt/acrn/vm.c | 1 +
include/uapi/linux/acrn.h | 27 ++++++++++++++++++
6 files changed, 111 insertions(+)
diff --git a/drivers/virt/acrn/acrn_drv.h b/drivers/virt/acrn/acrn_drv.h
index 106b2f0e6bac..b00b00c76f84 100644
--- a/drivers/virt/acrn/acrn_drv.h
+++ b/drivers/virt/acrn/acrn_drv.h
@@ -91,6 +91,10 @@ struct acrn_ioreq_buffer {
u64 ioreq_buf;
};
+struct acrn_fastio_buffer {
+ u64 fastio_buf;
+};
+
struct acrn_ioreq_range {
struct list_head list;
u32 type;
@@ -176,6 +180,10 @@ struct acrn_vm {
struct acrn_ioreq_client *default_client;
struct acrn_io_request_buffer *ioreq_buf;
struct page *ioreq_page;
+
+ struct acrn_fastio_req_buffer *fastio_buf;
+ struct page *fastio_page;
+ struct mutex fastio_lock;
u32 pci_conf_addr;
struct page *monitor_page;
struct mutex ioeventfds_lock;
@@ -199,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_fastio_init(struct acrn_vm *vm, u64 fastio_base);
+void acrn_fastio_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 acd8e9c9a296..0dadfb3cfeaf 100644
--- a/drivers/virt/acrn/hsm.c
+++ b/drivers/virt/acrn/hsm.c
@@ -121,6 +121,7 @@ static long acrn_dev_ioctl(struct file *filp, unsigned int cmd,
struct acrn_vdev *vdev;
struct page *page;
u64 cstate_cmd;
+ u64 fastio_base;
int i, ret = 0;
if (vm->vmid == ACRN_INVALID_VMID && cmd != ACRN_IOCTL_CREATE_VM) {
@@ -177,6 +178,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_FASTIO_BASE:
+ if (copy_from_user(&fastio_base, (void __user *)ioctl_param,
+ sizeof(fastio_base)))
+ return -EFAULT;
+ ret = acrn_fastio_init(vm, fastio_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 d410cfa16d2e..f30ff01c0bee 100644
--- a/drivers/virt/acrn/hypercall.h
+++ b/drivers/virt/acrn/hypercall.h
@@ -32,6 +32,7 @@
#define HC_ID_IOREQ_BASE 0x30UL
#define HC_SET_IOREQ_BUFFER _HC_ID(HC_ID, HC_ID_IOREQ_BASE + 0x00)
#define HC_NOTIFY_REQUEST_FINISH _HC_ID(HC_ID, HC_ID_IOREQ_BASE + 0x01)
+#define HC_SET_FASTIO_BUFFER _HC_ID(HC_ID, HC_ID_IOREQ_BASE + 0x02)
#define HC_ID_MEM_BASE 0x40UL
#define HC_VM_SET_MEMORY_REGIONS _HC_ID(HC_ID, HC_ID_MEM_BASE + 0x02)
@@ -178,6 +179,18 @@ static inline long hcall_set_ioreq_buffer(u64 vmid, u64 buffer)
return acrn_hypercall2(HC_SET_IOREQ_BUFFER, vmid, buffer);
}
+/**
+ * hcall_set_fastio_buffer() - Set up the shared buffer for fast I/O Requests.
+ * @vmid: User VM ID
+ * @buffer: Service VM GPA of the shared buffer
+ *
+ * Return: 0 on success, <0 on failure
+ */
+static inline long hcall_set_fastio_buffer(u64 vmid, u64 buffer)
+{
+ return acrn_hypercall2(HC_SET_FASTIO_BUFFER, 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 80b2e3f0e276..7821317f4032 100644
--- a/drivers/virt/acrn/ioreq.c
+++ b/drivers/virt/acrn/ioreq.c
@@ -638,6 +638,47 @@ int acrn_ioreq_init(struct acrn_vm *vm, u64 buf_vma)
return ret;
}
+int acrn_fastio_init(struct acrn_vm *vm, u64 fastio_base)
+{
+ struct acrn_fastio_buffer *fastio_buffer;
+ struct page *page;
+ int ret;
+
+ if (vm->fastio_buf)
+ return -EEXIST;
+
+ fastio_buffer = kzalloc(sizeof(*fastio_buffer), GFP_KERNEL);
+ if (!fastio_buffer)
+ return -ENOMEM;
+
+ ret = pin_user_pages_fast(fastio_base, 1,
+ FOLL_WRITE | FOLL_LONGTERM, &page);
+ if (unlikely(ret != 1) || !page) {
+ dev_err(acrn_dev.this_device, "Failed to pin fastio page!\n");
+ ret = -EFAULT;
+ goto free_buf;
+ }
+
+ vm->fastio_buf = page_address(page);
+ vm->fastio_page = page;
+ fastio_buffer->fastio_buf = page_to_phys(page);
+ ret = hcall_set_fastio_buffer(vm->vmid, virt_to_phys(fastio_buffer));
+ if (ret < 0) {
+ dev_err(acrn_dev.this_device, "Failed to init fastio buffer!\n");
+ unpin_user_page(page);
+ vm->fastio_buf = NULL;
+ goto free_buf;
+ }
+
+ mutex_init(&vm->fastio_lock);
+ dev_dbg(acrn_dev.this_device,
+ "Init fastio buffer %p\n", vm->fastio_buf);
+ ret = 0;
+free_buf:
+ kfree(fastio_buffer);
+ return ret;
+}
+
void acrn_ioreq_deinit(struct acrn_vm *vm)
{
struct acrn_ioreq_client *client, *next;
@@ -655,3 +696,15 @@ void acrn_ioreq_deinit(struct acrn_vm *vm)
vm->ioreq_buf = NULL;
}
}
+
+void acrn_fastio_deinit(struct acrn_vm *vm)
+{
+ struct acrn_ioreq_client *client, *next;
+
+ dev_dbg(acrn_dev.this_device,
+ "Deinit fastio buffer 0x%p\n", vm->fastio_buf);
+ if (vm->fastio_buf && vm->fastio_page) {
+ unpin_user_page(vm->fastio_page);
+ vm->fastio_buf = NULL;
+ }
+}
diff --git a/drivers/virt/acrn/vm.c b/drivers/virt/acrn/vm.c
index fbc9f1042000..0a97ec0fdbbb 100644
--- a/drivers/virt/acrn/vm.c
+++ b/drivers/virt/acrn/vm.c
@@ -80,6 +80,7 @@ int acrn_vm_destroy(struct acrn_vm *vm)
acrn_ioeventfd_deinit(vm);
acrn_irqfd_deinit(vm);
acrn_ioreq_deinit(vm);
+ acrn_fastio_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 2b00db2c14bd..255aa4aed4a8 100644
--- a/include/uapi/linux/acrn.h
+++ b/include/uapi/linux/acrn.h
@@ -15,6 +15,7 @@
#include <linux/uuid.h>
#define ACRN_IO_REQUEST_MAX 16
+#define ACRN_FASTIO_REQUEST_MAX 128
#define ACRN_IOREQ_STATE_PENDING 0
#define ACRN_IOREQ_STATE_COMPLETE 1
@@ -168,6 +169,30 @@ struct acrn_io_request_buffer {
};
};
+/**
+ * struct acrn_fastio_request - 32-byte ACRN Fast I/O request
+ * @addr: Base address of the I/O request
+ * @req_nums: The accumulated request numbers.
+ * @processed: The request processed by kernel.
+ * @fd: The eventfd corresponding to the I/O address.
+ * @reserved: Reserved fields.
+ */
+
+struct acrn_fastio_request {
+ __u64 addr;
+ __u32 req_nums;
+ __u32 processed;
+ void *fd;
+ __u64 reserved[1];
+} __attribute__((aligned(32)));
+
+struct acrn_fastio_req_buffer {
+ union {
+ struct acrn_fastio_request req_slot[ACRN_FASTIO_REQUEST_MAX];
+ __u8 reserved[4096];
+ };
+};
+
/**
* struct acrn_ioreq_notify - The structure of ioreq completion notification
* @vmid: User VM ID
@@ -652,5 +677,7 @@ struct sbuf_setup_param {
_IOW(ACRN_IOCTL_TYPE, 0x70, struct acrn_ioeventfd)
#define ACRN_IOCTL_IRQFD \
_IOW(ACRN_IOCTL_TYPE, 0x71, struct acrn_irqfd)
+#define ACRN_IOCTL_SETUP_FASTIO_BASE \
+ _IOW(ACRN_IOCTL_TYPE, 0x72, __u64)
#endif /* _UAPI_ACRN_H */
--
2.25.1
toggle quoted message
Show quoted text
If we go w/ a new page for asynchronous io_req, I suggest we use a ring descriptor with head and tail register, rather than a static array + bitmap inidicator.
BTW, why you call it fastio? Is there any evidence for the name ? How Other hypervisor/VMM call it? TO me, it is an asynchronous IO or a notification event. The later one is more accurate.
-----Original Message-----After 2nd thinking. I am fine with either choices: reusing the existing io_req slot, or add a new page for asynchronous io_req. It depends on how the Linux kernel side change may be accepted by community.
From: acrn-dev@... <acrn-dev@...> On
Behalf Of Conghui Chen
Sent: Tuesday, August 16, 2022 11:00 PM
To: acrn-dev@...
Cc: Li, Fei1 <fei1.li@...>; Wang, Yu1 <yu1.wang@...>; Chen,
Conghui <conghui.chen@...>
Subject: [acrn-dev] [PATCH v2 1/4] virt: acrn: add new share page for fast I/O
Fastio 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@...>
---
drivers/virt/acrn/acrn_drv.h | 10 +++++++
drivers/virt/acrn/hsm.c | 7 +++++
drivers/virt/acrn/hypercall.h | 13 +++++++++
drivers/virt/acrn/ioreq.c | 53 +++++++++++++++++++++++++++++++++++
drivers/virt/acrn/vm.c | 1 +
include/uapi/linux/acrn.h | 27 ++++++++++++++++++
6 files changed, 111 insertions(+)
diff --git a/drivers/virt/acrn/acrn_drv.h b/drivers/virt/acrn/acrn_drv.h index
106b2f0e6bac..b00b00c76f84 100644
--- a/drivers/virt/acrn/acrn_drv.h
+++ b/drivers/virt/acrn/acrn_drv.h
@@ -91,6 +91,10 @@ struct acrn_ioreq_buffer {
u64 ioreq_buf;
};
+struct acrn_fastio_buffer {
+ u64 fastio_buf;
+};
+
struct acrn_ioreq_range {
struct list_head list;
u32 type;
@@ -176,6 +180,10 @@ struct acrn_vm {
struct acrn_ioreq_client *default_client;
struct acrn_io_request_buffer *ioreq_buf;
struct page *ioreq_page;
+
+ struct acrn_fastio_req_buffer *fastio_buf;
+ struct page *fastio_page;
+ struct mutex fastio_lock;
u32 pci_conf_addr;
struct page *monitor_page;
struct mutex ioeventfds_lock;
@@ -199,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_fastio_init(struct acrn_vm *vm, u64 fastio_base); void
+acrn_fastio_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
acd8e9c9a296..0dadfb3cfeaf 100644
--- a/drivers/virt/acrn/hsm.c
+++ b/drivers/virt/acrn/hsm.c
@@ -121,6 +121,7 @@ static long acrn_dev_ioctl(struct file *filp, unsigned int
cmd,
struct acrn_vdev *vdev;
struct page *page;
u64 cstate_cmd;
+ u64 fastio_base;
int i, ret = 0;
if (vm->vmid == ACRN_INVALID_VMID && cmd !=
ACRN_IOCTL_CREATE_VM) { @@ -177,6 +178,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_FASTIO_BASE:
+ if (copy_from_user(&fastio_base, (void __user *)ioctl_param,
+ sizeof(fastio_base)))
+ return -EFAULT;
+ ret = acrn_fastio_init(vm, fastio_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
d410cfa16d2e..f30ff01c0bee 100644
--- a/drivers/virt/acrn/hypercall.h
+++ b/drivers/virt/acrn/hypercall.h
@@ -32,6 +32,7 @@
#define HC_ID_IOREQ_BASE 0x30UL
#define HC_SET_IOREQ_BUFFER _HC_ID(HC_ID, HC_ID_IOREQ_BASE
+ 0x00)
#define HC_NOTIFY_REQUEST_FINISH _HC_ID(HC_ID, HC_ID_IOREQ_BASE
+ 0x01)
+#define HC_SET_FASTIO_BUFFER _HC_ID(HC_ID,
HC_ID_IOREQ_BASE + 0x02)
#define HC_ID_MEM_BASE 0x40UL
#define HC_VM_SET_MEMORY_REGIONS _HC_ID(HC_ID,
HC_ID_MEM_BASE + 0x02)
@@ -178,6 +179,18 @@ static inline long hcall_set_ioreq_buffer(u64 vmid,
u64 buffer)
return acrn_hypercall2(HC_SET_IOREQ_BUFFER, vmid, buffer); }
+/**
+ * hcall_set_fastio_buffer() - Set up the shared buffer for fast I/O Requests.
+ * @vmid: User VM ID
+ * @buffer: Service VM GPA of the shared buffer
+ *
+ * Return: 0 on success, <0 on failure
+ */
+static inline long hcall_set_fastio_buffer(u64 vmid, u64 buffer) {
+ return acrn_hypercall2(HC_SET_FASTIO_BUFFER, 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
80b2e3f0e276..7821317f4032 100644
--- a/drivers/virt/acrn/ioreq.c
+++ b/drivers/virt/acrn/ioreq.c
@@ -638,6 +638,47 @@ int acrn_ioreq_init(struct acrn_vm *vm, u64 buf_vma)
return ret;
}
+int acrn_fastio_init(struct acrn_vm *vm, u64 fastio_base) {
+ struct acrn_fastio_buffer *fastio_buffer;
+ struct page *page;
+ int ret;
+
+ if (vm->fastio_buf)
+ return -EEXIST;
+
+ fastio_buffer = kzalloc(sizeof(*fastio_buffer), GFP_KERNEL);
+ if (!fastio_buffer)
+ return -ENOMEM;
+
+ ret = pin_user_pages_fast(fastio_base, 1,
+ FOLL_WRITE | FOLL_LONGTERM, &page);
+ if (unlikely(ret != 1) || !page) {
+ dev_err(acrn_dev.this_device, "Failed to pin fastio page!\n");
+ ret = -EFAULT;
+ goto free_buf;
+ }
+
+ vm->fastio_buf = page_address(page);
+ vm->fastio_page = page;
+ fastio_buffer->fastio_buf = page_to_phys(page);
+ ret = hcall_set_fastio_buffer(vm->vmid, virt_to_phys(fastio_buffer));
+ if (ret < 0) {
+ dev_err(acrn_dev.this_device, "Failed to init fastio buffer!\n");
+ unpin_user_page(page);
+ vm->fastio_buf = NULL;
+ goto free_buf;
+ }
+
+ mutex_init(&vm->fastio_lock);
+ dev_dbg(acrn_dev.this_device,
+ "Init fastio buffer %p\n", vm->fastio_buf);
+ ret = 0;
+free_buf:
+ kfree(fastio_buffer);
+ return ret;
+}
+
void acrn_ioreq_deinit(struct acrn_vm *vm) {
struct acrn_ioreq_client *client, *next; @@ -655,3 +696,15 @@ void
acrn_ioreq_deinit(struct acrn_vm *vm)
vm->ioreq_buf = NULL;
}
}
+
+void acrn_fastio_deinit(struct acrn_vm *vm) {
+ struct acrn_ioreq_client *client, *next;
+
+ dev_dbg(acrn_dev.this_device,
+ "Deinit fastio buffer 0x%p\n", vm->fastio_buf);
+ if (vm->fastio_buf && vm->fastio_page) {
+ unpin_user_page(vm->fastio_page);
+ vm->fastio_buf = NULL;
+ }
+}
diff --git a/drivers/virt/acrn/vm.c b/drivers/virt/acrn/vm.c index
fbc9f1042000..0a97ec0fdbbb 100644
--- a/drivers/virt/acrn/vm.c
+++ b/drivers/virt/acrn/vm.c
@@ -80,6 +80,7 @@ int acrn_vm_destroy(struct acrn_vm *vm)
acrn_ioeventfd_deinit(vm);
acrn_irqfd_deinit(vm);
acrn_ioreq_deinit(vm);
+ acrn_fastio_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
2b00db2c14bd..255aa4aed4a8 100644
--- a/include/uapi/linux/acrn.h
+++ b/include/uapi/linux/acrn.h
@@ -15,6 +15,7 @@
#include <linux/uuid.h>
#define ACRN_IO_REQUEST_MAX 16
+#define ACRN_FASTIO_REQUEST_MAX 128
#define ACRN_IOREQ_STATE_PENDING 0
#define ACRN_IOREQ_STATE_COMPLETE 1
@@ -168,6 +169,30 @@ struct acrn_io_request_buffer {
};
};
+/**
+ * struct acrn_fastio_request - 32-byte ACRN Fast I/O request
+ * @addr: Base address of the I/O request
+ * @req_nums: The accumulated request numbers.
+ * @processed: The request processed by kernel.
+ * @fd: The eventfd corresponding to the I/O address.
+ * @reserved: Reserved fields.
+ */
+
+struct acrn_fastio_request {
+ __u64 addr;
+ __u32 req_nums;
+ __u32 processed;
+ void *fd;
+ __u64 reserved[1];
+} __attribute__((aligned(32)));
+
+struct acrn_fastio_req_buffer {
+ union {
+ struct acrn_fastio_request
req_slot[ACRN_FASTIO_REQUEST_MAX];
+ __u8 reserved[4096];
+ };
+};
If we go w/ a new page for asynchronous io_req, I suggest we use a ring descriptor with head and tail register, rather than a static array + bitmap inidicator.
BTW, why you call it fastio? Is there any evidence for the name ? How Other hypervisor/VMM call it? TO me, it is an asynchronous IO or a notification event. The later one is more accurate.
+
/**
* struct acrn_ioreq_notify - The structure of ioreq completion notification
* @vmid: User VM ID
@@ -652,5 +677,7 @@ struct sbuf_setup_param {
_IOW(ACRN_IOCTL_TYPE, 0x70, struct acrn_ioeventfd)
#define ACRN_IOCTL_IRQFD \
_IOW(ACRN_IOCTL_TYPE, 0x71, struct acrn_irqfd)
+#define ACRN_IOCTL_SETUP_FASTIO_BASE \
+ _IOW(ACRN_IOCTL_TYPE, 0x72, __u64)
#endif /* _UAPI_ACRN_H */
--
2.25.1