Adds support for MGA DRM version 3.2.
authorIan Romanick <idr@us.ibm.com>
Tue, 14 Jun 2005 22:51:44 +0000 (22:51 +0000)
committerIan Romanick <idr@us.ibm.com>
Tue, 14 Jun 2005 22:51:44 +0000 (22:51 +0000)
This patch makes use of two of the new ioctls added in MGA DRM version
3.2.  Specifically, the DRM_MGA_SET_FENCE and DRM_MGA_WAIT_FENCE
ioctls are used in mgaWaitForFrameCompletion.  As a result the MMIO
register region and the primary DMA region are *not* mapped (if DRM
3.2 is available).

This patch does *not* make use of the new get_param query was added to
differentiate between G4x0 cards and G550 cards.  That is left to a
future update.

Xorg bug: 3259
Reviewed by: Eric Anholt

src/mesa/drivers/dri/mga/mga_xmesa.c
src/mesa/drivers/dri/mga/mgacontext.h
src/mesa/drivers/dri/mga/mgadd.c
src/mesa/drivers/dri/mga/mgaioctl.c

index aa4cfe5ccde94d69903c2575dbd42d4f1c96450f..44e69dd1de424f5d76b14dec1c58193a543a33b3 100644 (file)
@@ -31,6 +31,7 @@
  */
 
 #include <stdlib.h>
+#include <stdint.h>
 #include "drm.h"
 #include "mga_drm.h"
 #include "mga_xmesa.h"
@@ -264,22 +265,30 @@ mgaInitDriver(__DRIscreenPrivate *sPriv)
     * primary DMA region base address needs to be known is so that the driver
     * can busy wait for certain DMA operations to complete (see
     * mgaWaitForFrameCompletion in mgaioctl.c).
+    *
+    * Starting with MGA DRM version 3.2, these are completely unneeded as
+    * there is a new, in-kernel mechanism for handling the wait.
     */
 
