2 #ifdef HAVE_XORG_CONFIG_H
3 #include <xorg-config.h>
14 #include "xf86_OSproc.h"
18 #define PCIADDR_TYPE long long
19 #define PCIADDR_IGNORE_FMT "%*x"
20 #define PCIADDR_FMT "%llx"
22 #define PCIADDR_TYPE long
23 #define PCIADDR_IGNORE_FMT "%*x"
24 #define PCIADDR_FMT "%lx"
34 PCIADDR_TYPE offset
[7];
39 struct pci_dev
*xf86OSLinuxPCIDevs
= NULL
;
40 int xf86OSLinuxNumPciDevs
= 0;
42 static struct pci_dev
*xf86OSLinuxGetPciDevs(void) {
46 struct dirent
*dirent
;
47 struct pci_dev
*tmp
, *ret
= NULL
;
48 unsigned int i
, num
, devfn
;
49 unsigned PCIADDR_TYPE begin
, end
;
52 /* Try 2.6 devices first, with domain support */
53 if ( (dir
= opendir ("/sys/bus/pci/devices")) ) {
54 xf86OSLinuxNumPciDevs
= 0;
55 while ( (dirent
= readdir (dir
)) ) {
56 unsigned int domain
, bus
, dev
, fn
;
57 if (sscanf (dirent
->d_name
, "%04x:%02x:%02x.%01x",
58 &domain
, &bus
, &dev
, &fn
) == 4) {
59 tmp
= xcalloc (sizeof(struct pci_dev
), 1);
64 sprintf (c
, "/sys/bus/pci/devices/%12s/resource",
67 if ( (file
= fopen (c
, "r")) ) {
68 while (i
< 7 && fgets (c
, 0x200, file
)) {
69 if (sscanf (c
, PCIADDR_FMT
" " PCIADDR_FMT
" "
70 PCIADDR_IGNORE_FMT
, &begin
, &end
) == 2) {
71 tmp
->offset
[i
] = begin
;
72 tmp
->size
[i
] = begin
? end
-begin
+1 : 0;
81 xf86OSLinuxNumPciDevs
++;
92 file
= fopen("/proc/bus/pci/devices", "r");
93 if (!file
) return NULL
;
95 xf86OSLinuxNumPciDevs
= 0;
98 res
= fgets(c
, 0x1ff, file
);
100 tmp
= xcalloc(sizeof(struct pci_dev
),1);
102 /*bus+dev vendorid deviceid irq */
103 "%02x%02x\t%*04x%*04x\t%*x"
104 /* 7 PCI resource base addresses */
112 /* 7 PCI resource sizes, and then optionally a driver name */
120 &tmp
->bus
,&devfn
,&tmp
->offset
[0],&tmp
->offset
[1],&tmp
->offset
[2],&tmp
->offset
[3],
121 &tmp
->offset
[4],&tmp
->offset
[5],&tmp
->offset
[6], &tmp
->size
[0], &tmp
->size
[1], &tmp
->size
[2],
122 &tmp
->size
[3], &tmp
->size
[4], &tmp
->size
[5], &tmp
->size
[6]);
123 tmp
->dev
= devfn
>> 3;
124 tmp
->fn
= devfn
& 0x7;
125 if (num
!= 16) { /* apparantly not 2.3 style */
134 xf86OSLinuxNumPciDevs
++;
141 /* not to be confused with linuxPciInit (i.e. ARCH_PCI_INIT), found in
142 * os-support/bus/linuxPci.c. */
143 int lnxPciInit(void) {
144 if (!xf86OSLinuxPCIDevs
)
145 xf86OSLinuxPCIDevs
= xf86OSLinuxGetPciDevs();
146 return xf86OSLinuxNumPciDevs
;
150 xf86GetPciSizeFromOS(PCITAG tag
, int index
, int* bits
)
152 signed PCIADDR_TYPE Size
;
153 struct pci_dev
*device
;
158 if (!xf86OSLinuxPCIDevs
) {
159 xf86OSLinuxPCIDevs
= xf86OSLinuxGetPciDevs();
161 if (!xf86OSLinuxPCIDevs
)
164 for (device
= xf86OSLinuxPCIDevs
; device
; device
= device
->next
) {
165 if (tag
== pciDomTag (device
->domain
, device
->bus
,
166 device
->dev
, device
->fn
)) {
167 if (device
->size
[index
] != 0) {
168 Size
= device
->size
[index
] - ((PCIADDR_TYPE
) 1);
169 while (Size
& ((PCIADDR_TYPE
) 0x01)) {
170 Size
= Size
>> ((PCIADDR_TYPE
) 1);
184 /* Query the kvirt address (64bit) of a BAR range from TAG */
186 xf86GetPciOffsetFromOS(PCITAG tag
, int index
, unsigned long* bases
)
188 struct pci_dev
*device
;
193 if (!xf86OSLinuxPCIDevs
) {
194 xf86OSLinuxPCIDevs
= xf86OSLinuxGetPciDevs();
196 if (!xf86OSLinuxPCIDevs
)
199 for (device
= xf86OSLinuxPCIDevs
; device
; device
= device
->next
) {
200 if (tag
== pciDomTag (device
->domain
, device
->bus
,
201 device
->dev
, device
->fn
)) {
202 /* return the offset for the index requested */
203 *bases
= device
->offset
[index
];
212 /* Query the kvirt address (64bit) of a BAR range from size for a given TAG */
214 xf86GetOSOffsetFromPCI(PCITAG tag
, int space
, unsigned long base
)
217 struct pci_dev
*device
;
219 if (!xf86OSLinuxPCIDevs
) {
220 xf86OSLinuxPCIDevs
= xf86OSLinuxGetPciDevs();
222 if (!xf86OSLinuxPCIDevs
) {
226 for (device
= xf86OSLinuxPCIDevs
; device
; device
= device
->next
) {
227 if (tag
== pciDomTag (device
->domain
, device
->bus
,
228 device
->dev
, device
->fn
)) {
229 /* ok now look through all the BAR values of this device */
230 pciConfigPtr pDev
= xf86GetPciConfigFromTag(tag
);
232 for (ndx
=0; ndx
<7; ndx
++) {
233 unsigned long savePtr
, flagMask
;
235 savePtr
= pDev
->pci_baserom
;
236 else /* this the ROM bar */
237 savePtr
= (&pDev
->pci_base0
)[ndx
];
238 /* Ignore unset base addresses. The kernel may
239 * have reported non-zero size and address even
240 * if they are disabled (e.g. disabled ROM BAR).
244 /* Remove memory attribute bits, different for IO
245 * and memory ranges. */
246 flagMask
= (savePtr
& 0x1) ? ~0x3UL
: ~0xFUL
;
249 /* find the index of the incoming base */
250 if (base
>= savePtr
&& base
< (savePtr
+ device
->size
[ndx
])) {
251 return (device
->offset
[ndx
] & flagMask
) + (base
- savePtr
);