Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / xfree86 / os-support / bsd / i386_video.c
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
81 static Bool useDevMem = FALSE;
82 static int devMemFd = -1;
83
84 #ifdef HAS_APERTURE_DRV
85 #define DEV_APERTURE "/dev/xf86"
86 #endif
87
88 static pointer mapVidMem(int, unsigned long, unsigned long, int);
89 static void unmapVidMem(int, pointer, unsigned long);
90
91 #ifdef HAS_MTRR_SUPPORT
92 static pointer setWC(int, unsigned long, unsigned long, Bool, MessageType);
93 static void undoWC(int, pointer);
94 static Bool cleanMTRR(void);
95 #endif
96 #if defined(HAS_MTRR_BUILTIN) && defined(__NetBSD__)
97 static pointer NetBSDsetWC(int, unsigned long, unsigned long, Bool,
98 MessageType);
99 static 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 */
106 static void
107 checkDevMem(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
187 void
188 xf86OSInitVidMem(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
213 static pointer
214 mapVidMem(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
252 static void
253 unmapVidMem(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
262 int
263 xf86ReadBIOS(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
311 static Bool ExtendedEnabled = FALSE;
312
313 Bool
314 xf86EnableIO()
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
334 void
335 xf86DisableIO()
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
353 static Bool ExtendedEnabled = FALSE;
354
355 Bool
356 xf86EnableIO()
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
376 void
377 xf86DisableIO()
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
394 static int IoFd = -1;
395
396 Bool
397 xf86EnableIO()
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
410 void
411 xf86DisableIO()
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 /***************************************************************************/
427 void
428 xf86SetTVOut(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
450 void
451 xf86SetRGBOut()
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
486 static struct mem_range_desc *
487 getAllRanges(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
516 static Bool
517 cleanMTRR()
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
556 typedef struct x_RangeRec {
557 struct mem_range_desc mrd;
558 Bool wasWC;
559 struct x_RangeRec *next;
560 } RangeRec, *RangePtr;
561
562 static void
563 freeRangeList(RangePtr range)
564 {
565 RangePtr rp;
566
567 while (range) {
568 rp = range;
569 range = rp->next;
570 free(rp);
571 }
572 }
573
574 static RangePtr
575 dupRangeList(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
590 static RangePtr
591 sortRangeList(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
630 static void
631 findRanges(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
665 static Bool
666 fullCoverage(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
693 static pointer
694 addWC(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
734 static pointer
735 delWC(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
779 static pointer
780 setWC(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
789 static void
790 undoWC(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__)
838 static pointer
839 NetBSDsetWC(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
873 static void
874 NetBSDundoWC(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