#include <linux/export.h>
 
 /* Access macro for slots in vblank timestamp ringbuffer. */
-#define vblanktimestamp(dev, crtc, count) ( \
-       (dev)->_vblank_time[(crtc) * DRM_VBLANKTIME_RBSIZE + \
-       ((count) % DRM_VBLANKTIME_RBSIZE)])
+#define vblanktimestamp(dev, crtc, count) \
+       ((dev)->vblank[crtc].time[(count) % DRM_VBLANKTIME_RBSIZE])
 
 /* Retry timestamp calculation up to 3 times to satisfy
  * drm_timestamp_precision before giving up.
  */
 static void clear_vblank_timestamps(struct drm_device *dev, int crtc)
 {
-       memset(&dev->_vblank_time[crtc * DRM_VBLANKTIME_RBSIZE], 0,
-               DRM_VBLANKTIME_RBSIZE * sizeof(struct timeval));
+       memset(dev->vblank[crtc].time, 0, sizeof(dev->vblank[crtc].time));
 }
 
 /*
        spin_lock_irqsave(&dev->vblank_time_lock, irqflags);
 
        dev->driver->disable_vblank(dev, crtc);
-       dev->vblank_enabled[crtc] = false;
+       dev->vblank[crtc].enabled = false;
 
        /* No further vblank irq's will be processed after
         * this point. Get current hardware vblank count and
         * delayed gpu counter increment.
         */
        do {
-               dev->last_vblank[crtc] = dev->driver->get_vblank_counter(dev, crtc);
+               dev->vblank[crtc].last = dev->driver->get_vblank_counter(dev, crtc);
                vblrc = drm_get_last_vbltimestamp(dev, crtc, &tvblank, 0);
-       } while (dev->last_vblank[crtc] != dev->driver->get_vblank_counter(dev, crtc) && (--count) && vblrc);
+       } while (dev->vblank[crtc].last != dev->driver->get_vblank_counter(dev, crtc) && (--count) && vblrc);
 
        if (!count)
                vblrc = 0;
        /* Compute time difference to stored timestamp of last vblank
         * as updated by last invocation of drm_handle_vblank() in vblank irq.
         */
