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
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
47 #ifdef HAVE_XORG_CONFIG_H
48 #include <xorg-config.h>
55 #include "xf86_OSlib.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
);
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
,
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
,
93 /* pciAddrBusToHost */ linuxTransAddrBusToHost
,
94 #endif /* __sparc64__ */
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
,
111 /* secondary */ FALSE
,
113 /* funcs */ &linuxFuncs0
,
114 /* pciBusPriv */ NULL
,
118 /* from lnx_pci.c. */
119 extern int lnxPciInit(void);
121 static Bool domain_support
= FALSE
;
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 */
133 #ifndef INCLUDE_XF86_NO_DOMAIN
134 domain_support
= linuxDomainSupport();
137 pciBusInfo
[0] = &linuxPci0
;
138 pciFindFirstFP
= pciGenFindFirst
;
139 pciFindNextFP
= pciGenFindNext
;
140 pciSetOSBIOSPtr(linuxPciHandleBIOS
);
141 xf86MaxPciDevs
= lnxPciInit();
145 linuxPciOpenFile(PCITAG tag
, Bool write
)
147 static int ldomain
, lbus
,ldev
,lfunc
,fd
= -1,is_write
= 0;
148 int domain
, bus
, dev
, func
;
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
);
158 if (stat("/sys/bus/pci",&ignored
) < 0)
164 if (!domain_support
&& domain
> 0)
167 if (fd
== -1 || (write
&& (!is_write
)) || domain
!= ldomain
168 || bus
!= lbus
|| dev
!= ldev
|| func
!= lfunc
) {
174 sprintf(file
,"/sys/bus/pci/devices/%04x:%02x:%02x.%01x/config",
175 domain
, bus
, dev
, func
);
178 sprintf(file
, "/proc/bus/pci/%04x:%02x", domain
, bus
);
179 if (stat(file
, &ignored
) < 0) {
181 sprintf(file
, "/proc/bus/pci/%02x/%02x.%1x",
186 sprintf(file
, "/proc/bus/pci/%04x:%02x/%02x.%1x",
187 domain
, bus
, dev
, func
);
189 sprintf(file
, "/proc/bus/pci/%04x:%04x", domain
, bus
);
190 if (stat(file
, &ignored
) < 0) {
192 sprintf(file
, "/proc/bus/pci/%04x/%02x.%1x",
197 sprintf(file
, "/proc/bus/pci/%04x:%04x/%02x.%1x",
198 domain
, bus
, dev
, func
);
202 fd
= open(file
,O_RDWR
);
203 if (fd
!= -1) is_write
= TRUE
;
204 } else switch (is_write
) {
206 fd
= open(file
,O_RDWR
);
210 fd
= open(file
,O_RDONLY
);
223 linuxPciCfgRead(PCITAG tag
, int off
)
226 CARD32 val
= 0xffffffff;
228 if (-1 != (fd
= linuxPciOpenFile(tag
,FALSE
))) {
229 lseek(fd
,off
,SEEK_SET
);
236 linuxPciCfgWrite(PCITAG tag
, int off
, CARD32 val
)
240 if (-1 != (fd
= linuxPciOpenFile(tag
,TRUE
))) {
241 lseek(fd
,off
,SEEK_SET
);
248 linuxPciCfgSetBits(PCITAG tag
, int off
, CARD32 mask
, CARD32 bits
)
251 CARD32 val
= 0xffffffff;
253 if (-1 != (fd
= linuxPciOpenFile(tag
,TRUE
))) {
254 lseek(fd
,off
,SEEK_SET
);
257 val
= (val
& ~mask
) | (bits
& mask
);
259 lseek(fd
,off
,SEEK_SET
);
265 * This function will convert a BAR address into a host address
266 * suitable for passing into the mmap function of a /proc/bus
269 ADDRESS
linuxTransAddrBusToHost(PCITAG tag
, PciAddrType type
, ADDRESS addr
)
271 ADDRESS ret
= xf86GetOSOffsetFromPCI(tag
, PCI_MEM
|PCI_IO
, addr
);
277 * if it is not a BAR address, it must be legacy, (or wrong)
284 #if defined(__powerpc__)
286 #ifndef __NR_pciconfig_iobase
287 #define __NR_pciconfig_iobase 200
291 linuxPpcBusAddrToHostAddr(PCITAG tag
, PciAddrType type
, ADDRESS addr
)
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
);
309 linuxPpcHostAddrToBusAddr(PCITAG tag
, PciAddrType type
, ADDRESS addr
)
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
);
326 #endif /* __powerpc__ */
329 linuxPciCfgReadByte(PCITAG tag
, int off
)
334 if (-1 != (fd
= linuxPciOpenFile(tag
,FALSE
))) {
335 lseek(fd
,off
,SEEK_SET
);
343 linuxPciCfgWriteByte(PCITAG tag
, int off
, CARD8 val
)
347 if (-1 != (fd
= linuxPciOpenFile(tag
,TRUE
))) {
348 lseek(fd
,off
,SEEK_SET
);
354 linuxPciCfgReadWord(PCITAG tag
, int off
)
359 if (-1 != (fd
= linuxPciOpenFile(tag
,FALSE
))) {
360 lseek(fd
, off
, SEEK_SET
);
364 return PCI_CPU16(val
);
368 linuxPciCfgWriteWord(PCITAG tag
, int off
, CARD16 val
)
372 if (-1 != (fd
= linuxPciOpenFile(tag
,TRUE
))) {
373 lseek(fd
, off
, SEEK_SET
);
374 val
= PCI_CPU16(val
);
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)
424 /* This probably shouldn't be Linux-specific */
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
,
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)
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
;
513 linuxDomainSupport(void)
516 struct dirent
*dirent
;
519 if (!(dir
= opendir("/proc/bus/pci")))
522 if (!(dirent
= readdir(dir
)))
524 strtol(dirent
->d_name
,&end
,16);
525 /* entry of the form xx or xxxx : x=[0..f] no domain */
528 else if (*end
== ':') {
529 /* ':' found immediately after: verify for xxxx:xx or xxxx:xxxx */
530 strtol(end
+ 1,&end
,16);
539 xf86GetPciDomain(PCITAG Tag
)
544 pPCI
= xf86GetPciHostConfigFromTag(Tag
);
546 if (pPCI
&& (result
= PCI_DOM_FROM_BUS(pPCI
->busnum
)))
549 if (!pPCI
|| pPCI
->fakeDevice
)
550 return 1; /* Domain 0 is reserved */
552 if ((fd
= linuxPciOpenFile(pPCI
? pPCI
->tag
: 0,FALSE
)) < 0)
555 if ((result
= ioctl(fd
, PCIIOC_CONTROLLER
, 0)) < 0)
558 return result
+ 1; /* Domain 0 is reserved */
562 linuxMapPci(int ScreenNum
, int Flags
, PCITAG Tag
,
563 ADDRESS Base
, unsigned long Size
, int mmap_ioctl
)
567 unsigned char *result
;
568 ADDRESS realBase
, Offset
;
569 int fd
, mmapflags
, prot
;
573 prot
= ((Flags
& VIDMEM_READONLY
) == 0);
574 if (((fd
= linuxPciOpenFile(Tag
, prot
)) < 0) ||
575 (ioctl(fd
, mmap_ioctl
, 0) < 0))
578 /* Note: IA-64 doesn't compile this and doesn't need to */
581 # ifndef MAP_WRITECOMBINED
582 # define MAP_WRITECOMBINED 0x00010000
584 # ifndef MAP_NONCACHED
585 # define MAP_NONCACHED 0x00020000
588 if (Flags
& VIDMEM_FRAMEBUFFER
)
589 mmapflags
= MAP_SHARED
| MAP_WRITECOMBINED
;
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)
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
)
611 prot
= PROT_READ
| PROT_WRITE
;
613 result
= mmap(NULL
, Size
+ Offset
, prot
, mmapflags
, fd
, realBase
);
615 if (!result
|| ((pointer
)result
== MAP_FAILED
))
618 xf86MakeNewMapping(ScreenNum
, Flags
, realBase
, Size
+ Offset
, result
);
620 return result
+ Offset
;
623 if (mmap_ioctl
== PCIIOC_MMAP_IS_MEM
)
624 return xf86MapVidMem(ScreenNum
, Flags
, Base
, Size
);
629 #define MAX_DOMAINS 257
630 static pointer DomainMmappedIO
[MAX_DOMAINS
];
633 linuxOpenLegacy(PCITAG Tag
, char *name
)
635 #define PREFIX "/sys/class/pci_bus/%04x:%02x/%s"
638 pciBusInfo_t
*pBusInfo
;
639 pciConfigPtr bridge
= NULL
;
642 path
= xalloc(strlen(PREFIX
) + strlen(name
));
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
);
661 pBusInfo
= pciBusInfo
[PCI_BUS_FROM_TAG(Tag
)];
662 if (!pBusInfo
|| (bridge
== pBusInfo
->bridge
) ||
663 !(bridge
= pBusInfo
->bridge
)) {
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).
683 xf86MapDomainMemory(int ScreenNum
, int Flags
, PCITAG Tag
,
684 ADDRESS Base
, unsigned long Size
)
686 int domain
= xf86GetPciDomain(Tag
);
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
,
697 else if ((fd
= linuxOpenLegacy(Tag
, "legacy_mem")) < 0)
698 addr
= linuxMapPci(ScreenNum
, Flags
, Tag
, Base
, Size
,
701 addr
= mmap(NULL
, Size
, PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, Base
);
705 if (addr
== NULL
|| addr
== MAP_FAILED
) {
706 perror("mmap failure");
707 FatalError("xf86MapDomainMem(): mmap() failure\n");
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
728 xf86MapDomainIO(int ScreenNum
, int Flags
, PCITAG Tag
,
729 IOADDRESS Base
, unsigned long Size
)
731 int domain
= xf86GetPciDomain(Tag
);
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
),
745 /* ia64 can't mmap legacy IO port space */
746 if (!DomainMmappedIO
[domain
])
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
760 xf86ReadDomainMemory(PCITAG Tag
, ADDRESS Base
, int Len
, unsigned char *Buf
)
762 unsigned char *ptr
, *src
;
765 int len
, pagemask
= getpagesize() - 1;
767 unsigned int i
, dom
, bus
, dev
, func
;
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
)))
787 /* enable the ROM first */
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
)
803 /* Ensure page boundaries */
804 offset
= Base
& ~pagemask
;
805 size
= ((Base
+ Len
+ pagemask
) & ~pagemask
) - offset
;
807 ptr
= xf86MapDomainMemory(-1, VIDMEM_READONLY
, Tag
, offset
, size
);
812 /* Using memcpy() here can hang the system */
813 src
= ptr
+ (Base
- offset
);
814 for (len
= Len
; len
-- > 0;)
817 xf86UnMapVidMem(-1, ptr
, size
);
823 xf86BusAccWindowsFromOS(void)
825 pciConfigPtr
*ppPCI
, pPCI
;
828 unsigned long io_size
, mem_size
;
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
))
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);
857 xf86PciBusAccWindowsFromOS(void)
859 pciConfigPtr
*ppPCI
, pPCI
;
862 unsigned long io_size
, mem_size
;
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
))
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);
892 xf86AccResFromOS(resPtr pRes
)
894 pciConfigPtr
*ppPCI
, pPCI
;
896 unsigned long io_size
, mem_size
;
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
))
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
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);
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
;
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
)))
965 /* enable the ROM first */
967 lseek(fd
, 0, SEEK_SET
);
969 /* copy the ROM until we hit Len, EOF or read error */
970 ret
= read(fd
, buf
+sofar
, len
-sofar
);
974 } while (sofar
< len
);
979 xf86MsgVerb(X_INFO
, 3, "Attempted to read BIOS %dKB from %s: got %dKB\n", len
/1024, file
, sofar
/1024);
986 static PCITAG
ia64linuxPciFindFirst(void);
987 static PCITAG
ia64linuxPciFindNext(void);
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
;
1011 ia64linuxPciFindFirst(void)
1013 busdomdir
= opendir("/proc/bus/pci");
1016 return ia64linuxPciFindNext();
1019 static struct dirent
*getnextbus(int *domain
, int *bus
)
1021 struct dirent
*entry
;
1025 entry
= readdir(busdomdir
);
1026 if (entry
== NULL
) {
1029 closedir(busdomdir
);
1032 if (sscanf(entry
->d_name
, "%04x:%02x", domain
, bus
) != 2)
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];
1048 ia64linuxPciFindNext(void)
1050 struct dirent
*entry
;
1052 static int bus
, dev
, func
, domain
;
1053 PCITAG pciDeviceTag
;
1057 if (devdir
== NULL
) {
1058 entry
= getnextbus(&domain
, &bus
);
1060 return PCI_NOT_FOUND
;
1061 snprintf(file
, 40, "/proc/bus/pci/%s", entry
->d_name
);
1062 devdir
= opendir(file
);
1064 return PCI_NOT_FOUND
;
1068 entry
= readdir(devdir
);
1070 if (entry
== NULL
) {
1076 if (sscanf(entry
->d_name
, "%02x . %01x", &dev
, &func
) == 2) {
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
);
1099 ErrorF("ia64linuxPciFindNext: pri_bus %d sec_bus %d\n",
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
))
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
;