Hi!

Attached is a patch tha provides a solution to the problem that the hardware lock needs to be shared by all screens on the same entity (device) which will hopefully make it possible to enable DRI on all screens of a entity:

I'd like some comments on the general approach before proceeding:

1) A function DRIOpenDRMMaster is added. It is called during DRIScreenInit and sets up an entity private structure and opens up the drm master file descriptor. That file descriptor, together with the SAREA containing the heavyweight lock is stored in the entity private structure.

If the function hits an -EPERM while trying to do some master-specific stuff, it indicates that another master is busy with the DRM. (I've seen this happen if a previous X server has been killed, and DRM is still doing cleanup). DRIOpenDRMMaster will then back off and retry master opening for 1 sec, to give any previous server time to clean up.

DRIOpenDRMMaster can also be called manually at X server preinit stage to have a working DRM connection to initialize the memory manager, or to determine DRM available earlier than screeninit.

If it's called again after a successful return it will just return success. This will happen if it has been called during preinit or by a previous screeninit.

Unfortunately, there's currently no way to clean up the entity-private resources at X server exit. DRM will then do the kernel resource cleanup for the X server.

2) DRIScreenInit will reuse the master file descriptor and, if so indicated by a new flag in the DRIInfo structure, will use the entity private SAREA also for drawable information and the drawable spinlock for the first screen opened. (This is the case of all current OS drivers). Subsequent screens will allocate an SAREA of their own for drawable information and -spinlock, and it's possible to have the first screen do that as well. However, all screens will point the heavyweight lock to the entity-private SAREA.

3) For new implementations, a possible use of the entity-private SAREA is to implement more drm-type locks for a more efficient locking scheme, for example a 2D-engine lock, a 3D engine lock, an MPEG engine lock etc.

4) On the Mesa DRI side, the changes will be minimal. One needs to add a lock-SAREA member to the screen-private structure, and make the hw-lock utility functions use this SAREA instead of the drawable SAREA. Initially the SAREA pointers will be set up to point at the same sarea, which will guarantee full backwards compatibility. This can be changed by the drivers.

5) AFAICT there are no changes needed for DRM. For the hardware lock, DRM will find the correct sarea, and it appears not to be using the SAREA drawable information.

Comments / Opinions appreciated.

/Thomas




diff --git a/hw/xfree86/dri/dri.c b/hw/xfree86/dri/dri.c
index 7bd07c0..3185dc9 100644
--- a/hw/xfree86/dri/dri.c
+++ b/hw/xfree86/dri/dri.c
@@ -43,6 +43,7 @@ #include <unistd.h>
 #include <string.h>
 #include <stdio.h>
 #include <sys/ioctl.h>
+#include <errno.h>
 
 #define NEED_REPLIES
 #define NEED_EVENTS
@@ -77,6 +78,7 @@ #if !defined(PANORAMIX)
 extern Bool noPanoramiXExtension;
 #endif
 
+static int DRIEntPrivIndex = -1;
 static int DRIScreenPrivIndex = -1;
 static int DRIWindowPrivIndex = -1;
 static unsigned long DRIGeneration = 0;
@@ -112,18 +114,200 @@ DRIDrvMsg(int scrnIndex, MessageType typ
 }
 
 