-       vblcount = atomic_read(&dev->_vblank_count[crtc]);
+       vblcount = atomic_read(&dev->vblank[crtc].count);
        diff_ns = timeval_to_ns(&tvblank) -
                  timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount));
 
         * hope for the best.
         */
        if ((vblrc > 0) && (abs64(diff_ns) > 1000000)) {
-               atomic_inc(&dev->_vblank_count[crtc]);
+               atomic_inc(&dev->vblank[crtc].count);
                smp_mb__after_atomic_inc();
        }
 
 
        for (i = 0; i < dev->num_crtcs; i++) {
                spin_lock_irqsave(&dev->vbl_lock, irqflags);
-               if (atomic_read(&dev->vblank_refcount[i]) == 0 &&
-                   dev->vblank_enabled[i]) {
+               if (atomic_read(&dev->vblank[i].refcount) == 0 &&
+                   dev->vblank[i].enabled) {
                        DRM_DEBUG("disabling vblank on crtc %d\n", i);
                        vblank_disable_and_save(dev, i);
                }
 
        vblank_disable_fn((unsigned long)dev);
 
-       kfree(dev->vbl_queue);
-       kfree(dev->_vblank_count);
-       kfree(dev->vblank_refcount);
-       kfree(dev->vblank_enabled);
-       kfree(dev->last_vblank);
-       kfree(dev->last_vblank_wait);
-       kfree(dev->vblank_inmodeset);
-       kfree(dev->_vblank_time);
+       kfree(dev->vblank);
 
        dev->num_crtcs = 0;
 }
 
        dev->num_crtcs = num_crtcs;
 
-       dev->vbl_queue = kmalloc(sizeof(wait_queue_head_t) * num_crtcs,
-                                GFP_KERNEL);
-       if (!dev->vbl_queue)
+       dev->vblank = kcalloc(num_crtcs, sizeof(*dev->vblank), GFP_KERNEL);
+       if (!dev->vblank)
                goto err;
 
-       dev->_vblank_count = kmalloc(sizeof(atomic_t) * num_crtcs, GFP_KERNEL);
-       if (!dev->_vblank_count)
-               goto err;
-
-       dev->vblank_refcount = kmalloc(sizeof(atomic_t) * num_crtcs,
-                                      GFP_KERNEL);
-       if (!dev->vblank_refcount)
-               goto err;
-
-       dev->vblank_enabled = kcalloc(num_crtcs, sizeof(bool), GFP_KERNEL);
-       if (!dev->vblank_enabled)
-               goto err;
-
-       dev->last_vblank = kcalloc(num_crtcs, sizeof(u32), GFP_KERNEL);
-       if (!dev->last_vblank)
-               goto err;
-
-       dev->last_vblank_wait = kcalloc(num_crtcs, sizeof(u32), GFP_KERNEL);
-       if (!dev->last_vblank_wait)
-               goto err;
-
-       dev->vblank_inmodeset = kcalloc(num_crtcs, sizeof(int), GFP_KERNEL);
-       if (!dev->vblank_inmodeset)
-               goto err;
-
-       dev->_vblank_time = kcalloc(num_crtcs * DRM_VBLANKTIME_RBSIZE,
-                                   sizeof(struct timeval), GFP_KERNEL);
-       if (!dev->_vblank_time)
-               goto err;
+       for (i = 0; i < num_crtcs; i++)
+               init_waitqueue_head(&dev->vblank[i].queue);
 
        DRM_INFO("Supports vblank timestamp caching Rev 1 (10.10.2010).\n");
 
        else
                DRM_INFO("No driver support for vblank timestamp query.\n");
 
-       /* Zero per-crtc vblank stuff */
-       for (i = 0; i < num_crtcs; i++) {
-               init_waitqueue_head(&dev->vbl_queue[i]);
-               atomic_set(&dev->_vblank_count[i], 0);
-               atomic_set(&dev->vblank_refcount[i], 0);
-       }
-
        dev->vblank_disable_allowed = false;
 
        return 0;
        if (dev->num_crtcs) {
                spin_lock_irqsave(&dev->vbl_lock, irqflags);
                for (i = 0; i < dev->num_crtcs; i++) {
-                       DRM_WAKEUP(&dev->vbl_queue[i]);
-                       dev->vblank_enabled[i] = false;
-                       dev->last_vblank[i] =
+                       DRM_WAKEUP(&dev->vblank[i].queue);
+                       dev->vblank[i].enabled = false;
+                       dev->vblank[i].last =
                                dev->driver->get_vblank_counter(dev, i);
                }
                spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
  */
 u32 drm_vblank_count(struct drm_device *dev, int crtc)
 {
-       return atomic_read(&dev->_vblank_count[crtc]);
+       return atomic_read(&dev->vblank[crtc].count);
 }
 EXPORT_SYMBOL(drm_vblank_count);
 
         * a seqlock.
         */
        do {
-               cur_vblank = atomic_read(&dev->_vblank_count[crtc]);
+               cur_vblank = atomic_read(&dev->vblank[crtc].count);
                *vblanktime = vblanktimestamp(dev, crtc, cur_vblank);
                smp_rmb();
-       } while (cur_vblank != atomic_read(&dev->_vblank_count[crtc]));
+       } while (cur_vblank != atomic_read(&dev->vblank[crtc].count));
 
        return cur_vblank;
 }
        } while (cur_vblank != dev->driver->get_vblank_counter(dev, crtc));
 
        /* Deal with counter wrap */
-       diff = cur_vblank - dev->last_vblank[crtc];
-       if (cur_vblank < dev->last_vblank[crtc]) {
+       diff = cur_vblank - dev->vblank[crtc].last;
+       if (cur_vblank < dev->vblank[crtc].last) {
                diff += dev->max_vblank_count;
 
                DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n",
-                         crtc, dev->last_vblank[crtc], cur_vblank, diff);
+                         crtc, dev->vblank[crtc].last, cur_vblank, diff);
        }
 
        DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n",
         * reinitialize delayed at next vblank interrupt in that case.
         */
        if (rc) {
-               tslot = atomic_read(&dev->_vblank_count[crtc]) + diff;
+               tslot = atomic_read(&dev->vblank[crtc].count) + diff;
                vblanktimestamp(dev, crtc, tslot) = t_vblank;
        }
 
        smp_mb__before_atomic_inc();
