Commit | Line | Data |
---|---|---|
a09e091a JB |
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__ */ |