]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
accel/ivpu: Use workqueue for IRQ handling
authorMaciej Falkowski <maciej.falkowski@linux.intel.com>
Tue, 7 Jan 2025 17:32:28 +0000 (18:32 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 22 May 2025 12:31:57 +0000 (14:31 +0200)
commit bc3e5f48b7ee021371dc37297678f7089be6ce28 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>
drivers/accel/ivpu/ivpu_drv.c
drivers/accel/ivpu/ivpu_drv.h
drivers/accel/ivpu/ivpu_hw.c
drivers/accel/ivpu/ivpu_hw.h
drivers/accel/ivpu/ivpu_hw_btrs.c
drivers/accel/ivpu/ivpu_ipc.c
drivers/accel/ivpu/ivpu_ipc.h
drivers/accel/ivpu/ivpu_job.c
drivers/accel/ivpu/ivpu_job.h
drivers/accel/ivpu/ivpu_pm.c
drivers/accel/ivpu/ivpu_pm.h

index 93c3687d30b795ebfe0991d1c41a1d001cd84c25..34107b59dcf0a5de88d232d08bc51abf5ef39b09 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/pm_runtime.h>
+#include <linux/workqueue.h>
 #include <generated/utsrelease.h>
 
 #include <drm/drm_accel.h>
@@ -419,6 +420,9 @@ void ivpu_prepare_for_reset(struct ivpu_device *vdev)
 {
        ivpu_hw_irq_disable(vdev);
        disable_irq(vdev->irq);
+       cancel_work_sync(&vdev->irq_ipc_work);
+       cancel_work_sync(&vdev->irq_dct_work);
+       cancel_work_sync(&vdev->context_abort_work);
        ivpu_ipc_disable(vdev);
        ivpu_mmu_disable(vdev);
 }
@@ -463,31 +467,6 @@ static const struct drm_driver driver = {
        .major = 1,
 };
 
-static irqreturn_t ivpu_irq_thread_handler(int irq, void *arg)
-{
-       struct ivpu_device *vdev = arg;
-       u8 irq_src;
-
-       if (kfifo_is_empty(&vdev->hw->irq.fifo))
-               return IRQ_NONE;
-
-       while (kfifo_get(&vdev->hw->irq.fifo, &irq_src)) {
-               switch (irq_src) {
-               case IVPU_HW_IRQ_SRC_IPC:
-                       ivpu_ipc_irq_thread_handler(vdev);
-                       break;
-               case IVPU_HW_IRQ_SRC_DCT:
-                       ivpu_pm_dct_irq_thread_handler(vdev);
-                       break;
-               default:
-                       ivpu_err_ratelimited(vdev, "Unknown IRQ source: %u\n", irq_src);
-                       break;
-               }
-       }
-
-       return IRQ_HANDLED;
-}
-
 static int ivpu_irq_init(struct ivpu_device *vdev)
 {
        struct pci_dev *pdev = to_pci_dev(vdev->drm.dev);
@@ -499,12 +478,16 @@ static int ivpu_irq_init(struct ivpu_device *vdev)
                return ret;
        }
 
+       INIT_WORK(&vdev->irq_ipc_work, ivpu_ipc_irq_work_fn);
+       INIT_WORK(&vdev->irq_dct_work, ivpu_pm_irq_dct_work_fn);
+       INIT_WORK(&vdev->context_abort_work, ivpu_context_abort_work_fn);
+
        ivpu_irq_handlers_init(vdev);
 
        vdev->irq = pci_irq_vector(pdev, 0);
 
-       ret = devm_request_threaded_irq(vdev->drm.dev, vdev->irq, ivpu_hw_irq_handler,
-                                       ivpu_irq_thread_handler, IRQF_NO_AUTOEN, DRIVER_NAME, vdev);
+       ret = devm_request_irq(vdev->drm.dev, vdev->irq, ivpu_hw_irq_handler,
+                              IRQF_NO_AUTOEN, DRIVER_NAME, vdev);
        if (ret)
                ivpu_err(vdev, "Failed to request an IRQ %d\n", ret);
 
@@ -597,8 +580,6 @@ static int ivpu_dev_init(struct ivpu_device *vdev)
        vdev->db_limit.min = IVPU_MIN_DB;
        vdev->db_limit.max = IVPU_MAX_DB;
 
-       INIT_WORK(&vdev->context_abort_work, ivpu_context_abort_thread_handler);
-
        ret = drmm_mutex_init(&vdev->drm, &vdev->context_list_lock);
        if (ret)
                goto err_xa_destroy;
index ebfcf3e42a3d93df8a7ece549e08661b43a671b8..b57d878f2fcd390e8b63d5ac47601ff9fe2a3f22 100644 (file)
@@ -137,12 +137,15 @@ struct ivpu_device {
        struct mutex context_list_lock; /* Protects user context addition/removal */
        struct xarray context_xa;
        struct xa_limit context_xa_limit;
-       struct work_struct context_abort_work;
 
        struct xarray db_xa;
        struct xa_limit db_limit;
        u32 db_next;
 
+       struct work_struct irq_ipc_work;
+       struct work_struct irq_dct_work;
+       struct work_struct context_abort_work;
+
        struct mutex bo_list_lock; /* Protects bo_list */
        struct list_head bo_list;
 
index 65100576daf295da8c22f4f84c4de0a002659a11..d19e976893f8a77457eb066a0f55ebbcdc38b17d 100644 (file)
@@ -285,8 +285,6 @@ void ivpu_hw_profiling_freq_drive(struct ivpu_device *vdev, bool enable)
 
 void ivpu_irq_handlers_init(struct ivpu_device *vdev)
 {
-       INIT_KFIFO(vdev->hw->irq.fifo);
-
        if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
                vdev->hw->irq.ip_irq_handler = ivpu_hw_ip_irq_handler_37xx;
        else
@@ -300,7 +298,6 @@ void ivpu_irq_handlers_init(struct ivpu_device *vdev)
 
 void ivpu_hw_irq_enable(struct ivpu_device *vdev)
 {
-       kfifo_reset(&vdev->hw->irq.fifo);
        ivpu_hw_ip_irq_enable(vdev);
        ivpu_hw_btrs_irq_enable(vdev);
 }
@@ -327,8 +324,6 @@ irqreturn_t ivpu_hw_irq_handler(int irq, void *ptr)
        /* Re-enable global interrupts to re-trigger MSI for pending interrupts */
        ivpu_hw_btrs_global_int_enable(vdev);
 
-       if (!kfifo_is_empty(&vdev->hw->irq.fifo))
-               return IRQ_WAKE_THREAD;
        if (ip_handled || btrs_handled)
                return IRQ_HANDLED;
        return IRQ_NONE;
index 1e85306bcd065325da51638786b93005cd72ae80..aa8fdbf2fc222c0ac5ad4b022255765983209c1a 100644 (file)
@@ -6,18 +6,10 @@
 #ifndef __IVPU_HW_H__
 #define __IVPU_HW_H__
 
-#include <linux/kfifo.h>
-
 #include "ivpu_drv.h"
 #include "ivpu_hw_btrs.h"
 #include "ivpu_hw_ip.h"
 
-#define IVPU_HW_IRQ_FIFO_LENGTH 1024
-
-#define IVPU_HW_IRQ_SRC_IPC 1
-#define IVPU_HW_IRQ_SRC_MMU_EVTQ 2
-#define IVPU_HW_IRQ_SRC_DCT 3
-
 struct ivpu_addr_range {
        resource_size_t start;
        resource_size_t end;
@@ -27,7 +19,6 @@ struct ivpu_hw_info {
        struct {
                bool (*btrs_irq_handler)(struct ivpu_device *vdev, int irq);
                bool (*ip_irq_handler)(struct ivpu_device *vdev, int irq);
-               DECLARE_KFIFO(fifo, u8, IVPU_HW_IRQ_FIFO_LENGTH);
        } irq;
        struct {
                struct ivpu_addr_range global;
index 51b9581bb60aca6df57cbf332f798d741bb9f838..e17c69fe5a03a70d89646014408399eefecfa11c 100644 (file)
@@ -666,8 +666,7 @@ bool ivpu_hw_btrs_irq_handler_lnl(struct ivpu_device *vdev, int irq)
 
        if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, SURV_ERR, status)) {
                ivpu_dbg(vdev, IRQ, "Survivability IRQ\n");
-               if (!kfifo_put(&vdev->hw->irq.fifo, IVPU_HW_IRQ_SRC_DCT))
-                       ivpu_err_ratelimited(vdev, "IRQ FIFO full\n");
+               queue_work(system_wq, &vdev->irq_dct_work);
        }
 
        if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, FREQ_CHANGE, status)) {
index 5daaf07fc1a712e13d590c3fe1afcea62870f0e1..39f83225c1815ad1ea817e8aa09b1499edd02aa0 100644 (file)
@@ -460,13 +460,12 @@ void ivpu_ipc_irq_handler(struct ivpu_device *vdev)
                }
        }
 
-       if (!list_empty(&ipc->cb_msg_list))
-               if (!kfifo_put(&vdev->hw->irq.fifo, IVPU_HW_IRQ_SRC_IPC))
-                       ivpu_err_ratelimited(vdev, "IRQ FIFO full\n");
+       queue_work(system_wq, &vdev->irq_ipc_work);
 }
 
