NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

xsrc/48796: xf86-video-mga: bug with dual-head operations



>Number:         48796
>Category:       xsrc
>Synopsis:       xf86-video-mga: bug with dual-head operations
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    xsrc-manager
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri May 09 14:20:00 +0000 2014
>Originator:     Volkmar Seifert
>Release:        NetBSD 6.1_STABLE
>Organization:
>Environment:
NetBSD SnowLion.home.nifelheim.info 6.1_STABLE NetBSD 6.1_STABLE (GENERIC) #1: 
Fri May  9 12:48:47 CEST 2014  
mjoellnir@cheetah:/work/netbsd/v6/work/i386/GENERIC/obj/work/netbsd/v6/src/sys/arch/i386/compile/GENERIC
 i386

>Description:
The mga driver fails on dual head configurations with this error:

[  1099.472] (WW) MGA(0): Direct rendering disabled
[  1099.473] (EE) MGA(1): Unable to map BAR 0.  Invalid argument (22)
[  1099.473]
Fatal server error:
[  1099.473] AddScreen/ScreenInit failed for driver 1

This happens, because it tries to map the same PCI memory region twice.

The xorg.config looks like this (shortened to the relevant sections): 

Section "Monitor"
        Identifier "Monitor0"
        VendorName "Acer"
        ModelName  "V223HQ"
EndSection

Section "Monitor"
        Identifier "Monitor1"
        VendorName "Asus"
        ModelName  "V278"
EndSection

Section "Device"
        Identifier "Card0"
        Driver     "mga"
        #BusId      "PCI:1:0:0"
        Screen     0
EndSection

Section "Device"
        Identifier "Card1"
        Driver     "mga"
        #BusID      "PCI:1:0:0"
        Screen     1
EndSection

Section "Screen"
        Identifier   "Screen0"
        Device       "Card0"
        Monitor      "Monitor0"
        DefaultDepth 24
EndSection

Section "Screen"
        Identifier   "Screen1"
        Device       "Card1"
        Monitor      "Monitor1"
        DefaultDepth 24
EndSection

Section "ServerLayout"
        Identifier     "X.org Configured"
        InputDevice    "Mouse0" "CorePointer"
        InputDevice    "Keyboard0" "CoreKeyboard"
        Screen         "Screen0"
        Screen         "Screen1" RightOf "Screen0"
EndSection

Section "ServerFlags"
        Option "Xinerama"
EndSection

>How-To-Repeat:
Use a xorg.conf like the one above and an MGA card, call "startx" on cli, and 
there you go.
>Fix:
Following a few leads found via google, I found a patch that helped on Linux to 
get rid of the problem. I have applied that patch to our sources, and tested 
them on my system successfully. Using the xorg.conf above and the mga-driver 
starts a nice dual-headed system on which both screens are used for an extended 
display (meaning the output is not mirrored :) ). I have created this 
xsrc-specific patch, and would like to ask you to apply it to the repository, 
so that everyone can benefit from this:

? xf86-video-mga.patch
Index: mga.h
===================================================================
RCS file: /cvsroot/xsrc/external/mit/xf86-video-mga/dist/src/mga.h,v
retrieving revision 1.1.1.4
diff -u -r1.1.1.4 mga.h
--- mga.h       22 May 2010 10:09:00 -0000      1.1.1.4
+++ mga.h       9 May 2014 13:46:45 -0000
@@ -337,6 +337,10 @@
     int                        mastervideoRam;
     int                        slavevideoRam;
     Bool               directRenderingEnabled;
+    void  *            mappedIOBase;
+    int                        mappedIOUsage;
+    void  *            mappedILOADBase;
+    int                        mappedILOADUsage; 
     ScrnInfoPtr        pScrn_1;
     ScrnInfoPtr        pScrn_2;
 } MGAEntRec, *MGAEntPtr;
Index: mga_driver.c
===================================================================
RCS file: /cvsroot/xsrc/external/mit/xf86-video-mga/dist/src/mga_driver.c,v
retrieving revision 1.1.1.5
diff -u -r1.1.1.5 mga_driver.c
--- mga_driver.c        14 Aug 2010 08:33:53 -0000      1.1.1.5
+++ mga_driver.c        9 May 2014 13:46:45 -0000
@@ -2822,23 +2822,46 @@
 
     if (!pMga->FBDev) {
 #ifdef XSERVER_LIBPCIACCESS
-        memory[pMga->io_bar] = &pMga->IOBase;
-        memory[pMga->framebuffer_bar] = &pMga->FbBase;
+       pciaddr_t fbaddr = pMga->FbAddress;
+       pciaddr_t fbsize = pMga->FbMapSize;
+       err = pci_device_map_range(dev,
+                                  fbaddr, fbsize,
+                                  PCI_DEV_MAP_FLAG_WRITABLE,
+                                  (void **)&pMga->FbBase);
+       if (err) {
+         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+               "Unable to map Framebuffer %08llX %llx.  %s (%d)\n", (long 
long)fbaddr, (long long)fbsize,
+               strerror(err), err);
+         return FALSE;
+       }
+       else
+               xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+                       "MAPPED Framebuffer %08llX %llx to %08llX.\n", 
+                       (long long)fbaddr, (long long)fbsize, (long 
long)pMga->FbBase);
+
+       if(pMga->entityPrivate == NULL || pMga->entityPrivate->mappedIOUsage == 
0) {
+         region = &dev->regions[pMga->io_bar];
+         err = pci_device_map_range(dev,
+           region->base_addr, region->size,
+           PCI_DEV_MAP_FLAG_WRITABLE,
+           &pMga->IOBase);
+    
+         if (err) {
+           xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+             "Unable to map IO Region %i.  %s (%d)\n",
+           pMga->io_bar, strerror(err), err);
+           return FALSE;
+         }
 
