drm: Implement parts of the Linux irq subsystem
authorFrançois Tigeot <ftigeot@wolfpond.org>
Wed, 25 Apr 2018 09:52:23 +0000 (11:52 +0200)
committerFrançois Tigeot <ftigeot@wolfpond.org>
Wed, 25 Apr 2018 10:18:50 +0000 (12:18 +0200)
* Allowing to reuse more drm drivers code as-is from Linux

* Also allowing Linux irq functions to return expected status
  codes, increasing general driver robustness

Tested-with: many i915 devices, Radeon HD6450

14 files changed:
sys/conf/files
sys/dev/drm/drm/Makefile
sys/dev/drm/drm_dragonfly.c
sys/dev/drm/drm_drv.c
sys/dev/drm/drm_fops.c
sys/dev/drm/drm_irq.c
sys/dev/drm/i915/i915_irq.c
sys/dev/drm/include/drm/drmP.h
sys/dev/drm/include/linux/interrupt.h
sys/dev/drm/include/linux/irqreturn.h
sys/dev/drm/include/linux/pci.h
sys/dev/drm/linux_irq.c [new file with mode: 0644]
sys/dev/drm/radeon/radeon_irq_kms.c
sys/dev/drm/radeon/radeon_irq_kms.h

index 7c44bf5..25cbde0 100644 (file)
@@ -2289,6 +2289,7 @@ dev/drm/linux_hdmi.c                      optional drm
 dev/drm/linux_hrtimer.c                        optional drm
 dev/drm/linux_i2c.c                    optional drm
 dev/drm/linux_iomapping.c              optional drm
+dev/drm/linux_irq.c                    optional drm
 dev/drm/linux_list_sort.c              optional drm
 dev/drm/linux_shmem.c                  optional drm
 dev/drm/linux_sort.c                   optional drm
index 3d74f49..e171dbd 100644 (file)
@@ -53,6 +53,7 @@ SRCS  = \
        linux_i2c.c \
        linux_hrtimer.c \
        linux_iomapping.c \
+       linux_irq.c \
        linux_list_sort.c \
        linux_shmem.c \
        linux_sort.c \
index 4c4b724..3747138 100644 (file)
@@ -104,6 +104,9 @@ char *drm_asprintf(int flags, const char *format, ...)
 
 static void drm_fill_pdev(device_t dev, struct pci_dev *pdev)
 {
+       int msi_enable = 1;
+       u_int irq_flags;
+
        pdev->dev.bsddev = dev;
        pdev->vendor = pci_get_vendor(dev);
        pdev->device = pci_get_device(dev);
@@ -111,6 +114,16 @@ static void drm_fill_pdev(device_t dev, struct pci_dev *pdev)
        pdev->subsystem_device = pci_get_subdevice(dev);
 
        pdev->revision = pci_get_revid(dev) & 0xff;
+
+       pdev->_irq_type = pci_alloc_1intr(dev, msi_enable,
+           &pdev->_irqrid, &irq_flags);
+
+       pdev->_irqr = bus_alloc_resource_any(dev, SYS_RES_IRQ,
+           &pdev->_irqrid, irq_flags);
+       if (!pdev->_irqr)
+               return;
+
+       pdev->irq = rman_get_start(pdev->_irqr);
 }
 
 void drm_init_pdev(device_t dev, struct pci_dev **pdev)
index b4d4005..f4490a5 100644 (file)
@@ -1009,8 +1009,6 @@ int drm_attach(device_t kdev, drm_pci_id_list_t *idlist)
        struct drm_device *dev;
        drm_pci_id_list_t *id_entry;
        int unit, error;
-       u_int irq_flags;
-       int msi_enable;
 
        unit = device_get_unit(kdev);
        dev = device_get_softc(kdev);
@@ -1033,23 +1031,6 @@ int drm_attach(device_t kdev, drm_pci_id_list_t *idlist)
            dev->pdev->device, idlist);
        dev->id_entry = id_entry;
 
