From 5afc6c1a14fea2966017493b045fa7209faeb8eb Mon Sep 17 00:00:00 2001 From: Matthias Hopf Date: Thu, 2 Nov 2006 15:42:03 +0100 Subject: [PATCH] Added linux 2.6 compatible domain aware device scanning code. Additional scanning code uses the /sys interface of 2.6 kernels. Cleaned up the use of tags and already split domain/bus/dev/fn. --- hw/xfree86/os-support/bus/Pci.c | 8 +++ hw/xfree86/os-support/bus/xf86Pci.h | 1 + hw/xfree86/os-support/linux/lnx_pci.c | 71 ++++++++++++++++++++++----- 3 files changed, 67 insertions(+), 13 deletions(-) diff --git a/hw/xfree86/os-support/bus/Pci.c b/hw/xfree86/os-support/bus/Pci.c index ea6ac4ec0..b80371d83 100644 --- a/hw/xfree86/os-support/bus/Pci.c +++ b/hw/xfree86/os-support/bus/Pci.c @@ -20,6 +20,8 @@ * pciSetBitsByte() - Write an 8 bit value against a mask * pciTag() - Return tag for a given PCI bus, device, & * function + * pciDomTag() - Return tag for a given PCI domain, bus, + * device & function * pciBusAddrToHostAddr() - Convert a PCI address to a host address * pciHostAddrToBusAddr() - Convert a host address to a PCI address * pciGetBaseSize() - Returns the number of bits in a PCI base @@ -614,6 +616,12 @@ pciTag(int busnum, int devnum, int funcnum) return(PCI_MAKE_TAG(busnum,devnum,funcnum)); } +_X_EXPORT PCITAG +pciDomTag(int domnum, int busnum, int devnum, int funcnum) +{ + return(PCI_MAKE_TAG(PCI_MAKE_BUS(domnum,busnum),devnum,funcnum)); +} + #if defined(PCI_MFDEV_SUPPORT) Bool diff --git a/hw/xfree86/os-support/bus/xf86Pci.h b/hw/xfree86/os-support/bus/xf86Pci.h index fdb88e832..c444a0cd1 100644 --- a/hw/xfree86/os-support/bus/xf86Pci.h +++ b/hw/xfree86/os-support/bus/xf86Pci.h @@ -766,6 +766,7 @@ void pciSetBitsByte(PCITAG tag, int offset, CARD8 mask, CARD8 val); ADDRESS pciBusAddrToHostAddr(PCITAG tag, PciAddrType type, ADDRESS addr); ADDRESS pciHostAddrToBusAddr(PCITAG tag, PciAddrType type, ADDRESS addr); PCITAG pciTag(int busnum, int devnum, int funcnum); +PCITAG pciDomTag(int domnum, int busnum, int devnum, int funcnum); int pciGetBaseSize(PCITAG tag, int indx, Bool destructive, Bool *min); CARD32 pciCheckForBrokenBase(PCITAG tag,int basereg); pointer xf86MapPciMem(int ScreenNum, int Flags, PCITAG Tag, diff --git a/hw/xfree86/os-support/linux/lnx_pci.c b/hw/xfree86/os-support/linux/lnx_pci.c index a1dbc7604..aff6bb0ae 100644 --- a/hw/xfree86/os-support/linux/lnx_pci.c +++ b/hw/xfree86/os-support/linux/lnx_pci.c @@ -3,7 +3,9 @@ #include #endif +#include #include +#include #include #include "os.h" #include "xf86.h" @@ -25,8 +27,10 @@ int lnxPciInit(void); struct pci_dev { + unsigned int domain; unsigned int bus; - unsigned int devfn; + unsigned int dev; + unsigned int fn; PCIADDR_TYPE offset[7]; PCIADDR_TYPE size[7]; struct pci_dev *next; @@ -38,10 +42,53 @@ int xf86OSLinuxNumPciDevs = 0; static struct pci_dev *xf86OSLinuxGetPciDevs(void) { char c[0x200]; FILE *file = NULL; + DIR *dir; + struct dirent *dirent; struct pci_dev *tmp, *ret = NULL; - unsigned int num; + unsigned int i, num, devfn; + unsigned PCIADDR_TYPE begin, end; char *res; + /* Try 2.6 devices first, with domain support */ + if ( (dir = opendir ("/sys/bus/pci/devices")) ) { + xf86OSLinuxNumPciDevs = 0; + while ( (dirent = readdir (dir)) ) { + unsigned int domain, bus, dev, fn; + if (sscanf (dirent->d_name, "%04x:%02x:%02x.%01x", + &domain, &bus, &dev, &fn) == 4) { + tmp = xcalloc (sizeof(struct pci_dev), 1); + tmp->domain = domain; + tmp->bus = bus; + tmp->dev = dev; + tmp->fn = fn; + sprintf (c, "/sys/bus/pci/devices/%12s/resource", + dirent->d_name); + i = 0; + if ( (file = fopen (c, "r")) ) { + while (i < 7 && fgets (c, 0x200, file)) { + if (sscanf (c, PCIADDR_FMT " " PCIADDR_FMT " " + PCIADDR_IGNORE_FMT, &begin, &end) == 2) { + tmp->offset[i] = begin; + tmp->size[i] = begin ? end-begin+1 : 0; + i++; + } + } + fclose (file); + } + if (i > 0) { + tmp->next = ret; + ret = tmp; + xf86OSLinuxNumPciDevs++; + } else + xfree (tmp); + } + } + closedir (dir); + } + + if (ret) + return ret; + file = fopen("/proc/bus/pci/devices", "r"); if (!file) return NULL; @@ -70,9 +117,11 @@ static struct pci_dev *xf86OSLinuxGetPciDevs(void) { "\t" PCIADDR_FMT "\t" PCIADDR_FMT "\t" PCIADDR_FMT, - &tmp->bus,&tmp->devfn,&tmp->offset[0],&tmp->offset[1],&tmp->offset[2],&tmp->offset[3], + &tmp->bus,&devfn,&tmp->offset[0],&tmp->offset[1],&tmp->offset[2],&tmp->offset[3], &tmp->offset[4],&tmp->offset[5],&tmp->offset[6], &tmp->size[0], &tmp->size[1], &tmp->size[2], &tmp->size[3], &tmp->size[4], &tmp->size[5], &tmp->size[6]); + tmp->dev = devfn >> 3; + tmp->fn = devfn & 0x7; if (num != 16) { /* apparantly not 2.3 style */ xfree(tmp); fclose(file); @@ -114,10 +163,8 @@ xf86GetPciSizeFromOS(PCITAG tag, int index, int* bits) return FALSE; for (device = xf86OSLinuxPCIDevs; device; device = device->next) { - dev = device->devfn >> 3; - fn = device->devfn & 0x7; - if (tag == pciTag(device->bus,dev,fn)) { - *bits = 0; + if (tag == pciDomTag (device->domain, device->bus, + device->dev, device->fn)) { if (device->size[index] != 0) { Size = device->size[index] - ((PCIADDR_TYPE) 1); while (Size & ((PCIADDR_TYPE) 0x01)) { @@ -151,9 +198,8 @@ xf86GetPciOffsetFromOS(PCITAG tag, int index, unsigned long* bases) return FALSE; for (device = xf86OSLinuxPCIDevs; device; device = device->next) { - dev = device->devfn >> 3; - fn = device->devfn & 0x7; - if (tag == pciTag(device->bus,dev,fn)) { + if (tag == pciDomTag (device->domain, device->bus, + device->dev, device->fn)) { /* return the offset for the index requested */ *bases = device->offset[index]; return TRUE; @@ -179,9 +225,8 @@ xf86GetOSOffsetFromPCI(PCITAG tag, int space, unsigned long base) } for (device = xf86OSLinuxPCIDevs; device; device = device->next) { - dev = device->devfn >> 3; - fn = device->devfn & 0x7; - if (tag == pciTag(device->bus, dev, fn)) { + if (tag == pciDomTag (device->domain, device->bus, + device->dev, device->fn)) { /* ok now look through all the BAR values of this device */ pciConfigPtr pDev = xf86GetPciConfigFromTag(tag);