Skip to content

Commit da17dcb

Browse files
m-falkowskigregkh
authored andcommitted
accel/ivpu: Use workqueue for IRQ handling
commit bc3e5f4 upstream. Convert IRQ bottom half from the thread handler into workqueue. This increases a stability in rare scenarios where driver on debugging/hardening kernels processes IRQ too slow and misses some interrupts due to it. Workqueue handler also gives a very minor performance increase. Signed-off-by: Maciej Falkowski <maciej.falkowski@linux.intel.com> Reviewed-by: Jacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com> Signed-off-by: Jacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20250107173238.381120-6-maciej.falkowski@linux.intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent a7bd00f commit da17dcb

11 files changed

Lines changed: 24 additions & 55 deletions

File tree

drivers/accel/ivpu/ivpu_drv.c

Lines changed: 10 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <linux/module.h>
88
#include <linux/pci.h>
99
#include <linux/pm_runtime.h>
10+
#include <linux/workqueue.h>
1011
#include <generated/utsrelease.h>
1112

1213
#include <drm/drm_accel.h>
@@ -419,6 +420,9 @@ void ivpu_prepare_for_reset(struct ivpu_device *vdev)
419420
{
420421
ivpu_hw_irq_disable(vdev);
421422
disable_irq(vdev->irq);
423+
cancel_work_sync(&vdev->irq_ipc_work);
424+
cancel_work_sync(&vdev->irq_dct_work);
425+
cancel_work_sync(&vdev->context_abort_work);
422426
ivpu_ipc_disable(vdev);
423427
ivpu_mmu_disable(vdev);
424428
}
@@ -463,31 +467,6 @@ static const struct drm_driver driver = {
463467
.major = 1,
464468
};
465469

466-
static irqreturn_t ivpu_irq_thread_handler(int irq, void *arg)
467-
{
468-
struct ivpu_device *vdev = arg;
469-
u8 irq_src;
470-
471-
if (kfifo_is_empty(&vdev->hw->irq.fifo))
472-
return IRQ_NONE;
473-
474-
while (kfifo_get(&vdev->hw->irq.fifo, &irq_src)) {
475-
switch (irq_src) {
476-
case IVPU_HW_IRQ_SRC_IPC:
477-
ivpu_ipc_irq_thread_handler(vdev);
478-
break;
479-
case IVPU_HW_IRQ_SRC_DCT:
480-
ivpu_pm_dct_irq_thread_handler(vdev);
481-
break;
482-
default:
483-
ivpu_err_ratelimited(vdev, "Unknown IRQ source: %u\n", irq_src);
484-
break;
485-
}
486-
}
487-
488-
return IRQ_HANDLED;
489-
}
490-
491470
static int ivpu_irq_init(struct ivpu_device *vdev)
492471
{
493472
struct pci_dev *pdev = to_pci_dev(vdev->drm.dev);
@@ -499,12 +478,16 @@ static int ivpu_irq_init(struct ivpu_device *vdev)
499478
return ret;
500479
}
501480

481+
INIT_WORK(&vdev->irq_ipc_work, ivpu_ipc_irq_work_fn);
482+
INIT_WORK(&vdev->irq_dct_work, ivpu_pm_irq_dct_work_fn);
483+
INIT_WORK(&vdev->context_abort_work, ivpu_context_abort_work_fn);
484+
502485
ivpu_irq_handlers_init(vdev);
503486

504487
vdev->irq = pci_irq_vector(pdev, 0);
505488

506-
ret = devm_request_threaded_irq(vdev->drm.dev, vdev->irq, ivpu_hw_irq_handler,
507-
ivpu_irq_thread_handler, IRQF_NO_AUTOEN, DRIVER_NAME, vdev);
489+
ret = devm_request_irq(vdev->drm.dev, vdev->irq, ivpu_hw_irq_handler,
490+
IRQF_NO_AUTOEN, DRIVER_NAME, vdev);
508491
if (ret)
509492
ivpu_err(vdev, "Failed to request an IRQ %d\n", ret);
510493

