vertical blank ioctl can send signal instead of blocking

This commit is contained in:
Michel Daenzer 2002-11-30 14:24:07 +00:00
parent c869f4a1e5
commit 40891ac190
13 changed files with 255 additions and 34 deletions

View file

@ -518,6 +518,17 @@ typedef struct drm_map_list {
drm_map_t *map;
} drm_map_list_t;
#if __HAVE_VBL_IRQ
typedef struct drm_vbl_sig {
struct list_head head;
unsigned int sequence;
struct siginfo info;
struct task_struct *task;
} drm_vbl_sig_t;
#endif
typedef struct drm_device {
const char *name; /* Simple driver name */
char *unique; /* Unique identifier: e.g., busid */
@ -580,6 +591,9 @@ typedef struct drm_device {
#if __HAVE_VBL_IRQ
wait_queue_head_t vbl_queue;
atomic_t vbl_received;
struct tq_struct vbl_tq;
struct semaphore vbl_sem;
drm_vbl_sig_t vbl_sigs;
#endif
cycles_t ctx_start;
cycles_t lck_start;
@ -820,6 +834,7 @@ extern void DRM(driver_irq_uninstall)( drm_device_t *dev );
extern int DRM(wait_vblank)(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int DRM(vblank_wait)(drm_device_t *dev, unsigned int *vbl_seq);
extern void DRM(vbl_immediate_bh)( void *arg );
#endif
#if __HAVE_DMA_IRQ_BH
extern void DRM(dma_immediate_bh)( void *dev );

View file

@ -540,6 +540,17 @@ int DRM(irq_install)( drm_device_t *dev, int irq )
#if __HAVE_VBL_IRQ
init_waitqueue_head(&dev->vbl_queue);
sema_init( &dev->vbl_sem, 0 );
INIT_LIST_HEAD( &dev->vbl_sigs.head );
up( &dev->vbl_sem );
INIT_LIST_HEAD( &dev->vbl_tq.list );
dev->vbl_tq.sync = 0;
dev->vbl_tq.routine = DRM(vbl_immediate_bh);
dev->vbl_tq.data = dev;
#endif
/* Before installing handler */
@ -610,7 +621,8 @@ int DRM(wait_vblank)( DRM_IOCTL_ARGS )
drm_device_t *dev = priv->dev;
drm_wait_vblank_t vblwait;
struct timeval now;
int ret;
int ret = 0;
unsigned int flags;
if (!dev->irq)
return -EINVAL;
@ -618,15 +630,44 @@ int DRM(wait_vblank)( DRM_IOCTL_ARGS )
DRM_COPY_FROM_USER_IOCTL( vblwait, (drm_wait_vblank_t *)data,
sizeof(vblwait) );
if ( vblwait.type == _DRM_VBLANK_RELATIVE ) {
vblwait.sequence += atomic_read( &dev->vbl_received );
switch ( vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK ) {
case _DRM_VBLANK_RELATIVE:
vblwait.request.sequence += atomic_read( &dev->vbl_received );
case _DRM_VBLANK_ABSOLUTE:
break;
default:
return -EINVAL;
}
ret = DRM(vblank_wait)( dev, &vblwait.sequence );
flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
if ( flags & _DRM_VBLANK_SIGNAL ) {
drm_vbl_sig_t *vbl_sig = DRM_MALLOC( sizeof( drm_vbl_sig_t ) );
do_gettimeofday( &now );
vblwait.tval_sec = now.tv_sec;
vblwait.tval_usec = now.tv_usec;
if ( !vbl_sig )
return -ENOMEM;
memset( (void *)vbl_sig, 0, sizeof(*vbl_sig) );
vbl_sig->sequence = vblwait.request.sequence;
vbl_sig->info.si_signo = vblwait.request.signal;
vbl_sig->task = current;
vblwait.reply.sequence = atomic_read( &dev->vbl_received );
/* Hook signal entry into list */
down( &dev->vbl_sem );
list_add_tail( (struct list_head *) vbl_sig, &dev->vbl_sigs.head );
up( &dev->vbl_sem );
} else {
ret = DRM(vblank_wait)( dev, &vblwait.request.sequence );
do_gettimeofday( &now );
vblwait.reply.tval_sec = now.tv_sec;
vblwait.reply.tval_usec = now.tv_usec;
}
DRM_COPY_TO_USER_IOCTL( (drm_wait_vblank_t *)data, vblwait,
sizeof(vblwait) );
@ -634,6 +675,33 @@ int DRM(wait_vblank)( DRM_IOCTL_ARGS )
return ret;
}
void DRM(vbl_immediate_bh)( void *arg )
{
drm_device_t *dev = (drm_device_t *) arg;
struct list_head *entry, *tmp;
drm_vbl_sig_t *vbl_sig;
unsigned int vbl_seq = atomic_read( &dev->vbl_received );
down( &dev->vbl_sem );
list_for_each_safe( entry, tmp, &dev->vbl_sigs.head ) {
vbl_sig = (drm_vbl_sig_t *) entry;
if ( ( vbl_seq + ~vbl_sig->sequence + 1 ) <= (1<<23) ) {
vbl_sig->info.si_code = atomic_read( &dev->vbl_received );
send_sig_info( vbl_sig->info.si_signo, &vbl_sig->info, vbl_sig->task );
list_del( entry );
DRM_FREE( entry );
}
}
up( &dev->vbl_sem );
}
#endif /* __HAVE_VBL_IRQ */
#else

View file

@ -346,17 +346,30 @@ typedef struct drm_irq_busid {
} drm_irq_busid_t;
typedef enum {
_DRM_VBLANK_ABSOLUTE = 0x0, /* Wait for specific vblank sequence number */
_DRM_VBLANK_RELATIVE = 0x1 /* Wait for given number of vblanks */
_DRM_VBLANK_ABSOLUTE = 0x0, /* Wait for specific vblank sequence number */
_DRM_VBLANK_RELATIVE = 0x1, /* Wait for given number of vblanks */
_DRM_VBLANK_SIGNAL = 0x80000000 /* Send signal instead of blocking */
} drm_vblank_seq_type_t;
typedef struct drm_radeon_vbl_wait {
#define _DRM_VBLANK_FLAGS_MASK _DRM_VBLANK_SIGNAL
struct drm_wait_vblank_request {
drm_vblank_seq_type_t type;
unsigned int sequence;
unsigned long signal;
};
struct drm_wait_vblank_reply {
drm_vblank_seq_type_t type;
unsigned int sequence;
long tval_sec;
long tval_usec;
} drm_wait_vblank_t;
};
typedef union drm_wait_vblank {
struct drm_wait_vblank_request request;
struct drm_wait_vblank_reply reply;
} drm_wait_vblank_t;
typedef struct drm_agp_mode {
unsigned long mode;

View file

@ -518,6 +518,17 @@ typedef struct drm_map_list {
drm_map_t *map;
} drm_map_list_t;
#if __HAVE_VBL_IRQ
typedef struct drm_vbl_sig {
struct list_head head;
unsigned int sequence;
struct siginfo info;
struct task_struct *task;
} drm_vbl_sig_t;
#endif
typedef struct drm_device {
const char *name; /* Simple driver name */
char *unique; /* Unique identifier: e.g., busid */
@ -580,6 +591,9 @@ typedef struct drm_device {
#if __HAVE_VBL_IRQ
wait_queue_head_t vbl_queue;
atomic_t vbl_received;
struct tq_struct vbl_tq;
struct semaphore vbl_sem;
drm_vbl_sig_t vbl_sigs;
#endif
cycles_t ctx_start;
cycles_t lck_start;
@ -820,6 +834,7 @@ extern void DRM(driver_irq_uninstall)( drm_device_t *dev );
extern int DRM(wait_vblank)(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int DRM(vblank_wait)(drm_device_t *dev, unsigned int *vbl_seq);
extern void DRM(vbl_immediate_bh)( void *arg );
#endif
#if __HAVE_DMA_IRQ_BH
extern void DRM(dma_immediate_bh)( void *dev );

View file

@ -540,6 +540,17 @@ int DRM(irq_install)( drm_device_t *dev, int irq )
#if __HAVE_VBL_IRQ
init_waitqueue_head(&dev->vbl_queue);
sema_init( &dev->vbl_sem, 0 );
INIT_LIST_HEAD( &dev->vbl_sigs.head );
up( &dev->vbl_sem );
INIT_LIST_HEAD( &dev->vbl_tq.list );
dev->vbl_tq.sync = 0;
dev->vbl_tq.routine = DRM(vbl_immediate_bh);
dev->vbl_tq.data = dev;
#endif
/* Before installing handler */
@ -610,7 +621,8 @@ int DRM(wait_vblank)( DRM_IOCTL_ARGS )
drm_device_t *dev = priv->dev;
drm_wait_vblank_t vblwait;
struct timeval now;
int ret;
int ret = 0;
unsigned int flags;
if (!dev->irq)
return -EINVAL;
@ -618,15 +630,44 @@ int DRM(wait_vblank)( DRM_IOCTL_ARGS )
DRM_COPY_FROM_USER_IOCTL( vblwait, (drm_wait_vblank_t *)data,
sizeof(vblwait) );
if ( vblwait.type == _DRM_VBLANK_RELATIVE ) {
vblwait.sequence += atomic_read( &dev->vbl_received );
switch ( vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK ) {
case _DRM_VBLANK_RELATIVE:
vblwait.request.sequence += atomic_read( &dev->vbl_received );
case _DRM_VBLANK_ABSOLUTE:
break;
default:
return -EINVAL;
}
ret = DRM(vblank_wait)( dev, &vblwait.sequence );
flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
if ( flags & _DRM_VBLANK_SIGNAL ) {
drm_vbl_sig_t *vbl_sig = DRM_MALLOC( sizeof( drm_vbl_sig_t ) );
do_gettimeofday( &now );
vblwait.tval_sec = now.tv_sec;
vblwait.tval_usec = now.tv_usec;
if ( !vbl_sig )
return -ENOMEM;
memset( (void *)vbl_sig, 0, sizeof(*vbl_sig) );
vbl_sig->sequence = vblwait.request.sequence;
vbl_sig->info.si_signo = vblwait.request.signal;
vbl_sig->task = current;
vblwait.reply.sequence = atomic_read( &dev->vbl_received );
/* Hook signal entry into list */
down( &dev->vbl_sem );
list_add_tail( (struct list_head *) vbl_sig, &dev->vbl_sigs.head );
up( &dev->vbl_sem );
} else {
ret = DRM(vblank_wait)( dev, &vblwait.request.sequence );
do_gettimeofday( &now );
vblwait.reply.tval_sec = now.tv_sec;
vblwait.reply.tval_usec = now.tv_usec;
}
DRM_COPY_TO_USER_IOCTL( (drm_wait_vblank_t *)data, vblwait,
sizeof(vblwait) );
@ -634,6 +675,33 @@ int DRM(wait_vblank)( DRM_IOCTL_ARGS )
return ret;
}
void DRM(vbl_immediate_bh)( void *arg )
{
drm_device_t *dev = (drm_device_t *) arg;
struct list_head *entry, *tmp;
drm_vbl_sig_t *vbl_sig;
unsigned int vbl_seq = atomic_read( &dev->vbl_received );
down( &dev->vbl_sem );
list_for_each_safe( entry, tmp, &dev->vbl_sigs.head ) {
vbl_sig = (drm_vbl_sig_t *) entry;
if ( ( vbl_seq + ~vbl_sig->sequence + 1 ) <= (1<<23) ) {
vbl_sig->info.si_code = atomic_read( &dev->vbl_received );
send_sig_info( vbl_sig->info.si_signo, &vbl_sig->info, vbl_sig->task );
list_del( entry );
DRM_FREE( entry );
}
}
up( &dev->vbl_sem );
}
#endif /* __HAVE_VBL_IRQ */
#else

View file

@ -346,17 +346,30 @@ typedef struct drm_irq_busid {
} drm_irq_busid_t;
typedef enum {
_DRM_VBLANK_ABSOLUTE = 0x0, /* Wait for specific vblank sequence number */
_DRM_VBLANK_RELATIVE = 0x1 /* Wait for given number of vblanks */
_DRM_VBLANK_ABSOLUTE = 0x0, /* Wait for specific vblank sequence number */
_DRM_VBLANK_RELATIVE = 0x1, /* Wait for given number of vblanks */
_DRM_VBLANK_SIGNAL = 0x80000000 /* Send signal instead of blocking */
} drm_vblank_seq_type_t;
typedef struct drm_radeon_vbl_wait {
#define _DRM_VBLANK_FLAGS_MASK _DRM_VBLANK_SIGNAL
struct drm_wait_vblank_request {
drm_vblank_seq_type_t type;
unsigned int sequence;
unsigned long signal;
};
struct drm_wait_vblank_reply {
drm_vblank_seq_type_t type;
unsigned int sequence;
long tval_sec;
long tval_usec;
} drm_wait_vblank_t;
};
typedef union drm_wait_vblank {
struct drm_wait_vblank_request request;
struct drm_wait_vblank_reply reply;
} drm_wait_vblank_t;
typedef struct drm_agp_mode {
unsigned long mode;

View file

@ -50,6 +50,10 @@ void mga_dma_service( DRM_IRQ_ARGS )
MGA_WRITE( MGA_ICLEAR, MGA_VLINEICLR );
atomic_inc(&dev->vbl_received);
DRM_WAKEUP(&dev->vbl_queue);
/* kick off bottom half for signals */
queue_task(&dev->vbl_tq, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
}

View file

@ -50,6 +50,10 @@ void r128_dma_service( DRM_IRQ_ARGS )
R128_WRITE( R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK );
atomic_inc(&dev->vbl_received);
DRM_WAKEUP(&dev->vbl_queue);
/* kick off bottom half for signals */
queue_task(&dev->vbl_tq, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
}

View file

@ -70,13 +70,15 @@ void DRM(dma_service)( DRM_IRQ_ARGS )
DRM_WAKEUP( &dev_priv->swi_queue );
}
#if __HAVE_VBL_IRQ
/* VBLANK interrupt */
if (stat & RADEON_CRTC_VBLANK_STAT) {
atomic_inc(&dev->vbl_received);
DRM_WAKEUP(&dev->vbl_queue);
/* kick off bottom half for signals */
queue_task(&dev->vbl_tq, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
#endif
/* Acknowledge all the bits in GEN_INT_STATUS -- seem to get
* more than we asked for...
@ -138,7 +140,6 @@ int radeon_emit_and_wait_irq(drm_device_t *dev)
}
#if __HAVE_VBL_IRQ
int DRM(vblank_wait)(drm_device_t *dev, unsigned int *sequence)
{
drm_radeon_private_t *dev_priv =
@ -167,7 +168,6 @@ int DRM(vblank_wait)(drm_device_t *dev, unsigned int *sequence)
return ret;
}
#endif
/* Needs the lock as it touches the ring.

View file

@ -346,17 +346,30 @@ typedef struct drm_irq_busid {
} drm_irq_busid_t;
typedef enum {
_DRM_VBLANK_ABSOLUTE = 0x0, /* Wait for specific vblank sequence number */
_DRM_VBLANK_RELATIVE = 0x1 /* Wait for given number of vblanks */
_DRM_VBLANK_ABSOLUTE = 0x0, /* Wait for specific vblank sequence number */
_DRM_VBLANK_RELATIVE = 0x1, /* Wait for given number of vblanks */
_DRM_VBLANK_SIGNAL = 0x80000000 /* Send signal instead of blocking */
} drm_vblank_seq_type_t;
typedef struct drm_radeon_vbl_wait {
#define _DRM_VBLANK_FLAGS_MASK _DRM_VBLANK_SIGNAL
struct drm_wait_vblank_request {
drm_vblank_seq_type_t type;
unsigned int sequence;
unsigned long signal;
};
struct drm_wait_vblank_reply {
drm_vblank_seq_type_t type;
unsigned int sequence;
long tval_sec;
long tval_usec;
} drm_wait_vblank_t;
};
typedef union drm_wait_vblank {
struct drm_wait_vblank_request request;
struct drm_wait_vblank_reply reply;
} drm_wait_vblank_t;
typedef struct drm_agp_mode {
unsigned long mode;

View file

@ -50,6 +50,10 @@ void mga_dma_service( DRM_IRQ_ARGS )
MGA_WRITE( MGA_ICLEAR, MGA_VLINEICLR );
atomic_inc(&dev->vbl_received);
DRM_WAKEUP(&dev->vbl_queue);
/* kick off bottom half for signals */
queue_task(&dev->vbl_tq, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
}

View file

@ -50,6 +50,10 @@ void r128_dma_service( DRM_IRQ_ARGS )
R128_WRITE( R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK );
atomic_inc(&dev->vbl_received);
DRM_WAKEUP(&dev->vbl_queue);
/* kick off bottom half for signals */
queue_task(&dev->vbl_tq, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
}

View file

@ -70,13 +70,15 @@ void DRM(dma_service)( DRM_IRQ_ARGS )
DRM_WAKEUP( &dev_priv->swi_queue );
}
#if __HAVE_VBL_IRQ
/* VBLANK interrupt */
if (stat & RADEON_CRTC_VBLANK_STAT) {
atomic_inc(&dev->vbl_received);
DRM_WAKEUP(&dev->vbl_queue);
/* kick off bottom half for signals */
queue_task(&dev->vbl_tq, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
#endif
/* Acknowledge all the bits in GEN_INT_STATUS -- seem to get
* more than we asked for...
@ -138,7 +140,6 @@ int radeon_emit_and_wait_irq(drm_device_t *dev)
}
#if __HAVE_VBL_IRQ
int DRM(vblank_wait)(drm_device_t *dev, unsigned int *sequence)
{
drm_radeon_private_t *dev_priv =
@ -167,7 +168,6 @@ int DRM(vblank_wait)(drm_device_t *dev, unsigned int *sequence)
return ret;
}
#endif
/* Needs the lock as it touches the ring.