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