drm: add support for secondary vertical blank interrupt to DRM core
author=?utf-8?q?Michel_D=C3=A4nzer?= <michel@tungstengraphics.com>
Tue, 24 Oct 2006 12:24:38 +0000 (22:24 +1000)
committerairlied <airlied@linux.ie>
Thu, 7 Dec 2006 04:53:28 +0000 (15:53 +1100)
Signed-off-by: Dave Airlie <airlied@linux.ie>
drivers/char/drm/drm.h
drivers/char/drm/drmP.h
drivers/char/drm/drm_core.h
drivers/char/drm/drm_irq.c

index 5642ac4..077d0b1 100644 (file)
@@ -465,10 +465,12 @@ typedef struct drm_irq_busid {
 typedef enum {
        _DRM_VBLANK_ABSOLUTE = 0x0,     /**< Wait for specific vblank sequence number */
        _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_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 {
        drm_vblank_seq_type_t type;
index 7690a59..d7135d4 100644 (file)
@@ -97,6 +97,7 @@
 #define DRIVER_IRQ_VBL     0x100
 #define DRIVER_DMA_QUEUE   0x200
 #define DRIVER_FB_DMA      0x400
+#define DRIVER_IRQ_VBL2    0x800
 
 /***********************************************************************/
 /** \name Begin the DRM... */
@@ -562,6 +563,7 @@ struct drm_driver {
        void (*kernel_context_switch_unlock) (struct drm_device * dev,
                                              drm_lock_t *lock);
        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);
 
        /**
@@ -708,8 +710,10 @@ typedef struct drm_device {
 
        wait_queue_head_t vbl_queue;    /**< VBLANK wait queue */
        atomic_t vbl_received;
+       atomic_t vbl_received2;         /**< number of secondary VBLANK interrupts */
        spinlock_t vbl_lock;
        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;
 
        /*@} */
index f4f9db6..3167390 100644 (file)
 
 #define CORE_NAME              "drm"
 #define CORE_DESC              "DRM shared core routines"
-#define CORE_DATE              "20051102"
+#define CORE_DATE              "20060810"
 
 #define DRM_IF_MAJOR   1
-#define DRM_IF_MINOR   2
+#define DRM_IF_MINOR   3
 
 #define CORE_MAJOR     1
-#define CORE_MINOR     0
-#define CORE_PATCHLEVEL 1
+#define CORE_MINOR     1
+#define CORE_PATCHLEVEL 0
index 4553a3a..3c77756 100644 (file)
@@ -121,6 +121,7 @@ static int drm_irq_install(drm_device_t * dev)
                spin_lock_init(&dev->vbl_lock);
 
                INIT_LIST_HEAD(&dev->vbl_sigs.head);
+               INIT_LIST_HEAD(&dev->vbl_sigs2.head);
 
                dev->vbl_pending = 0;
        }
@@ -248,9 +249,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
        struct timeval now;
        int ret = 0;
        unsigned int flags;
-
-       if (!drm_core_check_feature(dev, DRIVER_IRQ_VBL))
-               return -EINVAL;
+       atomic_t *seq;
 
        if (!dev->irq)
                return -EINVAL;
@@ -258,9 +257,26 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
        if (copy_from_user(&vblwait, argp, sizeof(vblwait)))
                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:
-               vblwait.request.sequence += atomic_read(&dev->vbl_received);
+               vblwait.request.sequence += atomic_read(seq);
                vblwait.request.type &= ~_DRM_VBLANK_RELATIVE;
        case _DRM_VBLANK_ABSOLUTE:
                break;
@@ -268,13 +284,13 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
                return -EINVAL;
        }
 
-       flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
-
        if (flags & _DRM_VBLANK_SIGNAL) {
                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;
 
-               vblwait.reply.sequence = atomic_read(&dev->vbl_received);
+               vblwait.reply.sequence = atomic_read(seq);
 
                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
                 * 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
                            && vbl_sig->info.si_signo == vblwait.request.signal
                            && vbl_sig->task == current) {
@@ -315,11 +331,14 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
 
                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);
        } 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 =
                            dev->driver->vblank_wait(dev,
                                                     &vblwait.request.sequence);
@@ -347,25 +366,32 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
  */
 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;
+       int i;
 
        spin_lock_irqsave(&dev->vbl_lock, flags);
 
-       list_for_each_safe(list, tmp, &dev->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);
+       for (i = 0; i < 2; i++) {
+               struct list_head *list, *tmp;
+               drm_vbl_sig_t *vbl_sig;
+               drm_vbl_sig_t *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs;
+               unsigned int vbl_seq = atomic_read(i ? &dev->vbl_received2 :
+                                                  &dev->vbl_received);
+
+               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);
 
-                       list_del(list);
+                               list_del(list);
 
-                       drm_free(vbl_sig, sizeof(*vbl_sig), DRM_MEM_DRIVER);
+                               drm_free(vbl_sig, sizeof(*vbl_sig),
+                                        DRM_MEM_DRIVER);
 
-                       dev->vbl_pending--;
+                               dev->vbl_pending--;
+                       }
                }
        }