-void ivpu_ipc_irq_thread_handler(struct ivpu_device *vdev)
+void ivpu_ipc_irq_work_fn(struct work_struct *work)
 {
+       struct ivpu_device *vdev = container_of(work, struct ivpu_device, irq_ipc_work);
        struct ivpu_ipc_info *ipc = vdev->ipc;
        struct ivpu_ipc_rx_msg *rx_msg, *r;
        struct list_head cb_msg_list;
index b4dfb504679bac3c4537e2fb337a67dffa632601..b524a1985b9de834a084d3864320f4a08e453139 100644 (file)
@@ -90,7 +90,7 @@ void ivpu_ipc_disable(struct ivpu_device *vdev);
 void ivpu_ipc_reset(struct ivpu_device *vdev);
 
 void ivpu_ipc_irq_handler(struct ivpu_device *vdev);
-void ivpu_ipc_irq_thread_handler(struct ivpu_device *vdev);
+void ivpu_ipc_irq_work_fn(struct work_struct *work);
 
 void ivpu_ipc_consumer_add(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons,
                           u32 channel, ivpu_ipc_rx_callback_t callback);
index 79b77d8a35a772c4fd0116bac10b2dfd0d675302..fe3aea7b739bad1e7a8504055fa10338611866e8 100644 (file)
@@ -845,7 +845,7 @@ void ivpu_job_done_consumer_fini(struct ivpu_device *vdev)
        ivpu_ipc_consumer_del(vdev, &vdev->job_done_consumer);
 }
 
