Bug #6583: Only open /proc/bus/pci/devices once. (Bill Nottingham)

This commit is contained in:
Daniel Stone 2006-06-01 22:30:52 +00:00
parent a9ed5a8790
commit 56f21bda1c
3 changed files with 166 additions and 183 deletions

View File

@ -94,6 +94,10 @@
* os/utils.c: * os/utils.c:
Remove LBX. Goodbye. Remove LBX. Goodbye.
* hw/xfree86/os-support/bus/linuxPci.c:
* hw/xfree86/os-support/linux/lnx_pci.c:
Bug #6583: Only parse /proc/bus/pci/devices once. (Bill Nottingham)
2006-05-30 Matthieu Herrb <matthieu.herrb@laas.fr> 2006-05-30 Matthieu Herrb <matthieu.herrb@laas.fr>
* hw/xfree86/os-support/bsd/Makefile.am: * hw/xfree86/os-support/bsd/Makefile.am:

View File

@ -130,32 +130,45 @@ linuxPciOpenFile(PCITAG tag, Bool write)
{ {
static int lbus,ldev,lfunc,fd = -1,is_write = 0; static int lbus,ldev,lfunc,fd = -1,is_write = 0;
int bus, dev, func; int bus, dev, func;
char file[32]; char file[64];
struct stat ignored; struct stat ignored;
static int is26 = -1;
bus = PCI_BUS_FROM_TAG(tag); bus = PCI_BUS_FROM_TAG(tag);
dev = PCI_DEV_FROM_TAG(tag); dev = PCI_DEV_FROM_TAG(tag);
func = PCI_FUNC_FROM_TAG(tag); func = PCI_FUNC_FROM_TAG(tag);
if (is26 == -1) {
if (stat("/sys/bus/pci",&ignored) < 0)
is26 = 0;
else
is26 = 1;
}
if (fd == -1 || (write && (!is_write)) if (fd == -1 || (write && (!is_write))
|| bus != lbus || dev != ldev || func != lfunc) { || bus != lbus || dev != ldev || func != lfunc) {
if (fd != -1) if (fd != -1)
close(fd); close(fd);
if (bus < 256) { if (is26)
sprintf(file,"/proc/bus/pci/%02x",bus); sprintf(file,"/sys/bus/pci/devices/0000:%02x:%02x.%01x/config",
if (stat(file, &ignored) < 0) bus, dev, func);
sprintf(file, "/proc/bus/pci/0000:%02x/%02x.%1x", else {
bus, dev, func); if (bus < 256) {
else sprintf(file,"/proc/bus/pci/%02x",bus);
sprintf(file, "/proc/bus/pci/%02x/%02x.%1x", if (stat(file, &ignored) < 0)
bus, dev, func); sprintf(file, "/proc/bus/pci/0000:%02x/%02x.%1x",
} else { bus, dev, func);
sprintf(file,"/proc/bus/pci/%04x",bus); else
if (stat(file, &ignored) < 0) sprintf(file, "/proc/bus/pci/%02x/%02x.%1x",
sprintf(file, "/proc/bus/pci/0000:%04x/%02x.%1x", bus, dev, func);
bus, dev, func); } else {
else sprintf(file,"/proc/bus/pci/%04x",bus);
sprintf(file, "/proc/bus/pci/%04x/%02x.%1x", if (stat(file, &ignored) < 0)
bus, dev, func); 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) { if (write) {
fd = open(file,O_RDWR); fd = open(file,O_RDWR);

View File

@ -23,70 +23,99 @@
#define PCIADDR_FMT "%lx" #define PCIADDR_FMT "%lx"
#endif #endif
FILE *xf86OSLinuxPCIFile = NULL; struct pci_dev {
unsigned int bus;
unsigned int devfn;
PCIADDR_TYPE offset[7];
PCIADDR_TYPE size[7];
struct pci_dev *next;
};
struct pci_dev *xf86OSLinuxPCIDevs = NULL;
static struct pci_dev *xf86OSLinuxGetPciDevs(void) {
char c[0x200];
FILE *file = NULL;
struct pci_dev *tmp, *ret = NULL;
unsigned int num;
char *res;
file = fopen("/proc/bus/pci/devices", "r");
if (!file) return NULL;
do {
res = fgets(c, 0x1ff, file);
if (res) {
tmp = xcalloc(sizeof(struct pci_dev),1);
num = sscanf(res,
/*bus+dev vendorid deviceid irq */
"%02x%02x\t%*04x%*04x\t%*x"
/* 7 PCI resource base addresses */
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
/* 7 PCI resource sizes, and then optionally a driver name */
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
"\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->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]);
if (num != 16) { /* apparantly not 2.3 style */
xfree(tmp);
fclose(file);
return NULL;
}
if (ret) {
tmp->next = ret;
}
ret = tmp;
}
} while (res);
fclose(file);
return ret;
}
Bool Bool
xf86GetPciSizeFromOS(PCITAG tag, int index, int* bits) xf86GetPciSizeFromOS(PCITAG tag, int index, int* bits)
{ {
char c[0x200]; unsigned int dev, fn;
char *res;
unsigned int bus, devfn, dev, fn;
unsigned PCIADDR_TYPE size[7];
unsigned int num;
signed PCIADDR_TYPE Size; signed PCIADDR_TYPE Size;
struct pci_dev *device;
if (index > 7) if (index > 7)
return FALSE; return FALSE;
if (!xf86OSLinuxPCIFile && \ if (!xf86OSLinuxPCIDevs) {
!(xf86OSLinuxPCIFile = fopen("/proc/bus/pci/devices","r"))) xf86OSLinuxPCIDevs = xf86OSLinuxGetPciDevs();
return FALSE; }
do { if (!xf86OSLinuxPCIDevs)
res = fgets(c,0x1ff,xf86OSLinuxPCIFile); return FALSE;
if (res) {
num = sscanf(res, for (device = xf86OSLinuxPCIDevs; device; device = device->next) {
/*bus+dev vendorid deviceid irq */ dev = device->devfn >> 3;
"%02x%02x\t%*04x%*04x\t%*x" fn = device->devfn & 0x7;
/* 7 PCI resource base addresses */ if (tag == pciTag(device->bus,dev,fn)) {
"\t" PCIADDR_IGNORE_FMT *bits = 0;
"\t" PCIADDR_IGNORE_FMT if (device->size[index] != 0) {
"\t" PCIADDR_IGNORE_FMT Size = device->size[index] - ((PCIADDR_TYPE) 1);
"\t" PCIADDR_IGNORE_FMT while (Size & ((PCIADDR_TYPE) 0x01)) {
"\t" PCIADDR_IGNORE_FMT Size = Size >> ((PCIADDR_TYPE) 1);
"\t" PCIADDR_IGNORE_FMT (*bits)++;
"\t" PCIADDR_IGNORE_FMT }
/* 7 PCI resource sizes, and then optionally a driver name */ }
"\t" PCIADDR_FMT return TRUE;
"\t" PCIADDR_FMT }
"\t" PCIADDR_FMT }
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT,
&bus,&devfn,&size[0],&size[1],&size[2],&size[3],
&size[4],&size[5],&size[6]);
if (num != 9) { /* apparantly not 2.3 style */
fseek(xf86OSLinuxPCIFile, 0L, SEEK_SET);
return FALSE;
}
dev = devfn >> 3;
fn = devfn & 0x7;
if (tag == pciTag(bus,dev,fn)) {
*bits = 0;
if (size[index] != 0) {
Size = size[index] - ((PCIADDR_TYPE) 1);
while (Size & ((PCIADDR_TYPE) 0x01)) {
Size = Size >> ((PCIADDR_TYPE) 1);
(*bits)++;
}
}
fseek(xf86OSLinuxPCIFile, 0L, SEEK_SET);
return TRUE;
}
}
} while (res);
fseek(xf86OSLinuxPCIFile, 0L, SEEK_SET);
return FALSE; return FALSE;
} }
@ -96,59 +125,28 @@ xf86GetPciSizeFromOS(PCITAG tag, int index, int* bits)
Bool Bool
xf86GetPciOffsetFromOS(PCITAG tag, int index, unsigned long* bases) xf86GetPciOffsetFromOS(PCITAG tag, int index, unsigned long* bases)
{ {
FILE *file; unsigned int dev, fn;
char c[0x200]; struct pci_dev *device;
char *res;
unsigned int bus, devfn, dev, fn;
unsigned PCIADDR_TYPE offset[7];
unsigned int num;
if (index > 7) if (index > 7)
return FALSE; return FALSE;
if (!(file = fopen("/proc/bus/pci/devices","r"))) if (!xf86OSLinuxPCIDevs) {
xf86OSLinuxPCIDevs = xf86OSLinuxGetPciDevs();
}
if (!xf86OSLinuxPCIDevs)
return FALSE; return FALSE;
do {
res = fgets(c,0x1ff,file);
if (res) {
num = sscanf(res,
/*bus+dev vendorid deviceid irq */
"%02x%02x\t%*04x%*04x\t%*x"
/* 7 PCI resource base addresses */
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
/* 7 PCI resource sizes, and then optionally a driver name */
"\t" PCIADDR_IGNORE_FMT
"\t" PCIADDR_IGNORE_FMT
"\t" PCIADDR_IGNORE_FMT
"\t" PCIADDR_IGNORE_FMT
"\t" PCIADDR_IGNORE_FMT
"\t" PCIADDR_IGNORE_FMT
"\t" PCIADDR_IGNORE_FMT,
&bus,&devfn,&offset[0],&offset[1],&offset[2],&offset[3],
&offset[4],&offset[5],&offset[6]);
if (num != 9) { /* apparantly not 2.3 style */
fclose(file);
return FALSE;
}
dev = devfn >> 3; for (device = xf86OSLinuxPCIDevs; device; device = device->next) {
fn = devfn & 0x7; dev = device->devfn >> 3;
if (tag == pciTag(bus,dev,fn)) { fn = device->devfn & 0x7;
/* return the offset for the index requested */ if (tag == pciTag(device->bus,dev,fn)) {
*bases = offset[index]; /* return the offset for the index requested */
fclose(file); *bases = device->offset[index];
return TRUE; return TRUE;
}
} }
} while (res); }
fclose(file);
return FALSE; return FALSE;
} }
@ -156,81 +154,49 @@ xf86GetPciOffsetFromOS(PCITAG tag, int index, unsigned long* bases)
unsigned long unsigned long
xf86GetOSOffsetFromPCI(PCITAG tag, int space, unsigned long base) xf86GetOSOffsetFromPCI(PCITAG tag, int space, unsigned long base)
{ {
FILE *file; unsigned int dev, fn;
char c[0x200];
char *res;
unsigned int bus, devfn, dev, fn;
unsigned PCIADDR_TYPE offset[7];
unsigned PCIADDR_TYPE size[7];
unsigned int num;
unsigned int ndx; unsigned int ndx;
struct pci_dev *device;
if (!(file = fopen("/proc/bus/pci/devices","r"))) if (!xf86OSLinuxPCIDevs) {
return 0; xf86OSLinuxPCIDevs = xf86OSLinuxGetPciDevs();
do { }
res = fgets(c,0x1ff,file); if (!xf86OSLinuxPCIDevs) {
if (res) { return FALSE;
num = sscanf(res, }
/*bus+dev vendorid deviceid irq */
"%02x%02x\t%*04x%*04x\t%*x"
/* 7 PCI resource base addresses */
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
/* 7 PCI resource sizes, and then optionally a driver name */
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT
"\t" PCIADDR_FMT,
&bus,&devfn,&offset[0],&offset[1],&offset[2],&offset[3],
&offset[4],&offset[5],&offset[6], &size[0], &size[1], &size[2],
&size[3], &size[4], &size[5], &size[6]);
if (num != 16) { /* apparantly not 2.3 style */
fclose(file);
return 0;
}
dev = devfn >> 3; for (device = xf86OSLinuxPCIDevs; device; device = device->next) {
fn = devfn & 0x7; dev = device->devfn >> 3;
if (tag == pciTag(bus,dev,fn)) { fn = device->devfn & 0x7;
/* ok now look through all the BAR values of this device */ if (tag == pciTag(device->bus, dev, fn)) {
pciConfigPtr pDev = xf86GetPciConfigFromTag(tag); /* ok now look through all the BAR values of this device */
pciConfigPtr pDev = xf86GetPciConfigFromTag(tag);
for (ndx=0; ndx<7; ndx++) { for (ndx=0; ndx<7; ndx++) {
unsigned long savePtr, flagMask; unsigned long savePtr, flagMask;
if (ndx == 6) if (ndx == 6)
savePtr = pDev->pci_baserom; savePtr = pDev->pci_baserom;
else /* this the ROM bar */ else /* this the ROM bar */
savePtr = (&pDev->pci_base0)[ndx]; savePtr = (&pDev->pci_base0)[ndx];
/* Ignore unset base addresses. The kernel may /* Ignore unset base addresses. The kernel may
* have reported non-zero size and address even * have reported non-zero size and address even
* if they are disabled (e.g. disabled ROM BAR). * if they are disabled (e.g. disabled ROM BAR).
*/ */
if (savePtr == 0) if (savePtr == 0)
continue; continue;
/* Remove memory attribute bits, different for IO /* Remove memory attribute bits, different for IO
* and memory ranges. */ * and memory ranges. */
flagMask = (savePtr & 0x1) ? ~0x3UL : ~0xFUL; flagMask = (savePtr & 0x1) ? ~0x3UL : ~0xFUL;
savePtr &= flagMask; savePtr &= flagMask;
/* find the index of the incoming base */ /* find the index of the incoming base */
if (base >= savePtr && base < (savePtr + size[ndx])) { if (base >= savePtr && base < (savePtr + device->size[ndx])) {
fclose(file); return (device->offset[ndx] & flagMask) + (base - savePtr);
return (offset[ndx] & flagMask) + (base - savePtr);
}
} }
} }
} }
} while (res); };
fclose(file);
return 0; return 0;
} }