+static void 
+DRIOpenDRMCleanup(DRIEntPrivPtr pDRIEntPriv)
+{
+    if (pDRIEntPriv->pLSAREA != NULL) {
+       drmUnmap(pDRIEntPriv->pLSAREA, pDRIEntPriv->sAreaSize);
+       pDRIEntPriv->pLSAREA = NULL;
+    }
+    if (pDRIEntPriv->hLSAREA != 0) {
+       drmRmMap(pDRIEntPriv->drmFD, pDRIEntPriv->hLSAREA);
+    }
+    if (pDRIEntPriv->drmFD >= 0) {
+       drmClose(pDRIEntPriv->drmFD);
+       pDRIEntPriv->drmFD = 0;
+    }
+}
+
+int
+DRIMasterFD(ScrnInfoPtr pScrn) 
+{
+    return DRI_ENT_PRIV(pScrn)->drmFD;
+}
+
+XF86DRILSAREAPtr
+DRIMasterSareaPointer(ScrnInfoPtr pScrn)
+{
+    return DRI_ENT_PRIV(pScrn)->pLSAREA;
+}
+
+drm_handle_t
+DRIMasterSareaHandle(ScrnInfoPtr pScrn)
+{
+    return DRI_ENT_PRIV(pScrn)->hLSAREA;
+}
+                  
+
+Bool 
+DRIOpenDRMMaster(ScrnInfoPtr pScrn, 
+                unsigned long sAreaSize,
+                const char *busID, 
+                const char *drmDriverName)
+{
+    drmSetVersion saveSv, sv;
+    Bool drmWasAvailable;
+    DRIEntPrivPtr pDRIEntPriv;
+    DRIEntPrivRec tmp;
+    drmVersionPtr drmlibv;
+    int drmlibmajor, drmlibminor;
+    const char *openBusID;
+    int count;
+    int err;
+
+    if (DRIEntPrivIndex == -1)
+       DRIEntPrivIndex = xf86AllocateEntityPrivateIndex();
+       
+    pDRIEntPriv = DRI_ENT_PRIV(pScrn);
+    if (pDRIEntPriv) 
+       return TRUE;
+    
+    drmWasAvailable = drmAvailable();
+
+    memset(&tmp, 0, sizeof(tmp));
+
+    /* Check the DRM lib version.
+     * drmGetLibVersion was not supported in version 1.0, so check for
+     * symbol first to avoid possible crash or hang.
+     */
+
+    drmlibmajor = 1;
+    drmlibminor = 0;
+    if (xf86LoaderCheckSymbol("drmGetLibVersion")) {
+       drmlibv = drmGetLibVersion(-1);
+       if (drmlibv != NULL) {
+           drmlibmajor = drmlibv->version_major;
+           drmlibminor = drmlibv->version_minor;
+           drmFreeVersion(drmlibv);
+       }
+    }
+
+    /* Check if the libdrm can handle falling back to loading based on name
+     * if a busid string is passed.
+     */
+    openBusID = (drmlibmajor == 1 && drmlibminor >= 2) ? busID : NULL;
+
+    tmp.drmFD = -1;
+    sv.drm_di_major = 1;
+    sv.drm_di_minor = 1;
+    sv.drm_dd_major = -1;
+    
+    saveSv = sv;
+    count = 10;
+    while (count--) {
+       tmp.drmFD = drmOpen(drmDriverName, openBusID);
+       
+       if (tmp.drmFD < 0) {
+           DRIDrvMsg(-1, X_ERROR, "[drm] drmOpen failed.\n");
+           goto out_err;
+       }
+       
+       err = drmSetInterfaceVersion(tmp.drmFD, &sv);
+
+       if (err != -EPERM) 
+           break;
+
+       sv = saveSv;
+       drmClose(tmp.drmFD);
+       tmp.drmFD = -1;
+       usleep(100000);
+    }
+
+    if (tmp.drmFD <= 0) {
+       DRIDrvMsg(-1, X_ERROR, "[drm] DRM was busy with another master.\n");
+       goto out_err;
+    }
+       
+    if (!drmWasAvailable) {
+       DRIDrvMsg(-1, X_INFO,
+                 "[drm] loaded kernel module for \"%s\" driver.\n",
+                 drmDriverName);
+    }
+
+    if (err != 0) {
+       sv.drm_di_major = 1;
+       sv.drm_di_minor = 0;
+    }
+
+    DRIDrvMsg(-1, X_INFO, "[drm] DRM interface version %d.%d\n", 
+             sv.drm_di_major, sv.drm_di_minor);
+
+    if (sv.drm_di_major == 1 && sv.drm_di_minor >= 1)
+       err = 0;
+    else
+       err = drmSetBusid(tmp.drmFD, busID);
+       
+    if (err) {
+       DRIDrvMsg(-1, X_ERROR, "[drm] Could not set DRM device bus ID.\n");
+       goto out_err;
+    } 
+    
+    /*
+     * Create a lock-containing sarea.
+     */
+
+    if (drmAddMap( tmp.drmFD, 0, sAreaSize, DRM_SHM,
+                  DRM_CONTAINS_LOCK, &tmp.hLSAREA) < 0) {
+        DRIDrvMsg(-1, X_INFO, "[drm] Could not create SAREA for DRM lock.\n");
+       tmp.hLSAREA = 0;
+       goto out_err;
+    }
+
+    if (drmMap( tmp.drmFD, tmp.hLSAREA, sAreaSize, 
+               (drmAddressPtr)(&tmp.pLSAREA)) < 0) {
+        DRIDrvMsg(-1, X_INFO, "[drm] Mapping SAREA for DRM lock failed.\n");
+       tmp.pLSAREA = NULL;
+       goto out_err;
+    }
+
+    memset(tmp.pLSAREA, 0, sAreaSize);
+
+    /*
+     * Reserved contexts are handled by the first opened screen.
+     */
+
+    tmp.resOwner = NULL;
+
+    pDRIEntPriv = xnfcalloc(sizeof(*pDRIEntPriv), 1);
+    if (!pDRIEntPriv) {
+        DRIDrvMsg(-1, X_INFO, "[drm] Failed to allocate memory for "
+                 "DRM device.\n");
+       goto out_err;
+    }
+    *pDRIEntPriv = tmp;
+    xf86GetEntityPrivate((pScrn)->entityList[0],DRIEntPrivIndex)->ptr =
+       pDRIEntPriv;
+    
+    DRIDrvMsg(-1, X_INFO, "[drm] DRM open master succeeded.\n");
+    return TRUE;
+
+  out_err:
+
+    DRIOpenDRMCleanup(&tmp);
+    return FALSE;
+}
+
+
 Bool
 DRIScreenInit(ScreenPtr pScreen, DRIInfoPtr pDRIInfo, int *pDRMFD)
 {
     DRIScreenPrivPtr    pDRIPriv;
     drm_context_t *       reserved;
     int                 reserved_count;
-    int                 i, fd, drmWasAvailable;
+    int                 i;
     Bool                xineramaInCore = FALSE;
-    int                 err = 0;
-    char                *openbusid;
-    drmVersionPtr       drmlibv;
-    int                 drmlibmajor, drmlibminor, drmdimajor, drmdiminor;
+    DRIEntPrivPtr       pDRIEntPriv;
+    ScrnInfoPtr         pScrn = xf86Screens[pScreen->myNum];
 
     if (DRIGeneration != serverGeneration) {
        if ((DRIScreenPrivIndex = AllocateScreenPrivateIndex()) < 0)
@@ -153,48 +337,13 @@ DRIScreenInit(ScreenPtr pScreen, DRIInfo
        }
     }
 
-    drmWasAvailable = drmAvailable();
-
-    /* Check the DRM lib version.
-     * drmGetLibVersion was not supported in version 1.0, so check for
-     * symbol first to avoid possible crash or hang.
-     */
-    drmlibmajor = 1;
-    drmlibminor = 0;
-    if (xf86LoaderCheckSymbol("drmGetLibVersion")) {
-       drmlibv = drmGetLibVersion(-1);
-       if (drmlibv != NULL) {
-           drmlibmajor = drmlibv->version_major;
-           drmlibminor = drmlibv->version_minor;
-           drmFreeVersion(drmlibv);
-       }
-    }
-
-    /* Check if the libdrm can handle falling back to loading based on name
-     * if a busid string is passed.
-     */
-    if (drmlibmajor == 1 && drmlibminor >= 2)
-       openbusid = pDRIInfo->busIdString;
-    else
-       openbusid = NULL;
-
-    /* Note that drmOpen will try to load the kernel module, if needed. */
-    fd = drmOpen(pDRIInfo->drmDriverName, openbusid);
-    if (fd < 0) {
-        /* failed to open DRM */
-        pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL;
-        DRIDrvMsg(pScreen->myNum, X_INFO,
-                  "[drm] drmOpen failed\n");
-        return FALSE;
-    }
-
-    if (!drmWasAvailable) {
-       /* drmOpen loaded the kernel module, print a message to say so */
-       DRIDrvMsg(pScreen->myNum, X_INFO,
-                 "[drm] loaded kernel module for \"%s\" driver\n",
-                 pDRIInfo->drmDriverName);
-    }
-
+    if (!DRIOpenDRMMaster(pScrn, pDRIInfo->SAREASize,
+                         pDRIInfo->busIdString,
+                         pDRIInfo->drmDriverName))
+       return FALSE;
+   
+    pDRIEntPriv = DRI_ENT_PRIV(pScrn); 
+    
     pDRIPriv = (DRIScreenPrivPtr) xcalloc(1, sizeof(DRIScreenPrivRec));
     if (!pDRIPriv) {
         pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL;
@@ -202,7 +351,7 @@ DRIScreenInit(ScreenPtr pScreen, DRIInfo
     }
 
     pScreen->devPrivates[DRIScreenPrivIndex].ptr = (pointer) pDRIPriv;
-    pDRIPriv->drmFD = fd;
+    pDRIPriv->drmFD = pDRIEntPriv->drmFD;
     pDRIPriv->directRenderingSupport = TRUE;
     pDRIPriv->pDriverInfo = pDRIInfo;
     pDRIPriv->nrWindows = 0;
@@ -214,89 +363,54 @@ DRIScreenInit(ScreenPtr pScreen, DRIInfo
 
     pDRIPriv->grabbedDRILock = FALSE;
     pDRIPriv->drmSIGIOHandlerInstalled = FALSE;
-
-    if (drmlibmajor == 1 && drmlibminor >= 2) {
-       drmSetVersion sv;
-
-       /* Get the interface version, asking for 1.1. */
-       sv.drm_di_major = 1;
-       sv.drm_di_minor = 1;
-       sv.drm_dd_major = -1;
-       err = drmSetInterfaceVersion(pDRIPriv->drmFD, &sv);
-       if (err == 0) {
-           drmdimajor = sv.drm_di_major;
-           drmdiminor = sv.drm_di_minor;
-       } else {
-           /* failure, so set it to 1.0.0. */
-           drmdimajor = 1;
-           drmdiminor = 0;
-       }
-    }
-    else {
-       /* We can't check the DI DRM interface version, so set it to 1.0.0. */
-       drmdimajor = 1;
-       drmdiminor = 0;
-    }
-    DRIDrvMsg(pScreen->myNum, X_INFO,
-              "[drm] DRM interface version %d.%d\n", drmdimajor, drmdiminor);
-
-    /* If the interface minor number is 1.1, then we've opened a DRM device
-     * that already had the busid set through drmOpen.
-     */
-    if (drmdimajor == 1 && drmdiminor >= 1)
-       err = 0;
-    else
-       err = drmSetBusid(pDRIPriv->drmFD, pDRIPriv->pDriverInfo->busIdString);
-
-    if (err < 0) {
-       pDRIPriv->directRenderingSupport = FALSE;
-       pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL;
-       drmClose(pDRIPriv->drmFD);
-        DRIDrvMsg(pScreen->myNum, X_INFO,
-                  "[drm] drmSetBusid failed (%d, %s), %s\n",
-                  pDRIPriv->drmFD, pDRIPriv->pDriverInfo->busIdString, 
strerror(-err));
-       return FALSE;
-    }
-
     *pDRMFD = pDRIPriv->drmFD;
-    DRIDrvMsg(pScreen->myNum, X_INFO,
-             "[drm] created \"%s\" driver at busid \"%s\"\n",
-             pDRIPriv->pDriverInfo->drmDriverName,
-             pDRIPriv->pDriverInfo->busIdString);
 
-    if (drmAddMap( pDRIPriv->drmFD,
-                  0,
-                  pDRIPriv->pDriverInfo->SAREASize,
-                  DRM_SHM,
-                  DRM_CONTAINS_LOCK,
-                  &pDRIPriv->hSAREA) < 0)
-    {
-       pDRIPriv->directRenderingSupport = FALSE;
-       pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL;
-       drmClose(pDRIPriv->drmFD);
-        DRIDrvMsg(pScreen->myNum, X_INFO,
-                  "[drm] drmAddMap failed\n");
-       return FALSE;
+    if (pDRIEntPriv->sAreaGrabbed || pDRIInfo->allocSarea) {
+
+       if (drmAddMap( pDRIPriv->drmFD,
+                      0,
+                      pDRIPriv->pDriverInfo->SAREASize,
+                      DRM_SHM,
+                      0,
+                      &pDRIPriv->hSAREA) < 0)
+       {
+           pDRIPriv->directRenderingSupport = FALSE;
+           pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL;
+           drmClose(pDRIPriv->drmFD);
+           DRIDrvMsg(pScreen->myNum, X_INFO,
+                     "[drm] drmAddMap failed\n");
+           return FALSE;
+       }
+       DRIDrvMsg(pScreen->myNum, X_INFO,
+                 "[drm] added %d byte SAREA at %p\n",
+                 pDRIPriv->pDriverInfo->SAREASize, pDRIPriv->hSAREA);
+
+       /* Backwards compat. */
+       if (drmMap( pDRIPriv->drmFD,
+                   pDRIPriv->hSAREA,
+                   pDRIPriv->pDriverInfo->SAREASize,
+                   (drmAddressPtr)(&pDRIPriv->pSAREA)) < 0)
+       {
+           pDRIPriv->directRenderingSupport = FALSE;
+           pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL;
+           drmClose(pDRIPriv->drmFD);
+           DRIDrvMsg(pScreen->myNum, X_INFO,
+                     "[drm] drmMap failed\n");
+           return FALSE;
+       }
+       DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] mapped SAREA %p to %p\n",
+                 pDRIPriv->hSAREA, pDRIPriv->pSAREA);
+       memset(pDRIPriv->pSAREA, 0, pDRIPriv->pDriverInfo->SAREASize);
+    } else {
+       DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] Using the DRM lock "
+                 "SAREA also for drawables.\n");
+       pDRIPriv->hSAREA = pDRIEntPriv->hLSAREA;
+       pDRIPriv->pSAREA = (XF86DRISAREAPtr) pDRIEntPriv->pLSAREA;
+       pDRIEntPriv->sAreaGrabbed = TRUE;
     }
