First import
[xorg_rtime.git] / xorg-server-1.4 / hw / xfree86 / os-support / bus / axpPci.c
blobfc16a512e97650c8b26f0b9a69ffb33a099af6e0
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"
58 #include <asm/unistd.h>
59 #include "../linux/lnx.h" /* for _iobase */
62 * Alpha/Linux platform specific PCI access functions
64 static CARD32 axpPciCfgRead(PCITAG tag, int off);
65 static void axpPciCfgWrite(PCITAG, int off, CARD32 val);
66 static void axpPciCfgSetBits(PCITAG tag, int off, CARD32 mask, CARD32 bits);
68 static pciBusFuncs_t axpFuncs0 = {
69 /* pciReadLong */ axpPciCfgRead,
70 /* pciWriteLong */ axpPciCfgWrite,
71 /* pciSetBitsLong */ axpPciCfgSetBits,
72 /* pciAddrHostToBus */ pciAddrNOOP,
73 /* pciAddrBusToHost */ pciAddrNOOP
76 typedef struct _axpDomainRec {
77 int domain, hose;
78 int root_bus;
79 unsigned long dense_io, sparse_io;
80 unsigned long dense_mem, sparse_mem;
81 IOADDRESS mapped_io;
82 } axpDomainRec, *axpDomainPtr;
84 #define MAX_DOMAINS (MAX_PCI_BUSES / 256)
85 static axpDomainPtr xf86DomainInfo[MAX_DOMAINS] = { NULL, };
86 static int pciNumDomains = 0;
89 * For debug, domain assignment can start downward from a fixed base
90 * (instead of up from 0) by defining FORCE_HIGH_DOMAINS. This allows
91 * debug of large domain numbers and sparse domain numbering on systems
92 * which don't have as many hoses.
94 #if 0
95 # define FORCE_HIGH_DOMAINS MAX_DOMAINS /* assign domains downward from here */
96 #endif
99 * If FORCE_HIGH_DOMAINS is set, make sure it's not larger than the
100 * max domain
102 #if defined(FORCE_HIGH_DOMAINS) && (FORCE_HIGH_DOMAINS > MAX_DOMAINS)
103 # undef FORCE_HIGH_DOMAINS
104 # define FORCE_HIGH_DOMAINS MAX_DOMAINS
105 #endif
107 static int
108 axpSetupDomains(void)
110 axpDomainRec axpDomain;
111 int numDomains = 0;
112 int hose;
114 #ifndef INCLUDE_XF86_NO_DOMAIN
116 #ifdef FORCE_HIGH_DOMAINS
117 xf86Msg(X_WARNING,
118 "DEBUG OPTION FORCE_HIGH_DOMAINS in use - DRI will *NOT* work\n");
119 numDomains = FORCE_HIGH_DOMAINS;
120 #endif
123 * Since each hose has a different address space, hoses are a perfect
124 * overlay for domains, so set up one domain for each hose present
125 * in the system. We have to loop through all possible hoses because
126 * some systems allow sparse I/O controllers.
128 for(hose = 0; hose < MAX_DOMAINS; hose++) {
129 axpDomain.root_bus = _iobase(IOBASE_ROOT_BUS, hose, -1, -1);
130 if (axpDomain.root_bus < 0) continue;
132 axpDomain.hose = hose;
134 #ifndef FORCE_HIGH_DOMAINS
136 axpDomain.domain = axpDomain.hose = hose;
137 numDomains = axpDomain.domain + 1;
139 #else /* FORCE_HIGH_DOMAINS */
141 axpDomain.domain = numDomains - hose - 1;
143 xf86Msg(X_WARNING,
144 "FORCE_HIGH_DOMAINS - assigned hose %d to domain %d\n",
145 axpDomain.hose, axpDomain.domain);
147 #endif /* FORCE_HIGH_DOMAINS */
149 axpDomain.dense_io = _iobase(IOBASE_DENSE_IO, hose, -1, -1);
150 axpDomain.sparse_io = _iobase(IOBASE_SPARSE_IO, hose, -1, -1);
151 axpDomain.mapped_io = 0;
152 axpDomain.dense_mem = _iobase(IOBASE_DENSE_MEM, hose, -1, -1);
153 axpDomain.sparse_mem = _iobase(IOBASE_SPARSE_MEM, hose, -1, -1);
155 xf86DomainInfo[axpDomain.domain] = xnfalloc(sizeof(axpDomainRec));
156 *(xf86DomainInfo[axpDomain.domain]) = axpDomain;
159 * For now, only allow a single domain (hose) on sparse i/o systems.
161 * Allowing multiple domains on sparse systems would require:
162 * 1) either
163 * a) revamping the sparse video mapping code to allow
164 * for multiple unrelated address regions
165 * -- OR --
166 * b) implementing sparse mapping directly in
167 * xf86MapDomainMemory
168 * 2) revaming read/write sparse routines to correctly handle
169 * the solution to 1)
170 * 3) implementing a sparse I/O system (mapping, inX/outX)
171 * independent of glibc, since the glibc version only
172 * supports hose 0
174 if (axpDomain.sparse_io) {
175 if (_iobase(IOBASE_ROOT_BUS, hose + 1, -1, -1) >= 0) {
177 * It's a sparse i/o system with (at least) one more hose,
178 * show a message indicating that video is constrained to
179 * hose 0
181 xf86Msg(X_INFO,
182 "Sparse I/O system - constraining video to hose 0\n");
184 break;
188 #else /* INCLUDE_XF86_NO_DOMAIN */
191 * domain support is not included, so just set up a single domain (0)
192 * to represent the first hose so that axpPciInit will still have
193 * be able to set up the root bus
195 xf86DomainInfo[0] = xnfalloc(sizeof(axpDomainRec));
196 *(xf86DomainInfo[0]) = axpDomain;
197 numDomains = 1;
199 #endif /* INCLUDE_XF86_NO_DOMAIN */
201 return numDomains;
204 void
205 axpPciInit()
207 axpDomainPtr pDomain;
208 int domain, bus;
210 pciNumDomains = axpSetupDomains();
212 for(domain = 0; domain < pciNumDomains; domain++) {
213 if (!(pDomain = xf86DomainInfo[domain])) continue;
216 * Since any bridged buses will be behind a probed pci-pci bridge,
217 * only set up the root bus for each domain (hose) and the bridged
218 * buses will be set up as they are found.
220 /* make a bus with both the domain and the root bus in it */
221 bus = PCI_MAKE_BUS(domain, pDomain->root_bus);
222 pciBusInfo[bus] = xnfalloc(sizeof(pciBusInfo_t));
223 (void)memset(pciBusInfo[bus], 0, sizeof(pciBusInfo_t));
225 pciBusInfo[bus]->configMech = PCI_CFG_MECH_OTHER;
226 pciBusInfo[bus]->numDevices = 32;
227 pciBusInfo[bus]->funcs = &axpFuncs0;
228 pciBusInfo[bus]->pciBusPriv = pDomain;
230 pciNumBuses = bus + 1;
233 pciFindFirstFP = pciGenFindFirst;
234 pciFindNextFP = pciGenFindNext;
238 * Alpha/Linux PCI configuration space access routines
240 static int
241 axpPciBusFromTag(PCITAG tag)
243 pciBusInfo_t *pBusInfo;
244 axpDomainPtr pDomain;
245 int bus, dfn;
247 bus = PCI_BUS_FROM_TAG(tag);
248 if ((bus >= pciNumBuses)
249 || !(pBusInfo = pciBusInfo[bus])
250 || !(pDomain = pBusInfo->pciBusPriv)
251 || (pDomain->domain != PCI_DOM_FROM_TAG(tag))) return -1;
253 bus = PCI_BUS_NO_DOMAIN(bus); /* should just be root_bus */
254 dfn = PCI_DFN_FROM_TAG(tag);
255 if (_iobase(IOBASE_HOSE, -1, bus, dfn) != pDomain->hose) return -1;
257 return bus;
260 static CARD32
261 axpPciCfgRead(PCITAG tag, int off)
263 int bus, dfn;
264 CARD32 val = 0xffffffff;
266 if ((bus = axpPciBusFromTag(tag)) >= 0) {
267 dfn = PCI_DFN_FROM_TAG(tag);
269 syscall(__NR_pciconfig_read, bus, dfn, off, 4, &val);
271 return(val);
274 static void
275 axpPciCfgWrite(PCITAG tag, int off, CARD32 val)
277 int bus, dfn;
279 if ((bus = axpPciBusFromTag(tag)) >= 0) {
280 dfn = PCI_DFN_FROM_TAG(tag);
281 syscall(__NR_pciconfig_write, bus, dfn, off, 4, &val);
285 static void
286 axpPciCfgSetBits(PCITAG tag, int off, CARD32 mask, CARD32 bits)
288 int bus, dfn;
289 CARD32 val = 0xffffffff;
291 if ((bus = axpPciBusFromTag(tag)) >= 0) {
292 dfn = PCI_DFN_FROM_TAG(tag);
294 syscall(__NR_pciconfig_read, bus, dfn, off, 4, &val);
295 val = (val & ~mask) | (bits & mask);
296 syscall(__NR_pciconfig_write, bus, dfn, off, 4, &val);
300 #ifndef INCLUDE_XF86_NO_DOMAIN
303 * Alpha/Linux addressing domain support
306 _X_EXPORT int
307 xf86GetPciDomain(PCITAG Tag)
309 return PCI_DOM_FROM_TAG(Tag);
312 _X_EXPORT pointer
313 xf86MapDomainMemory(int ScreenNum, int Flags, PCITAG Tag,
314 ADDRESS Base, unsigned long Size)
316 axpDomainPtr pDomain;
317 int domain = PCI_DOM_FROM_TAG(Tag);
319 if ((domain < 0) || (domain >= pciNumDomains) ||
320 !(pDomain = xf86DomainInfo[domain]))
321 FatalError("%s called with invalid parameters\n", __FUNCTION__);
324 * xf86MapVidMem already does what we need, but remember to subtract
325 * _bus_base() (the physical dense memory root of hose 0) since
326 * xf86MapVidMem is expecting an offset relative to _bus_base() rather
327 * than an actual physical address.
329 return xf86MapVidMem(ScreenNum, Flags,
330 pDomain->dense_mem + Base - _bus_base(), Size);
333 _X_EXPORT IOADDRESS
334 xf86MapDomainIO(int ScreenNum, int Flags, PCITAG Tag,
335 IOADDRESS Base, unsigned long Size)
337 axpDomainPtr pDomain;
338 int domain = PCI_DOM_FROM_TAG(Tag);
340 if ((domain < 0) || (domain >= pciNumDomains) ||
341 !(pDomain = xf86DomainInfo[domain]))
342 FatalError("%s called with invalid parameters\n", __FUNCTION__);
345 * Use glibc inx/outx routines for sparse I/O, so just return the
346 * base [this is ok since we also constrain sparse I/O systems to
347 * a single domain in axpSetupDomains()]
349 if (pDomain->sparse_io) return Base;
352 * I/O addresses on Alpha are really just different physical memory
353 * addresses that the system corelogic turns into I/O commands on the
354 * bus, so just use xf86MapVidMem to map I/O as well, but remember
355 * to subtract _bus_base() (the physical dense memory root of hose 0)
356 * since xf86MapVidMem is expecting an offset relative to _bus_base()
357 * rather than an actual physical address.
359 * Map the entire I/O space (64kB) at once and only once.
361 if (!pDomain->mapped_io)
362 pDomain->mapped_io = (IOADDRESS)xf86MapVidMem(ScreenNum, Flags,
363 pDomain->dense_io - _bus_base(),
364 0x10000);
366 return pDomain->mapped_io + Base;
369 _X_EXPORT int
370 xf86ReadDomainMemory(PCITAG Tag, ADDRESS Base, int Len, unsigned char *Buf)
372 static unsigned long pagemask = 0;
373 unsigned char *MappedAddr;
374 unsigned long MapSize;
375 ADDRESS MapBase;
376 int i;
378 if (!pagemask) pagemask = xf86getpagesize() - 1;
380 /* Ensure page boundaries */
381 MapBase = Base & ~pagemask;
382 MapSize = ((Base + Len + pagemask) & ~pagemask) - MapBase;
385 * VIDMEM_MMIO in order to get sparse mapping on sparse memory systems
386 * so we can use mmio functions to read (that way we can really get byte
387 * at a time reads on dense memory systems with byte/word instructions.
389 MappedAddr = xf86MapDomainMemory(-1, VIDMEM_READONLY | VIDMEM_MMIO,
390 Tag, MapBase, MapSize);
392 for (i = 0; i < Len; i++) {
393 *Buf++ = xf86ReadMmio8(MappedAddr, Base - MapBase + i);
396 xf86UnMapVidMem(-1, MappedAddr, MapSize);
397 return Len;
400 resPtr
401 xf86PciBusAccWindowsFromOS(void)
403 resPtr pRes = NULL;
404 resRange range;
405 int domain;
407 for(domain = 0; domain < pciNumDomains; domain++) {
408 if (!xf86DomainInfo[domain]) continue;
410 RANGE(range, 0, 0xffffffffUL,
411 RANGE_TYPE(ResExcMemBlock, domain));
412 pRes = xf86AddResToList(pRes, &range, -1);
414 RANGE(range, 0, 0x0000ffffUL,
415 RANGE_TYPE(ResExcIoBlock, domain));
416 pRes = xf86AddResToList(pRes, &range, -1);
419 return pRes;
422 resPtr
423 xf86BusAccWindowsFromOS(void)
425 return xf86PciBusAccWindowsFromOS();
428 resPtr
429 xf86AccResFromOS(resPtr pRes)
431 resRange range;
432 int domain;
434 for(domain = 0; domain < pciNumDomains; domain++) {
435 if (!xf86DomainInfo[domain]) continue;
438 * Fallback is to claim the following areas:
440 * 0x000c0000 - 0x000effff location of VGA and other extensions ROMS
443 RANGE(range, 0x000c0000, 0x000effff,
444 RANGE_TYPE(ResExcMemBlock, domain));
445 pRes = xf86AddResToList(pRes, &range, -1);
448 * Fallback would be to claim well known ports in the 0x0 - 0x3ff
449 * range along with their sparse I/O aliases, but that's too
450 * imprecise. Instead claim a bare minimum here.
452 RANGE(range, 0x00000000, 0x000000ff,
453 RANGE_TYPE(ResExcIoBlock, domain)); /* For mainboard */
454 pRes = xf86AddResToList(pRes, &range, -1);
457 * At minimum, the top and bottom resources must be claimed, so that
458 * resources that are (or appear to be) unallocated can be relocated.
460 RANGE(range, 0x00000000, 0x00000000,
461 RANGE_TYPE(ResExcMemBlock, domain));
462 pRes = xf86AddResToList(pRes, &range, -1);
463 RANGE(range, 0xffffffff, 0xffffffff,
464 RANGE_TYPE(ResExcMemBlock, domain));
465 pRes = xf86AddResToList(pRes, &range, -1);
466 /* RANGE(range, 0x00000000, 0x00000000,
467 RANGE_TYPE(ResExcIoBlock, domain));
468 pRes = xf86AddResToList(pRes, &range, -1); */
469 RANGE(range, 0xffffffff, 0xffffffff,
470 RANGE_TYPE(ResExcIoBlock, domain));
471 pRes = xf86AddResToList(pRes, &range, -1);
474 return pRes;
477 #endif /* !INCLUDE_XF86_NO_DOMAIN */