mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
video: rockchip: mpp: rkvdec2: Trigger reset when iommu pagefault
1. When iommu pagefault, hardware will stop and wait to deal with it. in order to respond quickly, such as NVR, reset the hardware directly. 2. The iommu handle should be for the current device, not the queue. and, the mpp_task_dump_hw_reg function is used to dump hardware register info, it no relation for task. 3. In the mode of link-mode and multi-core, it cannot accurately get task via queue->running_task, thereforce, it is not suitable to dump task register here. Change-Id: Ifed2cbc484997a07ed65c38c16062abe9b9aff81 Signed-off-by: Ding Wei <leo.ding@rock-chips.com>
This commit is contained in:
@@ -1928,15 +1928,12 @@ int mpp_task_dump_reg(struct mpp_dev *mpp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mpp_task_dump_hw_reg(struct mpp_dev *mpp, struct mpp_task *task)
|
||||
int mpp_task_dump_hw_reg(struct mpp_dev *mpp)
|
||||
{
|
||||
if (!task)
|
||||
return -EIO;
|
||||
|
||||
if (mpp_debug_unlikely(DEBUG_DUMP_ERR_REG)) {
|
||||
u32 i;
|
||||
u32 s = task->hw_info->reg_start;
|
||||
u32 e = task->hw_info->reg_end;
|
||||
u32 s = mpp->var->hw_info->reg_start;
|
||||
u32 e = mpp->var->hw_info->reg_end;
|
||||
|
||||
mpp_err("--- dump hardware register ---\n");
|
||||
for (i = s; i <= e; i++) {
|
||||
@@ -1955,22 +1952,10 @@ static int mpp_iommu_handle(struct iommu_domain *iommu,
|
||||
unsigned long iova,
|
||||
int status, void *arg)
|
||||
{
|
||||
struct mpp_taskqueue *queue = (struct mpp_taskqueue *)arg;
|
||||
struct mpp_task *task = mpp_taskqueue_get_running_task(queue);
|
||||
struct mpp_dev *mpp;
|
||||
struct mpp_dev *mpp = (struct mpp_dev *)arg;
|
||||
|
||||
/*
|
||||
* NOTE: In link mode, this task may not be the task of the current
|
||||
* hardware processing error
|
||||
*/
|
||||
if (!task || !task->session)
|
||||
return -EIO;
|
||||
/* get mpp from cur task */
|
||||
mpp = mpp_get_task_used_device(task, task->session);
|
||||
dev_err(mpp->dev, "fault addr 0x%08lx status %x\n", iova, status);
|
||||
|
||||
mpp_task_dump_mem_region(mpp, task);
|
||||
mpp_task_dump_hw_reg(mpp, task);
|
||||
mpp_task_dump_hw_reg(mpp);
|
||||
|
||||
if (mpp->iommu_info->hdl)
|
||||
mpp->iommu_info->hdl(iommu, iommu_dev, iova, status, arg);
|
||||
@@ -2075,7 +2060,7 @@ int mpp_dev_probe(struct mpp_dev *mpp,
|
||||
/* set iommu fault handler */
|
||||
if (mpp->iommu_info)
|
||||
iommu_set_fault_handler(mpp->iommu_info->domain,
|
||||
mpp_iommu_handle, mpp->queue);
|
||||
mpp_iommu_handle, mpp);
|
||||
|
||||
/* read hardware id */
|
||||
if (hw_info->reg_id >= 0) {
|
||||
|
||||
@@ -625,8 +625,7 @@ int mpp_task_dump_mem_region(struct mpp_dev *mpp,
|
||||
struct mpp_task *task);
|
||||
int mpp_task_dump_reg(struct mpp_dev *mpp,
|
||||
struct mpp_task *task);
|
||||
int mpp_task_dump_hw_reg(struct mpp_dev *mpp,
|
||||
struct mpp_task *task);
|
||||
int mpp_task_dump_hw_reg(struct mpp_dev *mpp);
|
||||
void mpp_free_task(struct kref *ref);
|
||||
|
||||
int mpp_session_deinit(struct mpp_session *session);
|
||||
|
||||
@@ -384,9 +384,8 @@ static int rkvdec2_isr(struct mpp_dev *mpp)
|
||||
RKVDEC_TIMEOUT_STA | RKVDEC_ERROR_STA;
|
||||
if (err_mask & task->irq_status) {
|
||||
atomic_inc(&mpp->reset_request);
|
||||
mpp_debug(DEBUG_DUMP_ERR_REG, "irq_status: %08x\n",
|
||||
task->irq_status);
|
||||
mpp_task_dump_hw_reg(mpp, mpp_task);
|
||||
mpp_debug(DEBUG_DUMP_ERR_REG, "irq_status: %08x\n", task->irq_status);
|
||||
mpp_task_dump_hw_reg(mpp);
|
||||
}
|
||||
|
||||
mpp_task_finish(mpp_task->session, mpp_task);
|
||||
@@ -1111,6 +1110,7 @@ static int rkvdec2_core_probe(struct platform_device *pdev)
|
||||
mpp->dev_ops->task_worker = rkvdec2_soft_ccu_worker;
|
||||
kthread_init_work(&mpp->work, rkvdec2_soft_ccu_worker);
|
||||
|
||||
mpp->iommu_info->hdl = rkvdec2_ccu_iommu_fault_handle;
|
||||
/* get irq request */
|
||||
ret = devm_request_threaded_irq(dev, mpp->irq, rkvdec2_soft_ccu_irq, NULL,
|
||||
IRQF_SHARED, dev_name(dev), mpp);
|
||||
|
||||
@@ -1672,8 +1672,11 @@ static int rkvdec2_soft_ccu_dequeue(struct mpp_taskqueue *queue)
|
||||
task->irq_status = irq_status;
|
||||
mpp_debug(DEBUG_IRQ_CHECK, "irq_status=%08x, timeout=%u, abort=%u\n",
|
||||
irq_status, timeout_flag, abort_flag);
|
||||
if (mpp->dev_ops->finish)
|
||||
if (irq_status && mpp->dev_ops->finish)
|
||||
mpp->dev_ops->finish(mpp, mpp_task);
|
||||
else
|
||||
task->reg[RKVDEC_REG_INT_EN_INDEX] = RKVDEC_TIMEOUT_STA;
|
||||
|
||||
set_bit(TASK_STATE_FINISH, &mpp_task->state);
|
||||
set_bit(TASK_STATE_DONE, &mpp_task->state);
|
||||
|
||||
@@ -1771,6 +1774,26 @@ void *rkvdec2_ccu_alloc_task(struct mpp_session *session,
|
||||
return &task->mpp_task;
|
||||
}
|
||||
|
||||
int rkvdec2_ccu_iommu_fault_handle(struct iommu_domain *iommu,
|
||||
struct device *iommu_dev,
|
||||
unsigned long iova, int status, void *arg)
|
||||
{
|
||||
u32 i = 0;
|
||||
struct mpp_dev *mpp = (struct mpp_dev *)arg;
|
||||
|
||||
mpp_debug_enter();
|
||||
|
||||
atomic_inc(&mpp->queue->reset_request);
|
||||
for (i = 0; i < mpp->queue->core_count; i++)
|
||||
rk_iommu_mask_irq(mpp->queue->cores[i]->dev);
|
||||
|
||||
kthread_queue_work(&mpp->queue->worker, &mpp->work);
|
||||
|
||||
mpp_debug_leave();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
irqreturn_t rkvdec2_soft_ccu_irq(int irq, void *param)
|
||||
{
|
||||
struct mpp_dev *mpp = param;
|
||||
|
||||
@@ -171,6 +171,9 @@ void rkvdec2_link_session_deinit(struct mpp_session *session);
|
||||
int rkvdec2_attach_ccu(struct device *dev, struct rkvdec2_dev *dec);
|
||||
int rkvdec2_ccu_link_init(struct platform_device *pdev, struct rkvdec2_dev *dec);
|
||||
void *rkvdec2_ccu_alloc_task(struct mpp_session *session, struct mpp_task_msgs *msgs);
|
||||
int rkvdec2_ccu_iommu_fault_handle(struct iommu_domain *iommu,
|
||||
struct device *iommu_dev,
|
||||
unsigned long iova, int status, void *arg);
|
||||
irqreturn_t rkvdec2_soft_ccu_irq(int irq, void *param);
|
||||
void rkvdec2_soft_ccu_worker(struct kthread_work *work_s);
|
||||
|
||||
|
||||
@@ -524,11 +524,8 @@ static int rkvenc_isr(struct mpp_dev *mpp)
|
||||
if (task->irq_status & RKVENC_INT_ERROR_BITS) {
|
||||
atomic_inc(&mpp->reset_request);
|
||||
/* dump register */
|
||||
if (mpp_debug_unlikely(DEBUG_DUMP_ERR_REG)) {
|
||||
mpp_debug(DEBUG_DUMP_ERR_REG, "irq_status: %08x\n",
|
||||
task->irq_status);
|
||||
mpp_task_dump_hw_reg(mpp, mpp_task);
|
||||
}
|
||||
mpp_debug(DEBUG_DUMP_ERR_REG, "irq_status: %08x\n", task->irq_status);
|
||||
mpp_task_dump_hw_reg(mpp);
|
||||
}
|
||||
|
||||
/* unmap reserve buffer */
|
||||
|
||||
@@ -857,8 +857,8 @@ static int rkvenc_isr(struct mpp_dev *mpp)
|
||||
if (task->irq_status & enc->hw_info->err_mask) {
|
||||
atomic_inc(&mpp->reset_request);
|
||||
/* dump register */
|
||||
if (mpp_debug_unlikely(DEBUG_DUMP_ERR_REG))
|
||||
mpp_task_dump_hw_reg(mpp, mpp_task);
|
||||
|
||||
mpp_task_dump_hw_reg(mpp);
|
||||
}
|
||||
mpp_task_finish(mpp_task->session, mpp_task);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user