Patch by Kevin E. Martin based off a patch from Dell, which changes the X server to use Linux native /proc based PCI interfaces by default instead of bitbanging PCI config space directly. Patch updated by Olivier Baudron to fix all occurrences of PCI config space access. This fixes a problem in Linux where other software may be probing PCI config space using the native interfaces correctly and the kernel PCI lock is held, then the X server starts up and simultaneously stomps on PCI space, generally causing the machine to hang. Fixes bugs: https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=152608 https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=118130 This may also fix the following bugs (unconfirmed): https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=146386 Update: This is a forward port of a patch we added to XFree86-4.3.0 for RHEL-3. The only modification is the changes to xf86Globals.c were dropped, as they're included in xorg-x11 stock code already. Mike A. Harris This bug is nominated for the 6.8.3 release as attachment 2285. https://bugs.freedesktop.org/show_bug.cgi?id=2880 --- xc/programs/Xserver/hw/xfree86/os-support/bus/Pci.h.use-linux-native-pciscan-by-default 2005-09-19 14:05:14.000000000 -0400 +++ xc/programs/Xserver/hw/xfree86/os-support/bus/Pci.h 2005-09-19 14:29:20.000000000 -0400 @@ -190,8 +190,11 @@ ((val >> 8) & 0x0000ff00) | \ ((val << 8) & 0x00ff0000) | \ ((val << 24) & 0xff000000)) +#define PCI_CPU16(val) (((val >> 8) & 0x000000ff) | \ + ((val << 8) & 0x0000ff00)) #else #define PCI_CPU(val) (val) +#define PCI_CPU16(val) (val) #endif /* @@ -379,6 +382,14 @@ void (*pciGetBridgeBuses)(int, int *, int *, int *); /* Use pointer's to avoid #include recursion */ void (*pciGetBridgeResources)(int, pointer *, pointer *, pointer *); + + /* These are optional and will be implemented using read long + * if not present. */ + CARD8 (*pciReadByte)(PCITAG, int); + void (*pciWriteByte)(PCITAG, int, CARD8); + CARD16 (*pciReadWord)(PCITAG, int); + void (*pciWriteWord)(PCITAG, int, CARD16); + } pciBusFuncs_t, *pciBusFuncs_p; /* --- xc/programs/Xserver/hw/xfree86/os-support/bus/linuxPci.c.use-linux-native-pciscan-by-default 2004-12-15 00:48:20.000000000 -0500 +++ xc/programs/Xserver/hw/xfree86/os-support/bus/linuxPci.c 2005-09-19 14:34:38.000000000 -0400 @@ -60,12 +60,28 @@ static void linuxPciCfgWrite(PCITAG, int off, CARD32 val); static void linuxPciCfgSetBits(PCITAG tag, int off, CARD32 mask, CARD32 bits); +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, /* pciAddrHostToBus */ pciAddrNOOP, -/* pciAddrBusToHost */ pciAddrNOOP +/* pciAddrBusToHost */ pciAddrNOOP, + +/* pciControlBridge */ NULL, +/* pciGetBridgeBuses */ NULL, +/* pciGetBridgeResources */ NULL, + +/* pciReadByte */ linuxPciCfgReadByte, +/* pciWriteByte */ linuxPciCfgWriteByte, + +/* pciReadWord */ linuxPciCfgReadWord, +/* pciWriteWord */ linuxPciCfgWriteWord, + }; static pciBusInfo_t linuxPci0 = { @@ -179,6 +195,57 @@ } } +static CARD8 +linuxPciCfgReadByte(PCITAG tag, int off) +{ + int fd; + CARD8 val = 0xff; + + if (-1 != (fd = linuxPciOpenFile(tag))) { + 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))) { + 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))) { + 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))) { + lseek(fd, off, SEEK_SET); + val = PCI_CPU16(val); + write(fd, &val, 2); + } +} + #ifndef INCLUDE_XF86_NO_DOMAIN /* --- xc/programs/Xserver/hw/xfree86/os-support/bus/Pci.c.use-linux-native-pciscan-by-default 2004-12-15 00:52:16.000000000 -0500 +++ xc/programs/Xserver/hw/xfree86/os-support/bus/Pci.c 2005-09-19 14:05:15.000000000 -0400 @@ -322,14 +322,24 @@ CARD32 tmp; int shift = (offset & 3) * 8; int aligned_offset = offset & ~3; + int bus = PCI_BUS_FROM_TAG(tag); if (shift != 0 && shift != 16) FatalError("pciReadWord: Alignment error: Cannot read 16 bits " "at offset %d\n", offset); - tmp = pciReadLong(tag, aligned_offset); + pciInit(); + + if ((bus >= 0) && ((bus < pciNumBuses) || inProbe) && pciBusInfo[bus] && + pciBusInfo[bus]->funcs->pciReadWord) { + CARD32 rv = (*pciBusInfo[bus]->funcs->pciReadWord)(tag, offset); + + return(rv); + } else { + tmp = pciReadLong(tag, aligned_offset); - return((CARD16)((tmp >> shift) & 0xffff)); + return((CARD16)((tmp >> shift) & 0xffff)); + } } CARD8 @@ -338,10 +348,20 @@ CARD32 tmp; int shift = (offset & 3) * 8; int aligned_offset = offset & ~3; + int bus = PCI_BUS_FROM_TAG(tag); + + pciInit(); - tmp = pciReadLong(tag, aligned_offset); + if ((bus >= 0) && ((bus < pciNumBuses) || inProbe) && pciBusInfo[bus] && + pciBusInfo[bus]->funcs->pciReadByte) { + CARD8 rv = (*pciBusInfo[bus]->funcs->pciReadByte)(tag, offset); + + return(rv); + } else { + tmp = pciReadLong(tag, aligned_offset); - return((CARD8)((tmp >> shift) & 0xff)); + return((CARD8)((tmp >> shift) & 0xff)); + } } void @@ -362,17 +382,25 @@ CARD32 tmp; int aligned_offset = offset & ~3; int shift = (offset & 3) * 8; + int bus = PCI_BUS_FROM_TAG(tag); if (shift != 0 && shift != 16) FatalError("pciWriteWord: Alignment Error: Cannot read 16 bits " "from offset %d\n", offset); - tmp = pciReadLong(tag, aligned_offset); + pciInit(); - tmp &= ~(0xffffL << shift); - tmp |= (((CARD32)val) << shift); + if ((bus >= 0) && (bus < pciNumBuses) && pciBusInfo[bus] && + pciBusInfo[bus]->funcs->pciWriteWord) { + (*pciBusInfo[bus]->funcs->pciWriteWord)(tag, offset, val); + } else { + tmp = pciReadLong(tag, aligned_offset); - pciWriteLong(tag, aligned_offset, tmp); + tmp &= ~(0xffffL << shift); + tmp |= (((CARD32)val) << shift); + + pciWriteLong(tag, aligned_offset, tmp); + } } void @@ -381,13 +409,22 @@ CARD32 tmp; int aligned_offset = offset & ~3; int shift = (offset & 3) *8 ; + int bus = PCI_BUS_FROM_TAG(tag); - tmp = pciReadLong(tag, aligned_offset); + pciInit(); - tmp &= ~(0xffL << shift); - tmp |= (((CARD32)val) << shift); + if ((bus >= 0) && (bus < pciNumBuses) && pciBusInfo[bus] && + pciBusInfo[bus]->funcs->pciWriteByte) { + (*pciBusInfo[bus]->funcs->pciWriteByte)(tag, offset, val); + } else { - pciWriteLong(tag, aligned_offset, tmp); + tmp = pciReadLong(tag, aligned_offset); + + tmp &= ~(0xffL << shift); + tmp |= (((CARD32)val) << shift); + + pciWriteLong(tag, aligned_offset, tmp); + } } void --- xc/programs/Xserver/hw/xfree86/int10/helper_exec.c.use-linux-native-pciscan-by-default 2004-04-23 15:54:06.000000000 -0400 +++ xc/programs/Xserver/hw/xfree86/int10/helper_exec.c 2005-09-19 14:05:15.000000000 -0400 @@ -23,10 +23,12 @@ #include "int10Defines.h" #include "xf86int10.h" -#if !defined (_PC) && !defined (_PC_PCI) static int pciCfg1in(CARD16 addr, CARD32 *val); static int pciCfg1out(CARD16 addr, CARD32 val); -#endif +static int pciCfg1inw(CARD16 addr, CARD16 *val); +static int pciCfg1outw(CARD16 addr, CARD16 val); +static int pciCfg1inb(CARD16 addr, CARD8 *val); +static int pciCfg1outb(CARD16 addr, CARD8 val); #if defined (_PC) static void SetResetBIOSVars(xf86Int10InfoPtr pInt, Bool set); #endif @@ -321,7 +323,8 @@ } #endif /* __NOT_YET__ */ } else { - val = inb(Int10Current->ioBase + port); + if (!pciCfg1inb(port, &val)) + val = inb(Int10Current->ioBase + port); #ifdef PRINT_PORT ErrorF(" inb(%#x) = %2.2x\n", port, val); #endif @@ -343,7 +346,8 @@ (void)getsecs(&sec, &usec); val = (CARD16)(usec / 3); } else { - val = inw(Int10Current->ioBase + port); + if (!pciCfg1inw(port, &val)) + val = inw(Int10Current->ioBase + port); } #ifdef PRINT_PORT ErrorF(" inw(%#x) = %4.4x\n", port, val); @@ -380,7 +384,8 @@ #ifdef PRINT_PORT ErrorF(" outb(%#x, %2.2x)\n", port, val); #endif - outb(Int10Current->ioBase + port, val); + if (!pciCfg1outb(port, val)) + outb(Int10Current->ioBase + port, val); } } @@ -391,7 +396,8 @@ ErrorF(" outw(%#x, %4.4x)\n", port, val); #endif - outw(Int10Current->ioBase + port, val); + if (!pciCfg1outw(port, val)) + outw(Int10Current->ioBase + port, val); } CARD32 @@ -399,10 +405,8 @@ { CARD32 val; -#if !defined(_PC) && !defined(_PC_PCI) if (!pciCfg1in(port, &val)) -#endif - val = inl(Int10Current->ioBase + port); + val = inl(Int10Current->ioBase + port); #ifdef PRINT_PORT ErrorF(" inl(%#x) = %8.8x\n", port, val); @@ -417,10 +421,8 @@ ErrorF(" outl(%#x, %8.8x)\n", port, val); #endif -#if !defined(_PC) && !defined(_PC_PCI) if (!pciCfg1out(port, val)) -#endif - outl(Int10Current->ioBase + port, val); + outl(Int10Current->ioBase + port, val); } CARD8 @@ -459,7 +461,6 @@ (*Int10Current->mem->wl)(Int10Current, addr, val); } -#if !defined(_PC) && !defined(_PC_PCI) static CARD32 PciCfg1Addr = 0; #define TAG(Cfg1Addr) (Cfg1Addr & 0xffff00) @@ -487,12 +488,85 @@ return 1; } if (addr == 0xCFC) { - pciWriteLong(TAG(PciCfg1Addr), OFFSET(PciCfg1Addr),val); + pciWriteLong(TAG(PciCfg1Addr), OFFSET(PciCfg1Addr), val); + return 1; + } + return 0; +} + +static int +pciCfg1inw(CARD16 addr, CARD16 *val) +{ + int offset, shift; + + if ((addr >= 0xCF8) && (addr <= 0xCFB)) { + shift = (addr - 0xCF8) * 8; + *val = (PciCfg1Addr >> shift) & 0xffff; + return 1; + } + if ((addr >= 0xCFC) && (addr <= 0xCFF)) { + offset = addr - 0xCFC; + *val = pciReadWord(TAG(PciCfg1Addr), OFFSET(PciCfg1Addr) + offset); + return 1; + } + return 0; +} + +static int +pciCfg1outw(CARD16 addr, CARD16 val) +{ + int offset, shift; + + if ((addr >= 0xCF8) && (addr <= 0xCFB)) { + shift = (addr - 0xCF8) * 8; + PciCfg1Addr &= ~(0xffff << shift); + PciCfg1Addr |= ((CARD32) val) << shift; + return 1; + } + if ((addr >= 0xCFC) && (addr <= 0xCFF)) { + offset = addr - 0xCFC; + pciWriteWord(TAG(PciCfg1Addr), OFFSET(PciCfg1Addr) + offset, val); + return 1; + } + return 0; +} + +static int +pciCfg1inb(CARD16 addr, CARD8 *val) +{ + int offset, shift; + + if ((addr >= 0xCF8) && (addr <= 0xCFB)) { + shift = (addr - 0xCF8) * 8; + *val = (PciCfg1Addr >> shift) & 0xff; + return 1; + } + if ((addr >= 0xCFC) && (addr <= 0xCFF)) { + offset = addr - 0xCFC; + *val = pciReadByte(TAG(PciCfg1Addr), OFFSET(PciCfg1Addr) + offset); + return 1; + } + return 0; +} + +static int +pciCfg1outb(CARD16 addr, CARD8 val) +{ + int offset, shift; + + if ((addr >= 0xCF8) && (addr <= 0xCFB)) { + shift = (addr - 0xCF8) * 8; + PciCfg1Addr &= ~(0xff << shift); + PciCfg1Addr |= ((CARD32) val) << shift; + return 1; + } + if ((addr >= 0xCFC) && (addr <= 0xCFF)) { + offset = addr - 0xCFC; + pciWriteByte(TAG(PciCfg1Addr), OFFSET(PciCfg1Addr) + offset, val); return 1; } return 0; } -#endif CARD8 bios_checksum(CARD8 *start, int size)