From 472cb33488945b97e5bfdba9d7571a38187dc952 Mon Sep 17 00:00:00 2001 From: Ding Wei Date: Fri, 15 Oct 2021 11:15:17 +0800 Subject: [PATCH] video: rockchip: mpp: Use spinlock for queue->running_lock reason: mpp_iommu_handle is called by irq for iommu, thus it cannot use mutex which might case sleep, thus use spinlock instead. Call trace: [ 71.047958 ] Call trace: [ 71.047974 ] dump_backtrace+0x0/0x160 [ 71.047988 ] show_stack+0x14/0x1c [ 71.048003 ] dump_stack+0xd0/0x120 [ 71.048018 ] ___might_sleep+0x1f4/0x204 [ 71.048032 ] __might_sleep+0x4c/0x80 [ 71.048045 ] __mutex_lock_common+0x60/0x1028 [ 71.048057 ] mutex_lock_nested+0x28/0x30 [ 71.048073 ] mpp_iommu_handle+0x44/0x1c8 [ 71.048088 ] report_iommu_fault+0x3c/0x198 [ 71.048102 ] rk_iommu_irq+0x2a4/0x3bc [ 71.048117 ] __handle_irq_event_percpu+0x114/0x3c4 [ 71.048131 ] handle_irq_event+0x5c/0xd0 [ 71.048143 ] handle_fasteoi_irq+0x124/0x220 [ 71.048156 ] __handle_domain_irq+0x9c/0xf4 [ 71.048169 ] gic_handle_irq+0x108/0x180 [ 71.048181 ] el1_irq+0xec/0x1a0 [ 71.048194 ] _raw_spin_unlock_irqrestore+0x3c/0x78 [ 71.048209 ] vop2_crtc_atomic_flush+0x1c78/0x202c [ 71.048223 ] drm_atomic_helper_commit_planes+0x1a4/0x210 [ 71.048238 ] rockchip_atomic_commit_complete+0x1a4/0x390 [ 71.048252 ] rockchip_drm_atomic_commit+0x22c/0x24c [ 71.048266 ] drm_mode_atomic_ioctl+0xa18/0xddc [ 71.048280 ] drm_ioctl+0x2d8/0x46c [ 71.048296 ] do_vfs_ioctl+0x4dc/0x794 [ 71.048308 ] __arm64_sys_ioctl+0x70/0x98 [ 71.048322 ] el0_svc_common+0xa0/0x18c [ 71.048335 ] el0_svc_handler+0x28/0x60 [ 71.048348 ] el0_svc+0x8/0xc Change-Id: Ie8e79995ec4bebf4ccbb509a57306541de861754 Signed-off-by: Ding Wei --- drivers/video/rockchip/mpp/mpp_common.c | 25 ++++++++++++++++--------- drivers/video/rockchip/mpp/mpp_common.h | 2 +- drivers/video/rockchip/mpp/mpp_rkvdec.c | 5 +++-- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/drivers/video/rockchip/mpp/mpp_common.c b/drivers/video/rockchip/mpp/mpp_common.c index 5f186d688e8f..4fcced94c450 100644 --- a/drivers/video/rockchip/mpp/mpp_common.c +++ b/drivers/video/rockchip/mpp/mpp_common.c @@ -138,11 +138,12 @@ mpp_taskqueue_get_pending_task(struct mpp_taskqueue *queue) static bool mpp_taskqueue_is_running(struct mpp_taskqueue *queue) { + unsigned long flags; bool flag; - mutex_lock(&queue->running_lock); + spin_lock_irqsave(&queue->running_lock, flags); flag = !list_empty(&queue->running_list); - mutex_unlock(&queue->running_lock); + spin_unlock_irqrestore(&queue->running_lock, flags); return flag; } @@ -151,10 +152,13 @@ static int mpp_taskqueue_pending_to_run(struct mpp_taskqueue *queue, struct mpp_task *task) { + unsigned long flags; + mutex_lock(&queue->pending_lock); - mutex_lock(&queue->running_lock); + spin_lock_irqsave(&queue->running_lock, flags); list_move_tail(&task->queue_link, &queue->running_list); - mutex_unlock(&queue->running_lock); + spin_unlock_irqrestore(&queue->running_lock, flags); + mutex_unlock(&queue->pending_lock); return 0; @@ -163,13 +167,14 @@ mpp_taskqueue_pending_to_run(struct mpp_taskqueue *queue, static struct mpp_task * mpp_taskqueue_get_running_task(struct mpp_taskqueue *queue) { + unsigned long flags; struct mpp_task *task = NULL; - mutex_lock(&queue->running_lock); + spin_lock_irqsave(&queue->running_lock, flags); task = list_first_entry_or_null(&queue->running_list, struct mpp_task, queue_link); - mutex_unlock(&queue->running_lock); + spin_unlock_irqrestore(&queue->running_lock, flags); return task; } @@ -178,12 +183,14 @@ static int mpp_taskqueue_pop_running(struct mpp_taskqueue *queue, struct mpp_task *task) { + unsigned long flags; + if (!task->session || !task->session->mpp) return -EINVAL; - mutex_lock(&queue->running_lock); + spin_lock_irqsave(&queue->running_lock, flags); list_del_init(&task->queue_link); - mutex_unlock(&queue->running_lock); + spin_unlock_irqrestore(&queue->running_lock, flags); kref_put(&task->ref, mpp_free_task); return 0; @@ -932,7 +939,7 @@ struct mpp_taskqueue *mpp_taskqueue_init(struct device *dev) mutex_init(&queue->session_lock); mutex_init(&queue->pending_lock); - mutex_init(&queue->running_lock); + spin_lock_init(&queue->running_lock); mutex_init(&queue->mmu_lock); mutex_init(&queue->dev_lock); INIT_LIST_HEAD(&queue->session_attach); diff --git a/drivers/video/rockchip/mpp/mpp_common.h b/drivers/video/rockchip/mpp/mpp_common.h index c4cc8aac9d5b..b7d02b0a417d 100644 --- a/drivers/video/rockchip/mpp/mpp_common.h +++ b/drivers/video/rockchip/mpp/mpp_common.h @@ -430,7 +430,7 @@ struct mpp_taskqueue { struct mutex pending_lock; struct list_head pending_list; /* lock for running list */ - struct mutex running_lock; + spinlock_t running_lock; struct list_head running_list; /* point to MPP Service */ diff --git a/drivers/video/rockchip/mpp/mpp_rkvdec.c b/drivers/video/rockchip/mpp/mpp_rkvdec.c index dd261497b5b4..8f7e069333cd 100644 --- a/drivers/video/rockchip/mpp/mpp_rkvdec.c +++ b/drivers/video/rockchip/mpp/mpp_rkvdec.c @@ -853,12 +853,13 @@ fail: static void *rkvdec_prepare_with_reset(struct mpp_dev *mpp, struct mpp_task *mpp_task) { + unsigned long flags; struct mpp_task *out_task = NULL; struct rkvdec_dev *dec = to_rkvdec_dev(mpp); - mutex_lock(&mpp->queue->running_lock); + spin_lock_irqsave(&mpp->queue->running_lock, flags); out_task = list_empty(&mpp->queue->running_list) ? mpp_task : NULL; - mutex_unlock(&mpp->queue->running_lock); + spin_unlock_irqrestore(&mpp->queue->running_lock, flags); if (out_task && !dec->had_reset) { struct rkvdec_task *task = to_rkvdec_task(out_task);