-        for (i = 0; i < 2; i++) {
-            region = &dev->regions[i];
-            err = pci_device_map_range(dev,
-                                       region->base_addr, region->size,
-                                       PCI_DEV_MAP_FLAG_WRITABLE,
-                                       memory[i]);
+         if(pMga->entityPrivate != NULL) {
+           pMga->entityPrivate->mappedIOBase = pMga->IOBase;
+         }
+       }
+       else
+         pMga->IOBase = pMga->entityPrivate->mappedIOBase;
 
-            if (err) {
-                xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-                           "Unable to map BAR %i.  %s (%d)\n",
-                           i, strerror(err), err);
-                return FALSE;
-            }
-        }
+       if(pMga->entityPrivate != NULL)         
+         pMga->entityPrivate->mappedIOUsage ++;
 #else
        /*
         * For Alpha, we need to map SPARSE memory, since we need
@@ -2880,16 +2903,26 @@
     if (pMga->iload_bar != -1) {
 #ifdef XSERVER_LIBPCIACCESS
         region = &dev->regions[pMga->iload_bar];
-        err = pci_device_map_range(dev,
+        if(pMga->entityPrivate == NULL || 
pMga->entityPrivate->mappedILOADUsage == 0) { 
+               err = pci_device_map_range(dev,
                                    region->base_addr, region->size,
                                    PCI_DEV_MAP_FLAG_WRITABLE,
                                    (void *) &pMga->ILOADBase);
-       if (err) {
+         if (err) {
            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
                       "Unable to map BAR 2 (ILOAD region).  %s (%d)\n",
                       strerror(err), err);
            return FALSE;
+         }
+
+         if(pMga->entityPrivate != NULL)
+               pMga->entityPrivate->mappedILOADBase = pMga->ILOADBase;
        }
+       else
+         pMga->ILOADBase = pMga->entityPrivate->mappedILOADBase;
+
+       if(pMga->entityPrivate != NULL)
+         pMga->entityPrivate->mappedILOADUsage ++;
 #else
        pMga->ILOADBase = xf86MapPciMem(pScrn->scrnIndex,
                                        VIDMEM_MMIO | VIDMEM_MMIO_32BIT |
@@ -2919,10 +2952,19 @@
     
     if (!pMga->FBDev) {
 #ifdef XSERVER_LIBPCIACCESS
-        pci_device_unmap_range(dev, pMga->IOBase, 
-                              dev->regions[pMga->io_bar].size);
-        pci_device_unmap_range(dev, pMga->FbBase, 
-                              dev->regions[pMga->framebuffer_bar].size);
+       if(pMga->entityPrivate != NULL)
+         pMga->entityPrivate->mappedIOUsage --;
+       if(pMga->entityPrivate == NULL || pMga->entityPrivate->mappedIOUsage == 
0) {
+         pci_device_unmap_range(dev, pMga->IOBase,
+               dev->regions[pMga->io_bar].size);
+         if(pMga->entityPrivate != NULL)
+           pMga->entityPrivate->mappedIOBase = NULL;
+       }
+       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "UNMAPPING framebuffer 0x%08llX, 
0x%llX.\n", 
+               (long long)pMga->FbBase, (long long)pMga->FbMapSize);
+       
+       pci_device_unmap_range(dev, pMga->FbBase, 
+                              pMga->FbMapSize);
 #else
        xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pMga->IOBase, 0x4000);
        xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pMga->FbBase, 
pMga->FbMapSize);
@@ -2935,8 +2977,14 @@
 
     if ((pMga->iload_bar != -1) && (pMga->ILOADBase != NULL)) {
 #ifdef XSERVER_LIBPCIACCESS
-        pci_device_unmap_range(dev, pMga->ILOADBase,
+        if(pMga->entityPrivate != NULL) 
+         pMga->entityPrivate->mappedILOADUsage --;
+       if(pMga->entityPrivate == NULL || pMga->entityPrivate->mappedILOADUsage 
== 0) {
+         pci_device_unmap_range(dev, pMga->ILOADBase,
                               dev->regions[pMga->iload_bar].size);
+         if(pMga->entityPrivate != NULL)
+           pMga->entityPrivate->mappedILOADBase = NULL;
+       }
 #else
        xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pMga->ILOADBase, 0x800000);
 #endif



Home | Main Index | Thread Index | Old Index