Bug 116851 - x11-drivers/xf86-video-mga - Xorg 7.3 mga driver fails to read video BIOS (G450 dual-VGA)
Summary: x11-drivers/xf86-video-mga - Xorg 7.3 mga driver fails to read video BIOS (G4...
Status: Closed FIXED
Alias: None
Product: Ports & Packages
Classification: Unclassified
Component: Individual Port(s) (show other bugs)
Version: Latest
Hardware: Any Any
: Normal Affects Only Me
Assignee: freebsd-x11 (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2007-10-03 03:20 UTC by Warren Block
Modified: 2008-01-02 13:38 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Warren Block 2007-10-03 03:20:01 UTC
mga-1.4.7 fails to read the video BIOS of a Matrox G450 dual-VGA AGP card:

(--) MGA(0): Chipset: "mgag400" (G450)
(==) MGA(0): Depth 24, (==) framebuffer bpp 32
(==) MGA(0): RGB weight 888
(==) MGA(0): Using AGP 1x mode
(==) MGA(0): Using XAA acceleration
(--) MGA(0): Linear framebuffer at 0xDC000000
(==) MGA(0): MMIO registers at 0xDFEFC000
(--) MGA(0): Pseudo-DMA transfer window at 0xDF000000
(--) MGA(0): BIOS at 0xDFEC0000
Requesting insufficient memory window!: start: 0xdee00000 end: 0xdfefffff size 0x2000000
(EE) Cannot find empty range to map base to
(WW) MGA(0): Video BIOS info block not detected!

The driver still works, but without the BIOS, features of the card like more than one VGA port are not available.

The same computer running the 200709 snapshot of FreeBSD 7.0-CURRENT showed the same failure.

A Knoppix Linux liveCD with Xorg 7.2 on the same computer was able to read the BIOS:

(--) MGA(0): BIOS at 0xDFEC0000
(II) Attempted to read BIOS 64KB from /sys/bus/pci/devices/0000:01:00.0/rom: got 34KB
(--) MGA(0): Video BIOS info block at offset 0x07D00

From crude testing, it appears that the problem may be in the xorg-server freebsdPci.c routine (xorg-server-1.4/hw/xfree86/os-support/bus/freebsdPci.c)

Further information:

Excerpt from 'pciconf -lv':

agp0@pci0:0:0:  class=0x060000 card=0x00001106 chip=0x31891106 rev=0x80 hdr=0x00
    vendor     = 'VIA Technologies Inc'
    device     = 'VT8377 Apollo KT400/A/600 CPU to PCI Bridge'
    class      = bridge
    subclass   = HOST-PCI
pcib1@pci0:1:0: class=0x060400 card=0x00000000 chip=0xb1981106 rev=0x00 hdr=0x01
    vendor     = 'VIA Technologies Inc'
    device     = 'ProSavageDDR P4X600 CPU to AGP Bridge'
    class      = bridge
    subclass   = PCI-PCI
drm0@pci1:0:0:  class=0x030000 card=0x0641102b chip=0x0525102b rev=0x82 hdr=0x00
    vendor     = 'Matrox Electronic Systems Ltd.'
    device     = 'MGA G450 Dual Head Chip of G450 graphics card'
    class      = display
    subclass   = VGA

drm output on ttyv0:

drm0: <Matrox G400/G450 (AGP)> mem 0xdc000000-0xddffffff,0xdfefc000-0xdfefffff,0xdf000000-0xdf7fffff irq 16 at device 0.0 on pci1
info: [drm] AGP at 0xe0000000 128MB
info: [drm] Initialized mga 3.2.2 20060319
info: [drm] Initialized card for AGP DMA.

How-To-Repeat: Install Xorg 7.3 on FreeBSD computer with Matrox G450 card.
startx
Note 'Video BIOS info block not detected!' message in /var/log/Xorg.0.log.
Comment 1 Edwin Groothuis freebsd_committer 2007-10-03 04:38:57 UTC
Responsible Changed
From-To: freebsd-ports-bugs->freebsd-x11

Over to maintainer (via the GNATS Auto Assign Tool) 

http://www.freebsd.org/cgi/query-pr.cgi?pr=116851 

Adding to audit trail from misfiled PR ports/116915:
 
Date: Thu, 4 Oct 2007 10:16:28 -0600 (MDT)
Comment 2 c.angelini 2007-10-05 07:55:09 UTC
The same happens with G550:

(--) MGA(0): Chipset: "mgag550"
(**) MGA(0): Depth 24, (--) framebuffer bpp 32
(==) MGA(0): RGB weight 888
(**) MGA(0): Option "HWcursor" "off"
(**) MGA(0): Option "AGPMode" "4"
(**) MGA(0): Using AGP 4x mode
(==) MGA(0): Using XAA acceleration
(--) MGA(0): Linear framebuffer at 0xFA000000
(**) MGA(0): MMIO registers at 0xF9000000
(--) MGA(0): Pseudo-DMA transfer window at 0xF8800000
(--) MGA(0): BIOS at 0xF9FE0000
Requesting insufficient memory window!: start: 0xf8800000 end: 
0xf9efffff size 0x2000000
(EE) Cannot find empty range to map base to
(WW) MGA(0): Video BIOS info block not detected       !

and the second head is working only in clone mode.
Comment 3 Warren Block 2007-10-05 17:56:11 UTC
A Solution: Reading The Matrox BIOS As A File



The Problem

The FreeBSD xorg drivers try to map the Matrox video BIOS into a PCI 
range, but fail.  Something (OS? motherboard BIOS?) has mapped something 
else into the available ranges, leaving none big enough to hold the 
0x2000000 size wanted.  xf86GetRange (in xf86Bus.c) finds conflicts [tmp 
= ChkConflict(&r,Acc,SETUP);] and the user sees this message in the Xorg 
log:

Requesting insufficient memory window!: start: 0xdee00000 end: 0xdfefffff size 0
x2000000
(EE) Cannot find empty range to map base to

Without the BIOS, the mga driver has limited function.  This is 
particularly important with the xorg 1.3 xrandr support for multihead 
video boards (MGA450/550).  Newer versions of the mga driver use the 
BIOS to determine how many video connectors the card has; without the 
BIOS, only one is found.



The Solution

Well, maybe not *the* solution, but a solution.  The Linux folks fixed a
similar problem back in April of 2006:

     https://bugs.freedesktop.org/show_bug.cgi?id=6751

That code appears to have been integrated into xorg-server (linuxPci.c, 
Pci.h, and Pci.c).

This is a not-so-quick hack for FreeBSD based on that patch.  It seemed 
like a quick port of the Linux code would work.  But it did not, due to 
a) my inexperience with C; b) the complexity of X and multi-OS support 
(lots of twisty little ARCH_INIT_OS_PCI ifdefs, all alike); c) my 
inability to get pciconf to do what I wanted, and D) possibly badgers.

