diff --git a/drivers/video/rockchip/mpp/mpp_common.c b/drivers/video/rockchip/mpp/mpp_common.c index 2853d5ce91c0..72edfa6dbaf3 100644 --- a/drivers/video/rockchip/mpp/mpp_common.c +++ b/drivers/video/rockchip/mpp/mpp_common.c @@ -84,6 +84,8 @@ const char *enc_info_item_name[ENC_INFO_BUTT] = { #endif static void mpp_free_task(struct kref *ref); +static void mpp_attach_workqueue(struct mpp_dev *mpp, + struct mpp_taskqueue *queue); /* task queue schedule */ static int @@ -185,10 +187,9 @@ mpp_taskqueue_pop_running(struct mpp_taskqueue *queue, } static void -mpp_taskqueue_trigger_work(struct mpp_taskqueue *queue, - struct workqueue_struct *workq) +mpp_taskqueue_trigger_work(struct mpp_dev *mpp) { - queue_work(workq, &queue->work); + queue_work(mpp->workq, &mpp->work); } int mpp_power_on(struct mpp_dev *mpp) @@ -388,7 +389,7 @@ static int mpp_process_task(struct mpp_session *session, 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->queue, mpp->workq); + mpp_taskqueue_trigger_work(mpp); kref_put(&task->ref, mpp_free_task); return 0; @@ -543,10 +544,8 @@ static int mpp_task_run(struct mpp_dev *mpp, static void mpp_task_try_run(struct work_struct *work_s) { struct mpp_task *task; - struct mpp_dev *mpp; - struct mpp_taskqueue *queue = container_of(work_s, - struct mpp_taskqueue, - work); + struct mpp_dev *mpp = container_of(work_s, struct mpp_dev, work); + struct mpp_taskqueue *queue = mpp->queue; mpp_debug_enter(); @@ -702,6 +701,7 @@ static int mpp_attach_service(struct mpp_dev *mpp, struct device *dev) u32 reset_group_node = 0; struct device_node *np = NULL; struct platform_device *pdev = NULL; + struct mpp_taskqueue *queue = NULL; int ret = 0; np = of_parse_phandle(dev->of_node, "rockchip,srv", 0); @@ -728,28 +728,29 @@ static int mpp_attach_service(struct mpp_dev *mpp, struct device *dev) ret = of_property_read_u32(dev->of_node, "rockchip,taskqueue-node", &taskqueue_node); + if (taskqueue_node >= mpp->srv->taskqueue_cnt) { + dev_err(dev, "taskqueue-node %d must less than %d\n", + taskqueue_node, mpp->srv->taskqueue_cnt); + ret = -ENODEV; + goto err_put_pdev; + } + if (ret) { /* if device not set, then alloc one */ - struct mpp_taskqueue *queue; - - queue = devm_kzalloc(dev, sizeof(*queue), GFP_KERNEL); - if (!queue) { - ret = -ENOMEM; + queue = mpp_taskqueue_init(dev); + if (!queue) goto err_put_pdev; - } - mpp_taskqueue_init(queue, mpp->srv); - mpp->queue = queue; } else { /* set taskqueue according dtsi */ - if (taskqueue_node >= mpp->srv->taskqueue_cnt) { - dev_err(dev, "taskqueue-node %d must less than %d\n", - taskqueue_node, mpp->srv->taskqueue_cnt); + queue = mpp->srv->task_queues[taskqueue_node]; + if (!queue) { + dev_err(dev, "taskqueue attach to invalid node %d\n", + taskqueue_node); ret = -ENODEV; goto err_put_pdev; - } else { - mpp->queue = mpp->srv->task_queues[taskqueue_node]; } } + mpp_attach_workqueue(mpp, queue); ret = of_property_read_u32(dev->of_node, "rockchip,resetgroup-node", &reset_group_node); @@ -777,20 +778,48 @@ err_put_pdev: return ret; } -int mpp_taskqueue_init(struct mpp_taskqueue *queue, - struct mpp_service *srv) +struct mpp_taskqueue *mpp_taskqueue_init(struct device *dev) { + struct mpp_taskqueue *queue = devm_kzalloc(dev, sizeof(*queue), + GFP_KERNEL); + if (!queue) + return NULL; + mutex_init(&queue->pending_lock); mutex_init(&queue->running_lock); mutex_init(&queue->mmu_lock); + mutex_init(&queue->dev_lock); INIT_LIST_HEAD(&queue->pending_list); INIT_LIST_HEAD(&queue->running_list); INIT_LIST_HEAD(&queue->mmu_list); - INIT_WORK(&queue->work, mpp_task_try_run); + INIT_LIST_HEAD(&queue->dev_list); + /* default taskqueue has max 16 task capacity */ + queue->task_capacity = MPP_MAX_TASK_CAPACITY; - queue->srv = srv; + return queue; +} - return 0; +static void mpp_attach_workqueue(struct mpp_dev *mpp, + struct mpp_taskqueue *queue) +{ + mpp->queue = queue; + INIT_LIST_HEAD(&mpp->queue_link); + mutex_lock(&queue->dev_lock); + list_add_tail(&mpp->queue_link, &queue->dev_list); + if (queue->task_capacity > mpp->task_capacity) + queue->task_capacity = mpp->task_capacity; + mutex_unlock(&queue->dev_lock); +} + +static void mpp_detach_workqueue(struct mpp_dev *mpp) +{ + struct mpp_taskqueue *queue = mpp->queue; + + if (queue) { + mutex_lock(&queue->dev_lock); + list_del_init(&mpp->queue_link); + mutex_unlock(&queue->dev_lock); + } } static int mpp_check_cmd_v1(__u32 cmd) @@ -1627,6 +1656,16 @@ int mpp_dev_probe(struct mpp_dev *mpp, struct device_node *np = dev->of_node; struct mpp_hw_info *hw_info = mpp->var->hw_info; + /* read link table capacity */ + ret = of_property_read_u32(np, "rockchip,task-capacity", + &mpp->task_capacity); + if (ret) { + mpp->task_capacity = 1; + INIT_WORK(&mpp->work, mpp_task_try_run); + } else { + INIT_WORK(&mpp->work, NULL); + } + /* Get and attach to service */ ret = mpp_attach_service(mpp, dev); if (ret) { @@ -1719,6 +1758,7 @@ failed_init: pm_runtime_put_sync(dev); failed: destroy_workqueue(mpp->workq); + mpp_detach_workqueue(mpp); device_init_wakeup(dev, false); pm_runtime_disable(dev); @@ -1738,6 +1778,7 @@ int mpp_dev_remove(struct mpp_dev *mpp) mpp->workq = NULL; } + mpp_detach_workqueue(mpp); device_init_wakeup(mpp->dev, false); pm_runtime_disable(mpp->dev); @@ -1788,7 +1829,7 @@ irqreturn_t mpp_dev_isr_sched(int irq, void *param) ret = mpp->dev_ops->isr(mpp); /* trigger current queue to run next task */ - mpp_taskqueue_trigger_work(mpp->queue, mpp->workq); + mpp_taskqueue_trigger_work(mpp); return ret; } diff --git a/drivers/video/rockchip/mpp/mpp_common.h b/drivers/video/rockchip/mpp/mpp_common.h index 1d93a59a4b54..ef0acc5772d2 100644 --- a/drivers/video/rockchip/mpp/mpp_common.h +++ b/drivers/video/rockchip/mpp/mpp_common.h @@ -26,6 +26,7 @@ #define MPP_MAX_MSG_NUM (16) #define MPP_MAX_REG_TRANS_NUM (60) +#define MPP_MAX_TASK_CAPACITY (16) /* define flags for mpp_request */ #define MPP_FLAGS_MULTI_MSG (0x00000001) #define MPP_FLAGS_LAST_MSG (0x00000002) @@ -277,6 +278,16 @@ struct mpp_dev { struct mpp_hw_ops *hw_ops; struct mpp_dev_ops *dev_ops; + /* per-device work for attached taskqueue */ + struct work_struct work; + /* task for work queue */ + struct workqueue_struct *workq; + /* + * The task capacity is the task queue length that hardware can accept. + * Default 1 means normal hardware can only accept one task at once. + */ + u32 task_capacity; + int irq; u32 irq_status; @@ -288,8 +299,6 @@ struct mpp_dev { atomic_t session_index; atomic_t task_count; atomic_t task_index; - /* task for work queue */ - struct workqueue_struct *workq; /* current task in running */ struct mpp_task *cur_task; /* set session max buffers */ @@ -299,6 +308,8 @@ struct mpp_dev { /* point to MPP Service */ struct platform_device *pdev_srv; struct mpp_service *srv; + + struct list_head queue_link; }; struct mpp_task; @@ -379,9 +390,6 @@ struct mpp_task { }; struct mpp_taskqueue { - /* work for taskqueue */ - struct work_struct work; - /* lock for pending list */ struct mutex pending_lock; struct list_head pending_list; @@ -394,6 +402,14 @@ struct mpp_taskqueue { /* lock for mmu list */ struct mutex mmu_lock; struct list_head mmu_list; + /* lock for dev list */ + struct mutex dev_lock; + struct list_head dev_list; + /* + * task_capacity in taskqueue is the minimum task capacity of the + * device task capacity which is attached to the taskqueue + */ + u32 task_capacity; }; struct mpp_reset_group { @@ -488,8 +504,7 @@ struct mpp_dev_ops { int (*dump_session)(struct mpp_session *session, struct seq_file *seq); }; -int mpp_taskqueue_init(struct mpp_taskqueue *queue, - struct mpp_service *srv); +struct mpp_taskqueue *mpp_taskqueue_init(struct device *dev); struct mpp_mem_region * mpp_task_attach_fd(struct mpp_task *task, int fd); diff --git a/drivers/video/rockchip/mpp/mpp_service.c b/drivers/video/rockchip/mpp/mpp_service.c index 430ea0715360..a25232a65ff2 100644 --- a/drivers/video/rockchip/mpp/mpp_service.c +++ b/drivers/video/rockchip/mpp/mpp_service.c @@ -310,11 +310,10 @@ static int mpp_service_probe(struct platform_device *pdev) struct mpp_taskqueue *queue; for (i = 0; i < srv->taskqueue_cnt; i++) { - queue = devm_kzalloc(dev, sizeof(*queue), GFP_KERNEL); + queue = mpp_taskqueue_init(dev); if (!queue) continue; - mpp_taskqueue_init(queue, srv); srv->task_queues[i] = queue; } }