1/*
2 * Copyright 1992 by Orest Zborowski <obz@Kodak.com>
3 * Copyright 1993 by David Wexelblat <dwex@goblin.org>
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the names of Orest Zborowski and David Wexelblat
10 * not be used in advertising or publicity pertaining to distribution of
11 * the software without specific, written prior permission.  Orest Zborowski
12 * and David Wexelblat make no representations about the suitability of this
13 * software for any purpose.  It is provided "as is" without express or
14 * implied warranty.
15 *
16 * OREST ZBOROWSKI AND DAVID WEXELBLAT DISCLAIMS ALL WARRANTIES WITH REGARD
17 * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
18 * FITNESS, IN NO EVENT SHALL OREST ZBOROWSKI OR DAVID WEXELBLAT BE LIABLE
19 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
21 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
22 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 *
24 */
25
26#ifdef HAVE_XORG_CONFIG_H
27#include <xorg-config.h>
28#endif
29
30#include <errno.h>
31#include <string.h>
32
33#include <X11/X.h>
34#include "input.h"
35#include "scrnintstr.h"
36
37#include "xf86.h"
38#include "xf86Priv.h"
39#include "xf86_OSlib.h"
40#include "xf86OSpriv.h"
41#ifdef __alpha__
42#include "shared/xf86Axp.h"
43#endif
44
45#ifdef HAS_MTRR_SUPPORT
46#include <asm/mtrr.h>
47#endif
48
49#ifndef MAP_FAILED
50#define MAP_FAILED ((void *)-1)
51#endif
52
53static Bool ExtendedEnabled = FALSE;
54
55#ifdef __ia64__
56
57#include "compiler.h"
58#include <sys/io.h>
59
60#elif !defined(__powerpc__) && \
61      !defined(__mc68000__) && \
62      !defined(__sparc__) && \
63      !defined(__mips__) && \
64      !defined(__nds32__) && \
65      !defined(__arm__)
66
67/*
68 * Due to conflicts with "compiler.h", don't rely on <sys/io.h> to declare
69 * these.
70 */
71extern int ioperm(unsigned long __from, unsigned long __num, int __turn_on);
72extern int iopl(int __level);
73
74#endif
75
76#ifdef __alpha__
77# define BUS_BASE bus_base
78#else
79#define BUS_BASE (0)
80#endif /*  __alpha__ */
81
82/***************************************************************************/
83/* Video Memory Mapping section                                            */
84/***************************************************************************/
85
86static pointer mapVidMem(int, unsigned long, unsigned long, int);
87static void unmapVidMem(int, pointer, unsigned long);
88#if defined (__alpha__)
89extern void sethae(unsigned long hae);
90extern unsigned long _bus_base __P ((void)) __attribute__ ((const));
91extern unsigned long _bus_base_sparse __P ((void)) __attribute__ ((const));
92
93static pointer mapVidMemSparse(int, unsigned long, unsigned long, int);
94extern axpDevice lnxGetAXP(void);
95static void unmapVidMemSparse(int, pointer, unsigned long);
96static axpDevice axpSystem = -1;
97static Bool needSparse;
98static unsigned long hae_thresh;
99static unsigned long hae_mask;
100static unsigned long bus_base;
101#endif
102
103#ifdef HAS_MTRR_SUPPORT
104
105#define SPLIT_WC_REGIONS 1
106
107static pointer setWC(int, unsigned long, unsigned long, Bool, MessageType);
108static void undoWC(int, pointer);
109
110/* The file desc for /proc/mtrr. Once opened, left opened, and the mtrr
111   driver will clean up when we exit. */
112#define MTRR_FD_UNOPENED (-1)	/* We have yet to open /proc/mtrr */
113#define MTRR_FD_PROBLEM (-2)	/* We tried to open /proc/mtrr, but had
114				   a problem. */
115static int mtrr_fd = MTRR_FD_UNOPENED;
116
117/* Open /proc/mtrr. FALSE on failure. Will always fail on Linux 2.0,
118   and will fail on Linux 2.2 with MTRR support configured out,
119   so verbosity should be chosen appropriately. */
120static Bool
121mtrr_open(int verbosity)
122{
123	/* Only report absence of /proc/mtrr once. */
124	static Bool warned = FALSE;
125
126	if (mtrr_fd == MTRR_FD_UNOPENED) {
127		mtrr_fd = open("/proc/mtrr", O_WRONLY);
128
129		if (mtrr_fd < 0)
130			mtrr_fd = MTRR_FD_PROBLEM;
131	}
132
133	if (mtrr_fd == MTRR_FD_PROBLEM) {
134		/* To make sure we only ever warn once, need to check
135		   verbosity outside xf86MsgVerb */
136		if (!warned && verbosity <= xf86GetVerbosity()) {
137			xf86MsgVerb(X_WARNING, verbosity,
138				  "System lacks support for changing MTRRs\n");
139			warned = TRUE;
140		}
141
142		return FALSE;
143	}
144	else
145		return TRUE;
146}
147
148/*
149 * We maintain a list of WC regions for each physical mapping so they can
150 * be undone when unmapping.
151 */
152
153struct mtrr_wc_region {
154	struct mtrr_sentry	sentry;
155	Bool			added;		/* added WC or removed it */
156	struct mtrr_wc_region *	next;
157};
158
159
160static struct mtrr_wc_region *
161mtrr_cull_wc_region(int screenNum, unsigned long base, unsigned long size,
162		      MessageType from)
163{
164	/* Some BIOS writers thought that setting wc over the mmio
165	   region of a graphics devices was a good idea. Try to fix
166	   it. */
167
168	struct mtrr_gentry gent;
169	struct mtrr_wc_region *wcreturn = NULL, *wcr;
170	int count, ret=0;
171
172	/* Linux 2.0 users should not get a warning without -verbose */
173	if (!mtrr_open(2))
174		return NULL;
175
176	for (gent.regnum = 0;
177	     ioctl(mtrr_fd, MTRRIOC_GET_ENTRY, &gent) >= 0;
178	     gent.regnum++) {
179		if (gent.type != MTRR_TYPE_WRCOMB
180		    || gent.base + gent.size <= base
181		    || base + size <= gent.base)
182			continue;
183
184		/* Found an overlapping region. Delete it. */
185
186		wcr = malloc(sizeof(*wcr));
187		if (!wcr)
188			return NULL;
189		wcr->sentry.base = gent.base;
190		wcr->sentry.size = gent.size;
191		wcr->sentry.type = MTRR_TYPE_WRCOMB;
192		wcr->added = FALSE;
193
194		count = 3;
195		while (count-- &&
196		       (ret = ioctl(mtrr_fd, MTRRIOC_KILL_ENTRY, &(wcr->sentry))) < 0);
197
198		if (ret >= 0) {
199			xf86DrvMsg(screenNum, from,
200				   "Removed MMIO write-combining range "
201				   "(0x%lx,0x%lx)\n",
202				   (unsigned long) gent.base, (unsigned long) gent.size);
203			wcr->next = wcreturn;
204			wcreturn = wcr;
205			gent.regnum--;
206		} else {
207			free(wcr);
208			xf86DrvMsgVerb(screenNum, X_WARNING, 0,
209				   "Failed to remove MMIO "
210				   "write-combining range (0x%lx,0x%lx)\n",
211				       gent.base, (unsigned long) gent.size);
212		}
213	}
214	return wcreturn;
215}
216
217
218static struct mtrr_wc_region *
219mtrr_remove_offending(int screenNum, unsigned long base, unsigned long size,
220		      MessageType from)
221{
222    struct mtrr_gentry gent;
223    struct mtrr_wc_region *wcreturn = NULL, **wcr;
224
225    if (!mtrr_open(2))
226	return NULL;
227
228    wcr = &wcreturn;
229    for (gent.regnum = 0;
230	 ioctl(mtrr_fd, MTRRIOC_GET_ENTRY, &gent) >= 0; gent.regnum++ ) {
231	if (gent.type == MTRR_TYPE_WRCOMB
232	    && ((gent.base >= base && gent.base + gent.size < base + size) ||
233		(gent.base >  base && gent.base + gent.size <= base + size))) {
234	    *wcr = mtrr_cull_wc_region(screenNum, gent.base, gent.size, from);
235	    if (*wcr) gent.regnum--;
236	    while(*wcr) {
237		wcr = &((*wcr)->next);
238	    }
239	}
240    }
241    return wcreturn;
242}
243
244
245static struct mtrr_wc_region *
246mtrr_add_wc_region(int screenNum, unsigned long base, unsigned long size,
247		   MessageType from)
248{
249        struct mtrr_wc_region **wcr, *wcreturn, *curwcr;
250
251       /*
252        * There can be only one....
253        */
254
255	wcreturn = mtrr_remove_offending(screenNum, base, size, from);
256	wcr = &wcreturn;
257	while (*wcr) {
258	    wcr = &((*wcr)->next);
259	}
260
261	/* Linux 2.0 should not warn, unless the user explicitly asks for
262	   WC. */
263
264	if (!mtrr_open(from == X_CONFIG ? 0 : 2))
265		return wcreturn;
266
267	*wcr = curwcr = malloc(sizeof(**wcr));
268	if (!curwcr)
269	    return wcreturn;
270
271	curwcr->sentry.base = base;
272	curwcr->sentry.size = size;
273	curwcr->sentry.type = MTRR_TYPE_WRCOMB;
274	curwcr->added = TRUE;
275	curwcr->next = NULL;
276
277#if SPLIT_WC_REGIONS
278	/*
279	 * Splits up the write-combining region if it is not aligned on a
280 	 * size boundary.
281	 */
282
283	{
284	    unsigned long lbase, d_size = 1;
285	    unsigned long n_size = size;
286	    unsigned long n_base = base;
287
288	    for (lbase = n_base, d_size = 1; !(lbase & 1);
289		 lbase = lbase >> 1, d_size <<= 1);
290	    while (d_size > n_size)
291		d_size = d_size >> 1;
292	    DebugF("WC_BASE: 0x%lx WC_END: 0x%lx\n",base,base+d_size-1);
293	    n_base += d_size;
294	    n_size -= d_size;
295	    if (n_size) {
296		xf86DrvMsgVerb(screenNum,X_INFO,3,"Splitting WC range: "
297			       "base: 0x%lx, size: 0x%lx\n",base,size);
298		curwcr->next = mtrr_add_wc_region(screenNum, n_base, n_size,from);
299	    }
300	    curwcr->sentry.size = d_size;
301	}
302
303	/*****************************************************************/
304#endif /* SPLIT_WC_REGIONS */
305
306	if (ioctl(mtrr_fd, MTRRIOC_ADD_ENTRY, &curwcr->sentry) >= 0) {
307		/* Avoid printing on every VT switch */
308		if (xf86ServerIsInitialising()) {
309			xf86DrvMsg(screenNum, from,
310				   "Write-combining range (0x%lx,0x%lx)\n",
311				   base, size);
312		}
313		return wcreturn;
314	}
315	else {
316	        *wcr = curwcr->next;
317		free(curwcr);
318
319		/* Don't complain about the VGA region: MTRR fixed
320		   regions aren't currently supported, but might be in
321		   the future. */
322		if ((unsigned long)base >= 0x100000) {
323			xf86DrvMsgVerb(screenNum, X_WARNING, 0,
324				"Failed to set up write-combining range "
325				"(0x%lx,0x%lx)\n", base, size);
326		}
327		return wcreturn;
328	}
329}
330
331static void
332mtrr_undo_wc_region(int screenNum, struct mtrr_wc_region *wcr)
333{
334	struct mtrr_wc_region *p, *prev;
335
336	if (mtrr_fd >= 0) {
337		p = wcr;
338		while (p) {
339			if (p->added)
340				ioctl(mtrr_fd, MTRRIOC_DEL_ENTRY, &p->sentry);
341			prev = p;
342			p = p->next;
343			free(prev);
344		}
345	}
346}
347
348static pointer
349setWC(int screenNum, unsigned long base, unsigned long size, Bool enable,
350      MessageType from)
351{
352	if (enable)
353		return mtrr_add_wc_region(screenNum, base, size, from);
354	else
355		return mtrr_cull_wc_region(screenNum, base, size, from);
356}
357
358static void
359undoWC(int screenNum, pointer regioninfo)
360{
361	mtrr_undo_wc_region(screenNum, regioninfo);
362}
363
364#endif /* HAS_MTRR_SUPPORT */
365
366void
367xf86OSInitVidMem(VidMemInfoPtr pVidMem)
368{
369	pVidMem->linearSupported = TRUE;
370#ifdef __alpha__
371	if (axpSystem == -1) {
372	  axpSystem = lnxGetAXP();
373	  if ((needSparse = (_bus_base_sparse() > 0))) {
374	    hae_thresh = xf86AXPParams[axpSystem].hae_thresh;
375	    hae_mask = xf86AXPParams[axpSystem].hae_mask;
376	  }
377	  bus_base = _bus_base();
378	}
379	if (needSparse) {
380	  xf86Msg(X_INFO,"Machine needs sparse mapping\n");
381	  pVidMem->mapMem = mapVidMemSparse;
382	  pVidMem->unmapMem = unmapVidMemSparse;
383	} else {
384	  xf86Msg(X_INFO,"Machine type has 8/16 bit access\n");
385	  pVidMem->mapMem = mapVidMem;
386	  pVidMem->unmapMem = unmapVidMem;
387	}
388#else
389	pVidMem->mapMem = mapVidMem;
390	pVidMem->unmapMem = unmapVidMem;
391#endif /* __alpha__ */
392
393
394#ifdef HAS_MTRR_SUPPORT
395	pVidMem->setWC = setWC;
396	pVidMem->undoWC = undoWC;
397#endif
398	pVidMem->initialised = TRUE;
399}
400
401#ifdef __sparc__
402/* Basically, you simply cannot do this on Sparc.  You have to do something portable
403 * like use /dev/fb* or mmap() on /proc/bus/pci/X/Y nodes. -DaveM
404 */
405static pointer mapVidMem(int ScreenNum, unsigned long Base, unsigned long Size, int flags)
406{
407	return NULL;
408}
409#else
410static pointer
411mapVidMem(int ScreenNum, unsigned long Base, unsigned long Size, int flags)
412{
413    pointer base;
414    int fd;
415    int mapflags = MAP_SHARED;
416    int prot;
417    memType realBase, alignOff;
418
419    realBase = Base & ~(getpagesize() - 1);
420    alignOff = Base - realBase;
421    DebugF("base: %lx, realBase: %lx, alignOff: %lx \n",
422	   Base,realBase,alignOff);
423
424#if defined(__ia64__) || defined(__arm__) || defined(__s390__)
425#ifndef MAP_WRITECOMBINED
426#define MAP_WRITECOMBINED 0x00010000
427#endif
428#ifndef MAP_NONCACHED
429#define MAP_NONCACHED 0x00020000
430#endif
431    if(flags & VIDMEM_FRAMEBUFFER)
432        mapflags |= MAP_WRITECOMBINED;
433    else
434        mapflags |= MAP_NONCACHED;
435#endif
436
437#if 0
438    /* this will disappear when people upgrade their kernels */
439    fd = open(DEV_MEM,
440	      ((flags & VIDMEM_READONLY) ? O_RDONLY : O_RDWR) | O_SYNC);
441#else
442    fd = open(DEV_MEM, (flags & VIDMEM_READONLY) ? O_RDONLY : O_RDWR);
443#endif
444    if (fd < 0)
445    {
446	FatalError("xf86MapVidMem: failed to open " DEV_MEM " (%s)\n",
447		   strerror(errno));
448    }
449
450    if (flags & VIDMEM_READONLY)
451	prot = PROT_READ;
452    else
453	prot = PROT_READ | PROT_WRITE;
454
455    /* This requires linux-0.99.pl10 or above */
456    base = mmap((caddr_t)0, Size + alignOff, prot, mapflags, fd,
457 		(off_t)realBase  + BUS_BASE);
458    close(fd);
459    if (base == MAP_FAILED) {
460        FatalError("xf86MapVidMem: Could not mmap framebuffer"
461		   " (0x%08lx,0x%lx) (%s)\n", Base, Size,
462		   strerror(errno));
463    }
464    DebugF("base: %lx aligned base: %lx\n",base, (char *)base + alignOff);
465    return (char *)base + alignOff;
466}
467#endif /* !(__sparc__) */
468
469static void
470unmapVidMem(int ScreenNum, pointer Base, unsigned long Size)
471{
472    uintptr_t alignOff = (uintptr_t)Base
473	- ((uintptr_t)Base & ~(getpagesize() - 1));
474
475    DebugF("alignment offset: %lx\n", (unsigned long)alignOff);
476    munmap((void *)((uintptr_t)Base - alignOff), (Size + alignOff));
477}
478
479
480/***************************************************************************/
481/* I/O Permissions section                                                 */
482/***************************************************************************/
483
484#if defined(__powerpc__)
485volatile unsigned char *ioBase = NULL;
486
487#ifndef __NR_pciconfig_iobase
488#define __NR_pciconfig_iobase	200
489#endif
490
491#endif
492
493Bool
494xf86EnableIO(void)
495{
496#if defined(__powerpc__)
497	int fd;
498	unsigned int ioBase_phys;
499#endif
500
501	if (ExtendedEnabled)
502		return TRUE;
503
504#if defined(__powerpc__)
505	ioBase_phys = syscall(__NR_pciconfig_iobase, 2, 0, 0);
506
507	fd = open("/dev/mem", O_RDWR);
508	if (ioBase == NULL) {
509		ioBase = (volatile unsigned char *)mmap(0, 0x20000,
510				PROT_READ | PROT_WRITE, MAP_SHARED, fd,
511				ioBase_phys);
512/* Should this be fatal or just a warning? */
513#if 0
514		if (ioBase == MAP_FAILED) {
515		    xf86Msg(X_WARNING,
516			    "xf86EnableIOPorts: Failed to map iobase (%s)\n",
517			    strerror(errno));
518		    return FALSE;
519		}
520#endif
521	}
522	close(fd);
523#elif !defined(__mc68000__) && !defined(__sparc__) && !defined(__mips__) && !defined(__sh__) && !defined(__hppa__) && !defined(__s390__) && !defined(__arm__) && !defined(__m32r__) && !defined(__nds32__)
524        if (ioperm(0, 1024, 1) || iopl(3)) {
525                if (errno == ENODEV)
526                        ErrorF("xf86EnableIOPorts: no I/O ports found\n");
527                else
528                        FatalError("xf86EnableIOPorts: failed to set IOPL"
529                                   " for I/O (%s)\n", strerror(errno));
530		return FALSE;
531        }
532# if !defined(__alpha__)
533	/* XXX: this is actually not trapping anything because of iopl(3)
534	 * above */
535	ioperm(0x40,4,0); /* trap access to the timer chip */
536	ioperm(0x60,4,0); /* trap access to the keyboard controller */
537# endif
538#endif
539	ExtendedEnabled = TRUE;
540
541	return TRUE;
542}
543
544void
545xf86DisableIO(void)
546{
547	if (!ExtendedEnabled)
548		return;
549#if defined(__powerpc__)
550	munmap(ioBase, 0x20000);
551	ioBase = NULL;
552#elif !defined(__mc68000__) && !defined(__sparc__) && !defined(__mips__) && !defined(__sh__) && !defined(__hppa__) && !defined(__arm__) && !defined(__s390__) && !defined(__m32r__) && !defined(__nds32__)
553	iopl(0);
554	ioperm(0, 1024, 0);
555#endif
556	ExtendedEnabled = FALSE;
557
558	return;
559}
560
561#if defined (__alpha__)
562
563#define vuip    volatile unsigned int *
564
565extern int readDense8(pointer Base, register unsigned long Offset);
566extern int readDense16(pointer Base, register unsigned long Offset);
567extern int readDense32(pointer Base, register unsigned long Offset);
568extern void
569writeDenseNB8(int Value, pointer Base, register unsigned long Offset);
570extern void
571writeDenseNB16(int Value, pointer Base, register unsigned long Offset);
572extern void
573writeDenseNB32(int Value, pointer Base, register unsigned long Offset);
574extern void
575writeDense8(int Value, pointer Base, register unsigned long Offset);
576extern void
577writeDense16(int Value, pointer Base, register unsigned long Offset);
578extern void
579writeDense32(int Value, pointer Base, register unsigned long Offset);
580
581static int readSparse8(pointer Base, register unsigned long Offset);
582static int readSparse16(pointer Base, register unsigned long Offset);
583static int readSparse32(pointer Base, register unsigned long Offset);
584static void
585writeSparseNB8(int Value, pointer Base, register unsigned long Offset);
586static void
587writeSparseNB16(int Value, pointer Base, register unsigned long Offset);
588static void
589writeSparseNB32(int Value, pointer Base, register unsigned long Offset);
590static void
591writeSparse8(int Value, pointer Base, register unsigned long Offset);
592static void
593writeSparse16(int Value, pointer Base, register unsigned long Offset);
594static void
595writeSparse32(int Value, pointer Base, register unsigned long Offset);
596
597#define DENSE_BASE	0x2ff00000000UL
598#define SPARSE_BASE	0x30000000000UL
599
600static unsigned long msb_set = 0;
601
602static pointer
603mapVidMemSparse(int ScreenNum, unsigned long Base, unsigned long Size, int flags)
604{
605    int fd, prot;
606    unsigned long ret, rets = 0;
607
608    static Bool was_here = FALSE;
609
610    if (!was_here) {
611      was_here = TRUE;
612
613      xf86WriteMmio8 = writeSparse8;
614      xf86WriteMmio16 = writeSparse16;
615      xf86WriteMmio32 = writeSparse32;
616      xf86WriteMmioNB8 = writeSparseNB8;
617      xf86WriteMmioNB16 = writeSparseNB16;
618      xf86WriteMmioNB32 = writeSparseNB32;
619      xf86ReadMmio8 = readSparse8;
620      xf86ReadMmio16 = readSparse16;
621      xf86ReadMmio32 = readSparse32;
622    }
623
624    fd = open(DEV_MEM, (flags & VIDMEM_READONLY) ? O_RDONLY : O_RDWR);
625    if (fd < 0) {
626        FatalError("xf86MapVidMem: failed to open " DEV_MEM " (%s)\n",
627		   strerror(errno));
628    }
629
630#if 0
631    xf86Msg(X_INFO,"mapVidMemSparse: try Base 0x%lx size 0x%lx flags 0x%x\n",
632	    Base, Size, flags);
633#endif
634
635    if (flags & VIDMEM_READONLY)
636	prot = PROT_READ;
637    else
638	prot = PROT_READ | PROT_WRITE;
639
640    /* This requirers linux-0.99.pl10 or above */
641
642    /*
643     * Always do DENSE mmap, since read32/write32 currently require it.
644     */
645    ret = (unsigned long)mmap((caddr_t)(DENSE_BASE + Base), Size,
646		   prot, MAP_SHARED, fd,
647		   (off_t) (bus_base + Base));
648
649    /*
650     * Do SPARSE mmap only when MMIO and not MMIO_32BIT, or FRAMEBUFFER
651     * and SPARSE (which should require the use of read/write macros).
652     *
653     * By not SPARSE mmapping an 8MB framebuffer, we can save approx. 256K
654     * bytes worth of pagetable (32 pages).
655     */
656    if (((flags & VIDMEM_MMIO) && !(flags & VIDMEM_MMIO_32BIT)) ||
657	((flags & VIDMEM_FRAMEBUFFER) && (flags & VIDMEM_SPARSE)))
658    {
659        rets = (unsigned long)mmap((caddr_t)(SPARSE_BASE + (Base << 5)),
660				   Size << 5, prot, MAP_SHARED, fd,
661				   (off_t) _bus_base_sparse() + (Base << 5));
662    }
663
664    close(fd);
665
666    if (ret == (unsigned long)MAP_FAILED) {
667        FatalError("xf86MapVidMemSparse: Could not (dense) mmap fb (%s)\n",
668		   strerror(errno));
669    }
670
671    if (((flags & VIDMEM_MMIO) && !(flags & VIDMEM_MMIO_32BIT)) ||
672	((flags & VIDMEM_FRAMEBUFFER) && (flags & VIDMEM_SPARSE)))
673    {
674        if (rets == (unsigned long)MAP_FAILED ||
675	    rets != (SPARSE_BASE + (Base << 5)))
676	{
677	    FatalError("mapVidMemSparse: Could not (sparse) mmap fb (%s)\n",
678		       strerror(errno));
679	}
680    }
681
682#if 1
683    if (rets)
684        xf86Msg(X_INFO,"mapVidMemSparse: mapped Base 0x%lx size 0x%lx"
685		" to DENSE at 0x%lx and SPARSE at 0x%lx\n",
686		Base, Size, ret, rets);
687    else
688        xf86Msg(X_INFO,"mapVidMemSparse: mapped Base 0x%lx size 0x%lx"
689		" to DENSE only at 0x%lx\n",
690		Base, Size, ret);
691
692#endif
693    return (pointer) ret;
694}
695
696static void
697unmapVidMemSparse(int ScreenNum, pointer Base, unsigned long Size)
698{
699    unsigned long Offset = (unsigned long)Base - DENSE_BASE;
700#if 1
701    xf86Msg(X_INFO,"unmapVidMemSparse: unmapping Base 0x%lx Size 0x%lx\n",
702	    Base, Size);
703#endif
704    /* Unmap DENSE always. */
705    munmap((caddr_t)Base, Size);
706
707    /* Unmap SPARSE always, and ignore error in case we did not map it. */
708    munmap((caddr_t)(SPARSE_BASE + (Offset << 5)), Size << 5);
709}
710
711static int
712readSparse8(pointer Base, register unsigned long Offset)
713{
714    register unsigned long result, shift;
715    register unsigned long msb;
716
717    mem_barrier();
718    Offset += (unsigned long)Base - DENSE_BASE;
719    shift = (Offset & 0x3) << 3;
720    if (Offset >= (hae_thresh)) {
721        msb = Offset & hae_mask;
722        Offset -= msb;
723	if (msb_set != msb) {
724	    sethae(msb);
725	    msb_set = msb;
726	}
727    }
728
729    mem_barrier();
730    result = *(vuip) (SPARSE_BASE + (Offset << 5));
731    result >>= shift;
732    return 0xffUL & result;
733}
734
735static int
736readSparse16(pointer Base, register unsigned long Offset)
737{
738    register unsigned long result, shift;
739    register unsigned long msb;
740
741    mem_barrier();
742    Offset += (unsigned long)Base - DENSE_BASE;
743    shift = (Offset & 0x2) << 3;
744    if (Offset >= hae_thresh) {
745        msb = Offset & hae_mask;
746        Offset -= msb;
747	if (msb_set != msb) {
748	    sethae(msb);
749	    msb_set = msb;
750	}
751    }
752
753    mem_barrier();
754    result = *(vuip)(SPARSE_BASE + (Offset<<5) + (1<<(5-2)));
755    result >>= shift;
756    return 0xffffUL & result;
757}
758
759static int
760readSparse32(pointer Base, register unsigned long Offset)
761{
762    /* NOTE: this is really using DENSE. */
763    mem_barrier();
764    return *(vuip)((unsigned long)Base+(Offset));
765}
766
767static void
768writeSparse8(int Value, pointer Base, register unsigned long Offset)
769{
770    register unsigned long msb;
771    register unsigned int b = Value & 0xffU;
772
773    write_mem_barrier();
774    Offset += (unsigned long)Base - DENSE_BASE;
775    if (Offset >= hae_thresh) {
776        msb = Offset & hae_mask;
777	Offset -= msb;
778	if (msb_set != msb) {
779	    sethae(msb);
780	    msb_set = msb;
781	}
782    }
783
784    write_mem_barrier();
785    *(vuip) (SPARSE_BASE + (Offset << 5)) = b * 0x01010101;
786}
787
788static void
789writeSparse16(int Value, pointer Base, register unsigned long Offset)
790{
791    register unsigned long msb;
792    register unsigned int w = Value & 0xffffU;
793
794    write_mem_barrier();
795    Offset += (unsigned long)Base - DENSE_BASE;
796    if (Offset >= hae_thresh) {
797        msb = Offset & hae_mask;
798	Offset -= msb;
799	if (msb_set != msb) {
800	    sethae(msb);
801	    msb_set = msb;
802	}
803    }
804
805    write_mem_barrier();
806    *(vuip)(SPARSE_BASE + (Offset<<5) + (1<<(5-2))) = w * 0x00010001;
807}
808
809static void
810writeSparse32(int Value, pointer Base, register unsigned long Offset)
811{
812    /* NOTE: this is really using DENSE. */
813    write_mem_barrier();
814    *(vuip)((unsigned long)Base + (Offset)) = Value;
815    return;
816}
817
818static void
819writeSparseNB8(int Value, pointer Base, register unsigned long Offset)
820{
821    register unsigned long msb;
822    register unsigned int b = Value & 0xffU;
823
824    Offset += (unsigned long)Base - DENSE_BASE;
825    if (Offset >= hae_thresh) {
826        msb = Offset & hae_mask;
827	Offset -= msb;
828	if (msb_set != msb) {
829	    sethae(msb);
830	    msb_set = msb;
831	}
832    }
833    *(vuip) (SPARSE_BASE + (Offset << 5)) = b * 0x01010101;
834}
835
836static void
837writeSparseNB16(int Value, pointer Base, register unsigned long Offset)
838{
839    register unsigned long msb;
840    register unsigned int w = Value & 0xffffU;
841
842    Offset += (unsigned long)Base - DENSE_BASE;
843    if (Offset >= hae_thresh) {
844        msb = Offset & hae_mask;
845	Offset -= msb;
846	if (msb_set != msb) {
847	    sethae(msb);
848	    msb_set = msb;
849	}
850    }
851    *(vuip)(SPARSE_BASE+(Offset<<5)+(1<<(5-2))) = w * 0x00010001;
852}
853
854static void
855writeSparseNB32(int Value, pointer Base, register unsigned long Offset)
856{
857    /* NOTE: this is really using DENSE. */
858    *(vuip)((unsigned long)Base + (Offset)) = Value;
859    return;
860}
861
862void (*xf86WriteMmio8)(int Value, pointer Base, unsigned long Offset)
863     = writeDense8;
864void (*xf86WriteMmio16)(int Value, pointer Base, unsigned long Offset)
865     = writeDense16;
866void (*xf86WriteMmio32)(int Value, pointer Base, unsigned long Offset)
867     = writeDense32;
868void (*xf86WriteMmioNB8)(int Value, pointer Base, unsigned long Offset)
869     = writeDenseNB8;
870void (*xf86WriteMmioNB16)(int Value, pointer Base, unsigned long Offset)
871     = writeDenseNB16;
872void (*xf86WriteMmioNB32)(int Value, pointer Base, unsigned long Offset)
873     = writeDenseNB32;
874int  (*xf86ReadMmio8)(pointer Base, unsigned long Offset)
875     = readDense8;
876int  (*xf86ReadMmio16)(pointer Base, unsigned long Offset)
877     = readDense16;
878int  (*xf86ReadMmio32)(pointer Base, unsigned long Offset)
879     = readDense32;
880
881#endif /* __alpha__ */
882