2006-11-26 11:13:41 -07:00
|
|
|
/*
|
|
|
|
* Copyright 1992 by Orest Zborowski <obz@Kodak.com>
|
|
|
|
* Copyright 1993 by David Wexelblat <dwex@goblin.org>
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
|
|
* documentation for any purpose is hereby granted without fee, provided that
|
|
|
|
* the above copyright notice appear in all copies and that both that
|
|
|
|
* copyright notice and this permission notice appear in supporting
|
|
|
|
* documentation, and that the names of Orest Zborowski and David Wexelblat
|
|
|
|
* not be used in advertising or publicity pertaining to distribution of
|
|
|
|
* the software without specific, written prior permission. Orest Zborowski
|
|
|
|
* and David Wexelblat make no representations about the suitability of this
|
|
|
|
* software for any purpose. It is provided "as is" without express or
|
|
|
|
* implied warranty.
|
|
|
|
*
|
|
|
|
* OREST ZBOROWSKI AND DAVID WEXELBLAT DISCLAIMS ALL WARRANTIES WITH REGARD
|
|
|
|
* TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
|
|
* FITNESS, IN NO EVENT SHALL OREST ZBOROWSKI OR DAVID WEXELBLAT BE LIABLE
|
|
|
|
* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_XORG_CONFIG_H
|
|
|
|
#include <xorg-config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <X11/X.h>
|
|
|
|
#include "input.h"
|
|
|
|
#include "scrnintstr.h"
|
|
|
|
|
|
|
|
#include "xf86.h"
|
|
|
|
#include "xf86Priv.h"
|
|
|
|
#include "xf86_OSlib.h"
|
|
|
|
#include "xf86OSpriv.h"
|
|
|
|
#ifdef __alpha__
|
|
|
|
#include "shared/xf86Axp.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAS_MTRR_SUPPORT
|
|
|
|
#include <asm/mtrr.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef MAP_FAILED
|
|
|
|
#define MAP_FAILED ((void *)-1)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static Bool ExtendedEnabled = FALSE;
|
|
|
|
|
|
|
|
#ifdef __ia64__
|
|
|
|
|
|
|
|
#include "compiler.h"
|
|
|
|
#include <sys/io.h>
|
|
|
|
|
|
|
|
#elif !defined(__powerpc__) && \
|
|
|
|
!defined(__mc68000__) && \
|
|
|
|
!defined(__sparc__) && \
|
2007-11-24 10:55:21 -07:00
|
|
|
!defined(__mips__) && \
|
|
|
|
!defined(__arm__)
|
2006-11-26 11:13:41 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Due to conflicts with "compiler.h", don't rely on <sys/io.h> to declare
|
|
|
|
* these.
|
|
|
|
*/
|
|
|
|
extern int ioperm(unsigned long __from, unsigned long __num, int __turn_on);
|
|
|
|
extern int iopl(int __level);
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef __alpha__
|
|
|
|
# define BUS_BASE bus_base
|
|
|
|
#else
|
|
|
|
#define BUS_BASE (0)
|
|
|
|
#endif /* __alpha__ */
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
|
|
/* Video Memory Mapping section */
|
|
|
|
/***************************************************************************/
|
|
|
|
|
|
|
|
static pointer mapVidMem(int, unsigned long, unsigned long, int);
|
|
|
|
static void unmapVidMem(int, pointer, unsigned long);
|
|
|
|
#if defined (__alpha__)
|
2010-07-27 13:02:24 -06:00
|
|
|
extern void sethae(unsigned long hae);
|
|
|
|
extern unsigned long _bus_base __P ((void)) __attribute__ ((const));
|
|
|
|
extern unsigned long _bus_base_sparse __P ((void)) __attribute__ ((const));
|
|
|
|
|
2006-11-26 11:13:41 -07:00
|
|
|
static pointer mapVidMemSparse(int, unsigned long, unsigned long, int);
|
|
|
|
extern axpDevice lnxGetAXP(void);
|
|
|
|
static void unmapVidMemSparse(int, pointer, unsigned long);
|
|
|
|
static axpDevice axpSystem = -1;
|
|
|
|
static Bool needSparse;
|
|
|
|
static unsigned long hae_thresh;
|
|
|
|
static unsigned long hae_mask;
|
|
|
|
static unsigned long bus_base;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAS_MTRR_SUPPORT
|
|
|
|
|
|
|
|
#define SPLIT_WC_REGIONS 1
|
|
|
|
|
|
|
|
static pointer setWC(int, unsigned long, unsigned long, Bool, MessageType);
|
|
|
|
static void undoWC(int, pointer);
|
|
|
|
|
|
|
|
/* The file desc for /proc/mtrr. Once opened, left opened, and the mtrr
|
|
|
|
driver will clean up when we exit. */
|
|
|
|
#define MTRR_FD_UNOPENED (-1) /* We have yet to open /proc/mtrr */
|
|
|
|
#define MTRR_FD_PROBLEM (-2) /* We tried to open /proc/mtrr, but had
|
|
|
|
a problem. */
|
|
|
|
static int mtrr_fd = MTRR_FD_UNOPENED;
|
|
|
|
|
|
|
|
/* Open /proc/mtrr. FALSE on failure. Will always fail on Linux 2.0,
|
|
|
|
and will fail on Linux 2.2 with MTRR support configured out,
|
|
|
|
so verbosity should be chosen appropriately. */
|
|
|
|
static Bool
|
|
|
|
mtrr_open(int verbosity)
|
|
|
|
{
|
|
|
|
/* Only report absence of /proc/mtrr once. */
|
|
|
|
static Bool warned = FALSE;
|
|
|
|
|
|
|
|
if (mtrr_fd == MTRR_FD_UNOPENED) {
|
2008-11-02 08:26:08 -07:00
|
|
|
mtrr_fd = open("/proc/mtrr", O_WRONLY);
|
2006-11-26 11:13:41 -07:00
|
|
|
|
|
|
|
if (mtrr_fd < 0)
|
|
|
|
mtrr_fd = MTRR_FD_PROBLEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mtrr_fd == MTRR_FD_PROBLEM) {
|
|
|
|
/* To make sure we only ever warn once, need to check
|
|
|
|
verbosity outside xf86MsgVerb */
|
|
|
|
if (!warned && verbosity <= xf86GetVerbosity()) {
|
|
|
|
xf86MsgVerb(X_WARNING, verbosity,
|
|
|
|
"System lacks support for changing MTRRs\n");
|
|
|
|
warned = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We maintain a list of WC regions for each physical mapping so they can
|
|
|
|
* be undone when unmapping.
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct mtrr_wc_region {
|
|
|
|
struct mtrr_sentry sentry;
|
|
|
|
Bool added; /* added WC or removed it */
|
|
|
|
struct mtrr_wc_region * next;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static struct mtrr_wc_region *
|
|
|
|
mtrr_cull_wc_region(int screenNum, unsigned long base, unsigned long size,
|
|
|
|
MessageType from)
|
|
|
|
{
|
|
|
|
/* Some BIOS writers thought that setting wc over the mmio
|
|
|
|
region of a graphics devices was a good idea. Try to fix
|
|
|
|
it. */
|
|
|
|
|
|
|
|
struct mtrr_gentry gent;
|
|
|
|
struct mtrr_wc_region *wcreturn = NULL, *wcr;
|
|
|
|
int count, ret=0;
|
|
|
|
|
|
|
|
/* Linux 2.0 users should not get a warning without -verbose */
|
|
|
|
if (!mtrr_open(2))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
for (gent.regnum = 0;
|
|
|
|
ioctl(mtrr_fd, MTRRIOC_GET_ENTRY, &gent) >= 0;
|
|
|
|
gent.regnum++) {
|
|
|
|
if (gent.type != MTRR_TYPE_WRCOMB
|
|
|
|
|| gent.base + gent.size <= base
|
|
|
|
|| base + size <= gent.base)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Found an overlapping region. Delete it. */
|
|
|
|
|
2010-12-05 08:36:02 -07:00
|
|
|
wcr = malloc(sizeof(*wcr));
|
2006-11-26 11:13:41 -07:00
|
|
|
if (!wcr)
|
|
|
|
return NULL;
|
|
|
|
wcr->sentry.base = gent.base;
|
|
|
|
wcr->sentry.size = gent.size;
|
|
|
|
wcr->sentry.type = MTRR_TYPE_WRCOMB;
|
|
|
|
wcr->added = FALSE;
|
|
|
|
|
|
|
|
count = 3;
|
|
|
|
while (count-- &&
|
|
|
|
(ret = ioctl(mtrr_fd, MTRRIOC_KILL_ENTRY, &(wcr->sentry))) < 0);
|
|
|
|
|
|
|
|
if (ret >= 0) {
|
|
|
|
xf86DrvMsg(screenNum, from,
|
|
|
|
"Removed MMIO write-combining range "
|
|
|
|
"(0x%lx,0x%lx)\n",
|
|
|
|
(unsigned long) gent.base, (unsigned long) gent.size);
|
|
|
|
wcr->next = wcreturn;
|
|
|
|
wcreturn = wcr;
|
|
|
|
gent.regnum--;
|
|
|
|
} else {
|
2010-12-05 08:36:02 -07:00
|
|
|
free(wcr);
|
2006-11-26 11:13:41 -07:00
|
|
|
xf86DrvMsgVerb(screenNum, X_WARNING, 0,
|
|
|
|
"Failed to remove MMIO "
|
|
|
|
"write-combining range (0x%lx,0x%lx)\n",
|
|
|
|
gent.base, (unsigned long) gent.size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return wcreturn;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static struct mtrr_wc_region *
|
|
|
|
mtrr_remove_offending(int screenNum, unsigned long base, unsigned long size,
|
|
|
|
MessageType from)
|
|
|
|
{
|
|
|
|
struct mtrr_gentry gent;
|
|
|
|
struct mtrr_wc_region *wcreturn = NULL, **wcr;
|
|
|
|
|
|
|
|
if (!mtrr_open(2))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
wcr = &wcreturn;
|
|
|
|
for (gent.regnum = 0;
|
|
|
|
ioctl(mtrr_fd, MTRRIOC_GET_ENTRY, &gent) >= 0; gent.regnum++ ) {
|
|
|
|
if (gent.type == MTRR_TYPE_WRCOMB
|
|
|
|
&& ((gent.base >= base && gent.base + gent.size < base + size) ||
|
|
|
|
(gent.base > base && gent.base + gent.size <= base + size))) {
|
|
|
|
*wcr = mtrr_cull_wc_region(screenNum, gent.base, gent.size, from);
|
|
|
|
if (*wcr) gent.regnum--;
|
|
|
|
while(*wcr) {
|
|
|
|
wcr = &((*wcr)->next);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return wcreturn;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static struct mtrr_wc_region *
|
|
|
|
mtrr_add_wc_region(int screenNum, unsigned long base, unsigned long size,
|
|
|
|
MessageType from)
|
|
|
|
{
|
|
|
|
struct mtrr_wc_region **wcr, *wcreturn, *curwcr;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* There can be only one....
|
|
|
|
*/
|
|
|
|
|
|
|
|
wcreturn = mtrr_remove_offending(screenNum, base, size, from);
|
|
|
|
wcr = &wcreturn;
|
|
|
|
while (*wcr) {
|
|
|
|
wcr = &((*wcr)->next);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Linux 2.0 should not warn, unless the user explicitly asks for
|
|
|
|
WC. */
|
|
|
|
|
|
|
|
if (!mtrr_open(from == X_CONFIG ? 0 : 2))
|
|
|
|
return wcreturn;
|
|
|
|
|
2010-12-05 08:36:02 -07:00
|
|
|
*wcr = curwcr = malloc(sizeof(**wcr));
|
2006-11-26 11:13:41 -07:00
|
|
|
if (!curwcr)
|
|
|
|
return wcreturn;
|
|
|
|
|
|
|
|
curwcr->sentry.base = base;
|
|
|
|
curwcr->sentry.size = size;
|
|
|
|
curwcr->sentry.type = MTRR_TYPE_WRCOMB;
|
|
|
|
curwcr->added = TRUE;
|
|
|
|
curwcr->next = NULL;
|
|
|
|
|
|
|
|
#if SPLIT_WC_REGIONS
|
|
|
|
/*
|
|
|
|
* Splits up the write-combining region if it is not aligned on a
|
|
|
|
* size boundary.
|
|
|
|
*/
|
|
|
|
|
|
|
|
{
|
|
|
|
unsigned long lbase, d_size = 1;
|
|
|
|
unsigned long n_size = size;
|
|
|
|
unsigned long n_base = base;
|
|
|
|
|
|
|
|
for (lbase = n_base, d_size = 1; !(lbase & 1);
|
|
|
|
lbase = lbase >> 1, d_size <<= 1);
|
|
|
|
while (d_size > n_size)
|
|
|
|
d_size = d_size >> 1;
|
2010-07-27 13:02:24 -06:00
|
|
|
DebugF("WC_BASE: 0x%lx WC_END: 0x%lx\n",base,base+d_size-1);
|
2006-11-26 11:13:41 -07:00
|
|
|
n_base += d_size;
|
|
|
|
n_size -= d_size;
|
|
|
|
if (n_size) {
|
|
|
|
xf86DrvMsgVerb(screenNum,X_INFO,3,"Splitting WC range: "
|
|
|
|
"base: 0x%lx, size: 0x%lx\n",base,size);
|
|
|
|
curwcr->next = mtrr_add_wc_region(screenNum, n_base, n_size,from);
|
|
|
|
}
|
|
|
|
curwcr->sentry.size = d_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************/
|
|
|
|
#endif /* SPLIT_WC_REGIONS */
|
|
|
|
|
|
|
|
if (ioctl(mtrr_fd, MTRRIOC_ADD_ENTRY, &curwcr->sentry) >= 0) {
|
|
|
|
/* Avoid printing on every VT switch */
|
|
|
|
if (xf86ServerIsInitialising()) {
|
|
|
|
xf86DrvMsg(screenNum, from,
|
|
|
|
"Write-combining range (0x%lx,0x%lx)\n",
|
|
|
|
base, size);
|
|
|
|
}
|
|
|
|
return wcreturn;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*wcr = curwcr->next;
|
2010-12-05 08:36:02 -07:00
|
|
|
free(curwcr);
|
2006-11-26 11:13:41 -07:00
|
|
|
|
|
|
|
/* Don't complain about the VGA region: MTRR fixed
|
|
|
|
regions aren't currently supported, but might be in
|
|
|
|
the future. */
|
|
|
|
if ((unsigned long)base >= 0x100000) {
|
|
|
|
xf86DrvMsgVerb(screenNum, X_WARNING, 0,
|
|
|
|
"Failed to set up write-combining range "
|
|
|
|
"(0x%lx,0x%lx)\n", base, size);
|
|
|
|
}
|
|
|
|
return wcreturn;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
mtrr_undo_wc_region(int screenNum, struct mtrr_wc_region *wcr)
|
|
|
|
{
|
|
|
|
struct mtrr_wc_region *p, *prev;
|
|
|
|
|
2010-07-27 13:02:24 -06:00
|
|
|
if (mtrr_fd >= 0) {
|
2006-11-26 11:13:41 -07:00
|
|
|
p = wcr;
|
|
|
|
while (p) {
|
|
|
|
if (p->added)
|
|
|
|
ioctl(mtrr_fd, MTRRIOC_DEL_ENTRY, &p->sentry);
|
|
|
|
prev = p;
|
|
|
|
p = p->next;
|
2010-12-05 08:36:02 -07:00
|
|
|
free(prev);
|
2006-11-26 11:13:41 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static pointer
|
|
|
|
setWC(int screenNum, unsigned long base, unsigned long size, Bool enable,
|
|
|
|
MessageType from)
|
|
|
|
{
|
|
|
|
if (enable)
|
|
|
|
return mtrr_add_wc_region(screenNum, base, size, from);
|
|
|
|
else
|
|
|
|
return mtrr_cull_wc_region(screenNum, base, size, from);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
undoWC(int screenNum, pointer regioninfo)
|
|
|
|
{
|
|
|
|
mtrr_undo_wc_region(screenNum, regioninfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* HAS_MTRR_SUPPORT */
|
|
|
|
|
|
|
|
void
|
|
|
|
xf86OSInitVidMem(VidMemInfoPtr pVidMem)
|
|
|
|
{
|
|
|
|
pVidMem->linearSupported = TRUE;
|
|
|
|
#ifdef __alpha__
|
|
|
|
if (axpSystem == -1) {
|
|
|
|
axpSystem = lnxGetAXP();
|
|
|
|
if ((needSparse = (_bus_base_sparse() > 0))) {
|
|
|
|
hae_thresh = xf86AXPParams[axpSystem].hae_thresh;
|
|
|
|
hae_mask = xf86AXPParams[axpSystem].hae_mask;
|
|
|
|
}
|
|
|
|
bus_base = _bus_base();
|
|
|
|
}
|
2009-09-06 13:44:18 -06:00
|
|
|
if (needSparse) {
|
2006-11-26 11:13:41 -07:00
|
|
|
xf86Msg(X_INFO,"Machine needs sparse mapping\n");
|
|
|
|
pVidMem->mapMem = mapVidMemSparse;
|
|
|
|
pVidMem->unmapMem = unmapVidMemSparse;
|
|
|
|
} else {
|
|
|
|
xf86Msg(X_INFO,"Machine type has 8/16 bit access\n");
|
|
|
|
pVidMem->mapMem = mapVidMem;
|
|
|
|
pVidMem->unmapMem = unmapVidMem;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
pVidMem->mapMem = mapVidMem;
|
|
|
|
pVidMem->unmapMem = unmapVidMem;
|
|
|
|
#endif /* __alpha__ */
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef HAS_MTRR_SUPPORT
|
|
|
|
pVidMem->setWC = setWC;
|
|
|
|
pVidMem->undoWC = undoWC;
|
|
|
|
#endif
|
|
|
|
pVidMem->initialised = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef __sparc__
|
|
|
|
/* Basically, you simply cannot do this on Sparc. You have to do something portable
|
|
|
|
* like use /dev/fb* or mmap() on /proc/bus/pci/X/Y nodes. -DaveM
|
|
|
|
*/
|
|
|
|
static pointer mapVidMem(int ScreenNum, unsigned long Base, unsigned long Size, int flags)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static pointer
|
|
|
|
mapVidMem(int ScreenNum, unsigned long Base, unsigned long Size, int flags)
|
|
|
|
{
|
|
|
|
pointer base;
|
|
|
|
int fd;
|
|
|
|
int mapflags = MAP_SHARED;
|
|
|
|
int prot;
|
|
|
|
memType realBase, alignOff;
|
|
|
|
|
|
|
|
realBase = Base & ~(getpagesize() - 1);
|
|
|
|
alignOff = Base - realBase;
|
2010-07-27 13:02:24 -06:00
|
|
|
DebugF("base: %lx, realBase: %lx, alignOff: %lx \n",
|
2006-11-26 11:13:41 -07:00
|
|
|
Base,realBase,alignOff);
|
2010-07-27 13:02:24 -06:00
|
|
|
|
2006-11-26 11:13:41 -07:00
|
|
|
#if defined(__ia64__) || defined(__arm__) || defined(__s390__)
|
|
|
|
#ifndef MAP_WRITECOMBINED
|
|
|
|
#define MAP_WRITECOMBINED 0x00010000
|
|
|
|
#endif
|
|
|
|
#ifndef MAP_NONCACHED
|
|
|
|
#define MAP_NONCACHED 0x00020000
|
|
|
|
#endif
|
|
|
|
if(flags & VIDMEM_FRAMEBUFFER)
|
|
|
|
mapflags |= MAP_WRITECOMBINED;
|
|
|
|
else
|
|
|
|
mapflags |= MAP_NONCACHED;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
/* this will disappear when people upgrade their kernels */
|
|
|
|
fd = open(DEV_MEM,
|
|
|
|
((flags & VIDMEM_READONLY) ? O_RDONLY : O_RDWR) | O_SYNC);
|
|
|
|
#else
|
|
|
|
fd = open(DEV_MEM, (flags & VIDMEM_READONLY) ? O_RDONLY : O_RDWR);
|
|
|
|
#endif
|
|
|
|
if (fd < 0)
|
|
|
|
{
|
|
|
|
FatalError("xf86MapVidMem: failed to open " DEV_MEM " (%s)\n",
|
|
|
|
strerror(errno));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & VIDMEM_READONLY)
|
|
|
|
prot = PROT_READ;
|
|
|
|
else
|
|
|
|
prot = PROT_READ | PROT_WRITE;
|
|
|
|
|
|
|
|
/* This requires linux-0.99.pl10 or above */
|
|
|
|
base = mmap((caddr_t)0, Size + alignOff, prot, mapflags, fd,
|
|
|
|
(off_t)realBase + BUS_BASE);
|
|
|
|
close(fd);
|
|
|
|
if (base == MAP_FAILED) {
|
|
|
|
FatalError("xf86MapVidMem: Could not mmap framebuffer"
|
|
|
|
" (0x%08lx,0x%lx) (%s)\n", Base, Size,
|
|
|
|
strerror(errno));
|
|
|
|
}
|
2010-07-27 13:02:24 -06:00
|
|
|
DebugF("base: %lx aligned base: %lx\n",base, base + alignOff);
|
2006-11-26 11:13:41 -07:00
|
|
|
return (char *)base + alignOff;
|
|
|
|
}
|
|
|
|
#endif /* !(__sparc__) */
|
|
|
|
|
|
|
|
static void
|
|
|
|
unmapVidMem(int ScreenNum, pointer Base, unsigned long Size)
|
|
|
|
{
|
|
|
|
memType alignOff = (memType)Base
|
|
|
|
- ((memType)Base & ~(getpagesize() - 1));
|
2010-07-27 13:02:24 -06:00
|
|
|
|
|
|
|
DebugF("alignment offset: %lx\n",alignOff);
|
2006-11-26 11:13:41 -07:00
|
|
|
munmap((caddr_t)((memType)Base - alignOff), (Size + alignOff));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
|
|
/* I/O Permissions section */
|
|
|
|
/***************************************************************************/
|
|
|
|
|
|
|
|
#if defined(__powerpc__)
|
2010-07-27 13:02:24 -06:00
|
|
|
volatile unsigned char *ioBase = NULL;
|
2006-11-26 11:13:41 -07:00
|
|
|
|
|
|
|
#ifndef __NR_pciconfig_iobase
|
|
|
|
#define __NR_pciconfig_iobase 200
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2010-07-27 13:02:24 -06:00
|
|
|
Bool
|
2006-11-26 11:13:41 -07:00
|
|
|
xf86EnableIO(void)
|
|
|
|
{
|
|
|
|
#if defined(__powerpc__)
|
|
|
|
int fd;
|
|
|
|
unsigned int ioBase_phys;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (ExtendedEnabled)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
#if defined(__powerpc__)
|
|
|
|
ioBase_phys = syscall(__NR_pciconfig_iobase, 2, 0, 0);
|
|
|
|
|
|
|
|
fd = open("/dev/mem", O_RDWR);
|
|
|
|
if (ioBase == NULL) {
|
|
|
|
ioBase = (volatile unsigned char *)mmap(0, 0x20000,
|
|
|
|
PROT_READ | PROT_WRITE, MAP_SHARED, fd,
|
|
|
|
ioBase_phys);
|
|
|
|
/* Should this be fatal or just a warning? */
|
|
|
|
#if 0
|
|
|
|
if (ioBase == MAP_FAILED) {
|
|
|
|
xf86Msg(X_WARNING,
|
|
|
|
"xf86EnableIOPorts: Failed to map iobase (%s)\n",
|
|
|
|
strerror(errno));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
close(fd);
|
2009-09-06 13:44:18 -06:00
|
|
|
#elif !defined(__mc68000__) && !defined(__sparc__) && !defined(__mips__) && !defined(__sh__) && !defined(__hppa__) && !defined(__s390__) && !defined(__arm__) && !defined(__m32r__)
|
2006-11-26 11:13:41 -07:00
|
|
|
if (ioperm(0, 1024, 1) || iopl(3)) {
|
|
|
|
if (errno == ENODEV)
|
|
|
|
ErrorF("xf86EnableIOPorts: no I/O ports found\n");
|
|
|
|
else
|
|
|
|
FatalError("xf86EnableIOPorts: failed to set IOPL"
|
|
|
|
" for I/O (%s)\n", strerror(errno));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
# if !defined(__alpha__)
|
|
|
|
ioperm(0x40,4,0); /* trap access to the timer chip */
|
|
|
|
ioperm(0x60,4,0); /* trap access to the keyboard controller */
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
ExtendedEnabled = TRUE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2010-07-27 13:02:24 -06:00
|
|
|
void
|
2006-11-26 11:13:41 -07:00
|
|
|
xf86DisableIO(void)
|
|
|
|
{
|
|
|
|
if (!ExtendedEnabled)
|
|
|
|
return;
|
|
|
|
#if defined(__powerpc__)
|
|
|
|
munmap(ioBase, 0x20000);
|
|
|
|
ioBase = NULL;
|
2009-09-06 13:44:18 -06:00
|
|
|
#elif !defined(__mc68000__) && !defined(__sparc__) && !defined(__mips__) && !defined(__sh__) && !defined(__hppa__) && !defined(__arm__) && !defined(__s390__) && !defined(__m32r__)
|
2006-11-26 11:13:41 -07:00
|
|
|
iopl(0);
|
|
|
|
ioperm(0, 1024, 0);
|
|
|
|
#endif
|
|
|
|
ExtendedEnabled = FALSE;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined (__alpha__)
|
|
|
|
|
|
|
|
#define vuip volatile unsigned int *
|
|
|
|
|
|
|
|
extern int readDense8(pointer Base, register unsigned long Offset);
|
|
|
|
extern int readDense16(pointer Base, register unsigned long Offset);
|
|
|
|
extern int readDense32(pointer Base, register unsigned long Offset);
|
|
|
|
extern void
|
|
|
|
writeDenseNB8(int Value, pointer Base, register unsigned long Offset);
|
|
|
|
extern void
|
|
|
|
writeDenseNB16(int Value, pointer Base, register unsigned long Offset);
|
|
|
|
extern void
|
|
|
|
writeDenseNB32(int Value, pointer Base, register unsigned long Offset);
|
|
|
|
extern void
|
|
|
|
writeDense8(int Value, pointer Base, register unsigned long Offset);
|
|
|
|
extern void
|
|
|
|
writeDense16(int Value, pointer Base, register unsigned long Offset);
|
|
|
|
extern void
|
|
|
|
writeDense32(int Value, pointer Base, register unsigned long Offset);
|
|
|
|
|
|
|
|
static int readSparse8(pointer Base, register unsigned long Offset);
|
|
|
|
static int readSparse16(pointer Base, register unsigned long Offset);
|
|
|
|
static int readSparse32(pointer Base, register unsigned long Offset);
|
|
|
|
static void
|
|
|
|
writeSparseNB8(int Value, pointer Base, register unsigned long Offset);
|
|
|
|
static void
|
|
|
|
writeSparseNB16(int Value, pointer Base, register unsigned long Offset);
|
|
|
|
static void
|
|
|
|
writeSparseNB32(int Value, pointer Base, register unsigned long Offset);
|
|
|
|
static void
|
|
|
|
writeSparse8(int Value, pointer Base, register unsigned long Offset);
|
|
|
|
static void
|
|
|
|
writeSparse16(int Value, pointer Base, register unsigned long Offset);
|
|
|
|
static void
|
|
|
|
writeSparse32(int Value, pointer Base, register unsigned long Offset);
|
|
|
|
|
|
|
|
#define DENSE_BASE 0x2ff00000000UL
|
|
|
|
#define SPARSE_BASE 0x30000000000UL
|
|
|
|
|
|
|
|
static unsigned long msb_set = 0;
|
|
|
|
|
|
|
|
static pointer
|
|
|
|
mapVidMemSparse(int ScreenNum, unsigned long Base, unsigned long Size, int flags)
|
|
|
|
{
|
|
|
|
int fd, prot;
|
|
|
|
unsigned long ret, rets = 0;
|
|
|
|
|
|
|
|
static Bool was_here = FALSE;
|
|
|
|
|
|
|
|
if (!was_here) {
|
|
|
|
was_here = TRUE;
|
|
|
|
|
|
|
|
xf86WriteMmio8 = writeSparse8;
|
|
|
|
xf86WriteMmio16 = writeSparse16;
|
|
|
|
xf86WriteMmio32 = writeSparse32;
|
|
|
|
xf86WriteMmioNB8 = writeSparseNB8;
|
|
|
|
xf86WriteMmioNB16 = writeSparseNB16;
|
|
|
|
xf86WriteMmioNB32 = writeSparseNB32;
|
|
|
|
xf86ReadMmio8 = readSparse8;
|
|
|
|
xf86ReadMmio16 = readSparse16;
|
|
|
|
xf86ReadMmio32 = readSparse32;
|
|
|
|
}
|
|
|
|
|
|
|
|
fd = open(DEV_MEM, (flags & VIDMEM_READONLY) ? O_RDONLY : O_RDWR);
|
|
|
|
if (fd < 0) {
|
|
|
|
FatalError("xf86MapVidMem: failed to open " DEV_MEM " (%s)\n",
|
|
|
|
strerror(errno));
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
xf86Msg(X_INFO,"mapVidMemSparse: try Base 0x%lx size 0x%lx flags 0x%x\n",
|
|
|
|
Base, Size, flags);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (flags & VIDMEM_READONLY)
|
|
|
|
prot = PROT_READ;
|
|
|
|
else
|
|
|
|
prot = PROT_READ | PROT_WRITE;
|
|
|
|
|
|
|
|
/* This requirers linux-0.99.pl10 or above */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Always do DENSE mmap, since read32/write32 currently require it.
|
|
|
|
*/
|
|
|
|
ret = (unsigned long)mmap((caddr_t)(DENSE_BASE + Base), Size,
|
|
|
|
prot, MAP_SHARED, fd,
|
|
|
|
(off_t) (bus_base + Base));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Do SPARSE mmap only when MMIO and not MMIO_32BIT, or FRAMEBUFFER
|
|
|
|
* and SPARSE (which should require the use of read/write macros).
|
|
|
|
*
|
|
|
|
* By not SPARSE mmapping an 8MB framebuffer, we can save approx. 256K
|
|
|
|
* bytes worth of pagetable (32 pages).
|
|
|
|
*/
|
|
|
|
if (((flags & VIDMEM_MMIO) && !(flags & VIDMEM_MMIO_32BIT)) ||
|
|
|
|
((flags & VIDMEM_FRAMEBUFFER) && (flags & VIDMEM_SPARSE)))
|
|
|
|
{
|
|
|
|
rets = (unsigned long)mmap((caddr_t)(SPARSE_BASE + (Base << 5)),
|
|
|
|
Size << 5, prot, MAP_SHARED, fd,
|
|
|
|
(off_t) _bus_base_sparse() + (Base << 5));
|
|
|
|
}
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
if (ret == (unsigned long)MAP_FAILED) {
|
|
|
|
FatalError("xf86MapVidMemSparse: Could not (dense) mmap fb (%s)\n",
|
|
|
|
strerror(errno));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (((flags & VIDMEM_MMIO) && !(flags & VIDMEM_MMIO_32BIT)) ||
|
|
|
|
((flags & VIDMEM_FRAMEBUFFER) && (flags & VIDMEM_SPARSE)))
|
|
|
|
{
|
|
|
|
if (rets == (unsigned long)MAP_FAILED ||
|
|
|
|
rets != (SPARSE_BASE + (Base << 5)))
|
|
|
|
{
|
|
|
|
FatalError("mapVidMemSparse: Could not (sparse) mmap fb (%s)\n",
|
|
|
|
strerror(errno));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 1
|
|
|
|
if (rets)
|
|
|
|
xf86Msg(X_INFO,"mapVidMemSparse: mapped Base 0x%lx size 0x%lx"
|
|
|
|
" to DENSE at 0x%lx and SPARSE at 0x%lx\n",
|
|
|
|
Base, Size, ret, rets);
|
|
|
|
else
|
|
|
|
xf86Msg(X_INFO,"mapVidMemSparse: mapped Base 0x%lx size 0x%lx"
|
|
|
|
" to DENSE only at 0x%lx\n",
|
|
|
|
Base, Size, ret);
|
|
|
|
|
|
|
|
#endif
|
|
|
|
return (pointer) ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
unmapVidMemSparse(int ScreenNum, pointer Base, unsigned long Size)
|
|
|
|
{
|
|
|
|
unsigned long Offset = (unsigned long)Base - DENSE_BASE;
|
|
|
|
#if 1
|
|
|
|
xf86Msg(X_INFO,"unmapVidMemSparse: unmapping Base 0x%lx Size 0x%lx\n",
|
|
|
|
Base, Size);
|
|
|
|
#endif
|
|
|
|
/* Unmap DENSE always. */
|
|
|
|
munmap((caddr_t)Base, Size);
|
|
|
|
|
|
|
|
/* Unmap SPARSE always, and ignore error in case we did not map it. */
|
|
|
|
munmap((caddr_t)(SPARSE_BASE + (Offset << 5)), Size << 5);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
readSparse8(pointer Base, register unsigned long Offset)
|
|
|
|
{
|
|
|
|
register unsigned long result, shift;
|
|
|
|
register unsigned long msb;
|
|
|
|
|
|
|
|
mem_barrier();
|
|
|
|
Offset += (unsigned long)Base - DENSE_BASE;
|
|
|
|
shift = (Offset & 0x3) << 3;
|
|
|
|
if (Offset >= (hae_thresh)) {
|
|
|
|
msb = Offset & hae_mask;
|
|
|
|
Offset -= msb;
|
|
|
|
if (msb_set != msb) {
|
|
|
|
sethae(msb);
|
|
|
|
msb_set = msb;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mem_barrier();
|
|
|
|
result = *(vuip) (SPARSE_BASE + (Offset << 5));
|
|
|
|
result >>= shift;
|
|
|
|
return 0xffUL & result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
readSparse16(pointer Base, register unsigned long Offset)
|
|
|
|
{
|
|
|
|
register unsigned long result, shift;
|
|
|
|
register unsigned long msb;
|
|
|
|
|
|
|
|
mem_barrier();
|
|
|
|
Offset += (unsigned long)Base - DENSE_BASE;
|
|
|
|
shift = (Offset & 0x2) << 3;
|
|
|
|
if (Offset >= hae_thresh) {
|
|
|
|
msb = Offset & hae_mask;
|
|
|
|
Offset -= msb;
|
|
|
|
if (msb_set != msb) {
|
|
|
|
sethae(msb);
|
|
|
|
msb_set = msb;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mem_barrier();
|
|
|
|
result = *(vuip)(SPARSE_BASE + (Offset<<5) + (1<<(5-2)));
|
|
|
|
result >>= shift;
|
|
|
|
return 0xffffUL & result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
readSparse32(pointer Base, register unsigned long Offset)
|
|
|
|
{
|
|
|
|
/* NOTE: this is really using DENSE. */
|
|
|
|
mem_barrier();
|
|
|
|
return *(vuip)((unsigned long)Base+(Offset));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
writeSparse8(int Value, pointer Base, register unsigned long Offset)
|
|
|
|
{
|
|
|
|
register unsigned long msb;
|
|
|
|
register unsigned int b = Value & 0xffU;
|
|
|
|
|
|
|
|
write_mem_barrier();
|
|
|
|
Offset += (unsigned long)Base - DENSE_BASE;
|
|
|
|
if (Offset >= hae_thresh) {
|
|
|
|
msb = Offset & hae_mask;
|
|
|
|
Offset -= msb;
|
|
|
|
if (msb_set != msb) {
|
|
|
|
sethae(msb);
|
|
|
|
msb_set = msb;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
write_mem_barrier();
|
|
|
|
*(vuip) (SPARSE_BASE + (Offset << 5)) = b * 0x01010101;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
writeSparse16(int Value, pointer Base, register unsigned long Offset)
|
|
|
|
{
|
|
|
|
register unsigned long msb;
|
|
|
|
register unsigned int w = Value & 0xffffU;
|
|
|
|
|
|
|
|
write_mem_barrier();
|
|
|
|
Offset += (unsigned long)Base - DENSE_BASE;
|
|
|
|
if (Offset >= hae_thresh) {
|
|
|
|
msb = Offset & hae_mask;
|
|
|
|
Offset -= msb;
|
|
|
|
if (msb_set != msb) {
|
|
|
|
sethae(msb);
|
|
|
|
msb_set = msb;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
write_mem_barrier();
|
|
|
|
*(vuip)(SPARSE_BASE + (Offset<<5) + (1<<(5-2))) = w * 0x00010001;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
writeSparse32(int Value, pointer Base, register unsigned long Offset)
|
|
|
|
{
|
|
|
|
/* NOTE: this is really using DENSE. */
|
|
|
|
write_mem_barrier();
|
|
|
|
*(vuip)((unsigned long)Base + (Offset)) = Value;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
writeSparseNB8(int Value, pointer Base, register unsigned long Offset)
|
|
|
|
{
|
|
|
|
register unsigned long msb;
|
|
|
|
register unsigned int b = Value & 0xffU;
|
|
|
|
|
|
|
|
Offset += (unsigned long)Base - DENSE_BASE;
|
|
|
|
if (Offset >= hae_thresh) {
|
|
|
|
msb = Offset & hae_mask;
|
|
|
|
Offset -= msb;
|
|
|
|
if (msb_set != msb) {
|
|
|
|
sethae(msb);
|
|
|
|
msb_set = msb;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*(vuip) (SPARSE_BASE + (Offset << 5)) = b * 0x01010101;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
writeSparseNB16(int Value, pointer Base, register unsigned long Offset)
|
|
|
|
{
|
|
|
|
register unsigned long msb;
|
|
|
|
register unsigned int w = Value & 0xffffU;
|
|
|
|
|
|
|
|
Offset += (unsigned long)Base - DENSE_BASE;
|
|
|
|
if (Offset >= hae_thresh) {
|
|
|
|
msb = Offset & hae_mask;
|
|
|
|
Offset -= msb;
|
|
|
|
if (msb_set != msb) {
|
|
|
|
sethae(msb);
|
|
|
|
msb_set = msb;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*(vuip)(SPARSE_BASE+(Offset<<5)+(1<<(5-2))) = w * 0x00010001;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
writeSparseNB32(int Value, pointer Base, register unsigned long Offset)
|
|
|
|
{
|
|
|
|
/* NOTE: this is really using DENSE. */
|
|
|
|
*(vuip)((unsigned long)Base + (Offset)) = Value;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-07-27 13:02:24 -06:00
|
|
|
void (*xf86WriteMmio8)(int Value, pointer Base, unsigned long Offset)
|
2006-11-26 11:13:41 -07:00
|
|
|
= writeDense8;
|
2010-07-27 13:02:24 -06:00
|
|
|
void (*xf86WriteMmio16)(int Value, pointer Base, unsigned long Offset)
|
2006-11-26 11:13:41 -07:00
|
|
|
= writeDense16;
|
2010-07-27 13:02:24 -06:00
|
|
|
void (*xf86WriteMmio32)(int Value, pointer Base, unsigned long Offset)
|
2006-11-26 11:13:41 -07:00
|
|
|
= writeDense32;
|
2010-07-27 13:02:24 -06:00
|
|
|
void (*xf86WriteMmioNB8)(int Value, pointer Base, unsigned long Offset)
|
2006-11-26 11:13:41 -07:00
|
|
|
= writeDenseNB8;
|
2010-07-27 13:02:24 -06:00
|
|
|
void (*xf86WriteMmioNB16)(int Value, pointer Base, unsigned long Offset)
|
2006-11-26 11:13:41 -07:00
|
|
|
= writeDenseNB16;
|
2010-07-27 13:02:24 -06:00
|
|
|
void (*xf86WriteMmioNB32)(int Value, pointer Base, unsigned long Offset)
|
2006-11-26 11:13:41 -07:00
|
|
|
= writeDenseNB32;
|
2010-07-27 13:02:24 -06:00
|
|
|
int (*xf86ReadMmio8)(pointer Base, unsigned long Offset)
|
2006-11-26 11:13:41 -07:00
|
|
|
= readDense8;
|
2010-07-27 13:02:24 -06:00
|
|
|
int (*xf86ReadMmio16)(pointer Base, unsigned long Offset)
|
2006-11-26 11:13:41 -07:00
|
|
|
= readDense16;
|
2010-07-27 13:02:24 -06:00
|
|
|
int (*xf86ReadMmio32)(pointer Base, unsigned long Offset)
|
2006-11-26 11:13:41 -07:00
|
|
|
= readDense32;
|
|
|
|
|
|
|
|
#endif /* __alpha__ */
|