From 6cee981d5adb4073d33cfe07ca2e16c4209db007 Mon Sep 17 00:00:00 2001 From: Herman Chen Date: Fri, 18 Mar 2022 17:04:33 +0800 Subject: [PATCH] video: rockchip: mpp: rkvenc2: Fix slice mode issue 1. Use MPP_CMD_POLL_HW_IRQ to handle the hw slice irq. Old MPP_CMD_POLL_HW_FINISH will wait hardware finish and skip hw irq. 2. Clear poll request msgs when it is handled. NOTE: When MPP_CMD_POLL_HW_IRQ return slice with zero length the current task is completed. This way can reduce an extra MPP_CMD_POLL_HW_FINISH ioctl. Signed-off-by: Herman Chen Change-Id: I2c81d85c236d4290a497c1747ae2f3e5ac1ce55c --- drivers/video/rockchip/mpp/mpp_common.c | 14 ++++++-- drivers/video/rockchip/mpp/mpp_common.h | 1 + drivers/video/rockchip/mpp/mpp_rkvenc2.c | 43 +++++++++++++++--------- 3 files changed, 39 insertions(+), 19 deletions(-) diff --git a/drivers/video/rockchip/mpp/mpp_common.c b/drivers/video/rockchip/mpp/mpp_common.c index 8c6e0d1519f3..e7b15fe43a44 100644 --- a/drivers/video/rockchip/mpp/mpp_common.c +++ b/drivers/video/rockchip/mpp/mpp_common.c @@ -1202,12 +1202,20 @@ static int mpp_process_request(struct mpp_session *session, case MPP_CMD_POLL_HW_FINISH: { msgs->flags |= req->flags; msgs->poll_cnt++; + msgs->poll_req = NULL; + } break; + case MPP_CMD_POLL_HW_IRQ: { + if (msgs->poll_cnt || msgs->poll_req) + mpp_err("Do NOT poll hw irq when previous call not return\n"); + + msgs->flags |= req->flags; + msgs->poll_cnt++; if (req->size && req->data) { - if (msgs->poll_req) - mpp_err("can not poll more than one request\n"); - else + if (!msgs->poll_req) msgs->poll_req = req; + } else { + msgs->poll_req = NULL; } } break; case MPP_CMD_RESET_SESSION: { diff --git a/drivers/video/rockchip/mpp/mpp_common.h b/drivers/video/rockchip/mpp/mpp_common.h index 183d562d2828..cc673096c5fe 100644 --- a/drivers/video/rockchip/mpp/mpp_common.h +++ b/drivers/video/rockchip/mpp/mpp_common.h @@ -115,6 +115,7 @@ enum MPP_DEV_COMMAND_TYPE { MPP_CMD_POLL_BASE = 0x300, MPP_CMD_POLL_HW_FINISH = MPP_CMD_POLL_BASE + 0, + MPP_CMD_POLL_HW_IRQ = MPP_CMD_POLL_BASE + 1, MPP_CMD_POLL_BUTT, MPP_CMD_CONTROL_BASE = 0x400, diff --git a/drivers/video/rockchip/mpp/mpp_rkvenc2.c b/drivers/video/rockchip/mpp/mpp_rkvenc2.c index 72e48a95027f..847b5acf4e88 100644 --- a/drivers/video/rockchip/mpp/mpp_rkvenc2.c +++ b/drivers/video/rockchip/mpp/mpp_rkvenc2.c @@ -697,9 +697,9 @@ static int rkvenc2_is_split_task(struct rkvenc_task *task) } if (sli_split_en && slen_fifo_en && sli_flsh_en) { - mpp_dbg_slice("slice output with irq enabled\n"); if (!slc_done_en || slc_done_msk) - mpp_dbg_slice("slice output enabled but irq disabled!\n"); + mpp_dbg_slice("task %d slice output enabled but irq disabled!\n", + task->mpp_task.task_id); return 1; } @@ -984,7 +984,8 @@ static void rkvenc2_read_slice_len(struct mpp_dev *mpp, struct rkvenc_task *task for (i = 0; i < sli_num; i++) { u32 sli_len = mpp_read_relaxed(mpp, RKVENC2_REG_SLICE_LEN_BASE); - mpp_dbg_slice("wr %d:%d len %d\n", sli_num, i, sli_len); + mpp_dbg_slice("task %d wr len %d %d:%d\n", + task->mpp_task.task_id, sli_len, sli_num, i); kfifo_in(&task->slice_len, &sli_len, 1); } } @@ -993,7 +994,7 @@ static void rkvenc2_last_slice(struct rkvenc_task *task) { u32 sli_len = 0; - mpp_dbg_slice("wr last slice\n"); + mpp_dbg_slice("task %d last slice found\n", task->mpp_task.task_id); kfifo_in(&task->slice_len, &sli_len, 1); } @@ -1034,8 +1035,10 @@ static int rkvenc_irq(struct mpp_dev *mpp) ret = IRQ_WAKE_THREAD; if (task) { - rkvenc2_read_slice_len(mpp, task); - rkvenc2_last_slice(task); + if (task->task_split) { + rkvenc2_read_slice_len(mpp, task); + rkvenc2_last_slice(task); + } wake_up(&mpp_task->wait); } } @@ -1541,6 +1544,7 @@ static int rkvenc2_wait_result(struct mpp_session *session, struct mpp_task *task; struct mpp_dev *mpp; u32 slice_len = 0; + u32 task_id; int ret = 0; mutex_lock(&session->pending_lock); @@ -1555,6 +1559,9 @@ static int rkvenc2_wait_result(struct mpp_session *session, mpp = mpp_get_task_used_device(task, session); enc_task = to_rkvenc_task(task); + task_id = task->task_id; + + req = cmpxchg(&msgs->poll_req, msgs->poll_req, NULL); if (!enc_task->task_split || enc_task->task_split_done) { task_done_ret: @@ -1569,8 +1576,6 @@ task_done_ret: return ret; } - req = msgs->poll_req; - /* not slice return just wait all slice length */ if (!req) { do { @@ -1578,7 +1583,8 @@ task_done_ret: kfifo_out(&enc_task->slice_len, &slice_len, 1), msecs_to_jiffies(RKVENC2_WORK_TIMEOUT_DELAY)); if (ret > 0) { - mpp_dbg_slice("not ret rd len %d\n", slice_len); + mpp_dbg_slice("task %d skip slice len %d\n", + task_id, slice_len); if (slice_len == 0) goto task_done_ret; @@ -1595,7 +1601,8 @@ task_done_ret: return -EINVAL; } - mpp_dbg_slice("count %d : %d\n", cfg.count_max, cfg.count_ret); + mpp_dbg_slice("task %d poll irq %d:%d\n", task->task_id, + cfg.count_max, cfg.count_ret); cfg.count_ret = 0; /* handle slice mode poll return */ @@ -1603,24 +1610,28 @@ task_done_ret: kfifo_out(&enc_task->slice_len, &slice_len, 1), msecs_to_jiffies(RKVENC2_WORK_TIMEOUT_DELAY)); if (ret > 0) { - mpp_dbg_slice("rd len %d\n", slice_len); - if (!slice_len) - enc_task->task_split_done = 1; + mpp_dbg_slice("task %d rd len %d\n", task_id, slice_len); if (cfg.count_ret < cfg.count_max) { struct rkvenc_poll_slice_cfg __user *ucfg = (struct rkvenc_poll_slice_cfg __user *)(req->data); u32 __user *dst = (u32 __user *)(ucfg + 1); + /* Do NOT return here when put_user error. Just continue */ if (put_user(slice_len, dst + cfg.count_ret)) - return -EFAULT; + ret = -EFAULT; cfg.count_ret++; if (put_user(cfg.count_ret, &ucfg->count_ret)) - return -EFAULT; + ret = -EFAULT; } - return 0; + if (!slice_len) { + enc_task->task_split_done = 1; + goto task_done_ret; + } + + return ret < 0 ? ret : 0; } rkvenc2_task_timeout_process(session, task);