Add vblank signal code for BSD DRM. Untested so far, but working with a

4.2.0 userland at least.
This commit is contained in:
Eric Anholt 2002-12-06 02:27:30 +00:00
parent 85025d4f2a
commit a885d6786f
5 changed files with 153 additions and 15 deletions

View file

@ -392,6 +392,14 @@ typedef struct drm_map_list_entry {
drm_map_t *map;
} drm_map_list_entry_t;
TAILQ_HEAD(drm_vbl_sig_list, drm_vbl_sig);
typedef struct drm_vbl_sig {
TAILQ_ENTRY(drm_vbl_sig) link;
unsigned int sequence;
int signo;
int pid;
} drm_vbl_sig_t;
struct drm_device {
#ifdef __NetBSD__
struct device device; /* NetBSD's softc is an extension of struct device */
@ -469,6 +477,8 @@ struct drm_device {
#if __HAVE_VBL_IRQ
wait_queue_head_t vbl_queue; /* vbl wait channel */
atomic_t vbl_received;
struct drm_vbl_sig_list vbl_sig_list;
DRM_SPINTYPE vbl_lock;
#endif
cycles_t ctx_start;
cycles_t lck_start;
@ -613,6 +623,7 @@ extern drm_buf_t *DRM(freelist_get)(drm_freelist_t *bl, int block);
#endif /* __HAVE_DMA */
#if __HAVE_VBL_IRQ
extern int DRM(vblank_wait)(drm_device_t *dev, unsigned int *vbl_seq);
extern void DRM(vbl_send_signals)( drm_device_t *dev );
#endif
#if __REALLY_HAVE_AGP

View file

@ -524,6 +524,11 @@ int DRM(irq_install)( drm_device_t *dev, int irq )
TASK_INIT(&dev->task, 0, DRM(dma_immediate_bh), dev);
#endif
#if __HAVE_VBL_IRQ
DRM_SPININIT( dev->vbl_lock, "vblsig" );
TAILQ_INIT( &dev->vbl_sig_list );
#endif
/* Before installing handler */
DRM(driver_irq_preinstall)( dev );
@ -612,21 +617,67 @@ 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 );
if (vblwait.request.type & _DRM_VBLANK_RELATIVE) {
vblwait.request.sequence += atomic_read(&dev->vbl_received);
}
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));
if (vbl_sig == NULL)
return ENOMEM;
bzero(vbl_sig, sizeof(*vbl_sig));
vbl_sig->sequence = vblwait.request.sequence;
vbl_sig->signo = vblwait.request.signal;
vbl_sig->pid = DRM_CURRENTPID;
microtime( &now );
vblwait.tval_sec = now.tv_sec;
vblwait.tval_usec = now.tv_usec;
vblwait.reply.sequence = atomic_read(&dev->vbl_received);
DRM_SPINLOCK(&dev->vbl_lock);
TAILQ_INSERT_HEAD(&dev->vbl_sig_list, vbl_sig, link);
DRM_SPINUNLOCK(&dev->vbl_lock);
ret = 0;
} else {
ret = DRM(vblank_wait)(dev, &vblwait.request.sequence);
microtime(&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) );
return ret;
}
void DRM(vbl_send_signals)( drm_device_t *dev )
{
drm_vbl_sig_t *vbl_sig;
unsigned int vbl_seq = atomic_read( &dev->vbl_received );
struct proc *p;
DRM_SPINLOCK(&dev->vbl_lock);
vbl_sig = TAILQ_FIRST(&dev->vbl_sig_list);
while (vbl_sig != NULL) {
drm_vbl_sig_t *next = TAILQ_NEXT(vbl_sig, link);
if ( ( vbl_seq - vbl_sig->sequence ) <= (1<<23) ) {
p = pfind(vbl_sig->pid);
if (p != NULL)
psignal(p, vbl_sig->signo);
TAILQ_REMOVE(&dev->vbl_sig_list, vbl_sig, link);
DRM_FREE(vbl_sig);
}
vbl_sig = next;
}
DRM_SPINUNLOCK(&dev->vbl_lock);
}
#endif /* __HAVE_VBL_IRQ */
#else