-       if (drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) {
-               msi_enable = 1;
-
-               dev->irq_type = pci_alloc_1intr(dev->dev->bsddev, msi_enable,
-                   &dev->irqrid, &irq_flags);
-
-               dev->irqr = bus_alloc_resource_any(dev->dev->bsddev, SYS_RES_IRQ,
-                   &dev->irqrid, irq_flags);
-
-               if (!dev->irqr) {
-                       return (ENOENT);
-               }
-
-               dev->irq = (int) rman_get_start(dev->irqr);
-               dev->pdev->irq = dev->irq; /* for i915 */
-       }
-
        /* Print the contents of pdev struct. */
        drm_print_pdev(dev->pdev);
 
@@ -1063,18 +1044,8 @@ int drm_attach(device_t kdev, drm_pci_id_list_t *idlist)
                goto error;
 
        error = drm_create_cdevs(kdev);
-       if (error)
-               goto error;
 
-       return (error);
 error:
-       if (dev->irqr) {
-               bus_release_resource(dev->dev->bsddev, SYS_RES_IRQ,
-                   dev->irqrid, dev->irqr);
-       }
-       if (dev->irq_type == PCI_INTR_TYPE_MSI) {
-               pci_release_msi(dev->dev->bsddev);
-       }
        return (error);
 }
 
index 1f2257e..68c428f 100644 (file)
@@ -403,15 +403,6 @@ int drm_release(device_t kdev)
         * End inline drm_release
         */
 
-       if (dev->irqr) {
-               bus_release_resource(dev->dev->bsddev, SYS_RES_IRQ, dev->irqrid,
-                   dev->irqr);
-               if (dev->irq_type == PCI_INTR_TYPE_MSI) {
-                       pci_release_msi(dev->dev->bsddev);
-                       DRM_INFO("MSI released\n");
-               }
-       }
-
        mutex_unlock(&drm_global_mutex);
 
        return (0);
index 873c111..1dd6c53 100644 (file)
 #include "drm_trace.h"
 #include "drm_internal.h"
 
+#include <linux/interrupt.h>   /* For task queue support */
 #include <linux/slab.h>
 
+#include <linux/vgaarb.h>
 #include <linux/export.h>
 
 /* Access macro for slots in vblank timestamp ringbuffer. */
