On 21/06/2021 17:09, Steven Price wrote: > On 21/06/2021 15:02, Boris Brezillon wrote: >> This should avoid uneccessary interrupt-context switches when the GPU >> is passed a lot of short jobs. > > LGTM: > > Reviewed-by: Steven Price <steven.price@xxxxxxx> Well actually... see below. >> >> v2: >> * New patch >> >> Signed-off-by: Boris Brezillon <boris.brezillon@xxxxxxxxxxxxx> >> --- >> drivers/gpu/drm/panfrost/panfrost_job.c | 54 +++++++++++++++++-------- >> 1 file changed, 38 insertions(+), 16 deletions(-) >> >> diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c >> index cf6abe0fdf47..1b5c636794a1 100644 >> --- a/drivers/gpu/drm/panfrost/panfrost_job.c >> +++ b/drivers/gpu/drm/panfrost/panfrost_job.c >> @@ -473,19 +473,12 @@ static const struct drm_sched_backend_ops panfrost_sched_ops = { >> .free_job = panfrost_job_free >> }; >> >> -static irqreturn_t panfrost_job_irq_handler(int irq, void *data) >> +static void panfrost_job_handle_irq(struct panfrost_device *pfdev, u32 status) >> { >> - struct panfrost_device *pfdev = data; >> - u32 status = job_read(pfdev, JOB_INT_STAT); >> int j; >> >> dev_dbg(pfdev->dev, "jobslot irq status=%x\n", status); >> >> - if (!status) >> - return IRQ_NONE; >> - >> - pm_runtime_mark_last_busy(pfdev->dev); >> - >> for (j = 0; status; j++) { >> u32 mask = MK_JS_MASK(j); >> >> @@ -558,16 +551,43 @@ static irqreturn_t panfrost_job_irq_handler(int irq, void *data) Missing context: > if (status & JOB_INT_MASK_DONE(j)) { > struct panfrost_job *job; > > spin_lock(&pfdev->js->job_lock); > job = pfdev->jobs[j]; > /* Only NULL if job timeout occurred */ > if (job) { > pfdev->jobs[j] = NULL; > > panfrost_mmu_as_put(pfdev, job->file_priv->mmu); > panfrost_devfreq_record_idle(&pfdev->pfdevfreq); > > dma_fence_signal_locked(job->done_fence); > pm_runtime_put_autosuspend(pfdev->dev); > } > spin_unlock(&pfdev->js->job_lock); > } ^^^ Here we're still taking job_lock which is now held by panfrost_job_irq_handler_thread(). This is removed by the following patch, but it breaks bisection. Steve >> >> status &= ~mask; >> } >> +} >> >> +static irqreturn_t panfrost_job_irq_handler_thread(int irq, void *data) >> +{ >> + struct panfrost_device *pfdev = data; >> + u32 status = job_read(pfdev, JOB_INT_RAWSTAT); >> + >> + while (status) { >> + pm_runtime_mark_last_busy(pfdev->dev); >> + >> + spin_lock(&pfdev->js->job_lock); >> + panfrost_job_handle_irq(pfdev, status); >> + spin_unlock(&pfdev->js->job_lock); >> + status = job_read(pfdev, JOB_INT_RAWSTAT); >> + } >> + >> + job_write(pfdev, JOB_INT_MASK, ~0); >> return IRQ_HANDLED; >> } >> >> +static irqreturn_t panfrost_job_irq_handler(int irq, void *data) >> +{ >> + struct panfrost_device *pfdev = data; >> + u32 status = job_read(pfdev, JOB_INT_STAT); >> + >> + if (!status) >> + return IRQ_NONE; >> + >> + job_write(pfdev, JOB_INT_MASK, 0); >> + return IRQ_WAKE_THREAD; >> +} >> + >> static void panfrost_reset(struct work_struct *work) >> { >> struct panfrost_device *pfdev = container_of(work, >> struct panfrost_device, >> reset.work); >> - unsigned long flags; >> unsigned int i; >> >> for (i = 0; i < NUM_JOB_SLOTS; i++) { >> @@ -595,7 +615,7 @@ static void panfrost_reset(struct work_struct *work) >> /* All timers have been stopped, we can safely reset the pending state. */ >> atomic_set(&pfdev->reset.pending, 0); >> >> - spin_lock_irqsave(&pfdev->js->job_lock, flags); >> + spin_lock(&pfdev->js->job_lock); >> for (i = 0; i < NUM_JOB_SLOTS; i++) { >> if (pfdev->jobs[i]) { >> pm_runtime_put_noidle(pfdev->dev); >> @@ -603,7 +623,7 @@ static void panfrost_reset(struct work_struct *work) >> pfdev->jobs[i] = NULL; >> } >> } >> - spin_unlock_irqrestore(&pfdev->js->job_lock, flags); >> + spin_unlock(&pfdev->js->job_lock); >> >> panfrost_device_reset(pfdev); >> >> @@ -628,8 +648,11 @@ int panfrost_job_init(struct panfrost_device *pfdev) >> if (irq <= 0) >> return -ENODEV; >> >> - ret = devm_request_irq(pfdev->dev, irq, panfrost_job_irq_handler, >> - IRQF_SHARED, KBUILD_MODNAME "-job", pfdev); >> + ret = devm_request_threaded_irq(pfdev->dev, irq, >> + panfrost_job_irq_handler, >> + panfrost_job_irq_handler_thread, >> + IRQF_SHARED, KBUILD_MODNAME "-job", >> + pfdev); >> if (ret) { >> dev_err(pfdev->dev, "failed to request job irq"); >> return ret; >> @@ -696,14 +719,13 @@ int panfrost_job_open(struct panfrost_file_priv *panfrost_priv) >> void panfrost_job_close(struct panfrost_file_priv *panfrost_priv) >> { >> struct panfrost_device *pfdev = panfrost_priv->pfdev; >> - unsigned long flags; >> int i; >> >> for (i = 0; i < NUM_JOB_SLOTS; i++) >> drm_sched_entity_destroy(&panfrost_priv->sched_entity[i]); >> >> /* Kill in-flight jobs */ >> - spin_lock_irqsave(&pfdev->js->job_lock, flags); >> + spin_lock(&pfdev->js->job_lock); >> for (i = 0; i < NUM_JOB_SLOTS; i++) { >> struct drm_sched_entity *entity = &panfrost_priv->sched_entity[i]; >> struct panfrost_job *job = pfdev->jobs[i]; >> @@ -713,7 +735,7 @@ void panfrost_job_close(struct panfrost_file_priv *panfrost_priv) >> >> job_write(pfdev, JS_COMMAND(i), JS_COMMAND_HARD_STOP); >> } >> - spin_unlock_irqrestore(&pfdev->js->job_lock, flags); >> + spin_unlock(&pfdev->js->job_lock); >> } >> >> int panfrost_job_is_idle(struct panfrost_device *pfdev) >> >