View file

@ -346,15 +346,29 @@ 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;
};
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 {

View file

@ -392,6 +392,14 @@ typedef struct drm_map_list_entry {
drm_map_t *map;
} drm_map_list_entry_t;
TAILQ_HEAD(drm_vbl_sig_list, drm_vbl_sig);
typedef struct drm_vbl_sig {
TAILQ_ENTRY(drm_vbl_sig) link;
unsigned int sequence;
int signo;
int pid;
} drm_vbl_sig_t;
struct drm_device {
#ifdef __NetBSD__
struct device device; /* NetBSD's softc is an extension of struct device */
@ -469,6 +477,8 @@ struct drm_device {
#if __HAVE_VBL_IRQ
wait_queue_head_t vbl_queue; /* vbl wait channel */
atomic_t vbl_received;
struct drm_vbl_sig_list vbl_sig_list;
DRM_SPINTYPE vbl_lock;
#endif
cycles_t ctx_start;
cycles_t lck_start;
@ -613,6 +623,7 @@ extern drm_buf_t *DRM(freelist_get)(drm_freelist_t *bl, int block);
#endif /* __HAVE_DMA */
#if __HAVE_VBL_IRQ
extern int DRM(vblank_wait)(drm_device_t *dev, unsigned int *vbl_seq);
extern void DRM(vbl_send_signals)( drm_device_t *dev );
#endif
#if __REALLY_HAVE_AGP

View file

@ -524,6 +524,11 @@ int DRM(irq_install)( drm_device_t *dev, int irq )
TASK_INIT(&dev->task, 0, DRM(dma_immediate_bh), dev);
#endif
#if __HAVE_VBL_IRQ
DRM_SPININIT( dev->vbl_lock, "vblsig" );
TAILQ_INIT( &dev->vbl_sig_list );
#endif
/* Before installing handler */
DRM(driver_irq_preinstall)( dev );
@ -612,21 +617,67 @@ 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 );
if (vblwait.request.type & _DRM_VBLANK_RELATIVE) {
vblwait.request.sequence += atomic_read(&dev->vbl_received);
}
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));
if (vbl_sig == NULL)
return ENOMEM;
bzero(vbl_sig, sizeof(*vbl_sig));
vbl_sig->sequence = vblwait.request.sequence;
vbl_sig->signo = vblwait.request.signal;
vbl_sig->pid = DRM_CURRENTPID;
microtime( &now );
vblwait.tval_sec = now.tv_sec;
vblwait.tval_usec = now.tv_usec;
vblwait.reply.sequence = atomic_read(&dev->vbl_received);
DRM_SPINLOCK(&dev->vbl_lock);
TAILQ_INSERT_HEAD(&dev->vbl_sig_list, vbl_sig, link);
DRM_SPINUNLOCK(&dev->vbl_lock);
ret = 0;
} else {
ret = DRM(vblank_wait)(dev, &vblwait.request.sequence);
microtime(&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) );
return ret;
}
void DRM(vbl_send_signals)( drm_device_t *dev )
{
drm_vbl_sig_t *vbl_sig;
unsigned int vbl_seq = atomic_read( &dev->vbl_received );
struct proc *p;
DRM_SPINLOCK(&dev->vbl_lock);
vbl_sig = TAILQ_FIRST(&dev->vbl_sig_list);
while (vbl_sig != NULL) {
drm_vbl_sig_t *next = TAILQ_NEXT(vbl_sig, link);
if ( ( vbl_seq - vbl_sig->sequence ) <= (1<<23) ) {
p = pfind(vbl_sig->pid);
if (p != NULL)
psignal(p, vbl_sig->signo);
TAILQ_REMOVE(&dev->vbl_sig_list, vbl_sig, link);
DRM_FREE(vbl_sig);
}
vbl_sig = next;
}
DRM_SPINUNLOCK(&dev->vbl_lock);
}
#endif /* __HAVE_VBL_IRQ */
#else