diff options
author | =?utf-8?q?Michel_D=C3=A4nzer?= <michel@tungstengraphics.com> | 2006-10-24 08:24:38 -0400 |
---|---|---|
committer | airlied <airlied@linux.ie> | 2006-12-06 23:53:28 -0500 |
commit | 776c9443e28dddbde9b513db6cb8221c45b3a269 (patch) | |
tree | 41b753829e949371ee01d2930f5be1185f29b737 /drivers/char/drm | |
parent | 620034c84d1d939717bdfbe02c51a3fee43541c3 (diff) |
drm: add support for secondary vertical blank interrupt to DRM core
Signed-off-by: Dave Airlie <airlied@linux.ie>
Diffstat (limited to 'drivers/char/drm')
-rw-r--r-- | drivers/char/drm/drm.h | 4 | ||||
-rw-r--r-- | drivers/char/drm/drmP.h | 4 | ||||
-rw-r--r-- | drivers/char/drm/drm_core.h | 8 | ||||
-rw-r--r-- | drivers/char/drm/drm_irq.c | 72 |
4 files changed, 60 insertions, 28 deletions
diff --git a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h index 5642ac43e0f5..077d0b1914ab 100644 --- a/drivers/char/drm/drm.h +++ b/drivers/char/drm/drm.h | |||
@@ -465,10 +465,12 @@ typedef struct drm_irq_busid { | |||
465 | typedef enum { | 465 | typedef enum { |
466 | _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ | 466 | _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ |
467 | _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ | 467 | _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ |
468 | _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ | ||
468 | _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ | 469 | _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ |
469 | } drm_vblank_seq_type_t; | 470 | } drm_vblank_seq_type_t; |
470 | 471 | ||
471 | #define _DRM_VBLANK_FLAGS_MASK _DRM_VBLANK_SIGNAL | 472 | #define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE) |
473 | #define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_SIGNAL | _DRM_VBLANK_SECONDARY) | ||
472 | 474 | ||
473 | struct drm_wait_vblank_request { | 475 | struct drm_wait_vblank_request { |
474 | drm_vblank_seq_type_t type; | 476 | drm_vblank_seq_type_t type; |
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 7690a59ace04..d7135d41a42a 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h | |||
@@ -97,6 +97,7 @@ | |||
97 | #define DRIVER_IRQ_VBL 0x100 | 97 | #define DRIVER_IRQ_VBL 0x100 |
98 | #define DRIVER_DMA_QUEUE 0x200 | 98 | #define DRIVER_DMA_QUEUE 0x200 |
99 | #define DRIVER_FB_DMA 0x400 | 99 | #define DRIVER_FB_DMA 0x400 |
100 | #define DRIVER_IRQ_VBL2 0x800 | ||
100 | 101 | ||
101 | /***********************************************************************/ | 102 | /***********************************************************************/ |
102 | /** \name Begin the DRM... */ | 103 | /** \name Begin the DRM... */ |
@@ -562,6 +563,7 @@ struct drm_driver { | |||
562 | void (*kernel_context_switch_unlock) (struct drm_device * dev, | 563 | void (*kernel_context_switch_unlock) (struct drm_device * dev, |
563 | drm_lock_t *lock); | 564 | drm_lock_t *lock); |
564 | int (*vblank_wait) (struct drm_device * dev, unsigned int *sequence); | 565 | int (*vblank_wait) (struct drm_device * dev, unsigned int *sequence); |
566 | int (*vblank_wait2) (struct drm_device * dev, unsigned int *sequence); | ||
565 | int (*dri_library_name) (struct drm_device *dev, char *buf); | 567 | int (*dri_library_name) (struct drm_device *dev, char *buf); |
566 | 568 | ||
567 | /** | 569 | /** |
@@ -708,8 +710,10 @@ typedef struct drm_device { | |||
708 | 710 | ||
709 | wait_queue_head_t vbl_queue; /**< VBLANK wait queue */ | 711 | wait_queue_head_t vbl_queue; /**< VBLANK wait queue */ |
710 | atomic_t vbl_received; | 712 | atomic_t vbl_received; |
713 | atomic_t vbl_received2; /**< number of secondary VBLANK interrupts */ | ||
711 | spinlock_t vbl_lock; | 714 | spinlock_t vbl_lock; |
712 | drm_vbl_sig_t vbl_sigs; /**< signal list to send on VBLANK */ | 715 | drm_vbl_sig_t vbl_sigs; /**< signal list to send on VBLANK */ |
716 | drm_vbl_sig_t vbl_sigs2; /**< signals to send on secondary VBLANK */ | ||
713 | unsigned int vbl_pending; | 717 | unsigned int vbl_pending; |
714 | 718 | ||
715 | /*@} */ | 719 | /*@} */ |
diff --git a/drivers/char/drm/drm_core.h b/drivers/char/drm/drm_core.h index f4f9db6c7ed4..316739036079 100644 --- a/drivers/char/drm/drm_core.h +++ b/drivers/char/drm/drm_core.h | |||
@@ -24,11 +24,11 @@ | |||
24 | 24 | ||
25 | #define CORE_NAME "drm" | 25 | #define CORE_NAME "drm" |
26 | #define CORE_DESC "DRM shared core routines" | 26 | #define CORE_DESC "DRM shared core routines" |
27 | #define CORE_DATE "20051102" | 27 | #define CORE_DATE "20060810" |
28 | 28 | ||
29 | #define DRM_IF_MAJOR 1 | 29 | #define DRM_IF_MAJOR 1 |
30 | #define DRM_IF_MINOR 2 | 30 | #define DRM_IF_MINOR 3 |
31 | 31 | ||
32 | #define CORE_MAJOR 1 | 32 | #define CORE_MAJOR 1 |
33 | #define CORE_MINOR 0 | 33 | #define CORE_MINOR 1 |
34 | #define CORE_PATCHLEVEL 1 | 34 | #define CORE_PATCHLEVEL 0 |
diff --git a/drivers/char/drm/drm_irq.c b/drivers/char/drm/drm_irq.c index 4553a3a1e496..3c77756aad9c 100644 --- a/drivers/char/drm/drm_irq.c +++ b/drivers/char/drm/drm_irq.c | |||
@@ -121,6 +121,7 @@ static int drm_irq_install(drm_device_t * dev) | |||
121 | spin_lock_init(&dev->vbl_lock); | 121 | spin_lock_init(&dev->vbl_lock); |
122 | 122 | ||
123 | INIT_LIST_HEAD(&dev->vbl_sigs.head); | 123 | INIT_LIST_HEAD(&dev->vbl_sigs.head); |
124 | INIT_LIST_HEAD(&dev->vbl_sigs2.head); | ||
124 | 125 | ||
125 | dev->vbl_pending = 0; | 126 | dev->vbl_pending = 0; |
126 | } | 127 | } |
@@ -248,9 +249,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) | |||
248 | struct timeval now; | 249 | struct timeval now; |
249 | int ret = 0; | 250 | int ret = 0; |
250 | unsigned int flags; | 251 | unsigned int flags; |
251 | 252 | atomic_t *seq; | |
252 | if (!drm_core_check_feature(dev, DRIVER_IRQ_VBL)) | ||
253 | return -EINVAL; | ||
254 | 253 | ||
255 | if (!dev->irq) | 254 | if (!dev->irq) |
256 | return -EINVAL; | 255 | return -EINVAL; |
@@ -258,9 +257,26 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) | |||
258 | if (copy_from_user(&vblwait, argp, sizeof(vblwait))) | 257 | if (copy_from_user(&vblwait, argp, sizeof(vblwait))) |
259 | return -EFAULT; | 258 | return -EFAULT; |
260 | 259 | ||
261 | switch (vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK) { | 260 | if (vblwait.request.type & |
261 | ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) { | ||
262 | DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n", | ||
263 | vblwait.request.type, | ||
264 | (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)); | ||
265 | return -EINVAL; | ||
266 | } | ||
267 | |||
268 | flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK; | ||
269 | |||
270 | if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ? | ||
271 | DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL)) | ||
272 | return -EINVAL; | ||
273 | |||
274 | seq = (flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2 : | ||
275 | &dev->vbl_received; | ||
276 | |||
277 | switch (vblwait.request.type & _DRM_VBLANK_TYPES_MASK) { | ||
262 | case _DRM_VBLANK_RELATIVE: | 278 | case _DRM_VBLANK_RELATIVE: |
263 | vblwait.request.sequence += atomic_read(&dev->vbl_received); | 279 | vblwait.request.sequence += atomic_read(seq); |
264 | vblwait.request.type &= ~_DRM_VBLANK_RELATIVE; | 280 | vblwait.request.type &= ~_DRM_VBLANK_RELATIVE; |
265 | case _DRM_VBLANK_ABSOLUTE: | 281 | case _DRM_VBLANK_ABSOLUTE: |
266 | break; | 282 | break; |
@@ -268,13 +284,13 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) | |||
268 | return -EINVAL; | 284 | return -EINVAL; |
269 | } | 285 | } |
270 | 286 | ||
271 | flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK; | ||
272 | |||
273 | if (flags & _DRM_VBLANK_SIGNAL) { | 287 | if (flags & _DRM_VBLANK_SIGNAL) { |
274 | unsigned long irqflags; | 288 | unsigned long irqflags; |
289 | drm_vbl_sig_t *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY) | ||
290 | ? &dev->vbl_sigs2 : &dev->vbl_sigs; | ||
275 | drm_vbl_sig_t *vbl_sig; | 291 | drm_vbl_sig_t *vbl_sig; |
276 | 292 | ||
277 | vblwait.reply.sequence = atomic_read(&dev->vbl_received); | 293 | vblwait.reply.sequence = atomic_read(seq); |
278 | 294 | ||
279 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | 295 | spin_lock_irqsave(&dev->vbl_lock, irqflags); |
280 | 296 | ||
@@ -282,7 +298,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) | |||
282 | * for the same vblank sequence number; nothing to be done in | 298 | * for the same vblank sequence number; nothing to be done in |
283 | * that case | 299 | * that case |
284 | */ | 300 | */ |
285 | list_for_each_entry(vbl_sig, &dev->vbl_sigs.head, head) { | 301 | list_for_each_entry(vbl_sig, &vbl_sigs->head, head) { |
286 | if (vbl_sig->sequence == vblwait.request.sequence | 302 | if (vbl_sig->sequence == vblwait.request.sequence |
287 | && vbl_sig->info.si_signo == vblwait.request.signal | 303 | && vbl_sig->info.si_signo == vblwait.request.signal |
288 | && vbl_sig->task == current) { | 304 | && vbl_sig->task == current) { |
@@ -315,11 +331,14 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) | |||
315 | 331 | ||
316 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | 332 | spin_lock_irqsave(&dev->vbl_lock, irqflags); |
317 | 333 | ||
318 | list_add_tail((struct list_head *)vbl_sig, &dev->vbl_sigs.head); | 334 | list_add_tail((struct list_head *)vbl_sig, &vbl_sigs->head); |
319 | 335 | ||
320 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | 336 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); |
321 | } else { | 337 | } else { |
322 | if (dev->driver->vblank_wait) | 338 | if (flags & _DRM_VBLANK_SECONDARY) { |
339 | if (dev->driver->vblank_wait2) | ||
340 | ret = dev->driver->vblank_wait2(dev, &vblwait.request.sequence); | ||
341 | } else if (dev->driver->vblank_wait) | ||
323 | ret = | 342 | ret = |
324 | dev->driver->vblank_wait(dev, | 343 | dev->driver->vblank_wait(dev, |
325 | &vblwait.request.sequence); | 344 | &vblwait.request.sequence); |
@@ -347,25 +366,32 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) | |||
347 | */ | 366 | */ |
348 | void drm_vbl_send_signals(drm_device_t * dev) | 367 | void drm_vbl_send_signals(drm_device_t * dev) |
349 | { | 368 | { |
350 | struct list_head *list, *tmp; | ||
351 | drm_vbl_sig_t *vbl_sig; | ||
352 | unsigned int vbl_seq = atomic_read(&dev->vbl_received); | ||
353 | unsigned long flags; | 369 | unsigned long flags; |
370 | int i; | ||
354 | 371 | ||
355 | spin_lock_irqsave(&dev->vbl_lock, flags); | 372 | spin_lock_irqsave(&dev->vbl_lock, flags); |
356 | 373 | ||
357 | list_for_each_safe(list, tmp, &dev->vbl_sigs.head) { | 374 | for (i = 0; i < 2; i++) { |
358 | vbl_sig = list_entry(list, drm_vbl_sig_t, head); | 375 | struct list_head *list, *tmp; |
359 | if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) { | 376 | drm_vbl_sig_t *vbl_sig; |
360 | vbl_sig->info.si_code = vbl_seq; | 377 | drm_vbl_sig_t *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs; |
361 | send_sig_info(vbl_sig->info.si_signo, &vbl_sig->info, | 378 | unsigned int vbl_seq = atomic_read(i ? &dev->vbl_received2 : |
362 | vbl_sig->task); | 379 | &dev->vbl_received); |
380 | |||
381 | list_for_each_safe(list, tmp, &vbl_sigs->head) { | ||
382 | vbl_sig = list_entry(list, drm_vbl_sig_t, head); | ||
383 | if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) { | ||
384 | vbl_sig->info.si_code = vbl_seq; | ||
385 | send_sig_info(vbl_sig->info.si_signo, | ||
386 | &vbl_sig->info, vbl_sig->task); | ||
363 | 387 | ||
364 | list_del(list); | 388 | list_del(list); |
365 | 389 | ||
366 | drm_free(vbl_sig, sizeof(*vbl_sig), DRM_MEM_DRIVER); | 390 | drm_free(vbl_sig, sizeof(*vbl_sig), |
391 | DRM_MEM_DRIVER); | ||
367 | 392 | ||
368 | dev->vbl_pending--; | 393 | dev->vbl_pending--; |
394 | } | ||
369 | } | 395 | } |
370 | } | 396 | } |
371 | 397 | ||