From 6bdb50ad99d8bdd37c2817f2518410cc7a754331 Mon Sep 17 00:00:00 2001 From: Raghavendra Rao Ananta Date: Tue, 24 Mar 2020 07:24:08 -0700 Subject: [PATCH 1/4] haven: hh_msgq: Let clients manage the buffers for hh_msgq_recv Currently, the hh_msgq driver allocates the receive-buffer on behalf of the clients and it's the clients' responsibility to free it. However, this creates asymmetry in the buffer management and may lead to confusion. Hence, let the clients take full control of the buffers- allocation and freeing. Also make changes to the client driver to adapt to the new hh_msgq_recv interface. Change-Id: I95b72621ede5e62411e78e45c36d8a7ff3686bd4 Signed-off-by: Raghavendra Rao Ananta Signed-off-by: Murali Nalajala --- drivers/soc/qcom/mem-buf.c | 13 ++++++-- drivers/virt/haven/hh_msgq.c | 54 +++++++++++++++------------------ drivers/virt/haven/hh_rm_core.c | 9 +++++- include/linux/haven/hh_msgq.h | 3 +- 4 files changed, 44 insertions(+), 35 deletions(-) diff --git a/drivers/soc/qcom/mem-buf.c b/drivers/soc/qcom/mem-buf.c index ad7beba7a815..b921870babf8 100644 --- a/drivers/soc/qcom/mem-buf.c +++ b/drivers/soc/qcom/mem-buf.c @@ -786,12 +786,19 @@ static int mem_buf_msgq_recv_fn(void *unused) int ret; while (!kthread_should_stop()) { - ret = hh_msgq_recv(mem_buf_hh_msgq_hdl, &buf, &size, 0); - if (ret < 0) + buf = kzalloc(HH_MSGQ_MAX_MSG_SIZE_BYTES, GFP_KERNEL); + if (!buf) + continue; + + ret = hh_msgq_recv(mem_buf_hh_msgq_hdl, buf, + HH_MSGQ_MAX_MSG_SIZE_BYTES, &size, 0); + if (ret < 0) { + kfree(buf); pr_err_ratelimited("%s failed to receive message rc: %d\n", __func__, ret); - else + } else { mem_buf_process_msg(buf, size); + } } return 0; diff --git a/drivers/virt/haven/hh_msgq.c b/drivers/virt/haven/hh_msgq.c index 575f8211bc81..34a899d80805 100644 --- a/drivers/virt/haven/hh_msgq.c +++ b/drivers/virt/haven/hh_msgq.c @@ -71,7 +71,8 @@ static irqreturn_t hh_msgq_tx_isr(int irq, void *dev) } static int __hh_msgq_recv(struct hh_msgq_cap_table *cap_table_entry, - void *buff, size_t *size, u64 rx_flags) + void *buff, size_t buff_size, + size_t *recv_size, u64 rx_flags) { struct hh_hcall_msgq_recv_resp resp = {}; unsigned long flags; @@ -83,11 +84,11 @@ static int __hh_msgq_recv(struct hh_msgq_cap_table *cap_table_entry, spin_lock_irqsave(&cap_table_entry->rx_lock, flags); hh_ret = hh_hcall_msgq_recv(cap_table_entry->rx_cap_id, buff, - HH_MSGQ_MAX_MSG_SIZE_BYTES, &resp); + buff_size, &resp); switch (hh_ret) { case HH_ERROR_OK: - *size = resp.recv_size; + *recv_size = resp.recv_size; ret = 0; break; case HH_ERROR_MSGQUEUE_EMPTY: @@ -110,30 +111,36 @@ static int __hh_msgq_recv(struct hh_msgq_cap_table *cap_table_entry, /** * hh_msgq_recv: Receive a message from the client running on a different VM * @client_desc: The client descriptor that was obtained via hh_msgq_register() - * @buff: Pointer to the buffer where the received data must be placed. Note - * that the caller is responsible to free the data contained in buff - * @size: The size of the buffer received + * @buff: Pointer to the buffer where the received data must be placed + * @buff_size: The size of the buffer space available + * @recv_size: The actual amount of data that is copied into buff * @flags: Optional flags to pass to receive the data. For the list of flags, * see linux/haven/hh_msgq.h * - * The function returns -EINVAL if the caller passes invalid arguments, -EAGAIN + * The function returns 0 if the data is successfully received and recv_size + * would contain the actual amount of data copied into buff. + * It returns -EINVAL if the caller passes invalid arguments, -EAGAIN * if the message queue is not yet ready to communicate, and -EPERM if the - * caller doesn't have permissions to receive the data. 0 is the data is - * successfully received. + * caller doesn't have permissions to receive the data. In all these failure + * cases, recv_size is unmodified. * * Note: this function may sleep and should not be called from interrupt * context */ int hh_msgq_recv(void *msgq_client_desc, - void **buff, size_t *size, unsigned long flags) + void *buff, size_t buff_size, + size_t *recv_size, unsigned long flags) { struct hh_msgq_desc *client_desc = msgq_client_desc; struct hh_msgq_cap_table *cap_table_entry; int ret; - if (!client_desc || !(*buff) || !size) + if (!client_desc || !buff || !buff_size || !recv_size) return -EINVAL; + if (buff_size > HH_MSGQ_MAX_MSG_SIZE_BYTES) + return -E2BIG; + cap_table_entry = &hh_msgq_cap_table[client_desc->label]; spin_lock(&cap_table_entry->cap_entry_lock); @@ -170,31 +177,18 @@ int hh_msgq_recv(void *msgq_client_desc, spin_unlock(&cap_table_entry->cap_entry_lock); - *buff = kzalloc(HH_MSGQ_MAX_MSG_SIZE_BYTES, GFP_KERNEL); - if (!(*buff)) - return -ENOMEM; - do { - if (cap_table_entry->rx_empty && (flags & HH_MSGQ_NONBLOCK)) { - ret = -EAGAIN; - goto buff_free; - } + if (cap_table_entry->rx_empty && (flags & HH_MSGQ_NONBLOCK)) + return -EAGAIN; if (wait_event_interruptible(cap_table_entry->rx_wq, - !cap_table_entry->rx_empty)) { - ret = -ERESTARTSYS; - goto buff_free; - } + !cap_table_entry->rx_empty)) + return -ERESTARTSYS; - ret = __hh_msgq_recv(cap_table_entry, *buff, size, flags); + ret = __hh_msgq_recv(cap_table_entry, buff, buff_size, + recv_size, flags); } while (ret == -EAGAIN); -buff_free: - if (ret < 0) { - kfree(*buff); - *buff = NULL; - } - return ret; err: diff --git a/drivers/virt/haven/hh_rm_core.c b/drivers/virt/haven/hh_rm_core.c index d0c7db026dff..823b4da580b0 100644 --- a/drivers/virt/haven/hh_rm_core.c +++ b/drivers/virt/haven/hh_rm_core.c @@ -417,6 +417,7 @@ static void hh_rm_process_recv_work(struct work_struct *work) * to release the original packet that arrived. */ kfree(recv_buff); + kfree(msgq_data); } static int hh_rm_recv_task_fn(void *data) @@ -427,12 +428,18 @@ static int hh_rm_recv_task_fn(void *data) int ret; while (!kthread_should_stop()) { + recv_buff = kzalloc(HH_MSGQ_MAX_MSG_SIZE_BYTES, GFP_KERNEL); + if (!recv_buff) + continue; + /* Block until a new message is received */ - ret = hh_msgq_recv(hh_rm_msgq_desc, &recv_buff, + ret = hh_msgq_recv(hh_rm_msgq_desc, recv_buff, + HH_MSGQ_MAX_MSG_SIZE_BYTES, &recv_buff_size, 0); if (ret < 0) { pr_err("%s: Failed to receive the message: %d\n", __func__, ret); + kfree(recv_buff); continue; } else if (recv_buff_size <= sizeof(struct hh_rm_rpc_hdr)) { pr_err("%s: Invalid message size received\n", __func__); diff --git a/include/linux/haven/hh_msgq.h b/include/linux/haven/hh_msgq.h index 7990a61b8ec2..59bacd7decc3 100644 --- a/include/linux/haven/hh_msgq.h +++ b/include/linux/haven/hh_msgq.h @@ -31,7 +31,8 @@ int hh_msgq_unregister(void *msgq_client_desc); int hh_msgq_send(void *msgq_client_desc, void *buff, size_t size, unsigned long flags); int hh_msgq_recv(void *msgq_client_desc, - void **buff, size_t *size, unsigned long flags); + void *buff, size_t buff_size, + size_t *recv_size, unsigned long flags); int hh_msgq_populate_cap_info(enum hh_msgq_label label, u64 cap_id, int direction, int irq); From 51047f5ec8e26bd4cf7a6e3c1bded4670fb27312 Mon Sep 17 00:00:00 2001 From: Elliot Berman Date: Tue, 17 Mar 2020 11:03:03 -0700 Subject: [PATCH 2/4] arch: arm64: hh: Clobber x18 if SCS isn't enabled If SCS isn't enabled, then x18 should be considered clobbered by a Haven hypercall. Change-Id: I885e44a8bacc7f045f45df4e88fd04626e0baf41 Signed-off-by: Elliot Berman --- arch/arm64/include/asm/haven/hcall.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/include/asm/haven/hcall.h b/arch/arm64/include/asm/haven/hcall.h index 3bf89c558041..da07887c0818 100644 --- a/arch/arm64/include/asm/haven/hcall.h +++ b/arch/arm64/include/asm/haven/hcall.h @@ -31,14 +31,21 @@ static inline int _hh_hcall(const hh_hcall_fnid_t hcall_num, register uint64_t _x7 asm("x7") = args.arg7; asm volatile ( +#if IS_ENABLED(CONFIG_SHADOW_CALL_STACK) "str x18, [%[_x18]]\n" +#endif "hvc %[num]\n" +#if IS_ENABLED(CONFIG_SHADOW_CALL_STACK) "ldr x18, [%[_x18]]\n" "str xzr, [%[_x18]]\n" +#endif : "+r"(_x0), "+r"(_x1), "+r"(_x2), "+r"(_x3), "+r"(_x4), "+r"(_x5), "+r"(_x6), "+r"(_x7) : [num] "i" (hcall_num), [_x18] "r"(&_x18) : "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", +#if !IS_ENABLED(CONFIG_SHADOW_CALL_STACK) + "x18", +#endif "memory" ); From aff0badb4f2ace3fd6e5d3c5781f3e951ee21b34 Mon Sep 17 00:00:00 2001 From: Elliot Berman Date: Tue, 17 Mar 2020 11:16:57 -0700 Subject: [PATCH 3/4] haven: rm: Clean VM Services - Console APIs Standard replies are handled by hh_rm_call() and not by client driver. Thus, clean console APIs to handle hh_rm_call() response accordingly. Change-Id: I9bc49f15e33260a5fe539b141e311fa071e49211 Signed-off-by: Elliot Berman --- drivers/virt/haven/hh_rm_drv_private.h | 8 -- drivers/virt/haven/hh_rm_iface.c | 136 +++++++++++++------------ 2 files changed, 73 insertions(+), 71 deletions(-) diff --git a/drivers/virt/haven/hh_rm_drv_private.h b/drivers/virt/haven/hh_rm_drv_private.h index b71d59353559..8f68668630c8 100644 --- a/drivers/virt/haven/hh_rm_drv_private.h +++ b/drivers/virt/haven/hh_rm_drv_private.h @@ -118,10 +118,6 @@ struct hh_vm_console_common_req_payload { u32 reserved0; } __packed; -struct hh_vm_console_common_resp_payload { - u32 response; -} __packed; - /* Call: CONSOLE_WRITE */ struct hh_vm_console_write_req_payload { u32 vmid; @@ -129,10 +125,6 @@ struct hh_vm_console_write_req_payload { u8 data[0]; } __packed; -struct hh_vm_console_write_resp_payload { - u32 response; -} __packed; - /* Message ID headers */ /* Call: VM_GET_HYP_RESOURCES */ #define HH_RM_RES_TYPE_DB_TX 0 diff --git a/drivers/virt/haven/hh_rm_iface.c b/drivers/virt/haven/hh_rm_iface.c index 4d155bf971fc..619145389cac 100644 --- a/drivers/virt/haven/hh_rm_iface.c +++ b/drivers/virt/haven/hh_rm_iface.c @@ -426,33 +426,35 @@ EXPORT_SYMBOL(hh_rm_vm_start); */ int hh_rm_console_open(hh_vmid_t vmid) { - struct hh_vm_console_common_resp_payload *resp_payload; + void *resp; struct hh_vm_console_common_req_payload req_payload = {0}; size_t resp_payload_size; - int err = 0, reply_err_code = 0; + int reply_err_code = 0; req_payload.vmid = vmid; - resp_payload = hh_rm_call(HH_RM_RPC_MSG_ID_CALL_VM_CONSOLE_OPEN, - &req_payload, sizeof(req_payload), - &resp_payload_size, &reply_err_code); - if (reply_err_code || IS_ERR_OR_NULL(resp_payload)) { - err = PTR_ERR(resp_payload); - pr_err("%s: CONSOLE_OPEN failed with err: %d\n", - __func__, err); - goto out; + resp = hh_rm_call(HH_RM_RPC_MSG_ID_CALL_VM_CONSOLE_OPEN, + &req_payload, sizeof(req_payload), + &resp_payload_size, &reply_err_code); + if (IS_ERR(resp)) { + pr_err("%s: Unable to send CONSOLE_OPEN to RM: %d\n", __func__, + PTR_ERR(resp)); + return PTR_ERR(resp); } - if (resp_payload_size != sizeof(*resp_payload)) { + if (reply_err_code) { + pr_err("%s: CONSOLE_OPEN returned error: %d\n", __func__, + reply_err_code); + return reply_err_code; + } + + if (resp_payload_size) { pr_err("%s: Invalid size received for CONSOLE_OPEN: %u\n", __func__, resp_payload_size); - err = -EINVAL; + return -EINVAL; } - err = err ? : resp_payload->response; - kfree(resp_payload); -out: - return err; + return 0; } EXPORT_SYMBOL(hh_rm_console_open); @@ -462,33 +464,35 @@ EXPORT_SYMBOL(hh_rm_console_open); */ int hh_rm_console_close(hh_vmid_t vmid) { - struct hh_vm_console_common_resp_payload *resp_payload; + void *resp; struct hh_vm_console_common_req_payload req_payload = {0}; size_t resp_payload_size; - int err = 0, reply_err_code = 0; + int reply_err_code = 0; req_payload.vmid = vmid; - resp_payload = hh_rm_call(HH_RM_RPC_MSG_ID_CALL_VM_CONSOLE_CLOSE, - &req_payload, sizeof(req_payload), - &resp_payload_size, &reply_err_code); - if (reply_err_code || IS_ERR_OR_NULL(resp_payload)) { - err = PTR_ERR(resp_payload); - pr_err("%s: CONSOLE_CLOSE failed with err: %d\n", - __func__, err); - goto out; + resp = hh_rm_call(HH_RM_RPC_MSG_ID_CALL_VM_CONSOLE_CLOSE, + &req_payload, sizeof(req_payload), + &resp_payload_size, &reply_err_code); + if (IS_ERR(resp)) { + pr_err("%s: Unable to send CONSOLE_CLOSE to RM: %d\n", __func__, + PTR_ERR(resp)); + return PTR_ERR(resp); } - if (resp_payload_size != sizeof(*resp_payload)) { + if (reply_err_code) { + pr_err("%s: CONSOLE_CLOSE returned error: %d\n", __func__, + reply_err_code); + return reply_err_code; + } + + if (resp_payload_size) { pr_err("%s: Invalid size received for CONSOLE_CLOSE: %u\n", __func__, resp_payload_size); - err = -EINVAL; + return -EINVAL; } - err = err ? : resp_payload->response; - kfree(resp_payload); -out: - return err; + return 0; } EXPORT_SYMBOL(hh_rm_console_close); @@ -500,10 +504,10 @@ EXPORT_SYMBOL(hh_rm_console_close); */ int hh_rm_console_write(hh_vmid_t vmid, const char *buf, size_t size) { - struct hh_vm_console_write_resp_payload *resp_payload; + void *resp; struct hh_vm_console_write_req_payload *req_payload; size_t resp_payload_size; - int err = 0, reply_err_code = 0; + int reply_err_code = 0; size_t req_payload_size = sizeof(*req_payload) + size; if (size < 1 || size > U32_MAX) @@ -518,27 +522,30 @@ int hh_rm_console_write(hh_vmid_t vmid, const char *buf, size_t size) req_payload->num_bytes = size; memcpy(req_payload->data, buf, size); - resp_payload = hh_rm_call(HH_RM_RPC_MSG_ID_CALL_VM_CONSOLE_WRITE, - req_payload, req_payload_size, - &resp_payload_size, &reply_err_code); - if (reply_err_code || IS_ERR_OR_NULL(resp_payload)) { - err = PTR_ERR(resp_payload); - pr_err("%s: CONSOLE_WRITE failed with err: %d\n", - __func__, err); - goto out; + resp = hh_rm_call(HH_RM_RPC_MSG_ID_CALL_VM_CONSOLE_WRITE, + req_payload, req_payload_size, + &resp_payload_size, &reply_err_code); + kfree(req_payload); + + if (IS_ERR(resp)) { + pr_err("%s: Unable to send CONSOLE_WRITE to RM: %d\n", __func__, + PTR_ERR(resp)); + return PTR_ERR(resp); } - if (resp_payload_size != sizeof(*resp_payload)) { + if (reply_err_code) { + pr_err("%s: CONSOLE_WRITE returned error: %d\n", __func__, + reply_err_code); + return reply_err_code; + } + + if (resp_payload_size) { pr_err("%s: Invalid size received for CONSOLE_WRITE: %u\n", __func__, resp_payload_size); - err = -EINVAL; + return -EINVAL; } - err = err ? : resp_payload->response; - kfree(resp_payload); -out: - kfree(req_payload); - return err; + return 0; } EXPORT_SYMBOL(hh_rm_console_write); @@ -548,33 +555,36 @@ EXPORT_SYMBOL(hh_rm_console_write); */ int hh_rm_console_flush(hh_vmid_t vmid) { - struct hh_vm_console_common_resp_payload *resp_payload; + void *resp; struct hh_vm_console_common_req_payload req_payload = {0}; size_t resp_payload_size; - int err = 0, reply_err_code = 0; + int reply_err_code = 0; req_payload.vmid = vmid; - resp_payload = hh_rm_call(HH_RM_RPC_MSG_ID_CALL_VM_CONSOLE_FLUSH, + resp = hh_rm_call(HH_RM_RPC_MSG_ID_CALL_VM_CONSOLE_FLUSH, &req_payload, sizeof(req_payload), &resp_payload_size, &reply_err_code); - if (reply_err_code || IS_ERR_OR_NULL(resp_payload)) { - err = PTR_ERR(resp_payload); - pr_err("%s: CONSOLE_FLUSH failed with err: %d\n", - __func__, err); - goto out; + + if (IS_ERR(resp)) { + pr_err("%s: Unable to send CONSOLE_FLUSH to RM: %d\n", __func__, + PTR_ERR(resp)); + return PTR_ERR(resp); } - if (resp_payload_size != sizeof(*resp_payload)) { + if (reply_err_code) { + pr_err("%s: CONSOLE_FLUSH returned error: %d\n", __func__, + reply_err_code); + return reply_err_code; + } + + if (resp_payload_size) { pr_err("%s: Invalid size received for CONSOLE_FLUSH: %u\n", __func__, resp_payload_size); - err = -EINVAL; + return -EINVAL; } - err = err ? : resp_payload->response; - kfree(resp_payload); -out: - return err; + return 0; } EXPORT_SYMBOL(hh_rm_console_flush); From f56b018e3dc5c5c364c4dcc189b6a4fd5ae33132 Mon Sep 17 00:00:00 2001 From: Elliot Berman Date: Mon, 16 Mar 2020 14:03:20 -0700 Subject: [PATCH 4/4] tty: hvc_haven: Use thread worker to send characters hh_hvc_put_chars may be called with interrupts disabled. hh_rm_console_write is a blocking call (to wait for the response to come back). Use a FIFO and workqueue to send characters so that console_write may sleep. Change-Id: I7060b3604cb112caf00ecc1d94a5b2d543e7956e Signed-off-by: Elliot Berman --- drivers/tty/hvc/hvc_haven.c | 75 ++++++++++++++++++++++++++++++------- 1 file changed, 61 insertions(+), 14 deletions(-) diff --git a/drivers/tty/hvc/hvc_haven.c b/drivers/tty/hvc/hvc_haven.c index 2bf640cab02b..e4dea0ae32af 100644 --- a/drivers/tty/hvc/hvc_haven.c +++ b/drivers/tty/hvc/hvc_haven.c @@ -12,21 +12,27 @@ #include #include #include +#include +#include #include #include #include "hvc_console.h" #define HVC_HH_VTERM_COOKIE 0x474E5948 +/* # of payload bytes that can fit in a 1-fragment CONSOLE_WRITE message */ +#define HH_HVC_WRITE_MSG_SIZE ((1 * (HH_MSGQ_MAX_MSG_SIZE_BYTES - 8)) - 4) struct hh_hvc_prv { struct hvc_struct *hvc; - DECLARE_KFIFO(fifo, char, 1024); + DECLARE_KFIFO(get_fifo, char, 1024); + DECLARE_KFIFO(put_fifo, char, 1024); + struct work_struct put_work; }; static DEFINE_SPINLOCK(fifo_lock); -static struct hh_hvc_prv hh_hvc_data[2]; +static struct hh_hvc_prv hh_hvc_data[HH_VM_MAX]; static inline int hh_vm_name_to_vtermno(enum hh_vm_names vmname) { @@ -50,11 +56,12 @@ static int hh_hvc_notify_console_chars(struct notifier_block *this, ret = hh_rm_get_vm_name(msg->vmid, &vm_name); if (ret) { - pr_warn_ratelimited("don't know VMID %d\n", vm_name); + pr_warn_ratelimited("don't know VMID %d ret: %d\n", msg->vmid, + ret); return NOTIFY_OK; } - ret = kfifo_in_spinlocked(&hh_hvc_data[vm_name].fifo, + ret = kfifo_in_spinlocked(&hh_hvc_data[vm_name].get_fifo, msg->bytes, msg->num_bytes, &fifo_lock); @@ -69,6 +76,36 @@ static int hh_hvc_notify_console_chars(struct notifier_block *this, return NOTIFY_OK; } +static void hh_hvc_put_work_fn(struct work_struct *ws) +{ + hh_vmid_t vmid; + char buf[HH_HVC_WRITE_MSG_SIZE]; + int count, ret; + struct hh_hvc_prv *prv = container_of(ws, struct hh_hvc_prv, put_work); + enum hh_vm_names vm_name = vtermno_to_hh_vm_name(prv->hvc->vtermno); + + ret = hh_rm_get_vmid(vm_name, &vmid); + if (ret) { + pr_warn_once("hh_rm_get_vmid failed for %d: %d\n", + vm_name, ret); + return; + } + + while (!kfifo_is_empty(&prv->put_fifo)) { + count = kfifo_out_spinlocked(&prv->put_fifo, buf, sizeof(buf), + &fifo_lock); + if (count <= 0) + continue; + + ret = hh_rm_console_write(vmid, buf, count); + if (ret) { + pr_warn_once("hh_rm_console_write failed for %d: %d\n", + vm_name, ret); + break; + } + } +} + static int hh_hvc_get_chars(uint32_t vtermno, char *buf, int count) { int vm_name = vtermno_to_hh_vm_name(vtermno); @@ -76,24 +113,22 @@ static int hh_hvc_get_chars(uint32_t vtermno, char *buf, int count) if (vm_name < 0 || vm_name >= HH_VM_MAX) return -EINVAL; - return kfifo_out_spinlocked(&hh_hvc_data[vm_name].fifo, + return kfifo_out_spinlocked(&hh_hvc_data[vm_name].get_fifo, buf, count, &fifo_lock); } static int hh_hvc_put_chars(uint32_t vtermno, const char *buf, int count) { int ret, vm_name = vtermno_to_hh_vm_name(vtermno); - hh_vmid_t vmid; if (vm_name < 0 || vm_name >= HH_VM_MAX) return -EINVAL; - ret = hh_rm_get_vmid(vm_name, &vmid); - if (ret) - return ret; - - - return hh_rm_console_write(vmid, buf, count); + ret = kfifo_in_spinlocked(&hh_hvc_data[vm_name].put_fifo, + buf, count, &fifo_lock); + if (ret > 0) + schedule_work(&hh_hvc_data[vm_name].put_work); + return ret; } static int hh_hvc_flush(uint32_t vtermno, bool wait) @@ -108,6 +143,11 @@ static int hh_hvc_flush(uint32_t vtermno, bool wait) if (ret) return ret; + if (cancel_work_sync(&hh_hvc_data[vm_name].put_work)) { + /* flush the fifo */ + hh_hvc_put_work_fn(&hh_hvc_data[vm_name].put_work); + } + return hh_rm_console_flush(vmid); } @@ -131,6 +171,11 @@ static void hh_hvc_notify_del(struct hvc_struct *hp, int vm_name) if (vm_name < 0 || vm_name >= HH_VM_MAX) return; + if (cancel_work_sync(&hh_hvc_data[vm_name].put_work)) { + /* flush the fifo */ + hh_hvc_put_work_fn(&hh_hvc_data[vm_name].put_work); + } + ret = hh_rm_get_vmid(vm_name, &vmid); if (ret) return; @@ -140,7 +185,7 @@ static void hh_hvc_notify_del(struct hvc_struct *hp, int vm_name) if (ret) pr_err("Failed close VM%d console - %d\n", vm_name, ret); - kfifo_reset(&hh_hvc_data[vm_name].fifo); + kfifo_reset(&hh_hvc_data[vm_name].get_fifo); } static struct notifier_block hh_hvc_nb = { @@ -175,7 +220,9 @@ static int __init hvc_hh_init(void) for (i = 0; i < HH_VM_MAX; i++) { prv = &hh_hvc_data[i]; - INIT_KFIFO(prv->fifo); + INIT_KFIFO(prv->get_fifo); + INIT_KFIFO(prv->put_fifo); + INIT_WORK(&prv->put_work, hh_hvc_put_work_fn); prv->hvc = hvc_alloc(hh_vm_name_to_vtermno(i), i, &hh_hv_ops, 256); ret = PTR_ERR_OR_ZERO(prv->hvc);