2 * Copyright 1993 by Thomas Mueller
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Thomas Mueller not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission. Thomas Mueller makes no representations
11 * about the suitability of this software for any purpose. It is provided
12 * "as is" without express or implied warranty.
14 * THOMAS MUELLER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THOMAS MUELLER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
25 #ifdef HAVE_XORG_CONFIG_H
26 #include <xorg-config.h>
31 #include "scrnintstr.h"
35 #include "xf86_OSlib.h"
36 #include "xf86OSpriv.h"
38 #if defined(__powerpc__)
40 # if defined(USE_MACHINE_ABSOLUTE)
41 # include <machine/absolute.h>
43 # define __USER_SPACE_INCLUDE
44 # include <hw_absolute.h>
47 void ppcPciIoMap(int bus
);
54 #ifdef HAS_MTRR_SUPPORT
55 #include <sys/memrange.h>
56 #define X_MTRR_ID "XFree86"
58 static pointer
setWC(int, unsigned long, unsigned long, Bool
, MessageType
);
59 static void undoWC(int, pointer
);
60 static Bool
cleanMTRR(void);
61 static int devMemFd
= -1;
62 #define MTRR_DEVICE "/dev/mtrr"
69 int smem_remove(char *name
)
74 char *smem_create(char *name
, char *arg_addr
, long size
, int mode
)
80 int prot
= PROT_READ
|PROT_WRITE
|PROT_UNCACHE
;
81 int flags
= MAP_SHARED
;
82 off_t off
= (off_t
)arg_addr
;
84 if ((fd
= open("/dev/mem" , O_RDWR
)) < 0)
90 if (mode
== SM_DETACH
)
92 munmap(arg_addr
, len
);
97 if ((retval
= mmap (addr
, len
, prot
, flags
, fd
, off
) ) == MAP_FAILED
)
112 /***************************************************************************/
113 /* Video Memory Mapping section */
114 /***************************************************************************/
128 static _SMEMS smems
[MAX_SMEMS
];
132 #define MAP_FAILED ((void *)-1)
140 for (i
= 0; i
< MAX_SMEMS
; i
++) {
141 if (*smems
[i
].name
&& smems
[i
].ptr
) {
142 (void)smem_create(NULL
, smems
[i
].ptr
, 0, SM_DETACH
);
143 (void)smem_remove(smems
[i
].name
);
144 *smems
[i
].name
= '\0';
154 MapVidMem(int ScreenNum
, unsigned long Base
, unsigned long Size
, int flags
)
165 for (i
= 0; i
< MAX_SMEMS
; i
++)
167 if (!*smems
[i
].name
&& free_slot
== -1)
169 if (smems
[i
].Base
== Base
&& smems
[i
].Size
== Size
175 if (i
== MAX_SMEMS
&& free_slot
== -1)
177 FatalError("MapVidMem: failed to smem_create Base %x Size %x (out of SMEMS entries)\n",
182 sprintf(smems
[i
].name
, "Video-%d", i
);
183 smems
[i
].Base
= Base
;
184 smems
[i
].Size
= Size
;
186 xf86MsgVerb(X_INFO
, 3, "MapVidMem: Base=0x%x Size=0x%x\n",
189 #if defined(__powerpc__)
190 if (((unsigned long)Base
& PHYS_IO_MEM_START
) != PHYS_IO_MEM_START
) {
191 Base
= Base
| PHYS_IO_MEM_START
;
195 smems
[i
].ptr
= smem_create(smems
[i
].name
, (char *)Base
, Size
, SM_READ
|SM_WRITE
);
197 if (smems
[i
].ptr
== NULL
)
199 /* check if there is a stale segment around */
200 if (smem_remove(smems
[i
].name
) == 0) {
202 "MapVidMem: removed stale smem_ segment %s\n",
204 smems
[i
].ptr
= smem_create(smems
[i
].name
,
205 (char *)Base
, Size
, SM_READ
|SM_WRITE
);
207 if (smems
[i
].ptr
== NULL
) {
208 *smems
[i
].name
= '\0';
209 FatalError("MapVidMem: failed to smem_create Base %x Size %x (%s)\n",
210 Base
, Size
, strerror(errno
));
213 xf86MsgVerb(X_INFO
, 3, "MapVidMem: Base=0x%x Size=0x%x Ptr=0x%x\n",
214 Base
, Size
, smems
[i
].ptr
);
219 UnMapVidMem(int ScreenNum
, pointer Base
, unsigned long Size
)
223 xf86MsgVerb(X_INFO
, 3, "UnMapVidMem: Base/Ptr=0x%x Size=0x%x\n",
225 for (i
= 0; i
< MAX_SMEMS
; i
++)
227 if (*smems
[i
].name
&& smems
[i
].ptr
== Base
228 && smems
[i
].Size
== Size
)
230 if (--smems
[i
].RefCnt
> 0)
233 (void)smem_create(NULL
, smems
[i
].ptr
, 0, SM_DETACH
);
234 xf86MsgVerb(X_INFO
, 3,
235 "UnMapVidMem: smem_create(%s, 0x%08x, ... "
236 "SM_DETACH)\n", smems
[i
].name
, smems
[i
].ptr
);
237 (void)smem_remove(smems
[i
].name
);
238 *smems
[i
].name
= '\0';
243 xf86MsgVerb(X_WARNING
, 2,
244 "UnMapVidMem: no SMEM found for Base = %lx Size = %lx\n",
250 xf86OSInitVidMem(VidMemInfoPtr pVidMem
)
252 pVidMem
->linearSupported
= TRUE
;
253 pVidMem
->mapMem
= MapVidMem
;
254 pVidMem
->unmapMem
= UnMapVidMem
;
257 #ifdef HAS_MTRR_SUPPORT
259 pVidMem
->setWC
= setWC
;
260 pVidMem
->undoWC
= undoWC
;
263 pVidMem
->initialised
= TRUE
;
267 /***************************************************************************/
268 /* Interrupt Handling section */
269 /***************************************************************************/
272 xf86DisableInterrupts()
278 xf86EnableInterrupts()
283 /***************************************************************************/
284 /* I/O Permissions section for PowerPC */
285 /***************************************************************************/
287 #if defined(__powerpc__)
289 _X_EXPORT
volatile unsigned char *ioBase
= MAP_FAILED
;
290 volatile unsigned char *pciConfBase
= MAP_FAILED
;
292 static int IOEnabled
;
298 smem_create(NULL
, (char *) ioBase
, 0, SM_DETACH
);
299 smem_remove("IOBASE");
306 if (IOEnabled
++ == 0) {
307 ioBase
= (unsigned char *) smem_create("IOBASE",
308 (char *)PHYS_ISA_IO_SPACE
, 64*1024, SM_READ
|SM_WRITE
);
309 if (ioBase
== MAP_FAILED
) {
311 xf86Msg(X_WARNING
,"xf86EnableIO: Failed to map I/O\n");
315 ErrorF("xf86EnableIO: mapped I/O at vaddr 0x%08x\n",
318 atexit(removeIOSmem
);
330 if (--IOEnabled
== 0)
337 xf86DisableIOPrivs(void)
351 #ifdef HAS_MTRR_SUPPORT
352 /* memory range (MTRR) support for LynxOS (taken from BSD MTRR support) */
355 * This code is experimental. Some parts may be overkill, and other parts
360 * getAllRanges returns the full list of memory ranges with attributes set.
363 static struct mem_range_desc
*
364 getAllRanges(int *nmr
)
366 struct mem_range_desc
*mrd
;
367 struct mem_range_op mro
;
370 * Find how many ranges there are. If this fails, then the kernel
371 * probably doesn't have MTRR support.
374 if (ioctl(devMemFd
, MEMRANGE_GET
, &mro
))
376 *nmr
= mro
.mo_arg
[0];
377 mrd
= xnfalloc(*nmr
* sizeof(struct mem_range_desc
));
378 mro
.mo_arg
[0] = *nmr
;
380 if (ioctl(devMemFd
, MEMRANGE_GET
, &mro
)) {
388 * cleanMTRR removes any memory attribute that may be left by a previous
389 * X server. Normally there won't be any, but this takes care of the
390 * case where a server crashed without being able finish cleaning up.
396 struct mem_range_desc
*mrd
;
397 struct mem_range_op mro
;
400 /* This shouldn't happen */
402 if ((devMemFd
= open(MTRR_DEVICE
, O_RDONLY
)) < 0) {
408 if (!(mrd
= getAllRanges(&nmr
)))
411 for (i
= 0; i
< nmr
; i
++) {
412 if (strcmp(mrd
[i
].mr_owner
, X_MTRR_ID
) == 0 &&
413 (mrd
[i
].mr_flags
& MDF_ACTIVE
)) {
415 ErrorF("Clean for (0x%lx,0x%lx)\n",
416 (unsigned long)mrd
[i
].mr_base
,
417 (unsigned long)mrd
[i
].mr_len
);
419 if (mrd
[i
].mr_flags
& MDF_FIXACTIVE
) {
420 mro
.mo_arg
[0] = MEMRANGE_SET_UPDATE
;
421 mrd
[i
].mr_flags
= MDF_UNCACHEABLE
;
423 mro
.mo_arg
[0] = MEMRANGE_SET_REMOVE
;
425 mro
.mo_desc
= mrd
+ i
;
426 ioctl(devMemFd
, MEMRANGE_SET
, &mro
);
436 typedef struct x_RangeRec
{
437 struct mem_range_desc mrd
;
439 struct x_RangeRec
* next
;
440 } RangeRec
, *RangePtr
;
443 freeRangeList(RangePtr range
)
455 dupRangeList(RangePtr list
)
457 RangePtr
new = NULL
, rp
, p
;
461 p
= xnfalloc(sizeof(RangeRec
));
471 sortRangeList(RangePtr list
)
473 RangePtr rp1
, rp2
, copy
, sorted
= NULL
, minp
, prev
, minprev
;
474 unsigned long minBase
;
476 /* Sort by base address */
477 rp1
= copy
= dupRangeList(list
);
479 minBase
= rp1
->mrd
.mr_base
;
485 if (rp2
->mrd
.mr_base
< minBase
) {
486 minBase
= rp2
->mrd
.mr_base
;
494 minprev
->next
= minp
->next
;
506 * findRanges returns a list of ranges that overlap the specified range.
510 findRanges(unsigned long base
, unsigned long size
, RangePtr
*ucp
, RangePtr
*wcp
)
512 struct mem_range_desc
*mrd
;
516 if (!(mrd
= getAllRanges(&nmr
)))
519 for (i
= 0; i
< nmr
; i
++) {
520 if ((mrd
[i
].mr_flags
& MDF_ACTIVE
) &&
521 mrd
[i
].mr_base
< base
+ size
&&
522 mrd
[i
].mr_base
+ mrd
[i
].mr_len
> base
) {
523 if (mrd
[i
].mr_flags
& MDF_WRITECOMBINE
)
525 else if (mrd
[i
].mr_flags
& MDF_UNCACHEABLE
)
529 rp
= xnfalloc(sizeof(RangeRec
));
539 * This checks if the existing overlapping ranges fully cover the requested
540 * range. Is this overkill?
544 fullCoverage(unsigned long base
, unsigned long size
, RangePtr overlap
)
546 RangePtr rp1
, sorted
= NULL
;
549 sorted
= sortRangeList(overlap
);
554 if (rp1
->mrd
.mr_base
> base
) {
555 freeRangeList(sorted
);
558 base
= rp1
->mrd
.mr_base
+ rp1
->mrd
.mr_len
;
561 freeRangeList(sorted
);
566 freeRangeList(sorted
);
571 addWC(int screenNum
, unsigned long base
, unsigned long size
, MessageType from
)
573 RangePtr uc
= NULL
, wc
= NULL
, retlist
= NULL
;
574 struct mem_range_desc mrd
;
575 struct mem_range_op mro
;
577 findRanges(base
, size
, &uc
, &wc
);
579 /* See of the full range is already WC */
580 if (!uc
&& fullCoverage(base
, size
, wc
)) {
581 xf86DrvMsg(screenNum
, from
,
582 "Write-combining range (0x%lx,0x%lx) was already set\n",
587 /* Otherwise, try to add the new range */
590 strcpy(mrd
.mr_owner
, X_MTRR_ID
);
591 mrd
.mr_flags
= MDF_WRITECOMBINE
;
593 mro
.mo_arg
[0] = MEMRANGE_SET_UPDATE
;
594 if (ioctl(devMemFd
, MEMRANGE_SET
, &mro
)) {
595 xf86DrvMsg(screenNum
, X_WARNING
,
596 "Failed to set write-combining range "
597 "(0x%lx,0x%lx)\n", base
, size
);
600 xf86DrvMsg(screenNum
, from
,
601 "Write-combining range (0x%lx,0x%lx)\n", base
, size
);
602 retlist
= xnfalloc(sizeof(RangeRec
));
604 retlist
->wasWC
= FALSE
;
605 retlist
->next
= NULL
;
611 delWC(int screenNum
, unsigned long base
, unsigned long size
, MessageType from
)
613 RangePtr uc
= NULL
, wc
= NULL
, retlist
= NULL
;
614 struct mem_range_desc mrd
;
615 struct mem_range_op mro
;
617 findRanges(base
, size
, &uc
, &wc
);
620 * See of the full range is already not WC, or if there is full
621 * coverage from UC ranges.
623 if (!wc
|| fullCoverage(base
, size
, uc
)) {
624 xf86DrvMsg(screenNum
, from
,
625 "Write-combining range (0x%lx,0x%lx) was already clear\n",
630 /* Otherwise, try to add the new range */
633 strcpy(mrd
.mr_owner
, X_MTRR_ID
);
634 mrd
.mr_flags
= MDF_UNCACHEABLE
;
636 mro
.mo_arg
[0] = MEMRANGE_SET_UPDATE
;
637 if (ioctl(devMemFd
, MEMRANGE_SET
, &mro
)) {
638 xf86DrvMsg(screenNum
, X_WARNING
,
639 "Failed to remove write-combining range "
640 "(0x%lx,0x%lx)\n", base
, size
);
641 /* XXX Should then remove all of the overlapping WC ranges */
644 xf86DrvMsg(screenNum
, from
,
645 "Removed Write-combining range (0x%lx,0x%lx)\n",
647 retlist
= xnfalloc(sizeof(RangeRec
));
649 retlist
->wasWC
= TRUE
;
650 retlist
->next
= NULL
;
656 setWC(int screenNum
, unsigned long base
, unsigned long size
, Bool enable
,
660 return addWC(screenNum
, base
, size
, from
);
662 return delWC(screenNum
, base
, size
, from
);
666 undoWC(int screenNum
, pointer list
)
669 struct mem_range_op mro
;
675 ErrorF("Undo for (0x%lx,0x%lx), %d\n",
676 (unsigned long)rp
->mrd
.mr_base
,
677 (unsigned long)rp
->mrd
.mr_len
, rp
->wasWC
);
681 mro
.mo_arg
[0] = MEMRANGE_SET_UPDATE
;
682 rp
->mrd
.mr_flags
= MDF_WRITECOMBINE
;
683 strcpy(rp
->mrd
.mr_owner
, "unknown");
685 mro
.mo_arg
[0] = MEMRANGE_SET_REMOVE
;
687 mro
.mo_desc
= &rp
->mrd
;
689 if (ioctl(devMemFd
, MEMRANGE_SET
, &mro
)) {
691 mro
.mo_arg
[0] = MEMRANGE_SET_UPDATE
;
692 rp
->mrd
.mr_flags
= MDF_UNCACHEABLE
;
693 strcpy(rp
->mrd
.mr_owner
, "unknown");
694 if (ioctl(devMemFd
, MEMRANGE_SET
, &mro
))
700 xf86DrvMsg(screenNum
, X_WARNING
,
701 "Failed to restore MTRR range (0x%lx,0x%lx)\n",
702 (unsigned long)rp
->mrd
.mr_base
,
703 (unsigned long)rp
->mrd
.mr_len
);
709 #endif /* HAS_MTRR_SUPPORT */