So I'm documenting a hack that does work in the hopes that it will help 
someone else implement it correctly.


1. Copy the video BIOS from your card to a file.

Real FreeBSD xorg code should read the BIOS data directly from the card. 
Maybe pciconf can do that, but I couldn't figure out how, so I read it 
from a file.  Use Linux to copy the BIOS to a file:

     $ lspci | grep Matrox

     (on my system this is 01:00.0)

     $ cd /sys/bus/pci/devices/0000:01:00.0
     $ echo 1 > rom
     $ cat rom > /tmp/videobios.bin
     $ echo 0 > rom

Save the videobios.bin file somewhere (/tmp/mga/videobios.bin is where 
the patch expects it) and reboot in FreeBSD.


2. Patch xorg-server's Pci.c:

     # cd /usr/ports/x11-servers/xorg-server
     # copy patch-Pci.c (included at the end of this file) to files/
     # make install

Of course this is wrong, the code should be in freebsdPci.c.  However, 
adding the changes in the Linux diff was not enough, and the #ifdefs in 
Pci.h defeated my attempts.  Somebody who knows what they are doing here 
would probably have no trouble.


3.  The Result

Using the experimental mga-1.9.99, xorg log output shows:

(II) Attempted to read BIOS 128KB from /tmp/mga/videobios.bin: got 34KB
(--) MGA(0): Video BIOS info block at offset 0x07D00

Output from xrandr 1.2:

Screen 0: minimum 320 x 200, current 1280 x 1024, maximum 2304 x 1024
VGA1 connected 1280x1024+0+0 375mm x 301mm
    1280x1024      60.0*+   59.9
    1024x768       70.1     60.0
    832x624        74.6
    800x600        72.2     75.0     60.3     56.2
    640x480        75.0     72.8     66.7     60.0
    720x400        70.1 
