From d076f0201704624314a7b318adcabb2a26a0d1e5 Mon Sep 17 00:00:00 2001 From: Jeykumar Sankaran Date: Thu, 24 Sep 2020 18:49:27 -0700 Subject: [PATCH] disp: msm: sde: add msgq support for sde vm layer Linux message queues(msgq) are used to communicate between VM's This change creates a display specific msgq and a set of framework api's for the VM layer to invoke communication between the VMs'. Display msgq is bidirectional. Tx end is created by default for both the VM's. Rx is kept optional to avoid unnecessary creation of listener threads. Change-Id: If4e6410045293d6b21087a76ec018d4784dd5238 Signed-off-by: Jeykumar Sankaran --- msm/Makefile | 3 +- msm/sde/sde_vm.h | 50 ++++++++++++++++ msm/sde/sde_vm_common.c | 9 +++ msm/sde/sde_vm_common.h | 17 +++++- msm/sde/sde_vm_msgq.c | 125 +++++++++++++++++++++++++++++++++++++++ msm/sde/sde_vm_msgq.h | 28 +++++++++ msm/sde/sde_vm_primary.c | 10 ++++ msm/sde/sde_vm_trusted.c | 11 ++++ 8 files changed, 251 insertions(+), 2 deletions(-) create mode 100644 msm/sde/sde_vm_msgq.c create mode 100644 msm/sde/sde_vm_msgq.h diff --git a/msm/Makefile b/msm/Makefile index 6ec592b5ebfe..9c7df05e71b3 100644 --- a/msm/Makefile +++ b/msm/Makefile @@ -87,7 +87,8 @@ msm_drm-$(CONFIG_DRM_MSM_SDE) += sde/sde_crtc.o \ msm_drm-$(CONFIG_DRM_SDE_VM) += sde/sde_vm_common.o \ sde/sde_vm_primary.o \ - sde/sde_vm_trusted.o + sde/sde_vm_trusted.o \ + sde/sde_vm_msgq.o msm_drm-$(CONFIG_DRM_SDE_WB) += sde/sde_wb.o \ sde/sde_encoder_phys_wb.o diff --git a/msm/sde/sde_vm.h b/msm/sde/sde_vm.h index 238452072d70..bf69e2720cd9 100644 --- a/msm/sde/sde_vm.h +++ b/msm/sde/sde_vm.h @@ -12,6 +12,35 @@ struct sde_kms; +/* sde_vm_msg_type - msg_type for dispaly custom messages */ +enum sde_vm_msg_type { + SDE_VM_MSG_MAX, +}; + +/** + * sde_vm_msg_work - sde msgq work definition + * @work - base kthread work object + * @msg_buf - payload buffer + * @msg_size - payload buffer size + * @sde_vm - handle to vm structure + */ +struct sde_vm_msg_work { + struct kthread_work work; + void *msg_buf; + size_t msg_size; + struct sde_vm *sde_vm; +}; + +/** + * sde_vm_msg_header - header definition for custom messages. Must + * be placed at the beginning of each custom + * message definition. + * @msg_type - type of the message + */ +struct sde_vm_msg_header { + enum sde_vm_msg_type msg_type; +}; + /** * sde_vm_irq_entry - VM irq specification * @label - VM_IRQ_LABEL assigned by Hyp RM @@ -122,6 +151,21 @@ struct sde_vm_ops { * @sde_kms - handle to sde_kms */ int (*vm_acquire_fail_handler)(struct sde_kms *sde_kms); + + /** vm_msg_recv_cb - sde kms callback hook for msgq data + * @sde_vm - handle to sde_vm struct + * @data - paylod data + * @size - size of payload data + */ + void (*vm_msg_recv_cb)(struct sde_vm *sde_vm, void *data, size_t size); + + /** vm_msg_send - hook to send custom data to VM + * @sde_vm - handle to sde_vm struct + * @msg - payload data + * @msg_size - payload data size + * @return - 0 on success, errorcode otherwise + */ + int (*vm_msg_send)(struct sde_vm *sde_vm, void *msg, size_t msg_size); }; /** @@ -132,6 +176,9 @@ struct sde_vm_ops { * @io_mem_handle - RM identifier for the IO range * @sde_kms - handle to sde_kms * @vm_ops - VM operation hooks for respective VM type + * @msgq_listener_thread - handle to msgq receiver thread + * @vm_work - kthread work obj for msgq + * @msgq_handle - handle to display msgq */ struct sde_vm { struct mutex vm_res_lock; @@ -140,6 +187,9 @@ struct sde_vm { int io_mem_handle; struct sde_kms *sde_kms; struct sde_vm_ops vm_ops; + struct task_struct *msgq_listener_thread; + struct sde_vm_msg_work vm_work; + void *msgq_handle; }; /** diff --git a/msm/sde/sde_vm_common.c b/msm/sde/sde_vm_common.c index 5026a8aa64c2..82b18b67ebda 100644 --- a/msm/sde/sde_vm_common.c +++ b/msm/sde/sde_vm_common.c @@ -10,6 +10,7 @@ #include "sde_kms.h" #include "sde_vm_common.h" #include "sde_crtc.h" +#include "sde_vm_msgq.h" struct hh_notify_vmid_desc *sde_vm_populate_vmid(hh_vmid_t vmid) { @@ -321,3 +322,11 @@ int sde_vm_request_valid(struct sde_kms *sde_kms, return rc; } + +int sde_vm_msg_send(struct sde_vm *sde_vm, void *msg, size_t msg_size) +{ + if (!sde_vm) + return -EINVAL; + + return sde_vm_msgq_send(sde_vm, msg, msg_size); +} diff --git a/msm/sde/sde_vm_common.h b/msm/sde/sde_vm_common.h index 1c5fcaad257c..657266372598 100644 --- a/msm/sde/sde_vm_common.h +++ b/msm/sde/sde_vm_common.h @@ -75,9 +75,24 @@ int sde_vm_post_acquire(struct sde_kms *kms); */ int sde_vm_pre_release(struct sde_kms *kms); - +/** + * sde_vm_request_valid - check the validity of state transition request + * @sde_kms: handle to sde_kms + * @old_state: old crtc vm req state + * @new_state: new crtc vm req state + * @return: 0 on success + */ int sde_vm_request_valid(struct sde_kms *sde_kms, enum sde_crtc_vm_req old_state, enum sde_crtc_vm_req new_state); +/** + * sde_vm_msg_send - send display custom message through message queue + * @sde_vm: handle to sde_vm struct + * @msg: payload data + * @msg_size: payload data size + * @return: 0 on success + */ +int sde_vm_msg_send(struct sde_vm *sde_vm, void *msg, size_t msg_size); + #endif /* __SDE_VM_COMMON_H__ */ diff --git a/msm/sde/sde_vm_msgq.c b/msm/sde/sde_vm_msgq.c new file mode 100644 index 000000000000..f339ac5060b1 --- /dev/null +++ b/msm/sde/sde_vm_msgq.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include "sde_kms.h" +#include "sde_vm.h" + +static void _sde_vm_msgq_process_msg(struct kthread_work *work) +{ + struct sde_vm_msg_work *vm_work = + container_of(work, struct sde_vm_msg_work, work); + struct sde_vm_ops *vm_ops = &vm_work->sde_vm->vm_ops; + + if (vm_ops->vm_msg_recv_cb) + vm_ops->vm_msg_recv_cb(vm_work->sde_vm, vm_work->msg_buf, + vm_work->msg_size); + + kfree(vm_work->msg_buf); +} + +static int _sde_vm_msgq_listener(void *data) +{ + struct sde_vm *sde_vm = (struct sde_vm *)data; + struct sde_kms *sde_kms = sde_vm->sde_kms; + struct sde_vm_msg_work *vm_work; + struct msm_drm_private *priv; + struct msm_drm_thread *event_thread; + void *buf; + size_t size; + int ret = 0; + + priv = sde_kms->dev->dev_private; + event_thread = &priv->event_thread[0]; + vm_work = &sde_vm->vm_work; + + while (true) { + buf = kzalloc(HH_MSGQ_MAX_MSG_SIZE_BYTES, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = hh_msgq_recv(sde_vm->msgq_handle, buf, + HH_MSGQ_MAX_MSG_SIZE_BYTES, &size, 0); + if (ret < 0) { + kfree(buf); + SDE_ERROR("hh_msgq_recv failed, rc=%d\n", ret); + return -EINVAL; + } + + vm_work->msg_buf = buf; + vm_work->msg_size = size; + vm_work->sde_vm = sde_vm; + + kthread_queue_work(&event_thread->worker, &vm_work->work); + } + + return 0; +} + +int sde_vm_msgq_send(struct sde_vm *sde_vm, void *msg, size_t msg_size) +{ + if (!sde_vm->msgq_handle) { + SDE_ERROR("Failed to send msg, invalid msgq handle\n"); + return -EINVAL; + } + + if (msg_size > HH_MSGQ_MAX_MSG_SIZE_BYTES) { + SDE_ERROR("msg size unsupported for msgq: %d > %d\n", msg_size, + HH_MSGQ_MAX_MSG_SIZE_BYTES); + return -E2BIG; + } + + return hh_msgq_send(sde_vm->msgq_handle, msg, msg_size, HH_MSGQ_TX_PUSH); +} + +int sde_vm_msgq_init(struct sde_vm *sde_vm) +{ + struct sde_vm_ops *vm_ops = &sde_vm->vm_ops; + void *msgq_handle = NULL; + struct task_struct *msgq_listener_thread = NULL; + int rc = 0; + + msgq_handle = hh_msgq_register(HH_MSGQ_LABEL_DISPLAY); + if (IS_ERR(msgq_handle)) { + SDE_ERROR("hh_msgq_register failed, hdl=%p\n", msgq_handle); + return -EINVAL; + } + + sde_vm->msgq_handle = msgq_handle; + + if (!vm_ops->vm_msg_recv_cb) + goto done; + + msgq_listener_thread = kthread_run(_sde_vm_msgq_listener, + (void *)sde_vm, "disp_msgq_listener"); + if (IS_ERR(msgq_listener_thread)) { + SDE_ERROR("kthread creation failed for msgq, hdl: %p\n", + msgq_listener_thread); + rc = -EINVAL; + goto kthread_create_fail; + } + + kthread_init_work(&sde_vm->vm_work.work, _sde_vm_msgq_process_msg); + + sde_vm->msgq_listener_thread = msgq_listener_thread; + + return 0; + +kthread_create_fail: + hh_msgq_unregister(msgq_handle); + sde_vm->msgq_handle = NULL; +done: + return rc; +} + +void sde_vm_msgq_deinit(struct sde_vm *sde_vm) +{ + if (sde_vm->msgq_listener_thread) + kthread_stop(sde_vm->msgq_listener_thread); + + if (sde_vm->msgq_handle) + hh_msgq_unregister(sde_vm->msgq_handle); +} diff --git a/msm/sde/sde_vm_msgq.h b/msm/sde/sde_vm_msgq.h new file mode 100644 index 000000000000..6813d43f33ce --- /dev/null +++ b/msm/sde/sde_vm_msgq.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ +#ifndef __SDE_VM_MSGQ_H__ +#define __SDE_VM_MSGQ_H__ + +/** + * sde_vm_msgq_init - initialize display message queue: both TX and RX + * @sde_kms - handle to sde_kms + */ +int sde_vm_msgq_init(struct sde_vm *sde_vm); + +/** + * sde_vm_msgq_deinit - deinitialize display message queue: both TX and RX + * @sde_kms - handle to sde_kms + */ +void sde_vm_msgq_deinit(struct sde_vm *sde_vm); + +/** + * sde_vm_msgq_send - send custom messages across VM's + * @sde_vm - handle to vm base struct + * @msg - payload data + * @msg_size - size of the payload_data + */ +int sde_vm_msgq_send(struct sde_vm *sde_vm, void *msg, size_t msg_size); + +#endif // __SDE_VM_MSGQ_H__ diff --git a/msm/sde/sde_vm_primary.c b/msm/sde/sde_vm_primary.c index a3a0eb26c375..f9ee40642a9d 100644 --- a/msm/sde/sde_vm_primary.c +++ b/msm/sde/sde_vm_primary.c @@ -9,6 +9,7 @@ #include "sde_kms.h" #include "sde_vm.h" #include "sde_vm_common.h" +#include "sde_vm_msgq.h" #define to_vm_primary(vm) ((struct sde_vm_primary *)vm) @@ -266,6 +267,8 @@ static void _sde_vm_deinit(struct sde_kms *sde_kms, struct sde_vm_ops *ops) sde_vm = to_vm_primary(sde_kms->vm); + sde_vm_msgq_deinit(sde_kms->vm); + if (sde_vm->base.mem_notification_cookie) hh_mem_notifier_unregister( sde_vm->base.mem_notification_cookie); @@ -289,6 +292,7 @@ static void _sde_vm_set_ops(struct sde_vm_ops *ops) ops->vm_prepare_commit = sde_kms_vm_primary_prepare_commit; ops->vm_post_commit = sde_kms_vm_primary_post_commit; ops->vm_request_valid = sde_vm_request_valid; + ops->vm_msg_send = sde_vm_msg_send; } int sde_vm_primary_init(struct sde_kms *kms) @@ -318,6 +322,12 @@ int sde_vm_primary_init(struct sde_kms *kms) mutex_init(&sde_vm->base.vm_res_lock); + rc = sde_vm_msgq_init(kms->vm); + if (rc) { + SDE_ERROR("failed to initialize the msgq, rc=%d\n", rc); + goto init_fail; + } + return 0; init_fail: _sde_vm_deinit(kms, &sde_vm->base.vm_ops); diff --git a/msm/sde/sde_vm_trusted.c b/msm/sde/sde_vm_trusted.c index fe05d9fb063e..7e0457e299a6 100644 --- a/msm/sde/sde_vm_trusted.c +++ b/msm/sde/sde_vm_trusted.c @@ -13,6 +13,8 @@ #include "sde_kms.h" #include "sde_vm_common.h" #include "sde_vm.h" +#include "sde_vm_msgq.h" + #define to_vm_trusted(vm) ((struct sde_vm_trusted *)vm) @@ -247,6 +249,8 @@ static void _sde_vm_deinit(struct sde_kms *kms, struct sde_vm_ops *ops) memset(ops, 0, sizeof(*ops)); + sde_vm_msgq_deinit(kms->vm); + if (sde_vm->base.mem_notification_cookie) hh_mem_notifier_unregister( sde_vm->base.mem_notification_cookie); @@ -409,6 +413,7 @@ static void _sde_vm_set_ops(struct sde_vm_ops *ops) ops->vm_post_commit = sde_kms_vm_trusted_post_commit; ops->vm_request_valid = sde_vm_request_valid; ops->vm_acquire_fail_handler = _sde_vm_release; + ops->vm_msg_send = sde_vm_msg_send; } int sde_vm_trusted_init(struct sde_kms *kms) @@ -460,6 +465,12 @@ int sde_vm_trusted_init(struct sde_kms *kms) atomic_set(&sde_vm->base.n_irq_lent, 0); + rc = sde_vm_msgq_init(kms->vm); + if (rc) { + SDE_ERROR("failed to initialize the msgq, rc=%d\n", rc); + goto init_fail; + } + return 0; init_fail: _sde_vm_deinit(kms, &sde_vm->base.vm_ops);