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 <herman.chen@rock-chips.com>
Change-Id: I9d96bb96c24001dc5d27893fb09d1b8073d1a4a5
This commit is contained in:
Herman Chen
2022-01-25 17:46:42 +08:00
committed by Tao Huang
parent d6ce2a864f
commit baccd98fb9
3 changed files with 328 additions and 107 deletions

View File

@@ -54,6 +54,14 @@ struct mpp_msg_v1 {
__u64 data_ptr; __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 #ifdef CONFIG_ROCKCHIP_MPP_PROC_FS
const char *mpp_device_name[MPP_DEVICE_BUTT] = { const char *mpp_device_name[MPP_DEVICE_BUTT] = {
[MPP_DEVICE_VDPU1] = "VDPU1", [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, static void mpp_attach_workqueue(struct mpp_dev *mpp,
struct mpp_taskqueue *queue); 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 static int
mpp_taskqueue_pop_pending(struct mpp_taskqueue *queue, mpp_taskqueue_pop_pending(struct mpp_taskqueue *queue,
struct mpp_task *task) 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) static struct mpp_session *mpp_session_init(void)
{ {
struct mpp_session *session = kzalloc(sizeof(*session), GFP_KERNEL); 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; return NULL;
}
session->pid = current->pid; 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->task_count, 0);
atomic_set(&session->release_request, 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); mpp_dbg_session("session %p init\n", session);
return 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); mpp_dbg_session("session %p:%d deinit\n", session, session->index);
kfree(session->msgs);
kfree(session); kfree(session);
return 0; 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, 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_task *task = NULL;
struct mpp_dev *mpp = session->mpp; 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) if (mpp->auto_freq_en && mpp->hw_ops->get_freq)
mpp->hw_ops->get_freq(mpp, task); 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. * Push task to session should be in front of push task to queue.
* Otherwise, when mpp_task_finish finish and worker_thread call * 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); atomic_inc(&session->task_count);
mpp_session_push_pending(session, task); 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; return 0;
} }
@@ -940,27 +938,6 @@ static int mpp_check_cmd_v1(__u32 cmd)
return found ? 0 : -EINVAL; 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) static inline int mpp_msg_is_last(struct mpp_request *req)
{ {
int flag; int flag;
@@ -1010,7 +987,8 @@ static int mpp_process_request(struct mpp_session *session,
int ret; int ret;
struct mpp_dev *mpp; 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) { switch (req->cmd) {
case MPP_CMD_QUERY_HW_SUPPORT: { case MPP_CMD_QUERY_HW_SUPPORT: {
u32 hw_support = srv->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)) if (test_bit(client_type, &srv->hw_support))
mpp = srv->sub_devices[client_type]; mpp = srv->sub_devices[client_type];
} }
if (!mpp) if (!mpp)
return -EINVAL; return -EINVAL;
hw_info = mpp->var->hw_info; hw_info = mpp->var->hw_info;
mpp_debug(DEBUG_IOCTL, "hw_id %08x\n", hw_info->hw_id); mpp_debug(DEBUG_IOCTL, "hw_id %08x\n", hw_info->hw_id);
if (put_user(hw_info->hw_id, (u32 __user *)req->data)) 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]; mpp = srv->sub_devices[client_type];
if (!mpp) if (!mpp)
return -EINVAL; return -EINVAL;
session->device_type = (enum MPP_DEVICE_TYPE)client_type; session->device_type = (enum MPP_DEVICE_TYPE)client_type;
session->dma = mpp_dma_session_create(mpp->dev, mpp->session_max_buffers); session->dma = mpp_dma_session_create(mpp->dev, mpp->session_max_buffers);
session->mpp = mpp; session->mpp = mpp;
@@ -1089,6 +1070,16 @@ static int mpp_process_request(struct mpp_session *session,
if (ret) if (ret)
return 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); mpp_session_attach_workqueue(session, mpp->queue);
} break; } break;
case MPP_CMD_INIT_DRIVER_DATA: { case MPP_CMD_INIT_DRIVER_DATA: {
@@ -1234,17 +1225,250 @@ static int mpp_process_request(struct mpp_session *session,
return 0; return 0;
} }
static long mpp_dev_ioctl(struct file *filp, static void task_msgs_reset(struct mpp_task_msgs *msgs)
unsigned int cmd, {
unsigned long arg) 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; int ret = 0;
struct mpp_service *srv; struct mpp_service *srv;
void __user *msg; struct mpp_session *session = (struct mpp_session *)filp->private_data;
struct mpp_request *req; struct list_head msgs_list;
struct mpp_task_msgs task_msgs; u32 i;
struct mpp_session *session =
(struct mpp_session *)filp->private_data;
mpp_debug_enter(); mpp_debug_enter();
@@ -1252,7 +1476,9 @@ static long mpp_dev_ioctl(struct file *filp,
mpp_err("session %p\n", session); mpp_err("session %p\n", session);
return -EINVAL; return -EINVAL;
} }
srv = session->srv; srv = session->srv;
if (atomic_read(&session->release_request) > 0) { if (atomic_read(&session->release_request) > 0) {
mpp_debug(DEBUG_IOCTL, "release session had request\n"); mpp_debug(DEBUG_IOCTL, "release session had request\n");
return -EBUSY; return -EBUSY;
@@ -1262,54 +1488,19 @@ static long mpp_dev_ioctl(struct file *filp,
return -EBUSY; return -EBUSY;
} }
msg = (void __user *)arg; for (i = 0; i < session->msgs_cap; i++)
memset(&task_msgs, 0, sizeof(task_msgs)); task_msgs_init(&session->msgs[i], session);
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;
memset(&msg_v1, 0, sizeof(msg_v1)); session->msgs_cnt = 0;
if (copy_from_user(&msg_v1, msg, sizeof(msg_v1))) INIT_LIST_HEAD(&msgs_list);
return -EFAULT;
ret = mpp_parse_msg_v1(&msg_v1, req);
if (ret)
return -EFAULT;
msg += sizeof(msg_v1); ret = mpp_collect_msgs(&msgs_list, session, cmd, (void __user *)arg);
} break; if (ret)
default: mpp_err("collect msgs failed %d\n", ret);
mpp_err("unknown ioctl cmd %x\n", cmd);
return -EINVAL; mpp_msgs_trigger(&msgs_list);
}
task_msgs.req_cnt++; mpp_msgs_wait(&msgs_list);
/* 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));
mpp_debug_leave(); mpp_debug_leave();
@@ -1776,6 +1967,7 @@ int mpp_dev_probe(struct mpp_dev *mpp,
mpp->task_capacity); mpp->task_capacity);
/* do not setup autosuspend on multi task device */ /* do not setup autosuspend on multi task device */
} }
mpp->msgs_cap = 1;
kthread_init_work(&mpp->work, mpp_task_worker_default); kthread_init_work(&mpp->work, mpp_task_worker_default);