-    DRIDrvMsg(pScreen->myNum, X_INFO,
-             "[drm] added %d byte SAREA at %p\n",
-             pDRIPriv->pDriverInfo->SAREASize, pDRIPriv->hSAREA);
 
-    if (drmMap( pDRIPriv->drmFD,
-               pDRIPriv->hSAREA,
-               pDRIPriv->pDriverInfo->SAREASize,
-               (drmAddressPtr)(&pDRIPriv->pSAREA)) < 0)
-    {
-       pDRIPriv->directRenderingSupport = FALSE;
-       pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL;
-       drmClose(pDRIPriv->drmFD);
-        DRIDrvMsg(pScreen->myNum, X_INFO,
-                  "[drm] drmMap failed\n");
-       return FALSE;
-    }
-    memset(pDRIPriv->pSAREA, 0, pDRIPriv->pDriverInfo->SAREASize);
-    DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] mapped SAREA %p to %p\n",
-             pDRIPriv->hSAREA, pDRIPriv->pSAREA);
+    pDRIPriv->hLSAREA = pDRIEntPriv->hLSAREA;
+    pDRIPriv->pLSAREA = pDRIEntPriv->pLSAREA;
 
     if (drmAddMap( pDRIPriv->drmFD,
                   
(drm_handle_t)pDRIPriv->pDriverInfo->frameBufferPhysicalAddress,
@@ -316,22 +430,26 @@ DRIScreenInit(ScreenPtr pScreen, DRIInfo
     DRIDrvMsg(pScreen->myNum, X_INFO, "[drm] framebuffer handle = %p\n",
              pDRIPriv->hFrameBuffer);
 
-                               /* Add tags for reserved contexts */
-    if ((reserved = drmGetReservedContextList(pDRIPriv->drmFD,
-                                             &reserved_count))) {
-       int  i;
-       void *tag;
-
-       for (i = 0; i < reserved_count; i++) {
-           tag = DRICreateContextPrivFromHandle(pScreen,
-                                                reserved[i],
-                                                DRI_CONTEXT_RESERVED);
-           drmAddContextTag(pDRIPriv->drmFD, reserved[i], tag);
+    if (pDRIEntPriv->resOwner == NULL) {
+       pDRIEntPriv->resOwner = pScreen;
+
+       /* Add tags for reserved contexts */
+       if ((reserved = drmGetReservedContextList(pDRIPriv->drmFD,
+                                                 &reserved_count))) {
+           int  i;
+           void *tag;
+           
+           for (i = 0; i < reserved_count; i++) {
+               tag = DRICreateContextPrivFromHandle(pScreen,
+                                                    reserved[i],
+                                                    DRI_CONTEXT_RESERVED);
+               drmAddContextTag(pDRIPriv->drmFD, reserved[i], tag);
+           }
+           drmFreeReservedContextList(reserved);
+           DRIDrvMsg(pScreen->myNum, X_INFO,
+                     "[drm] added %d reserved context%s for kernel\n",
+                     reserved_count, reserved_count > 1 ? "s" : "");
        }
-       drmFreeReservedContextList(reserved);
-       DRIDrvMsg(pScreen->myNum, X_INFO,
-                 "[drm] added %d reserved context%s for kernel\n",
-                 reserved_count, reserved_count > 1 ? "s" : "");
     }
 
     /* validate max drawable table entry set by driver */
@@ -349,6 +467,9 @@ DRIScreenInit(ScreenPtr pScreen, DRIInfo
        pDRIPriv->pSAREA->drawableTable[i].flags = 0;
     }
 
+    pDRIPriv->pLockRefCount = &pDRIEntPriv->lockRefCount;
+    pDRIPriv->pLockingContext = &pDRIEntPriv->lockingContext;
+
     return TRUE;
 }
 
@@ -490,6 +611,8 @@ DRICloseScreen(ScreenPtr pScreen)
     DRIInfoPtr       pDRIInfo;
     drm_context_t *    reserved;
     int              reserved_count;
+    ScrnInfoPtr      pScrn = xf86Screens[pScreen->myNum];
+    DRIEntPrivPtr    pDRIEntPriv = DRI_ENT_PRIV(pScrn);
 
     if (pDRIPriv && pDRIPriv->directRenderingSupport) {
 
@@ -542,38 +665,47 @@ DRICloseScreen(ScreenPtr pScreen)
        }
 
                                /* Remove tags for reserved contexts */
-       if ((reserved = drmGetReservedContextList(pDRIPriv->drmFD,
+       if (pDRIEntPriv->resOwner == pScreen) {
+           pDRIEntPriv->resOwner = NULL;
+
+           if ((reserved = drmGetReservedContextList(pDRIPriv->drmFD,
                                                  &reserved_count))) {
-           int  i;
+               int  i;
 
-           for (i = 0; i < reserved_count; i++) {
-               DRIDestroyContextPriv(drmGetContextTag(pDRIPriv->drmFD,
-                                                      reserved[i]));
+               for (i = 0; i < reserved_count; i++) {
+                   DRIDestroyContextPriv(drmGetContextTag(pDRIPriv->drmFD,
+                                                          reserved[i]));
+               }
+               drmFreeReservedContextList(reserved);
+               DRIDrvMsg(pScreen->myNum, X_INFO,
+                         "[drm] removed %d reserved context%s for kernel\n",
+                         reserved_count, reserved_count > 1 ? "s" : "");
            }
-           drmFreeReservedContextList(reserved);
-           DRIDrvMsg(pScreen->myNum, X_INFO,
-                     "[drm] removed %d reserved context%s for kernel\n",
-                     reserved_count, reserved_count > 1 ? "s" : "");
        }
 
        /* Make sure signals get unblocked etc. */
        drmUnlock(pDRIPriv->drmFD, pDRIPriv->myContext);
-       pDRIPriv->lockRefCount = 0;
-       DRIDrvMsg(pScreen->myNum, X_INFO,
-                 "[drm] unmapping %d bytes of SAREA %p at %p\n",
-                 pDRIInfo->SAREASize,
-                 pDRIPriv->hSAREA,
-                 pDRIPriv->pSAREA);
-       if (drmUnmap(pDRIPriv->pSAREA, pDRIInfo->SAREASize)) {
-           DRIDrvMsg(pScreen->myNum, X_ERROR,
-                     "[drm] unable to unmap %d bytes"
-                     " of SAREA %p at %p\n",
+       pDRIPriv->pLockRefCount = NULL;
+       if (pDRIPriv->hSAREA != pDRIEntPriv->hLSAREA) {
+           DRIDrvMsg(pScreen->myNum, X_INFO,
+                     "[drm] unmapping %d bytes of SAREA %p at %p\n",
                      pDRIInfo->SAREASize,
                      pDRIPriv->hSAREA,
                      pDRIPriv->pSAREA);
+           if (drmUnmap(pDRIPriv->pSAREA, pDRIInfo->SAREASize)) {
+               DRIDrvMsg(pScreen->myNum, X_ERROR,
+                         "[drm] unable to unmap %d bytes"
+                         " of SAREA %p at %p\n",
+                         pDRIInfo->SAREASize,
+                         pDRIPriv->hSAREA,
+                         pDRIPriv->pSAREA);
+           }
+       } else {
+           pDRIEntPriv->sAreaGrabbed = FALSE;
        }
 
-       drmClose(pDRIPriv->drmFD);
+       if (pDRIEntPriv->drmFD != pDRIPriv->drmFD)
+           drmClose(pDRIPriv->drmFD);
 
        xfree(pDRIPriv);
        pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL;
@@ -2001,28 +2133,46 @@ void
 DRILock(ScreenPtr pScreen, int flags)
 {
     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
-    if(!pDRIPriv) return;
 
-    if (!pDRIPriv->lockRefCount)
-        DRM_LOCK(pDRIPriv->drmFD, pDRIPriv->pSAREA, pDRIPriv->myContext, 
flags);
-    pDRIPriv->lockRefCount++;
+    if(!pDRIPriv || !pDRIPriv->pLockRefCount) return;
+
+    if (!*pDRIPriv->pLockRefCount) {
+        DRM_LOCK(pDRIPriv->drmFD, pDRIPriv->pLSAREA, pDRIPriv->myContext, 
flags);
+       *pDRIPriv->pLockingContext = pDRIPriv->myContext;
+    } else if (*pDRIPriv->pLockingContext != pDRIPriv->myContext) {
+       DRIDrvMsg(pScreen->myNum, X_ERROR, 
+                 "[DRI] Locking deadlock.\n"
+                 "\tAlready locked with context %d,\n"
+                 "\ttrying to lock with context %d.\n",
+                 pDRIPriv->pLockingContext,
+                 pDRIPriv->myContext);
+    }  
+    (*pDRIPriv->pLockRefCount)++;
 }
 
 void
 DRIUnlock(ScreenPtr pScreen)
 {
     DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen);
-    if(!pDRIPriv) return;
 
-    if (pDRIPriv->lockRefCount > 0) {
-        pDRIPriv->lockRefCount--;
-    }
-    else {
-        ErrorF("DRIUnlock called when not locked\n");
+    if(!pDRIPriv || !pDRIPriv->pLockRefCount) return;
+
+    if (*pDRIPriv->pLockRefCount > 0) {
+       if (pDRIPriv->myContext != *pDRIPriv->pLockingContext) {
+           DRIDrvMsg(pScreen->myNum, X_ERROR, 
+                     "[DRI] Unlocking inconsistency:\n"
+                     "\tContext %d trying to unlock lock held by context %d\n",
+                     pDRIPriv->pLockingContext,
+                     pDRIPriv->myContext);
+       }           
+       (*pDRIPriv->pLockRefCount)--;
+    } else {
+        DRIDrvMsg(pScreen->myNum, X_ERROR, 
+                 "DRIUnlock called when not locked.\n");
         return;
     }
-    if (!pDRIPriv->lockRefCount)
-        DRM_UNLOCK(pDRIPriv->drmFD, pDRIPriv->pSAREA, pDRIPriv->myContext);
+    if (! *pDRIPriv->pLockRefCount)
+        DRM_UNLOCK(pDRIPriv->drmFD, pDRIPriv->pLSAREA, pDRIPriv->myContext);
 }
 
 void *
diff --git a/hw/xfree86/dri/dri.h b/hw/xfree86/dri/dri.h
index f65c571..3fae026 100644
--- a/hw/xfree86/dri/dri.h
+++ b/hw/xfree86/dri/dri.h
@@ -107,7 +107,7 @@ typedef struct {
  */
 
 #define DRIINFO_MAJOR_VERSION   5
-#define DRIINFO_MINOR_VERSION   1
+#define DRIINFO_MINOR_VERSION   2
 #define DRIINFO_PATCH_VERSION   0
 
 typedef struct {
@@ -176,9 +176,16 @@ typedef struct {
 
     /* New with DRI version 5.1.0 */
     void        (*ClipNotify)(ScreenPtr pScreen, WindowPtr *ppWin, int num);
+
+    /* New with DRI version 5.2.0 */
+    Bool                allocSarea;
 } DRIInfoRec, *DRIInfoPtr;
 
 
+extern Bool DRIOpenDRMMaster(ScrnInfoPtr pScrn, unsigned long sAreaSize,
+                            const char *busID, 
+                            const char *drmDriverName);
+
 extern Bool DRIScreenInit(ScreenPtr pScreen,
                           DRIInfoPtr pDRIInfo,
                           int *pDRMFD);
diff --git a/hw/xfree86/dri/dristruct.h b/hw/xfree86/dri/dristruct.h
index 9c42ff9..2e3d9cd 100644
--- a/hw/xfree86/dri/dristruct.h
+++ b/hw/xfree86/dri/dristruct.h
@@ -73,6 +73,11 @@ #define DRI_SCREEN_PRIV(pScreen) \
 #define DRI_SCREEN_PRIV_FROM_INDEX(screenIndex) ((DRIScreenPrivPtr) \
     (screenInfo.screens[screenIndex]->devPrivates[DRIScreenPrivIndex].ptr))
 
+#define DRI_ENT_PRIV(pScrn)  \
+    ((DRIEntPrivIndex < 0) ? \
+     NULL:                  \
+     ((DRIEntPrivPtr)(xf86GetEntityPrivate((pScrn)->entityList[0], \
+                                          DRIEntPrivIndex)->ptr)))
 
 typedef struct _DRIScreenPrivRec
 {
@@ -103,6 +108,29 @@ typedef struct _DRIScreenPrivRec
     Bool               wrapped;
     Bool               windowsTouched;
     int                        lockRefCount;
+    drm_handle_t        hLSAREA;      /* Handle to SAREA containing lock, for 
mapping */
+    XF86DRILSAREAPtr    pLSAREA;      /* Mapped pointer to SAREA containing 
lock */
+    int*                pLockRefCount;
+    int*                pLockingContext;
 } DRIScreenPrivRec, *DRIScreenPrivPtr;
 
+
+typedef struct _DRIEntPrivRec {
+    int drmFD;
+    Bool drmOpened;
+    Bool sAreaGrabbed;
+    drm_handle_t hLSAREA;
+    XF86DRILSAREAPtr pLSAREA;
+    unsigned long sAreaSize;
+    int lockRefCount;
+    int lockingContext;
+    ScreenPtr resOwner;    
+} DRIEntPrivRec, *DRIEntPrivPtr;
+
+extern int DRIMasterFD(ScrnInfoPtr pScrn);
+ 
+extern XF86DRILSAREAPtr DRIMasterSareaPointer(ScrnInfoPtr pScrn);
+
+extern drm_handle_t DRIMasterSareaHandle(ScrnInfoPtr pScrn);
+
 #endif /* DRI_STRUCT_H */
diff --git a/hw/xfree86/dri/sarea.h b/hw/xfree86/dri/sarea.h
index a0d6084..996631c 100644
--- a/hw/xfree86/dri/sarea.h
+++ b/hw/xfree86/dri/sarea.h
@@ -89,4 +89,16 @@ typedef struct _XF86DRISAREA {
     drm_context_t                      dummy_context;
 } XF86DRISAREARec, *XF86DRISAREAPtr;
 
+typedef struct _XF86DRILSAREA  {
+    drmLock                     lock;
+    drmLock                     otherLocks[4096 / sizeof(drmLock) - 1];
+} XF86DRILSAREARec, *XF86DRILSAREAPtr;
+
+
+
+
+
+
+
+
 #endif
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
--
_______________________________________________
Dri-devel mailing list
Dri-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dri-devel

Reply via email to