First import
[xorg_rtime.git] / xorg-server-1.4 / hw / xfree86 / os-support / lynxos / lynx_video.c
blob4602076c7c4feeeb04ca0deda6b6c7f33015e01b
1 /*
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>
27 #endif
29 #include <X11/X.h>
30 #include "input.h"
31 #include "scrnintstr.h"
33 #include "xf86.h"
34 #include "xf86Priv.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>
42 # else
43 # define __USER_SPACE_INCLUDE
44 # include <hw_absolute.h>
45 # endif
47 void ppcPciIoMap(int bus);
48 #endif
50 #if 0
51 #define DEBUG
52 #endif
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"
63 #endif
66 #if !defined(NO_MMAP)
67 #include <sys/mman.h>
69 int smem_remove(char *name)
71 return(0);
74 char *smem_create(char *name, char *arg_addr, long size, int mode)
76 int fd;
77 void *addr = 0;
78 char *retval;
79 size_t len = size;
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)
86 retval = (char *)-1;
88 else
90 if (mode == SM_DETACH)
92 munmap(arg_addr, len);
93 retval = 0;
95 else
97 if ((retval = mmap (addr, len, prot, flags, fd, off) ) == MAP_FAILED)
99 retval = (char *)-1;
103 close(fd);
106 return(retval);
109 #endif
112 /***************************************************************************/
113 /* Video Memory Mapping section */
114 /***************************************************************************/
116 typedef struct
118 char name[16];
119 unsigned long Base;
120 unsigned long Size;
121 char *ptr;
122 int RefCnt;
124 _SMEMS;
126 #define MAX_SMEMS 16
128 static _SMEMS smems[MAX_SMEMS];
131 #ifndef MAP_FAILED
132 #define MAP_FAILED ((void *)-1)
133 #endif
135 static void
136 smemCleanup(void)
138 int i;
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';
145 smems[i].ptr = NULL;
146 smems[i].Base = 0;
147 smems[i].Size = 0;
148 smems[i].RefCnt = 0;
153 static pointer
154 MapVidMem(int ScreenNum, unsigned long Base, unsigned long Size, int flags)
156 static int once;
157 int free_slot = -1;
158 int i;
160 if (!once)
162 atexit(smemCleanup);
163 once = 1;
165 for (i = 0; i < MAX_SMEMS; i++)
167 if (!*smems[i].name && free_slot == -1)
168 free_slot = i;
169 if (smems[i].Base == Base && smems[i].Size == Size
170 && *smems[i].name) {
171 smems[i].RefCnt++;
172 return smems[i].ptr;
175 if (i == MAX_SMEMS && free_slot == -1)
177 FatalError("MapVidMem: failed to smem_create Base %x Size %x (out of SMEMS entries)\n",
178 Base, Size);
181 i = free_slot;
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",
187 Base, Size);
189 #if defined(__powerpc__)
190 if (((unsigned long)Base & PHYS_IO_MEM_START) != PHYS_IO_MEM_START) {
191 Base = Base | PHYS_IO_MEM_START;
193 #endif
195 smems[i].ptr = smem_create(smems[i].name, (char *)Base, Size, SM_READ|SM_WRITE);
196 smems[i].RefCnt = 1;
197 if (smems[i].ptr == NULL)
199 /* check if there is a stale segment around */
200 if (smem_remove(smems[i].name) == 0) {
201 xf86Msg(X_INFO,
202 "MapVidMem: removed stale smem_ segment %s\n",
203 smems[i].name);
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);
215 return smems[i].ptr;
218 static void
219 UnMapVidMem(int ScreenNum, pointer Base, unsigned long Size)
221 int i;
223 xf86MsgVerb(X_INFO, 3, "UnMapVidMem: Base/Ptr=0x%x Size=0x%x\n",
224 Base, Size);
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)
231 return;
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';
239 smems[i].RefCnt = 0;
240 return;
243 xf86MsgVerb(X_WARNING, 2,
244 "UnMapVidMem: no SMEM found for Base = %lx Size = %lx\n",
245 Base, Size);
249 void
250 xf86OSInitVidMem(VidMemInfoPtr pVidMem)
252 pVidMem->linearSupported = TRUE;
253 pVidMem->mapMem = MapVidMem;
254 pVidMem->unmapMem = UnMapVidMem;
255 pVidMem->setWC = 0;
256 pVidMem->undoWC = 0;
257 #ifdef HAS_MTRR_SUPPORT
258 if (cleanMTRR()) {
259 pVidMem->setWC = setWC;
260 pVidMem->undoWC = undoWC;
262 #endif
263 pVidMem->initialised = TRUE;
267 /***************************************************************************/
268 /* Interrupt Handling section */
269 /***************************************************************************/
271 _X_EXPORT Bool
272 xf86DisableInterrupts()
274 return(TRUE);
277 _X_EXPORT void
278 xf86EnableInterrupts()
280 return;
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;
295 static void
296 removeIOSmem(void)
298 smem_create(NULL, (char *) ioBase, 0, SM_DETACH);
299 smem_remove("IOBASE");
300 ioBase = MAP_FAILED;
303 _X_EXPORT Bool
304 xf86EnableIO()
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) {
310 --IOEnabled;
311 xf86Msg(X_WARNING,"xf86EnableIO: Failed to map I/O\n");
312 return FALSE;
313 } else {
314 #ifdef DEBUG
315 ErrorF("xf86EnableIO: mapped I/O at vaddr 0x%08x\n",
316 ioBase);
317 #endif
318 atexit(removeIOSmem);
321 return TRUE;
324 _X_EXPORT void
325 xf86DisableIO()
327 if (!IOEnabled)
328 return;
330 if (--IOEnabled == 0)
331 removeIOSmem();
332 return;
335 #if 0
336 void
337 xf86DisableIOPrivs(void)
339 return;
341 #endif
342 void
343 ppcPciIoMap(int bus)
345 xf86EnableIO();
348 #endif
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
356 * may be incomplete.
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.
373 mro.mo_arg[0] = 0;
374 if (ioctl(devMemFd, MEMRANGE_GET, &mro))
375 return NULL;
376 *nmr = mro.mo_arg[0];
377 mrd = xnfalloc(*nmr * sizeof(struct mem_range_desc));
378 mro.mo_arg[0] = *nmr;
379 mro.mo_desc = mrd;
380 if (ioctl(devMemFd, MEMRANGE_GET, &mro)) {
381 xfree(mrd);
382 return NULL;
384 return mrd;
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.
393 static Bool
394 cleanMTRR()
396 struct mem_range_desc *mrd;
397 struct mem_range_op mro;
398 int nmr, i;
400 /* This shouldn't happen */
401 if (devMemFd < 0) {
402 if ((devMemFd = open(MTRR_DEVICE, O_RDONLY)) < 0) {
403 perror("open MTRR");
404 return FALSE;
408 if (!(mrd = getAllRanges(&nmr)))
409 return FALSE;
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)) {
414 #ifdef DEBUG
415 ErrorF("Clean for (0x%lx,0x%lx)\n",
416 (unsigned long)mrd[i].mr_base,
417 (unsigned long)mrd[i].mr_len);
418 #endif
419 if (mrd[i].mr_flags & MDF_FIXACTIVE) {
420 mro.mo_arg[0] = MEMRANGE_SET_UPDATE;
421 mrd[i].mr_flags = MDF_UNCACHEABLE;
422 } else {
423 mro.mo_arg[0] = MEMRANGE_SET_REMOVE;
425 mro.mo_desc = mrd + i;
426 ioctl(devMemFd, MEMRANGE_SET, &mro);
429 #ifdef DEBUG
430 sleep(10);
431 #endif
432 xfree(mrd);
433 return TRUE;
436 typedef struct x_RangeRec {
437 struct mem_range_desc mrd;
438 Bool wasWC;
439 struct x_RangeRec * next;
440 } RangeRec, *RangePtr;
442 static void
443 freeRangeList(RangePtr range)
445 RangePtr rp;
447 while (range) {
448 rp = range;
449 range = rp->next;
450 xfree(rp);
454 static RangePtr
455 dupRangeList(RangePtr list)
457 RangePtr new = NULL, rp, p;
459 rp = list;
460 while (rp) {
461 p = xnfalloc(sizeof(RangeRec));
462 *p = *rp;
463 p->next = new;
464 new = p;
465 rp = rp->next;
467 return new;
470 static RangePtr
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);
478 while (rp1) {
479 minBase = rp1->mrd.mr_base;
480 minp = rp1;
481 minprev = NULL;
482 prev = rp1;
483 rp2 = rp1->next;
484 while (rp2) {
485 if (rp2->mrd.mr_base < minBase) {
486 minBase = rp2->mrd.mr_base;
487 minp = rp2;
488 minprev = prev;
490 prev = rp2;
491 rp2 = rp2->next;
493 if (minprev) {
494 minprev->next = minp->next;
495 rp1 = copy;
496 } else {
497 rp1 = minp->next;
499 minp->next = sorted;
500 sorted = minp;
502 return sorted;
506 * findRanges returns a list of ranges that overlap the specified range.
509 static void
510 findRanges(unsigned long base, unsigned long size, RangePtr *ucp, RangePtr *wcp)
512 struct mem_range_desc *mrd;
513 int nmr, i;
514 RangePtr rp, *p;
516 if (!(mrd = getAllRanges(&nmr)))
517 return;
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)
524 p = wcp;
525 else if (mrd[i].mr_flags & MDF_UNCACHEABLE)
526 p = ucp;
527 else
528 continue;
529 rp = xnfalloc(sizeof(RangeRec));
530 rp->mrd = mrd[i];
531 rp->next = *p;
532 *p = rp;
535 xfree(mrd);
539 * This checks if the existing overlapping ranges fully cover the requested
540 * range. Is this overkill?
543 static Bool
544 fullCoverage(unsigned long base, unsigned long size, RangePtr overlap)
546 RangePtr rp1, sorted = NULL;
547 unsigned long end;
549 sorted = sortRangeList(overlap);
550 /* Look for gaps */
551 rp1 = sorted;
552 end = base + size;
553 while (rp1) {
554 if (rp1->mrd.mr_base > base) {
555 freeRangeList(sorted);
556 return FALSE;
557 } else {
558 base = rp1->mrd.mr_base + rp1->mrd.mr_len;
560 if (base >= end) {
561 freeRangeList(sorted);
562 return TRUE;
564 rp1 = rp1->next;
566 freeRangeList(sorted);
567 return FALSE;
570 static pointer
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",
583 base, size);
584 return NULL;
587 /* Otherwise, try to add the new range */
588 mrd.mr_base = base;
589 mrd.mr_len = size;
590 strcpy(mrd.mr_owner, X_MTRR_ID);
591 mrd.mr_flags = MDF_WRITECOMBINE;
592 mro.mo_desc = &mrd;
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);
598 return NULL;
599 } else {
600 xf86DrvMsg(screenNum, from,
601 "Write-combining range (0x%lx,0x%lx)\n", base, size);
602 retlist = xnfalloc(sizeof(RangeRec));
603 retlist->mrd = mrd;
604 retlist->wasWC = FALSE;
605 retlist->next = NULL;
606 return retlist;
610 static pointer
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",
626 base, size);
627 return NULL;
630 /* Otherwise, try to add the new range */
631 mrd.mr_base = base;
632 mrd.mr_len = size;
633 strcpy(mrd.mr_owner, X_MTRR_ID);
634 mrd.mr_flags = MDF_UNCACHEABLE;
635 mro.mo_desc = &mrd;
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 */
642 return NULL;
643 } else {
644 xf86DrvMsg(screenNum, from,
645 "Removed Write-combining range (0x%lx,0x%lx)\n",
646 base, size);
647 retlist = xnfalloc(sizeof(RangeRec));
648 retlist->mrd = mrd;
649 retlist->wasWC = TRUE;
650 retlist->next = NULL;
651 return retlist;
655 static pointer
656 setWC(int screenNum, unsigned long base, unsigned long size, Bool enable,
657 MessageType from)
659 if (enable)
660 return addWC(screenNum, base, size, from);
661 else
662 return delWC(screenNum, base, size, from);
665 static void
666 undoWC(int screenNum, pointer list)
668 RangePtr rp;
669 struct mem_range_op mro;
670 Bool failed;
672 rp = list;
673 while (rp) {
674 #ifdef DEBUG
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);
678 #endif
679 failed = FALSE;
680 if (rp->wasWC) {
681 mro.mo_arg[0] = MEMRANGE_SET_UPDATE;
682 rp->mrd.mr_flags = MDF_WRITECOMBINE;
683 strcpy(rp->mrd.mr_owner, "unknown");
684 } else {
685 mro.mo_arg[0] = MEMRANGE_SET_REMOVE;
687 mro.mo_desc = &rp->mrd;
689 if (ioctl(devMemFd, MEMRANGE_SET, &mro)) {
690 if (!rp->wasWC) {
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))
695 failed = TRUE;
696 } else
697 failed = TRUE;
699 if (failed) {
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);
705 rp = rp->next;
709 #endif /* HAS_MTRR_SUPPORT */