diff --git a/msm/Makefile b/msm/Makefile index 6ec592b5eb..9c7df05e71 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 238452072d..bf69e2720c 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 5026a8aa64..82b18b67eb 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 1c5fcaad25..6572663725 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 0000000000..f339ac5060 --- /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 0000000000..6813d43f33 --- /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 a3a0eb26c3..f9ee40642a 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 fe05d9fb06..7e0457e299 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);