Branch data Line data Source code
1 : : /*
2 : : * drm_irq.c IRQ and vblank support
3 : : *
4 : : * \author Rickard E. (Rik) Faith <faith@valinux.com>
5 : : * \author Gareth Hughes <gareth@valinux.com>
6 : : *
7 : : * Permission is hereby granted, free of charge, to any person obtaining a
8 : : * copy of this software and associated documentation files (the "Software"),
9 : : * to deal in the Software without restriction, including without limitation
10 : : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 : : * and/or sell copies of the Software, and to permit persons to whom the
12 : : * Software is furnished to do so, subject to the following conditions:
13 : : *
14 : : * The above copyright notice and this permission notice (including the next
15 : : * paragraph) shall be included in all copies or substantial portions of the
16 : : * Software.
17 : : *
18 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 : : * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22 : : * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23 : : * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 : : * OTHER DEALINGS IN THE SOFTWARE.
25 : : */
26 : :
27 : : /*
28 : : * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com
29 : : *
30 : : * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
31 : : * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
32 : : * All Rights Reserved.
33 : : *
34 : : * Permission is hereby granted, free of charge, to any person obtaining a
35 : : * copy of this software and associated documentation files (the "Software"),
36 : : * to deal in the Software without restriction, including without limitation
37 : : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
38 : : * and/or sell copies of the Software, and to permit persons to whom the
39 : : * Software is furnished to do so, subject to the following conditions:
40 : : *
41 : : * The above copyright notice and this permission notice (including the next
42 : : * paragraph) shall be included in all copies or substantial portions of the
43 : : * Software.
44 : : *
45 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
46 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
47 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
48 : : * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
49 : : * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
50 : : * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
51 : : * OTHER DEALINGS IN THE SOFTWARE.
52 : : */
53 : :
54 : :
55 : : #include <linux/export.h>
56 : : #include <linux/interrupt.h> /* For task queue support */
57 : : #include <linux/pci.h>
58 : : #include <linux/vgaarb.h>
59 : :
60 : : #include <drm/drm.h>
61 : : #include <drm/drm_device.h>
62 : : #include <drm/drm_drv.h>
63 : : #include <drm/drm_irq.h>
64 : : #include <drm/drm_print.h>
65 : : #include <drm/drm_vblank.h>
66 : :
67 : : #include "drm_internal.h"
68 : :
69 : : /**
70 : : * DOC: irq helpers
71 : : *
72 : : * The DRM core provides very simple support helpers to enable IRQ handling on a
73 : : * device through the drm_irq_install() and drm_irq_uninstall() functions. This
74 : : * only supports devices with a single interrupt on the main device stored in
75 : : * &drm_device.dev and set as the device paramter in drm_dev_alloc().
76 : : *
77 : : * These IRQ helpers are strictly optional. Drivers which roll their own only
78 : : * need to set &drm_device.irq_enabled to signal the DRM core that vblank
79 : : * interrupts are working. Since these helpers don't automatically clean up the
80 : : * requested interrupt like e.g. devm_request_irq() they're not really
81 : : * recommended.
82 : : */
83 : :
84 : : /**
85 : : * drm_irq_install - install IRQ handler
86 : : * @dev: DRM device
87 : : * @irq: IRQ number to install the handler for
88 : : *
89 : : * Initializes the IRQ related data. Installs the handler, calling the driver
90 : : * &drm_driver.irq_preinstall and &drm_driver.irq_postinstall functions before
91 : : * and after the installation.
92 : : *
93 : : * This is the simplified helper interface provided for drivers with no special
94 : : * needs. Drivers which need to install interrupt handlers for multiple
95 : : * interrupts must instead set &drm_device.irq_enabled to signal the DRM core
96 : : * that vblank interrupts are available.
97 : : *
98 : : * @irq must match the interrupt number that would be passed to request_irq(),
99 : : * if called directly instead of using this helper function.
100 : : *
101 : : * &drm_driver.irq_handler is called to handle the registered interrupt.
102 : : *
103 : : * Returns:
104 : : * Zero on success or a negative error code on failure.
105 : : */
106 : 0 : int drm_irq_install(struct drm_device *dev, int irq)
107 : : {
108 : 0 : int ret;
109 : 0 : unsigned long sh_flags = 0;
110 : :
111 [ # # ]: 0 : if (irq == 0)
112 : : return -EINVAL;
113 : :
114 : : /* Driver must have been initialized */
115 [ # # ]: 0 : if (!dev->dev_private)
116 : : return -EINVAL;
117 : :
118 [ # # ]: 0 : if (dev->irq_enabled)
119 : : return -EBUSY;
120 : 0 : dev->irq_enabled = true;
121 : :
122 : 0 : DRM_DEBUG("irq=%d\n", irq);
123 : :
124 : : /* Before installing handler */
125 [ # # ]: 0 : if (dev->driver->irq_preinstall)
126 : 0 : dev->driver->irq_preinstall(dev);
127 : :
128 : : /* PCI devices require shared interrupts. */
129 [ # # ]: 0 : if (dev->pdev)
130 : 0 : sh_flags = IRQF_SHARED;
131 : :
132 : 0 : ret = request_irq(irq, dev->driver->irq_handler,
133 : 0 : sh_flags, dev->driver->name, dev);
134 : :
135 [ # # ]: 0 : if (ret < 0) {
136 : 0 : dev->irq_enabled = false;
137 : 0 : return ret;
138 : : }
139 : :
140 : : /* After installing handler */
141 [ # # ]: 0 : if (dev->driver->irq_postinstall)
142 : 0 : ret = dev->driver->irq_postinstall(dev);
143 : :
144 [ # # ]: 0 : if (ret < 0) {
145 : 0 : dev->irq_enabled = false;
146 [ # # ]: 0 : if (drm_core_check_feature(dev, DRIVER_LEGACY))
147 : 0 : vga_client_register(dev->pdev, NULL, NULL, NULL);
148 : 0 : free_irq(irq, dev);
149 : : } else {
150 : 0 : dev->irq = irq;
151 : : }
152 : :
153 : : return ret;
154 : : }
155 : : EXPORT_SYMBOL(drm_irq_install);
156 : :
157 : : /**
158 : : * drm_irq_uninstall - uninstall the IRQ handler
159 : : * @dev: DRM device
160 : : *
161 : : * Calls the driver's &drm_driver.irq_uninstall function and unregisters the IRQ
162 : : * handler. This should only be called by drivers which used drm_irq_install()
163 : : * to set up their interrupt handler. Other drivers must only reset
164 : : * &drm_device.irq_enabled to false.
165 : : *
166 : : * Note that for kernel modesetting drivers it is a bug if this function fails.
167 : : * The sanity checks are only to catch buggy user modesetting drivers which call
168 : : * the same function through an ioctl.
169 : : *
170 : : * Returns:
171 : : * Zero on success or a negative error code on failure.
172 : : */
173 : 0 : int drm_irq_uninstall(struct drm_device *dev)
174 : : {
175 : 0 : unsigned long irqflags;
176 : 0 : bool irq_enabled;
177 : 0 : int i;
178 : :
179 : 0 : irq_enabled = dev->irq_enabled;
180 : 0 : dev->irq_enabled = false;
181 : :
182 : : /*
183 : : * Wake up any waiters so they don't hang. This is just to paper over
184 : : * issues for UMS drivers which aren't in full control of their
185 : : * vblank/irq handling. KMS drivers must ensure that vblanks are all
186 : : * disabled when uninstalling the irq handler.
187 : : */
188 [ # # ]: 0 : if (dev->num_crtcs) {
189 : 0 : spin_lock_irqsave(&dev->vbl_lock, irqflags);
190 [ # # ]: 0 : for (i = 0; i < dev->num_crtcs; i++) {
191 : 0 : struct drm_vblank_crtc *vblank = &dev->vblank[i];
192 : :
193 [ # # ]: 0 : if (!vblank->enabled)
194 : 0 : continue;
195 : :
196 [ # # ]: 0 : WARN_ON(drm_core_check_feature(dev, DRIVER_MODESET));
197 : :
198 : 0 : drm_vblank_disable_and_save(dev, i);
199 : 0 : wake_up(&vblank->queue);
200 : : }
201 : 0 : spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
202 : : }
203 : :
204 [ # # ]: 0 : if (!irq_enabled)
205 : : return -EINVAL;
206 : :
207 : 0 : DRM_DEBUG("irq=%d\n", dev->irq);
208 : :
209 [ # # ]: 0 : if (drm_core_check_feature(dev, DRIVER_LEGACY))
210 : 0 : vga_client_register(dev->pdev, NULL, NULL, NULL);
211 : :
212 [ # # ]: 0 : if (dev->driver->irq_uninstall)
213 : 0 : dev->driver->irq_uninstall(dev);
214 : :
215 : 0 : free_irq(dev->irq, dev);
216 : :
217 : 0 : return 0;
218 : : }
219 : : EXPORT_SYMBOL(drm_irq_uninstall);
220 : :
221 : : #if IS_ENABLED(CONFIG_DRM_LEGACY)
222 : : int drm_legacy_irq_control(struct drm_device *dev, void *data,
223 : : struct drm_file *file_priv)
224 : : {
225 : : struct drm_control *ctl = data;
226 : : int ret = 0, irq;
227 : :
228 : : /* if we haven't irq we fallback for compatibility reasons -
229 : : * this used to be a separate function in drm_dma.h
230 : : */
231 : :
232 : : if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
233 : : return 0;
234 : : if (!drm_core_check_feature(dev, DRIVER_LEGACY))
235 : : return 0;
236 : : /* UMS was only ever supported on pci devices. */
237 : : if (WARN_ON(!dev->pdev))
238 : : return -EINVAL;
239 : :
240 : : switch (ctl->func) {
241 : : case DRM_INST_HANDLER:
242 : : irq = dev->pdev->irq;
243 : :
244 : : if (dev->if_version < DRM_IF_VERSION(1, 2) &&
245 : : ctl->irq != irq)
246 : : return -EINVAL;
247 : : mutex_lock(&dev->struct_mutex);
248 : : ret = drm_irq_install(dev, irq);
249 : : mutex_unlock(&dev->struct_mutex);
250 : :
251 : : return ret;
252 : : case DRM_UNINST_HANDLER:
253 : : mutex_lock(&dev->struct_mutex);
254 : : ret = drm_irq_uninstall(dev);
255 : : mutex_unlock(&dev->struct_mutex);
256 : :
257 : : return ret;
258 : : default:
259 : : return -EINVAL;
260 : : }
261 : : }
262 : : #endif
|