@@ -485,6 +487,7 @@ static void drm_irq_vgaarb_nokms(void *cookie, bool state)
 int drm_irq_install(struct drm_device *dev, int irq)
 {
        int ret;
+       unsigned long sh_flags = 0;
 
        if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
                return -EINVAL;
@@ -507,10 +510,13 @@ int drm_irq_install(struct drm_device *dev, int irq)
                dev->driver->irq_preinstall(dev);
 
        /* Install handler */
-       ret = -bus_setup_intr(dev->dev->bsddev, dev->irqr, INTR_MPSAFE,
-           dev->driver->irq_handler, dev, &dev->irqh, &dev->irq_lock);
+       if (drm_core_check_feature(dev, DRIVER_IRQ_SHARED))
+               sh_flags = IRQF_SHARED;
 
-       if (ret != 0) {
+       ret = request_irq(irq, dev->driver->irq_handler,
+                         sh_flags, dev->driver->name, dev);
+
+       if (ret < 0) {
                dev->irq_enabled = false;
                return ret;
        }
@@ -521,7 +527,7 @@ int drm_irq_install(struct drm_device *dev, int irq)
 
        if (ret < 0) {
                dev->irq_enabled = false;
-               bus_teardown_intr(dev->dev->bsddev, dev->irqr, dev->irqh);
+               free_irq(irq, dev);
        } else {
                dev->irq = irq;
        }
@@ -588,7 +594,7 @@ int drm_irq_uninstall(struct drm_device *dev)
        if (dev->driver->irq_uninstall)
                dev->driver->irq_uninstall(dev);
 
-       bus_teardown_intr(dev->dev->bsddev, dev->irqr, dev->irqh);
+       free_irq(dev->irq, dev);
 
        return 0;
 }
index 34e589e..0371929 100644 (file)
  *
  */
 
+#define KBUILD_MODNAME "i915"
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/sysrq.h>
 #include <linux/circ_buf.h>
 #include <drm/drmP.h>
 #include <drm/i915_drm.h>
@@ -1324,11 +1329,13 @@ static irqreturn_t gen8_gt_irq_ack(struct drm_i915_private *dev_priv,
                                   u32 master_ctl,
                                   u32 gt_iir[4])
 {
+       irqreturn_t ret = IRQ_NONE;
 
        if (master_ctl & (GEN8_GT_RCS_IRQ | GEN8_GT_BCS_IRQ)) {
                gt_iir[0] = I915_READ_FW(GEN8_GT_IIR(0));
                if (gt_iir[0]) {
                        I915_WRITE_FW(GEN8_GT_IIR(0), gt_iir[0]);
+                       ret = IRQ_HANDLED;
                } else
                        DRM_ERROR("The master control interrupt lied (GT0)!\n");
        }
@@ -1337,6 +1344,7 @@ static irqreturn_t gen8_gt_irq_ack(struct drm_i915_private *dev_priv,
                gt_iir[1] = I915_READ_FW(GEN8_GT_IIR(1));
                if (gt_iir[1]) {
                        I915_WRITE_FW(GEN8_GT_IIR(1), gt_iir[1]);
+                       ret = IRQ_HANDLED;
                } else
                        DRM_ERROR("The master control interrupt lied (GT1)!\n");
        }
@@ -1345,6 +1353,7 @@ static irqreturn_t gen8_gt_irq_ack(struct drm_i915_private *dev_priv,
                gt_iir[3] = I915_READ_FW(GEN8_GT_IIR(3));
                if (gt_iir[3]) {
                        I915_WRITE_FW(GEN8_GT_IIR(3), gt_iir[3]);
+                       ret = IRQ_HANDLED;
                } else
                        DRM_ERROR("The master control interrupt lied (GT3)!\n");
        }
@@ -1354,10 +1363,12 @@ static irqreturn_t gen8_gt_irq_ack(struct drm_i915_private *dev_priv,
                if (gt_iir[2] & dev_priv->pm_rps_events) {
                        I915_WRITE_FW(GEN8_GT_IIR(2),
                                      gt_iir[2] & dev_priv->pm_rps_events);
+                       ret = IRQ_HANDLED;
                } else
                        DRM_ERROR("The master control interrupt lied (PM)!\n");
        }
 
+       return ret;
 }
 
 static void gen8_gt_irq_handler(struct drm_i915_private *dev_priv,
@@ -1767,10 +1778,11 @@ static void i9xx_hpd_irq_handler(struct drm_device *dev,
        }
 }
 
-static irqreturn_t valleyview_irq_handler(void *arg)
+static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 {
        struct drm_device *dev = arg;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       irqreturn_t ret = IRQ_NONE;
 
        if (!intel_irqs_enabled(dev_priv))
                return IRQ_NONE;
@@ -1791,6 +1803,7 @@ static irqreturn_t valleyview_irq_handler(void *arg)
                if (gt_iir == 0 && pm_iir == 0 && iir == 0)
                        break;
 
+               ret = IRQ_HANDLED;
 
                /*
                 * Theory on interrupt generation, based on empirical evidence:
@@ -1845,12 +1858,14 @@ static irqreturn_t valleyview_irq_handler(void *arg)
 
        enable_rpm_wakeref_asserts(dev_priv);
 
+       return ret;
 }
 
-static irqreturn_t cherryview_irq_handler(void *arg)
+static irqreturn_t cherryview_irq_handler(int irq, void *arg)
 {
        struct drm_device *dev = arg;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       irqreturn_t ret = IRQ_NONE;
 
        if (!intel_irqs_enabled(dev_priv))
                return IRQ_NONE;
@@ -1871,6 +1886,7 @@ static irqreturn_t cherryview_irq_handler(void *arg)
                if (master_ctl == 0 && iir == 0)
                        break;
 
+               ret = IRQ_HANDLED;
 
                /*
                 * Theory on interrupt generation, based on empirical evidence:
@@ -1919,6 +1935,7 @@ static irqreturn_t cherryview_irq_handler(void *arg)
 
        enable_rpm_wakeref_asserts(dev_priv);
 
+       return ret;
 }
 
 static void ibx_hpd_irq_handler(struct drm_device *dev, u32 hotplug_trigger,
@@ -2238,11 +2255,12 @@ static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir)
  * 4 - Process the interrupt(s) that had bits set in the IIRs.
  * 5 - Re-enable Master Interrupt Control.
  */
-static irqreturn_t ironlake_irq_handler(void *arg)
+static irqreturn_t ironlake_irq_handler(int irq, void *arg)
 {
        struct drm_device *dev = arg;
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 de_iir, gt_iir, de_ier, sde_ier = 0;
+       irqreturn_t ret = IRQ_NONE;
 
        if (!intel_irqs_enabled(dev_priv))
                return IRQ_NONE;
@@ -2271,6 +2289,7 @@ static irqreturn_t ironlake_irq_handler(void *arg)
        gt_iir = I915_READ(GTIIR);
        if (gt_iir) {
                I915_WRITE(GTIIR, gt_iir);
+               ret = IRQ_HANDLED;
                if (INTEL_INFO(dev)->gen >= 6)
                        snb_gt_irq_handler(dev_priv, gt_iir);
                else
@@ -2280,6 +2299,7 @@ static irqreturn_t ironlake_irq_handler(void *arg)
        de_iir = I915_READ(DEIIR);
        if (de_iir) {
                I915_WRITE(DEIIR, de_iir);
+               ret = IRQ_HANDLED;
                if (INTEL_INFO(dev)->gen >= 7)
                        ivb_display_irq_handler(dev, de_iir);
                else
@@ -2290,6 +2310,7 @@ static irqreturn_t ironlake_irq_handler(void *arg)
                u32 pm_iir = I915_READ(GEN6_PMIIR);
                if (pm_iir) {
                        I915_WRITE(GEN6_PMIIR, pm_iir);
+                       ret = IRQ_HANDLED;
                        gen6_rps_irq_handler(dev_priv, pm_iir);
                }
        }
@@ -2304,6 +2325,7 @@ static irqreturn_t ironlake_irq_handler(void *arg)
        /* IRQs are synced during runtime_suspend, we don't require a wakeref */
        enable_rpm_wakeref_asserts(dev_priv);
 
+       return ret;
 }
 
 static void bxt_hpd_irq_handler(struct drm_device *dev, u32 hotplug_trigger,
@@ -2326,6 +2348,7 @@ static irqreturn_t
 gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
 {
        struct drm_device *dev = dev_priv->dev;
+       irqreturn_t ret = IRQ_NONE;
        u32 iir;
        enum i915_pipe pipe;
 
@@ -2333,6 +2356,7 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
                iir = I915_READ(GEN8_DE_MISC_IIR);
                if (iir) {
                        I915_WRITE(GEN8_DE_MISC_IIR, iir);
+                       ret = IRQ_HANDLED;
                        if (iir & GEN8_DE_MISC_GSE)
                                intel_opregion_asle_intr(dev);
                        else
@@ -2349,6 +2373,7 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
                        bool found = false;
 
                        I915_WRITE(GEN8_DE_PORT_IIR, iir);
+                       ret = IRQ_HANDLED;
 
                        tmp_mask = GEN8_AUX_CHANNEL_A;
                        if (INTEL_INFO(dev_priv)->gen >= 9)
@@ -2399,6 +2424,7 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
                        continue;
                }
 
+               ret = IRQ_HANDLED;
                I915_WRITE(GEN8_DE_PIPE_IIR(pipe), iir);
 
                if (iir & GEN8_PIPE_VBLANK &&
@@ -2444,6 +2470,7 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
                iir = I915_READ(SDEIIR);
                if (iir) {
                        I915_WRITE(SDEIIR, iir);
+                       ret = IRQ_HANDLED;
 
                        if (HAS_PCH_SPT(dev_priv) || HAS_PCH_KBP(dev_priv))
                                spt_irq_handler(dev, iir);
@@ -2458,14 +2485,16 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
                }
        }
 
+       return ret;
 }
 
-static irqreturn_t gen8_irq_handler(void *arg)
+static irqreturn_t gen8_irq_handler(int irq, void *arg)
 {
        struct drm_device *dev = arg;
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 master_ctl;
        u32 gt_iir[4] = {};
+       irqreturn_t ret;
 
        if (!intel_irqs_enabled(dev_priv))
                return IRQ_NONE;
@@ -2481,15 +2510,16 @@ static irqreturn_t gen8_irq_handler(void *arg)
        disable_rpm_wakeref_asserts(dev_priv);
 
        /* Find, clear, then process each source of interrupt */
-       gen8_gt_irq_ack(dev_priv, master_ctl, gt_iir);
+       ret = gen8_gt_irq_ack(dev_priv, master_ctl, gt_iir);
        gen8_gt_irq_handler(dev_priv, gt_iir);
-       gen8_de_irq_handler(dev_priv, master_ctl);
+       ret |= gen8_de_irq_handler(dev_priv, master_ctl);
 
        I915_WRITE_FW(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
        POSTING_READ_FW(GEN8_MASTER_IRQ);
 
        enable_rpm_wakeref_asserts(dev_priv);
 
+       return ret;
 }
 
 static void i915_error_wake_up(struct drm_i915_private *dev_priv,
@@ -4009,7 +4039,7 @@ check_page_flip:
        return false;
 }
 
-static irqreturn_t i8xx_irq_handler(void *arg)
+static irqreturn_t i8xx_irq_handler(int irq, void *arg)
 {
        struct drm_device *dev = arg;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -4019,6 +4049,7 @@ static irqreturn_t i8xx_irq_handler(void *arg)
        u16 flip_mask =
                I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
                I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
+       irqreturn_t ret;
 
        if (!intel_irqs_enabled(dev_priv))
                return IRQ_NONE;
@@ -4026,6 +4057,7 @@ static irqreturn_t i8xx_irq_handler(void *arg)
        /* IRQs are synced during runtime_suspend, we don't require a wakeref */
        disable_rpm_wakeref_asserts(dev_priv);
 
+       ret = IRQ_NONE;
        iir = I915_READ16(IIR);
        if (iir == 0)
                goto out;
@@ -4077,10 +4109,12 @@ static irqreturn_t i8xx_irq_handler(void *arg)
 
                iir = new_iir;
        }
+       ret = IRQ_HANDLED;
 
 out:
        enable_rpm_wakeref_asserts(dev_priv);
 
+       return ret;
 }
 
 static void i8xx_irq_uninstall(struct drm_device * dev)
@@ -4196,7 +4230,7 @@ check_page_flip:
        return false;
 }
 
-static irqreturn_t i915_irq_handler(void *arg)
+static irqreturn_t i915_irq_handler(int irq, void *arg)
 {
        struct drm_device *dev = arg;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -4204,7 +4238,7 @@ static irqreturn_t i915_irq_handler(void *arg)
        u32 flip_mask =
                I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
                I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
-       int pipe;
+       int pipe, ret = IRQ_NONE;
 
        if (!intel_irqs_enabled(dev_priv))
                return IRQ_NONE;
@@ -4293,11 +4327,13 @@ static irqreturn_t i915_irq_handler(void *arg)
                 * trigger the 99% of 100,000 interrupts test for disabling
                 * stray interrupts.
                 */
+               ret = IRQ_HANDLED;
                iir = new_iir;
        } while (iir & ~flip_mask);
 
        enable_rpm_wakeref_asserts(dev_priv);
 
+       return ret;
 }
 
 static void i915_irq_uninstall(struct drm_device * dev)
@@ -4422,13 +4458,13 @@ static void i915_hpd_irq_setup(struct drm_device *dev)
                                             hotplug_en);
 }
 
