Initial pass at porting MGA to vblank-rework
authorIan Romanick <idr@us.ibm.com>
Fri, 26 Oct 2007 00:14:53 +0000 (17:14 -0700)
committerIan Romanick <idr@us.ibm.com>
Fri, 26 Oct 2007 00:14:53 +0000 (17:14 -0700)
This is currently only compile tested.

linux-core/mga_drv.c
shared-core/mga_drv.h
shared-core/mga_irq.c

index ef6f1e4..6419cbd 100644 (file)
@@ -46,15 +46,16 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *ent);
 static struct drm_driver driver = {
        .driver_features =
            DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA |
-           DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
-           DRIVER_IRQ_VBL,
+           DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
        .dev_priv_size = sizeof (drm_mga_buf_priv_t),
        .load = mga_driver_load,
        .unload = mga_driver_unload,
        .lastclose = mga_driver_lastclose,
        .dma_quiescent = mga_driver_dma_quiescent,
        .device_is_agp = mga_driver_device_is_agp,
-       .vblank_wait = mga_driver_vblank_wait,
+       .get_vblank_counter = mga_get_vblank_counter,
+       .enable_vblank = mga_enable_vblank,
+       .disable_vblank = mga_disable_vblank,
        .irq_preinstall = mga_driver_irq_preinstall,
        .irq_postinstall = mga_driver_irq_postinstall,
        .irq_uninstall = mga_driver_irq_uninstall,
index bce8213..4764eda 100644 (file)
@@ -113,13 +113,14 @@ typedef struct drm_mga_private {
         * \sa drm_mga_private_t::mmio
         */
        /*@{*/
-       u32 mmio_base;             /**< Bus address of base of MMIO. */
-       u32 mmio_size;             /**< Size of the MMIO region. */
+       u32 mmio_base;                  /**< Bus address of base of MMIO. */
+       u32 mmio_size;                  /**< Size of the MMIO region. */
        /*@}*/
 
        u32 clear_cmd;
        u32 maccess;
 
+       atomic_t vbl_received;          /**< Number of vblanks received. */
        wait_queue_head_t fence_queue;
        atomic_t last_fence_retired;
        u32 next_fence_to_post;
@@ -177,10 +178,12 @@ extern int mga_warp_init(drm_mga_private_t * dev_priv);
 
                                /* mga_irq.c */
 extern int mga_driver_fence_wait(drm_device_t * dev, unsigned int *sequence);
-extern int mga_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence);
+extern int mga_enable_vblank(drm_device_t *dev, int crtc);
+extern void mga_disable_vblank(drm_device_t *dev, int crtc);
+extern u32 mga_get_vblank_counter(drm_device_t *dev, int crtc);
 extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS);
 extern void mga_driver_irq_preinstall(drm_device_t * dev);
-extern void mga_driver_irq_postinstall(drm_device_t * dev);
+extern int mga_driver_irq_postinstall(drm_device_t * dev);
 extern void mga_driver_irq_uninstall(drm_device_t * dev);
 extern long mga_compat_ioctl(struct file *filp, unsigned int cmd,
                             unsigned long arg);
index 490d1fb..a49a9b6 100644 (file)
 #include "mga_drm.h"
 #include "mga_drv.h"
 
+u32 mga_get_vblank_counter(drm_device_t *dev, int crtc)
+{
+       const drm_mga_private_t *const dev_priv = 
+               (drm_mga_private_t *) dev->dev_private;
+
+       if (crtc != 0) {
+               return 0;
+       }
+
+
+       return atomic_read(&dev_priv->vbl_received);
+}
+
+
 irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
 {
        drm_device_t *dev = (drm_device_t *) arg;
@@ -48,9 +62,8 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
        /* VBLANK interrupt */
        if (status & MGA_VLINEPEN) {
                MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR);
-               atomic_inc(&dev->vbl_received);
-               DRM_WAKEUP(&dev->vbl_queue);
-               drm_vbl_send_signals(dev);
+               atomic_inc(&dev_priv->vbl_received);
+               drm_handle_vblank(dev, 0);
                handled = 1;
        }
 
@@ -74,30 +87,41 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
                handled = 1;
        }
 
-       if ( handled ) {
-               return IRQ_HANDLED;
-       }
-       return IRQ_NONE;
+       return (handled) ? IRQ_HANDLED : IRQ_NONE;
 }
 
-int mga_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
+
+int mga_enable_vblank(drm_device_t *dev, int crtc)
 {
-       unsigned int cur_vblank;
-       int ret = 0;
+       drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
 
-       /* Assume that the user has missed the current sequence number
-        * by about a day rather than she wants to wait for years
-        * using vertical blanks...
-        */
-       DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
-                   (((cur_vblank = atomic_read(&dev->vbl_received))
-                     - *sequence) <= (1 << 23)));
+       if (crtc != 0) {
+               DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
+                         crtc);
+               return 0;
+       }
+
+       MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
+       return 0;
+}
 
-       *sequence = cur_vblank;
 
-       return ret;
+void mga_disable_vblank(drm_device_t *dev, int crtc)
+{
+       if (crtc != 0) {
+               DRM_ERROR("tried to disable vblank on non-existent crtc %d\n",
+                         crtc);
+       }
+
+       /* Do *NOT* disable the vertical refresh interrupt.  MGA doesn't have
+        * a nice hardware counter that tracks the number of refreshes when
+        * the interrupt is disabled, and the kernel doesn't know the refresh
+        * rate to calculate an estimate.
+        */
+       /* MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); */
 }
 
+
 int mga_driver_fence_wait(drm_device_t * dev, unsigned int *sequence)
 {
        drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
@@ -127,16 +151,25 @@ void mga_driver_irq_preinstall(drm_device_t * dev)
        MGA_WRITE(MGA_ICLEAR, ~0);
 }
 
-void mga_driver_irq_postinstall(drm_device_t * dev)
+int mga_driver_irq_postinstall(drm_device_t * dev)
 {
        drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
+       int ret;
 
-       DRM_INIT_WAITQUEUE( &dev_priv->fence_queue );
+       ret = drm_vblank_init(dev, 1);
+       if (ret)
+               return ret;
 
-       /* Turn on vertical blank interrupt and soft trap interrupt. */
-       MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
+       DRM_INIT_WAITQUEUE(&dev_priv->fence_queue);
+
+       /* Turn on soft trap interrupt.  Vertical blank interrupts are enabled
+        * in mga_enable_vblank.
+        */
+       MGA_WRITE(MGA_IEN, MGA_SOFTRAPEN);
+       return 0;
 }
 
+
 void mga_driver_irq_uninstall(drm_device_t * dev)
 {
        drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;