]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/xe/irq: Manage MSI-X interrupts allocation
authorIlia Levi <ilia.levi@intel.com>
Fri, 13 Dec 2024 07:25:37 +0000 (09:25 +0200)
committerRodrigo Vivi <rodrigo.vivi@intel.com>
Fri, 13 Dec 2024 18:38:13 +0000 (13:38 -0500)
Expose functions to request and free MSI-X interrupts.

The request has two flavors:
- Static MSI-X allocation, for known MSI-X interrupts (e.g. GuC-to-host)
- Dynamic MSI-X allocation, which uses the next available MSI-X interrupt

Signed-off-by: Ilia Levi <ilia.levi@intel.com>
Reviewed-by: Piotr Piórkowski <piotr.piorkowski@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20241213072538.6823-4-ilia.levi@intel.com
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
drivers/gpu/drm/xe/xe_device_types.h
drivers/gpu/drm/xe/xe_irq.c
drivers/gpu/drm/xe/xe_irq.h

index 7b90df4e00212eb61d72593cb08aab92cd817ff1..8a7b159724135573386057d97affc4fd4e98aaa6 100644 (file)
@@ -353,6 +353,8 @@ struct xe_device {
                struct {
                        /** @irq.msix.nvec: number of MSI-X interrupts */
                        u16 nvec;
+                       /** @irq.msix.indexes: used to allocate MSI-X indexes */
+                       struct xarray indexes;
                } msix;
        } irq;
 
index b8a0b9bbf24c440e224ca9b61fcc07dd7cf87a79..32f5a67a917b5828d6295647ff5811cb89723439 100644 (file)
@@ -830,6 +830,7 @@ static int xe_irq_msix_init(struct xe_device *xe)
        }
 
        xe->irq.msix.nvec = nvec;
+       xa_init_flags(&xe->irq.msix.indexes, XA_FLAGS_ALLOC);
        return 0;
 }
 
@@ -879,8 +880,32 @@ static irqreturn_t xe_irq_msix_default_hwe_handler(int irq, void *arg)
        return IRQ_HANDLED;
 }
 