VGA2 connected 1024x768+0+0 307mm x 230mm
    1024x768       60.0*+   75.1     70.1     60.0*
    832x624        74.6
    800x600        72.2     75.0     60.3     56.2
    640x480        75.0     72.8     66.7     60.0
    720x400        70.1


The Patch

--- hw/xfree86/os-support/bus/Pci.c.orig	2007-09-05 18:48:26.000000000 -0600
+++ hw/xfree86/os-support/bus/Pci.c	2007-10-05 10:40:01.000000000 -0600
@@ -210,6 +210,12 @@
  #include "xf86_OSproc.h"
  #include "Pci.h"

+/* WB: start */
+#include "compiler.h"
+#include <stdio.h>
+#include "xf86_OSlib.h"
+/* WB: end */
+
  #define PCI_MFDEV_SUPPORT   1 /* Include PCI multifunction device support */
  #define PCI_BRIDGE_SUPPORT  1 /* Include support for PCI-to-PCI bridges */

@@ -238,6 +244,9 @@
  			unsigned char * buf, int len, PciBiosType BiosType );

  static int (*pciOSHandleBIOS)(PCITAG Tag, int basereg, unsigned char *buf, int len);
+/* WB: start */
+static int freebsdpciOsHandleBIOS(PCITAG Tag, int basereg, unsigned char *buf, int len);
+/* WB: end */

  int xf86MaxPciDevs = 0;

@@ -1324,6 +1333,13 @@
    PCITAG *pTag;
    int i;

+  /* WB: start */
+  /* this should be in pciOSHandleBIOS */
+  n = freebsdpciOsHandleBIOS(Tag, basereg, buf, len);
+  if (n)
+      return n;
+  /* WB: end */
+
    /* fall back to the old code if the OS code fails */
    if (pciOSHandleBIOS) {
    	n = pciOSHandleBIOS(Tag, basereg, buf, len);
@@ -1415,3 +1431,37 @@
  }

  #endif /* INCLUDE_XF86_NO_DOMAIN */
+
+/* WB: start */
+/* MGA BIOS read code for example only, do not use for real.  Don't even look directly at it. */
+#define BIOSFILE "/tmp/mga/videobios.bin"
+
+int freebsdpciOsHandleBIOS(PCITAG Tag, int basereg, unsigned char *buf, int len)
+{
+    unsigned int fd;
+    struct stat st;
+    int ret;
+    int sofar = 0;
+
+    if (stat(BIOSFILE, &st) == 0)
+    {
+        if ((fd = open(BIOSFILE, O_RDWR)))
+            basereg = 0x0;
+
+        lseek(fd, 0, SEEK_SET);
+        do {
+            /* copy the ROM until we hit Len, EOF or read error */
+            ret = read(fd, buf+sofar, len-sofar);
+            if (ret <= 0)
+                break;
+            sofar += ret;
+        } while (sofar < len);
+
+        close(fd);
+        if (sofar < len)
+            xf86MsgVerb(X_INFO, 3, "Attempted to read BIOS %dKB from %s: got %dKB\n", len/1024, BIOSFILE, sofar/1024);
+        return sofar;
+    }
+    return 0;
+}
+/* WB: end */

-Warren Block * Rapid City, South Dakota USA
Comment 4 Warren Block 2007-10-21 04:40:09 UTC
When the FreeBSD port of xorg-server starts using libpciaccess, the 
problem reading the video BIOS ROM should be fixed.  Until then, I have 
an easier patch and instructions for xorg-server 1.4.1:

http://www.wonkity.com/~wblock/mgapatch/xorg-patch.txt

-Warren Block * Rapid City, South Dakota USA
Comment 5 Florent Thoumie freebsd_committer 2008-01-02 13:34:54 UTC
State Changed
From-To: open->closed

I'm closing this PR cause there's no easy way to fix this in the ports 
collection right now. Please work with xorg maintainers to get your 
patches in the git repo. If it's committed to master but too late for 
1.4.1, I'll reconsider adding it as a local patch. 

In the meantime, I've rolled back the mga driver to 1.4.7 as it seems to 
fix all single-head issues. 

Thanks for your submission.