[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