120c04ff7SFrançois Tigeot /*
220c04ff7SFrançois Tigeot * drm_irq.c IRQ and vblank support
3782e40d3SFrançois Tigeot *
4782e40d3SFrançois Tigeot * \author Rickard E. (Rik) Faith <faith@valinux.com>
5782e40d3SFrançois Tigeot * \author Gareth Hughes <gareth@valinux.com>
6*3f2dd94aSFrançois Tigeot *
7*3f2dd94aSFrançois Tigeot * Permission is hereby granted, free of charge, to any person obtaining a
8*3f2dd94aSFrançois Tigeot * copy of this software and associated documentation files (the "Software"),
9*3f2dd94aSFrançois Tigeot * to deal in the Software without restriction, including without limitation
10*3f2dd94aSFrançois Tigeot * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11*3f2dd94aSFrançois Tigeot * and/or sell copies of the Software, and to permit persons to whom the
12*3f2dd94aSFrançois Tigeot * Software is furnished to do so, subject to the following conditions:
13*3f2dd94aSFrançois Tigeot *
14*3f2dd94aSFrançois Tigeot * The above copyright notice and this permission notice (including the next
15*3f2dd94aSFrançois Tigeot * paragraph) shall be included in all copies or substantial portions of the
16*3f2dd94aSFrançois Tigeot * Software.
17*3f2dd94aSFrançois Tigeot *
18*3f2dd94aSFrançois Tigeot * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19*3f2dd94aSFrançois Tigeot * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20*3f2dd94aSFrançois Tigeot * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21*3f2dd94aSFrançois Tigeot * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22*3f2dd94aSFrançois Tigeot * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23*3f2dd94aSFrançois Tigeot * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24*3f2dd94aSFrançois Tigeot * OTHER DEALINGS IN THE SOFTWARE.
25782e40d3SFrançois Tigeot */
26782e40d3SFrançois Tigeot
27782e40d3SFrançois Tigeot /*
28782e40d3SFrançois Tigeot * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com
29782e40d3SFrançois Tigeot *
30782e40d3SFrançois Tigeot * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
31782e40d3SFrançois Tigeot * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
327f3c3d6fSHasso Tepper * All Rights Reserved.
337f3c3d6fSHasso Tepper *
347f3c3d6fSHasso Tepper * Permission is hereby granted, free of charge, to any person obtaining a
357f3c3d6fSHasso Tepper * copy of this software and associated documentation files (the "Software"),
367f3c3d6fSHasso Tepper * to deal in the Software without restriction, including without limitation
377f3c3d6fSHasso Tepper * the rights to use, copy, modify, merge, publish, distribute, sublicense,
387f3c3d6fSHasso Tepper * and/or sell copies of the Software, and to permit persons to whom the
397f3c3d6fSHasso Tepper * Software is furnished to do so, subject to the following conditions:
407f3c3d6fSHasso Tepper *
417f3c3d6fSHasso Tepper * The above copyright notice and this permission notice (including the next
427f3c3d6fSHasso Tepper * paragraph) shall be included in all copies or substantial portions of the
437f3c3d6fSHasso Tepper * Software.
447f3c3d6fSHasso Tepper *
457f3c3d6fSHasso Tepper * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
467f3c3d6fSHasso Tepper * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
477f3c3d6fSHasso Tepper * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
48782e40d3SFrançois Tigeot * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
49782e40d3SFrançois Tigeot * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
50782e40d3SFrançois Tigeot * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
51782e40d3SFrançois Tigeot * OTHER DEALINGS IN THE SOFTWARE.
527f3c3d6fSHasso Tepper */
537f3c3d6fSHasso Tepper
54*3f2dd94aSFrançois Tigeot #include <drm/drm_irq.h>
5518e26a6dSFrançois Tigeot #include <drm/drmP.h>
567f3c3d6fSHasso Tepper
57183e2373SFrançois Tigeot #include <linux/interrupt.h> /* For task queue support */
58ba55f2f5SFrançois Tigeot
59183e2373SFrançois Tigeot #include <linux/vgaarb.h>
60ba55f2f5SFrançois Tigeot #include <linux/export.h>
61ba55f2f5SFrançois Tigeot
62*3f2dd94aSFrançois Tigeot #include "drm_internal.h"
634be47400SFrançois Tigeot
641dedbd3bSFrançois Tigeot /**
65*3f2dd94aSFrançois Tigeot * DOC: irq helpers
661dedbd3bSFrançois Tigeot *
67*3f2dd94aSFrançois Tigeot * The DRM core provides very simple support helpers to enable IRQ handling on a
68*3f2dd94aSFrançois Tigeot * device through the drm_irq_install() and drm_irq_uninstall() functions. This
69*3f2dd94aSFrançois Tigeot * only supports devices with a single interrupt on the main device stored in
70*3f2dd94aSFrançois Tigeot * &drm_device.dev and set as the device paramter in drm_dev_alloc().
711dedbd3bSFrançois Tigeot *
72*3f2dd94aSFrançois Tigeot * These IRQ helpers are strictly optional. Drivers which roll their own only
73*3f2dd94aSFrançois Tigeot * need to set &drm_device.irq_enabled to signal the DRM core that vblank
74*3f2dd94aSFrançois Tigeot * interrupts are working. Since these helpers don't automatically clean up the
75*3f2dd94aSFrançois Tigeot * requested interrupt like e.g. devm_request_irq() they're not really
76*3f2dd94aSFrançois Tigeot * recommended.
771dedbd3bSFrançois Tigeot */
785718399fSFrançois Tigeot
79ea2ce9e4SFrançois Tigeot /**
8020c04ff7SFrançois Tigeot * drm_irq_install - install IRQ handler
8120c04ff7SFrançois Tigeot * @dev: DRM device
8220c04ff7SFrançois Tigeot * @irq: IRQ number to install the handler for
83ea2ce9e4SFrançois Tigeot *
84ea2ce9e4SFrançois Tigeot * Initializes the IRQ related data. Installs the handler, calling the driver
85*3f2dd94aSFrançois Tigeot * &drm_driver.irq_preinstall and &drm_driver.irq_postinstall functions before
86*3f2dd94aSFrançois Tigeot * and after the installation.
8720c04ff7SFrançois Tigeot *
8820c04ff7SFrançois Tigeot * This is the simplified helper interface provided for drivers with no special
8920c04ff7SFrançois Tigeot * needs. Drivers which need to install interrupt handlers for multiple
90a85cb24fSFrançois Tigeot * interrupts must instead set &drm_device.irq_enabled to signal the DRM core
9120c04ff7SFrançois Tigeot * that vblank interrupts are available.
9220c04ff7SFrançois Tigeot *
93*3f2dd94aSFrançois Tigeot * @irq must match the interrupt number that would be passed to request_irq(),
94*3f2dd94aSFrançois Tigeot * if called directly instead of using this helper function.
95*3f2dd94aSFrançois Tigeot *
96*3f2dd94aSFrançois Tigeot * &drm_driver.irq_handler is called to handle the registered interrupt.
97*3f2dd94aSFrançois Tigeot *
9820c04ff7SFrançois Tigeot * Returns:
9920c04ff7SFrançois Tigeot * Zero on success or a negative error code on failure.
100ea2ce9e4SFrançois Tigeot */
drm_irq_install(struct drm_device * dev,int irq)101ba55f2f5SFrançois Tigeot int drm_irq_install(struct drm_device *dev, int irq)
10203ad0861SFrançois Tigeot {
103ea2ce9e4SFrançois Tigeot int ret;
104183e2373SFrançois Tigeot unsigned long sh_flags = 0;
10503ad0861SFrançois Tigeot
106ea2ce9e4SFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
107ea2ce9e4SFrançois Tigeot return -EINVAL;
10803ad0861SFrançois Tigeot
109ba55f2f5SFrançois Tigeot if (irq == 0)
110ea2ce9e4SFrançois Tigeot return -EINVAL;
11103ad0861SFrançois Tigeot
112ea2ce9e4SFrançois Tigeot /* Driver must have been initialized */
113ba55f2f5SFrançois Tigeot if (!dev->dev_private)
114ea2ce9e4SFrançois Tigeot return -EINVAL;
115ea2ce9e4SFrançois Tigeot
116ba55f2f5SFrançois Tigeot if (dev->irq_enabled)
117ea2ce9e4SFrançois Tigeot return -EBUSY;
11820c04ff7SFrançois Tigeot dev->irq_enabled = true;
11903ad0861SFrançois Tigeot
120ba55f2f5SFrançois Tigeot DRM_DEBUG("irq=%d\n", irq);
12103ad0861SFrançois Tigeot
12203ad0861SFrançois Tigeot /* Before installing handler */
12303ad0861SFrançois Tigeot if (dev->driver->irq_preinstall)
12403ad0861SFrançois Tigeot dev->driver->irq_preinstall(dev);
12503ad0861SFrançois Tigeot
12603ad0861SFrançois Tigeot /* Install handler */
127183e2373SFrançois Tigeot if (drm_core_check_feature(dev, DRIVER_IRQ_SHARED))
128183e2373SFrançois Tigeot sh_flags = IRQF_SHARED;
12903ad0861SFrançois Tigeot
130183e2373SFrançois Tigeot ret = request_irq(irq, dev->driver->irq_handler,
131183e2373SFrançois Tigeot sh_flags, dev->driver->name, dev);
132183e2373SFrançois Tigeot
133183e2373SFrançois Tigeot if (ret < 0) {
13420c04ff7SFrançois Tigeot dev->irq_enabled = false;
135ea2ce9e4SFrançois Tigeot return ret;
13603ad0861SFrançois Tigeot }
13703ad0861SFrançois Tigeot
138ea2ce9e4SFrançois Tigeot /* After installing handler */
139ea2ce9e4SFrançois Tigeot if (dev->driver->irq_postinstall)
140ea2ce9e4SFrançois Tigeot ret = dev->driver->irq_postinstall(dev);
141ea2ce9e4SFrançois Tigeot
142ea2ce9e4SFrançois Tigeot if (ret < 0) {
14320c04ff7SFrançois Tigeot dev->irq_enabled = false;
144*3f2dd94aSFrançois Tigeot #if 0
145*3f2dd94aSFrançois Tigeot if (drm_core_check_feature(dev, DRIVER_LEGACY))
146*3f2dd94aSFrançois Tigeot vga_client_register(dev->pdev, NULL, NULL, NULL);
147*3f2dd94aSFrançois Tigeot #endif
148183e2373SFrançois Tigeot free_irq(irq, dev);
149ba55f2f5SFrançois Tigeot } else {
150ba55f2f5SFrançois Tigeot dev->irq = irq;
151ea2ce9e4SFrançois Tigeot }
152ea2ce9e4SFrançois Tigeot
153ea2ce9e4SFrançois Tigeot return ret;
154ea2ce9e4SFrançois Tigeot }
155ea2ce9e4SFrançois Tigeot EXPORT_SYMBOL(drm_irq_install);
156ea2ce9e4SFrançois Tigeot
157ea2ce9e4SFrançois Tigeot /**
15820c04ff7SFrançois Tigeot * drm_irq_uninstall - uninstall the IRQ handler
15920c04ff7SFrançois Tigeot * @dev: DRM device
160ea2ce9e4SFrançois Tigeot *
161*3f2dd94aSFrançois Tigeot * Calls the driver's &drm_driver.irq_uninstall function and unregisters the IRQ
162*3f2dd94aSFrançois Tigeot * handler. This should only be called by drivers which used drm_irq_install()
163*3f2dd94aSFrançois Tigeot * to set up their interrupt handler. Other drivers must only reset
164a85cb24fSFrançois Tigeot * &drm_device.irq_enabled to false.
165ea2ce9e4SFrançois Tigeot *
16620c04ff7SFrançois Tigeot * Note that for kernel modesetting drivers it is a bug if this function fails.
16720c04ff7SFrançois Tigeot * The sanity checks are only to catch buggy user modesetting drivers which call
16820c04ff7SFrançois Tigeot * the same function through an ioctl.
16920c04ff7SFrançois Tigeot *
17020c04ff7SFrançois Tigeot * Returns:
17120c04ff7SFrançois Tigeot * Zero on success or a negative error code on failure.
172ea2ce9e4SFrançois Tigeot */
drm_irq_uninstall(struct drm_device * dev)17303ad0861SFrançois Tigeot int drm_irq_uninstall(struct drm_device *dev)
17403ad0861SFrançois Tigeot {
17593fbfa9aSFrançois Tigeot unsigned long irqflags;
176782e40d3SFrançois Tigeot bool irq_enabled;
177782e40d3SFrançois Tigeot int i;
17803ad0861SFrançois Tigeot
179ea2ce9e4SFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
180ea2ce9e4SFrançois Tigeot return -EINVAL;
18103ad0861SFrançois Tigeot
182ea2ce9e4SFrançois Tigeot irq_enabled = dev->irq_enabled;
183782e40d3SFrançois Tigeot dev->irq_enabled = false;
18403ad0861SFrançois Tigeot
18503ad0861SFrançois Tigeot /*
18619c468b4SFrançois Tigeot * Wake up any waiters so they don't hang. This is just to paper over
1871dedbd3bSFrançois Tigeot * issues for UMS drivers which aren't in full control of their
18819c468b4SFrançois Tigeot * vblank/irq handling. KMS drivers must ensure that vblanks are all
18919c468b4SFrançois Tigeot * disabled when uninstalling the irq handler.
19003ad0861SFrançois Tigeot */
19103ad0861SFrançois Tigeot if (dev->num_crtcs) {
19293fbfa9aSFrançois Tigeot spin_lock_irqsave(&dev->vbl_lock, irqflags);
19303ad0861SFrançois Tigeot for (i = 0; i < dev->num_crtcs; i++) {
19420c04ff7SFrançois Tigeot struct drm_vblank_crtc *vblank = &dev->vblank[i];
19520c04ff7SFrançois Tigeot
19619c468b4SFrançois Tigeot if (!vblank->enabled)
19719c468b4SFrançois Tigeot continue;
19819c468b4SFrançois Tigeot
19919c468b4SFrançois Tigeot WARN_ON(drm_core_check_feature(dev, DRIVER_MODESET));
20019c468b4SFrançois Tigeot
201*3f2dd94aSFrançois Tigeot drm_vblank_disable_and_save(dev, i);
20220c04ff7SFrançois Tigeot wake_up(&vblank->queue);
20303ad0861SFrançois Tigeot }
20493fbfa9aSFrançois Tigeot spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
20503ad0861SFrançois Tigeot }
20603ad0861SFrançois Tigeot
207ea2ce9e4SFrançois Tigeot if (!irq_enabled)
208ea2ce9e4SFrançois Tigeot return -EINVAL;
209ea2ce9e4SFrançois Tigeot
21003ad0861SFrançois Tigeot DRM_DEBUG("irq=%d\n", dev->irq);
21103ad0861SFrançois Tigeot
212a85cb24fSFrançois Tigeot #if 0
213a85cb24fSFrançois Tigeot if (drm_core_check_feature(dev, DRIVER_LEGACY))
214a85cb24fSFrançois Tigeot vga_client_register(dev->pdev, NULL, NULL, NULL);
215a85cb24fSFrançois Tigeot #endif
216a85cb24fSFrançois Tigeot
21703ad0861SFrançois Tigeot if (dev->driver->irq_uninstall)
21803ad0861SFrançois Tigeot dev->driver->irq_uninstall(dev);
21903ad0861SFrançois Tigeot
220183e2373SFrançois Tigeot free_irq(dev->irq, dev);
22103ad0861SFrançois Tigeot
22203ad0861SFrançois Tigeot return 0;
22303ad0861SFrançois Tigeot }
224ea2ce9e4SFrançois Tigeot EXPORT_SYMBOL(drm_irq_uninstall);
22503ad0861SFrançois Tigeot
drm_legacy_irq_control(struct drm_device * dev,void * data,struct drm_file * file_priv)226a85cb24fSFrançois Tigeot int drm_legacy_irq_control(struct drm_device *dev, void *data,
227ea2ce9e4SFrançois Tigeot struct drm_file *file_priv)
22803ad0861SFrançois Tigeot {
22903ad0861SFrançois Tigeot struct drm_control *ctl = data;
230ba55f2f5SFrançois Tigeot int ret = 0, irq;
231ea2ce9e4SFrançois Tigeot
232ea2ce9e4SFrançois Tigeot /* if we haven't irq we fallback for compatibility reasons -
233ea2ce9e4SFrançois Tigeot * this used to be a separate function in drm_dma.h
234ea2ce9e4SFrançois Tigeot */
235ea2ce9e4SFrançois Tigeot
236ba55f2f5SFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
237ba55f2f5SFrançois Tigeot return 0;
2381dedbd3bSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_LEGACY))
239ba55f2f5SFrançois Tigeot return 0;
2401dedbd3bSFrançois Tigeot /* UMS was only ever supported on pci devices. */
241ba55f2f5SFrançois Tigeot if (WARN_ON(!dev->pdev))
242ba55f2f5SFrançois Tigeot return -EINVAL;
24303ad0861SFrançois Tigeot
24403ad0861SFrançois Tigeot switch (ctl->func) {
24503ad0861SFrançois Tigeot case DRM_INST_HANDLER:
246d4d73b30SFrançois Tigeot irq = dev->pdev->irq;
247ba55f2f5SFrançois Tigeot
24803ad0861SFrançois Tigeot if (dev->if_version < DRM_IF_VERSION(1, 2) &&
249ba55f2f5SFrançois Tigeot ctl->irq != irq)
250ea2ce9e4SFrançois Tigeot return -EINVAL;
251ba55f2f5SFrançois Tigeot mutex_lock(&dev->struct_mutex);
252ba55f2f5SFrançois Tigeot ret = drm_irq_install(dev, irq);
253ba55f2f5SFrançois Tigeot mutex_unlock(&dev->struct_mutex);
254ba55f2f5SFrançois Tigeot
255ba55f2f5SFrançois Tigeot return ret;
25603ad0861SFrançois Tigeot case DRM_UNINST_HANDLER:
257ba55f2f5SFrançois Tigeot mutex_lock(&dev->struct_mutex);
258ba55f2f5SFrançois Tigeot ret = drm_irq_uninstall(dev);
259ba55f2f5SFrançois Tigeot mutex_unlock(&dev->struct_mutex);
260ba55f2f5SFrançois Tigeot
261ba55f2f5SFrançois Tigeot return ret;
26203ad0861SFrançois Tigeot default:
263ea2ce9e4SFrançois Tigeot return -EINVAL;
26403ad0861SFrançois Tigeot }
26503ad0861SFrançois Tigeot }
266