-void ivpu_context_abort_thread_handler(struct work_struct *work)
+void ivpu_context_abort_work_fn(struct work_struct *work)
 {
        struct ivpu_device *vdev = container_of(work, struct ivpu_device, context_abort_work);
        struct ivpu_file_priv *file_priv;
index af1ed039569cd613db6467e40d273b904911b68d..8c0e1845e5dd600d8417908ed6de46cf36544ebf 100644 (file)
@@ -66,7 +66,7 @@ void ivpu_cmdq_reset_all_contexts(struct ivpu_device *vdev);
 
 void ivpu_job_done_consumer_init(struct ivpu_device *vdev);
 void ivpu_job_done_consumer_fini(struct ivpu_device *vdev);
-void ivpu_context_abort_thread_handler(struct work_struct *work);
+void ivpu_context_abort_work_fn(struct work_struct *work);
 
 void ivpu_jobs_abort_all(struct ivpu_device *vdev);
 
index 7acf78aeb3800560b9afe500071c15531de136bb..57228e190e7fc09e0597c6b4696fe8f73f2ac58b 100644 (file)
@@ -464,8 +464,9 @@ int ivpu_pm_dct_disable(struct ivpu_device *vdev)
        return 0;
 }
 
-void ivpu_pm_dct_irq_thread_handler(struct ivpu_device *vdev)
+void ivpu_pm_irq_dct_work_fn(struct work_struct *work)
 {
+       struct ivpu_device *vdev = container_of(work, struct ivpu_device, irq_dct_work);
        bool enable;
        int ret;
 
index b70efe6c36e47fd80638c72e7e95172d22090c75..89b264cc0e3e785cb62182d55ccaa1050d9f1633 100644 (file)
@@ -45,6 +45,6 @@ void ivpu_stop_job_timeout_detection(struct ivpu_device *vdev);
 int ivpu_pm_dct_init(struct ivpu_device *vdev);
 int ivpu_pm_dct_enable(struct ivpu_device *vdev, u8 active_percent);
 int ivpu_pm_dct_disable(struct ivpu_device *vdev);
-void ivpu_pm_dct_irq_thread_handler(struct ivpu_device *vdev);
+void ivpu_pm_irq_dct_work_fn(struct work_struct *work);
 
 #endif /* __IVPU_PM_H__ */