From 494c0a303537c55971421b5552d98eb55e652cf3 Mon Sep 17 00:00:00 2001 From: Shuangjie Lin Date: Wed, 18 Oct 2023 15:18:06 +0800 Subject: [PATCH] driver: rknpu: Fixing deadlock issue with spin_lock in interrupt handling Signed-off-by: Shuangjie Lin Change-Id: I14a57c43aeb56110f58fe4d902f03604a9983d05 --- drivers/rknpu/include/rknpu_drv.h | 2 +- drivers/rknpu/rknpu_job.c | 39 ++++++++++++++++++++----------- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/drivers/rknpu/include/rknpu_drv.h b/drivers/rknpu/include/rknpu_drv.h index 2f7de548a5754..fb5ae90a837f6 100644 --- a/drivers/rknpu/include/rknpu_drv.h +++ b/drivers/rknpu/include/rknpu_drv.h @@ -30,7 +30,7 @@ #define DRIVER_NAME "rknpu" #define DRIVER_DESC "RKNPU driver" -#define DRIVER_DATE "20230825" +#define DRIVER_DATE "20231018" #define DRIVER_MAJOR 0 #define DRIVER_MINOR 9 #define DRIVER_PATCHLEVEL 2 diff --git a/drivers/rknpu/rknpu_job.c b/drivers/rknpu/rknpu_job.c index f0f1dd79c9a62..92f2df7430ec9 100644 --- a/drivers/rknpu/rknpu_job.c +++ b/drivers/rknpu/rknpu_job.c @@ -217,7 +217,7 @@ static inline int rknpu_job_wait(struct rknpu_job *job) last_task = job->last_task; if (!last_task) { - spin_lock_irqsave(&rknpu_dev->lock, flags); + spin_lock_irqsave(&rknpu_dev->irq_lock, flags); for (i = 0; i < job->use_core_num; i++) { subcore_data = &rknpu_dev->subcore_datas[i]; list_for_each_entry_safe( @@ -289,6 +289,7 @@ static inline int rknpu_job_subcore_commit_pc(struct rknpu_job *job, int i = 0; int submit_index = atomic_read(&job->submit_count[core_index]); int max_submit_number = rknpu_dev->config->max_submit_number; + unsigned long flags; if (!task_obj) { job->ret = -EINVAL; @@ -334,9 +335,13 @@ static inline int rknpu_job_subcore_commit_pc(struct rknpu_job *job, first_task = &task_base[task_start]; last_task = &task_base[task_end]; - spin_lock(&rknpu_dev->lock); - REG_WRITE(first_task->regcmd_addr, RKNPU_OFFSET_PC_DATA_ADDR); - spin_unlock(&rknpu_dev->lock); + if (rknpu_dev->config->pc_dma_ctrl) { + spin_lock_irqsave(&rknpu_dev->irq_lock, flags); + REG_WRITE(first_task->regcmd_addr, RKNPU_OFFSET_PC_DATA_ADDR); + spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags); + } else { + REG_WRITE(first_task->regcmd_addr, RKNPU_OFFSET_PC_DATA_ADDR); + } REG_WRITE((first_task->regcfg_amount + RKNPU_PC_DATA_EXTRA_AMOUNT + pc_data_amount_scale - 1) / @@ -368,11 +373,16 @@ static inline int rknpu_job_subcore_commit(struct rknpu_job *job, int core_index struct rknpu_device *rknpu_dev = job->rknpu_dev; struct rknpu_submit *args = job->args; void __iomem *rknpu_core_base = rknpu_dev->base[core_index]; + unsigned long flags; // switch to slave mode - spin_lock(&rknpu_dev->lock); - REG_WRITE(0x1, RKNPU_OFFSET_PC_DATA_ADDR); - spin_unlock(&rknpu_dev->lock); + if (rknpu_dev->config->pc_dma_ctrl) { + spin_lock_irqsave(&rknpu_dev->irq_lock, flags); + REG_WRITE(0x1, RKNPU_OFFSET_PC_DATA_ADDR); + spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags); + } else { + REG_WRITE(0x1, RKNPU_OFFSET_PC_DATA_ADDR); + } if (!(args->flags & RKNPU_JOB_PC)) { job->ret = -EINVAL; @@ -451,7 +461,7 @@ static void rknpu_job_done(struct rknpu_job *job, int ret, int core_index) if (atomic_inc_return(&job->submit_count[core_index]) < (rknpu_get_task_number(job, core_index) + max_submit_number - 1) / max_submit_number) { - rknpu_job_commit(job); + rknpu_job_subcore_commit(job, core_index); return; } @@ -936,28 +946,31 @@ int rknpu_set_bw_priority(struct rknpu_device *rknpu_dev, uint32_t priority, int rknpu_clear_rw_amount(struct rknpu_device *rknpu_dev) { void __iomem *rknpu_core_base = rknpu_dev->base[0]; + unsigned long flags; if (!rknpu_dev->config->bw_enable) { LOG_WARN("Clear rw_amount is not supported on this device!\n"); return 0; } - spin_lock(&rknpu_dev->lock); - if (rknpu_dev->config->pc_dma_ctrl) { - uint32_t pc_data_addr = REG_READ(RKNPU_OFFSET_PC_DATA_ADDR); + uint32_t pc_data_addr = 0; + + spin_lock_irqsave(&rknpu_dev->irq_lock, flags); + pc_data_addr = REG_READ(RKNPU_OFFSET_PC_DATA_ADDR); REG_WRITE(0x1, RKNPU_OFFSET_PC_DATA_ADDR); REG_WRITE(0x80000101, RKNPU_OFFSET_CLR_ALL_RW_AMOUNT); REG_WRITE(0x00000101, RKNPU_OFFSET_CLR_ALL_RW_AMOUNT); REG_WRITE(pc_data_addr, RKNPU_OFFSET_PC_DATA_ADDR); + spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags); } else { + spin_lock(&rknpu_dev->lock); REG_WRITE(0x80000101, RKNPU_OFFSET_CLR_ALL_RW_AMOUNT); REG_WRITE(0x00000101, RKNPU_OFFSET_CLR_ALL_RW_AMOUNT); + spin_unlock(&rknpu_dev->lock); } - spin_unlock(&rknpu_dev->lock); - return 0; }