Deleted Added
full compact
drm_irq.c (166901) drm_irq.c (182080)
1/* drm_irq.c -- IRQ IOCTL and function support
2 * Created: Fri Oct 18 2003 by anholt@FreeBSD.org
3 */
4/*-
5 * Copyright 2003 Eric Anholt
6 * All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,

--- 12 unchanged lines hidden (view full) ---

24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 * Authors:
27 * Eric Anholt <anholt@FreeBSD.org>
28 *
29 */
30
31#include <sys/cdefs.h>
1/*-
2 * Copyright 2003 Eric Anholt
3 * All Rights Reserved.
4 *
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,

--- 12 unchanged lines hidden (view full) ---

21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 * Authors:
24 * Eric Anholt <anholt@FreeBSD.org>
25 *
26 */
27
28#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: head/sys/dev/drm/drm_irq.c 166901 2007-02-23 12:19:07Z piso $");
29__FBSDID("$FreeBSD: head/sys/dev/drm/drm_irq.c 182080 2008-08-23 20:59:12Z rnoland $");
33
30
31/** @file drm_irq.c
32 * Support code for handling setup/teardown of interrupt handlers and
33 * handing interrupt handlers off to the drivers.
34 */
35
34#include "dev/drm/drmP.h"
35#include "dev/drm/drm.h"
36
36#include "dev/drm/drmP.h"
37#include "dev/drm/drm.h"
38
37int drm_irq_by_busid(DRM_IOCTL_ARGS)
39static void drm_locked_task(void *context, int pending __unused);
40
41int drm_irq_by_busid(struct drm_device *dev, void *data,
42 struct drm_file *file_priv)
38{
43{
39 DRM_DEVICE;
40 drm_irq_busid_t irq;
44 drm_irq_busid_t *irq = data;
41
45
42 DRM_COPY_FROM_USER_IOCTL(irq, (drm_irq_busid_t *)data, sizeof(irq));
43
44 if ((irq.busnum >> 8) != dev->pci_domain ||
45 (irq.busnum & 0xff) != dev->pci_bus ||
46 irq.devnum != dev->pci_slot ||
47 irq.funcnum != dev->pci_func)
46 if ((irq->busnum >> 8) != dev->pci_domain ||
47 (irq->busnum & 0xff) != dev->pci_bus ||
48 irq->devnum != dev->pci_slot ||
49 irq->funcnum != dev->pci_func)
48 return EINVAL;
49
50 return EINVAL;
51
50 irq.irq = dev->irq;
52 irq->irq = dev->irq;
51
52 DRM_DEBUG("%d:%d:%d => IRQ %d\n",
53
54 DRM_DEBUG("%d:%d:%d => IRQ %d\n",
53 irq.busnum, irq.devnum, irq.funcnum, irq.irq);
55 irq->busnum, irq->devnum, irq->funcnum, irq->irq);
54
56
55 DRM_COPY_TO_USER_IOCTL( (drm_irq_busid_t *)data, irq, sizeof(irq) );
56
57 return 0;
58}
59
60#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
61static irqreturn_t
62drm_irq_handler_wrap(DRM_IRQ_ARGS)
63{
57 return 0;
58}
59
60#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
61static irqreturn_t
62drm_irq_handler_wrap(DRM_IRQ_ARGS)
63{
64 drm_device_t *dev = (drm_device_t *)arg;
64 struct drm_device *dev = arg;
65
66 DRM_SPINLOCK(&dev->irq_lock);
67 dev->driver.irq_handler(arg);
68 DRM_SPINUNLOCK(&dev->irq_lock);
69}
70#endif
71
65
66 DRM_SPINLOCK(&dev->irq_lock);
67 dev->driver.irq_handler(arg);
68 DRM_SPINUNLOCK(&dev->irq_lock);
69}
70#endif
71
72int drm_irq_install(drm_device_t *dev)
72static void vblank_disable_fn(void *arg)
73{
73{
74 struct drm_device *dev = (struct drm_device *)arg;
75 int i;
76
77 if (callout_pending(&dev->vblank_disable_timer)) {
78 /* callout was reset */
79 return;
80 }
81 if (!callout_active(&dev->vblank_disable_timer)) {
82 /* callout was stopped */
83 return;
84 }
85 callout_deactivate(&dev->vblank_disable_timer);
86
87 if (!dev->vblank_disable_allowed)
88 return;
89
90 for (i = 0; i < dev->num_crtcs; i++) {
91 if (atomic_read(&dev->vblank[i].refcount) == 0 &&
92 dev->vblank[i].enabled) {
93 DRM_DEBUG("disabling vblank on crtc %d\n", i);
94 dev->vblank[i].last =
95 dev->driver.get_vblank_counter(dev, i);
96 dev->driver.disable_vblank(dev, i);
97 dev->vblank[i].enabled = 0;
98 }
99 }
100}
101
102static void drm_vblank_cleanup(struct drm_device *dev)
103{
104 unsigned long irqflags;
105
106 /* Bail if the driver didn't call drm_vblank_init() */
107 if (dev->num_crtcs == 0)
108 return;
109
110 DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags);
111 callout_stop(&dev->vblank_disable_timer);
112 DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags);
113
114 callout_drain(&dev->vblank_disable_timer);
115
116 vblank_disable_fn((void *)dev);
117
118 drm_free(dev->vblank, sizeof(struct drm_vblank_info) * dev->num_crtcs,
119 DRM_MEM_DRIVER);
120
121 dev->num_crtcs = 0;
122}
123
124int drm_vblank_init(struct drm_device *dev, int num_crtcs)
125{
126 int i, ret = ENOMEM;
127
128 callout_init_mtx(&dev->vblank_disable_timer, &dev->vbl_lock, 0);
129 atomic_set(&dev->vbl_signal_pending, 0);
130 dev->num_crtcs = num_crtcs;
131
132 dev->vblank = drm_calloc(num_crtcs, sizeof(struct drm_vblank_info),
133 DRM_MEM_DRIVER);
134 if (!dev->vblank)
135 goto err;
136
137 /* Zero per-crtc vblank stuff */
138 for (i = 0; i < num_crtcs; i++) {
139 DRM_INIT_WAITQUEUE(&dev->vblank[i].queue);
140 TAILQ_INIT(&dev->vblank[i].sigs);
141 atomic_set(&dev->vblank[i].count, 0);
142 atomic_set(&dev->vblank[i].refcount, 0);
143 }
144
145 dev->vblank_disable_allowed = 0;
146
147 return 0;
148
149err:
150 drm_vblank_cleanup(dev);
151 return ret;
152}
153
154int drm_irq_install(struct drm_device *dev)
155{
74 int retcode;
75#ifdef __NetBSD__
76 pci_intr_handle_t ih;
77#endif
78
79 if (dev->irq == 0 || dev->dev_private == NULL)
156 int retcode;
157#ifdef __NetBSD__
158 pci_intr_handle_t ih;
159#endif
160
161 if (dev->irq == 0 || dev->dev_private == NULL)
80 return DRM_ERR(EINVAL);
162 return EINVAL;
81
82 DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq );
83
84 DRM_LOCK();
85 if (dev->irq_enabled) {
86 DRM_UNLOCK();
163
164 DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq );
165
166 DRM_LOCK();
167 if (dev->irq_enabled) {
168 DRM_UNLOCK();
87 return DRM_ERR(EBUSY);
169 return EBUSY;
88 }
89 dev->irq_enabled = 1;
90
91 dev->context_flag = 0;
92
170 }
171 dev->irq_enabled = 1;
172
173 dev->context_flag = 0;
174
93 DRM_SPININIT(dev->irq_lock, "DRM IRQ lock");
94
95 /* Before installing handler */
96 dev->driver.irq_preinstall(dev);
97 DRM_UNLOCK();
98
99 /* Install handler */
100#ifdef __FreeBSD__
101 dev->irqrid = 0;
102 dev->irqr = bus_alloc_resource_any(dev->device, SYS_RES_IRQ,
103 &dev->irqrid, RF_SHAREABLE);
104 if (!dev->irqr) {
105 retcode = ENOENT;
106 goto err;
107 }
175 /* Before installing handler */
176 dev->driver.irq_preinstall(dev);
177 DRM_UNLOCK();
178
179 /* Install handler */
180#ifdef __FreeBSD__
181 dev->irqrid = 0;
182 dev->irqr = bus_alloc_resource_any(dev->device, SYS_RES_IRQ,
183 &dev->irqrid, RF_SHAREABLE);
184 if (!dev->irqr) {
185 retcode = ENOENT;
186 goto err;
187 }
108#if __FreeBSD_version < 500000
109 retcode = bus_setup_intr(dev->device, dev->irqr, INTR_TYPE_TTY,
110 dev->irq_handler, dev, &dev->irqh);
111#else
112 retcode = bus_setup_intr(dev->device, dev->irqr, INTR_TYPE_TTY | INTR_MPSAFE,
188#if __FreeBSD_version >= 700031
189 retcode = bus_setup_intr(dev->device, dev->irqr,
190 INTR_TYPE_TTY | INTR_MPSAFE,
113 NULL, drm_irq_handler_wrap, dev, &dev->irqh);
191 NULL, drm_irq_handler_wrap, dev, &dev->irqh);
192#else
193 retcode = bus_setup_intr(dev->device, dev->irqr,
194 INTR_TYPE_TTY | INTR_MPSAFE,
195 drm_irq_handler_wrap, dev, &dev->irqh);
114#endif
115 if (retcode != 0)
116 goto err;
117#elif defined(__NetBSD__) || defined(__OpenBSD__)
118 if (pci_intr_map(&dev->pa, &ih) != 0) {
119 retcode = ENOENT;
120 goto err;
121 }

