mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
video: rockchip: mpp: vepu2: Fix multi-core vepu2 stuck on RK3588
Signed-off-by: Herman Chen <herman.chen@rock-chips.com> Change-Id: Idac11024e1cc98346e68a7f7f12f3e9f33d89c10
This commit is contained in:
@@ -715,7 +715,6 @@ static int mpp_task_run(struct mpp_dev *mpp,
|
||||
}
|
||||
|
||||
mpp_power_on(mpp);
|
||||
mpp_time_record(task);
|
||||
mpp_debug_func(DEBUG_TASK_INFO, "pid %d run %s\n",
|
||||
task->session->pid, dev_name(mpp->dev));
|
||||
|
||||
@@ -728,6 +727,7 @@ static int mpp_task_run(struct mpp_dev *mpp,
|
||||
mpp_reset_down_read(mpp->reset_group);
|
||||
|
||||
set_bit(TASK_STATE_START, &task->state);
|
||||
mpp_time_record(task);
|
||||
schedule_delayed_work(&task->timeout_work,
|
||||
msecs_to_jiffies(MPP_WORK_TIMEOUT_DELAY));
|
||||
if (mpp->dev_ops->run)
|
||||
@@ -2244,9 +2244,9 @@ int mpp_time_part_diff(struct mpp_task *task)
|
||||
struct mpp_dev *mpp = mpp_get_task_used_device(task, task->session);
|
||||
|
||||
end = ktime_get();
|
||||
mpp_debug(DEBUG_PART_TIMING, "%s: session %d:%d part time: %lld us\n",
|
||||
dev_name(mpp->dev), task->session->pid, task->session->index,
|
||||
ktime_us_delta(end, task->part));
|
||||
mpp_debug(DEBUG_PART_TIMING, "%s:%d session %d:%d part time: %lld us\n",
|
||||
dev_name(mpp->dev), task->core_id, task->session->pid,
|
||||
task->session->index, ktime_us_delta(end, task->part));
|
||||
task->part = end;
|
||||
|
||||
return 0;
|
||||
@@ -2258,9 +2258,9 @@ int mpp_time_diff(struct mpp_task *task)
|
||||
struct mpp_dev *mpp = mpp_get_task_used_device(task, task->session);
|
||||
|
||||
end = ktime_get();
|
||||
mpp_debug(DEBUG_TIMING, "%s: session %d:%d task time: %lld us\n",
|
||||
dev_name(mpp->dev), task->session->pid, task->session->index,
|
||||
ktime_us_delta(end, task->start));
|
||||
mpp_debug(DEBUG_TIMING, "%s:%d session %d:%d time: %lld us\n",
|
||||
dev_name(mpp->dev), task->core_id, task->session->pid,
|
||||
task->session->index, ktime_us_delta(end, task->start));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -293,92 +293,33 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct vepu_dev *vepu_core_balance(struct vepu_ccu *ccu)
|
||||
static void *vepu_prepare(struct mpp_dev *mpp, struct mpp_task *mpp_task)
|
||||
{
|
||||
struct vepu_dev *enc;
|
||||
struct vepu_dev *core = NULL, *n;
|
||||
struct mpp_taskqueue *queue = mpp->queue;
|
||||
unsigned long flags;
|
||||
s32 core_id;
|
||||
|
||||
mpp_debug_enter();
|
||||
spin_lock_irqsave(&queue->running_lock, flags);
|
||||
|
||||
mutex_lock(&ccu->lock);
|
||||
enc = list_first_entry(&ccu->core_list, struct vepu_dev, core_link);
|
||||
list_for_each_entry_safe(core, n, &ccu->core_list, core_link) {
|
||||
mpp_debug(DEBUG_DEVICE, "%s, disable_work=%d, task_count=%d, task_index=%d\n",
|
||||
dev_name(core->mpp.dev), core->disable_work,
|
||||
atomic_read(&core->mpp.task_count), atomic_read(&core->mpp.task_index));
|
||||
/* if core (except main-core) disabled, skip it */
|
||||
if (core->disable_work)
|
||||
continue;
|
||||
/* choose core with less task in queue */
|
||||
if (atomic_read(&core->mpp.task_count) < atomic_read(&enc->mpp.task_count)) {
|
||||
enc = core;
|
||||
break;
|
||||
}
|
||||
/* choose core with less task which done */
|
||||
if (atomic_read(&core->mpp.task_index) < atomic_read(&enc->mpp.task_index))
|
||||
enc = core;
|
||||
}
|
||||
mutex_unlock(&ccu->lock);
|
||||
core_id = find_first_bit(&queue->core_idle, queue->core_count);
|
||||
|
||||
mpp_debug_leave();
|
||||
if (core_id >= queue->core_count) {
|
||||
mpp_task = NULL;
|
||||
mpp_dbg_core("core %d all busy %lx\n", core_id, queue->core_idle);
|
||||
} else {
|
||||
unsigned long core_idle = queue->core_idle;
|
||||
|
||||
return enc;
|
||||
}
|
||||
clear_bit(core_id, &queue->core_idle);
|
||||
mpp_task->mpp = queue->cores[core_id];
|
||||
mpp_task->core_id = core_id;
|
||||
|
||||
static void *vepu_ccu_alloc_task(struct mpp_session *session,
|
||||
struct mpp_task_msgs *msgs)
|
||||
{
|
||||
int ret;
|
||||
struct mpp_task *mpp_task = NULL;
|
||||
struct vepu_task *task = NULL;
|
||||
struct mpp_dev *mpp = session->mpp;
|
||||
struct vepu_dev *enc = to_vepu_dev(mpp);
|
||||
|
||||
mpp_debug_enter();
|
||||
|
||||
task = kzalloc(sizeof(*task), GFP_KERNEL);
|
||||
if (!task)
|
||||
return NULL;
|
||||
|
||||
mpp_task = &task->mpp_task;
|
||||
/* if multicore, choose one for current task */
|
||||
if (enc->ccu) {
|
||||
enc = vepu_core_balance(enc->ccu);
|
||||
mpp_task->mpp = &enc->mpp;
|
||||
mpp = mpp_task->mpp;
|
||||
mpp_debug(DEBUG_TASK_INFO, "%s\n", dev_name(mpp->dev));
|
||||
mpp_dbg_core("core %d set idle %lx -> %lx\n", core_id,
|
||||
core_idle, queue->core_idle);
|
||||
}
|
||||
|
||||
mpp_task_init(session, mpp_task);
|
||||
mpp_task->hw_info = mpp->var->hw_info;
|
||||
mpp_task->reg = task->reg;
|
||||
/* extract reqs for current task */
|
||||
ret = vepu_extract_task_msg(task, msgs);
|
||||
if (ret)
|
||||
goto fail;
|
||||
/* process fd in register */
|
||||
if (!(msgs->flags & MPP_FLAGS_REG_FD_NO_TRANS)) {
|
||||
ret = vepu_process_reg_fd(session, task, msgs);
|
||||
if (ret)
|
||||
goto fail;
|
||||
}
|
||||
task->clk_mode = CLK_MODE_NORMAL;
|
||||
/* get resolution info */
|
||||
task->width = VEPU2_GET_WIDTH(task->reg[VEPU2_REG_ENC_EN_INDEX]);
|
||||
task->height = VEPU2_GET_HEIGHT(task->reg[VEPU2_REG_ENC_EN_INDEX]);
|
||||
task->pixels = task->width * task->height;
|
||||
mpp_debug(DEBUG_TASK_INFO, "width=%d, height=%d\n", task->width, task->height);
|
||||
|
||||
mpp_debug_leave();
|
||||
spin_unlock_irqrestore(&queue->running_lock, flags);
|
||||
|
||||
return mpp_task;
|
||||
|
||||
fail:
|
||||
mpp_task_dump_mem_region(mpp, mpp_task);
|
||||
mpp_task_dump_reg(mpp, mpp_task);
|
||||
mpp_task_finalize(session, mpp_task);
|
||||
kfree(task);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int vepu_run(struct mpp_dev *mpp,
|
||||
@@ -433,6 +374,8 @@ static int vepu_isr(struct mpp_dev *mpp)
|
||||
u32 err_mask;
|
||||
struct vepu_task *task = NULL;
|
||||
struct mpp_task *mpp_task = mpp->cur_task;
|
||||
struct mpp_taskqueue *queue = mpp->queue;
|
||||
unsigned long core_idle;
|
||||
|
||||
/* FIXME use a spin lock here */
|
||||
if (!mpp_task) {
|
||||
@@ -455,6 +398,12 @@ static int vepu_isr(struct mpp_dev *mpp)
|
||||
|
||||
mpp_task_finish(mpp_task->session, mpp_task);
|
||||
|
||||
core_idle = queue->core_idle;
|
||||
set_bit(mpp->core_id, &queue->core_idle);
|
||||
|
||||
mpp_dbg_core("core %d isr idle %lx -> %lx\n", mpp->core_id, core_idle,
|
||||
queue->core_idle);
|
||||
|
||||
mpp_debug_leave();
|
||||
|
||||
return IRQ_HANDLED;
|
||||
@@ -847,6 +796,7 @@ static int vepu_reduce_freq(struct mpp_dev *mpp)
|
||||
static int vepu_reset(struct mpp_dev *mpp)
|
||||
{
|
||||
struct vepu_dev *enc = to_vepu_dev(mpp);
|
||||
struct mpp_taskqueue *queue = mpp->queue;
|
||||
|
||||
if (enc->rst_a && enc->rst_h) {
|
||||
/* Don't skip this or iommu won't work after reset */
|
||||
@@ -860,6 +810,9 @@ static int vepu_reset(struct mpp_dev *mpp)
|
||||
}
|
||||
mpp_write(mpp, VEPU2_REG_INT, VEPU2_INT_CLEAR);
|
||||
|
||||
set_bit(mpp->core_id, &queue->core_idle);
|
||||
mpp_dbg_core("core %d reset idle %lx\n", mpp->core_id, queue->core_idle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -898,7 +851,8 @@ static struct mpp_dev_ops vepu_v2_dev_ops = {
|
||||
};
|
||||
|
||||
static struct mpp_dev_ops vepu_ccu_dev_ops = {
|
||||
.alloc_task = vepu_ccu_alloc_task,
|
||||
.alloc_task = vepu_alloc_task,
|
||||
.prepare = vepu_prepare,
|
||||
.run = vepu_run,
|
||||
.irq = vepu_irq,
|
||||
.isr = vepu_isr,
|
||||
|
||||
Reference in New Issue
Block a user