-   mgaScreen->mmio.handle = serverInfo->registers.handle;
-   mgaScreen->mmio.size = serverInfo->registers.size;
-   if ( drmMap( sPriv->fd,
-               mgaScreen->mmio.handle, mgaScreen->mmio.size,
-               &mgaScreen->mmio.map ) < 0 ) {
-      FREE( mgaScreen );
-      sPriv->private = NULL;
-      __driUtilMessage( "Couldn't map MMIO registers" );
-      return GL_FALSE;
-   }
-
-   mgaScreen->primary.handle = serverInfo->primary.handle;
-   mgaScreen->primary.size = serverInfo->primary.size;
+   if (mgaScreen->sPriv->drmMinor < 2) {
+      mgaScreen->mmio.handle = serverInfo->registers.handle;
+      mgaScreen->mmio.size = serverInfo->registers.size;
+      if ( drmMap( sPriv->fd,
+                  mgaScreen->mmio.handle, mgaScreen->mmio.size,
+                  &mgaScreen->mmio.map ) < 0 ) {
+        FREE( mgaScreen );
+        sPriv->private = NULL;
+        __driUtilMessage( "Couldn't map MMIO registers" );
+        return GL_FALSE;
+      }
 
+      mgaScreen->primary.handle = serverInfo->primary.handle;
+      mgaScreen->primary.size = serverInfo->primary.size;
+   }
+   else {
+      (void) memset( & mgaScreen->primary, 0, sizeof( mgaScreen->primary ) );
+      (void) memset( & mgaScreen->mmio, 0, sizeof( mgaScreen->mmio ) );
+   }
 
    mgaScreen->textureOffset[MGA_CARD_HEAP] = serverInfo->textureOffset;
    mgaScreen->textureOffset[MGA_AGP_HEAP] = (serverInfo->agpTextureOffset |
index 72c1841fedd05494946129b4b3be1ffc793bbe78..1d8c5da6dae5b3869b233ffe20fd08f4ab787c04 100644 (file)
@@ -29,6 +29,7 @@
 #ifndef MGALIB_INC
 #define MGALIB_INC
 
+#include <stdint.h>
 #include "drm.h"
 #include "mga_drm.h"
 #include "dri_util.h"
@@ -268,6 +269,8 @@ struct mga_context_t {
    GLuint swap_count;
    GLuint swap_missed_count;
 
+   uint32_t last_frame_fence;
+
    PFNGLXGETUSTPROC get_ust;
 
    /* Drawable, cliprect and scissor information
index 7310641efa3c4bd83e24570fc4c77305e2e5be27..8532ea95f101fe649bbe8f939d1ab9f3997e3bd7 100644 (file)
@@ -41,7 +41,7 @@
 #include "mga_xmesa.h"
 #include "utils.h"
 
-#define DRIVER_DATE    "20030328"
+#define DRIVER_DATE    "20050609"
 
 
 /***************************************
index d741b57cead05256c9776b2a3fc7d8d09d86af2a..62785f6344b6258cd63daa1d4098b789034d0d9c 100644 (file)
 #include "vblank.h"
 
 
+int
+mgaSetFence( mgaContextPtr mmesa, uint32_t * fence )
+{
+    int ret = ENOSYS;
+
+    if ( mmesa->driScreen->drmMinor >= 2 ) {
+       ret = drmCommandWriteRead( mmesa->driScreen->fd, DRM_MGA_SET_FENCE,
+                                  fence, sizeof( uint32_t ));
+       if (ret) {
+           fprintf(stderr, "drmMgaSetFence: %d\n", ret);
+           exit(1);
+       }
+    }
+
+    return ret;
+}
+
+
+int
+mgaWaitFence( mgaContextPtr mmesa, uint32_t fence, uint32_t * curr_fence )
+{
+    int ret = ENOSYS;
+
+    if ( mmesa->driScreen->drmMinor >= 2 ) {
+       uint32_t temp = fence;
+       
+       ret = drmCommandWriteRead( mmesa->driScreen->fd,
+                                  DRM_MGA_WAIT_FENCE,
+                                  & temp, sizeof( uint32_t ));
+       if (ret) {
+          fprintf(stderr, "drmMgaSetFence: %d\n", ret);
+           exit(1);
+       }
+
+       if ( curr_fence ) {
+           *curr_fence = temp;
+       }
+    }
+
+    return ret;
+}
+
+
 static void mga_iload_dma_ioctl(mgaContextPtr mmesa,
                                unsigned long dest,
                                int length)
@@ -294,58 +337,64 @@ mgaClear( GLcontext *ctx, GLbitfield mask, GLboolean all,
  * \bug
  * The loop in this function should have some sort of a timeout mechanism.
  *
- * \todo
- * This routine should be modified to wait on a semaphore.  To do this,
- * the DRM would have to queue an interrupt when the swap command was
- * put in the DMA buffer.  When the interrupt occured, the DRM would UP
- * the semaphore.  This function would then just DOWN the semaphore.
+ * \warning
+ * This routine used to assume that the hardware lock was held on entry.  It
+ * now assumes that the lock is \b not held on entry.
  */
 
 static void mgaWaitForFrameCompletion( mgaContextPtr mmesa )
 {
-   unsigned wait = 0;
-   const GLuint last_frame = mmesa->sarea->last_frame.head;
-   const GLuint last_wrap = mmesa->sarea->last_frame.wrap;
-
-
-   /* The DMA routines in the kernel track a couple values in the SAREA that
-    * we use here.  The number of times that the primary DMA buffer has
-    * "wrapped" around is tracked in last_wrap.  In addition, the wrap count
-    * and the buffer position at the end of the last frame are stored in
-    * last_frame.wrap and last_frame.head.
-    * 
-    * By comparing the wrap counts and the current DMA pointer value (read
-    * directly from the hardware) to last_frame.head, we can determine when
-    * the graphics processor has processed all of the commands for the last
-    * frame.
-    * 
-    * In this case "last frame" means the frame of the *previous* swap-
-    * buffers call.  This is done to prevent queuing a second buffer swap
-    * before the previous swap is executed.
-    */
-   while ( 1 ) {
-      if ( last_wrap < mmesa->sarea->last_wrap ||
-          ( last_wrap == mmesa->sarea->last_wrap &&
-            last_frame <= (MGA_READ( MGAREG_PRIMADDRESS ) -
-                           mmesa->primary_offset) ) ) {
-        break;
-      }
-      if ( 0 ) {
-        wait++;
-        fprintf( stderr, "   last: head=0x%06x wrap=%d\n",
-                 last_frame, last_wrap );
-        fprintf( stderr, "   head: head=0x%06lx wrap=%d\n",
-                 (long)(MGA_READ( MGAREG_PRIMADDRESS ) - mmesa->primary_offset),
-                 mmesa->sarea->last_wrap );
-      }
-      UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH );
+    if ( mgaWaitFence( mmesa, mmesa->last_frame_fence, NULL ) == ENOSYS ) {
+       unsigned wait = 0;
+       GLuint last_frame;
+       GLuint last_wrap;
+
+
+       LOCK_HARDWARE( mmesa );
+       last_frame = mmesa->sarea->last_frame.head;
+       last_wrap = mmesa->sarea->last_frame.wrap;
+
+       /* The DMA routines in the kernel track a couple values in the SAREA
+        * that we use here.  The number of times that the primary DMA buffer
+        * has "wrapped" around is tracked in last_wrap.  In addition, the
+        * wrap count and the buffer position at the end of the last frame are
+        * stored in last_frame.wrap and last_frame.head.
+        * 
+        * By comparing the wrap counts and the current DMA pointer value
+        * (read directly from the hardware) to last_frame.head, we can
+        * determine when the graphics processor has processed all of the
+        * commands for the last frame.
+        * 
+        * In this case "last frame" means the frame of the *previous* swap-
+        * buffers call.  This is done to prevent queuing a second buffer swap
+        * before the previous swap is executed.
+        */
+       while ( 1 ) {
+           if ( last_wrap < mmesa->sarea->last_wrap ||
+                ( last_wrap == mmesa->sarea->last_wrap &&
+                  last_frame <= (MGA_READ( MGAREG_PRIMADDRESS ) -
+                                 mmesa->primary_offset) ) ) {
+               break;
+           }
+           if ( 0 ) {
+               wait++;
+               fprintf( stderr, "   last: head=0x%06x wrap=%d\n",
+                        last_frame, last_wrap );
+               fprintf( stderr, "   head: head=0x%06lx wrap=%d\n",
+                        (long)(MGA_READ( MGAREG_PRIMADDRESS ) - mmesa->primary_offset),
+                        mmesa->sarea->last_wrap );
+           }
+           UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH );
 
-      UNLOCK_HARDWARE( mmesa );
-      DO_USLEEP( 1 );
-      LOCK_HARDWARE( mmesa );
-   }
-   if ( wait )
-      fprintf( stderr, "\n" );
+           UNLOCK_HARDWARE( mmesa );
+           DO_USLEEP( 1 );
+           LOCK_HARDWARE( mmesa );
+       }
+       if ( wait )
+         fprintf( stderr, "\n" );
+
+       UNLOCK_HARDWARE( mmesa );
+    }
 }
 
 
