[Xorg] Re: Xserver device I/O on Linux

Jesse Barnes jbarnes at engr.sgi.com
Tue Jun 29 13:50:25 PDT 2004


On Friday, June 25, 2004 10:00 am, Jesse Barnes wrote:
> On Tuesday, May 4, 2004 1:30 pm, John Dennis wrote:
> > Both xfree86 and xorg on which it is based has code for using
> > /proc/bus/pci on linux, in fact when building for ia64 this is exactly
> > what happens so I'm a bit confused as to why you're having an issue with
> > ia64.
>
> ia64 doesn't, by default, build with PCI domain support.  It defines
> INCLUDE_XF86_NO_DOMAIN which causes it to use /dev/mem for things.  I'd
> like to change that.
>
> > We've been building and shipping X for ia64 for a while using this
> > code base. One change we recently made was to always use the linux
> > version of the pci routines on all architectures, it had been the case
> > that on x86 the pci code was accessing pci config space via the IO ports
> > and soon this won't be supported (pci express does not support it and
> > there are issues with concurrency on mp machines). This was a trival one
> > line change to an ifdef to use the linux code.
>
> So you removed the INCLUDE_XF86_NO_DOMAIN define?
>
> > I'm not sure what you mean by port I/O and mapping not being provided in
> > a way the server expects could you elaborate? A lot of these issues have
> > been addressed. But you're certainly right, port I/O on non-x86
> > architectures has been a nasty area.
>
> Here's a patch that might illustrate some of what I'm trying to do.  There
> are several issues at play here:
>
>   o Linux/ia64 kernel PCI domain support (I still need to do this properly,
>     the attached patch is funky because PCIIOC_CONTROLLER isn't implemented
>     in my kernel)
>   o bus addr != host addr on some ia64 platforms, so X on ia64 needs to
> have pciBusAddrToHostAddr implemented, this should be easy with
>     the /proc/bus/pci API
>   o ia64Pci.c roots around in /dev/mem, which can cause MCAs on machines
> that don't have the addresses it's looking for, so some other mechanism for
> discovering which PCI bridge is present would be desirable
>   o legacy port access isn't handled gracefully on some platforms, it
> causes master aborts.  I've got a patch to the Linux/ia64 kernel which will
> recover from this condition and send offending apps a SIGBUS when this
> occurs, which seems to be working well enough for X to boot cards up
>
> So does anyone own hw/xorg/os-support in the new tree?  If not, Shrijeet
> and I would be willing to help out...

Ugg, it looks like the attachment was truncated.  Here it is inline for anyone 
who wants to look.

Jesse

Index: hw/xorg/common/compiler.h
===================================================================
RCS file: /cvs/xserver/debrix/hw/xorg/common/compiler.h,v
retrieving revision 1.3
diff -u -r1.3 compiler.h
--- hw/xorg/common/compiler.h	10 Jun 2004 19:40:04 -0000	1.3
+++ hw/xorg/common/compiler.h	25 Jun 2004 14:42:23 -0000
@@ -465,10 +465,12 @@
 #    ifndef __INTEL_COMPILER  
 #      define mem_barrier()        __asm__ __volatile__ ("mf" ::: "memory")
 #      define write_mem_barrier()  __asm__ __volatile__ ("mf" ::: "memory")
+#      define io_mem_barrier()     __asm__ __volatile__ ("mf.a" ::: "memory")
 #    else
 #      include "ia64intrin.h"
 #      define mem_barrier() __mf()
 #      define write_mem_barrier() __mf()
+#      define io_mem_barrier() __mfa
 #    endif
 
 /*
@@ -491,14 +493,132 @@
         __mf();\
         __isrlz();\
        }
-#    endif
+#    endif /* __INTEL_COMPILER */
+
+/*
+ * It seems like the in/out routines in this file could be consolidated a bit
+ * and/or split into multiple, arch specific header files.
+ *
+ * Many also assume that the 'port' value passed in is an actual address,
+ * rather than relative to some 'IOBase' value.  This means that callers
+ * have to be fixed up to get their own 'IOBase' (which will be PCI device
+ * specific), or the inX/outX routines need to be changed to take a PCI
+ * tag so that platforms can route the PIOs to the correct bus.
+ */
+
 #    undef outb
 #    undef outw
 #    undef outl
