First import
[xorg_rtime.git] / xorg-server-1.4 / hw / xfree86 / os-support / linux / lnx_pci.c
bloba957038997bcee43303e3ae8407e537f13293476
2 #ifdef HAVE_XORG_CONFIG_H
3 #include <xorg-config.h>
4 #endif
6 #include <sys/types.h>
7 #include <stdio.h>
8 #include <dirent.h>
9 #include <X11/X.h>
10 #include "os.h"
11 #include "xf86.h"
12 #include "xf86Priv.h"
13 #define XF86_OS_PRIVS
14 #include "xf86_OSproc.h"
15 #include "xf86Pci.h"
17 #ifdef __sparc__
18 #define PCIADDR_TYPE long long
19 #define PCIADDR_IGNORE_FMT "%*x"
20 #define PCIADDR_FMT "%llx"
21 #else
22 #define PCIADDR_TYPE long
23 #define PCIADDR_IGNORE_FMT "%*x"
24 #define PCIADDR_FMT "%lx"
25 #endif
27 int lnxPciInit(void);
29 struct pci_dev {
30 unsigned int domain;
31 unsigned int bus;
32 unsigned int dev;
33 unsigned int fn;
34 PCIADDR_TYPE offset[7];
35 PCIADDR_TYPE size[7];
36 struct pci_dev *next;
39 struct pci_dev *xf86OSLinuxPCIDevs = NULL;
40 int xf86OSLinuxNumPciDevs = 0;
42 static struct pci_dev *xf86OSLinuxGetPciDevs(void) {
43 char c[0x200];
44 FILE *file = NULL;
45 DIR *dir;
46 struct dirent *dirent;
47 struct pci_dev *tmp, *ret = NULL;
48 unsigned int i, num, devfn;
49 unsigned PCIADDR_TYPE begin, end;
50 char *res;
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);
60 tmp->domain = domain;
61 tmp->bus = bus;
62 tmp->dev = dev;
63 tmp->fn = fn;
64 sprintf (c, "/sys/bus/pci/devices/%12s/resource",
65 dirent->d_name);
66 i = 0;
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;
73 i++;
76 fclose (file);
78 if (i > 0) {
79 tmp->next = ret;
80 ret = tmp;
81 xf86OSLinuxNumPciDevs++;
82 } else
83 xfree (tmp);
86 closedir (dir);
89 if (ret)
90 return ret;
92 file = fopen("/proc/bus/pci/devices", "r");
93 if (!file) return NULL;
95 xf86OSLinuxNumPciDevs = 0;
97 do {
98 res = fgets(c, 0x1ff, file);
99 if (res) {
100 tmp = xcalloc(sizeof(struct pci_dev),1);
101 num = sscanf(res,
102 /*bus+dev vendorid deviceid irq */
103 "%02x%02x\t%*04x%*04x\t%*x"
104 /* 7 PCI resource base addresses */
105 "\t" PCIADDR_FMT
106 "\t" PCIADDR_FMT
107 "\t" PCIADDR_FMT
108 "\t" PCIADDR_FMT
109 "\t" PCIADDR_FMT
110 "\t" PCIADDR_FMT
111 "\t" PCIADDR_FMT
112 /* 7 PCI resource sizes, and then optionally a driver name */
113 "\t" PCIADDR_FMT
114 "\t" PCIADDR_FMT
115 "\t" PCIADDR_FMT
116 "\t" PCIADDR_FMT
117 "\t" PCIADDR_FMT
118 "\t" PCIADDR_FMT
119 "\t" PCIADDR_FMT,
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 */
126 xfree(tmp);
127 fclose(file);
128 return NULL;
130 if (ret) {
131 tmp->next = ret;
133 ret = tmp;
134 xf86OSLinuxNumPciDevs++;
136 } while (res);
137 fclose(file);
138 return ret;
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;
149 Bool
150 xf86GetPciSizeFromOS(PCITAG tag, int index, int* bits)
152 signed PCIADDR_TYPE Size;
153 struct pci_dev *device;
155 if (index >= 7)
156 return FALSE;
158 if (!xf86OSLinuxPCIDevs) {
159 xf86OSLinuxPCIDevs = xf86OSLinuxGetPciDevs();
161 if (!xf86OSLinuxPCIDevs)
162 return FALSE;
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);
171 (*bits)++;
174 return TRUE;
178 return FALSE;
183 #if 0
184 /* Query the kvirt address (64bit) of a BAR range from TAG */
185 Bool
186 xf86GetPciOffsetFromOS(PCITAG tag, int index, unsigned long* bases)
188 struct pci_dev *device;
190 if (index >= 7)
191 return FALSE;
193 if (!xf86OSLinuxPCIDevs) {
194 xf86OSLinuxPCIDevs = xf86OSLinuxGetPciDevs();
196 if (!xf86OSLinuxPCIDevs)
197 return FALSE;
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];
204 return TRUE;
208 return FALSE;
210 #endif
212 /* Query the kvirt address (64bit) of a BAR range from size for a given TAG */
213 unsigned long
214 xf86GetOSOffsetFromPCI(PCITAG tag, int space, unsigned long base)
216 unsigned int ndx;
217 struct pci_dev *device;
219 if (!xf86OSLinuxPCIDevs) {
220 xf86OSLinuxPCIDevs = xf86OSLinuxGetPciDevs();
222 if (!xf86OSLinuxPCIDevs) {
223 return FALSE;
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;
234 if (ndx == 6)
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).
242 if (savePtr == 0)
243 continue;
244 /* Remove memory attribute bits, different for IO
245 * and memory ranges. */
246 flagMask = (savePtr & 0x1) ? ~0x3UL : ~0xFUL;
247 savePtr &= flagMask;
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);
257 return 0;