--- 5 unchanged lines hidden (view full) ---

127 }
128#endif
129
130 /* After installing handler */
131 DRM_LOCK();
132 dev->driver.irq_postinstall(dev);
133 DRM_UNLOCK();
134
196#endif
197 if (retcode != 0)
198 goto err;
199#elif defined(__NetBSD__) || defined(__OpenBSD__)
200 if (pci_intr_map(&dev->pa, &ih) != 0) {
201 retcode = ENOENT;
202 goto err;
203 }

--- 5 unchanged lines hidden (view full) ---

209 }
210#endif
211
212 /* After installing handler */
213 DRM_LOCK();
214 dev->driver.irq_postinstall(dev);
215 DRM_UNLOCK();
216
217 TASK_INIT(&dev->locked_task, 0, drm_locked_task, dev);
135 return 0;
136err:
137 DRM_LOCK();
138 dev->irq_enabled = 0;
139#ifdef ___FreeBSD__
140 if (dev->irqrid != 0) {
141 bus_release_resource(dev->device, SYS_RES_IRQ, dev->irqrid,
142 dev->irqr);
143 dev->irqrid = 0;
144 }
145#endif
218 return 0;
219err:
220 DRM_LOCK();
221 dev->irq_enabled = 0;
222#ifdef ___FreeBSD__
223 if (dev->irqrid != 0) {
224 bus_release_resource(dev->device, SYS_RES_IRQ, dev->irqrid,
225 dev->irqr);
226 dev->irqrid = 0;
227 }
228#endif
146 DRM_SPINUNINIT(dev->irq_lock);
147 DRM_UNLOCK();
148 return retcode;
149}
150
229 DRM_UNLOCK();
230 return retcode;
231}
232
151int drm_irq_uninstall(drm_device_t *dev)
233int drm_irq_uninstall(struct drm_device *dev)
152{
153#ifdef __FreeBSD__
154 int irqrid;
155#endif
156
157 if (!dev->irq_enabled)
234{
235#ifdef __FreeBSD__
236 int irqrid;
237#endif
238
239 if (!dev->irq_enabled)
158 return DRM_ERR(EINVAL);
240 return EINVAL;
159
160 dev->irq_enabled = 0;
161#ifdef __FreeBSD__
162 irqrid = dev->irqrid;
163 dev->irqrid = 0;
164#endif
165
166 DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq );
167
168 dev->driver.irq_uninstall(dev);
169
170#ifdef __FreeBSD__
171 DRM_UNLOCK();
172 bus_teardown_intr(dev->device, dev->irqr, dev->irqh);
173 bus_release_resource(dev->device, SYS_RES_IRQ, irqrid, dev->irqr);
174 DRM_LOCK();
175#elif defined(__NetBSD__) || defined(__OpenBSD__)
176 pci_intr_disestablish(&dev->pa.pa_pc, dev->irqh);
177#endif
241
242 dev->irq_enabled = 0;
243#ifdef __FreeBSD__
244 irqrid = dev->irqrid;
245 dev->irqrid = 0;
246#endif
247
248 DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq );
249
250 dev->driver.irq_uninstall(dev);
251
252#ifdef __FreeBSD__
253 DRM_UNLOCK();
254 bus_teardown_intr(dev->device, dev->irqr, dev->irqh);
255 bus_release_resource(dev->device, SYS_RES_IRQ, irqrid, dev->irqr);
256 DRM_LOCK();
257#elif defined(__NetBSD__) || defined(__OpenBSD__)
258 pci_intr_disestablish(&dev->pa.pa_pc, dev->irqh);
259#endif
178 DRM_SPINUNINIT(dev->irq_lock);
260 drm_vblank_cleanup(dev);
179
180 return 0;
181}
182
261
262 return 0;
263}
264
183int drm_control(DRM_IOCTL_ARGS)
265int drm_control(struct drm_device *dev, void *data, struct drm_file *file_priv)
184{
266{
185 DRM_DEVICE;
186 drm_control_t ctl;
267 drm_control_t *ctl = data;
187 int err;
188
268 int err;
269
189 DRM_COPY_FROM_USER_IOCTL( ctl, (drm_control_t *) data, sizeof(ctl) );
190
191 switch ( ctl.func ) {
270 switch ( ctl->func ) {
192 case DRM_INST_HANDLER:
193 /* Handle drivers whose DRM used to require IRQ setup but the
194 * no longer does.
195 */
196 if (!dev->driver.use_irq)
197 return 0;
198 if (dev->if_version < DRM_IF_VERSION(1, 2) &&
271 case DRM_INST_HANDLER:
272 /* Handle drivers whose DRM used to require IRQ setup but the
273 * no longer does.
274 */
275 if (!dev->driver.use_irq)
276 return 0;
277 if (dev->if_version < DRM_IF_VERSION(1, 2) &&
199 ctl.irq != dev->irq)
200 return DRM_ERR(EINVAL);
278 ctl->irq != dev->irq)
279 return EINVAL;
201 return drm_irq_install(dev);
202 case DRM_UNINST_HANDLER:
203 if (!dev->driver.use_irq)
204 return 0;
205 DRM_LOCK();
206 err = drm_irq_uninstall(dev);
207 DRM_UNLOCK();
208 return err;
209 default:
280 return drm_irq_install(dev);
281 case DRM_UNINST_HANDLER:
282 if (!dev->driver.use_irq)
283 return 0;
284 DRM_LOCK();
285 err = drm_irq_uninstall(dev);
286 DRM_UNLOCK();
287 return err;
288 default:
210 return DRM_ERR(EINVAL);
289 return EINVAL;
211 }
212}
213
290 }
291}
292
214int drm_wait_vblank(DRM_IOCTL_ARGS)
293u32 drm_vblank_count(struct drm_device *dev, int crtc)
215{
294{
216 DRM_DEVICE;
217 drm_wait_vblank_t vblwait;
218 struct timeval now;
219 int ret;
295 return atomic_read(&dev->vblank[crtc].count);
296}
220
297
298static void drm_update_vblank_count(struct drm_device *dev, int crtc)
299{
300 u32 cur_vblank, diff;
301
302 /*
303 * Interrupts were disabled prior to this call, so deal with counter
304 * wrap if needed.
305 * NOTE! It's possible we lost a full dev->max_vblank_count events
306 * here if the register is small or we had vblank interrupts off for
307 * a long time.
308 */
309 cur_vblank = dev->driver.get_vblank_counter(dev, crtc);
310 diff = cur_vblank - dev->vblank[crtc].last;
311 if (cur_vblank < dev->vblank[crtc].last) {
312 diff += dev->max_vblank_count;
313
314 DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n",
315 crtc, dev->vblank[crtc].last, cur_vblank, diff);
316 }
317
318 DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n",
319 crtc, diff);
320
321 atomic_add(diff, &dev->vblank[crtc].count);
322}
323
324int drm_vblank_get(struct drm_device *dev, int crtc)
325{
326 unsigned long irqflags;
327 int ret = 0;
328
329 DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags);
330 /* Going from 0->1 means we have to enable interrupts again */
331 atomic_add_acq_int(&dev->vblank[crtc].refcount, 1);
332 if (dev->vblank[crtc].refcount == 1 &&
333 !dev->vblank[crtc].enabled) {
334 ret = dev->driver.enable_vblank(dev, crtc);
335 if (ret)
336 atomic_dec(&dev->vblank[crtc].refcount);
337 else {
338 dev->vblank[crtc].enabled = 1;
339 drm_update_vblank_count(dev, crtc);
340 }
341 }
342 DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags);
343
344 return ret;
345}
346
347void drm_vblank_put(struct drm_device *dev, int crtc)
348{
349 unsigned long irqflags;
350
351 DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags);
352 /* Last user schedules interrupt disable */
353 atomic_subtract_acq_int(&dev->vblank[crtc].refcount, 1);
354 if (dev->vblank[crtc].refcount == 0)
355 callout_reset(&dev->vblank_disable_timer, 5 * DRM_HZ,
356 (timeout_t *)vblank_disable_fn, (void *)dev);
357 DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags);
358}
359
360int drm_modeset_ctl(struct drm_device *dev, void *data,
361 struct drm_file *file_priv)
362{
363 struct drm_modeset_ctl *modeset = data;
364 unsigned long irqflags;
365 int crtc, ret = 0;
366
367 /* If drm_vblank_init() hasn't been called yet, just no-op */
368 if (!dev->num_crtcs)
369 goto out;
370
371 crtc = modeset->crtc;
372 if (crtc >= dev->num_crtcs) {
373 ret = EINVAL;
374 goto out;
375 }
376
377 /*
378 * To avoid all the problems that might happen if interrupts
379 * were enabled/disabled around or between these calls, we just
380 * have the kernel take a reference on the CRTC (just once though
381 * to avoid corrupting the count if multiple, mismatch calls occur),
382 * so that interrupts remain enabled in the interim.
383 */
384 switch (modeset->cmd) {
385 case _DRM_PRE_MODESET:
386 if (!dev->vblank[crtc].inmodeset) {
387 dev->vblank[crtc].inmodeset = 1;
388 drm_vblank_get(dev, crtc);
389 }
390 break;
391 case _DRM_POST_MODESET:
392 if (dev->vblank[crtc].inmodeset) {
393 DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags);
394 dev->vblank_disable_allowed = 1;
395 dev->vblank[crtc].inmodeset = 0;
396 DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags);
397 drm_vblank_put(dev, crtc);
398 }
399 break;
400 default:
401 ret = EINVAL;
402 break;
403 }
404
405out:
406 return ret;
407}
408
409int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv)
410{
411 drm_wait_vblank_t *vblwait = data;
412 int ret = 0;
413 int flags, seq, crtc;
414
221 if (!dev->irq_enabled)
415 if (!dev->irq_enabled)
222 return DRM_ERR(EINVAL);
416 return EINVAL;
223
417
224 DRM_COPY_FROM_USER_IOCTL( vblwait, (drm_wait_vblank_t *)data,
225 sizeof(vblwait) );
418 if (vblwait->request.type &
419 ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) {
420 DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n",
421 vblwait->request.type,
422 (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK));
423 return EINVAL;
424 }
226
425
227 if (vblwait.request.type & _DRM_VBLANK_RELATIVE) {
228 vblwait.request.sequence += atomic_read(&dev->vbl_received);
229 vblwait.request.type &= ~_DRM_VBLANK_RELATIVE;
426 flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK;
427 crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
428
429 if (crtc >= dev->num_crtcs)
430 return EINVAL;
431
432 ret = drm_vblank_get(dev, crtc);
433 if (ret)
434 return ret;
435 seq = drm_vblank_count(dev, crtc);
436
437 switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) {
438 case _DRM_VBLANK_RELATIVE:
439 vblwait->request.sequence += seq;
440 vblwait->request.type &= ~_DRM_VBLANK_RELATIVE;
441 case _DRM_VBLANK_ABSOLUTE:
442 break;
443 default:
444 ret = EINVAL;
445 goto done;
230 }
231
446 }
447
232 flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
448 if ((flags & _DRM_VBLANK_NEXTONMISS) &&
449 (seq - vblwait->request.sequence) <= (1<<23)) {
450 vblwait->request.sequence = seq + 1;
451 }
452
233 if (flags & _DRM_VBLANK_SIGNAL) {
234#if 0 /* disabled */
235 drm_vbl_sig_t *vbl_sig = malloc(sizeof(drm_vbl_sig_t), M_DRM,
236 M_NOWAIT | M_ZERO);
237 if (vbl_sig == NULL)
238 return ENOMEM;
239
453 if (flags & _DRM_VBLANK_SIGNAL) {
454#if 0 /* disabled */
455 drm_vbl_sig_t *vbl_sig = malloc(sizeof(drm_vbl_sig_t), M_DRM,
456 M_NOWAIT | M_ZERO);
457 if (vbl_sig == NULL)
458 return ENOMEM;
459
240 vbl_sig->sequence = vblwait.request.sequence;
241 vbl_sig->signo = vblwait.request.signal;
460 vbl_sig->sequence = vblwait->request.sequence;
461 vbl_sig->signo = vblwait->request.signal;
242 vbl_sig->pid = DRM_CURRENTPID;
243
462 vbl_sig->pid = DRM_CURRENTPID;
463
244 vblwait.reply.sequence = atomic_read(&dev->vbl_received);
464 vblwait->reply.sequence = atomic_read(&dev->vbl_received);
245
465
246 DRM_SPINLOCK(&dev->irq_lock);
466 DRM_SPINLOCK(&dev->vbl_lock);
247 TAILQ_INSERT_HEAD(&dev->vbl_sig_list, vbl_sig, link);
467 TAILQ_INSERT_HEAD(&dev->vbl_sig_list, vbl_sig, link);
248 DRM_SPINUNLOCK(&dev->irq_lock);
468 DRM_SPINUNLOCK(&dev->vbl_lock);
249 ret = 0;
250#endif
251 ret = EINVAL;
252 } else {
253 DRM_LOCK();
469 ret = 0;
470#endif
471 ret = EINVAL;
472 } else {
473 DRM_LOCK();
254 ret = dev->driver.vblank_wait(dev, &vblwait.request.sequence);
474 /* shared code returns -errno */
475
476 DRM_WAIT_ON(ret, dev->vblank[crtc].queue, 3 * DRM_HZ,
477 ((drm_vblank_count(dev, crtc)
478 - vblwait->request.sequence) <= (1 << 23)));
255 DRM_UNLOCK();
256
479 DRM_UNLOCK();
480
257 microtime(&now);
258 vblwait.reply.tval_sec = now.tv_sec;
259 vblwait.reply.tval_usec = now.tv_usec;
481 if (ret != EINTR) {
482 struct timeval now;
483
484 microtime(&now);
485 vblwait->reply.tval_sec = now.tv_sec;
486 vblwait->reply.tval_usec = now.tv_usec;
487 vblwait->reply.sequence = drm_vblank_count(dev, crtc);
488 }
260 }
261
489 }
490
262 DRM_COPY_TO_USER_IOCTL( (drm_wait_vblank_t *)data, vblwait,
263 sizeof(vblwait) );
264
491done:
492 drm_vblank_put(dev, crtc);
265 return ret;
266}
267
493 return ret;
494}
495
268void drm_vbl_send_signals(drm_device_t *dev)
496void drm_vbl_send_signals(struct drm_device *dev, int crtc)
269{
270}
271
272#if 0 /* disabled */
497{
498}
499
500#if 0 /* disabled */
273void drm_vbl_send_signals( drm_device_t *dev )
501void drm_vbl_send_signals(struct drm_device *dev, int crtc )
274{
275 drm_vbl_sig_t *vbl_sig;
276 unsigned int vbl_seq = atomic_read( &dev->vbl_received );
277 struct proc *p;
278
279 vbl_sig = TAILQ_FIRST(&dev->vbl_sig_list);
280 while (vbl_sig != NULL) {
281 drm_vbl_sig_t *next = TAILQ_NEXT(vbl_sig, link);

--- 5 unchanged lines hidden (view full) ---

287
288 TAILQ_REMOVE(&dev->vbl_sig_list, vbl_sig, link);
289 DRM_FREE(vbl_sig,sizeof(*vbl_sig));
290 }
291 vbl_sig = next;
292 }
293}
294#endif
502{
503 drm_vbl_sig_t *vbl_sig;
504 unsigned int vbl_seq = atomic_read( &dev->vbl_received );
505 struct proc *p;
506
507 vbl_sig = TAILQ_FIRST(&dev->vbl_sig_list);
508 while (vbl_sig != NULL) {
509 drm_vbl_sig_t *next = TAILQ_NEXT(vbl_sig, link);

--- 5 unchanged lines hidden (view full) ---

515
516 TAILQ_REMOVE(&dev->vbl_sig_list, vbl_sig, link);
517 DRM_FREE(vbl_sig,sizeof(*vbl_sig));
518 }
519 vbl_sig = next;
520 }
521}
522#endif
523
524void drm_handle_vblank(struct drm_device *dev, int crtc)
525{
526 atomic_inc(&dev->vblank[crtc].count);
527 DRM_WAKEUP(&dev->vblank[crtc].queue);
528 drm_vbl_send_signals(dev, crtc);
529}
530
531static void drm_locked_task(void *context, int pending __unused)
532{
533 struct drm_device *dev = context;
534
535 DRM_SPINLOCK(&dev->tsk_lock);
536
537 DRM_LOCK(); /* XXX drm_lock_take() should do it's own locking */
538 if (dev->locked_task_call == NULL ||
539 drm_lock_take(&dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT) == 0) {
540 DRM_UNLOCK();
541 DRM_SPINUNLOCK(&dev->tsk_lock);
542 return;
543 }
544
545 dev->lock.file_priv = NULL; /* kernel owned */
546 dev->lock.lock_time = jiffies;
547 atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
548
549 DRM_UNLOCK();
550
551 dev->locked_task_call(dev);
552
553 drm_lock_free(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT);
554
555 dev->locked_task_call = NULL;
556
557 DRM_SPINUNLOCK(&dev->tsk_lock);
558}
559
560void
561drm_locked_tasklet(struct drm_device *dev,
562 void (*tasklet)(struct drm_device *dev))
563{
564 DRM_SPINLOCK(&dev->tsk_lock);
565 if (dev->locked_task_call != NULL) {
566 DRM_SPINUNLOCK(&dev->tsk_lock);
567 return;
568 }
569
570 dev->locked_task_call = tasklet;
571 DRM_SPINUNLOCK(&dev->tsk_lock);
572 taskqueue_enqueue(taskqueue_swi, &dev->locked_task);
573}