- 
-#    define outb(a,b)	_outb(b,a)
-#    define outw(a,b)	_outw(b,a)
-#    define outl(a,b)	_outl(b,a) 
+
+/*
+ * Deal with outX on platforms where it's simply a store.
+ */
+
+static inline unsigned int outb(unsigned long port, unsigned char val)
+{
+	volatile unsigned char *addr = (unsigned char *)port;
+
+	*addr = val;
+	io_memory_barrier();
+}
+
+static inline unsigned int outw(unsigned long port, unsigned short val)
+{
+	volatile unsigned short *addr = (unsigned char *)port;
+
+	*addr = val;
+	io_memory_barrier();
+}
+
+static inline unsigned int outl(unsigned long port, unsigned int val)
+{
+	volatile unsigned int *addr = (unsigned char *)port;
+
+	*addr = val;
+	io_memory_barrier();
+}
+
+#    undef inb
+#    undef inw
+#    undef inl
+
+/*
+ * Deal with master aborts on a really funky platform.  The kernel will send
+ * a SIGBUS to applications that have mapped /proc/bus/pci/... when an I/O
+ * error, like a master abort, occurs.
+ *
+ * On ia64, an error caused by an uncached read may (and probably will) be
+ * reported to software *way* after the instruction that did the read.  The
+ * only way to be sure that any errors that might occur have been flushed out
+ * is to use the value we get back in a statement that affects control flow.
+ *
+ * Note that on some platforms, an PIO read does *not* guarantee that DMA
+ * initiated prior to the PIO is complete.
+ */
+extern int ia64_io_error;
+
+static inline unsigned int inb(unsigned long port)
+{
+	unsigned int val;
+
+	/* The SIGBUS handler will set this for us if an error occurs */
+        ia64_io_error = 0;
+
+        val = (unsigned int) (*((volatile unsigned char *)port));
+
+	/* Use val in an expression to flush out errors */
+        if (val && ia64_io_error)
+                return -1;
+
+	/* Double check for an error */
+        if (ia64_io_error)
+                return -1;
+
+	/* val was actually read from the hardware */
+        return val;
+}
+
+static inline unsigned int inw(unsigned long port)
+{
+	unsigned int val;
+
+	/* The SIGBUS handler will set this for us if an error occurs */
+        ia64_io_error = 0;
+
+        val = (unsigned int) (*((volatile unsigned short *)port));
+
+	/* Use val in an expression to flush out errors */
+        if (val && ia64_io_error)
+                return -1;
+
+	/* Double check for an error */
+        if (ia64_io_error)
+                return -1;
+
+	/* val was actually read from the hardware */
+        return val;
+}
+
+static inline unsigned int inl(unsigned long port)
+{
+	unsigned int val;
+
+	/* The SIGBUS handler will set this for us if an error occurs */
+        ia64_io_error = 0;
+
+        val = (unsigned int) (*((volatile unsigned int *)port));
+
+	/* Use val in an expression to flush out errors */
+        if (val && ia64_io_error)
+                return -1;
+
+	/* Double check for an error */
+        if (ia64_io_error)
+                return -1;
+
+	/* val was actually read from the hardware */
+        return val;
+}
 
 #   elif defined(linux) && defined(__amd64__) 
  
Index: hw/xorg/os-support/bus/Pci.h
===================================================================
RCS file: /cvs/xserver/debrix/hw/xorg/os-support/bus/Pci.h,v
retrieving revision 1.3
diff -u -r1.3 Pci.h
--- hw/xorg/os-support/bus/Pci.h	10 Jun 2004 19:40:52 -0000	1.3
+++ hw/xorg/os-support/bus/Pci.h	25 Jun 2004 14:42:23 -0000
@@ -257,7 +257,6 @@
 # if defined(linux)
 #  define ARCH_PCI_INIT linuxPciInit
 #  define INCLUDE_XF86_MAP_PCI_MEM
