| 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 | static Bool ExtendedEnabled = FALSE; |
| 50 | |
| 51 | #ifdef __ia64__ |
| 52 | |
| 53 | #include "compiler.h" |
| 54 | #include <sys/io.h> |
| 55 | |
| 56 | #elif !defined(__powerpc__) && \ |
| 57 | !defined(__mc68000__) && \ |
| 58 | !defined(__sparc__) && \ |
| 59 | !defined(__mips__) && \ |
| 60 | !defined(__nds32__) && \ |
| 61 | !defined(__arm__) && \ |
| 62 | !defined(__aarch64__) |
| 63 | |
| 64 | /* |
| 65 | * Due to conflicts with "compiler.h", don't rely on <sys/io.h> to declare |
| 66 | * these. |
| 67 | */ |
| 68 | extern int ioperm(unsigned long __from, unsigned long __num, int __turn_on); |
| 69 | extern int iopl(int __level); |
| 70 | |
| 71 | #endif |
| 72 | |
| 73 | #ifdef __alpha__ |
| 74 | #define BUS_BASE bus_base |
| 75 | #else |
| 76 | #define BUS_BASE (0) |
| 77 | #endif /* __alpha__ */ |
| 78 | |
| 79 | /***************************************************************************/ |
| 80 | /* Video Memory Mapping section */ |
| 81 | /***************************************************************************/ |
| 82 | |
| 83 | static pointer mapVidMem(int, unsigned long, unsigned long, int); |
| 84 | static void unmapVidMem(int, pointer, unsigned long); |
| 85 | |
| 86 | #if defined (__alpha__) |
| 87 | extern void sethae(unsigned long hae); |
| 88 | extern unsigned long _bus_base __P((void)) __attribute__ ((const)); |
| 89 | extern unsigned long _bus_base_sparse __P((void)) __attribute__ ((const)); |
| 90 | |
| 91 | static pointer mapVidMemSparse(int, unsigned long, unsigned long, int); |
| 92 | extern axpDevice lnxGetAXP(void); |
| 93 | static void unmapVidMemSparse(int, pointer, unsigned long); |
| 94 | static axpDevice axpSystem = -1; |
| 95 | static Bool needSparse; |
| 96 | static unsigned long hae_thresh; |
| 97 | static unsigned long hae_mask; |
| 98 | static unsigned long bus_base; |
| 99 | #endif |
| 100 | |
| 101 | #ifdef HAS_MTRR_SUPPORT |
| 102 | |
| 103 | #define SPLIT_WC_REGIONS 1 |
| 104 | |
| 105 | static pointer setWC(int, unsigned long, unsigned long, Bool, MessageType); |
| 106 | static void undoWC(int, pointer); |
| 107 | |
| 108 | /* The file desc for /proc/mtrr. Once opened, left opened, and the mtrr |
| 109 | driver will clean up when we exit. */ |
| 110 | #define MTRR_FD_UNOPENED (-1) /* We have yet to open /proc/mtrr */ |
| 111 | #define MTRR_FD_PROBLEM (-2) /* We tried to open /proc/mtrr, but had |
| 112 | a problem. */ |
| 113 | static int mtrr_fd = MTRR_FD_UNOPENED; |
| 114 | |
| 115 | /* Open /proc/mtrr. FALSE on failure. Will always fail on Linux 2.0, |
| 116 | and will fail on Linux 2.2 with MTRR support configured out, |
| 117 | so verbosity should be chosen appropriately. */ |
| 118 | static Bool |
| 119 | mtrr_open(int verbosity) |
| 120 | { |
| 121 | /* Only report absence of /proc/mtrr once. */ |
| 122 | static Bool warned = FALSE; |
| 123 | |
| 124 | if (mtrr_fd == MTRR_FD_UNOPENED) { |
| 125 | mtrr_fd = open("/proc/mtrr", O_WRONLY); |
| 126 | |
| 127 | if (mtrr_fd < 0) |
| 128 | mtrr_fd = MTRR_FD_PROBLEM; |
| 129 | } |
| 130 | |
| 131 | if (mtrr_fd == MTRR_FD_PROBLEM) { |
| 132 | /* To make sure we only ever warn once, need to check |
| 133 | verbosity outside xf86MsgVerb */ |
| 134 | if (!warned && verbosity <= xf86GetVerbosity()) { |
| 135 | xf86MsgVerb(X_WARNING, verbosity, |
| 136 | "System lacks support for changing MTRRs\n"); |
| 137 | warned = TRUE; |
| 138 | } |
| 139 | |
| 140 | return FALSE; |
| 141 | } |
| 142 | else |
| 143 | return TRUE; |
| 144 | } |
| 145 | |
| 146 | /* |
| 147 | * We maintain a list of WC regions for each physical mapping so they can |
| 148 | * be undone when unmapping. |
| 149 | */ |
| 150 | |
| 151 | struct mtrr_wc_region { |
| 152 | struct mtrr_sentry sentry; |
| 153 | Bool added; /* added WC or removed it */ |
| 154 | struct mtrr_wc_region *next; |
| 155 | }; |
| 156 | |
| 157 | static struct mtrr_wc_region * |
| 158 | mtrr_cull_wc_region(int screenNum, unsigned long base, unsigned long size, |
| 159 | MessageType from) |
| 160 | { |
| 161 | /* Some BIOS writers thought that setting wc over the mmio |
| 162 | region of a graphics devices was a good idea. Try to fix |
| 163 | it. */ |
| 164 | |
| 165 | struct mtrr_gentry gent; |
| 166 | struct mtrr_wc_region *wcreturn = NULL, *wcr; |
| 167 | int count, ret = 0; |
| 168 | |
| 169 | /* Linux 2.0 users should not get a warning without -verbose */ |
| 170 | if (!mtrr_open(2)) |
| 171 | return NULL; |
| 172 | |
| 173 | for (gent.regnum = 0; |
| 174 | ioctl(mtrr_fd, MTRRIOC_GET_ENTRY, &gent) >= 0; gent.regnum++) { |
| 175 | if (gent.type != MTRR_TYPE_WRCOMB |
| 176 | || gent.base + gent.size <= base || base + size <= gent.base) |
| 177 | continue; |
| 178 | |
| 179 | /* Found an overlapping region. Delete it. */ |
| 180 | |
| 181 | wcr = malloc(sizeof(*wcr)); |
| 182 | if (!wcr) |
| 183 | return NULL; |
| 184 | wcr->sentry.base = gent.base; |
| 185 | wcr->sentry.size = gent.size; |
| 186 | wcr->sentry.type = MTRR_TYPE_WRCOMB; |
| 187 | wcr->added = FALSE; |
| 188 | |
| 189 | count = 3; |
| 190 | while (count-- && |
| 191 | (ret = ioctl(mtrr_fd, MTRRIOC_KILL_ENTRY, &(wcr->sentry))) < 0); |
| 192 | |
| 193 | if (ret >= 0) { |
| 194 | xf86DrvMsg(screenNum, from, |
| 195 | "Removed MMIO write-combining range " |
| 196 | "(0x%lx,0x%lx)\n", |
| 197 | (unsigned long) gent.base, (unsigned long) gent.size); |
| 198 | wcr->next = wcreturn; |
| 199 | wcreturn = wcr; |
| 200 | gent.regnum--; |
| 201 | } |
| 202 | else { |
| 203 | free(wcr); |
| 204 | xf86DrvMsgVerb(screenNum, X_WARNING, 0, |
| 205 | "Failed to remove MMIO " |
| 206 | "write-combining range (0x%lx,0x%lx)\n", |
| 207 | gent.base, (unsigned long) gent.size); |
| 208 | } |
| 209 | } |
| 210 | return wcreturn; |
| 211 | } |
| 212 | |
| 213 | static struct mtrr_wc_region * |
| 214 | mtrr_remove_offending(int screenNum, unsigned long base, unsigned long size, |
| 215 | MessageType from) |
| 216 | { |
| 217 | struct mtrr_gentry gent; |
| 218 | struct mtrr_wc_region *wcreturn = NULL, **wcr; |
| 219 | |
| 220 | if (!mtrr_open(2)) |
| 221 | return NULL; |
| 222 | |
| 223 | wcr = &wcreturn; |
| 224 | for (gent.regnum = 0; |
| 225 | ioctl(mtrr_fd, MTRRIOC_GET_ENTRY, &gent) >= 0; gent.regnum++) { |
| 226 | if (gent.type == MTRR_TYPE_WRCOMB |
| 227 | && ((gent.base >= base && gent.base + gent.size < base + size) || |
| 228 | (gent.base > base && gent.base + gent.size <= base + size))) { |
| 229 | *wcr = mtrr_cull_wc_region(screenNum, gent.base, gent.size, from); |
| 230 | if (*wcr) |
| 231 | gent.regnum--; |
| 232 | while (*wcr) { |
| 233 | wcr = &((*wcr)->next); |
| 234 | } |
| 235 | } |
| 236 | } |
| 237 | return wcreturn; |
| 238 | } |
| 239 | |
| 240 | static struct mtrr_wc_region * |
| 241 | mtrr_add_wc_region(int screenNum, unsigned long base, unsigned long size, |
| 242 | MessageType from) |
| 243 | { |
| 244 | struct mtrr_wc_region **wcr, *wcreturn, *curwcr; |
| 245 | |
| 246 | /* |
| 247 | * There can be only one.... |
| 248 | */ |
| 249 | |
| 250 | wcreturn = mtrr_remove_offending(screenNum, base, size, from); |
| 251 | wcr = &wcreturn; |
| 252 | while (*wcr) { |
| 253 | wcr = &((*wcr)->next); |
| 254 | } |
| 255 | |
| 256 | /* Linux 2.0 should not warn, unless the user explicitly asks for |
| 257 | WC. */ |
| 258 | |
| 259 | if (!mtrr_open(from == X_CONFIG ? 0 : 2)) |
| 260 | return wcreturn; |
| 261 | |
| 262 | *wcr = curwcr = malloc(sizeof(**wcr)); |
| 263 | if (!curwcr) |
| 264 | return wcreturn; |
| 265 | |
| 266 | curwcr->sentry.base = base; |
| 267 | curwcr->sentry.size = size; |
| 268 | curwcr->sentry.type = MTRR_TYPE_WRCOMB; |
| 269 | curwcr->added = TRUE; |
| 270 | curwcr->next = NULL; |
| 271 | |
| 272 | #if SPLIT_WC_REGIONS |
| 273 | /* |
| 274 | * Splits up the write-combining region if it is not aligned on a |
| 275 | * size boundary. |
| 276 | */ |
| 277 | |
| 278 | { |
| 279 | unsigned long lbase, d_size = 1; |
| 280 | unsigned long n_size = size; |
| 281 | unsigned long n_base = base; |
| 282 | |
| 283 | for (lbase = n_base, d_size = 1; !(lbase & 1); |
| 284 | lbase = lbase >> 1, d_size <<= 1); |
| 285 | while (d_size > n_size) |
| 286 | d_size = d_size >> 1; |
| 287 | DebugF("WC_BASE: 0x%lx WC_END: 0x%lx\n", base, base + d_size - 1); |
| 288 | n_base += d_size; |
| 289 | n_size -= d_size; |
| 290 | if (n_size) { |
| 291 | xf86DrvMsgVerb(screenNum, X_INFO, 3, "Splitting WC range: " |
| 292 | "base: 0x%lx, size: 0x%lx\n", base, size); |
| 293 | curwcr->next = mtrr_add_wc_region(screenNum, n_base, n_size, from); |
| 294 | } |
| 295 | curwcr->sentry.size = d_size; |
| 296 | } |
| 297 | |
| 298 | /*****************************************************************/ |
| 299 | #endif /* SPLIT_WC_REGIONS */ |
| 300 | |
| 301 | if (ioctl(mtrr_fd, MTRRIOC_ADD_ENTRY, &curwcr->sentry) >= 0) { |
| 302 | /* Avoid printing on every VT switch */ |
| 303 | if (xf86ServerIsInitialising()) { |
| 304 | xf86DrvMsg(screenNum, from, |
| 305 | "Write-combining range (0x%lx,0x%lx)\n", base, size); |
| 306 | } |
| 307 | return wcreturn; |
| 308 | } |
| 309 | else { |
| 310 | *wcr = curwcr->next; |
| 311 | free(curwcr); |
| 312 | |
| 313 | /* Don't complain about the VGA region: MTRR fixed |
| 314 | regions aren't currently supported, but might be in |
| 315 | the future. */ |
| 316 | if ((unsigned long) base >= 0x100000) { |
| 317 | xf86DrvMsgVerb(screenNum, X_WARNING, 0, |
| 318 | "Failed to set up write-combining range " |
| 319 | "(0x%lx,0x%lx)\n", base, size); |
| 320 | } |
| 321 | return wcreturn; |
| 322 | } |
| 323 | } |
| 324 | |
| 325 | static void |
| 326 | mtrr_undo_wc_region(int screenNum, struct mtrr_wc_region *wcr) |
| 327 | { |
| 328 | struct mtrr_wc_region *p, *prev; |
| 329 | |
| 330 | if (mtrr_fd >= 0) { |
| 331 | p = wcr; |
| 332 | while (p) { |
| 333 | if (p->added) |
| 334 | ioctl(mtrr_fd, MTRRIOC_DEL_ENTRY, &p->sentry); |
| 335 | prev = p; |
| 336 | p = p->next; |
| 337 | free(prev); |
| 338 | } |
| 339 | } |
| 340 | } |
| 341 | |
| 342 | static pointer |
| 343 | setWC(int screenNum, unsigned long base, unsigned long size, Bool enable, |
| 344 | MessageType from) |
| 345 | { |
| 346 | if (enable) |
| 347 | return mtrr_add_wc_region(screenNum, base, size, from); |
| 348 | else |
| 349 | return mtrr_cull_wc_region(screenNum, base, size, from); |
| 350 | } |
| 351 | |
| 352 | static void |
| 353 | undoWC(int screenNum, pointer regioninfo) |
| 354 | { |
| 355 | mtrr_undo_wc_region(screenNum, regioninfo); |
| 356 | } |
| 357 | |
| 358 | #endif /* HAS_MTRR_SUPPORT */ |
| 359 | |
| 360 | void |
| 361 | xf86OSInitVidMem(VidMemInfoPtr pVidMem) |
| 362 | { |
| 363 | pVidMem->linearSupported = TRUE; |
| 364 | #ifdef __alpha__ |
| 365 | if (axpSystem == -1) { |
| 366 | axpSystem = lnxGetAXP(); |
| 367 | if ((needSparse = (_bus_base_sparse() > 0))) { |
| 368 | hae_thresh = xf86AXPParams[axpSystem].hae_thresh; |
| 369 | hae_mask = xf86AXPParams[axpSystem].hae_mask; |
| 370 | } |
| 371 | bus_base = _bus_base(); |
| 372 | } |
| 373 | if (needSparse) { |
| 374 | xf86Msg(X_INFO, "Machine needs sparse mapping\n"); |
| 375 | pVidMem->mapMem = mapVidMemSparse; |
| 376 | pVidMem->unmapMem = unmapVidMemSparse; |
| 377 | } |
| 378 | else { |
| 379 | xf86Msg(X_INFO, "Machine type has 8/16 bit access\n"); |
| 380 | pVidMem->mapMem = mapVidMem; |
| 381 | pVidMem->unmapMem = unmapVidMem; |
| 382 | } |
| 383 | #else |
| 384 | pVidMem->mapMem = mapVidMem; |
| 385 | pVidMem->unmapMem = unmapVidMem; |
| 386 | #endif /* __alpha__ */ |
| 387 | |
| 388 | #ifdef HAS_MTRR_SUPPORT |
| 389 | pVidMem->setWC = setWC; |
| 390 | pVidMem->undoWC = undoWC; |
| 391 | #endif |
| 392 | pVidMem->initialised = TRUE; |
| 393 | } |
| 394 | |
| 395 | #ifdef __sparc__ |
| 396 | /* Basically, you simply cannot do this on Sparc. You have to do something portable |
| 397 | * like use /dev/fb* or mmap() on /proc/bus/pci/X/Y nodes. -DaveM |
| 398 | */ |
| 399 | static pointer |
| 400 | mapVidMem(int ScreenNum, unsigned long Base, unsigned long Size, int flags) |
| 401 | { |
| 402 | return NULL; |
| 403 | } |
| 404 | #else |
| 405 | static pointer |
| 406 | mapVidMem(int ScreenNum, unsigned long Base, unsigned long Size, int flags) |
| 407 | { |
| 408 | pointer base; |
| 409 | int fd; |
| 410 | int mapflags = MAP_SHARED; |
| 411 | int prot; |
| 412 | memType realBase, alignOff; |
| 413 | |
| 414 | realBase = Base & ~(getpagesize() - 1); |
| 415 | alignOff = Base - realBase; |
| 416 | DebugF("base: %lx, realBase: %lx, alignOff: %lx \n", |
| 417 | Base, realBase, alignOff); |
| 418 | |
| 419 | #if defined(__ia64__) || defined(__arm__) || defined(__s390__) |
| 420 | #ifndef MAP_WRITECOMBINED |
| 421 | #define MAP_WRITECOMBINED 0x00010000 |
| 422 | #endif |
| 423 | #ifndef MAP_NONCACHED |
| 424 | #define MAP_NONCACHED 0x00020000 |
| 425 | #endif |
| 426 | if (flags & VIDMEM_FRAMEBUFFER) |
| 427 | mapflags |= MAP_WRITECOMBINED; |
| 428 | else |
| 429 | mapflags |= MAP_NONCACHED; |
| 430 | #endif |
| 431 | |
| 432 | #if 0 |
| 433 | /* this will disappear when people upgrade their kernels */ |
| 434 | fd = open(DEV_MEM, |
| 435 | ((flags & VIDMEM_READONLY) ? O_RDONLY : O_RDWR) | O_SYNC); |
| 436 | #else |
| 437 | fd = open(DEV_MEM, (flags & VIDMEM_READONLY) ? O_RDONLY : O_RDWR); |
| 438 | #endif |
| 439 | if (fd < 0) { |
| 440 | FatalError("xf86MapVidMem: failed to open " DEV_MEM " (%s)\n", |
| 441 | strerror(errno)); |
| 442 | } |
| 443 | |
| 444 | if (flags & VIDMEM_READONLY) |
| 445 | prot = PROT_READ; |
| 446 | else |
| 447 | prot = PROT_READ | PROT_WRITE; |
| 448 | |
| 449 | /* This requires linux-0.99.pl10 or above */ |
| 450 | base = mmap((caddr_t) 0, Size + alignOff, prot, mapflags, fd, |
| 451 | (off_t) realBase + BUS_BASE); |
| 452 | close(fd); |
| 453 | if (base == MAP_FAILED) { |
| 454 | FatalError("xf86MapVidMem: Could not mmap framebuffer" |
| 455 | " (0x%08lx,0x%lx) (%s)\n", Base, Size, strerror(errno)); |
| 456 | } |
| 457 | DebugF("base: %lx aligned base: %lx\n", base, (char *) base + alignOff); |
| 458 | return (char *) base + alignOff; |
| 459 | } |
| 460 | #endif /* !(__sparc__) */ |
| 461 | |
| 462 | static void |
| 463 | unmapVidMem(int ScreenNum, pointer Base, unsigned long Size) |
| 464 | { |
| 465 | uintptr_t alignOff = (uintptr_t) Base |
| 466 | - ((uintptr_t) Base & ~(getpagesize() - 1)); |
| 467 | |
| 468 | DebugF("alignment offset: %lx\n", (unsigned long) alignOff); |
| 469 | munmap((void *) ((uintptr_t) Base - alignOff), (Size + alignOff)); |
| 470 | } |
| 471 | |
| 472 | /***************************************************************************/ |
| 473 | /* I/O Permissions section */ |
| 474 | /***************************************************************************/ |
| 475 | |
| 476 | #if defined(__powerpc__) |
| 477 | volatile unsigned char *ioBase = NULL; |
| 478 | |
| 479 | #ifndef __NR_pciconfig_iobase |
| 480 | #define __NR_pciconfig_iobase 200 |
| 481 | #endif |
| 482 | |
| 483 | static Bool |
| 484 | hwEnableIO(void) |
| 485 | { |
| 486 | int fd; |
| 487 | unsigned int ioBase_phys = syscall(__NR_pciconfig_iobase, 2, 0, 0); |
| 488 | |
| 489 | fd = open("/dev/mem", O_RDWR); |
| 490 | if (ioBase == NULL) { |
| 491 | ioBase = (volatile unsigned char *) mmap(0, 0x20000, |
| 492 | PROT_READ | PROT_WRITE, |
| 493 | MAP_SHARED, fd, ioBase_phys); |
| 494 | } |
| 495 | close(fd); |
| 496 | |
| 497 | return ioBase != MAP_FAILED; |
| 498 | } |
| 499 | |
| 500 | static void |
| 501 | hwDisableIO(void) |
| 502 | { |
| 503 | munmap(ioBase, 0x20000); |
| 504 | ioBase = NULL; |
| 505 | } |
| 506 | |
| 507 | #elif defined(__i386__) || defined(__x86_64__) || defined(__ia64__) || \ |
| 508 | defined(__alpha__) |
| 509 | |
| 510 | static Bool |
| 511 | hwEnableIO(void) |
| 512 | { |
| 513 | if (ioperm(0, 1024, 1) || iopl(3)) { |
| 514 | ErrorF("xf86EnableIOPorts: failed to set IOPL for I/O (%s)\n", |
| 515 | strerror(errno)); |
| 516 | return FALSE; |
| 517 | } |
| 518 | #if !defined(__alpha__) |
| 519 | /* XXX: this is actually not trapping anything because of iopl(3) |
| 520 | * above */ |
| 521 | ioperm(0x40, 4, 0); /* trap access to the timer chip */ |
| 522 | ioperm(0x60, 4, 0); /* trap access to the keyboard controller */ |
| 523 | #endif |
| 524 | |
| 525 | return TRUE; |
| 526 | } |
| 527 | |
| 528 | static void |
| 529 | hwDisableIO(void) |
| 530 | { |
| 531 | iopl(0); |
| 532 | ioperm(0, 1024, 0); |
| 533 | } |
| 534 | |
| 535 | #else /* non-IO architectures */ |
| 536 | |
| 537 | #define hwEnableIO() TRUE |
| 538 | #define hwDisableIO() do {} while (0) |
| 539 | |
| 540 | #endif |
| 541 | |
| 542 | Bool |
| 543 | xf86EnableIO(void) |
| 544 | { |
| 545 | if (ExtendedEnabled) |
| 546 | return TRUE; |
| 547 | |
| 548 | ExtendedEnabled = hwEnableIO(); |
| 549 | |
| 550 | return ExtendedEnabled; |
| 551 | } |
| 552 | |
| 553 | void |
| 554 | xf86DisableIO(void) |
| 555 | { |
| 556 | if (!ExtendedEnabled) |
| 557 | return; |
| 558 | |
| 559 | hwDisableIO(); |
| 560 | |
| 561 | ExtendedEnabled = FALSE; |
| 562 | } |
| 563 | |
| 564 | #if defined (__alpha__) |
| 565 | |
| 566 | #define vuip volatile unsigned int * |
| 567 | |
| 568 | extern int readDense8(pointer Base, register unsigned long Offset); |
| 569 | extern int readDense16(pointer Base, register unsigned long Offset); |
| 570 | extern int readDense32(pointer Base, register unsigned long Offset); |
| 571 | extern void |
| 572 | writeDenseNB8(int Value, pointer Base, register unsigned long Offset); |
| 573 | extern void |
| 574 | writeDenseNB16(int Value, pointer Base, register unsigned long Offset); |
| 575 | extern void |
| 576 | writeDenseNB32(int Value, pointer Base, register unsigned long Offset); |
| 577 | extern void |
| 578 | writeDense8(int Value, pointer Base, register unsigned long Offset); |
| 579 | extern void |
| 580 | writeDense16(int Value, pointer Base, register unsigned long Offset); |
| 581 | extern void |
| 582 | writeDense32(int Value, pointer Base, register unsigned long Offset); |
| 583 | |
| 584 | static int readSparse8(pointer Base, register unsigned long Offset); |
| 585 | static int readSparse16(pointer Base, register unsigned long Offset); |
| 586 | static int readSparse32(pointer Base, register unsigned long Offset); |
| 587 | static void |
| 588 | writeSparseNB8(int Value, pointer Base, register unsigned long Offset); |
| 589 | static void |
| 590 | writeSparseNB16(int Value, pointer Base, register unsigned long Offset); |
| 591 | static void |
| 592 | writeSparseNB32(int Value, pointer Base, register unsigned long Offset); |
| 593 | static void |
| 594 | writeSparse8(int Value, pointer Base, register unsigned long Offset); |
| 595 | static void |
| 596 | writeSparse16(int Value, pointer Base, register unsigned long Offset); |
| 597 | static void |
| 598 | writeSparse32(int Value, pointer Base, register unsigned long Offset); |
| 599 | |
| 600 | #define DENSE_BASE 0x2ff00000000UL |
| 601 | #define SPARSE_BASE 0x30000000000UL |
| 602 | |
| 603 | static unsigned long msb_set = 0; |
| 604 | |
| 605 | static pointer |
| 606 | mapVidMemSparse(int ScreenNum, unsigned long Base, unsigned long Size, |
| 607 | int flags) |
| 608 | { |
| 609 | int fd, prot; |
| 610 | unsigned long ret, rets = 0; |
| 611 | |
| 612 | static Bool was_here = FALSE; |
| 613 | |
| 614 | if (!was_here) { |
| 615 | was_here = TRUE; |
| 616 | |
| 617 | xf86WriteMmio8 = writeSparse8; |
| 618 | xf86WriteMmio16 = writeSparse16; |
| 619 | xf86WriteMmio32 = writeSparse32; |
| 620 | xf86WriteMmioNB8 = writeSparseNB8; |
| 621 | xf86WriteMmioNB16 = writeSparseNB16; |
| 622 | xf86WriteMmioNB32 = writeSparseNB32; |
| 623 | xf86ReadMmio8 = readSparse8; |
| 624 | xf86ReadMmio16 = readSparse16; |
| 625 | xf86ReadMmio32 = readSparse32; |
| 626 | } |
| 627 | |
| 628 | fd = open(DEV_MEM, (flags & VIDMEM_READONLY) ? O_RDONLY : O_RDWR); |
| 629 | if (fd < 0) { |
| 630 | FatalError("xf86MapVidMem: failed to open " DEV_MEM " (%s)\n", |
| 631 | strerror(errno)); |
| 632 | } |
| 633 | |
| 634 | #if 0 |
| 635 | xf86Msg(X_INFO, "mapVidMemSparse: try Base 0x%lx size 0x%lx flags 0x%x\n", |
| 636 | Base, Size, flags); |
| 637 | #endif |
| 638 | |
| 639 | if (flags & VIDMEM_READONLY) |
| 640 | prot = PROT_READ; |
| 641 | else |
| 642 | prot = PROT_READ | PROT_WRITE; |
| 643 | |
| 644 | /* This requirers linux-0.99.pl10 or above */ |
| 645 | |
| 646 | /* |
| 647 | * Always do DENSE mmap, since read32/write32 currently require it. |
| 648 | */ |
| 649 | ret = (unsigned long) mmap((caddr_t) (DENSE_BASE + Base), Size, |
| 650 | prot, MAP_SHARED, fd, (off_t) (bus_base + Base)); |
| 651 | |
| 652 | /* |
| 653 | * Do SPARSE mmap only when MMIO and not MMIO_32BIT, or FRAMEBUFFER |
| 654 | * and SPARSE (which should require the use of read/write macros). |
| 655 | * |
| 656 | * By not SPARSE mmapping an 8MB framebuffer, we can save approx. 256K |
| 657 | * bytes worth of pagetable (32 pages). |
| 658 | */ |
| 659 | if (((flags & VIDMEM_MMIO) && !(flags & VIDMEM_MMIO_32BIT)) || |
| 660 | ((flags & VIDMEM_FRAMEBUFFER) && (flags & VIDMEM_SPARSE))) { |
| 661 | rets = (unsigned long) mmap((caddr_t) (SPARSE_BASE + (Base << 5)), |
| 662 | Size << 5, prot, MAP_SHARED, fd, |
| 663 | (off_t) _bus_base_sparse() + (Base << 5)); |
| 664 | } |
| 665 | |
| 666 | close(fd); |
| 667 | |
| 668 | if (ret == (unsigned long) MAP_FAILED) { |
| 669 | FatalError("xf86MapVidMemSparse: Could not (dense) mmap fb (%s)\n", |
| 670 | strerror(errno)); |
| 671 | } |
| 672 | |
| 673 | if (((flags & VIDMEM_MMIO) && !(flags & VIDMEM_MMIO_32BIT)) || |
| 674 | ((flags & VIDMEM_FRAMEBUFFER) && (flags & VIDMEM_SPARSE))) { |
| 675 | if (rets == (unsigned long) MAP_FAILED || |
| 676 | rets != (SPARSE_BASE + (Base << 5))) { |
| 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", Base, Size, ret); |
| 690 | |
| 691 | #endif |
| 692 | return (pointer) ret; |
| 693 | } |
| 694 | |
| 695 | static void |
| 696 | unmapVidMemSparse(int ScreenNum, pointer Base, unsigned long Size) |
| 697 | { |
| 698 | unsigned long Offset = (unsigned long) Base - DENSE_BASE; |
| 699 | |
| 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 | |
| 711 | static int |
| 712 | readSparse8(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 | |
| 735 | static int |
| 736 | readSparse16(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 | |
| 759 | static int |
| 760 | readSparse32(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 | |
| 767 | static void |
| 768 | writeSparse8(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 | |
| 788 | static void |
| 789 | writeSparse16(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 | |
| 809 | static void |
| 810 | writeSparse32(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 | |
| 818 | static void |
| 819 | writeSparseNB8(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 | |
| 836 | static void |
| 837 | writeSparseNB16(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 | |
| 854 | static void |
| 855 | writeSparseNB32(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 | |
| 862 | void (*xf86WriteMmio8) (int Value, pointer Base, unsigned long Offset) |
| 863 | = writeDense8; |
| 864 | void (*xf86WriteMmio16) (int Value, pointer Base, unsigned long Offset) |
| 865 | = writeDense16; |
| 866 | void (*xf86WriteMmio32) (int Value, pointer Base, unsigned long Offset) |
| 867 | = writeDense32; |
| 868 | void (*xf86WriteMmioNB8) (int Value, pointer Base, unsigned long Offset) |
| 869 | = writeDenseNB8; |
| 870 | void (*xf86WriteMmioNB16) (int Value, pointer Base, unsigned long Offset) |
| 871 | = writeDenseNB16; |
| 872 | void (*xf86WriteMmioNB32) (int Value, pointer Base, unsigned long Offset) |
| 873 | = writeDenseNB32; |
| 874 | int (*xf86ReadMmio8) (pointer Base, unsigned long Offset) |
| 875 | = readDense8; |
| 876 | int (*xf86ReadMmio16) (pointer Base, unsigned long Offset) |
| 877 | = readDense16; |
| 878 | int (*xf86ReadMmio32) (pointer Base, unsigned long Offset) |
| 879 | = readDense32; |
| 880 | |
| 881 | #endif /* __alpha__ */ |