xfree86: Remove {set,undo}WC from VidMemInfo
Now that mapMem is gone this can never actually get called. Reviewed-by: Eric Anholt <eric@anholt.net> Signed-off-by: Adam Jackson <ajax@redhat.com>
This commit is contained in:
parent
9db2af6f75
commit
ec0e29ed5b
|
@ -86,15 +86,8 @@ static int devMemFd = -1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAS_MTRR_SUPPORT
|
#ifdef HAS_MTRR_SUPPORT
|
||||||
static void *setWC(int, unsigned long, unsigned long, Bool, MessageType);
|
|
||||||
static void undoWC(int, void *);
|
|
||||||
static Bool cleanMTRR(void);
|
static Bool cleanMTRR(void);
|
||||||
#endif
|
#endif
|
||||||
#if defined(HAS_MTRR_BUILTIN) && defined(__NetBSD__)
|
|
||||||
static void *NetBSDsetWC(int, unsigned long, unsigned long, Bool,
|
|
||||||
MessageType);
|
|
||||||
static void NetBSDundoWC(int, void *);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if /dev/mem can be mmap'd. If it can't print a warning when
|
* Check if /dev/mem can be mmap'd. If it can't print a warning when
|
||||||
|
@ -192,15 +185,8 @@ xf86OSInitVidMem(VidMemInfoPtr pVidMem)
|
||||||
|
|
||||||
#ifdef HAS_MTRR_SUPPORT
|
#ifdef HAS_MTRR_SUPPORT
|
||||||
if (useDevMem) {
|
if (useDevMem) {
|
||||||
if (cleanMTRR()) {
|
cleanMTRR();
|
||||||
pVidMem->setWC = setWC;
|
|
||||||
pVidMem->undoWC = undoWC;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
#if defined(HAS_MTRR_BUILTIN) && defined(__NetBSD__)
|
|
||||||
pVidMem->setWC = NetBSDsetWC;
|
|
||||||
pVidMem->undoWC = NetBSDundoWC;
|
|
||||||
#endif
|
#endif
|
||||||
pVidMem->initialised = TRUE;
|
pVidMem->initialised = TRUE;
|
||||||
}
|
}
|
||||||
|
@ -503,334 +489,4 @@ cleanMTRR()
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct x_RangeRec {
|
|
||||||
struct mem_range_desc mrd;
|
|
||||||
Bool wasWC;
|
|
||||||
struct x_RangeRec *next;
|
|
||||||
} RangeRec, *RangePtr;
|
|
||||||
|
|
||||||
static void
|
|
||||||
freeRangeList(RangePtr range)
|
|
||||||
{
|
|
||||||
RangePtr rp;
|
|
||||||
|
|
||||||
while (range) {
|
|
||||||
rp = range;
|
|
||||||
range = rp->next;
|
|
||||||
free(rp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static RangePtr
|
|
||||||
dupRangeList(RangePtr list)
|
|
||||||
{
|
|
||||||
RangePtr new = NULL, rp, p;
|
|
||||||
|
|
||||||
rp = list;
|
|
||||||
while (rp) {
|
|
||||||
p = xnfalloc(sizeof(RangeRec));
|
|
||||||
*p = *rp;
|
|
||||||
p->next = new;
|
|
||||||
new = p;
|
|
||||||
rp = rp->next;
|
|
||||||
}
|
|
||||||
return new;
|
|
||||||
}
|
|
||||||
|
|
||||||
static RangePtr
|
|
||||||
sortRangeList(RangePtr list)
|
|
||||||
{
|
|
||||||
RangePtr rp1, rp2, copy, sorted = NULL, minp, prev, minprev;
|
|
||||||
unsigned long minBase;
|
|
||||||
|
|
||||||
/* Sort by base address */
|
|
||||||
rp1 = copy = dupRangeList(list);
|
|
||||||
while (rp1) {
|
|
||||||
minBase = rp1->mrd.mr_base;
|
|
||||||
minp = rp1;
|
|
||||||
minprev = NULL;
|
|
||||||
prev = rp1;
|
|
||||||
rp2 = rp1->next;
|
|
||||||
while (rp2) {
|
|
||||||
if (rp2->mrd.mr_base < minBase) {
|
|
||||||
minBase = rp2->mrd.mr_base;
|
|
||||||
minp = rp2;
|
|
||||||
minprev = prev;
|
|
||||||
}
|
|
||||||
prev = rp2;
|
|
||||||
rp2 = rp2->next;
|
|
||||||
}
|
|
||||||
if (minprev) {
|
|
||||||
minprev->next = minp->next;
|
|
||||||
rp1 = copy;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
rp1 = minp->next;
|
|
||||||
}
|
|
||||||
minp->next = sorted;
|
|
||||||
sorted = minp;
|
|
||||||
}
|
|
||||||
return sorted;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* findRanges returns a list of ranges that overlap the specified range.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
findRanges(unsigned long base, unsigned long size, RangePtr * ucp,
|
|
||||||
RangePtr * wcp)
|
|
||||||
{
|
|
||||||
struct mem_range_desc *mrd;
|
|
||||||
int nmr, i;
|
|
||||||
RangePtr rp, *p;
|
|
||||||
|
|
||||||
if (!(mrd = getAllRanges(&nmr)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (i = 0; i < nmr; i++) {
|
|
||||||
if ((mrd[i].mr_flags & MDF_ACTIVE) &&
|
|
||||||
mrd[i].mr_base < base + size &&
|
|
||||||
mrd[i].mr_base + mrd[i].mr_len > base) {
|
|
||||||
if (mrd[i].mr_flags & MDF_WRITECOMBINE)
|
|
||||||
p = wcp;
|
|
||||||
else if (mrd[i].mr_flags & MDF_UNCACHEABLE)
|
|
||||||
p = ucp;
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
rp = xnfalloc(sizeof(RangeRec));
|
|
||||||
rp->mrd = mrd[i];
|
|
||||||
rp->next = *p;
|
|
||||||
*p = rp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(mrd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This checks if the existing overlapping ranges fully cover the requested
|
|
||||||
* range. Is this overkill?
|
|
||||||
*/
|
|
||||||
|
|
||||||
static Bool
|
|
||||||
fullCoverage(unsigned long base, unsigned long size, RangePtr overlap)
|
|
||||||
{
|
|
||||||
RangePtr rp1, sorted = NULL;
|
|
||||||
unsigned long end;
|
|
||||||
|
|
||||||
sorted = sortRangeList(overlap);
|
|
||||||
/* Look for gaps */
|
|
||||||
rp1 = sorted;
|
|
||||||
end = base + size;
|
|
||||||
while (rp1) {
|
|
||||||
if (rp1->mrd.mr_base > base) {
|
|
||||||
freeRangeList(sorted);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
base = rp1->mrd.mr_base + rp1->mrd.mr_len;
|
|
||||||
}
|
|
||||||
if (base >= end) {
|
|
||||||
freeRangeList(sorted);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
rp1 = rp1->next;
|
|
||||||
}
|
|
||||||
freeRangeList(sorted);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *
|
|
||||||
addWC(int screenNum, unsigned long base, unsigned long size, MessageType from)
|
|
||||||
{
|
|
||||||
RangePtr uc = NULL, wc = NULL, retlist = NULL;
|
|
||||||
struct mem_range_desc mrd;
|
|
||||||
struct mem_range_op mro;
|
|
||||||
|
|
||||||
findRanges(base, size, &uc, &wc);
|
|
||||||
|
|
||||||
/* See of the full range is already WC */
|
|
||||||
if (!uc && fullCoverage(base, size, wc)) {
|
|
||||||
xf86DrvMsg(screenNum, from,
|
|
||||||
"Write-combining range (0x%lx,0x%lx) was already set\n",
|
|
||||||
base, size);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Otherwise, try to add the new range */
|
|
||||||
mrd.mr_base = base;
|
|
||||||
mrd.mr_len = size;
|
|
||||||
strcpy(mrd.mr_owner, X_MTRR_ID);
|
|
||||||
mrd.mr_flags = MDF_WRITECOMBINE;
|
|
||||||
mro.mo_desc = &mrd;
|
|
||||||
mro.mo_arg[0] = MEMRANGE_SET_UPDATE;
|
|
||||||
if (ioctl(devMemFd, MEMRANGE_SET, &mro)) {
|
|
||||||
xf86DrvMsg(screenNum, X_WARNING,
|
|
||||||
"Failed to set write-combining range "
|
|
||||||
"(0x%lx,0x%lx)\n", base, size);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
xf86DrvMsg(screenNum, from,
|
|
||||||
"Write-combining range (0x%lx,0x%lx)\n", base, size);
|
|
||||||
retlist = xnfalloc(sizeof(RangeRec));
|
|
||||||
retlist->mrd = mrd;
|
|
||||||
retlist->wasWC = FALSE;
|
|
||||||
retlist->next = NULL;
|
|
||||||
return retlist;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *
|
|
||||||
delWC(int screenNum, unsigned long base, unsigned long size, MessageType from)
|
|
||||||
{
|
|
||||||
RangePtr uc = NULL, wc = NULL, retlist = NULL;
|
|
||||||
struct mem_range_desc mrd;
|
|
||||||
struct mem_range_op mro;
|
|
||||||
|
|
||||||
findRanges(base, size, &uc, &wc);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* See of the full range is already not WC, or if there is full
|
|
||||||
* coverage from UC ranges.
|
|
||||||
*/
|
|
||||||
if (!wc || fullCoverage(base, size, uc)) {
|
|
||||||
xf86DrvMsg(screenNum, from,
|
|
||||||
"Write-combining range (0x%lx,0x%lx) was already clear\n",
|
|
||||||
base, size);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Otherwise, try to add the new range */
|
|
||||||
mrd.mr_base = base;
|
|
||||||
mrd.mr_len = size;
|
|
||||||
strcpy(mrd.mr_owner, X_MTRR_ID);
|
|
||||||
mrd.mr_flags = MDF_UNCACHEABLE;
|
|
||||||
mro.mo_desc = &mrd;
|
|
||||||
mro.mo_arg[0] = MEMRANGE_SET_UPDATE;
|
|
||||||
if (ioctl(devMemFd, MEMRANGE_SET, &mro)) {
|
|
||||||
xf86DrvMsg(screenNum, X_WARNING,
|
|
||||||
"Failed to remove write-combining range "
|
|
||||||
"(0x%lx,0x%lx)\n", base, size);
|
|
||||||
/* XXX Should then remove all of the overlapping WC ranges */
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
xf86DrvMsg(screenNum, from,
|
|
||||||
"Removed Write-combining range (0x%lx,0x%lx)\n", base, size);
|
|
||||||
retlist = xnfalloc(sizeof(RangeRec));
|
|
||||||
retlist->mrd = mrd;
|
|
||||||
retlist->wasWC = TRUE;
|
|
||||||
retlist->next = NULL;
|
|
||||||
return retlist;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *
|
|
||||||
setWC(int screenNum, unsigned long base, unsigned long size, Bool enable,
|
|
||||||
MessageType from)
|
|
||||||
{
|
|
||||||
if (enable)
|
|
||||||
return addWC(screenNum, base, size, from);
|
|
||||||
else
|
|
||||||
return delWC(screenNum, base, size, from);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
undoWC(int screenNum, void *list)
|
|
||||||
{
|
|
||||||
RangePtr rp;
|
|
||||||
struct mem_range_op mro;
|
|
||||||
Bool failed;
|
|
||||||
|
|
||||||
rp = list;
|
|
||||||
while (rp) {
|
|
||||||
#ifdef DEBUG
|
|
||||||
ErrorF("Undo for (0x%lx,0x%lx), %d\n",
|
|
||||||
(unsigned long) rp->mrd.mr_base,
|
|
||||||
(unsigned long) rp->mrd.mr_len, rp->wasWC);
|
|
||||||
#endif
|
|
||||||
failed = FALSE;
|
|
||||||
if (rp->wasWC) {
|
|
||||||
mro.mo_arg[0] = MEMRANGE_SET_UPDATE;
|
|
||||||
rp->mrd.mr_flags = MDF_WRITECOMBINE;
|
|
||||||
strcpy(rp->mrd.mr_owner, "unknown");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mro.mo_arg[0] = MEMRANGE_SET_REMOVE;
|
|
||||||
}
|
|
||||||
mro.mo_desc = &rp->mrd;
|
|
||||||
|
|
||||||
if (ioctl(devMemFd, MEMRANGE_SET, &mro)) {
|
|
||||||
if (!rp->wasWC) {
|
|
||||||
mro.mo_arg[0] = MEMRANGE_SET_UPDATE;
|
|
||||||
rp->mrd.mr_flags = MDF_UNCACHEABLE;
|
|
||||||
strcpy(rp->mrd.mr_owner, "unknown");
|
|
||||||
if (ioctl(devMemFd, MEMRANGE_SET, &mro))
|
|
||||||
failed = TRUE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
failed = TRUE;
|
|
||||||
}
|
|
||||||
if (failed) {
|
|
||||||
xf86DrvMsg(screenNum, X_WARNING,
|
|
||||||
"Failed to restore MTRR range (0x%lx,0x%lx)\n",
|
|
||||||
(unsigned long) rp->mrd.mr_base,
|
|
||||||
(unsigned long) rp->mrd.mr_len);
|
|
||||||
}
|
|
||||||
rp = rp->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* HAS_MTRR_SUPPORT */
|
#endif /* HAS_MTRR_SUPPORT */
|
||||||
|
|
||||||
#if defined(HAS_MTRR_BUILTIN) && defined(__NetBSD__)
|
|
||||||
static void *
|
|
||||||
NetBSDsetWC(int screenNum, unsigned long base, unsigned long size, Bool enable,
|
|
||||||
MessageType from)
|
|
||||||
{
|
|
||||||
struct mtrr *mtrrp;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
xf86DrvMsg(screenNum, X_WARNING,
|
|
||||||
"%s MTRR %lx - %lx\n", enable ? "set" : "remove",
|
|
||||||
base, (base + size));
|
|
||||||
|
|
||||||
mtrrp = xnfalloc(sizeof(struct mtrr));
|
|
||||||
mtrrp->base = base;
|
|
||||||
mtrrp->len = size;
|
|
||||||
mtrrp->type = MTRR_TYPE_WC;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* MTRR_PRIVATE will make this MTRR get reset automatically
|
|
||||||
* if this process exits, so we have no need for an explicit
|
|
||||||
* cleanup operation when starting a new server.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (enable)
|
|
||||||
mtrrp->flags = MTRR_VALID | MTRR_PRIVATE;
|
|
||||||
else
|
|
||||||
mtrrp->flags = 0;
|
|
||||||
n = 1;
|
|
||||||
|
|
||||||
if (i386_set_mtrr(mtrrp, &n) < 0) {
|
|
||||||
free(mtrrp);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return mtrrp;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
NetBSDundoWC(int screenNum, void *list)
|
|
||||||
{
|
|
||||||
struct mtrr *mtrrp = (struct mtrr *) list;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
if (mtrrp == NULL)
|
|
||||||
return;
|
|
||||||
n = 1;
|
|
||||||
mtrrp->flags &= ~MTRR_VALID;
|
|
||||||
i386_set_mtrr(mtrrp, &n);
|
|
||||||
free(mtrrp);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -42,10 +42,6 @@
|
||||||
#include "shared/xf86Axp.h"
|
#include "shared/xf86Axp.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAS_MTRR_SUPPORT
|
|
||||||
#include <asm/mtrr.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static Bool ExtendedEnabled = FALSE;
|
static Bool ExtendedEnabled = FALSE;
|
||||||
|
|
||||||
#ifdef __ia64__
|
#ifdef __ia64__
|
||||||
|
@ -95,265 +91,6 @@ static unsigned long hae_mask;
|
||||||
static unsigned long bus_base;
|
static unsigned long bus_base;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAS_MTRR_SUPPORT
|
|
||||||
|
|
||||||
#define SPLIT_WC_REGIONS 1
|
|
||||||
|
|
||||||
static void *setWC(int, unsigned long, unsigned long, Bool, MessageType);
|
|
||||||
static void undoWC(int, void *);
|
|
||||||
|
|
||||||
/* 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) {
|
|
||||||
mtrr_fd = open("/proc/mtrr", O_WRONLY);
|
|
||||||
|
|
||||||
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. */
|
|
||||||
|
|
||||||
wcr = malloc(sizeof(*wcr));
|
|
||||||
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 {
|
|
||||||
free(wcr);
|
|
||||||
xf86DrvMsgVerb(screenNum, X_WARNING, 0,
|
|
||||||
"Failed to remove MMIO "
|
|
||||||
"write-combining range (0x%lx,0x%lx)\n",
|
|
||||||
(unsigned long)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;
|
|
||||||
|
|
||||||
*wcr = curwcr = malloc(sizeof(**wcr));
|
|
||||||
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;
|
|
||||||
DebugF("WC_BASE: 0x%lx WC_END: 0x%lx\n", base, base + d_size - 1);
|
|
||||||
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;
|
|
||||||
free(curwcr);
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
|
|
||||||
if (mtrr_fd >= 0) {
|
|
||||||
p = wcr;
|
|
||||||
while (p) {
|
|
||||||
if (p->added)
|
|
||||||
ioctl(mtrr_fd, MTRRIOC_DEL_ENTRY, &p->sentry);
|
|
||||||
prev = p;
|
|
||||||
p = p->next;
|
|
||||||
free(prev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *
|
|
||||||
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, void *regioninfo)
|
|
||||||
{
|
|
||||||
mtrr_undo_wc_region(screenNum, regioninfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* HAS_MTRR_SUPPORT */
|
|
||||||
|
|
||||||
void
|
void
|
||||||
xf86OSInitVidMem(VidMemInfoPtr pVidMem)
|
xf86OSInitVidMem(VidMemInfoPtr pVidMem)
|
||||||
{
|
{
|
||||||
|
@ -375,10 +112,6 @@ xf86OSInitVidMem(VidMemInfoPtr pVidMem)
|
||||||
}
|
}
|
||||||
#endif /* __alpha__ */
|
#endif /* __alpha__ */
|
||||||
|
|
||||||
#ifdef HAS_MTRR_SUPPORT
|
|
||||||
pVidMem->setWC = setWC;
|
|
||||||
pVidMem->undoWC = undoWC;
|
|
||||||
#endif
|
|
||||||
pVidMem->initialised = TRUE;
|
pVidMem->initialised = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -129,7 +129,7 @@ xf86CheckMTRR(int ScreenNum)
|
||||||
*/
|
*/
|
||||||
checkMtrrOption(vp);
|
checkMtrrOption(vp);
|
||||||
|
|
||||||
if (vp->mtrrEnabled && vidMemInfo.setWC)
|
if (vp->mtrrEnabled)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
|
@ -32,14 +32,8 @@
|
||||||
#ifndef _XF86OSPRIV_H
|
#ifndef _XF86OSPRIV_H
|
||||||
#define _XF86OSPRIV_H
|
#define _XF86OSPRIV_H
|
||||||
|
|
||||||
typedef void *(*SetWCProcPtr) (int, unsigned long, unsigned long, Bool,
|
|
||||||
MessageType);
|
|
||||||
typedef void (*UndoWCProcPtr) (int, void *);
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Bool initialised;
|
Bool initialised;
|
||||||
SetWCProcPtr setWC;
|
|
||||||
UndoWCProcPtr undoWC;
|
|
||||||
Bool linearSupported;
|
Bool linearSupported;
|
||||||
} VidMemInfo, *VidMemInfoPtr;
|
} VidMemInfo, *VidMemInfoPtr;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user