-#  define INCLUDE_XF86_NO_DOMAIN
 # elif defined(FreeBSD)
 #  define ARCH_PCI_INIT freebsdPciInit
 #  define INCLUDE_XF86_MAP_PCI_MEM
Index: hw/xorg/os-support/bus/ia64Pci.c
===================================================================
RCS file: /cvs/xserver/debrix/hw/xorg/os-support/bus/ia64Pci.c,v
retrieving revision 1.2
diff -u -r1.2 ia64Pci.c
--- hw/xorg/os-support/bus/ia64Pci.c	10 Jun 2004 19:40:52 -0000	1.2
+++ hw/xorg/os-support/bus/ia64Pci.c	25 Jun 2004 14:42:23 -0000
@@ -32,17 +32,37 @@
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
+#include <signal.h>
 #include "460gxPCI.h"
 #include "e8870PCI.h"
 #include "zx1PCI.h"
 #include "Pci.h"
 
+/* Used by the in/out routines to check for master aborts */
+int ia64_io_error;
+
+void ia64SigBusHandler(int signo, siginfo_t *sinfo, void *unused)
+{
+	ia64_io_error = 1;
+}
+
+void
+ia64SigBusSetup(void)
+{
+	struct sigaction saction;
+
+        saction.sa_sigaction = ia64SigBusHandler;
+        saction.sa_flags = SA_SIGINFO;
+        sigaction(SIGBUS, &saction, NULL);
+}
+
 void
 ia64ScanPCIWrapper(scanpciWrapperOpt flags)
 {
 
     if (flags == SCANPCI_INIT) {
-
+	ia64SigBusSetup();
+#if 0
 	/* PCI configuration space probes should be done first */
 	if (xf86PreScan460GX())
 	    return;
@@ -50,13 +70,13 @@
 	    return;
 	if (xf86PreScanZX1())
 	    return;
-
+#endif
     } else /* if (flags == SCANPCI_TERM) */ {
-
+#if 0
 	xf86PostScan460GX();
 	xf86PostScanE8870();
 	xf86PostScanZX1();
-
+#endif
     }
 
 }
Index: hw/xorg/os-support/bus/linuxPci.c
===================================================================
RCS file: /cvs/xserver/debrix/hw/xorg/os-support/bus/linuxPci.c,v
retrieving revision 1.3
diff -u -r1.3 linuxPci.c
--- hw/xorg/os-support/bus/linuxPci.c	10 Jun 2004 19:40:52 -0000	1.3
+++ hw/xorg/os-support/bus/linuxPci.c	25 Jun 2004 14:42:23 -0000
@@ -327,7 +327,8 @@
     if (pPCI && (result = PCI_DOM_FROM_BUS(pPCI->busnum)))
 	return result;
 
-    if ((fd = linuxPciOpenFile(pPCI ? pPCI->tag : 0)) < 0)
+    /* Open the bridge if present, otherwise try this device */
+    if ((fd = linuxPciOpenFile(pPCI ? pPCI->tag : Tag)) < 0)
 	return 0;
 
     if ((result = ioctl(fd, PCIIOC_CONTROLLER, 0)) < 0)
@@ -350,7 +351,8 @@
 
 	pPCI = xf86GetPciHostConfigFromTag(Tag);
 
-	if (((fd = linuxPciOpenFile(pPCI ? pPCI->tag : 0)) < 0) ||
+	/* Again, use the tag we were given if there's no parent bridge */
+	if (((fd = linuxPciOpenFile(pPCI ? pPCI->tag : Tag)) < 0) ||
 	    (ioctl(fd, mmap_ioctl, 0) < 0))
 	    break;
 




More information about the xorg mailing list