@@ -597,8 +580,6 @@ static int ivpu_dev_init(struct ivpu_device *vdev)
597580
vdev->db_limit.min = IVPU_MIN_DB;
598581
vdev->db_limit.max = IVPU_MAX_DB;
599582

600-
INIT_WORK(&vdev->context_abort_work, ivpu_context_abort_thread_handler);
601-
602583
ret = drmm_mutex_init(&vdev->drm, &vdev->context_list_lock);
603584
if (ret)
604585
goto err_xa_destroy;

drivers/accel/ivpu/ivpu_drv.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,12 +137,15 @@ struct ivpu_device {
137137
struct mutex context_list_lock; /* Protects user context addition/removal */
138138
struct xarray context_xa;
139139
struct xa_limit context_xa_limit;
140-
struct work_struct context_abort_work;
141140

142141
struct xarray db_xa;
143142
struct xa_limit db_limit;
144143
u32 db_next;
145144

145+
struct work_struct irq_ipc_work;
146+
struct work_struct irq_dct_work;
147+
struct work_struct context_abort_work;
148+
146149
struct mutex bo_list_lock; /* Protects bo_list */
147150
struct list_head bo_list;
148151

drivers/accel/ivpu/ivpu_hw.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -285,8 +285,6 @@ void ivpu_hw_profiling_freq_drive(struct ivpu_device *vdev, bool enable)
285285

286286
void ivpu_irq_handlers_init(struct ivpu_device *vdev)
287287
{
288-
INIT_KFIFO(vdev->hw->irq.fifo);
289-
290288
if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
291289
vdev->hw->irq.ip_irq_handler = ivpu_hw_ip_irq_handler_37xx;
292290
else
@@ -300,7 +298,6 @@ void ivpu_irq_handlers_init(struct ivpu_device *vdev)
300298

301299
void ivpu_hw_irq_enable(struct ivpu_device *vdev)
302300
{
303-
kfifo_reset(&vdev->hw->irq.fifo);
304301
ivpu_hw_ip_irq_enable(vdev);
305302
ivpu_hw_btrs_irq_enable(vdev);
306303
}
@@ -327,8 +324,6 @@ irqreturn_t ivpu_hw_irq_handler(int irq, void *ptr)
327324
/* Re-enable global interrupts to re-trigger MSI for pending interrupts */
328325
ivpu_hw_btrs_global_int_enable(vdev);
329326

330-
if (!kfifo_is_empty(&vdev->hw->irq.fifo))
331-
return IRQ_WAKE_THREAD;
332327
if (ip_handled || btrs_handled)
333328
return IRQ_HANDLED;
334329
return IRQ_NONE;

drivers/accel/ivpu/ivpu_hw.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,10 @@
66
#ifndef __IVPU_HW_H__
77
#define __IVPU_HW_H__
88

9-
#include <linux/kfifo.h>
10-
119
#include "ivpu_drv.h"
1210
#include "ivpu_hw_btrs.h"
1311
#include "ivpu_hw_ip.h"
1412

15-
#define IVPU_HW_IRQ_FIFO_LENGTH 1024
16-
17-
#define IVPU_HW_IRQ_SRC_IPC 1
18-
#define IVPU_HW_IRQ_SRC_MMU_EVTQ 2
19-
#define IVPU_HW_IRQ_SRC_DCT 3
20-
2113
struct ivpu_addr_range {
2214
resource_size_t start;
2315
resource_size_t end;
@@ -27,7 +19,6 @@ struct ivpu_hw_info {
2719
struct {
2820
bool (*btrs_irq_handler)(struct ivpu_device *vdev, int irq);
2921
bool (*ip_irq_handler)(struct ivpu_device *vdev, int irq);
30-
DECLARE_KFIFO(fifo, u8, IVPU_HW_IRQ_FIFO_LENGTH);
3122
} irq;
3223
struct {
3324
struct ivpu_addr_range global;

drivers/accel/ivpu/ivpu_hw_btrs.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -666,8 +666,7 @@ bool ivpu_hw_btrs_irq_handler_lnl(struct ivpu_device *vdev, int irq)
666666

667667
if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, SURV_ERR, status)) {
668668
ivpu_dbg(vdev, IRQ, "Survivability IRQ\n");
669-
if (!kfifo_put(&vdev->hw->irq.fifo, IVPU_HW_IRQ_SRC_DCT))
670-
ivpu_err_ratelimited(vdev, "IRQ FIFO full\n");
669+
queue_work(system_wq, &vdev->irq_dct_work);
671670
}
672671

673672
if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, FREQ_CHANGE, status)) {

drivers/accel/ivpu/ivpu_ipc.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -460,13 +460,12 @@ void ivpu_ipc_irq_handler(struct ivpu_device *vdev)
460460
}
461461
}
462462

