aboutsummaryrefslogtreecommitdiff
path: root/nx-X11/programs/Xserver/hw/xfree86/os-support/bus/linuxPci.c
diff options
context:
space:
mode:
Diffstat (limited to 'nx-X11/programs/Xserver/hw/xfree86/os-support/bus/linuxPci.c')
-rw-r--r--nx-X11/programs/Xserver/hw/xfree86/os-support/bus/linuxPci.c894
1 files changed, 894 insertions, 0 deletions
diff --git a/nx-X11/programs/Xserver/hw/xfree86/os-support/bus/linuxPci.c b/nx-X11/programs/Xserver/hw/xfree86/os-support/bus/linuxPci.c
new file mode 100644
index 000000000..40fb4604b
--- /dev/null
+++ b/nx-X11/programs/Xserver/hw/xfree86/os-support/bus/linuxPci.c
@@ -0,0 +1,894 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/bus/linuxPci.c,v 1.9 2002/09/24 16:14:16 tsi Exp $ */
+/*
+ * Copyright 1998 by Concurrent Computer Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Concurrent Computer
+ * Corporation not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Concurrent Computer Corporation makes no representations
+ * about the suitability of this software for any purpose. It is
+ * provided "as is" without express or implied warranty.
+ *
+ * CONCURRENT COMPUTER CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD
+ * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CONCURRENT COMPUTER CORPORATION BE
+ * LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
+ * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ *
+ * Copyright 1998 by Metro Link Incorporated
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Metro Link
+ * Incorporated not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Metro Link Incorporated makes no representations
+ * about the suitability of this software for any purpose. It is
+ * provided "as is" without express or implied warranty.
+ *
+ * METRO LINK INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD
+ * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL METRO LINK INCORPORATED BE
+ * LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
+ * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#ifdef HAVE_XORG_CONFIG_H
+#include <xorg-config.h>
+#endif
+
+#include <stdio.h>
+#include "compiler.h"
+#include "xf86.h"
+#include "xf86Priv.h"
+#include "xf86_OSlib.h"
+#include "Pci.h"
+
+/*
+ * linux platform specific PCI access functions -- using /proc/bus/pci
+ * needs kernel version 2.2.x
+ */
+static CARD32 linuxPciCfgRead(PCITAG tag, int off);
+static void linuxPciCfgWrite(PCITAG, int off, CARD32 val);
+static void linuxPciCfgSetBits(PCITAG tag, int off, CARD32 mask, CARD32 bits);
+static ADDRESS linuxTransAddrBusToHost(PCITAG tag, PciAddrType type, ADDRESS addr);
+#if defined(__powerpc__)
+static ADDRESS linuxPpcBusAddrToHostAddr(PCITAG, PciAddrType, ADDRESS);
+static ADDRESS linuxPpcHostAddrToBusAddr(PCITAG, PciAddrType, ADDRESS);
+#endif
+
+static CARD8 linuxPciCfgReadByte(PCITAG tag, int off);
+static void linuxPciCfgWriteByte(PCITAG tag, int off, CARD8 val);
+static CARD16 linuxPciCfgReadWord(PCITAG tag, int off);
+static void linuxPciCfgWriteWord(PCITAG tag, int off, CARD16 val);
+
+static pciBusFuncs_t linuxFuncs0 = {
+/* pciReadLong */ linuxPciCfgRead,
+/* pciWriteLong */ linuxPciCfgWrite,
+/* pciSetBitsLong */ linuxPciCfgSetBits,
+#if defined(__powerpc__)
+/* pciAddrHostToBus */ linuxPpcHostAddrToBusAddr,
+/* pciAddrBusToHost */ linuxPpcBusAddrToHostAddr,
+#else
+/* pciAddrHostToBus */ pciAddrNOOP,
+/* pciAddrBusToHost */ linuxTransAddrBusToHost,
+#endif
+
+/* pciControlBridge */ NULL,
+/* pciGetBridgeBuses */ NULL,
+/* pciGetBridgeResources */ NULL,
+
+/* pciReadByte */ linuxPciCfgReadByte,
+/* pciWriteByte */ linuxPciCfgWriteByte,
+
+/* pciReadWord */ linuxPciCfgReadWord,
+/* pciWriteWord */ linuxPciCfgWriteWord,
+};
+
+static pciBusInfo_t linuxPci0 = {
+/* configMech */ PCI_CFG_MECH_OTHER,
+/* numDevices */ 32,
+/* secondary */ FALSE,
+/* primary_bus */ 0,
+#ifdef PowerMAX_OS
+/* ppc_io_base */ 0,
+/* ppc_io_size */ 0,
+#endif
+/* funcs */ &linuxFuncs0,
+/* pciBusPriv */ NULL,
+/* bridge */ NULL
+};
+
+void
+linuxPciInit()
+{
+ struct stat st;
+ if ((xf86Info.pciFlags == PCIForceNone) ||
+ (-1 == stat("/proc/bus/pci", &st))) {
+ /* when using this as default for all linux architectures,
+ we'll need a fallback for 2.0 kernels here */
+ return;
+ }
+ pciNumBuses = 1;
+ pciBusInfo[0] = &linuxPci0;
+ pciFindFirstFP = pciGenFindFirst;
+ pciFindNextFP = pciGenFindNext;
+}
+
+static int
+linuxPciOpenFile(PCITAG tag, Bool write)
+{
+ static int lbus,ldev,lfunc,fd = -1,is_write = 0;
+ int bus, dev, func;
+ char file[32];
+ struct stat ignored;
+
+ bus = PCI_BUS_FROM_TAG(tag);
+ dev = PCI_DEV_FROM_TAG(tag);
+ func = PCI_FUNC_FROM_TAG(tag);
+ if (fd == -1 || (write && (!is_write))
+ || bus != lbus || dev != ldev || func != lfunc) {
+ if (fd != -1)
+ close(fd);
+ if (bus < 256) {
+ sprintf(file,"/proc/bus/pci/%02x",bus);
+ if (stat(file, &ignored) < 0)
+ sprintf(file, "/proc/bus/pci/0000:%02x/%02x.%1x",
+ bus, dev, func);
+ else
+ sprintf(file, "/proc/bus/pci/%02x/%02x.%1x",
+ bus, dev, func);
+ } else {
+ sprintf(file,"/proc/bus/pci/%04x",bus);
+ if (stat(file, &ignored) < 0)
+ sprintf(file, "/proc/bus/pci/0000:%04x/%02x.%1x",
+ bus, dev, func);
+ else
+ sprintf(file, "/proc/bus/pci/%04x/%02x.%1x",
+ bus, dev, func);
+ }
+ if (write) {
+ fd = open(file,O_RDWR);
+ if (fd != -1) is_write = TRUE;
+ } else switch (is_write) {
+ case TRUE:
+ fd = open(file,O_RDWR);
+ if (fd > -1)
+ break;
+ default:
+ fd = open(file,O_RDONLY);
+ is_write = FALSE;
+ }
+
+ lbus = bus;
+ ldev = dev;
+ lfunc = func;
+ }
+ return fd;
+}
+
+static CARD32
+linuxPciCfgRead(PCITAG tag, int off)
+{
+ int fd;
+ CARD32 val = 0xffffffff;
+
+ if (-1 != (fd = linuxPciOpenFile(tag,FALSE))) {
+ lseek(fd,off,SEEK_SET);
+ read(fd,&val,4);
+ }
+ return PCI_CPU(val);
+}
+
+static void
+linuxPciCfgWrite(PCITAG tag, int off, CARD32 val)
+{
+ int fd;
+
+ if (-1 != (fd = linuxPciOpenFile(tag,TRUE))) {
+ lseek(fd,off,SEEK_SET);
+ val = PCI_CPU(val);
+ write(fd,&val,4);
+ }
+}
+
+static void
+linuxPciCfgSetBits(PCITAG tag, int off, CARD32 mask, CARD32 bits)
+{
+ int fd;
+ CARD32 val = 0xffffffff;
+
+ if (-1 != (fd = linuxPciOpenFile(tag,TRUE))) {
+ lseek(fd,off,SEEK_SET);
+ read(fd,&val,4);
+ val = PCI_CPU(val);
+ val = (val & ~mask) | (bits & mask);
+ val = PCI_CPU(val);
+ lseek(fd,off,SEEK_SET);
+ write(fd,&val,4);
+ }
+}
+
+/*
+ * This function will convert a BAR address into a host address
+ * suitable for passing into the mmap function of a /proc/bus
+ * device.
+ */
+ADDRESS linuxTransAddrBusToHost(PCITAG tag, PciAddrType type, ADDRESS addr)
+{
+ ADDRESS ret = xf86GetOSOffsetFromPCI(tag, PCI_MEM|PCI_IO, addr);
+
+ if (ret)
+ return ret;
+
+ /*
+ * if it is not a BAR address, it must be legacy, (or wrong)
+ * return it as is..
+ */
+ return addr;
+}
+
+
+#if defined(__powerpc__)
+
+#ifndef __NR_pciconfig_iobase
+#define __NR_pciconfig_iobase 200
+#endif
+
+static ADDRESS
+linuxPpcBusAddrToHostAddr(PCITAG tag, PciAddrType type, ADDRESS addr)
+{
+ if (type == PCI_MEM)
+ {
+ ADDRESS membase = syscall(__NR_pciconfig_iobase, 1,
+ PCI_BUS_FROM_TAG(tag), PCI_DFN_FROM_TAG(tag));
+ return (addr + membase);
+ }
+ else if (type == PCI_IO)
+ {
+ ADDRESS iobase = syscall(__NR_pciconfig_iobase, 2,
+ PCI_BUS_FROM_TAG(tag), PCI_DFN_FROM_TAG(tag));
+ return (addr + iobase);
+ }
+ else return addr;
+}
+
+static ADDRESS
+linuxPpcHostAddrToBusAddr(PCITAG tag, PciAddrType type, ADDRESS addr)
+{
+ if (type == PCI_MEM)
+ {
+ ADDRESS membase = syscall(__NR_pciconfig_iobase, 1,
+ PCI_BUS_FROM_TAG(tag), PCI_DFN_FROM_TAG(tag));
+ return (addr - membase);
+ }
+ else if (type == PCI_IO)
+ {
+ ADDRESS iobase = syscall(__NR_pciconfig_iobase, 2,
+ PCI_BUS_FROM_TAG(tag), PCI_DFN_FROM_TAG(tag));
+ return (addr - iobase);
+ }
+ else return addr;
+}
+
+#endif /* __powerpc__ */
+
+static CARD8
+linuxPciCfgReadByte(PCITAG tag, int off)
+{
+ int fd;
+ CARD8 val = 0xff;
+
+ if (-1 != (fd = linuxPciOpenFile(tag,FALSE))) {
+ lseek(fd,off,SEEK_SET);
+ read(fd,&val,1);
+ }
+
+ return val;
+}
+
+static void
+linuxPciCfgWriteByte(PCITAG tag, int off, CARD8 val)
+{
+ int fd;
+
+ if (-1 != (fd = linuxPciOpenFile(tag,TRUE))) {
+ lseek(fd,off,SEEK_SET);
+ write(fd, &val, 1);
+ }
+}
+
+static CARD16
+linuxPciCfgReadWord(PCITAG tag, int off)
+{
+ int fd;
+ CARD16 val = 0xff;
+
+ if (-1 != (fd = linuxPciOpenFile(tag,FALSE))) {
+ lseek(fd, off, SEEK_SET);
+ read(fd, &val, 2);
+ }
+
+ return PCI_CPU16(val);
+}
+
+static void
+linuxPciCfgWriteWord(PCITAG tag, int off, CARD16 val)
+{
+ int fd;
+
+ if (-1 != (fd = linuxPciOpenFile(tag,TRUE))) {
+ lseek(fd, off, SEEK_SET);
+ val = PCI_CPU16(val);
+ write(fd, &val, 2);
+ }
+}
+
+#ifndef INCLUDE_XF86_NO_DOMAIN
+
+/*
+ * Compiling the following simply requires the presence of <linux/pci.c>.
+ * Actually running this is another matter altogether...
+ *
+ * This scheme requires that the kernel allow mmap()'ing of a host bridge's I/O
+ * and memory spaces through its /proc/bus/pci/BUS/DFN entry. Which one is
+ * determined by a prior ioctl().
+ *
+ * For the sparc64 port, this means 2.4.12 or later. For ppc, this
+ * functionality is almost, but not quite there yet. Alpha and other kernel
+ * ports to multi-domain architectures still need to implement this.
+ *
+ * This scheme is also predicated on the use of an IOADDRESS compatible type to
+ * designate I/O addresses. Although IOADDRESS is defined as an unsigned
+ * integral type, it is actually the virtual address of, i.e. a pointer to, the
+ * I/O port to access. And so, the inX/outX macros in "compiler.h" need to be
+ * #define'd appropriately (as is done on SPARC's).
+ *
+ * Another requirement to port this scheme to another multi-domain architecture
+ * is to add the appropriate entries in the pciControllerSizes array below.
+ *
+ * TO DO: Address the deleterious reaction some host bridges have to master
+ * aborts. This is already done for secondary PCI buses, but not yet
+ * for accesses to primary buses (except for the SPARC port, where
+ * master aborts are avoided during PCI scans).
+ */
+
+#include <linux/pci.h>
+
+#ifndef PCIIOC_BASE /* Ioctls for /proc/bus/pci/X/Y nodes. */
+#define PCIIOC_BASE ('P' << 24 | 'C' << 16 | 'I' << 8)
+
+/* Get controller for PCI device. */
+#define PCIIOC_CONTROLLER (PCIIOC_BASE | 0x00)
+/* Set mmap state to I/O space. */
+#define PCIIOC_MMAP_IS_IO (PCIIOC_BASE | 0x01)
+/* Set mmap state to MEM space. */
+#define PCIIOC_MMAP_IS_MEM (PCIIOC_BASE | 0x02)
+/* Enable/disable write-combining. */
+#define PCIIOC_WRITE_COMBINE (PCIIOC_BASE | 0x03)
+
+#endif
+
+/* This probably shouldn't be Linux-specific */
+static pciConfigPtr
+xf86GetPciHostConfigFromTag(PCITAG Tag)
+{
+ int bus = PCI_BUS_FROM_TAG(Tag);
+ pciBusInfo_t *pBusInfo;
+
+ while ((bus < pciNumBuses) && (pBusInfo = pciBusInfo[bus])) {
+ if (bus == pBusInfo->primary_bus)
+ return pBusInfo->bridge;
+ bus = pBusInfo->primary_bus;
+ }
+
+ return NULL; /* Bad data */
+}
+
+/*
+ * This is ugly, but until I can extract this information from the kernel,
+ * it'll have to do. The default I/O space size is 64K, and 4G for memory.
+ * Anything else needs to go in this table. (PowerPC folk take note.)
+ *
+ * Note that Linux/SPARC userland is 32-bit, so 4G overflows to zero here.
+ *
+ * Please keep this table in ascending vendor/device order.
+ */
+static struct pciSizes {
+ unsigned short vendor, device;
+ unsigned long io_size, mem_size;
+} pciControllerSizes[] = {
+ {
+ PCI_VENDOR_SUN, PCI_CHIP_PSYCHO,
+ 1U << 16, 1U << 31
+ },
+ {
+ PCI_VENDOR_SUN, PCI_CHIP_SCHIZO,
+ 1U << 24, 1U << 31 /* ??? */
+ },
+ {
+ PCI_VENDOR_SUN, PCI_CHIP_SABRE,
+ 1U << 24, (unsigned long)(1ULL << 32)
+ },
+ {
+ PCI_VENDOR_SUN, PCI_CHIP_HUMMINGBIRD,
+ 1U << 24, (unsigned long)(1ULL << 32)
+ }
+};
+#define NUM_SIZES (sizeof(pciControllerSizes) / sizeof(pciControllerSizes[0]))
+
+static unsigned long
+linuxGetIOSize(PCITAG Tag)
+{
+ pciConfigPtr pPCI;
+ int i;
+
+ /* Find host bridge */
+ if ((pPCI = xf86GetPciHostConfigFromTag(Tag))) {
+ /* Look up vendor/device */
+ for (i = 0; i < NUM_SIZES; i++) {
+ if (pPCI->pci_vendor > pciControllerSizes[i].vendor)
+ continue;
+ if (pPCI->pci_vendor < pciControllerSizes[i].vendor)
+ break;
+ if (pPCI->pci_device > pciControllerSizes[i].device)
+ continue;
+ if (pPCI->pci_device < pciControllerSizes[i].device)
+ break;
+ return pciControllerSizes[i].io_size;
+ }
+ }
+
+ return 1U << 16; /* Default to 64K */
+}
+
+static void
+linuxGetSizes(PCITAG Tag, unsigned long *io_size, unsigned long *mem_size)
+{
+ pciConfigPtr pPCI;
+ int i;
+
+ *io_size = (1U << 16); /* Default to 64K */
+ *mem_size = (unsigned long)(1ULL << 32); /* Default to 4G */
+
+ /* Find host bridge */
+ if ((pPCI = xf86GetPciHostConfigFromTag(Tag))) {
+ /* Look up vendor/device */
+ for (i = 0; i < NUM_SIZES; i++) {
+ if (pPCI->pci_vendor > pciControllerSizes[i].vendor)
+ continue;
+ if (pPCI->pci_vendor < pciControllerSizes[i].vendor)
+ break;
+ if (pPCI->pci_device > pciControllerSizes[i].device)
+ continue;
+ if (pPCI->pci_device < pciControllerSizes[i].device)
+ break;
+ *io_size = pciControllerSizes[i].io_size;
+ *mem_size = pciControllerSizes[i].mem_size;
+ break;
+ }
+ }
+}
+
+int
+xf86GetPciDomain(PCITAG Tag)
+{
+ pciConfigPtr pPCI;
+ int fd, result;
+
+ pPCI = xf86GetPciHostConfigFromTag(Tag);
+
+ if (pPCI && (result = PCI_DOM_FROM_BUS(pPCI->busnum)))
+ return result;
+
+ if (!pPCI || pPCI->fakeDevice)
+ return 1; /* Domain 0 is reserved */
+
+ if ((fd = linuxPciOpenFile(pPCI ? pPCI->tag : 0,FALSE)) < 0)
+ return 0;
+
+ if ((result = ioctl(fd, PCIIOC_CONTROLLER, 0)) < 0)
+ return 0;
+
+ return result + 1; /* Domain 0 is reserved */
+}
+
+static pointer
+linuxMapPci(int ScreenNum, int Flags, PCITAG Tag,
+ ADDRESS Base, unsigned long Size, int mmap_ioctl)
+{
+ do {
+ pciConfigPtr pPCI;
+ unsigned char *result;
+ ADDRESS realBase, Offset;
+ int fd, mmapflags, prot;
+
+ xf86InitVidMem();
+
+ pPCI = xf86GetPciHostConfigFromTag(Tag);
+
+ if (((fd = linuxPciOpenFile(pPCI ? pPCI->tag : 0,FALSE)) < 0) ||
+ (ioctl(fd, mmap_ioctl, 0) < 0))
+ break;
+
+/* Note: IA-64 doesn't compile this and doesn't need to */
+#ifdef __ia64__
+
+# ifndef MAP_WRITECOMBINED
+# define MAP_WRITECOMBINED 0x00010000
+# endif
+# ifndef MAP_NONCACHED
+# define MAP_NONCACHED 0x00020000
+# endif
+
+ if (Flags & VIDMEM_FRAMEBUFFER)
+ mmapflags = MAP_SHARED | MAP_WRITECOMBINED;
+ else
+ mmapflags = MAP_SHARED | MAP_NONCACHED;
+
+#else /* !__ia64__ */
+
+ mmapflags = (Flags & VIDMEM_FRAMEBUFFER) / VIDMEM_FRAMEBUFFER;
+
+ if (ioctl(fd, PCIIOC_WRITE_COMBINE, mmapflags) < 0)
+ break;
+
+ mmapflags = MAP_SHARED;
+
+#endif /* ?__ia64__ */
+
+ /* Align to page boundary */
+ realBase = Base & ~(getpagesize() - 1);
+ Offset = Base - realBase;
+
+ if (Flags & VIDMEM_READONLY)
+ prot = PROT_READ;
+ else
+ prot = PROT_READ | PROT_WRITE;
+
+ result = mmap(NULL, Size + Offset, prot, mmapflags, fd, realBase);
+
+ if (!result || ((pointer)result == MAP_FAILED))
+ return NULL;
+
+ xf86MakeNewMapping(ScreenNum, Flags, realBase, Size + Offset, result);
+
+ return result + Offset;
+ } while (0);
+
+ if (mmap_ioctl == PCIIOC_MMAP_IS_MEM)
+ return xf86MapVidMem(ScreenNum, Flags, Base, Size);
+
+ return NULL;
+}
+
+#define MAX_DOMAINS 257
+static pointer DomainMmappedIO[MAX_DOMAINS];
+static pointer DomainMmappedMem[MAX_DOMAINS];
+
+static int
+linuxOpenLegacy(PCITAG Tag, char *name)
+{
+#define PREFIX "/sys/class/pci_bus/%04x:%02x/%s"
+ char *path;
+ int domain, bus;
+ pciBusInfo_t *pBusInfo;
+ pciConfigPtr bridge = NULL;
+ int fd;
+
+ path = xalloc(strlen(PREFIX) + strlen(name));
+ if (!path)
+ return -1;
+
+ for (;;) {
+ domain = xf86GetPciDomain(Tag);
+ bus = PCI_BUS_NO_DOMAIN(PCI_BUS_FROM_TAG(Tag));
+
+ /* Domain 0 is reserved -- see xf86GetPciDomain() */
+ if ((domain <= 0) || (domain >= MAX_DOMAINS))
+ FatalError("linuxOpenLegacy(): domain out of range\n");
+
+ sprintf(path, PREFIX, domain - 1, bus, name);
+ fd = open(path, O_RDWR);
+ if (fd >= 0) {
+ xfree(path);
+ return fd;
+ }
+
+ pBusInfo = pciBusInfo[bus];
+ if (!pBusInfo || (bridge == pBusInfo->bridge) ||
+ !(bridge = pBusInfo->bridge)) {
+ xfree(path);
+ return -1;
+ }
+
+ Tag = bridge->tag;
+ }
+
+ xfree(path);
+ return fd;
+}
+
+/*
+ * xf86MapDomainMemory - memory map PCI domain memory
+ *
+ * This routine maps the memory region in the domain specified by Tag and
+ * returns a pointer to it. The pointer is saved for future use if it's in
+ * the legacy ISA memory space (memory in a domain between 0 and 1MB).
+ */
+pointer
+xf86MapDomainMemory(int ScreenNum, int Flags, PCITAG Tag,
+ ADDRESS Base, unsigned long Size)
+{
+ int domain = xf86GetPciDomain(Tag);
+ int fd;
+
+ /*
+ * We use /proc/bus/pci on non-legacy addresses or if the Linux sysfs
+ * legacy_mem interface is unavailable.
+ */
+ if (Base > 1024*1024)
+ return linuxMapPci(ScreenNum, Flags, Tag, Base, Size,
+ PCIIOC_MMAP_IS_MEM);
+
+ if ((fd = linuxOpenLegacy(Tag, "legacy_mem")) < 0)
+ return linuxMapPci(ScreenNum, Flags, Tag, Base, Size,
+ PCIIOC_MMAP_IS_MEM);
+
+
+ /* If we haven't already mapped this legacy space, try to. */
+ if (!DomainMmappedMem[domain]) {
+ DomainMmappedMem[domain] = mmap(NULL, 1024*1024, PROT_READ|PROT_WRITE,
+ MAP_SHARED, fd, 0);
+ if (DomainMmappedMem[domain] == MAP_FAILED) {
+ close(fd);
+ perror("mmap failure");
+ FatalError("xf86MapDomainMem(): mmap() failure\n");
+ }
+ }
+
+ close(fd);
+ return (pointer)((char *)DomainMmappedMem[domain] + Base);
+}
+
+/*
+ * xf86MapDomainIO - map I/O space in this domain
+ *
+ * Each domain has a legacy ISA I/O space. This routine will try to
+ * map it using the Linux sysfs legacy_io interface. If that fails,
+ * it'll fall back to using /proc/bus/pci.
+ *
+ * If the legacy_io interface *does* exist, the file descriptor (fd below)
+ * will be saved in the DomainMmappedIO array in the upper bits of the
+ * pointer. Callers will do I/O with small port numbers (<64k values), so
+ * the platform I/O code can extract the port number and the fd, lseek to
+ * the port number in the legacy_io file, and issue the read or write.
+ *
+ * This has no means of returning failure, so all errors are fatal
+ */
+IOADDRESS
+xf86MapDomainIO(int ScreenNum, int Flags, PCITAG Tag,
+ IOADDRESS Base, unsigned long Size)
+{
+ int domain = xf86GetPciDomain(Tag);
+ int fd;
+
+ if ((domain <= 0) || (domain >= MAX_DOMAINS))
+ FatalError("xf86MapDomainIO(): domain out of range\n");
+
+ if (DomainMmappedIO[domain])
+ return (IOADDRESS)DomainMmappedIO[domain] + Base;
+
+ /* Permanently map all of I/O space */
+ if ((fd = linuxOpenLegacy(Tag, "legacy_io")) < 0) {
+ DomainMmappedIO[domain] = linuxMapPci(ScreenNum, Flags, Tag,
+ 0, linuxGetIOSize(Tag),
+ PCIIOC_MMAP_IS_IO);
+ /* ia64 can't mmap legacy IO port space */
+ if (!DomainMmappedIO[domain])
+ return Base;
+ }
+ else { /* legacy_io file exists, encode fd */
+ DomainMmappedIO[domain] = (pointer)(fd << 24);
+ }
+
+ return (IOADDRESS)DomainMmappedIO[domain] + Base;
+}
+
+/*
+ * xf86ReadDomainMemory - copy from domain memory into a caller supplied buffer
+ */
+int
+xf86ReadDomainMemory(PCITAG Tag, ADDRESS Base, int Len, unsigned char *Buf)
+{
+ unsigned char *ptr, *src;
+ ADDRESS offset;
+ unsigned long size;
+ int len, pagemask = getpagesize() - 1;
+
+ unsigned int i, dom, bus, dev, func;
+ unsigned int fd;
+ char file[256];
+ struct stat st;
+
+ dom = PCI_DOM_FROM_TAG(Tag);
+ bus = PCI_BUS_FROM_TAG(Tag);
+ dev = PCI_DEV_FROM_TAG(Tag);
+ func = PCI_FUNC_FROM_TAG(Tag);
+ sprintf(file, "/sys/devices/pci%04x:%02x/%04x:%02x:%02x.%1x/rom",
+ dom, bus, dom, bus, dev, func);
+
+ /*
+ * If the caller wants the ROM and the sysfs rom interface exists,
+ * try to use it instead of reading it from /proc/bus/pci.
+ */
+ if (((Base & 0xfffff) == 0xC0000) && (stat(file, &st) == 0)) {
+ if ((fd = open(file, O_RDWR)))
+ Base = 0x0;
+
+ /* enable the ROM first */
+ write(fd, "1", 2);
+ lseek(fd, 0, SEEK_SET);
+
+ /* copy the ROM until we hit Len, EOF or read error */
+ for (i = 0; i < Len && read(fd, Buf, 1) > 0; Buf++, i++)
+ ;
+
+ write(fd, "0", 2);
+ close(fd);
+
+ return Len;
+ }
+
+ /* Ensure page boundaries */
+ offset = Base & ~pagemask;
+ size = ((Base + Len + pagemask) & ~pagemask) - offset;
+
+ ptr = xf86MapDomainMemory(-1, VIDMEM_READONLY, Tag, offset, size);
+
+ if (!ptr)
+ return -1;
+
+ /* Using memcpy() here can hang the system */
+ src = ptr + (Base - offset);
+ for (len = Len; len-- > 0;)
+ *Buf++ = *src++;
+
+ xf86UnMapVidMem(-1, ptr, size);
+
+ return Len;
+}
+
+resPtr
+xf86BusAccWindowsFromOS(void)
+{
+ pciConfigPtr *ppPCI, pPCI;
+ resPtr pRes = NULL;
+ resRange range;
+ unsigned long io_size, mem_size;
+ int domain;
+
+ if ((ppPCI = xf86scanpci(0))) {
+ for (; (pPCI = *ppPCI); ppPCI++) {
+ if ((pPCI->pci_base_class != PCI_CLASS_BRIDGE) ||
+ (pPCI->pci_sub_class != PCI_SUBCLASS_BRIDGE_HOST))
+ continue;
+
+ domain = xf86GetPciDomain(pPCI->tag);
+ linuxGetSizes(pPCI->tag, &io_size, &mem_size);
+
+ RANGE(range, 0, (ADDRESS)(mem_size - 1),
+ RANGE_TYPE(ResExcMemBlock, domain));
+ pRes = xf86AddResToList(pRes, &range, -1);
+
+ RANGE(range, 0, (IOADDRESS)(io_size - 1),
+ RANGE_TYPE(ResExcIoBlock, domain));
+ pRes = xf86AddResToList(pRes, &range, -1);
+
+ if (domain <= 0)
+ break;
+ }
+ }
+
+ return pRes;
+}
+
+resPtr
+xf86PciBusAccWindowsFromOS(void)
+{
+ pciConfigPtr *ppPCI, pPCI;
+ resPtr pRes = NULL;
+ resRange range;
+ unsigned long io_size, mem_size;
+ int domain;
+
+ if ((ppPCI = xf86scanpci(0))) {
+ for (; (pPCI = *ppPCI); ppPCI++) {
+ if ((pPCI->pci_base_class != PCI_CLASS_BRIDGE) ||
+ (pPCI->pci_sub_class != PCI_SUBCLASS_BRIDGE_HOST))
+ continue;
+
+ domain = xf86GetPciDomain(pPCI->tag);
+ linuxGetSizes(pPCI->tag, &io_size, &mem_size);
+
+ RANGE(range, 0, (ADDRESS)(mem_size - 1),
+ RANGE_TYPE(ResExcMemBlock, domain));
+ pRes = xf86AddResToList(pRes, &range, -1);
+
+ RANGE(range, 0, (IOADDRESS)(io_size - 1),
+ RANGE_TYPE(ResExcIoBlock, domain));
+ pRes = xf86AddResToList(pRes, &range, -1);
+
+ if (domain <= 0)
+ break;
+ }
+ }
+
+ return pRes;
+}
+
+
+resPtr
+xf86AccResFromOS(resPtr pRes)
+{
+ pciConfigPtr *ppPCI, pPCI;
+ resRange range;
+ unsigned long io_size, mem_size;
+ int domain;
+
+ if ((ppPCI = xf86scanpci(0))) {
+ for (; (pPCI = *ppPCI); ppPCI++) {
+ if ((pPCI->pci_base_class != PCI_CLASS_BRIDGE) ||
+ (pPCI->pci_sub_class != PCI_SUBCLASS_BRIDGE_HOST))
+ continue;
+
+ domain = xf86GetPciDomain(pPCI->tag);
+ linuxGetSizes(pPCI->tag, &io_size, &mem_size);
+
+ /*
+ * At minimum, the top and bottom resources must be claimed, so
+ * that resources that are (or appear to be) unallocated can be
+ * relocated.
+ */
+ RANGE(range, 0x00000000u, 0x0009ffffu,
+ RANGE_TYPE(ResExcMemBlock, domain));
+ pRes = xf86AddResToList(pRes, &range, -1);
+ RANGE(range, 0x000c0000u, 0x000effffu,
+ RANGE_TYPE(ResExcMemBlock, domain));
+ pRes = xf86AddResToList(pRes, &range, -1);
+ RANGE(range, 0x000f0000u, 0x000fffffu,
+ RANGE_TYPE(ResExcMemBlock, domain));
+ pRes = xf86AddResToList(pRes, &range, -1);
+
+ RANGE(range, (ADDRESS)(mem_size - 1), (ADDRESS)(mem_size - 1),
+ RANGE_TYPE(ResExcMemBlock, domain));
+ pRes = xf86AddResToList(pRes, &range, -1);
+
+ RANGE(range, 0x00000000u, 0x00000000u,
+ RANGE_TYPE(ResExcIoBlock, domain));
+ pRes = xf86AddResToList(pRes, &range, -1);
+ RANGE(range, (IOADDRESS)(io_size - 1), (IOADDRESS)(io_size - 1),
+ RANGE_TYPE(ResExcIoBlock, domain));
+ pRes = xf86AddResToList(pRes, &range, -1);
+
+ if (domain <= 0)
+ break;
+ }
+ }
+
+ return pRes;
+}
+
+#endif /* !INCLUDE_XF86_NO_DOMAIN */