2 * Copyright 2003 Eric Anholt
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * ERIC ANHOLT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 * Eric Anholt <anholt@FreeBSD.org>
26 * $DragonFly: src/sys/dev/drm/drm_irq.c,v 1.1 2008/04/05 18:12:29 hasso Exp $
30 * Support code for handling setup/teardown of interrupt handlers and
31 * handing interrupt handlers off to the drivers.
37 static void drm_locked_task(void *context, int pending __unused);
39 int drm_irq_by_busid(drm_device_t *dev, void *data, struct drm_file *file_priv)
41 drm_irq_busid_t *irq = data;
43 if ((irq->busnum >> 8) != dev->pci_domain ||
44 (irq->busnum & 0xff) != dev->pci_bus ||
45 irq->devnum != dev->pci_slot ||
46 irq->funcnum != dev->pci_func)
51 DRM_DEBUG("%d:%d:%d => IRQ %d\n",
52 irq->busnum, irq->devnum, irq->funcnum, irq->irq);
57 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
59 drm_irq_handler_wrap(DRM_IRQ_ARGS)
61 drm_device_t *dev = (drm_device_t *)arg;
63 DRM_SPINLOCK(&dev->irq_lock);
64 dev->driver.irq_handler(arg);
65 DRM_SPINUNLOCK(&dev->irq_lock);
69 int drm_irq_install(drm_device_t *dev)
76 if (dev->irq == 0 || dev->dev_private == NULL)
79 DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq );
82 if (dev->irq_enabled) {
88 dev->context_flag = 0;
91 DRM_SPININIT(&dev->irq_lock, "DRM IRQ lock");
93 lwkt_serialize_init(&dev->irq_lock);
96 /* Before installing handler */
97 dev->driver.irq_preinstall(dev);
100 /* Install handler */
101 #if defined(__FreeBSD__) || defined(__DragonFly__)
103 dev->irqr = bus_alloc_resource_any(dev->device, SYS_RES_IRQ,
104 &dev->irqrid, RF_SHAREABLE);
109 #if __FreeBSD_version >= 700031
110 retcode = bus_setup_intr(dev->device, dev->irqr,
111 INTR_TYPE_TTY | INTR_MPSAFE,
112 NULL, drm_irq_handler_wrap, dev, &dev->irqh);
113 #elif defined(__DragonFly__)
114 retcode = bus_setup_intr(dev->device, dev->irqr,
116 dev->driver.irq_handler, dev, &dev->irqh,
119 retcode = bus_setup_intr(dev->device, dev->irqr,
120 INTR_TYPE_TTY | INTR_MPSAFE,
121 drm_irq_handler_wrap, dev, &dev->irqh);
125 #elif defined(__NetBSD__) || defined(__OpenBSD__)
126 if (pci_intr_map(&dev->pa, &ih) != 0) {
130 dev->irqh = pci_intr_establish(&dev->pa.pa_pc, ih, IPL_TTY,
131 (irqreturn_t (*)(void *))dev->irq_handler, dev);
138 /* After installing handler */
140 dev->driver.irq_postinstall(dev);
143 TASK_INIT(&dev->locked_task, 0, drm_locked_task, dev);
147 dev->irq_enabled = 0;
148 #if defined(___FreeBSD__) || defined(__DragonFly__)
149 if (dev->irqrid != 0) {
150 bus_release_resource(dev->device, SYS_RES_IRQ, dev->irqrid,
155 #ifndef __DragonFly__
156 DRM_SPINUNINIT(&dev->irq_lock);
162 int drm_irq_uninstall(drm_device_t *dev)
164 #if defined(__FreeBSD__) || defined(__DragonFly__)
168 if (!dev->irq_enabled)
171 dev->irq_enabled = 0;
172 #if defined(__FreeBSD__) || defined(__DragonFly__)
173 irqrid = dev->irqrid;
177 DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq );
179 dev->driver.irq_uninstall(dev);
181 #if defined(__FreeBSD__) || defined(__DragonFly__)
183 bus_teardown_intr(dev->device, dev->irqr, dev->irqh);
184 bus_release_resource(dev->device, SYS_RES_IRQ, irqrid, dev->irqr);
186 #elif defined(__NetBSD__) || defined(__OpenBSD__)
187 pci_intr_disestablish(&dev->pa.pa_pc, dev->irqh);
189 #ifndef __DragonFly__
190 DRM_SPINUNINIT(&dev->irq_lock);
196 int drm_control(drm_device_t *dev, void *data, struct drm_file *file_priv)
198 drm_control_t *ctl = data;
201 switch ( ctl->func ) {
202 case DRM_INST_HANDLER:
203 /* Handle drivers whose DRM used to require IRQ setup but the
206 if (!dev->driver.use_irq)
208 if (dev->if_version < DRM_IF_VERSION(1, 2) &&
209 ctl->irq != dev->irq)
211 return drm_irq_install(dev);
212 case DRM_UNINST_HANDLER:
213 if (!dev->driver.use_irq)
216 err = drm_irq_uninstall(dev);
224 int drm_wait_vblank(drm_device_t *dev, void *data, struct drm_file *file_priv)
226 drm_wait_vblank_t *vblwait = data;
231 if (!dev->irq_enabled)
234 if (vblwait->request.type &
235 ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) {
236 DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n",
237 vblwait->request.type,
238 (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK));
242 flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK;
244 if ((flags & _DRM_VBLANK_SECONDARY) && !dev->driver.use_vbl_irq2)
247 seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ?
248 &dev->vbl_received2 : &dev->vbl_received);
250 switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) {
251 case _DRM_VBLANK_RELATIVE:
252 vblwait->request.sequence += seq;
253 vblwait->request.type &= ~_DRM_VBLANK_RELATIVE;
254 case _DRM_VBLANK_ABSOLUTE:
260 if ((flags & _DRM_VBLANK_NEXTONMISS) &&
261 (seq - vblwait->request.sequence) <= (1<<23)) {
262 vblwait->request.sequence = seq + 1;
265 if (flags & _DRM_VBLANK_SIGNAL) {
267 drm_vbl_sig_t *vbl_sig = malloc(sizeof(drm_vbl_sig_t), M_DRM,
272 vbl_sig->sequence = vblwait->request.sequence;
273 vbl_sig->signo = vblwait->request.signal;
274 vbl_sig->pid = DRM_CURRENTPID;
276 vblwait->reply.sequence = atomic_read(&dev->vbl_received);
278 DRM_SPINLOCK(&dev->irq_lock);
279 TAILQ_INSERT_HEAD(&dev->vbl_sig_list, vbl_sig, link);
280 DRM_SPINUNLOCK(&dev->irq_lock);
286 /* shared code returns -errno */
287 if (flags & _DRM_VBLANK_SECONDARY) {
288 if (dev->driver.vblank_wait2)
289 ret = -dev->driver.vblank_wait2(dev,
290 &vblwait->request.sequence);
291 } else if (dev->driver.vblank_wait)
292 ret = -dev->driver.vblank_wait(dev,
293 &vblwait->request.sequence);
298 vblwait->reply.tval_sec = now.tv_sec;
299 vblwait->reply.tval_usec = now.tv_usec;
305 void drm_vbl_send_signals(drm_device_t *dev)
310 void drm_vbl_send_signals( drm_device_t *dev )
312 drm_vbl_sig_t *vbl_sig;
313 unsigned int vbl_seq = atomic_read( &dev->vbl_received );
316 vbl_sig = TAILQ_FIRST(&dev->vbl_sig_list);
317 while (vbl_sig != NULL) {
318 drm_vbl_sig_t *next = TAILQ_NEXT(vbl_sig, link);
320 if ( ( vbl_seq - vbl_sig->sequence ) <= (1<<23) ) {
321 p = pfind(vbl_sig->pid);
323 psignal(p, vbl_sig->signo);
325 TAILQ_REMOVE(&dev->vbl_sig_list, vbl_sig, link);
326 DRM_FREE(vbl_sig,sizeof(*vbl_sig));
333 static void drm_locked_task(void *context, int pending __unused)
335 drm_device_t *dev = context;
341 if (drm_lock_take(&dev->lock.hw_lock->lock,
344 dev->lock.file_priv = NULL; /* kernel owned */
345 dev->lock.lock_time = jiffies;
346 atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
347 break; /* Got lock */
351 #if defined(__FreeBSD__) && __FreeBSD_version > 500000
352 ret = mtx_sleep((void *)&dev->lock.lock_queue, &dev->dev_lock,
353 PZERO | PCATCH, "drmlk2", 0);
354 #elif defined(__DragonFly__)
356 tsleep_interlock((void *)&dev->lock.lock_queue);
358 ret = tsleep((void *)&dev->lock.lock_queue, PCATCH,
363 ret = tsleep((void *)&dev->lock.lock_queue, PZERO | PCATCH,
371 dev->locked_task_call(dev);
373 drm_lock_free(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT);
377 drm_locked_tasklet(drm_device_t *dev, void (*tasklet)(drm_device_t *dev))
379 dev->locked_task_call = tasklet;
380 taskqueue_enqueue(taskqueue_swi, &dev->locked_task);