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"
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
{
79 unsigned long dense_io
, sparse_io
;
80 unsigned long dense_mem
, sparse_mem
;
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.
95 # define FORCE_HIGH_DOMAINS MAX_DOMAINS /* assign domains downward from here */
99 * If FORCE_HIGH_DOMAINS is set, make sure it's not larger than the
102 #if defined(FORCE_HIGH_DOMAINS) && (FORCE_HIGH_DOMAINS > MAX_DOMAINS)
103 # undef FORCE_HIGH_DOMAINS
104 # define FORCE_HIGH_DOMAINS MAX_DOMAINS
108 axpSetupDomains(void)
110 axpDomainRec axpDomain
;
114 #ifndef INCLUDE_XF86_NO_DOMAIN
116 #ifdef FORCE_HIGH_DOMAINS
118 "DEBUG OPTION FORCE_HIGH_DOMAINS in use - DRI will *NOT* work\n");
119 numDomains
= FORCE_HIGH_DOMAINS
;
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;
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:
163 * a) revamping the sparse video mapping code to allow
164 * for multiple unrelated address regions
166 * b) implementing sparse mapping directly in
167 * xf86MapDomainMemory
168 * 2) revaming read/write sparse routines to correctly handle
170 * 3) implementing a sparse I/O system (mapping, inX/outX)
171 * independent of glibc, since the glibc version only
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
182 "Sparse I/O system - constraining video to hose 0\n");
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
;
199 #endif /* INCLUDE_XF86_NO_DOMAIN */
207 axpDomainPtr pDomain
;
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
241 axpPciBusFromTag(PCITAG tag
)
243 pciBusInfo_t
*pBusInfo
;
244 axpDomainPtr pDomain
;
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;
261 axpPciCfgRead(PCITAG tag
, int off
)
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
);
275 axpPciCfgWrite(PCITAG tag
, int off
, CARD32 val
)
279 if ((bus
= axpPciBusFromTag(tag
)) >= 0) {
280 dfn
= PCI_DFN_FROM_TAG(tag
);
281 syscall(__NR_pciconfig_write
, bus
, dfn
, off
, 4, &val
);
286 axpPciCfgSetBits(PCITAG tag
, int off
, CARD32 mask
, CARD32 bits
)
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
307 xf86GetPciDomain(PCITAG Tag
)
309 return PCI_DOM_FROM_TAG(Tag
);
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
);
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(),
366 return pDomain
->mapped_io
+ Base
;
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
;
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
);
401 xf86PciBusAccWindowsFromOS(void)
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);
423 xf86BusAccWindowsFromOS(void)
425 return xf86PciBusAccWindowsFromOS();
429 xf86AccResFromOS(resPtr pRes
)
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);
477 #endif /* !INCLUDE_XF86_NO_DOMAIN */