-static irqreturn_t i965_irq_handler(void *arg)
+static irqreturn_t i965_irq_handler(int irq, void *arg)
 {
        struct drm_device *dev = arg;
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 iir, new_iir;
        u32 pipe_stats[I915_MAX_PIPES];
-       int pipe;
+       int ret = IRQ_NONE, pipe;
        u32 flip_mask =
                I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
                I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
@@ -4471,6 +4507,7 @@ static irqreturn_t i965_irq_handler(void *arg)
                if (!irq_received)
                        break;
 
+               ret = IRQ_HANDLED;
 
                /* Consume port.  Then clear IIR or we'll miss events */
                if (iir & I915_DISPLAY_PORT_INTERRUPT) {
@@ -4528,6 +4565,7 @@ static irqreturn_t i965_irq_handler(void *arg)
 
        enable_rpm_wakeref_asserts(dev_priv);
 
+       return ret;
 }
 
 static void i965_irq_uninstall(struct drm_device * dev)
index 07b2292..990f5ce 100644 (file)
@@ -704,7 +704,7 @@ struct drm_driver {
 
        /* these have to be filled in */
 
-       void (*irq_handler) (void *arg);
+       irqreturn_t(*irq_handler) (int irq, void *arg);
        void (*irq_preinstall) (struct drm_device *dev);
        int (*irq_postinstall) (struct drm_device *dev);
        void (*irq_uninstall) (struct drm_device *dev);
@@ -893,11 +893,6 @@ struct drm_device {
        struct drm_device_dma *dma;             /**< Optional pointer for DMA support */
        /*@} */
 
-       int               irq_type;     /* IRQ type (MSI enabled or not) */
-       int               irqrid;       /* Interrupt used by board */
-       struct resource   *irqr;        /* Resource for interrupt used by board    */
-       void              *irqh;        /* Handle from bus_setup_intr      */
-
        /* Storage of resource pointers for drm_get_resource_* */
        struct resource   *pcir[DRM_MAX_PCI_RESOURCE];
        int               pcirid[DRM_MAX_PCI_RESOURCE];
index b181f4c..f475cb0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 François Tigeot
+ * Copyright (c) 2017-2018 François Tigeot <ftigeot@wolfpond.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -37,6 +37,8 @@
 
 #include <linux/atomic.h>
 
+#define IRQF_SHARED    0x00000080
+
 struct tasklet_struct {
        unsigned long state;
        void (*func)(unsigned long);
@@ -96,4 +98,11 @@ tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned lon
        t->data = data;
 }
 
+typedef irqreturn_t (*irq_handler_t)(int, void *);
+
+int request_irq(unsigned int irq, irq_handler_t handler,
+               unsigned long flags, const char *name, void *dev);
+
+void free_irq(unsigned int irq, void *dev_id);
+
 #endif /* _LINUX_INTERRUPT_H_ */
index 90b337b..03bd204 100644 (file)
 #ifndef _LINUX_IRQRETURN_H_
 #define _LINUX_IRQRETURN_H_
 
-typedef void   irqreturn_t;
+enum irqreturn {
+       IRQ_NONE        = 0,
+       IRQ_HANDLED     = 1,
+};
 
-#define IRQ_NONE       /* nothing, should be 0 */
-#define IRQ_HANDLED    /* nothing, should be 1 */
+typedef enum irqreturn irqreturn_t;
 
 #endif /* _LINUX_IRQRETURN_H_ */
index 5285d42..87b38a4 100644 (file)
@@ -72,6 +72,11 @@ struct pci_dev {
 
        unsigned int irq;               /* handle with care */
        void *pci_dev_data;
+
+       /* DragonFly-specific data */
+       int             _irq_type;
+       struct resource *_irqr;
+       int             _irqrid;
 };
 
 struct pci_bus {
diff --git a/sys/dev/drm/linux_irq.c b/sys/dev/drm/linux_irq.c
new file mode 100644 (file)
index 0000000..e61ac25
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2018 François Tigeot
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <drm/drmP.h>
+
+#include <sys/bus.h>
+#include <bus/pci/pcivar.h>
+
+struct irq_data {
+       unsigned int            irq;
+       void                    *dev_id;
+       irq_handler_t           handler;
+       const char              *name;
+       int                     rid;
+       struct resource         *resource;
+       void                    *cookiep;
+       struct                  lwkt_serialize irq_lock;
+       SLIST_ENTRY(irq_data)   id_irq_entries;
+};
+
+SLIST_HEAD(irq_data_list_head, irq_data) irq_list = SLIST_HEAD_INITIALIZER(irq_list);
+
+/* DragonFly irq handler, used to invoke Linux ones */
+static void
+linux_irq_handler(void *arg)
+{
+       struct irq_data *irq_entry = arg;
+
+       irq_entry->handler(irq_entry->irq, irq_entry->dev_id);
+}
+
+/*
+ * dev is a struct drm_device*
+ * returns: zero on success, non-zero on failure
+ */
+int
+request_irq(unsigned int irq, irq_handler_t handler,
+           unsigned long flags, const char *name, void *dev)
+{
+       int error;
+       struct irq_data *irq_entry;
+       struct drm_device *ddev = dev;
+       device_t bdev = ddev->dev->bsddev;
+
+       irq_entry = kmalloc(sizeof(*irq_entry), M_DRM, M_WAITOK);
+
+       /* From drm_init_pdev() */
+       irq_entry->rid = ddev->pdev->_irqrid;
+       irq_entry->resource = ddev->pdev->_irqr;
+
+       irq_entry->irq = irq;
+       irq_entry->dev_id = dev;
+       irq_entry->handler = handler;
+       irq_entry->name = name;
+       lwkt_serialize_init(&irq_entry->irq_lock);
+
+       error = bus_setup_intr(bdev, irq_entry->resource, INTR_MPSAFE,
+           linux_irq_handler, irq_entry, &irq_entry->cookiep,
+           &irq_entry->irq_lock);
+       if (error) {
+               kprintf("request_irq: failed in bus_setup_intr()\n");
+               bus_release_resource(bdev, SYS_RES_IRQ,
+                   irq_entry->rid, irq_entry->resource);
+               kfree(irq_entry);
+               return -error;
+       }
+       SLIST_INSERT_HEAD(&irq_list, irq_entry, id_irq_entries);
+
+       return 0;
+}
+
+/* dev_id is a struct drm_device* */
+void
+free_irq(unsigned int irq, void *dev_id)
+{
+       struct irq_data *irq_entry, *tmp_ie;
+       struct drm_device *ddev = dev_id;
+       device_t bsddev = ddev->dev->bsddev;
+       struct resource *res = ddev->pdev->_irqr;
+       int found = 0;
+
+       SLIST_FOREACH_MUTABLE(irq_entry, &irq_list, id_irq_entries, tmp_ie) {
+               if ((irq_entry->irq == irq) && (irq_entry->dev_id == dev_id)) {
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (!found) {
+               kprintf("free_irq: irq %d for dev_id %p was not registered\n",
+                   irq, dev_id);
+               return;
+       }
+
+       bus_teardown_intr(bsddev, res, irq_entry->cookiep);
+       bus_release_resource(bsddev, SYS_RES_IRQ, irq_entry->rid, res);
+       if (ddev->pdev->_irq_type == PCI_INTR_TYPE_MSI)
+               pci_release_msi(bsddev);
+
+       SLIST_REMOVE(&irq_list, irq_entry, irq_data, id_irq_entries);
+       kfree(irq_entry);
+}
index 8603819..d4a0ddf 100644 (file)
  * radeon_irq_process is a macro that points to the per-asic
  * irq handler callback.
  */
-irqreturn_t radeon_driver_irq_handler_kms(void *arg)
+irqreturn_t radeon_driver_irq_handler_kms(int irq, void *arg)
 {
        struct drm_device *dev = (struct drm_device *) arg;
        struct radeon_device *rdev = dev->dev_private;
-#ifdef PM_TODO
        irqreturn_t ret;
 
        ret = radeon_irq_process(rdev);
+#ifdef PM_TODO
        if (ret == IRQ_HANDLED)
                pm_runtime_mark_last_busy(dev->dev);
-       return ret;
-#else
-       return radeon_irq_process(rdev);
 #endif
+       return ret;
 }
 
 /*
@@ -264,7 +262,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
        }
 
        /* enable msi */
-       rdev->msi_enabled = (rdev->ddev->irq_type == PCI_INTR_TYPE_MSI);
+       rdev->msi_enabled = (rdev->ddev->pdev->_irq_type == PCI_INTR_TYPE_MSI);
 
 #ifndef __DragonFly__
        if (radeon_msi_ok(rdev)) {
@@ -283,7 +281,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
        TASK_INIT(&rdev->audio_work, 0, r600_audio_update_hdmi, rdev);
 
        rdev->irq.installed = true;
-       r = drm_irq_install(rdev->ddev, rdev->ddev->irq);
+       r = drm_irq_install(rdev->ddev, rdev->ddev->pdev->irq);
        if (r) {
                rdev->irq.installed = false;
                taskqueue_drain(rdev->tq, &rdev->hotplug_work);
index d0a4ee6..ba16adf 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __RADEON_IRQ_KMS_H__
 #define        __RADEON_IRQ_KMS_H__
 
-irqreturn_t radeon_driver_irq_handler_kms(void *arg);
+irqreturn_t radeon_driver_irq_handler_kms(int irq, void *arg);
 void radeon_driver_irq_preinstall_kms(struct drm_device *dev);
 int radeon_driver_irq_postinstall_kms(struct drm_device *dev);
 void radeon_driver_irq_uninstall_kms(struct drm_device *dev);