View File

@@ -108,6 +108,7 @@ enum MPP_DEV_COMMAND_TYPE {
MPP_CMD_SET_REG_READ = MPP_CMD_SEND_BASE + 1, MPP_CMD_SET_REG_READ = MPP_CMD_SEND_BASE + 1,
MPP_CMD_SET_REG_ADDR_OFFSET = MPP_CMD_SEND_BASE + 2, MPP_CMD_SET_REG_ADDR_OFFSET = MPP_CMD_SEND_BASE + 2,
MPP_CMD_SET_RCB_INFO = MPP_CMD_SEND_BASE + 3, 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_SEND_BUTT,
MPP_CMD_POLL_BASE = 0x300, MPP_CMD_POLL_BASE = 0x300,
@@ -181,6 +182,11 @@ enum CODEC_INFO_FLAGS {
CODEC_INFO_FLAG_BUTT, CODEC_INFO_FLAG_BUTT,
}; };
struct mpp_task;
struct mpp_session;
struct mpp_dma_session;
struct mpp_taskqueue;
/* data common struct for parse out */ /* data common struct for parse out */
struct mpp_request { struct mpp_request {
__u32 cmd; __u32 cmd;
@@ -192,11 +198,23 @@ struct mpp_request {
/* struct use to collect task set and poll message */ /* struct use to collect task set and poll message */
struct mpp_task_msgs { 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 flags;
u32 req_cnt; u32 req_cnt;
struct mpp_request reqs[MPP_MAX_MSG_NUM];
u32 set_cnt; u32 set_cnt;
u32 poll_cnt; u32 poll_cnt;
struct mpp_request reqs[MPP_MAX_MSG_NUM];
}; };
struct mpp_grf_info { struct mpp_grf_info {
@@ -281,9 +299,6 @@ struct mpp_mem_region {
bool is_dup; bool is_dup;
}; };
struct mpp_dma_session;
struct mpp_taskqueue;
struct mpp_dev { struct mpp_dev {
struct device *dev; struct device *dev;
@@ -303,6 +318,13 @@ struct mpp_dev {
* Default 1 means normal hardware can only accept one task at once. * Default 1 means normal hardware can only accept one task at once.
*/ */
u32 task_capacity; 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; int irq;
u32 irq_status; u32 irq_status;
@@ -329,8 +351,6 @@ struct mpp_dev {
s32 core_id; s32 core_id;
}; };
struct mpp_task;
struct mpp_session { struct mpp_session {
enum MPP_DEVICE_TYPE device_type; enum MPP_DEVICE_TYPE device_type;
u32 index; u32 index;
@@ -369,6 +389,11 @@ struct mpp_session {
int (*wait_result)(struct mpp_session *session, int (*wait_result)(struct mpp_session *session,
struct mpp_task_msgs *msgs); struct mpp_task_msgs *msgs);
void (*deinit)(struct mpp_session *session); 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 */ /* task state in work thread */

View File

@@ -1392,6 +1392,10 @@ static int rkvenc_attach_ccu(struct device *dev, struct rkvenc_dev *enc)
cur_info->domain = ccu_info->domain; cur_info->domain = ccu_info->domain;
cur_info->rw_sem = ccu_info->rw_sem; cur_info->rw_sem = ccu_info->rw_sem;
mpp_iommu_attach(cur_info); mpp_iommu_attach(cur_info);
/* increase main core message capacity */
ccu->main_core->msgs_cap++;
enc->mpp.msgs_cap = 0;
} }
enc->ccu = ccu; enc->ccu = ccu;