mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 04:10:18 +09:00
video: rockchip: mpp: re-write mpp_wait_result
1. use task->state to mark the state of task in taskqueue. 2. add delay work in case of hardware dead, then abort current task. 3. if wait timeout, set task->abort_requet for work thread to abort it. relative dump stack: <4>[84461.189906] __list_del_entry_valid+0x30/0x9c <4>[84461.190616] cc60 00000000 00000000 00000000 00000048 00014b0e 00000550 00000598 00000620 <4>[84461.191018] mpp_task_finish+0x108/0x15c <4>[84461.191735] <4>[84461.191735] X29: 0xffffff800e0cba50: <4>[84461.192100] vdpu_isr+0x60/0xbc <4>[84461.192536] ba50 00000000 ffffff80 f153c4c0 ffffffc0 08109fe0 ffffff80 0e0cba68 ffffff80 <4>[84461.192828] mpp_dev_isr_sched+0x4c/0x94 <4>[84461.193545] ba70 0e0cba68 ffffff80 b8a42e00 04d029b0 f0401000 ffffffc0 00000000 00000000 Change-Id: I2391a97fca4b6a7fddbf88a05cedf6f2fe564be0 Signed-off-by: Ding Wei <leo.ding@rock-chips.com>
This commit is contained in:
@@ -31,8 +31,8 @@
|
||||
#include "mpp_common.h"
|
||||
#include "mpp_iommu.h"
|
||||
|
||||
#define MPP_TIMEOUT_DELAY (2000)
|
||||
#define MPP_SESSION_MAX_DONE_TASK (20)
|
||||
#define MPP_WORK_TIMEOUT_DELAY (200)
|
||||
#define MPP_WAIT_TIMEOUT_DELAY (2000)
|
||||
|
||||
/* Use 'v' as magic number */
|
||||
#define MPP_IOC_MAGIC 'v'
|
||||
@@ -56,20 +56,48 @@ struct mpp_msg_v1 {
|
||||
__u64 data_ptr;
|
||||
};
|
||||
|
||||
static void mpp_task_try_run(struct work_struct *work_s);
|
||||
static void mpp_free_task(struct kref *ref);
|
||||
static int mpp_dev_reset(struct mpp_dev *mpp);
|
||||
|
||||
/* task queue schedule */
|
||||
static int
|
||||
mpp_taskqueue_push_pending(struct mpp_taskqueue *queue,
|
||||
struct mpp_task *task)
|
||||
{
|
||||
struct mpp_dev *mpp;
|
||||
|
||||
if (!task->session || !task->session->mpp)
|
||||
return -EINVAL;
|
||||
mpp = task->session->mpp;
|
||||
|
||||
kref_get(&task->ref);
|
||||
atomic_inc(&mpp->task_count);
|
||||
mutex_lock(&queue->pending_lock);
|
||||
list_add_tail(&task->pending_link, &queue->pending_list);
|
||||
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)
|
||||
{
|
||||
struct mpp_dev *mpp;
|
||||
|
||||
if (!task->session || !task->session->mpp)
|
||||
return -EINVAL;
|
||||
mpp = task->session->mpp;
|
||||
|
||||
mutex_lock(&queue->pending_lock);
|
||||
list_del_init(&task->queue_link);
|
||||
mutex_unlock(&queue->pending_lock);
|
||||
atomic_dec(&mpp->task_count);
|
||||
kref_put(&task->ref, mpp_free_task);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mpp_task *
|
||||
mpp_taskqueue_get_pending_task(struct mpp_taskqueue *queue)
|
||||
{
|
||||
@@ -78,7 +106,7 @@ mpp_taskqueue_get_pending_task(struct mpp_taskqueue *queue)
|
||||
mutex_lock(&queue->pending_lock);
|
||||
task = list_first_entry_or_null(&queue->pending_list,
|
||||
struct mpp_task,
|
||||
pending_link);
|
||||
queue_link);
|
||||
mutex_unlock(&queue->pending_lock);
|
||||
|
||||
return task;
|
||||
@@ -100,12 +128,10 @@ static int
|
||||
mpp_taskqueue_pending_to_run(struct mpp_taskqueue *queue,
|
||||
struct mpp_task *task)
|
||||
{
|
||||
mutex_lock(&queue->running_lock);
|
||||
list_add_tail(&task->running_link, &queue->running_list);
|
||||
mutex_unlock(&queue->running_lock);
|
||||
|
||||
mutex_lock(&queue->pending_lock);
|
||||
list_del_init(&task->pending_link);
|
||||
mutex_lock(&queue->running_lock);
|
||||
list_move_tail(&task->queue_link, &queue->running_list);
|
||||
mutex_unlock(&queue->running_lock);
|
||||
mutex_unlock(&queue->pending_lock);
|
||||
|
||||
return 0;
|
||||
@@ -119,19 +145,27 @@ mpp_taskqueue_get_running_task(struct mpp_taskqueue *queue)
|
||||
mutex_lock(&queue->running_lock);
|
||||
task = list_first_entry_or_null(&queue->running_list,
|
||||
struct mpp_task,
|
||||
running_link);
|
||||
queue_link);
|
||||
mutex_unlock(&queue->running_lock);
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
static int
|
||||
mpp_taskqueue_done(struct mpp_taskqueue *queue,
|
||||
struct mpp_task *task)
|
||||
mpp_taskqueue_pop_running(struct mpp_taskqueue *queue,
|
||||
struct mpp_task *task)
|
||||
{
|
||||
struct mpp_dev *mpp;
|
||||
|
||||
if (!task->session || !task->session->mpp)
|
||||
return -EINVAL;
|
||||
mpp = task->session->mpp;
|
||||
|
||||
mutex_lock(&queue->running_lock);
|
||||
list_del_init(&task->running_link);
|
||||
list_del_init(&task->queue_link);
|
||||
mutex_unlock(&queue->running_lock);
|
||||
atomic_dec(&mpp->task_count);
|
||||
kref_put(&task->ref, mpp_free_task);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -174,47 +208,123 @@ static int
|
||||
mpp_session_push_pending(struct mpp_session *session,
|
||||
struct mpp_task *task)
|
||||
{
|
||||
kref_get(&task->ref);
|
||||
atomic_inc(&session->task_count);
|
||||
mutex_lock(&session->pending_lock);
|
||||
list_add_tail(&task->session_link, &session->pending_list);
|
||||
list_add_tail(&task->pending_link, &session->pending_list);
|
||||
mutex_unlock(&session->pending_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpp_session_push_done(struct mpp_task *task)
|
||||
static int
|
||||
mpp_session_pop_pending(struct mpp_session *session,
|
||||
struct mpp_task *task)
|
||||
{
|
||||
struct mpp_session *session = NULL;
|
||||
|
||||
session = task->session;
|
||||
|
||||
mutex_lock(&session->pending_lock);
|
||||
list_del_init(&task->session_link);
|
||||
list_del_init(&task->pending_link);
|
||||
mutex_unlock(&session->pending_lock);
|
||||
|
||||
mutex_lock(&session->done_lock);
|
||||
kfifo_in(&session->done_fifo, &task, 1);
|
||||
mutex_unlock(&session->done_lock);
|
||||
|
||||
wake_up(&session->wait);
|
||||
atomic_dec(&session->task_count);
|
||||
kref_put(&task->ref, mpp_free_task);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mpp_task *
|
||||
mpp_session_pull_done(struct mpp_session *session)
|
||||
mpp_session_get_pending_task(struct mpp_session *session)
|
||||
{
|
||||
int ret;
|
||||
struct mpp_task *task = NULL;
|
||||
|
||||
mutex_lock(&session->done_lock);
|
||||
ret = kfifo_out(&session->done_fifo, &task, 1);
|
||||
mutex_unlock(&session->done_lock);
|
||||
if (!ret)
|
||||
task = NULL;
|
||||
mutex_lock(&session->pending_lock);
|
||||
task = list_first_entry_or_null(&session->pending_list,
|
||||
struct mpp_task,
|
||||
pending_link);
|
||||
mutex_unlock(&session->pending_lock);
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
static int mpp_session_push_done(struct mpp_session *session,
|
||||
struct mpp_task *task)
|
||||
{
|
||||
kref_get(&task->ref);
|
||||
mutex_lock(&session->done_lock);
|
||||
list_add_tail(&task->done_link, &session->done_list);
|
||||
mutex_unlock(&session->done_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpp_session_pop_done(struct mpp_session *session,
|
||||
struct mpp_task *task)
|
||||
{
|
||||
mutex_lock(&session->done_lock);
|
||||
list_del_init(&task->done_link);
|
||||
mutex_unlock(&session->done_lock);
|
||||
kref_put(&task->ref, mpp_free_task);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mpp_free_task(struct kref *ref)
|
||||
{
|
||||
struct mpp_dev *mpp;
|
||||
struct mpp_session *session;
|
||||
struct mpp_task *task = container_of(ref, struct mpp_task, ref);
|
||||
|
||||
if (!task->session) {
|
||||
mpp_err("task %p, task->session is null.\n", task);
|
||||
return;
|
||||
}
|
||||
session = task->session;
|
||||
|
||||
mpp_debug_func(DEBUG_TASK_INFO,
|
||||
"session=%p, task=%p, state=%08x, abort_request=%d\n",
|
||||
session, task, task->state,
|
||||
atomic_read(&task->abort_request));
|
||||
|
||||
if (!session->mpp) {
|
||||
mpp_err("session %p, session->mpp is null.\n", session);
|
||||
return;
|
||||
}
|
||||
mpp = session->mpp;
|
||||
|
||||
if (mpp->dev_ops->free_task)
|
||||
mpp->dev_ops->free_task(session, task);
|
||||
}
|
||||
|
||||
static void mpp_task_timeout_work(struct work_struct *work_s)
|
||||
{
|
||||
struct mpp_dev *mpp;
|
||||
struct mpp_session *session;
|
||||
struct mpp_task *task = container_of(to_delayed_work(work_s),
|
||||
struct mpp_task,
|
||||
timeout_work);
|
||||
|
||||
mpp_err("task %p processing timed out!\n", task);
|
||||
|
||||
if (!task->session) {
|
||||
mpp_err("task %p, task->session is null.\n", task);
|
||||
return;
|
||||
}
|
||||
session = task->session;
|
||||
|
||||
if (!session->mpp) {
|
||||
mpp_err("session %p, session->mpp is null.\n", session);
|
||||
return;
|
||||
}
|
||||
mpp = session->mpp;
|
||||
|
||||
/* hardware maybe dead, reset it */
|
||||
up_read(&mpp->reset_group->rw_sem);
|
||||
mpp_dev_reset(mpp);
|
||||
mpp_power_off(mpp);
|
||||
|
||||
/* remove task from taskqueue running list */
|
||||
task->state = TASK_STATE_TIMEOUT;
|
||||
mpp_taskqueue_pop_running(mpp->queue, task);
|
||||
}
|
||||
|
||||
static int mpp_process_task(struct mpp_session *session,
|
||||
struct mpp_task_msgs *msgs)
|
||||
{
|
||||
@@ -233,6 +343,9 @@ static int mpp_process_task(struct mpp_session *session,
|
||||
mpp_err("alloc_task failed.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
kref_init(&task->ref);
|
||||
atomic_set(&task->abort_request, 0);
|
||||
INIT_DELAYED_WORK(&task->timeout_work, mpp_task_timeout_work);
|
||||
|
||||
if (mpp->hw_ops->get_freq)
|
||||
mpp->hw_ops->get_freq(mpp, task);
|
||||
@@ -246,25 +359,14 @@ static int mpp_process_task(struct mpp_session *session,
|
||||
mpp_session_push_pending(session, task);
|
||||
/* push current task to queue */
|
||||
mpp_taskqueue_push_pending(mpp->queue, task);
|
||||
atomic_inc(&session->task_count);
|
||||
atomic_inc(&mpp->task_count);
|
||||
task->state = TASK_STATE_PENDING;
|
||||
/* trigger current queue to run task */
|
||||
mpp_taskqueue_trigger_work(mpp->queue, mpp->workq);
|
||||
kref_put(&task->ref, mpp_free_task);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mpp_free_task(struct mpp_session *session,
|
||||
struct mpp_task *task)
|
||||
{
|
||||
struct mpp_dev *mpp = session->mpp;
|
||||
|
||||
if (mpp->dev_ops->free_task)
|
||||
mpp->dev_ops->free_task(session, task);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpp_refresh_pm_runtime(struct device *dev)
|
||||
{
|
||||
struct device_link *link;
|
||||
@@ -403,33 +505,6 @@ static int mpp_dev_reset(struct mpp_dev *mpp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpp_dev_abort(struct mpp_dev *mpp)
|
||||
{
|
||||
struct mpp_task *task = NULL;
|
||||
|
||||
mpp_debug_enter();
|
||||
|
||||
up_read(&mpp->reset_group->rw_sem);
|
||||
|
||||
mpp_dev_reset(mpp);
|
||||
/* destroy the current task after hardware reset */
|
||||
task = mpp_taskqueue_get_running_task(mpp->queue);
|
||||
if (task) {
|
||||
mutex_lock(&task->session->pending_lock);
|
||||
list_del_init(&task->session_link);
|
||||
mutex_unlock(&task->session->pending_lock);
|
||||
mpp_taskqueue_done(mpp->queue, task);
|
||||
atomic_dec(&task->session->task_count);
|
||||
mpp_free_task(task->session, task);
|
||||
} else {
|
||||
mpp_err("error: task is null!\n");
|
||||
}
|
||||
|
||||
mpp_debug_leave();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpp_task_run(struct mpp_dev *mpp,
|
||||
struct mpp_task *task)
|
||||
{
|
||||
@@ -471,9 +546,11 @@ static int mpp_task_run(struct mpp_dev *mpp,
|
||||
* TODO: Lock the reader locker of the device resource lock here,
|
||||
* release at the finish operation
|
||||
*/
|
||||
|
||||
down_read(&mpp->reset_group->rw_sem);
|
||||
|
||||
task->state = TASK_STATE_START;
|
||||
schedule_delayed_work(&task->timeout_work,
|
||||
msecs_to_jiffies(MPP_WORK_TIMEOUT_DELAY));
|
||||
if (mpp->dev_ops->run)
|
||||
mpp->dev_ops->run(mpp, task);
|
||||
|
||||
@@ -496,6 +573,12 @@ static void mpp_task_try_run(struct work_struct *work_s)
|
||||
if (!task)
|
||||
goto done;
|
||||
|
||||
/* if task timeout and aborted, remove it */
|
||||
if (atomic_read(&task->abort_request) > 0) {
|
||||
mpp_taskqueue_pop_pending(queue, task);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* get device for current task */
|
||||
mpp = task->session->mpp;
|
||||
|
||||
@@ -519,7 +602,9 @@ static void mpp_task_try_run(struct work_struct *work_s)
|
||||
/* Push a pending task to running queue */
|
||||
if (task) {
|
||||
mpp_taskqueue_pending_to_run(queue, task);
|
||||
mpp_task_run(mpp, task);
|
||||
task->state = TASK_STATE_RUNNING;
|
||||
if (mpp_task_run(mpp, task))
|
||||
mpp_taskqueue_pop_running(mpp->queue, task);
|
||||
}
|
||||
|
||||
done:
|
||||
@@ -529,46 +614,33 @@ done:
|
||||
static int mpp_session_clear(struct mpp_dev *mpp,
|
||||
struct mpp_session *session)
|
||||
{
|
||||
struct mpp_task *task, *n, *task_done;
|
||||
struct mpp_task *task = NULL, *n;
|
||||
|
||||
/* clear task which have done */
|
||||
/* clear session done list */
|
||||
mutex_lock(&session->done_lock);
|
||||
while (kfifo_out(&session->done_fifo, &task_done, 1))
|
||||
mpp_free_task(session, task_done);
|
||||
list_for_each_entry_safe(task, n,
|
||||
&session->done_list,
|
||||
done_link) {
|
||||
list_del_init(&task->done_link);
|
||||
kref_put(&task->ref, mpp_free_task);
|
||||
}
|
||||
mutex_unlock(&session->done_lock);
|
||||
|
||||
/* clear task which have not start */
|
||||
/* clear session pending list */
|
||||
mutex_lock(&session->pending_lock);
|
||||
list_for_each_entry_safe(task, n,
|
||||
&session->pending_list,
|
||||
session_link) {
|
||||
list_del_init(&task->session_link);
|
||||
mpp_free_task(session, task);
|
||||
pending_link) {
|
||||
/* abort task in taskqueue */
|
||||
atomic_inc(&task->abort_request);
|
||||
list_del_init(&task->pending_link);
|
||||
kref_put(&task->ref, mpp_free_task);
|
||||
}
|
||||
mutex_unlock(&session->pending_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpp_task_result(struct mpp_dev *mpp,
|
||||
struct mpp_task *task,
|
||||
struct mpp_task_msgs *msgs)
|
||||
{
|
||||
mpp_debug_enter();
|
||||
|
||||
if (!mpp || !task)
|
||||
return -EINVAL;
|
||||
|
||||
if (mpp->dev_ops->result)
|
||||
mpp->dev_ops->result(mpp, task, msgs);
|
||||
|
||||
mpp_free_task(task->session, task);
|
||||
|
||||
mpp_debug_leave();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpp_wait_result(struct mpp_session *session,
|
||||
struct mpp_task_msgs *msgs)
|
||||
{
|
||||
@@ -583,19 +655,57 @@ static int mpp_wait_result(struct mpp_session *session,
|
||||
}
|
||||
|
||||
ret = wait_event_timeout(session->wait,
|
||||
!kfifo_is_empty(&session->done_fifo),
|
||||
msecs_to_jiffies(MPP_TIMEOUT_DELAY));
|
||||
if (ret > 0) {
|
||||
task = mpp_session_pull_done(session);
|
||||
ret = mpp_task_result(mpp, task, msgs);
|
||||
} else {
|
||||
mpp_err("pid %d wait %d task done timeout.\n",
|
||||
session->pid, atomic_read(&session->task_count));
|
||||
mpp_dev_abort(mpp);
|
||||
ret = -ETIMEDOUT;
|
||||
!list_empty(&session->done_list),
|
||||
msecs_to_jiffies(MPP_WAIT_TIMEOUT_DELAY));
|
||||
|
||||
task = mpp_session_get_pending_task(session);
|
||||
if (!task) {
|
||||
mpp_err("session %p pending list is empty!\n", session);
|
||||
return -EIO;
|
||||
}
|
||||
atomic_dec(&mpp->task_count);
|
||||
mpp_power_off(mpp);
|
||||
|
||||
if (ret > 0) {
|
||||
u32 task_found = 0;
|
||||
struct mpp_task *loop = NULL, *n;
|
||||
|
||||
/* find task in session done list */
|
||||
mutex_lock(&session->done_lock);
|
||||
list_for_each_entry_safe(loop, n,
|
||||
&session->done_list,
|
||||
done_link) {
|
||||
if (loop == task) {
|
||||
task_found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&session->done_lock);
|
||||
if (task_found) {
|
||||
if (mpp->dev_ops->result)
|
||||
ret = mpp->dev_ops->result(mpp, task, msgs);
|
||||
mpp_session_pop_done(session, task);
|
||||
} else {
|
||||
mpp_err("session %p task %p, not found in done list!\n",
|
||||
session, task);
|
||||
ret = -EIO;
|
||||
}
|
||||
} else {
|
||||
atomic_inc(&task->abort_request);
|
||||
mpp_err("timeout, pid %d session %p count %d cur_task %p.\n",
|
||||
session->pid, session,
|
||||
atomic_read(&session->task_count), task);
|
||||
/* if twice and return timeout, otherwise, re-wait */
|
||||
if (atomic_read(&task->abort_request) > 1) {
|
||||
mpp_err("session %p, task %p abort wait twice!\n",
|
||||
session, task);
|
||||
ret = -ETIMEDOUT;
|
||||
} else {
|
||||
ret = mpp_wait_result(session, msgs);
|
||||
}
|
||||
}
|
||||
|
||||
mpp_debug_func(DEBUG_TASK_INFO,
|
||||
"kref_read=%d, ret=%d\n", kref_read(&task->ref), ret);
|
||||
mpp_session_pop_pending(session, task);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1027,7 +1137,6 @@ static long mpp_dev_ioctl(struct file *filp,
|
||||
|
||||
static int mpp_dev_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
int ret;
|
||||
struct mpp_session *session = NULL;
|
||||
struct mpp_service *srv = container_of(inode->i_cdev,
|
||||
struct mpp_service,
|
||||
@@ -1041,30 +1150,21 @@ static int mpp_dev_open(struct inode *inode, struct file *filp)
|
||||
session->srv = srv;
|
||||
session->pid = current->pid;
|
||||
|
||||
mutex_init(&session->pending_lock);
|
||||
mutex_init(&session->reg_lock);
|
||||
mutex_init(&session->pending_lock);
|
||||
mutex_init(&session->done_lock);
|
||||
INIT_LIST_HEAD(&session->pending_list);
|
||||
init_waitqueue_head(&session->wait);
|
||||
ret = kfifo_alloc(&session->done_fifo,
|
||||
MPP_SESSION_MAX_DONE_TASK,
|
||||
GFP_KERNEL);
|
||||
if (ret < 0) {
|
||||
ret = -ENOMEM;
|
||||
goto failed_kfifo;
|
||||
}
|
||||
INIT_LIST_HEAD(&session->done_list);
|
||||
|
||||
init_waitqueue_head(&session->wait);
|
||||
atomic_set(&session->task_count, 0);
|
||||
atomic_set(&session->release_request, 0);
|
||||
|
||||
filp->private_data = (void *)session;
|
||||
|
||||
mpp_debug_leave();
|
||||
|
||||
return nonseekable_open(inode, filp);
|
||||
|
||||
failed_kfifo:
|
||||
kfree(session);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mpp_dev_release(struct inode *inode, struct file *filp)
|
||||
@@ -1087,7 +1187,8 @@ static int mpp_dev_release(struct inode *inode, struct file *filp)
|
||||
&session->task_count,
|
||||
val, val == 0, 1000, 50000);
|
||||
if (ret == -ETIMEDOUT)
|
||||
mpp_err("wait total running time out\n");
|
||||
mpp_err("session %p, wait task count %d time out\n",
|
||||
session, atomic_read(&session->task_count));
|
||||
wake_up(&session->wait);
|
||||
|
||||
/* release device resource */
|
||||
@@ -1104,7 +1205,6 @@ static int mpp_dev_release(struct inode *inode, struct file *filp)
|
||||
up_read(&mpp->iommu_info->rw_sem);
|
||||
}
|
||||
|
||||
kfifo_free(&session->done_fifo);
|
||||
kfree(session);
|
||||
filp->private_data = NULL;
|
||||
|
||||
@@ -1120,7 +1220,7 @@ mpp_dev_poll(struct file *filp, poll_table *wait)
|
||||
(struct mpp_session *)filp->private_data;
|
||||
|
||||
poll_wait(filp, &session->wait, wait);
|
||||
if (kfifo_len(&session->done_fifo))
|
||||
if (!list_empty(&session->done_list))
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
|
||||
return mask;
|
||||
@@ -1298,9 +1398,8 @@ int mpp_translate_reg_offset_info(struct mpp_task *task,
|
||||
int mpp_task_init(struct mpp_session *session,
|
||||
struct mpp_task *task)
|
||||
{
|
||||
INIT_LIST_HEAD(&task->session_link);
|
||||
INIT_LIST_HEAD(&task->pending_link);
|
||||
INIT_LIST_HEAD(&task->running_link);
|
||||
INIT_LIST_HEAD(&task->queue_link);
|
||||
INIT_LIST_HEAD(&task->mem_region_list);
|
||||
|
||||
task->session = session;
|
||||
@@ -1315,16 +1414,19 @@ int mpp_task_finish(struct mpp_session *session,
|
||||
|
||||
if (mpp->dev_ops->finish)
|
||||
mpp->dev_ops->finish(mpp, task);
|
||||
atomic_dec(&session->task_count);
|
||||
|
||||
up_read(&mpp->reset_group->rw_sem);
|
||||
|
||||
if (atomic_read(&mpp->reset_request) > 0)
|
||||
mpp_dev_reset(mpp);
|
||||
mpp_power_off(mpp);
|
||||
|
||||
/* Wake up the GET thread */
|
||||
mpp_session_push_done(task);
|
||||
mpp_taskqueue_done(mpp->queue, task);
|
||||
if (!atomic_read(&task->abort_request)) {
|
||||
mpp_session_push_done(session, task);
|
||||
/* Wake up the GET thread */
|
||||
wake_up(&session->wait);
|
||||
}
|
||||
task->state = TASK_STATE_DONE;
|
||||
mpp_taskqueue_pop_running(mpp->queue, task);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1574,6 +1676,10 @@ irqreturn_t mpp_dev_isr_sched(int irq, void *param)
|
||||
list_empty(&mpp->queue->pending_list))
|
||||
mpp->hw_ops->reduce_freq(mpp);
|
||||
|
||||
if (mpp->cur_task) {
|
||||
mpp->cur_task->state = TASK_STATE_IRQ;
|
||||
cancel_delayed_work(&mpp->cur_task->timeout_work);
|
||||
}
|
||||
if (mpp->dev_ops->isr)
|
||||
ret = mpp->dev_ops->isr(mpp);
|
||||
|
||||
|
||||
@@ -213,17 +213,18 @@ struct mpp_session {
|
||||
struct mpp_dev *mpp;
|
||||
struct mpp_dma_session *dma;
|
||||
|
||||
/* lock for session task pending list */
|
||||
struct mutex pending_lock;
|
||||
/* lock for session task register list */
|
||||
struct mutex reg_lock;
|
||||
/* lock for session task done list */
|
||||
struct mutex done_lock;
|
||||
/* lock for session task pending list */
|
||||
struct mutex pending_lock;
|
||||
/* task pending list in session */
|
||||
struct list_head pending_list;
|
||||
/* lock for session task done list */
|
||||
struct mutex done_lock;
|
||||
/* task done list in session */
|
||||
struct list_head done_list;
|
||||
|
||||
DECLARE_KFIFO_PTR(done_fifo, struct mpp_task *);
|
||||
|
||||
/* event for session wait thread */
|
||||
wait_queue_head_t wait;
|
||||
pid_t pid;
|
||||
atomic_t task_count;
|
||||
@@ -233,20 +234,37 @@ struct mpp_session {
|
||||
u16 trans_table[MPP_MAX_REG_TRANS_NUM];
|
||||
};
|
||||
|
||||
/* task state in work thread */
|
||||
enum mpp_task_state {
|
||||
TASK_STATE_PENDING = BIT(0),
|
||||
TASK_STATE_RUNNING = BIT(1),
|
||||
TASK_STATE_START = BIT(2),
|
||||
TASK_STATE_IRQ = BIT(3),
|
||||
TASK_STATE_DONE = BIT(4),
|
||||
TASK_STATE_TIMEOUT = BIT(5),
|
||||
};
|
||||
|
||||
/* The context for the a task */
|
||||
struct mpp_task {
|
||||
/* context belong to */
|
||||
struct mpp_session *session;
|
||||
|
||||
/* link to session pending_list */
|
||||
struct list_head session_link;
|
||||
/* link to taskqueue node pending_list */
|
||||
/* link to pending list in session */
|
||||
struct list_head pending_link;
|
||||
/* link to taskqueue node running_list */
|
||||
struct list_head running_link;
|
||||
/* link to done list in session */
|
||||
struct list_head done_link;
|
||||
/* link to list in taskqueue */
|
||||
struct list_head queue_link;
|
||||
/* The DMA buffer used in this task */
|
||||
struct list_head mem_region_list;
|
||||
|
||||
/* state in the taskqueue */
|
||||
enum mpp_task_state state;
|
||||
atomic_t abort_request;
|
||||
/* delayed work for hardware timeout */
|
||||
struct delayed_work timeout_work;
|
||||
struct kref ref;
|
||||
|
||||
/* record context running start time */
|
||||
struct timeval start;
|
||||
/* hardware info for current task */
|
||||
|
||||
Reference in New Issue
Block a user