#include <stdio.h>
#include "compiler.h"
#include "xf86.h"
#include "xf86Priv.h"
#include "xf86_OSlib.h"
#include "Pci.h"
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 pciBusFuncs_t linuxFuncs0 = {
linuxPciCfgRead,
linuxPciCfgWrite,
linuxPciCfgSetBits,
pciAddrNOOP,
pciAddrNOOP
};
static pciBusInfo_t linuxPci0 = {
PCI_CFG_MECH_OTHER,
32,
FALSE,
0,
#ifdef PowerMAX_OS
0,
0,
#endif
&linuxFuncs0,
NULL,
NULL
};
void
linuxPciInit()
{
struct stat st;
if ((xf86Info.pciFlags == PCIForceNone) ||
(-1 == stat("/proc/bus/pci", &st))) {
return;
}
pciNumBuses = 1;
pciBusInfo[0] = &linuxPci0;
pciFindFirstFP = pciGenFindFirst;
pciFindNextFP = pciGenFindNext;
}
static int
linuxPciOpenFile(PCITAG tag)
{
static int lbus,ldev,lfunc,fd = -1;
int bus, dev, func;
char file[32];
bus = PCI_BUS_FROM_TAG(tag);
dev = PCI_DEV_FROM_TAG(tag);
func = PCI_FUNC_FROM_TAG(tag);
if (fd == -1 || bus != lbus || dev != ldev || func != lfunc) {
if (fd != -1)
close(fd);
if (bus < 256)
sprintf(file, "/proc/bus/pci/%02x/%02x.%1x",
bus, dev, func);
else
sprintf(file, "/proc/bus/pci/%04x/%02x.%1x",
bus, dev, func);
fd = open(file,O_RDWR);
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))) {
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))) {
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))) {
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);
}
}
#ifndef INCLUDE_XF86_NO_DOMAIN
#include <linux/pci.h>
#ifndef PCIIOC_BASE
#define PCIIOC_BASE ('P' << 24 | 'C' << 16 | 'I' << 8)
#define PCIIOC_CONTROLLER (PCIIOC_BASE | 0x00)
#define PCIIOC_MMAP_IS_IO (PCIIOC_BASE | 0x01)
#define PCIIOC_MMAP_IS_MEM (PCIIOC_BASE | 0x02)
#define PCIIOC_WRITE_COMBINE (PCIIOC_BASE | 0x03)
#endif
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;
}
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;
if ((pPCI = xf86GetPciHostConfigFromTag(Tag))) {
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;
}
static void
linuxGetSizes(PCITAG Tag, unsigned long *io_size, unsigned long *mem_size)
{
pciConfigPtr pPCI;
int i;
*io_size = (1U << 16);
*mem_size = (unsigned long)(1ULL << 32);
if ((pPCI = xf86GetPciHostConfigFromTag(Tag))) {
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 ((fd = linuxPciOpenFile(pPCI ? pPCI->tag : 0)) < 0)
return 0;
if ((result = ioctl(fd, PCIIOC_CONTROLLER, 0)) < 0)
return 0;
return result + 1;
}
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)) < 0) ||
(ioctl(fd, mmap_ioctl, 0) < 0))
break;
#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
mmapflags = (Flags & VIDMEM_FRAMEBUFFER) / VIDMEM_FRAMEBUFFER;
if (ioctl(fd, PCIIOC_WRITE_COMBINE, mmapflags) < 0)
break;
mmapflags = MAP_SHARED;
#endif
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))
FatalError("linuxMapPci() mmap failure: %s\n", strerror(errno));
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;
}
pointer
xf86MapDomainMemory(int ScreenNum, int Flags, PCITAG Tag,
ADDRESS Base, unsigned long Size)
{
return linuxMapPci(ScreenNum, Flags, Tag, Base, Size, PCIIOC_MMAP_IS_MEM);
}
#define MAX_DOMAINS 257
static pointer DomainMmappedIO[MAX_DOMAINS];
IOADDRESS
xf86MapDomainIO(int ScreenNum, int Flags, PCITAG Tag,
IOADDRESS Base, unsigned long Size)
{
int domain = xf86GetPciDomain(Tag);
if ((domain <= 0) || (domain >= MAX_DOMAINS))
FatalError("xf86MapDomainIO(): domain out of range\n");
if (!DomainMmappedIO[domain]) {
DomainMmappedIO[domain] = linuxMapPci(ScreenNum, Flags, Tag,
0, linuxGetIOSize(Tag),
PCIIOC_MMAP_IS_IO);
if (!DomainMmappedIO[domain])
FatalError("xf86MapDomainIO(): mmap() failure\n");
}
return (IOADDRESS)DomainMmappedIO[domain] + Base;
}
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;
offset = Base & ~pagemask;
size = ((Base + Len + pagemask) & ~pagemask) - offset;
ptr = xf86MapDomainMemory(-1, VIDMEM_READONLY, Tag, offset, size);
if (!ptr)
return -1;
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);
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