From 1d731fc54a2cf5d3f353d8ee1c7c4989df27f011 Mon Sep 17 00:00:00 2001 From: Matthias Hopf Date: Thu, 2 Nov 2006 18:50:15 +0100 Subject: [PATCH] Add domain support to linuxPciOpenFile(). Loosely based on patch from David S. Miller See also bug #2368. --- hw/xfree86/os-support/bus/linuxPci.c | 90 +++++++++++++++++++++------- 1 file changed, 68 insertions(+), 22 deletions(-) diff --git a/hw/xfree86/os-support/bus/linuxPci.c b/hw/xfree86/os-support/bus/linuxPci.c index 0f7fc470c..97d60f599 100644 --- a/hw/xfree86/os-support/bus/linuxPci.c +++ b/hw/xfree86/os-support/bus/linuxPci.c @@ -54,6 +54,7 @@ #include "xf86Priv.h" #include "xf86_OSlib.h" #include "Pci.h" +#include /* * linux platform specific PCI access functions -- using /proc/bus/pci @@ -73,6 +74,7 @@ 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 int linuxPciHandleBIOS(PCITAG Tag, int basereg, unsigned char *buf, int len); +static Bool linuxDomainSupport(void); static pciBusFuncs_t linuxFuncs0 = { /* pciReadLong */ linuxPciCfgRead, @@ -116,6 +118,8 @@ static pciBusInfo_t linuxPci0 = { /* from lnx_pci.c. */ extern int lnxPciInit(void); +static Bool domain_support = FALSE; + void linuxPciInit() { @@ -126,6 +130,9 @@ linuxPciInit() we'll need a fallback for 2.0 kernels here */ return; } +#ifndef INCLUDE_XF86_NO_DOMAIN + domain_support = linuxDomainSupport(); +#endif pciNumBuses = 1; pciBusInfo[0] = &linuxPci0; pciFindFirstFP = pciGenFindFirst; @@ -137,13 +144,14 @@ linuxPciInit() static int linuxPciOpenFile(PCITAG tag, Bool write) { - static int lbus,ldev,lfunc,fd = -1,is_write = 0; - int bus, dev, func; + static int ldomain, lbus,ldev,lfunc,fd = -1,is_write = 0; + int domain, bus, dev, func; char file[64]; struct stat ignored; static int is26 = -1; - bus = PCI_BUS_FROM_TAG(tag); + domain = PCI_DOM_FROM_TAG(tag); + bus = PCI_BUS_NO_DOMAIN(PCI_BUS_FROM_TAG(tag)); dev = PCI_DEV_FROM_TAG(tag); func = PCI_FUNC_FROM_TAG(tag); if (is26 == -1) { @@ -153,30 +161,41 @@ linuxPciOpenFile(PCITAG tag, Bool write) is26 = 1; } - if (fd == -1 || (write && (!is_write)) + if (!domain_support && domain > 0) + return -1; + + if (fd == -1 || (write && (!is_write)) || domain != ldomain || bus != lbus || dev != ldev || func != lfunc) { - if (fd != -1) + if (fd != -1) { close(fd); + fd = -1; + } if (is26) - sprintf(file,"/sys/bus/pci/devices/0000:%02x:%02x.%01x/config", - bus, dev, func); + sprintf(file,"/sys/bus/pci/devices/%04x:%02x:%02x.%01x/config", + domain, bus, dev, func); else { 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); + sprintf(file, "/proc/bus/pci/%04x:%02x", domain, bus); + if (stat(file, &ignored) < 0) { + if (domain == 0) + sprintf(file, "/proc/bus/pci/%02x/%02x.%1x", + bus, dev, func); + else + goto bail; + } else + sprintf(file, "/proc/bus/pci/%04x:%02x/%02x.%1x", + domain, 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); + sprintf(file, "/proc/bus/pci/%04x:%04x", domain, bus); + if (stat(file, &ignored) < 0) { + if (domain == 0) + sprintf(file, "/proc/bus/pci/%04x/%02x.%1x", + bus, dev, func); + else + goto bail; + } else + sprintf(file, "/proc/bus/pci/%04x:%04x/%02x.%1x", + domain, bus, dev, func); } } if (write) { @@ -191,7 +210,8 @@ linuxPciOpenFile(PCITAG tag, Bool write) fd = open(file,O_RDONLY); is_write = FALSE; } - + bail: + ldomain = domain; lbus = bus; ldev = dev; lfunc = func; @@ -489,6 +509,32 @@ linuxGetSizes(PCITAG Tag, unsigned long *io_size, unsigned long *mem_size) *mem_size = sizes->mem_size; } +static Bool +linuxDomainSupport(void) +{ + DIR *dir; + struct dirent *dirent; + char *end; + + if (!(dir = opendir("/proc/bus/pci"))) + return FALSE; + while (1) { + if (!(dirent = readdir(dir))) + return FALSE; + strtol(dirent->d_name,&end,16); + /* entry of the form xx or xxxx : x=[0..f] no domain */ + if (*end == '\0') + return FALSE; + else if (*end == ':') { + /* ':' found immediately after: verify for xxxx:xx or xxxx:xxxx */ + strtol(end + 1,&end,16); + if (*end == '\0') + return TRUE; + } + } + return FALSE; +} + _X_EXPORT int xf86GetPciDomain(PCITAG Tag) {