463-
if (!list_empty(&ipc->cb_msg_list))
464-
if (!kfifo_put(&vdev->hw->irq.fifo, IVPU_HW_IRQ_SRC_IPC))
465-
ivpu_err_ratelimited(vdev, "IRQ FIFO full\n");
463+
queue_work(system_wq, &vdev->irq_ipc_work);
466464
}
467465

468-
void ivpu_ipc_irq_thread_handler(struct ivpu_device *vdev)
466+
void ivpu_ipc_irq_work_fn(struct work_struct *work)
469467
{
468+
struct ivpu_device *vdev = container_of(work, struct ivpu_device, irq_ipc_work);
470469
struct ivpu_ipc_info *ipc = vdev->ipc;
471470
struct ivpu_ipc_rx_msg *rx_msg, *r;
472471
struct list_head cb_msg_list;

drivers/accel/ivpu/ivpu_ipc.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ void ivpu_ipc_disable(struct ivpu_device *vdev);
9090
void ivpu_ipc_reset(struct ivpu_device *vdev);
9191

9292
void ivpu_ipc_irq_handler(struct ivpu_device *vdev);
93-
void ivpu_ipc_irq_thread_handler(struct ivpu_device *vdev);
93+
void ivpu_ipc_irq_work_fn(struct work_struct *work);
9494

9595
void ivpu_ipc_consumer_add(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons,
9696
u32 channel, ivpu_ipc_rx_callback_t callback);

drivers/accel/ivpu/ivpu_job.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -845,7 +845,7 @@ void ivpu_job_done_consumer_fini(struct ivpu_device *vdev)
845845
ivpu_ipc_consumer_del(vdev, &vdev->job_done_consumer);
846846
}
847847

848-
void ivpu_context_abort_thread_handler(struct work_struct *work)
848+
void ivpu_context_abort_work_fn(struct work_struct *work)
849849
{
850850
struct ivpu_device *vdev = container_of(work, struct ivpu_device, context_abort_work);
851851
struct ivpu_file_priv *file_priv;

drivers/accel/ivpu/ivpu_job.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ void ivpu_cmdq_reset_all_contexts(struct ivpu_device *vdev);
6666

6767
void ivpu_job_done_consumer_init(struct ivpu_device *vdev);
6868
void ivpu_job_done_consumer_fini(struct ivpu_device *vdev);
69-
void ivpu_context_abort_thread_handler(struct work_struct *work);
69+
void ivpu_context_abort_work_fn(struct work_struct *work);
7070

7171
void ivpu_jobs_abort_all(struct ivpu_device *vdev);
7272

drivers/accel/ivpu/ivpu_pm.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,8 +464,9 @@ int ivpu_pm_dct_disable(struct ivpu_device *vdev)
464464
return 0;
465465
}
466466

467-
void ivpu_pm_dct_irq_thread_handler(struct ivpu_device *vdev)
467+
void ivpu_pm_irq_dct_work_fn(struct work_struct *work)
468468
{
469+
struct ivpu_device *vdev = container_of(work, struct ivpu_device, irq_dct_work);
469470
bool enable;
470471
int ret;
471472

0 commit comments

Comments
 (0)