Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / xfree86 / os-support / bsd / i386_video.c
CommitLineData
a09e091a
JB
1/*
2 * Copyright 1992 by Rich Murphey <Rich@Rice.edu>
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 Rich Murphey and David Wexelblat
10 * not be used in advertising or publicity pertaining to distribution of
11 * the software without specific, written prior permission. Rich Murphey and
12 * 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 * RICH MURPHEY AND DAVID WEXELBLAT DISCLAIM ALL WARRANTIES WITH REGARD TO
17 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
18 * FITNESS, IN NO EVENT SHALL RICH MURPHEY OR DAVID WEXELBLAT BE LIABLE FOR
19 * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
20 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
21 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22 * 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 <X11/X.h>
31#include "xf86.h"
32#include "xf86Priv.h"
33
34#include <errno.h>
35#include <sys/mman.h>
36
37#ifdef HAS_MTRR_SUPPORT
38#ifndef __NetBSD__
39#include <sys/types.h>
40#include <sys/memrange.h>
41#else
42#include "memrange.h"
43#endif
44#define X_MTRR_ID "XFree86"
45#endif
46
47#if defined(HAS_MTRR_BUILTIN) && defined(__NetBSD__)
48#include <machine/mtrr.h>
49#include <machine/sysarch.h>
50#include <sys/queue.h>
51#ifdef __x86_64__
52#define i386_set_mtrr x86_64_set_mtrr
53#define i386_get_mtrr x86_64_get_mtrr
54#define i386_iopl x86_64_iopl
55#endif
56#endif
57
58#include "xf86_OSlib.h"
59#include "xf86OSpriv.h"
60
61#if defined(__NetBSD__) && !defined(MAP_FILE)
62#define MAP_FLAGS MAP_SHARED
63#else
64#define MAP_FLAGS (MAP_FILE | MAP_SHARED)
65#endif
66
67#ifdef __OpenBSD__
68#define SYSCTL_MSG "\tCheck that you have set 'machdep.allowaperture=1'\n"\
69 "\tin /etc/sysctl.conf and reboot your machine\n" \
70 "\trefer to xf86(4) for details"
71#define SYSCTL_MSG2 \
72 "Check that you have set 'machdep.allowaperture=2'\n" \
73 "\tin /etc/sysctl.conf and reboot your machine\n" \
74 "\trefer to xf86(4) for details"
75#endif
76
77/***************************************************************************/
78/* Video Memory Mapping section */
79/***************************************************************************/
80
81static Bool useDevMem = FALSE;
82static int devMemFd = -1;
83
84#ifdef HAS_APERTURE_DRV
85#define DEV_APERTURE "/dev/xf86"
86#endif
87
88static pointer mapVidMem(int, unsigned long, unsigned long, int);
89static void unmapVidMem(int, pointer, unsigned long);
90
91#ifdef HAS_MTRR_SUPPORT
92static pointer setWC(int, unsigned long, unsigned long, Bool, MessageType);
93static void undoWC(int, pointer);
94static Bool cleanMTRR(void);
95#endif
96#if defined(HAS_MTRR_BUILTIN) && defined(__NetBSD__)
97static pointer NetBSDsetWC(int, unsigned long, unsigned long, Bool,
98 MessageType);
99static void NetBSDundoWC(int, pointer);
100#endif
101
102/*
103 * Check if /dev/mem can be mmap'd. If it can't print a warning when
104 * "warn" is TRUE.
105 */
106static void
107checkDevMem(Bool warn)
108{
109 static Bool devMemChecked = FALSE;
110 int fd;
111 pointer base;
112
113 if (devMemChecked)
114 return;
115 devMemChecked = TRUE;
116
117 if ((fd = open(DEV_MEM, O_RDWR)) >= 0) {
118 /* Try to map a page at the VGA address */
119 base = mmap((caddr_t) 0, 4096, PROT_READ | PROT_WRITE,
120 MAP_FLAGS, fd, (off_t) 0xA0000);
121
122 if (base != MAP_FAILED) {
123 munmap((caddr_t) base, 4096);
124 devMemFd = fd;
125 useDevMem = TRUE;
126 return;
127 }
128 else {
129 /* This should not happen */
130 if (warn) {
131 xf86Msg(X_WARNING, "checkDevMem: failed to mmap %s (%s)\n",
132 DEV_MEM, strerror(errno));
133 }
134 useDevMem = FALSE;
135 return;
136 }
137 }
138#ifndef HAS_APERTURE_DRV
139 if (warn) {
140 xf86Msg(X_WARNING, "checkDevMem: failed to open %s (%s)\n",
141 DEV_MEM, strerror(errno));
142 }
143 useDevMem = FALSE;
144 return;
145#else
146 /* Failed to open /dev/mem, try the aperture driver */
147 if ((fd = open(DEV_APERTURE, O_RDWR)) >= 0) {
148 /* Try to map a page at the VGA address */
149 base = mmap((caddr_t) 0, 4096, PROT_READ | PROT_WRITE,
150 MAP_FLAGS, fd, (off_t) 0xA0000);
151
152 if (base != MAP_FAILED) {
153 munmap((caddr_t) base, 4096);
154 devMemFd = fd;
155 useDevMem = TRUE;
156 xf86Msg(X_INFO, "checkDevMem: using aperture driver %s\n",
157 DEV_APERTURE);
158 return;
159 }
160 else {
161
162 if (warn) {
163 xf86Msg(X_WARNING, "checkDevMem: failed to mmap %s (%s)\n",
164 DEV_APERTURE, strerror(errno));
165 }
166 }
167 }
168 else {
169 if (warn) {
170#ifndef __OpenBSD__
171 xf86Msg(X_WARNING, "checkDevMem: failed to open %s and %s\n"
172 "\t(%s)\n", DEV_MEM, DEV_APERTURE, strerror(errno));
173#else /* __OpenBSD__ */
174 xf86Msg(X_WARNING, "checkDevMem: failed to open %s and %s\n"
175 "\t(%s)\n%s", DEV_MEM, DEV_APERTURE, strerror(errno),
176 SYSCTL_MSG);
177#endif /* __OpenBSD__ */
178 }
179 }
180
181 useDevMem = FALSE;
182 return;
183
184#endif
185}
186
187void
188xf86OSInitVidMem(VidMemInfoPtr pVidMem)
189{
190 checkDevMem(TRUE);
191 pVidMem->linearSupported = useDevMem;
192 pVidMem->mapMem = mapVidMem;
193 pVidMem->unmapMem = unmapVidMem;
194
195 if (useDevMem)
196 pci_system_init_dev_mem(devMemFd);
197
198#ifdef HAS_MTRR_SUPPORT
199 if (useDevMem) {
200 if (cleanMTRR()) {
201 pVidMem->setWC = setWC;
202 pVidMem->undoWC = undoWC;
203 }
204 }
205#endif
206#if defined(HAS_MTRR_BUILTIN) && defined(__NetBSD__)
207 pVidMem->setWC = NetBSDsetWC;
208 pVidMem->undoWC = NetBSDundoWC;
209#endif
210 pVidMem->initialised = TRUE;
211}
212
213static pointer
214mapVidMem(int ScreenNum, unsigned long Base, unsigned long Size, int flags)
215{
216 pointer base;
217
218 checkDevMem(FALSE);
219
220 if (useDevMem) {
221 if (devMemFd < 0) {
222 FatalError("xf86MapVidMem: failed to open %s (%s)",
223 DEV_MEM, strerror(errno));
224 }
225 base = mmap((caddr_t) 0, Size,
226 (flags & VIDMEM_READONLY) ?
227 PROT_READ : (PROT_READ | PROT_WRITE),
228 MAP_FLAGS, devMemFd, (off_t) Base);
229 if (base == MAP_FAILED) {
230 FatalError("%s: could not mmap %s [s=%lx,a=%lx] (%s)",
231 "xf86MapVidMem", DEV_MEM, Size, Base, strerror(errno));
232 }
233 return base;
234 }
235
236 /* else, mmap /dev/vga */
237 if ((unsigned long) Base < 0xA0000 || (unsigned long) Base >= 0xC0000) {
238 FatalError("%s: Address 0x%lx outside allowable range",
239 "xf86MapVidMem", Base);
240 }
241 base = mmap(0, Size,
242 (flags & VIDMEM_READONLY) ?
243 PROT_READ : (PROT_READ | PROT_WRITE),
244 MAP_FLAGS, xf86Info.consoleFd, (unsigned long) Base - 0xA0000);
245 if (base == MAP_FAILED) {
246 FatalError("xf86MapVidMem: Could not mmap /dev/vga (%s)",
247 strerror(errno));
248 }
249 return base;
250}
251
252static void
253unmapVidMem(int ScreenNum, pointer Base, unsigned long Size)
254{
255 munmap((caddr_t) Base, Size);
256}
257
258/*
259 * Read BIOS via mmap()ing DEV_MEM
260 */
261
262int
263xf86ReadBIOS(unsigned long Base, unsigned long Offset, unsigned char *Buf,
264 int Len)
265{
266 unsigned char *ptr;
267 int psize;
268 int mlen;
269
270 checkDevMem(TRUE);
271 if (devMemFd == -1) {
272 return -1;
273 }
274
275 psize = getpagesize();
276 Offset += Base & (psize - 1);
277 Base &= ~(psize - 1);
278 mlen = (Offset + Len + psize - 1) & ~(psize - 1);
279 ptr = (unsigned char *) mmap((caddr_t) 0, mlen, PROT_READ,
280 MAP_SHARED, devMemFd, (off_t) Base);
281 if ((long) ptr == -1) {
282 xf86Msg(X_WARNING,
283 "xf86ReadBIOS: %s mmap[s=%x,a=%lx,o=%lx] failed (%s)\n",
284 DEV_MEM, Len, Base, Offset, strerror(errno));
285#ifdef __OpenBSD__
286 if (Base < 0xa0000) {
287 xf86Msg(X_WARNING, SYSCTL_MSG2);
288 }
289#endif
290 return -1;
291 }
292#ifdef DEBUG
293 ErrorF("xf86ReadBIOS: BIOS at 0x%08x has signature 0x%04x\n",
294 Base, ptr[0] | (ptr[1] << 8));
295#endif
296 (void) memcpy(Buf, (void *) (ptr + Offset), Len);
297 (void) munmap((caddr_t) ptr, mlen);
298#ifdef DEBUG
299 xf86MsgVerb(X_INFO, 3, "xf86ReadBIOS(%x, %x, Buf, %x)"
300 "-> %02x %02x %02x %02x...\n",
301 Base, Offset, Len, Buf[0], Buf[1], Buf[2], Buf[3]);
302#endif
303 return Len;
304}
305
306#ifdef USE_I386_IOPL
307/***************************************************************************/
308/* I/O Permissions section */
309/***************************************************************************/
310
311static Bool ExtendedEnabled = FALSE;
312
313Bool
314xf86EnableIO()
315{
316 if (ExtendedEnabled)
317 return TRUE;
318
319 if (i386_iopl(TRUE) < 0) {
320#ifndef __OpenBSD__
321 xf86Msg(X_WARNING, "%s: Failed to set IOPL for extended I/O",
322 "xf86EnableIO");
323#else
324 xf86Msg(X_WARNING, "%s: Failed to set IOPL for extended I/O\n%s",
325 "xf86EnableIO", SYSCTL_MSG);
326#endif
327 return FALSE;
328 }
329 ExtendedEnabled = TRUE;
330
331 return TRUE;
332}
333
334void
335xf86DisableIO()
336{
337 if (!ExtendedEnabled)
338 return;
339
340 i386_iopl(FALSE);
341 ExtendedEnabled = FALSE;
342
343 return;
344}
345
346#endif /* USE_I386_IOPL */
347
348#ifdef USE_AMD64_IOPL
349/***************************************************************************/
350/* I/O Permissions section */
351/***************************************************************************/
352
353static Bool ExtendedEnabled = FALSE;
354
355Bool
356xf86EnableIO()
357{
358 if (ExtendedEnabled)
359 return TRUE;
360
361 if (amd64_iopl(TRUE) < 0) {
362#ifndef __OpenBSD__
363 xf86Msg(X_WARNING, "%s: Failed to set IOPL for extended I/O",
364 "xf86EnableIO");
365#else
366 xf86Msg(X_WARNING, "%s: Failed to set IOPL for extended I/O\n%s",
367 "xf86EnableIO", SYSCTL_MSG);
368#endif
369 return FALSE;
370 }
371 ExtendedEnabled = TRUE;
372
373 return TRUE;
374}
375
376void
377xf86DisableIO()
378{
379 if (!ExtendedEnabled)
380 return;
381
382 if (amd64_iopl(FALSE) == 0) {
383 ExtendedEnabled = FALSE;
384 }
385 /* Otherwise, the X server has revoqued its root uid,
386 and thus cannot give up IO privileges any more */
387
388 return;
389}
390
391#endif /* USE_AMD64_IOPL */
392
393#ifdef USE_DEV_IO
394static int IoFd = -1;
395
396Bool
397xf86EnableIO()
398{
399 if (IoFd >= 0)
400 return TRUE;
401
402 if ((IoFd = open("/dev/io", O_RDWR)) == -1) {
403 xf86Msg(X_WARNING, "xf86EnableIO: "
404 "Failed to open /dev/io for extended I/O");
405 return FALSE;
406 }
407 return TRUE;
408}
409
410void
411xf86DisableIO()
412{
413 if (IoFd < 0)
414 return;
415
416 close(IoFd);
417 IoFd = -1;
418 return;
419}
420
421#endif
422
423#ifdef __NetBSD__
424/***************************************************************************/
425/* Set TV output mode */
426/***************************************************************************/
427void
428xf86SetTVOut(int mode)
429{
430 switch (xf86Info.consType) {
431#ifdef PCCONS_SUPPORT
432 case PCCONS:{
433
434 if (ioctl(xf86Info.consoleFd, CONSOLE_X_TV_ON, &mode) < 0) {
435 xf86Msg(X_WARNING,
436 "xf86SetTVOut: Could not set console to TV output, %s\n",
437 strerror(errno));
438 }
439 }
440 break;
441#endif /* PCCONS_SUPPORT */
442
443 default:
444 FatalError("Xf86SetTVOut: Unsupported console");
445 break;
446 }
447 return;
448}
449
450void
451xf86SetRGBOut()
452{
453 switch (xf86Info.consType) {
454#ifdef PCCONS_SUPPORT
455 case PCCONS:{
456
457 if (ioctl(xf86Info.consoleFd, CONSOLE_X_TV_OFF, 0) < 0) {
458 xf86Msg(X_WARNING,
459 "xf86SetTVOut: Could not set console to RGB output, %s\n",
460 strerror(errno));
461 }
462 }
463 break;
464#endif /* PCCONS_SUPPORT */
465
466 default:
467 FatalError("Xf86SetTVOut: Unsupported console");
468 break;
469 }
470 return;
471}
472#endif
473
474#ifdef HAS_MTRR_SUPPORT
475/* memory range (MTRR) support for FreeBSD */
476
477/*
478 * This code is experimental. Some parts may be overkill, and other parts
479 * may be incomplete.
480 */
481
482/*
483 * getAllRanges returns the full list of memory ranges with attributes set.
484 */
485
486static struct mem_range_desc *
487getAllRanges(int *nmr)
488{
489 struct mem_range_desc *mrd;
490 struct mem_range_op mro;
491
492 /*
493 * Find how many ranges there are. If this fails, then the kernel
494 * probably doesn't have MTRR support.
495 */
496 mro.mo_arg[0] = 0;
497 if (ioctl(devMemFd, MEMRANGE_GET, &mro))
498 return NULL;
499 *nmr = mro.mo_arg[0];
500 mrd = xnfalloc(*nmr * sizeof(struct mem_range_desc));
501 mro.mo_arg[0] = *nmr;
502 mro.mo_desc = mrd;
503 if (ioctl(devMemFd, MEMRANGE_GET, &mro)) {
504 free(mrd);
505 return NULL;
506 }
507 return mrd;
508}
509
510/*
511 * cleanMTRR removes any memory attribute that may be left by a previous
512 * X server. Normally there won't be any, but this takes care of the
513 * case where a server crashed without being able finish cleaning up.
514 */
515
516static Bool
517cleanMTRR()
518{
519 struct mem_range_desc *mrd;
520 struct mem_range_op mro;
521 int nmr, i;
522
523 /* This shouldn't happen */
524 if (devMemFd < 0)
525 return FALSE;
526
527 if (!(mrd = getAllRanges(&nmr)))
528 return FALSE;
529
530 for (i = 0; i < nmr; i++) {
531 if (strcmp(mrd[i].mr_owner, X_MTRR_ID) == 0 &&
532 (mrd[i].mr_flags & MDF_ACTIVE)) {
533#ifdef DEBUG
534 ErrorF("Clean for (0x%lx,0x%lx)\n",
535 (unsigned long) mrd[i].mr_base,
536 (unsigned long) mrd[i].mr_len);
537#endif
538 if (mrd[i].mr_flags & MDF_FIXACTIVE) {
539 mro.mo_arg[0] = MEMRANGE_SET_UPDATE;
540 mrd[i].mr_flags = MDF_UNCACHEABLE;
541 }
542 else {
543 mro.mo_arg[0] = MEMRANGE_SET_REMOVE;
544 }
545 mro.mo_desc = mrd + i;
546 ioctl(devMemFd, MEMRANGE_SET, &mro);
547 }
548 }
549#ifdef DEBUG
550 sleep(10);
551#endif
552 free(mrd);
553 return TRUE;
554}
555
556typedef struct x_RangeRec {
557 struct mem_range_desc mrd;
558 Bool wasWC;
559 struct x_RangeRec *next;
560} RangeRec, *RangePtr;
561
562static void
563freeRangeList(RangePtr range)
564{
565 RangePtr rp;
566
567 while (range) {
568 rp = range;
569 range = rp->next;
570 free(rp);
571 }
572}
573
574static RangePtr
575dupRangeList(RangePtr list)
576{
577 RangePtr new = NULL, rp, p;
578
579 rp = list;
580 while (rp) {
581 p = xnfalloc(sizeof(RangeRec));
582 *p = *rp;
583 p->next = new;
584 new = p;
585 rp = rp->next;
586 }
587 return new;
588}
589
590static RangePtr
591sortRangeList(RangePtr list)
592{
593 RangePtr rp1, rp2, copy, sorted = NULL, minp, prev, minprev;
594 unsigned long minBase;
595
596 /* Sort by base address */
597 rp1 = copy = dupRangeList(list);
598 while (rp1) {
599 minBase = rp1->mrd.mr_base;
600 minp = rp1;
601 minprev = NULL;
602 prev = rp1;
603 rp2 = rp1->next;
604 while (rp2) {
605 if (rp2->mrd.mr_base < minBase) {
606 minBase = rp2->mrd.mr_base;
607 minp = rp2;
608 minprev = prev;
609 }
610 prev = rp2;
611 rp2 = rp2->next;
612 }
613 if (minprev) {
614 minprev->next = minp->next;
615 rp1 = copy;
616 }
617 else {
618 rp1 = minp->next;
619 }
620 minp->next = sorted;
621 sorted = minp;
622 }
623 return sorted;
624}
625
626/*
627 * findRanges returns a list of ranges that overlap the specified range.
628 */
629
630static void
631findRanges(unsigned long base, unsigned long size, RangePtr * ucp,
632 RangePtr * wcp)
633{
634 struct mem_range_desc *mrd;
635 int nmr, i;
636 RangePtr rp, *p;
637
638 if (!(mrd = getAllRanges(&nmr)))
639 return;
640
641 for (i = 0; i < nmr; i++) {
642 if ((mrd[i].mr_flags & MDF_ACTIVE) &&
643 mrd[i].mr_base < base + size &&
644 mrd[i].mr_base + mrd[i].mr_len > base) {
645 if (mrd[i].mr_flags & MDF_WRITECOMBINE)
646 p = wcp;
647 else if (mrd[i].mr_flags & MDF_UNCACHEABLE)
648 p = ucp;
649 else
650 continue;
651 rp = xnfalloc(sizeof(RangeRec));
652 rp->mrd = mrd[i];
653 rp->next = *p;
654 *p = rp;
655 }
656 }
657 free(mrd);
658}
659
660/*
661 * This checks if the existing overlapping ranges fully cover the requested
662 * range. Is this overkill?
663 */
664
665static Bool
666fullCoverage(unsigned long base, unsigned long size, RangePtr overlap)
667{
668 RangePtr rp1, sorted = NULL;
669 unsigned long end;
670
671 sorted = sortRangeList(overlap);
672 /* Look for gaps */
673 rp1 = sorted;
674 end = base + size;
675 while (rp1) {
676 if (rp1->mrd.mr_base > base) {
677 freeRangeList(sorted);
678 return FALSE;
679 }
680 else {
681 base = rp1->mrd.mr_base + rp1->mrd.mr_len;
682 }
683 if (base >= end) {
684 freeRangeList(sorted);
685 return TRUE;
686 }
687 rp1 = rp1->next;
688 }
689 freeRangeList(sorted);
690 return FALSE;
691}
692
693static pointer
694addWC(int screenNum, unsigned long base, unsigned long size, MessageType from)
695{
696 RangePtr uc = NULL, wc = NULL, retlist = NULL;
697 struct mem_range_desc mrd;
698 struct mem_range_op mro;
699
700 findRanges(base, size, &uc, &wc);
701
702 /* See of the full range is already WC */
703 if (!uc && fullCoverage(base, size, wc)) {
704 xf86DrvMsg(screenNum, from,
705 "Write-combining range (0x%lx,0x%lx) was already set\n",
706 base, size);
707 return NULL;
708 }
709
710 /* Otherwise, try to add the new range */
711 mrd.mr_base = base;
712 mrd.mr_len = size;
713 strcpy(mrd.mr_owner, X_MTRR_ID);
714 mrd.mr_flags = MDF_WRITECOMBINE;
715 mro.mo_desc = &mrd;
716 mro.mo_arg[0] = MEMRANGE_SET_UPDATE;
717 if (ioctl(devMemFd, MEMRANGE_SET, &mro)) {
718 xf86DrvMsg(screenNum, X_WARNING,
719 "Failed to set write-combining range "
720 "(0x%lx,0x%lx)\n", base, size);
721 return NULL;
722 }
723 else {
724 xf86DrvMsg(screenNum, from,
725 "Write-combining range (0x%lx,0x%lx)\n", base, size);
726 retlist = xnfalloc(sizeof(RangeRec));
727 retlist->mrd = mrd;
728 retlist->wasWC = FALSE;
729 retlist->next = NULL;
730 return retlist;
731 }
732}
733
734static pointer
735delWC(int screenNum, unsigned long base, unsigned long size, MessageType from)
736{
737 RangePtr uc = NULL, wc = NULL, retlist = NULL;
738 struct mem_range_desc mrd;
739 struct mem_range_op mro;
740
741 findRanges(base, size, &uc, &wc);
742
743 /*
744 * See of the full range is already not WC, or if there is full
745 * coverage from UC ranges.
746 */
747 if (!wc || fullCoverage(base, size, uc)) {
748 xf86DrvMsg(screenNum, from,
749 "Write-combining range (0x%lx,0x%lx) was already clear\n",
750 base, size);
751 return NULL;
752 }
753
754 /* Otherwise, try to add the new range */
755 mrd.mr_base = base;
756 mrd.mr_len = size;
757 strcpy(mrd.mr_owner, X_MTRR_ID);
758 mrd.mr_flags = MDF_UNCACHEABLE;
759 mro.mo_desc = &mrd;
760 mro.mo_arg[0] = MEMRANGE_SET_UPDATE;
761 if (ioctl(devMemFd, MEMRANGE_SET, &mro)) {
762 xf86DrvMsg(screenNum, X_WARNING,
763 "Failed to remove write-combining range "
764 "(0x%lx,0x%lx)\n", base, size);
765 /* XXX Should then remove all of the overlapping WC ranges */
766 return NULL;
767 }
768 else {
769 xf86DrvMsg(screenNum, from,
770 "Removed Write-combining range (0x%lx,0x%lx)\n", base, size);
771 retlist = xnfalloc(sizeof(RangeRec));
772 retlist->mrd = mrd;
773 retlist->wasWC = TRUE;
774 retlist->next = NULL;
775 return retlist;
776 }
777}
778
779static pointer
780setWC(int screenNum, unsigned long base, unsigned long size, Bool enable,
781 MessageType from)
782{
783 if (enable)
784 return addWC(screenNum, base, size, from);
785 else
786 return delWC(screenNum, base, size, from);
787}
788
789static void
790undoWC(int screenNum, pointer list)
791{
792 RangePtr rp;
793 struct mem_range_op mro;
794 Bool failed;
795
796 rp = list;
797 while (rp) {
798#ifdef DEBUG
799 ErrorF("Undo for (0x%lx,0x%lx), %d\n",
800 (unsigned long) rp->mrd.mr_base,
801 (unsigned long) rp->mrd.mr_len, rp->wasWC);
802#endif
803 failed = FALSE;
804 if (rp->wasWC) {
805 mro.mo_arg[0] = MEMRANGE_SET_UPDATE;
806 rp->mrd.mr_flags = MDF_WRITECOMBINE;
807 strcpy(rp->mrd.mr_owner, "unknown");
808 }
809 else {
810 mro.mo_arg[0] = MEMRANGE_SET_REMOVE;
811 }
812 mro.mo_desc = &rp->mrd;
813
814 if (ioctl(devMemFd, MEMRANGE_SET, &mro)) {
815 if (!rp->wasWC) {
816 mro.mo_arg[0] = MEMRANGE_SET_UPDATE;
817 rp->mrd.mr_flags = MDF_UNCACHEABLE;
818 strcpy(rp->mrd.mr_owner, "unknown");
819 if (ioctl(devMemFd, MEMRANGE_SET, &mro))
820 failed = TRUE;
821 }
822 else
823 failed = TRUE;
824 }
825 if (failed) {
826 xf86DrvMsg(screenNum, X_WARNING,
827 "Failed to restore MTRR range (0x%lx,0x%lx)\n",
828 (unsigned long) rp->mrd.mr_base,
829 (unsigned long) rp->mrd.mr_len);
830 }
831 rp = rp->next;
832 }
833}
834
835#endif /* HAS_MTRR_SUPPORT */
836
837#if defined(HAS_MTRR_BUILTIN) && defined(__NetBSD__)
838static pointer
839NetBSDsetWC(int screenNum, unsigned long base, unsigned long size, Bool enable,
840 MessageType from)
841{
842 struct mtrr *mtrrp;
843 int n;
844
845 xf86DrvMsg(screenNum, X_WARNING,
846 "%s MTRR %lx - %lx\n", enable ? "set" : "remove",
847 base, (base + size));
848
849 mtrrp = xnfalloc(sizeof(struct mtrr));
850 mtrrp->base = base;
851 mtrrp->len = size;
852 mtrrp->type = MTRR_TYPE_WC;
853
854 /*
855 * MTRR_PRIVATE will make this MTRR get reset automatically
856 * if this process exits, so we have no need for an explicit
857 * cleanup operation when starting a new server.
858 */
859
860 if (enable)
861 mtrrp->flags = MTRR_VALID | MTRR_PRIVATE;
862 else
863 mtrrp->flags = 0;
864 n = 1;
865
866 if (i386_set_mtrr(mtrrp, &n) < 0) {
867 free(mtrrp);
868 return NULL;
869 }
870 return mtrrp;
871}
872
873static void
874NetBSDundoWC(int screenNum, pointer list)
875{
876 struct mtrr *mtrrp = (struct mtrr *) list;
877 int n;
878
879 if (mtrrp == NULL)
880 return;
881 n = 1;
882 mtrrp->flags &= ~MTRR_VALID;
883 i386_set_mtrr(mtrrp, &n);
884 free(mtrrp);
885}
886#endif