-static int xe_irq_msix_request_irq(struct xe_device *xe, irq_handler_t handler,
-                                  const char *name, u16 msix)
+static int xe_irq_msix_alloc_vector(struct xe_device *xe, void *irq_buf,
+                                   bool dynamic_msix, u16 *msix)
+{
+       struct xa_limit limit;
+       int ret;
+       u32 id;
+
+       limit = (dynamic_msix) ? XA_LIMIT(NUM_OF_STATIC_MSIX, xe->irq.msix.nvec - 1) :
+                                XA_LIMIT(*msix, *msix);
+       ret = xa_alloc(&xe->irq.msix.indexes, &id, irq_buf, limit, GFP_KERNEL);
+       if (ret)
+               return ret;
+
+       if (dynamic_msix)
+               *msix = id;
+
+       return 0;
+}
+
+static void xe_irq_msix_release_vector(struct xe_device *xe, u16 msix)
+{
+       xa_erase(&xe->irq.msix.indexes, msix);
+}
+
+static int xe_irq_msix_request_irq_internal(struct xe_device *xe, irq_handler_t handler,
+                                           void *irq_buf, const char *name, u16 msix)
 {
        struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
        int ret, irq;
@@ -889,17 +914,41 @@ static int xe_irq_msix_request_irq(struct xe_device *xe, irq_handler_t handler,
        if (irq < 0)
                return irq;
 
-       ret = request_irq(irq, handler, IRQF_SHARED, name, xe);
+       ret = request_irq(irq, handler, IRQF_SHARED, name, irq_buf);
        if (ret < 0)
                return ret;
 
        return 0;
 }
 
-static void xe_irq_msix_free_irq(struct xe_device *xe, u16 msix)
+int xe_irq_msix_request_irq(struct xe_device *xe, irq_handler_t handler, void *irq_buf,
+                           const char *name, bool dynamic_msix, u16 *msix)
+{
+       int ret;
+
+       ret = xe_irq_msix_alloc_vector(xe, irq_buf, dynamic_msix, msix);
+       if (ret)
+               return ret;
+
+       ret = xe_irq_msix_request_irq_internal(xe, handler, irq_buf, name, *msix);
+       if (ret) {
+               drm_err(&xe->drm, "Failed to request IRQ for MSI-X %u\n", *msix);
+               xe_irq_msix_release_vector(xe, *msix);
+               return ret;
+       }
+
+       return 0;
+}
+
+void xe_irq_msix_free_irq(struct xe_device *xe, u16 msix)
 {
        struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
        int irq;
+       void *irq_buf;
+
+       irq_buf = xa_load(&xe->irq.msix.indexes, msix);
+       if (!irq_buf)
+               return;
 
        irq = pci_irq_vector(pdev, msix);
        if (irq < 0) {
@@ -907,24 +956,25 @@ static void xe_irq_msix_free_irq(struct xe_device *xe, u16 msix)
                return;
        }
 
-       free_irq(irq, xe);
+       free_irq(irq, irq_buf);
+       xe_irq_msix_release_vector(xe, msix);
 }
 
-static int xe_irq_msix_request_irqs(struct xe_device *xe)
+int xe_irq_msix_request_irqs(struct xe_device *xe)
 {
        int err;
+       u16 msix;
 
-       err = xe_irq_msix_request_irq(xe, guc2host_irq_handler,
-                                     DRIVER_NAME "-guc2host", GUC2HOST_MSIX);
-       if (err) {
-               drm_err(&xe->drm, "Failed to request MSI-X IRQ %d: %d\n", GUC2HOST_MSIX, err);
+       msix = GUC2HOST_MSIX;
+       err = xe_irq_msix_request_irq(xe, guc2host_irq_handler, xe,
+                                     DRIVER_NAME "-guc2host", false, &msix);
+       if (err)
                return err;
-       }
 
-       err = xe_irq_msix_request_irq(xe, xe_irq_msix_default_hwe_handler,
-                                     DRIVER_NAME "-default-msix", DEFAULT_MSIX);
+       msix = DEFAULT_MSIX;
+       err = xe_irq_msix_request_irq(xe, xe_irq_msix_default_hwe_handler, xe,
+                                     DRIVER_NAME "-default-msix", false, &msix);
        if (err) {
-               drm_err(&xe->drm, "Failed to request MSI-X IRQ %d: %d\n", DEFAULT_MSIX, err);
                xe_irq_msix_free_irq(xe, GUC2HOST_MSIX);
                return err;
        }
@@ -932,16 +982,22 @@ static int xe_irq_msix_request_irqs(struct xe_device *xe)
        return 0;
 }
 
-static void xe_irq_msix_free(struct xe_device *xe)
+void xe_irq_msix_free(struct xe_device *xe)
 {
-       xe_irq_msix_free_irq(xe, GUC2HOST_MSIX);
-       xe_irq_msix_free_irq(xe, DEFAULT_MSIX);
+       unsigned long msix;
+       u32 *dummy;
+
+       xa_for_each(&xe->irq.msix.indexes, msix, dummy)
+               xe_irq_msix_free_irq(xe, msix);
+       xa_destroy(&xe->irq.msix.indexes);
 }
 
-static void xe_irq_msix_synchronize_irq(struct xe_device *xe)
+void xe_irq_msix_synchronize_irq(struct xe_device *xe)
 {
        struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
+       unsigned long msix;
+       u32 *dummy;
 
-       synchronize_irq(pci_irq_vector(pdev, GUC2HOST_MSIX));
-       synchronize_irq(pci_irq_vector(pdev, DEFAULT_MSIX));
+       xa_for_each(&xe->irq.msix.indexes, msix, dummy)
+               synchronize_irq(pci_irq_vector(pdev, msix));
 }
index 24ff16111b9688f5157ffdb3f5070a4572423ceb..a28bd577ba52ab18b69ca5c4010d702ad2116941 100644 (file)
@@ -6,6 +6,8 @@
 #ifndef _XE_IRQ_H_
 #define _XE_IRQ_H_
 
+#include <linux/interrupt.h>
+
 #define XE_IRQ_DEFAULT_MSIX 1
 
 struct xe_device;
@@ -17,5 +19,8 @@ int xe_irq_install(struct xe_device *xe);
 void xe_irq_suspend(struct xe_device *xe);
 void xe_irq_resume(struct xe_device *xe);
 void xe_irq_enable_hwe(struct xe_gt *gt);
+int xe_irq_msix_request_irq(struct xe_device *xe, irq_handler_t handler, void *irq_buf,
+                           const char *name, bool dynamic_msix, u16 *msix);
+void xe_irq_msix_free_irq(struct xe_device *xe, u16 msix);
 
 #endif