drm: add support for secondary vertical blank interrupt to DRM core

Signed-off-by: Dave Airlie <airlied@linux.ie>
This commit is contained in:
=?utf-8?q?Michel_D=C3=A4nzer?= 2006-10-24 22:24:38 +10:00 committed by airlied
parent 620034c84d
commit 776c9443e2
4 changed files with 60 additions and 28 deletions

View File

@ -465,10 +465,12 @@ typedef struct drm_irq_busid {
typedef enum { typedef enum {
_DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */
_DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */
_DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */
_DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */
} drm_vblank_seq_type_t; } drm_vblank_seq_type_t;
#define _DRM_VBLANK_FLAGS_MASK _DRM_VBLANK_SIGNAL #define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE)
#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_SIGNAL | _DRM_VBLANK_SECONDARY)
struct drm_wait_vblank_request { struct drm_wait_vblank_request {
drm_vblank_seq_type_t type; drm_vblank_seq_type_t type;

View File

@ -97,6 +97,7 @@
#define DRIVER_IRQ_VBL 0x100 #define DRIVER_IRQ_VBL 0x100
#define DRIVER_DMA_QUEUE 0x200 #define DRIVER_DMA_QUEUE 0x200
#define DRIVER_FB_DMA 0x400 #define DRIVER_FB_DMA 0x400
#define DRIVER_IRQ_VBL2 0x800
/***********************************************************************/ /***********************************************************************/
/** \name Begin the DRM... */ /** \name Begin the DRM... */
@ -562,6 +563,7 @@ struct drm_driver {
void (*kernel_context_switch_unlock) (struct drm_device * dev, void (*kernel_context_switch_unlock) (struct drm_device * dev,
drm_lock_t *lock); drm_lock_t *lock);
int (*vblank_wait) (struct drm_device * dev, unsigned int *sequence); int (*vblank_wait) (struct drm_device * dev, unsigned int *sequence);
int (*vblank_wait2) (struct drm_device * dev, unsigned int *sequence);
int (*dri_library_name) (struct drm_device *dev, char *buf); int (*dri_library_name) (struct drm_device *dev, char *buf);
/** /**
@ -708,8 +710,10 @@ typedef struct drm_device {
wait_queue_head_t vbl_queue; /**< VBLANK wait queue */ wait_queue_head_t vbl_queue; /**< VBLANK wait queue */
atomic_t vbl_received; atomic_t vbl_received;
atomic_t vbl_received2; /**< number of secondary VBLANK interrupts */
spinlock_t vbl_lock; spinlock_t vbl_lock;
drm_vbl_sig_t vbl_sigs; /**< signal list to send on VBLANK */ drm_vbl_sig_t vbl_sigs; /**< signal list to send on VBLANK */
drm_vbl_sig_t vbl_sigs2; /**< signals to send on secondary VBLANK */
unsigned int vbl_pending; unsigned int vbl_pending;
/*@} */ /*@} */

View File

@ -24,11 +24,11 @@
#define CORE_NAME "drm" #define CORE_NAME "drm"
#define CORE_DESC "DRM shared core routines" #define CORE_DESC "DRM shared core routines"
#define CORE_DATE "20051102" #define CORE_DATE "20060810"
#define DRM_IF_MAJOR 1 #define DRM_IF_MAJOR 1
#define DRM_IF_MINOR 2 #define DRM_IF_MINOR 3
#define CORE_MAJOR 1 #define CORE_MAJOR 1
#define CORE_MINOR 0 #define CORE_MINOR 1
#define CORE_PATCHLEVEL 1 #define CORE_PATCHLEVEL 0

View File

@ -121,6 +121,7 @@ static int drm_irq_install(drm_device_t * dev)
spin_lock_init(&dev->vbl_lock); spin_lock_init(&dev->vbl_lock);
INIT_LIST_HEAD(&dev->vbl_sigs.head); INIT_LIST_HEAD(&dev->vbl_sigs.head);
INIT_LIST_HEAD(&dev->vbl_sigs2.head);
dev->vbl_pending = 0; dev->vbl_pending = 0;
} }
@ -248,9 +249,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
struct timeval now; struct timeval now;
int ret = 0; int ret = 0;
unsigned int flags; unsigned int flags;
atomic_t *seq;
if (!drm_core_check_feature(dev, DRIVER_IRQ_VBL))
return -EINVAL;
if (!dev->irq) if (!dev->irq)
return -EINVAL; return -EINVAL;
@ -258,9 +257,26 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
if (copy_from_user(&vblwait, argp, sizeof(vblwait))) if (copy_from_user(&vblwait, argp, sizeof(vblwait)))
return -EFAULT; return -EFAULT;
switch (vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK) { if (vblwait.request.type &
~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) {
DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n",
vblwait.request.type,
(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK));
return -EINVAL;
}
flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ?
DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL))
return -EINVAL;
seq = (flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2 :
&dev->vbl_received;
switch (vblwait.request.type & _DRM_VBLANK_TYPES_MASK) {
case _DRM_VBLANK_RELATIVE: case _DRM_VBLANK_RELATIVE:
vblwait.request.sequence += atomic_read(&dev->vbl_received); vblwait.request.sequence += atomic_read(seq);
vblwait.request.type &= ~_DRM_VBLANK_RELATIVE; vblwait.request.type &= ~_DRM_VBLANK_RELATIVE;
case _DRM_VBLANK_ABSOLUTE: case _DRM_VBLANK_ABSOLUTE:
break; break;
@ -268,13 +284,13 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
return -EINVAL; return -EINVAL;
} }
flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
if (flags & _DRM_VBLANK_SIGNAL) { if (flags & _DRM_VBLANK_SIGNAL) {
unsigned long irqflags; unsigned long irqflags;
drm_vbl_sig_t *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY)
? &dev->vbl_sigs2 : &dev->vbl_sigs;
drm_vbl_sig_t *vbl_sig; drm_vbl_sig_t *vbl_sig;
vblwait.reply.sequence = atomic_read(&dev->vbl_received); vblwait.reply.sequence = atomic_read(seq);
spin_lock_irqsave(&dev->vbl_lock, irqflags); spin_lock_irqsave(&dev->vbl_lock, irqflags);
@ -282,7 +298,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
* for the same vblank sequence number; nothing to be done in * for the same vblank sequence number; nothing to be done in
* that case * that case
*/ */
list_for_each_entry(vbl_sig, &dev->vbl_sigs.head, head) { list_for_each_entry(vbl_sig, &vbl_sigs->head, head) {
if (vbl_sig->sequence == vblwait.request.sequence if (vbl_sig->sequence == vblwait.request.sequence
&& vbl_sig->info.si_signo == vblwait.request.signal && vbl_sig->info.si_signo == vblwait.request.signal
&& vbl_sig->task == current) { && vbl_sig->task == current) {
@ -315,11 +331,14 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
spin_lock_irqsave(&dev->vbl_lock, irqflags); spin_lock_irqsave(&dev->vbl_lock, irqflags);
list_add_tail((struct list_head *)vbl_sig, &dev->vbl_sigs.head); list_add_tail((struct list_head *)vbl_sig, &vbl_sigs->head);
spin_unlock_irqrestore(&dev->vbl_lock, irqflags); spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
} else { } else {
if (dev->driver->vblank_wait) if (flags & _DRM_VBLANK_SECONDARY) {
if (dev->driver->vblank_wait2)
ret = dev->driver->vblank_wait2(dev, &vblwait.request.sequence);
} else if (dev->driver->vblank_wait)
ret = ret =
dev->driver->vblank_wait(dev, dev->driver->vblank_wait(dev,
&vblwait.request.sequence); &vblwait.request.sequence);
@ -347,25 +366,32 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
*/ */
void drm_vbl_send_signals(drm_device_t * dev) void drm_vbl_send_signals(drm_device_t * dev)
{ {
struct list_head *list, *tmp;
drm_vbl_sig_t *vbl_sig;
unsigned int vbl_seq = atomic_read(&dev->vbl_received);
unsigned long flags; unsigned long flags;
int i;
spin_lock_irqsave(&dev->vbl_lock, flags); spin_lock_irqsave(&dev->vbl_lock, flags);
list_for_each_safe(list, tmp, &dev->vbl_sigs.head) { for (i = 0; i < 2; i++) {
vbl_sig = list_entry(list, drm_vbl_sig_t, head); struct list_head *list, *tmp;
if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) { drm_vbl_sig_t *vbl_sig;
vbl_sig->info.si_code = vbl_seq; drm_vbl_sig_t *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs;
send_sig_info(vbl_sig->info.si_signo, &vbl_sig->info, unsigned int vbl_seq = atomic_read(i ? &dev->vbl_received2 :
vbl_sig->task); &dev->vbl_received);
list_del(list); list_for_each_safe(list, tmp, &vbl_sigs->head) {
vbl_sig = list_entry(list, drm_vbl_sig_t, head);
if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) {
vbl_sig->info.si_code = vbl_seq;
send_sig_info(vbl_sig->info.si_signo,
&vbl_sig->info, vbl_sig->task);
drm_free(vbl_sig, sizeof(*vbl_sig), DRM_MEM_DRIVER); list_del(list);
dev->vbl_pending--; drm_free(vbl_sig, sizeof(*vbl_sig),
DRM_MEM_DRIVER);
dev->vbl_pending--;
}
} }
} }