@@ -370,9 +419,7 @@ void mgaCopyBuffer( const __DRIdrawablePrivate *dPriv )
 
    FLUSH_BATCH( mmesa );
 
-   LOCK_HARDWARE( mmesa );
    mgaWaitForFrameCompletion( mmesa );
-   UNLOCK_HARDWARE( mmesa );
    driWaitForVBlank( dPriv, & mmesa->vbl_seq, mmesa->vblank_flags,
                     & missed_target );
    if ( missed_target ) {
@@ -410,6 +457,7 @@ void mgaCopyBuffer( const __DRIdrawablePrivate *dPriv )
       }
    }
 
+   (void) mgaSetFence( mmesa, & mmesa->last_frame_fence );
    UNLOCK_HARDWARE( mmesa );
 
    mmesa->dirty |= MGA_UPLOAD_CLIPRECTS;
@@ -425,17 +473,12 @@ void mgaCopyBuffer( const __DRIdrawablePrivate *dPriv )
  * 
  * \param ctx  Context where the \c glFinish command was issued.
  *
- * \todo
- * This is overkill.  The lock, update-lock, unlock sequence grabs the
- * hardware, waits for \b all hardware activity to finish, then releases the
- * hardware.  A better way would be to flush the pending DMA buffers, emit
- * a SOFTRAP, and wait for the SOFTRAP.
- *
  * \sa glFinish, mgaFlush, mgaFlushDMA
  */
 static void mgaFinish( GLcontext *ctx  )
 {
     mgaContextPtr mmesa = MGA_CONTEXT(ctx);
+    uint32_t  fence;
 
 
     LOCK_HARDWARE( mmesa );
@@ -443,12 +486,18 @@ static void mgaFinish( GLcontext *ctx  )
        mgaFlushVerticesLocked( mmesa );
     }
 
-    if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) {
-       fprintf(stderr, "mgaRegetLockQuiescent\n");
+    if ( mgaSetFence( mmesa, & fence ) == 0 ) {
+       UNLOCK_HARDWARE( mmesa );
+       (void) mgaWaitFence( mmesa, fence, NULL );
     }
+    else {
+       if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) {
+           fprintf(stderr, "mgaRegetLockQuiescent\n");
+       }
 
-    UPDATE_LOCK( mmesa, DRM_LOCK_QUIESCENT | DRM_LOCK_FLUSH );
-    UNLOCK_HARDWARE( mmesa );
+       UPDATE_LOCK( mmesa, DRM_LOCK_QUIESCENT | DRM_LOCK_FLUSH );
+       UNLOCK_HARDWARE( mmesa );
+    }
 }