Add vblank signal code for BSD DRM. Untested so far, but working with a
authorEric Anholt <anholt@freebsd.org>
Fri, 6 Dec 2002 02:27:30 +0000 (02:27 +0000)
committerEric Anholt <anholt@freebsd.org>
Fri, 6 Dec 2002 02:27:30 +0000 (02:27 +0000)
    4.2.0 userland at least.

bsd-core/drmP.h
bsd-core/drm_dma.c
bsd/drm.h
bsd/drmP.h
bsd/drm_dma.h

index b7b21da..541bc2e 100644 (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
index 5632b5a..69c66c9 100644 (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 );
-
-       microtime( &now );
-       vblwait.tval_sec = now.tv_sec;
-       vblwait.tval_usec = now.tv_usec;
+       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;
+
+               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
index f45f088..d3c9f15 100644 (file)
--- a/bsd/drm.h
+++ b/bsd/drm.h
@@ -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 {
index b7b21da..541bc2e 100644 (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
index 5632b5a..69c66c9 100644 (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 );
-
-       microtime( &now );
-       vblwait.tval_sec = now.tv_sec;
-       vblwait.tval_usec = now.tv_usec;
+       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;
+
+               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