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:
Adam Jackson 2014-05-02 12:32:02 -04:00
parent 9db2af6f75
commit ec0e29ed5b
4 changed files with 2 additions and 619 deletions

View File

@ -86,15 +86,8 @@ static int devMemFd = -1;
#endif
#ifdef HAS_MTRR_SUPPORT
static void *setWC(int, unsigned long, unsigned long, Bool, MessageType);
static void undoWC(int, void *);
static Bool cleanMTRR(void);
#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
@ -192,15 +185,8 @@ xf86OSInitVidMem(VidMemInfoPtr pVidMem)
#ifdef HAS_MTRR_SUPPORT
if (useDevMem) {
if (cleanMTRR()) {
pVidMem->setWC = setWC;
pVidMem->undoWC = undoWC;
}
cleanMTRR();
}
#endif
#if defined(HAS_MTRR_BUILTIN) && defined(__NetBSD__)
pVidMem->setWC = NetBSDsetWC;
pVidMem->undoWC = NetBSDundoWC;
#endif
pVidMem->initialised = TRUE;
}
@ -503,334 +489,4 @@ cleanMTRR()
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 */
#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

View File

@ -42,10 +42,6 @@
#include "shared/xf86Axp.h"
#endif
#ifdef HAS_MTRR_SUPPORT
#include <asm/mtrr.h>
#endif
static Bool ExtendedEnabled = FALSE;
#ifdef __ia64__
@ -95,265 +91,6 @@ static unsigned long hae_mask;
static unsigned long bus_base;
#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
xf86OSInitVidMem(VidMemInfoPtr pVidMem)
{
@ -375,10 +112,6 @@ xf86OSInitVidMem(VidMemInfoPtr pVidMem)
}
#endif /* __alpha__ */
#ifdef HAS_MTRR_SUPPORT
pVidMem->setWC = setWC;
pVidMem->undoWC = undoWC;
#endif
pVidMem->initialised = TRUE;
}

View File

@ -129,7 +129,7 @@ xf86CheckMTRR(int ScreenNum)
*/
checkMtrrOption(vp);
if (vp->mtrrEnabled && vidMemInfo.setWC)
if (vp->mtrrEnabled)
return TRUE;
return FALSE;

View File

@ -32,14 +32,8 @@
#ifndef _XF86OSPRIV_H
#define _XF86OSPRIV_H
typedef void *(*SetWCProcPtr) (int, unsigned long, unsigned long, Bool,
MessageType);
typedef void (*UndoWCProcPtr) (int, void *);
typedef struct {
Bool initialised;
SetWCProcPtr setWC;
UndoWCProcPtr undoWC;
Bool linearSupported;
} VidMemInfo, *VidMemInfoPtr;