Initial commit
[xorg_rtime.git] / xorg-server-1.4 / hw / xfree86 / os-support / bus / linuxPci.c
blob9a9a99d49f24a0eb560da60d31c34174baa1e308
1 /*
2 * Copyright 1998 by Concurrent Computer Corporation
4 * Permission to use, copy, modify, distribute, and sell this software
5 * and its documentation for any purpose is hereby granted without fee,
6 * provided that the above copyright notice appear in all copies and that
7 * both that copyright notice and this permission notice appear in
8 * supporting documentation, and that the name of Concurrent Computer
9 * Corporation not be used in advertising or publicity pertaining to
10 * distribution of the software without specific, written prior
11 * permission. Concurrent Computer Corporation makes no representations
12 * about the suitability of this software for any purpose. It is
13 * provided "as is" without express or implied warranty.
15 * CONCURRENT COMPUTER CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD
16 * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
17 * AND FITNESS, IN NO EVENT SHALL CONCURRENT COMPUTER CORPORATION BE
18 * LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
19 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
22 * SOFTWARE.
24 * Copyright 1998 by Metro Link Incorporated
26 * Permission to use, copy, modify, distribute, and sell this software
27 * and its documentation for any purpose is hereby granted without fee,
28 * provided that the above copyright notice appear in all copies and that
29 * both that copyright notice and this permission notice appear in
30 * supporting documentation, and that the name of Metro Link
31 * Incorporated not be used in advertising or publicity pertaining to
32 * distribution of the software without specific, written prior
33 * permission. Metro Link Incorporated makes no representations
34 * about the suitability of this software for any purpose. It is
35 * provided "as is" without express or implied warranty.
37 * METRO LINK INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD
38 * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
39 * AND FITNESS, IN NO EVENT SHALL METRO LINK INCORPORATED BE
40 * LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
41 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44 * SOFTWARE.
47 #ifdef HAVE_XORG_CONFIG_H
48 #include <xorg-config.h>
49 #endif
51 #include <stdio.h>
52 #include "compiler.h"
53 #include "xf86.h"
54 #include "xf86Priv.h"
55 #include "xf86_OSlib.h"
56 #include "Pci.h"
57 #include <dirent.h>
60 * linux platform specific PCI access functions -- using /proc/bus/pci
61 * needs kernel version 2.2.x
63 static CARD32 linuxPciCfgRead(PCITAG tag, int off);
64 static void linuxPciCfgWrite(PCITAG, int off, CARD32 val);
65 static void linuxPciCfgSetBits(PCITAG tag, int off, CARD32 mask, CARD32 bits);
66 static ADDRESS linuxTransAddrBusToHost(PCITAG tag, PciAddrType type, ADDRESS addr);
67 #if defined(__powerpc__)
68 static ADDRESS linuxPpcBusAddrToHostAddr(PCITAG, PciAddrType, ADDRESS);
69 static ADDRESS linuxPpcHostAddrToBusAddr(PCITAG, PciAddrType, ADDRESS);
70 #endif
72 static CARD8 linuxPciCfgReadByte(PCITAG tag, int off);
73 static void linuxPciCfgWriteByte(PCITAG tag, int off, CARD8 val);
74 static CARD16 linuxPciCfgReadWord(PCITAG tag, int off);
75 static void linuxPciCfgWriteWord(PCITAG tag, int off, CARD16 val);
76 static int linuxPciHandleBIOS(PCITAG Tag, int basereg, unsigned char *buf, int len);
77 static Bool linuxDomainSupport(void);
79 static pciBusFuncs_t linuxFuncs0 = {
80 /* pciReadLong */ linuxPciCfgRead,
81 /* pciWriteLong */ linuxPciCfgWrite,
82 /* pciSetBitsLong */ linuxPciCfgSetBits,
83 #if defined(__powerpc__)
84 /* pciAddrHostToBus */ linuxPpcHostAddrToBusAddr,
85 /* pciAddrBusToHost */ linuxPpcBusAddrToHostAddr,
86 #else
87 /* pciAddrHostToBus */ pciAddrNOOP,
88 /* linuxTransAddrBusToHost is busted on sparc64 but the PCI rework tree
89 * makes it all moot, so we kludge it for now */
90 #if defined(__sparc__)
91 /* pciAddrBusToHost */ pciAddrNOOP,
92 #else
93 /* pciAddrBusToHost */ linuxTransAddrBusToHost,
94 #endif /* __sparc64__ */
95 #endif
97 /* pciControlBridge */ NULL,
98 /* pciGetBridgeBuses */ NULL,
99 /* pciGetBridgeResources */ NULL,
101 /* pciReadByte */ linuxPciCfgReadByte,
102 /* pciWriteByte */ linuxPciCfgWriteByte,
104 /* pciReadWord */ linuxPciCfgReadWord,
105 /* pciWriteWord */ linuxPciCfgWriteWord,
108 static pciBusInfo_t linuxPci0 = {
109 /* configMech */ PCI_CFG_MECH_OTHER,
110 /* numDevices */ 32,
111 /* secondary */ FALSE,
112 /* primary_bus */ 0,
113 /* funcs */ &linuxFuncs0,
114 /* pciBusPriv */ NULL,
115 /* bridge */ NULL
118 /* from lnx_pci.c. */
119 extern int lnxPciInit(void);
121 static Bool domain_support = FALSE;
123 void
124 linuxPciInit()
126 struct stat st;
127 if ((xf86Info.pciFlags == PCIForceNone) ||
128 (-1 == stat("/proc/bus/pci", &st))) {
129 /* when using this as default for all linux architectures,
130 we'll need a fallback for 2.0 kernels here */
131 return;
133 #ifndef INCLUDE_XF86_NO_DOMAIN
134 domain_support = linuxDomainSupport();
135 #endif
136 pciNumBuses = 1;
137 pciBusInfo[0] = &linuxPci0;
138 pciFindFirstFP = pciGenFindFirst;
139 pciFindNextFP = pciGenFindNext;
140 pciSetOSBIOSPtr(linuxPciHandleBIOS);
141 xf86MaxPciDevs = lnxPciInit();
144 static int
145 linuxPciOpenFile(PCITAG tag, Bool write)
147 static int ldomain, lbus,ldev,lfunc,fd = -1,is_write = 0;
148 int domain, bus, dev, func;
149 char file[64];
150 struct stat ignored;
151 static int is26 = -1;
153 domain = PCI_DOM_FROM_TAG(tag);
154 bus = PCI_BUS_NO_DOMAIN(PCI_BUS_FROM_TAG(tag));
155 dev = PCI_DEV_FROM_TAG(tag);
156 func = PCI_FUNC_FROM_TAG(tag);
157 if (is26 == -1) {
158 if (stat("/sys/bus/pci",&ignored) < 0)
159 is26 = 0;
160 else
161 is26 = 1;
164 if (!domain_support && domain > 0)
165 return -1;
167 if (fd == -1 || (write && (!is_write)) || domain != ldomain
168 || bus != lbus || dev != ldev || func != lfunc) {
169 if (fd != -1) {
170 close(fd);
171 fd = -1;
173 if (is26)
174 sprintf(file,"/sys/bus/pci/devices/%04x:%02x:%02x.%01x/config",
175 domain, bus, dev, func);
176 else {
177 if (bus < 256) {
178 sprintf(file, "/proc/bus/pci/%04x:%02x", domain, bus);
179 if (stat(file, &ignored) < 0) {
180 if (domain == 0)
181 sprintf(file, "/proc/bus/pci/%02x/%02x.%1x",
182 bus, dev, func);
183 else
184 goto bail;
185 } else
186 sprintf(file, "/proc/bus/pci/%04x:%02x/%02x.%1x",
187 domain, bus, dev, func);
188 } else {
189 sprintf(file, "/proc/bus/pci/%04x:%04x", domain, bus);
190 if (stat(file, &ignored) < 0) {
191 if (domain == 0)
192 sprintf(file, "/proc/bus/pci/%04x/%02x.%1x",
193 bus, dev, func);
194 else
195 goto bail;
196 } else
197 sprintf(file, "/proc/bus/pci/%04x:%04x/%02x.%1x",
198 domain, bus, dev, func);
201 if (write) {
202 fd = open(file,O_RDWR);
203 if (fd != -1) is_write = TRUE;
204 } else switch (is_write) {
205 case TRUE:
206 fd = open(file,O_RDWR);
207 if (fd > -1)
208 break;
209 default:
210 fd = open(file,O_RDONLY);
211 is_write = FALSE;
213 bail:
214 ldomain = domain;
215 lbus = bus;
216 ldev = dev;
217 lfunc = func;
219 return fd;
222 static CARD32
223 linuxPciCfgRead(PCITAG tag, int off)
225 int fd;
226 CARD32 val = 0xffffffff;
228 if (-1 != (fd = linuxPciOpenFile(tag,FALSE))) {
229 lseek(fd,off,SEEK_SET);
230 read(fd,&val,4);
232 return PCI_CPU(val);
235 static void
236 linuxPciCfgWrite(PCITAG tag, int off, CARD32 val)
238 int fd;
240 if (-1 != (fd = linuxPciOpenFile(tag,TRUE))) {
241 lseek(fd,off,SEEK_SET);
242 val = PCI_CPU(val);
243 write(fd,&val,4);
247 static void
248 linuxPciCfgSetBits(PCITAG tag, int off, CARD32 mask, CARD32 bits)
250 int fd;
251 CARD32 val = 0xffffffff;
253 if (-1 != (fd = linuxPciOpenFile(tag,TRUE))) {
254 lseek(fd,off,SEEK_SET);
255 read(fd,&val,4);
256 val = PCI_CPU(val);
257 val = (val & ~mask) | (bits & mask);
258 val = PCI_CPU(val);
259 lseek(fd,off,SEEK_SET);
260 write(fd,&val,4);
265 * This function will convert a BAR address into a host address
266 * suitable for passing into the mmap function of a /proc/bus
267 * device.
269 ADDRESS linuxTransAddrBusToHost(PCITAG tag, PciAddrType type, ADDRESS addr)
271 ADDRESS ret = xf86GetOSOffsetFromPCI(tag, PCI_MEM|PCI_IO, addr);
273 if (ret)
274 return ret;
277 * if it is not a BAR address, it must be legacy, (or wrong)
278 * return it as is..
280 return addr;
284 #if defined(__powerpc__)
286 #ifndef __NR_pciconfig_iobase
287 #define __NR_pciconfig_iobase 200
288 #endif
290 static ADDRESS
291 linuxPpcBusAddrToHostAddr(PCITAG tag, PciAddrType type, ADDRESS addr)
293 if (type == PCI_MEM)
295 ADDRESS membase = syscall(__NR_pciconfig_iobase, 1,
296 PCI_BUS_FROM_TAG(tag), PCI_DFN_FROM_TAG(tag));
297 return (addr + membase);
299 else if (type == PCI_IO)
301 ADDRESS iobase = syscall(__NR_pciconfig_iobase, 2,
302 PCI_BUS_FROM_TAG(tag), PCI_DFN_FROM_TAG(tag));
303 return (addr + iobase);
305 else return addr;
308 static ADDRESS
309 linuxPpcHostAddrToBusAddr(PCITAG tag, PciAddrType type, ADDRESS addr)
311 if (type == PCI_MEM)
313 ADDRESS membase = syscall(__NR_pciconfig_iobase, 1,
314 PCI_BUS_FROM_TAG(tag), PCI_DFN_FROM_TAG(tag));
315 return (addr - membase);
317 else if (type == PCI_IO)
319 ADDRESS iobase = syscall(__NR_pciconfig_iobase, 2,
320 PCI_BUS_FROM_TAG(tag), PCI_DFN_FROM_TAG(tag));
321 return (addr - iobase);
323 else return addr;
326 #endif /* __powerpc__ */
328 static CARD8
329 linuxPciCfgReadByte(PCITAG tag, int off)
331 int fd;
332 CARD8 val = 0xff;
334 if (-1 != (fd = linuxPciOpenFile(tag,FALSE))) {
335 lseek(fd,off,SEEK_SET);
336 read(fd,&val,1);
339 return val;
342 static void
343 linuxPciCfgWriteByte(PCITAG tag, int off, CARD8 val)
345 int fd;
347 if (-1 != (fd = linuxPciOpenFile(tag,TRUE))) {
348 lseek(fd,off,SEEK_SET);
349 write(fd, &val, 1);
353 static CARD16
354 linuxPciCfgReadWord(PCITAG tag, int off)
356 int fd;
357 CARD16 val = 0xff;
359 if (-1 != (fd = linuxPciOpenFile(tag,FALSE))) {
360 lseek(fd, off, SEEK_SET);
361 read(fd, &val, 2);
364 return PCI_CPU16(val);
367 static void
368 linuxPciCfgWriteWord(PCITAG tag, int off, CARD16 val)
370 int fd;
372 if (-1 != (fd = linuxPciOpenFile(tag,TRUE))) {
373 lseek(fd, off, SEEK_SET);
374 val = PCI_CPU16(val);
375 write(fd, &val, 2);
379 #ifndef INCLUDE_XF86_NO_DOMAIN
382 * Compiling the following simply requires the presence of <linux/pci.c>.
383 * Actually running this is another matter altogether...
385 * This scheme requires that the kernel allow mmap()'ing of a host bridge's I/O
386 * and memory spaces through its /proc/bus/pci/BUS/DFN entry. Which one is
387 * determined by a prior ioctl().
389 * For the sparc64 port, this means 2.4.12 or later. For ppc, this
390 * functionality is almost, but not quite there yet. Alpha and other kernel
391 * ports to multi-domain architectures still need to implement this.
393 * This scheme is also predicated on the use of an IOADDRESS compatible type to
394 * designate I/O addresses. Although IOADDRESS is defined as an unsigned
395 * integral type, it is actually the virtual address of, i.e. a pointer to, the
396 * I/O port to access. And so, the inX/outX macros in "compiler.h" need to be
397 * #define'd appropriately (as is done on SPARC's).
399 * Another requirement to port this scheme to another multi-domain architecture
400 * is to add the appropriate entries in the pciControllerSizes array below.
402 * TO DO: Address the deleterious reaction some host bridges have to master
403 * aborts. This is already done for secondary PCI buses, but not yet
404 * for accesses to primary buses (except for the SPARC port, where
405 * master aborts are avoided during PCI scans).
408 #include <linux/pci.h>
410 #ifndef PCIIOC_BASE /* Ioctls for /proc/bus/pci/X/Y nodes. */
411 #define PCIIOC_BASE ('P' << 24 | 'C' << 16 | 'I' << 8)
413 /* Get controller for PCI device. */
414 #define PCIIOC_CONTROLLER (PCIIOC_BASE | 0x00)
415 /* Set mmap state to I/O space. */
416 #define PCIIOC_MMAP_IS_IO (PCIIOC_BASE | 0x01)
417 /* Set mmap state to MEM space. */
418 #define PCIIOC_MMAP_IS_MEM (PCIIOC_BASE | 0x02)
419 /* Enable/disable write-combining. */
420 #define PCIIOC_WRITE_COMBINE (PCIIOC_BASE | 0x03)
422 #endif
424 /* This probably shouldn't be Linux-specific */
425 static pciConfigPtr
426 xf86GetPciHostConfigFromTag(PCITAG Tag)
428 int bus = PCI_BUS_FROM_TAG(Tag);
429 pciBusInfo_t *pBusInfo;
431 while ((bus < pciNumBuses) && (pBusInfo = pciBusInfo[bus])) {
432 if (bus == pBusInfo->primary_bus)
433 return pBusInfo->bridge;
434 bus = pBusInfo->primary_bus;
437 return NULL; /* Bad data */
441 * This is ugly, but until I can extract this information from the kernel,
442 * it'll have to do. The default I/O space size is 64K, and 4G for memory.
443 * Anything else needs to go in this table. (PowerPC folk take note.)
445 * Note that Linux/SPARC userland is 32-bit, so 4G overflows to zero here.
447 * Please keep this table in ascending vendor/device order.
449 static const struct pciSizes {
450 unsigned short vendor, device;
451 unsigned long io_size, mem_size;
452 } pciControllerSizes[] = {
454 PCI_VENDOR_SUN, PCI_CHIP_PSYCHO,
455 1U << 16, 1U << 31
458 PCI_VENDOR_SUN, PCI_CHIP_SCHIZO,
459 1U << 24, 1U << 31 /* ??? */
462 PCI_VENDOR_SUN, PCI_CHIP_SABRE,
463 1U << 24, (unsigned long)(1ULL << 32)
466 PCI_VENDOR_SUN, PCI_CHIP_HUMMINGBIRD,
467 1U << 24, (unsigned long)(1ULL << 32)
470 #define NUM_SIZES (sizeof(pciControllerSizes) / sizeof(pciControllerSizes[0]))
472 static const struct pciSizes *
473 linuxGetSizesStruct(PCITAG Tag)
475 static const struct pciSizes default_size = {
476 0, 0, 1U << 16, (unsigned long)(1ULL << 32)
478 pciConfigPtr pPCI;
479 int i;
481 /* Find host bridge */
482 if ((pPCI = xf86GetPciHostConfigFromTag(Tag))) {
483 /* Look up vendor/device */
484 for (i = 0; i < NUM_SIZES; i++) {
485 if ((pPCI->pci_vendor == pciControllerSizes[i].vendor)
486 && (pPCI->pci_device == pciControllerSizes[i].device)) {
487 return & pciControllerSizes[i];
492 /* Default to 64KB I/O and 4GB memory. */
493 return & default_size;
496 static __inline__ unsigned long
497 linuxGetIOSize(PCITAG Tag)
499 const struct pciSizes * const sizes = linuxGetSizesStruct(Tag);
500 return sizes->io_size;
503 static __inline__ void
504 linuxGetSizes(PCITAG Tag, unsigned long *io_size, unsigned long *mem_size)
506 const struct pciSizes * const sizes = linuxGetSizesStruct(Tag);
508 *io_size = sizes->io_size;
509 *mem_size = sizes->mem_size;
512 static Bool
513 linuxDomainSupport(void)
515 DIR *dir;
516 struct dirent *dirent;
517 char *end;
519 if (!(dir = opendir("/proc/bus/pci")))
520 return FALSE;
521 while (1) {
522 if (!(dirent = readdir(dir)))
523 return FALSE;
524 strtol(dirent->d_name,&end,16);
525 /* entry of the form xx or xxxx : x=[0..f] no domain */
526 if (*end == '\0')
527 return FALSE;
528 else if (*end == ':') {
529 /* ':' found immediately after: verify for xxxx:xx or xxxx:xxxx */
530 strtol(end + 1,&end,16);
531 if (*end == '\0')
532 return TRUE;
535 return FALSE;
538 _X_EXPORT int
539 xf86GetPciDomain(PCITAG Tag)
541 pciConfigPtr pPCI;
542 int fd, result;
544 pPCI = xf86GetPciHostConfigFromTag(Tag);
546 if (pPCI && (result = PCI_DOM_FROM_BUS(pPCI->busnum)))
547 return result + 1;
549 if (!pPCI || pPCI->fakeDevice)
550 return 1; /* Domain 0 is reserved */
552 if ((fd = linuxPciOpenFile(pPCI ? pPCI->tag : 0,FALSE)) < 0)
553 return 0;
555 if ((result = ioctl(fd, PCIIOC_CONTROLLER, 0)) < 0)
556 return 0;
558 return result + 1; /* Domain 0 is reserved */
561 static pointer
562 linuxMapPci(int ScreenNum, int Flags, PCITAG Tag,
563 ADDRESS Base, unsigned long Size, int mmap_ioctl)
565 do {
566 pciConfigPtr pPCI;
567 unsigned char *result;
568 ADDRESS realBase, Offset;
569 int fd, mmapflags, prot;
571 xf86InitVidMem();
573 prot = ((Flags & VIDMEM_READONLY) == 0);
574 if (((fd = linuxPciOpenFile(Tag, prot)) < 0) ||
575 (ioctl(fd, mmap_ioctl, 0) < 0))
576 break;
578 /* Note: IA-64 doesn't compile this and doesn't need to */
579 #ifdef __ia64__
581 # ifndef MAP_WRITECOMBINED
582 # define MAP_WRITECOMBINED 0x00010000
583 # endif
584 # ifndef MAP_NONCACHED
585 # define MAP_NONCACHED 0x00020000
586 # endif
588 if (Flags & VIDMEM_FRAMEBUFFER)
589 mmapflags = MAP_SHARED | MAP_WRITECOMBINED;
590 else
591 mmapflags = MAP_SHARED | MAP_NONCACHED;
593 #else /* !__ia64__ */
595 mmapflags = (Flags & VIDMEM_FRAMEBUFFER) / VIDMEM_FRAMEBUFFER;
597 if (ioctl(fd, PCIIOC_WRITE_COMBINE, mmapflags) < 0)
598 break;
600 mmapflags = MAP_SHARED;
602 #endif /* ?__ia64__ */
604 /* Align to page boundary */
605 realBase = Base & ~(getpagesize() - 1);
606 Offset = Base - realBase;
608 if (Flags & VIDMEM_READONLY)
609 prot = PROT_READ;
610 else
611 prot = PROT_READ | PROT_WRITE;
613 result = mmap(NULL, Size + Offset, prot, mmapflags, fd, realBase);
615 if (!result || ((pointer)result == MAP_FAILED))
616 return NULL;
618 xf86MakeNewMapping(ScreenNum, Flags, realBase, Size + Offset, result);
620 return result + Offset;
621 } while (0);
623 if (mmap_ioctl == PCIIOC_MMAP_IS_MEM)
624 return xf86MapVidMem(ScreenNum, Flags, Base, Size);
626 return NULL;
629 #define MAX_DOMAINS 257
630 static pointer DomainMmappedIO[MAX_DOMAINS];
632 static int
633 linuxOpenLegacy(PCITAG Tag, char *name)
635 #define PREFIX "/sys/class/pci_bus/%04x:%02x/%s"
636 char *path;
637 int domain, bus;
638 pciBusInfo_t *pBusInfo;
639 pciConfigPtr bridge = NULL;
640 int fd;
642 path = xalloc(strlen(PREFIX) + strlen(name));
643 if (!path)
644 return -1;
646 for (;;) {
647 domain = xf86GetPciDomain(Tag);
648 bus = PCI_BUS_NO_DOMAIN(PCI_BUS_FROM_TAG(Tag));
650 /* Domain 0 is reserved -- see xf86GetPciDomain() */
651 if ((domain <= 0) || (domain >= MAX_DOMAINS))
652 FatalError("linuxOpenLegacy(): domain out of range\n");
654 sprintf(path, PREFIX, domain - 1, bus, name);
655 fd = open(path, O_RDWR);
656 if (fd >= 0) {
657 xfree(path);
658 return fd;
661 pBusInfo = pciBusInfo[PCI_BUS_FROM_TAG(Tag)];
662 if (!pBusInfo || (bridge == pBusInfo->bridge) ||
663 !(bridge = pBusInfo->bridge)) {
664 xfree(path);
665 return -1;
668 Tag = bridge->tag;
671 xfree(path);
672 return fd;
676 * xf86MapDomainMemory - memory map PCI domain memory
678 * This routine maps the memory region in the domain specified by Tag and
679 * returns a pointer to it. The pointer is saved for future use if it's in
680 * the legacy ISA memory space (memory in a domain between 0 and 1MB).
682 _X_EXPORT pointer
683 xf86MapDomainMemory(int ScreenNum, int Flags, PCITAG Tag,
684 ADDRESS Base, unsigned long Size)
686 int domain = xf86GetPciDomain(Tag);
687 int fd = -1;
688 pointer addr;
691 * We use /proc/bus/pci on non-legacy addresses or if the Linux sysfs
692 * legacy_mem interface is unavailable.
694 if (Base >= 1024*1024)
695 addr = linuxMapPci(ScreenNum, Flags, Tag, Base, Size,
696 PCIIOC_MMAP_IS_MEM);
697 else if ((fd = linuxOpenLegacy(Tag, "legacy_mem")) < 0)
698 addr = linuxMapPci(ScreenNum, Flags, Tag, Base, Size,
699 PCIIOC_MMAP_IS_MEM);
700 else
701 addr = mmap(NULL, Size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, Base);
703 if (fd >= 0)
704 close(fd);
705 if (addr == NULL || addr == MAP_FAILED) {
706 perror("mmap failure");
707 FatalError("xf86MapDomainMem(): mmap() failure\n");
709 return addr;
713 * xf86MapDomainIO - map I/O space in this domain
715 * Each domain has a legacy ISA I/O space. This routine will try to
716 * map it using the Linux sysfs legacy_io interface. If that fails,
717 * it'll fall back to using /proc/bus/pci.
719 * If the legacy_io interface *does* exist, the file descriptor (fd below)
720 * will be saved in the DomainMmappedIO array in the upper bits of the
721 * pointer. Callers will do I/O with small port numbers (<64k values), so
722 * the platform I/O code can extract the port number and the fd, lseek to
723 * the port number in the legacy_io file, and issue the read or write.
725 * This has no means of returning failure, so all errors are fatal
727 _X_EXPORT IOADDRESS
728 xf86MapDomainIO(int ScreenNum, int Flags, PCITAG Tag,
729 IOADDRESS Base, unsigned long Size)
731 int domain = xf86GetPciDomain(Tag);
732 int fd;
734 if ((domain <= 0) || (domain >= MAX_DOMAINS))
735 FatalError("xf86MapDomainIO(): domain out of range\n");
737 if (DomainMmappedIO[domain])
738 return (IOADDRESS)DomainMmappedIO[domain] + Base;
740 /* Permanently map all of I/O space */
741 if ((fd = linuxOpenLegacy(Tag, "legacy_io")) < 0) {
742 DomainMmappedIO[domain] = linuxMapPci(ScreenNum, Flags, Tag,
743 0, linuxGetIOSize(Tag),
744 PCIIOC_MMAP_IS_IO);
745 /* ia64 can't mmap legacy IO port space */
746 if (!DomainMmappedIO[domain])
747 return Base;
749 else { /* legacy_io file exists, encode fd */
750 DomainMmappedIO[domain] = (pointer)(fd << 24);
753 return (IOADDRESS)DomainMmappedIO[domain] + Base;
757 * xf86ReadDomainMemory - copy from domain memory into a caller supplied buffer
759 _X_EXPORT int
760 xf86ReadDomainMemory(PCITAG Tag, ADDRESS Base, int Len, unsigned char *Buf)
762 unsigned char *ptr, *src;
763 ADDRESS offset;
764 unsigned long size;
765 int len, pagemask = getpagesize() - 1;
767 unsigned int i, dom, bus, dev, func;
768 unsigned int fd;
769 char file[256];
770 struct stat st;
772 dom = PCI_DOM_FROM_TAG(Tag);
773 bus = PCI_BUS_NO_DOMAIN(PCI_BUS_FROM_TAG(Tag));
774 dev = PCI_DEV_FROM_TAG(Tag);
775 func = PCI_FUNC_FROM_TAG(Tag);
776 sprintf(file, "/sys/bus/pci/devices/%04x:%02x:%02x.%1x/rom",
777 dom, bus, dev, func);
780 * If the caller wants the ROM and the sysfs rom interface exists,
781 * try to use it instead of reading it from /proc/bus/pci.
783 if (((Base & 0xfffff) == 0xC0000) && (stat(file, &st) == 0)) {
784 if ((fd = open(file, O_RDWR)))
785 Base = 0x0;
787 /* enable the ROM first */
788 write(fd, "1", 2);
789 lseek(fd, 0, SEEK_SET);
791 len = min(Len, st.st_size);
793 /* copy the ROM until we hit Len, EOF or read error */
794 for (; len && (size = read(fd, Buf, len)) > 0 ; Buf+=size, len-=size)
797 write(fd, "0", 2);
798 close(fd);
800 return Len;
803 /* Ensure page boundaries */
804 offset = Base & ~pagemask;
805 size = ((Base + Len + pagemask) & ~pagemask) - offset;
807 ptr = xf86MapDomainMemory(-1, VIDMEM_READONLY, Tag, offset, size);
809 if (!ptr)
810 return -1;
812 /* Using memcpy() here can hang the system */
813 src = ptr + (Base - offset);
814 for (len = Len; len-- > 0;)
815 *Buf++ = *src++;
817 xf86UnMapVidMem(-1, ptr, size);
819 return Len;
822 resPtr
823 xf86BusAccWindowsFromOS(void)
825 pciConfigPtr *ppPCI, pPCI;
826 resPtr pRes = NULL;
827 resRange range;
828 unsigned long io_size, mem_size;
829 int domain;
831 if ((ppPCI = xf86scanpci(0))) {
832 for (; (pPCI = *ppPCI); ppPCI++) {
833 if ((pPCI->pci_base_class != PCI_CLASS_BRIDGE) ||
834 (pPCI->pci_sub_class != PCI_SUBCLASS_BRIDGE_HOST))
835 continue;
837 domain = xf86GetPciDomain(pPCI->tag);
838 linuxGetSizes(pPCI->tag, &io_size, &mem_size);
840 RANGE(range, 0, (ADDRESS)(mem_size - 1),
841 RANGE_TYPE(ResExcMemBlock, domain));
842 pRes = xf86AddResToList(pRes, &range, -1);
844 RANGE(range, 0, (IOADDRESS)(io_size - 1),
845 RANGE_TYPE(ResExcIoBlock, domain));
846 pRes = xf86AddResToList(pRes, &range, -1);
848 if (domain <= 0)
849 break;
853 return pRes;
856 resPtr
857 xf86PciBusAccWindowsFromOS(void)
859 pciConfigPtr *ppPCI, pPCI;
860 resPtr pRes = NULL;
861 resRange range;
862 unsigned long io_size, mem_size;
863 int domain;
865 if ((ppPCI = xf86scanpci(0))) {
866 for (; (pPCI = *ppPCI); ppPCI++) {
867 if ((pPCI->pci_base_class != PCI_CLASS_BRIDGE) ||
868 (pPCI->pci_sub_class != PCI_SUBCLASS_BRIDGE_HOST))
869 continue;
871 domain = xf86GetPciDomain(pPCI->tag);
872 linuxGetSizes(pPCI->tag, &io_size, &mem_size);
874 RANGE(range, 0, (ADDRESS)(mem_size - 1),
875 RANGE_TYPE(ResExcMemBlock, domain));
876 pRes = xf86AddResToList(pRes, &range, -1);
878 RANGE(range, 0, (IOADDRESS)(io_size - 1),
879 RANGE_TYPE(ResExcIoBlock, domain));
880 pRes = xf86AddResToList(pRes, &range, -1);
882 if (domain <= 0)
883 break;
887 return pRes;
891 resPtr
892 xf86AccResFromOS(resPtr pRes)
894 pciConfigPtr *ppPCI, pPCI;
895 resRange range;
896 unsigned long io_size, mem_size;
897 int domain;
899 if ((ppPCI = xf86scanpci(0))) {
900 for (; (pPCI = *ppPCI); ppPCI++) {
901 if ((pPCI->pci_base_class != PCI_CLASS_BRIDGE) ||
902 (pPCI->pci_sub_class != PCI_SUBCLASS_BRIDGE_HOST))
903 continue;
905 domain = xf86GetPciDomain(pPCI->tag);
906 linuxGetSizes(pPCI->tag, &io_size, &mem_size);
909 * At minimum, the top and bottom resources must be claimed, so
910 * that resources that are (or appear to be) unallocated can be
911 * relocated.
913 RANGE(range, 0x00000000u, 0x0009ffffu,
914 RANGE_TYPE(ResExcMemBlock, domain));
915 pRes = xf86AddResToList(pRes, &range, -1);
916 RANGE(range, 0x000c0000u, 0x000effffu,
917 RANGE_TYPE(ResExcMemBlock, domain));
918 pRes = xf86AddResToList(pRes, &range, -1);
919 RANGE(range, 0x000f0000u, 0x000fffffu,
920 RANGE_TYPE(ResExcMemBlock, domain));
921 pRes = xf86AddResToList(pRes, &range, -1);
923 RANGE(range, (ADDRESS)(mem_size - 1), (ADDRESS)(mem_size - 1),
924 RANGE_TYPE(ResExcMemBlock, domain));
925 pRes = xf86AddResToList(pRes, &range, -1);
927 RANGE(range, 0x00000000u, 0x00000000u,
928 RANGE_TYPE(ResExcIoBlock, domain));
929 pRes = xf86AddResToList(pRes, &range, -1);
930 RANGE(range, (IOADDRESS)(io_size - 1), (IOADDRESS)(io_size - 1),
931 RANGE_TYPE(ResExcIoBlock, domain));
932 pRes = xf86AddResToList(pRes, &range, -1);
934 if (domain <= 0)
935 break;
939 return pRes;
942 #endif /* !INCLUDE_XF86_NO_DOMAIN */
944 int linuxPciHandleBIOS(PCITAG Tag, int basereg, unsigned char *buf, int len)
946 unsigned int dom, bus, dev, func;
947 unsigned int fd;
948 char file[256];
949 struct stat st;
950 int ret;
951 int sofar = 0;
953 dom = PCI_DOM_FROM_TAG(Tag);
954 bus = PCI_BUS_NO_DOMAIN(PCI_BUS_FROM_TAG(Tag));
955 dev = PCI_DEV_FROM_TAG(Tag);
956 func = PCI_FUNC_FROM_TAG(Tag);
957 sprintf(file, "/sys/bus/pci/devices/%04x:%02x:%02x.%1x/rom",
958 dom, bus, dev, func);
960 if (stat(file, &st) == 0)
962 if ((fd = open(file, O_RDWR)))
963 basereg = 0x0;
965 /* enable the ROM first */
966 write(fd, "1", 2);
967 lseek(fd, 0, SEEK_SET);
968 do {
969 /* copy the ROM until we hit Len, EOF or read error */
970 ret = read(fd, buf+sofar, len-sofar);
971 if (ret <= 0)
972 break;
973 sofar += ret;
974 } while (sofar < len);
976 write(fd, "0", 2);
977 close(fd);
978 if (sofar < len)
979 xf86MsgVerb(X_INFO, 3, "Attempted to read BIOS %dKB from %s: got %dKB\n", len/1024, file, sofar/1024);
980 return sofar;
982 return 0;
985 #ifdef __ia64__
986 static PCITAG ia64linuxPciFindFirst(void);
987 static PCITAG ia64linuxPciFindNext(void);
989 void
990 ia64linuxPciInit()
992 struct stat st;
994 linuxPciInit();
996 if (!stat("/proc/sgi_sn/licenseID", &st) && pciNumBuses) {
997 /* Be a little paranoid here and only use this code for Altix systems.
998 * It is generic, so it should work on any system, but depends on
999 * /proc/bus/pci entries for each domain/bus combination. Altix is
1000 * guaranteed a recent enough kernel to have them.
1002 pciFindFirstFP = ia64linuxPciFindFirst;
1003 pciFindNextFP = ia64linuxPciFindNext;
1007 static DIR *busdomdir;
1008 static DIR *devdir;
1010 static PCITAG
1011 ia64linuxPciFindFirst(void)
1013 busdomdir = opendir("/proc/bus/pci");
1014 devdir = NULL;
1016 return ia64linuxPciFindNext();
1019 static struct dirent *getnextbus(int *domain, int *bus)
1021 struct dirent *entry;
1022 int dombus;
1024 for (;;) {
1025 entry = readdir(busdomdir);
1026 if (entry == NULL) {
1027 *domain = 0;
1028 *bus = 0;
1029 closedir(busdomdir);
1030 return NULL;
1032 if (sscanf(entry->d_name, "%04x:%02x", domain, bus) != 2)
1033 continue;
1034 dombus = PCI_MAKE_BUS(*domain, *bus);
1036 if (pciNumBuses <= dombus)
1037 pciNumBuses = dombus + 1;
1038 if (!pciBusInfo[dombus]) {
1039 pciBusInfo[dombus] = xnfalloc(sizeof(pciBusInfo_t));
1040 *pciBusInfo[dombus] = *pciBusInfo[0];
1043 return entry;
1047 static PCITAG
1048 ia64linuxPciFindNext(void)
1050 struct dirent *entry;
1051 char file[40];
1052 static int bus, dev, func, domain;
1053 PCITAG pciDeviceTag;
1054 CARD32 devid;
1056 for (;;) {
1057 if (devdir == NULL) {
1058 entry = getnextbus(&domain, &bus);
1059 if (!entry)
1060 return PCI_NOT_FOUND;
1061 snprintf(file, 40, "/proc/bus/pci/%s", entry->d_name);
1062 devdir = opendir(file);
1063 if (!devdir)
1064 return PCI_NOT_FOUND;
1068 entry = readdir(devdir);
1070 if (entry == NULL) {
1071 closedir(devdir);
1072 devdir = NULL;
1073 continue;
1076 if (sscanf(entry->d_name, "%02x . %01x", &dev, &func) == 2) {
1077 CARD32 tmp;
1078 int sec_bus, pri_bus;
1079 unsigned char base_class, sub_class;
1081 int pciBusNum = PCI_MAKE_BUS(domain, bus);
1082 pciDeviceTag = PCI_MAKE_TAG(pciBusNum, dev, func);
1085 * Before checking for a specific devid, look for enabled
1086 * PCI to PCI bridge devices. If one is found, create and
1087 * initialize a bus info record (if one does not already exist).
1089 tmp = pciReadLong(pciDeviceTag, PCI_CLASS_REG);
1090 base_class = PCI_CLASS_EXTRACT(tmp);
1091 sub_class = PCI_SUBCLASS_EXTRACT(tmp);
1092 if ((base_class == PCI_CLASS_BRIDGE) &&
1093 ((sub_class == PCI_SUBCLASS_BRIDGE_PCI) ||
1094 (sub_class == PCI_SUBCLASS_BRIDGE_CARDBUS))) {
1095 tmp = pciReadLong(pciDeviceTag, PCI_PCI_BRIDGE_BUS_REG);
1096 sec_bus = PCI_SECONDARY_BUS_EXTRACT(tmp, pciDeviceTag);
1097 pri_bus = PCI_PRIMARY_BUS_EXTRACT(tmp, pciDeviceTag);
1098 #ifdef DEBUGPCI
1099 ErrorF("ia64linuxPciFindNext: pri_bus %d sec_bus %d\n",
1100 pri_bus, sec_bus);
1101 #endif
1102 if (pciBusNum != pri_bus) {
1103 /* Some bridges do not implement the primary bus register */
1104 if ((PCI_BUS_NO_DOMAIN(pri_bus) != 0) ||
1105 (sub_class != PCI_SUBCLASS_BRIDGE_CARDBUS))
1106 xf86Msg(X_WARNING,
1107 "ia64linuxPciFindNext: primary bus mismatch on PCI"
1108 " bridge 0x%08lx (0x%02x, 0x%02x)\n",
1109 pciDeviceTag, pciBusNum, pri_bus);
1110 pri_bus = pciBusNum;
1112 if ((pri_bus < sec_bus) && (sec_bus < pciMaxBusNum) &&
1113 pciBusInfo[pri_bus]) {
1115 * Found a secondary PCI bus
1117 if (!pciBusInfo[sec_bus]) {
1118 pciBusInfo[sec_bus] = xnfalloc(sizeof(pciBusInfo_t));
1120 /* Copy parents settings... */
1121 *pciBusInfo[sec_bus] = *pciBusInfo[pri_bus];
1124 /* ...but not everything same as parent */
1125 pciBusInfo[sec_bus]->primary_bus = pri_bus;
1126 pciBusInfo[sec_bus]->secondary = TRUE;
1127 pciBusInfo[sec_bus]->numDevices = 32;
1129 if (pciNumBuses <= sec_bus)
1130 pciNumBuses = sec_bus + 1;
1134 devid = pciReadLong(pciDeviceTag, PCI_ID_REG);
1135 if ((devid & pciDevidMask) == pciDevid)
1136 /* Yes - Return it. Otherwise, next device */
1137 return pciDeviceTag;
1141 #endif