xref: /dflybsd-src/sys/dev/drm/drm_irq.c (revision 3f2dd94a569761201b5b0a18b2f697f97fe1b9dc)
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