-       atomic_add(diff, &dev->_vblank_count[crtc]);
+       atomic_add(diff, &dev->vblank[crtc].count);
        smp_mb__after_atomic_inc();
 }
 
 
        spin_lock_irqsave(&dev->vbl_lock, irqflags);
        /* Going from 0->1 means we have to enable interrupts again */
-       if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) {
+       if (atomic_add_return(1, &dev->vblank[crtc].refcount) == 1) {
                spin_lock_irqsave(&dev->vblank_time_lock, irqflags2);
-               if (!dev->vblank_enabled[crtc]) {
+               if (!dev->vblank[crtc].enabled) {
                        /* Enable vblank irqs under vblank_time_lock protection.
                         * All vblank count & timestamp updates are held off
                         * until we are done reinitializing master counter and
                        DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n",
                                  crtc, ret);
                        if (ret)
-                               atomic_dec(&dev->vblank_refcount[crtc]);
+                               atomic_dec(&dev->vblank[crtc].refcount);
                        else {
-                               dev->vblank_enabled[crtc] = true;
+                               dev->vblank[crtc].enabled = true;
                                drm_update_vblank_count(dev, crtc);
                        }
                }
                spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags2);
        } else {
-               if (!dev->vblank_enabled[crtc]) {
-                       atomic_dec(&dev->vblank_refcount[crtc]);
+               if (!dev->vblank[crtc].enabled) {
+                       atomic_dec(&dev->vblank[crtc].refcount);
                        ret = -EINVAL;
                }
        }
  */
 void drm_vblank_put(struct drm_device *dev, int crtc)
 {
-       BUG_ON(atomic_read(&dev->vblank_refcount[crtc]) == 0);
+       BUG_ON(atomic_read(&dev->vblank[crtc].refcount) == 0);
 
        /* Last user schedules interrupt disable */
-       if (atomic_dec_and_test(&dev->vblank_refcount[crtc]) &&
+       if (atomic_dec_and_test(&dev->vblank[crtc].refcount) &&
            (drm_vblank_offdelay > 0))
                mod_timer(&dev->vblank_disable_timer,
                          jiffies + ((drm_vblank_offdelay * DRM_HZ)/1000));
 
        spin_lock_irqsave(&dev->vbl_lock, irqflags);
        vblank_disable_and_save(dev, crtc);
-       DRM_WAKEUP(&dev->vbl_queue[crtc]);
+       DRM_WAKEUP(&dev->vblank[crtc].queue);
 
        /* Send any queued vblank events, lest the natives grow disquiet */
        seq = drm_vblank_count_and_time(dev, crtc, &now);
         * to avoid corrupting the count if multiple, mismatch calls occur),
         * so that interrupts remain enabled in the interim.
         */
-       if (!dev->vblank_inmodeset[crtc]) {
-               dev->vblank_inmodeset[crtc] = 0x1;
+       if (!dev->vblank[crtc].inmodeset) {
+               dev->vblank[crtc].inmodeset = 0x1;
                if (drm_vblank_get(dev, crtc) == 0)
-                       dev->vblank_inmodeset[crtc] |= 0x2;
+                       dev->vblank[crtc].inmodeset |= 0x2;
        }
 }
 EXPORT_SYMBOL(drm_vblank_pre_modeset);
        if (!dev->num_crtcs)
                return;
 
-       if (dev->vblank_inmodeset[crtc]) {
+       if (dev->vblank[crtc].inmodeset) {
                spin_lock_irqsave(&dev->vbl_lock, irqflags);
                dev->vblank_disable_allowed = true;
                spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 
-               if (dev->vblank_inmodeset[crtc] & 0x2)
+               if (dev->vblank[crtc].inmodeset & 0x2)
                        drm_vblank_put(dev, crtc);
 
-               dev->vblank_inmodeset[crtc] = 0;
+               dev->vblank[crtc].inmodeset = 0;
        }
 }
 EXPORT_SYMBOL(drm_vblank_post_modeset);
 
        DRM_DEBUG("waiting on vblank count %d, crtc %d\n",
                  vblwait->request.sequence, crtc);
-       dev->last_vblank_wait[crtc] = vblwait->request.sequence;
-       DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ,
+       dev->vblank[crtc].last_wait = vblwait->request.sequence;
+       DRM_WAIT_ON(ret, dev->vblank[crtc].queue, 3 * DRM_HZ,
                    (((drm_vblank_count(dev, crtc) -
                       vblwait->request.sequence) <= (1 << 23)) ||
                     !dev->irq_enabled));
        spin_lock_irqsave(&dev->vblank_time_lock, irqflags);
 
        /* Vblank irq handling disabled. Nothing to do. */
-       if (!dev->vblank_enabled[crtc]) {
+       if (!dev->vblank[crtc].enabled) {
                spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
                return false;
        }
         */
 
        /* Get current timestamp and count. */
-       vblcount = atomic_read(&dev->_vblank_count[crtc]);
+       vblcount = atomic_read(&dev->vblank[crtc].count);
        drm_get_last_vbltimestamp(dev, crtc, &tvblank, DRM_CALLED_FROM_VBLIRQ);
 
        /* Compute time difference to timestamp of last vblank */
                 * the timestamp computed above.
                 */
                smp_mb__before_atomic_inc();
-               atomic_inc(&dev->_vblank_count[crtc]);
+               atomic_inc(&dev->vblank[crtc].count);
                smp_mb__after_atomic_inc();
        } else {
                DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n",
                          crtc, (int) diff_ns);
        }
 
-       DRM_WAKEUP(&dev->vbl_queue[crtc]);
+       DRM_WAKEUP(&dev->vblank[crtc].queue);
        drm_handle_vblank_events(dev, crtc);
 
        spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
 
 
        if (gma_power_is_on(dev))
                PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM);
-       if (dev->vblank_enabled[0])
+       if (dev->vblank[0].enabled)
                dev_priv->vdc_irq_mask |= _PSB_VSYNC_PIPEA_FLAG;
-       if (dev->vblank_enabled[1])
+       if (dev->vblank[1].enabled)
                dev_priv->vdc_irq_mask |= _PSB_VSYNC_PIPEB_FLAG;
 
        /* FIXME: Handle Medfield irq mask
-       if (dev->vblank_enabled[1])
+       if (dev->vblank[1].enabled)
                dev_priv->vdc_irq_mask |= _MDFLD_PIPEB_EVENT_FLAG;
-       if (dev->vblank_enabled[2])
+       if (dev->vblank[2].enabled)
                dev_priv->vdc_irq_mask |= _MDFLD_PIPEC_EVENT_FLAG;
        */
 
        PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R);
        PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM);
 
-       if (dev->vblank_enabled[0])
+       if (dev->vblank[0].enabled)
                psb_enable_pipestat(dev_priv, 0, PIPE_VBLANK_INTERRUPT_ENABLE);
        else
                psb_disable_pipestat(dev_priv, 0, PIPE_VBLANK_INTERRUPT_ENABLE);
 
-       if (dev->vblank_enabled[1])
+       if (dev->vblank[1].enabled)
                psb_enable_pipestat(dev_priv, 1, PIPE_VBLANK_INTERRUPT_ENABLE);
        else
                psb_disable_pipestat(dev_priv, 1, PIPE_VBLANK_INTERRUPT_ENABLE);
 
-       if (dev->vblank_enabled[2])
+       if (dev->vblank[2].enabled)
                psb_enable_pipestat(dev_priv, 2, PIPE_VBLANK_INTERRUPT_ENABLE);
        else
                psb_disable_pipestat(dev_priv, 2, PIPE_VBLANK_INTERRUPT_ENABLE);
 
        PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM);
 
-       if (dev->vblank_enabled[0])
+       if (dev->vblank[0].enabled)
                psb_disable_pipestat(dev_priv, 0, PIPE_VBLANK_INTERRUPT_ENABLE);
 
-       if (dev->vblank_enabled[1])
+       if (dev->vblank[1].enabled)
                psb_disable_pipestat(dev_priv, 1, PIPE_VBLANK_INTERRUPT_ENABLE);
 
-       if (dev->vblank_enabled[2])
+       if (dev->vblank[2].enabled)
                psb_disable_pipestat(dev_priv, 2, PIPE_VBLANK_INTERRUPT_ENABLE);
 
        dev_priv->vdc_irq_mask &= _PSB_IRQ_SGX_FLAG |
 {
        unsigned int cur_vblank;
        int ret = 0;
-       DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
+       DRM_WAIT_ON(ret, dev->vblank.queue, 3 * DRM_HZ,
                    (((cur_vblank = atomic_read(counter))
                      - *sequence) <= (1 << 23)));
        *sequence = cur_vblank;