From baccd98fb933be1f5808f50ed5164d49bcf9df35 Mon Sep 17 00:00:00 2001 From: Herman Chen Date: Tue, 25 Jan 2022 17:46:42 +0800 Subject: [PATCH] video: rockchip: mpp: Add message batch process 1. Add SET_SESSION_FD cmd for message session switch. 2. Use session to temporally store the ioctl message. Default message capacity is 2. For multi-core hardware the message capacity can be larger. 3. Split message handling into several stages. All the batch messages are attached to the temporary list and process stage by stage. Signed-off-by: Herman Chen Change-Id: I9d96bb96c24001dc5d27893fb09d1b8073d1a4a5 --- drivers/video/rockchip/mpp/mpp_common.c | 394 +++++++++++++++++------ drivers/video/rockchip/mpp/mpp_common.h | 37 ++- drivers/video/rockchip/mpp/mpp_rkvenc2.c | 4 + 3 files changed, 328 insertions(+), 107 deletions(-) diff --git a/drivers/video/rockchip/mpp/mpp_common.c b/drivers/video/rockchip/mpp/mpp_common.c index c3d337456472..54920893b0d6 100644 --- a/drivers/video/rockchip/mpp/mpp_common.c +++ b/drivers/video/rockchip/mpp/mpp_common.c @@ -54,6 +54,14 @@ struct mpp_msg_v1 { __u64 data_ptr; }; +#define MPP_BAT_MSG_DONE (0x00000001) + +struct mpp_bat_msg { + __u64 flag; + __u32 fd; + __s32 ret; +}; + #ifdef CONFIG_ROCKCHIP_MPP_PROC_FS const char *mpp_device_name[MPP_DEVICE_BUTT] = { [MPP_DEVICE_VDPU1] = "VDPU1", @@ -89,22 +97,6 @@ const char *enc_info_item_name[ENC_INFO_BUTT] = { static void mpp_attach_workqueue(struct mpp_dev *mpp, struct mpp_taskqueue *queue); -/* task queue schedule */ -static int -mpp_taskqueue_push_pending(struct mpp_taskqueue *queue, - struct mpp_task *task) -{ - if (!task->session || !task->session->mpp) - return -EINVAL; - - kref_get(&task->ref); - mutex_lock(&queue->pending_lock); - list_add_tail(&task->queue_link, &queue->pending_list); - mutex_unlock(&queue->pending_lock); - - return 0; -} - static int mpp_taskqueue_pop_pending(struct mpp_taskqueue *queue, struct mpp_task *task) @@ -252,9 +244,13 @@ static int mpp_session_clear(struct mpp_dev *mpp, static struct mpp_session *mpp_session_init(void) { struct mpp_session *session = kzalloc(sizeof(*session), GFP_KERNEL); + struct mpp_task_msgs *msgs = kzalloc(sizeof(*msgs), GFP_KERNEL); - if (!session) + if (!session || !msgs) { + kfree(session); + kfree(msgs); return NULL; + } session->pid = current->pid; @@ -266,6 +262,10 @@ static struct mpp_session *mpp_session_init(void) atomic_set(&session->task_count, 0); atomic_set(&session->release_request, 0); + session->msgs_cap = 1; + session->msgs_cnt = 0; + session->msgs = msgs; + mpp_dbg_session("session %p init\n", session); return session; } @@ -315,6 +315,7 @@ int mpp_session_deinit(struct mpp_session *session) mpp_dbg_session("session %p:%d deinit\n", session, session->index); + kfree(session->msgs); kfree(session); return 0; } @@ -459,7 +460,7 @@ static void mpp_task_timeout_work(struct work_struct *work_s) } static int mpp_process_task_default(struct mpp_session *session, - struct mpp_task_msgs *msgs) + struct mpp_task_msgs *msgs) { struct mpp_task *task = NULL; struct mpp_dev *mpp = session->mpp; @@ -485,6 +486,10 @@ static int mpp_process_task_default(struct mpp_session *session, if (mpp->auto_freq_en && mpp->hw_ops->get_freq) mpp->hw_ops->get_freq(mpp, task); + msgs->queue = mpp->queue; + msgs->task = task; + msgs->mpp = mpp; + /* * Push task to session should be in front of push task to queue. * Otherwise, when mpp_task_finish finish and worker_thread call @@ -493,13 +498,6 @@ static int mpp_process_task_default(struct mpp_session *session, */ atomic_inc(&session->task_count); mpp_session_push_pending(session, task); - /* push current task to queue */ - atomic_inc(&mpp->task_count); - mpp_taskqueue_push_pending(mpp->queue, task); - set_bit(TASK_STATE_PENDING, &task->state); - /* trigger current queue to run task */ - mpp_taskqueue_trigger_work(mpp); - kref_put(&task->ref, mpp_free_task); return 0; } @@ -940,27 +938,6 @@ static int mpp_check_cmd_v1(__u32 cmd) return found ? 0 : -EINVAL; } -static int mpp_parse_msg_v1(struct mpp_msg_v1 *msg, - struct mpp_request *req) -{ - int ret = 0; - - req->cmd = msg->cmd; - req->flags = msg->flags; - req->size = msg->size; - req->offset = msg->offset; - req->data = (void __user *)(unsigned long)msg->data_ptr; - - mpp_debug(DEBUG_IOCTL, "cmd %x, flags %08x, size %d, offset %x\n", - req->cmd, req->flags, req->size, req->offset); - - ret = mpp_check_cmd_v1(req->cmd); - if (ret) - mpp_err("mpp cmd %x is not supproted.\n", req->cmd); - - return ret; -} - static inline int mpp_msg_is_last(struct mpp_request *req) { int flag; @@ -1010,7 +987,8 @@ static int mpp_process_request(struct mpp_session *session, int ret; struct mpp_dev *mpp; - mpp_debug(DEBUG_IOCTL, "req->cmd %x\n", req->cmd); + mpp_debug(DEBUG_IOCTL, "cmd %x process\n", req->cmd); + switch (req->cmd) { case MPP_CMD_QUERY_HW_SUPPORT: { u32 hw_support = srv->hw_support; @@ -1036,8 +1014,10 @@ static int mpp_process_request(struct mpp_session *session, if (test_bit(client_type, &srv->hw_support)) mpp = srv->sub_devices[client_type]; } + if (!mpp) return -EINVAL; + hw_info = mpp->var->hw_info; mpp_debug(DEBUG_IOCTL, "hw_id %08x\n", hw_info->hw_id); if (put_user(hw_info->hw_id, (u32 __user *)req->data)) @@ -1068,6 +1048,7 @@ static int mpp_process_request(struct mpp_session *session, mpp = srv->sub_devices[client_type]; if (!mpp) return -EINVAL; + session->device_type = (enum MPP_DEVICE_TYPE)client_type; session->dma = mpp_dma_session_create(mpp->dev, mpp->session_max_buffers); session->mpp = mpp; @@ -1089,6 +1070,16 @@ static int mpp_process_request(struct mpp_session *session, if (ret) return ret; } + + if (session->msgs_cap != mpp->msgs_cap) { + kfree(session->msgs); + session->msgs = kcalloc(mpp->msgs_cap, sizeof(*session->msgs), GFP_KERNEL); + if (!session->msgs) + return -EINVAL; + + session->msgs_cap = mpp->msgs_cap; + } + mpp_session_attach_workqueue(session, mpp->queue); } break; case MPP_CMD_INIT_DRIVER_DATA: { @@ -1234,17 +1225,250 @@ static int mpp_process_request(struct mpp_session *session, return 0; } -static long mpp_dev_ioctl(struct file *filp, - unsigned int cmd, - unsigned long arg) +static void task_msgs_reset(struct mpp_task_msgs *msgs) +{ + msgs->flags = 0; + msgs->req_cnt = 0; + msgs->set_cnt = 0; + msgs->poll_cnt = 0; +} + +static void task_msgs_init(struct mpp_task_msgs *msgs, struct mpp_session *session) +{ + INIT_LIST_HEAD(&msgs->list); + + msgs->session = session; + msgs->queue = NULL; + msgs->task = NULL; + msgs->mpp = NULL; + + msgs->ext_fd = -1; + + task_msgs_reset(msgs); +} + +static void task_msgs_add(struct mpp_task_msgs *msgs, struct list_head *head) +{ + struct mpp_session *session = msgs->session; + int ret = 0; + + /* process each task */ + if (msgs->set_cnt) + ret = mpp_process_task(session, msgs); + + if (!ret) { + INIT_LIST_HEAD(&msgs->list); + list_add_tail(&msgs->list, head); + session->msgs_cnt++; + } +} + +static int mpp_collect_msgs(struct list_head *head, struct mpp_session *session, + unsigned int cmd, void __user *msg) +{ + struct mpp_msg_v1 msg_v1; + struct mpp_task_msgs *msgs = NULL; + struct mpp_request *req; + int last = 1; + int ret; + + if (cmd != MPP_IOC_CFG_V1) { + mpp_err("unknown ioctl cmd %x\n", cmd); + return -EINVAL; + } + +next: + /* first, parse to fixed struct */ + if (copy_from_user(&msg_v1, msg, sizeof(msg_v1))) + return -EFAULT; + + msg += sizeof(msg_v1); + + mpp_debug(DEBUG_IOCTL, "cmd %x collect flags %08x, size %d, offset %x\n", + msg_v1.cmd, msg_v1.flags, msg_v1.size, msg_v1.offset); + + if (mpp_check_cmd_v1(msg_v1.cmd)) { + mpp_err("mpp cmd %x is not supported.\n", msg_v1.cmd); + return -EFAULT; + } + + if (msg_v1.flags & MPP_FLAGS_MULTI_MSG) + last = (msg_v1.flags & MPP_FLAGS_LAST_MSG) ? 1 : 0; + else + last = 1; + + /* check cmd for change msgs session */ + if (msg_v1.cmd == MPP_CMD_SET_SESSION_FD) { + struct mpp_bat_msg bat_msg; + struct mpp_bat_msg __user *usr_cmd; + struct fd f; + + /* try session switch here */ + usr_cmd = (struct mpp_bat_msg __user *)(unsigned long)msg_v1.data_ptr; + + if (copy_from_user(&bat_msg, usr_cmd, sizeof(bat_msg))) + return -EFAULT; + + /* skip finished message */ + if (bat_msg.flag & MPP_BAT_MSG_DONE) + goto session_switch_done; + + f = fdget(bat_msg.fd); + if (!f.file) { + int ret = -EBADF; + + mpp_err("fd %d get session failed\n", bat_msg.fd); + + if (copy_to_user(&usr_cmd->ret, &ret, sizeof(usr_cmd->ret))) + mpp_err("copy_to_user failed.\n"); + goto session_switch_done; + } + + if (msgs && msgs->req_cnt) { + msgs->session = session; + + task_msgs_add(msgs, head); + } + + if (f.file->private_data == session) { + fdput(f); + msgs = &session->msgs[session->msgs_cnt]; + msgs->ext_fd = -1; + } else { + session = f.file->private_data; + msgs = &session->msgs[session->msgs_cnt]; + msgs->ext_fd = bat_msg.fd; + msgs->f = f; + } + + /* skip finished message */ + task_msgs_reset(msgs); + + mpp_debug(DEBUG_IOCTL, "fd %d, session %d msg_cnt %d\n", + bat_msg.fd, session->index, session->msgs_cnt); + +session_switch_done: + /* session id should NOT be the last message */ + if (last) + return 0; + + goto next; + } + + if (session->msgs_cnt >= session->msgs_cap) { + mpp_err("session %d request count %d more than capacity %d\n", + session->index, session->msgs_cnt, session->msgs_cap); + return -EINVAL; + } + + msgs = &session->msgs[session->msgs_cnt]; + + if (msgs->req_cnt >= MPP_MAX_MSG_NUM) { + mpp_err("session %d message count %d more than %d.\n", + session->index, msgs->req_cnt, MPP_MAX_MSG_NUM); + return -EINVAL; + } + + req = &msgs->reqs[msgs->req_cnt++]; + req->cmd = msg_v1.cmd; + req->flags = msg_v1.flags; + req->size = msg_v1.size; + req->offset = msg_v1.offset; + req->data = (void __user *)(unsigned long)msg_v1.data_ptr; + + ret = mpp_process_request(session, session->srv, req, msgs); + if (ret) { + mpp_err("session %d process cmd %x ret %d\n", + session->index, req->cmd, ret); + return ret; + } + + if (!last) + goto next; + + msgs->session = session; + task_msgs_add(msgs, head); + + return 0; +} + +static void mpp_msgs_trigger(struct list_head *msgs_list) +{ + struct mpp_task_msgs *msgs, *n; + struct mpp_dev *mpp_prev = NULL; + struct mpp_taskqueue *queue_prev = NULL; + + /* push task to queue */ + list_for_each_entry_safe(msgs, n, msgs_list, list) { + struct mpp_dev *mpp; + struct mpp_task *task; + struct mpp_taskqueue *queue; + + if (!msgs->set_cnt || !msgs->queue) + continue; + + mpp = msgs->mpp; + task = msgs->task; + queue = msgs->queue; + + if (queue_prev != queue) { + if (queue_prev && mpp_prev) { + mutex_unlock(&queue_prev->pending_lock); + mpp_taskqueue_trigger_work(mpp_prev); + } + + if (queue) + mutex_lock(&queue->pending_lock); + + mpp_prev = mpp; + queue_prev = queue; + } + + atomic_inc(&mpp->task_count); + + set_bit(TASK_STATE_PENDING, &task->state); + list_add_tail(&task->queue_link, &queue->pending_list); + } + + if (mpp_prev && queue_prev) { + mutex_unlock(&queue_prev->pending_lock); + mpp_taskqueue_trigger_work(mpp_prev); + } +} + +static void mpp_msgs_wait(struct list_head *msgs_list) +{ + struct mpp_task_msgs *msgs, *n; + + /* poll and release each task */ + list_for_each_entry_safe(msgs, n, msgs_list, list) { + struct mpp_session *session = msgs->session; + + if (msgs->poll_cnt) { + int ret = mpp_wait_result(session, msgs); + + if (ret) { + mpp_err("session %d wait result ret %d\n", + session->index, ret); + } + } + + task_msgs_reset(msgs); + list_del_init(&msgs->list); + msgs->session->msgs_cnt--; + + if (msgs->ext_fd >= 0) + fdput(msgs->f); + } +} + +static long mpp_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int ret = 0; struct mpp_service *srv; - void __user *msg; - struct mpp_request *req; - struct mpp_task_msgs task_msgs; - struct mpp_session *session = - (struct mpp_session *)filp->private_data; + struct mpp_session *session = (struct mpp_session *)filp->private_data; + struct list_head msgs_list; + u32 i; mpp_debug_enter(); @@ -1252,7 +1476,9 @@ static long mpp_dev_ioctl(struct file *filp, mpp_err("session %p\n", session); return -EINVAL; } + srv = session->srv; + if (atomic_read(&session->release_request) > 0) { mpp_debug(DEBUG_IOCTL, "release session had request\n"); return -EBUSY; @@ -1262,54 +1488,19 @@ static long mpp_dev_ioctl(struct file *filp, return -EBUSY; } - msg = (void __user *)arg; - memset(&task_msgs, 0, sizeof(task_msgs)); - do { - req = &task_msgs.reqs[task_msgs.req_cnt]; - /* first, parse to fixed struct */ - switch (cmd) { - case MPP_IOC_CFG_V1: { - struct mpp_msg_v1 msg_v1; + for (i = 0; i < session->msgs_cap; i++) + task_msgs_init(&session->msgs[i], session); - memset(&msg_v1, 0, sizeof(msg_v1)); - if (copy_from_user(&msg_v1, msg, sizeof(msg_v1))) - return -EFAULT; - ret = mpp_parse_msg_v1(&msg_v1, req); - if (ret) - return -EFAULT; + session->msgs_cnt = 0; + INIT_LIST_HEAD(&msgs_list); - msg += sizeof(msg_v1); - } break; - default: - mpp_err("unknown ioctl cmd %x\n", cmd); - return -EINVAL; - } - task_msgs.req_cnt++; - /* check loop times */ - if (task_msgs.req_cnt > MPP_MAX_MSG_NUM) { - mpp_err("fail, message count %d more than %d.\n", - task_msgs.req_cnt, MPP_MAX_MSG_NUM); - return -EINVAL; - } - /* second, process request */ - ret = mpp_process_request(session, srv, req, &task_msgs); - if (ret) - return -EFAULT; - /* last, process task message */ - if (mpp_msg_is_last(req)) { - session->msg_flags = task_msgs.flags; - if (task_msgs.set_cnt > 0) { - ret = mpp_process_task(session, &task_msgs); - if (ret) - return ret; - } - if (task_msgs.poll_cnt > 0) { - ret = mpp_wait_result(session, &task_msgs); - if (ret) - return ret; - } - } - } while (!mpp_msg_is_last(req)); + ret = mpp_collect_msgs(&msgs_list, session, cmd, (void __user *)arg); + if (ret) + mpp_err("collect msgs failed %d\n", ret); + + mpp_msgs_trigger(&msgs_list); + + mpp_msgs_wait(&msgs_list); mpp_debug_leave(); @@ -1776,6 +1967,7 @@ int mpp_dev_probe(struct mpp_dev *mpp, mpp->task_capacity); /* do not setup autosuspend on multi task device */ } + mpp->msgs_cap = 1; kthread_init_work(&mpp->work, mpp_task_worker_default); diff --git a/drivers/video/rockchip/mpp/mpp_common.h b/drivers/video/rockchip/mpp/mpp_common.h index e63b796d5a81..692b838620b8 100644 --- a/drivers/video/rockchip/mpp/mpp_common.h +++ b/drivers/video/rockchip/mpp/mpp_common.h @@ -108,6 +108,7 @@ enum MPP_DEV_COMMAND_TYPE { MPP_CMD_SET_REG_READ = MPP_CMD_SEND_BASE + 1, MPP_CMD_SET_REG_ADDR_OFFSET = MPP_CMD_SEND_BASE + 2, MPP_CMD_SET_RCB_INFO = MPP_CMD_SEND_BASE + 3, + MPP_CMD_SET_SESSION_FD = MPP_CMD_SEND_BASE + 4, MPP_CMD_SEND_BUTT, MPP_CMD_POLL_BASE = 0x300, @@ -181,6 +182,11 @@ enum CODEC_INFO_FLAGS { CODEC_INFO_FLAG_BUTT, }; +struct mpp_task; +struct mpp_session; +struct mpp_dma_session; +struct mpp_taskqueue; + /* data common struct for parse out */ struct mpp_request { __u32 cmd; @@ -192,11 +198,23 @@ struct mpp_request { /* struct use to collect task set and poll message */ struct mpp_task_msgs { + /* for ioctl msgs bat process */ + struct list_head list; + struct mpp_session *session; + struct mpp_taskqueue *queue; + struct mpp_task *task; + struct mpp_dev *mpp; + + /* for fd reference */ + int ext_fd; + struct fd f; + u32 flags; u32 req_cnt; - struct mpp_request reqs[MPP_MAX_MSG_NUM]; u32 set_cnt; u32 poll_cnt; + + struct mpp_request reqs[MPP_MAX_MSG_NUM]; }; struct mpp_grf_info { @@ -281,9 +299,6 @@ struct mpp_mem_region { bool is_dup; }; -struct mpp_dma_session; - -struct mpp_taskqueue; struct mpp_dev { struct device *dev; @@ -303,6 +318,13 @@ struct mpp_dev { * Default 1 means normal hardware can only accept one task at once. */ u32 task_capacity; + /* + * The message capacity is the max message parallel process capacity. + * Default 1 means normal hardware can only accept one message at one + * shot ioctl. + * Multi-core hardware can accept more message at one shot ioctl. + */ + u32 msgs_cap; int irq; u32 irq_status; @@ -329,8 +351,6 @@ struct mpp_dev { s32 core_id; }; -struct mpp_task; - struct mpp_session { enum MPP_DEVICE_TYPE device_type; u32 index; @@ -369,6 +389,11 @@ struct mpp_session { int (*wait_result)(struct mpp_session *session, struct mpp_task_msgs *msgs); void (*deinit)(struct mpp_session *session); + + /* max message count */ + int msgs_cap; + int msgs_cnt; + struct mpp_task_msgs *msgs; }; /* task state in work thread */ diff --git a/drivers/video/rockchip/mpp/mpp_rkvenc2.c b/drivers/video/rockchip/mpp/mpp_rkvenc2.c index 8628c44d5d83..86adb0185271 100644 --- a/drivers/video/rockchip/mpp/mpp_rkvenc2.c +++ b/drivers/video/rockchip/mpp/mpp_rkvenc2.c @@ -1392,6 +1392,10 @@ static int rkvenc_attach_ccu(struct device *dev, struct rkvenc_dev *enc) cur_info->domain = ccu_info->domain; cur_info->rw_sem = ccu_info->rw_sem; mpp_iommu_attach(cur_info); + + /* increase main core message capacity */ + ccu->main_core->msgs_cap++; + enc->mpp.msgs_cap = 0; } enc->ccu = ccu;