summaryrefslogtreecommitdiff
path: root/hw/xfree86/os-support/lynxos
diff options
context:
space:
mode:
authorKaleb Keithley <kaleb@freedesktop.org>2003-11-14 16:49:22 +0000
committerKaleb Keithley <kaleb@freedesktop.org>2003-11-14 16:49:22 +0000
commitd568221710959cf7d783e6ff0fb80fb43a231124 (patch)
tree8d6f039393294c6ffac8533639afdebe5d68bfc1 /hw/xfree86/os-support/lynxos
parent9508a382f8a9f241dab097d921b6d290c1c3a776 (diff)
Diffstat (limited to 'hw/xfree86/os-support/lynxos')
-rw-r--r--hw/xfree86/os-support/lynxos/lynx_init.c45
-rw-r--r--hw/xfree86/os-support/lynxos/lynx_io.c78
-rw-r--r--hw/xfree86/os-support/lynxos/lynx_mmap.c25
-rw-r--r--hw/xfree86/os-support/lynxos/lynx_video.c597
4 files changed, 634 insertions, 111 deletions
diff --git a/hw/xfree86/os-support/lynxos/lynx_init.c b/hw/xfree86/os-support/lynxos/lynx_init.c
index 6c0e00aa3..8565dcc5c 100644
--- a/hw/xfree86/os-support/lynxos/lynx_init.c
+++ b/hw/xfree86/os-support/lynxos/lynx_init.c
@@ -22,36 +22,33 @@
*/
-/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/lynxos/lynx_init.c,v 3.1.6.1 1998/02/06 22:36:51 hohndel Exp $ */
+/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/lynxos/lynx_init.c,v 3.3 1998/08/29 05:43:58 dawes Exp $ */
#include "X.h"
#include "Xmd.h"
-#include "input.h"
-#include "scrnintstr.h"
#include "compiler.h"
#include "xf86.h"
-#include "xf86Procs.h"
+#include "xf86Priv.h"
#include "xf86_OSlib.h"
static int VTnum = -1;
-void xf86OpenConsole()
+void
+xf86OpenConsole()
{
struct vt_mode VT;
char vtname1[11];
- int i, fd, pgrp;
+ int fd, pgrp;
+ MessageType from = X_PROBED;
if (serverGeneration == 1)
{
/* check if we're run with euid==0 */
if (geteuid() != 0)
{
- FatalError("xf86OpenConsole: Server must be running with root "
- "permissions\n"
- "You should be using Xwrapper to start the server or xdm.\n"
- "We strongly advise against making the server SUID root!\n");
+ FatalError("xf86OpenConsole: Server must be suid root\n");
}
/*
@@ -67,6 +64,7 @@ void xf86OpenConsole()
if (VTnum != -1)
{
xf86Info.vtno = VTnum;
+ from = X_CMDLINE;
}
else
{
@@ -88,7 +86,7 @@ void xf86OpenConsole()
}
close(fd);
}
- ErrorF("(using VT number %d)\n\n", xf86Info.vtno);
+ xf86Msg(from, "using VT number %d\n", xf86Info.vtno);
sprintf(vtname1,"/dev/atc%d",xf86Info.vtno);
@@ -104,19 +102,12 @@ void xf86OpenConsole()
/* change ownership of the vt */
chown(vtname1, getuid(), getgid());
- /* Reading Config after opening the VT get's rid of */
- /* problems with LynxOS VT handling (i.e. VT_OPENQUERY */
- /* without open() leaves the vtxx busy until next */
- /* open/close) */
-
- xf86Config(FALSE); /* Read XF86Config */
-
/*
* now get the VT
*/
if (ioctl(xf86Info.consoleFd, VT_ACTIVATE, xf86Info.vtno) != 0)
{
- ErrorF("xf86OpenConsole: VT_ACTIVATE failed\n");
+ xf86Msg(X_WARNING, "xf86OpenConsole: VT_ACTIVATE failed\n");
}
if (ioctl(xf86Info.consoleFd, VT_GETMODE, &VT) < 0)
{
@@ -142,20 +133,21 @@ void xf86OpenConsole()
*/
if (ioctl(xf86Info.consoleFd, VT_ACTIVATE, xf86Info.vtno) != 0)
{
- ErrorF("xf86OpenConsole: VT_ACTIVATE failed\n");
+ xf86Msg(X_WARNING, "xf86OpenConsole: VT_ACTIVATE failed\n");
}
/*
* If the server doesn't have the VT when the reset occurs,
* this is to make sure we don't continue until the activate
* signal is received.
*/
- if (!xf86VTSema)
+ if (!xf86Screens[0]->vtSema)
sleep(5);
}
return;
}
-void xf86CloseConsole()
+void
+xf86CloseConsole()
{
struct vt_mode VT;
@@ -172,10 +164,8 @@ void xf86CloseConsole()
return;
}
-int xf86ProcessArgument (argc, argv, i)
-int argc;
-char *argv[];
-int i;
+int
+xf86ProcessArgument(int argc, char *argv[], int i)
{
if ((argv[i][0] == 'v') && (argv[i][1] == 't'))
{
@@ -190,7 +180,8 @@ int i;
return(0);
}
-void xf86UseMsg()
+void
+xf86UseMsg()
{
ErrorF("vtXX use the specified VT number\n");
return;
diff --git a/hw/xfree86/os-support/lynxos/lynx_io.c b/hw/xfree86/os-support/lynxos/lynx_io.c
index e0134609e..e61ce76b7 100644
--- a/hw/xfree86/os-support/lynxos/lynx_io.c
+++ b/hw/xfree86/os-support/lynxos/lynx_io.c
@@ -21,25 +21,20 @@
*
*/
-/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/lynxos/lynx_io.c,v 3.3 1996/08/10 13:07:36 dawes Exp $ */
+/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/lynxos/lynx_io.c,v 3.10 2003/02/17 15:11:57 dawes Exp $ */
-#define NEED_EVENTS
#include "X.h"
-#include "Xproto.h"
-#include "inputstr.h"
-#include "scrnintstr.h"
#include "compiler.h"
-#include "xf86Procs.h"
+#include "xf86.h"
+#include "xf86Priv.h"
#include "xf86_OSlib.h"
#if defined(KDMKTONE) || defined(KIOCSOUND)
/* Lynx 2.2.1 has sophisticated atc stuff.... */
-void xf86SoundKbdBell(loudness, pitch, duration)
-int loudness;
-int pitch;
-int duration;
+void
+xf86SoundKbdBell(int loudness, int pitch, int duration)
{
if (loudness && pitch)
{
@@ -73,10 +68,8 @@ int duration;
#define FREQ_LO(f) ((TIMER_CONSTANT / (f)) % 256)
#define FREQ_HI(f) ((TIMER_CONSTANT / (f)) / 256)
-void xf86SoundKbdBell(loudness, pitch, duration)
-int loudness;
-int pitch;
-int duration;
+void
+xf86SoundKbdBell(int loudness, int pitch, int duration)
{
int flo = FREQ_LO(pitch);
int fhi = FREQ_HI(pitch);
@@ -93,28 +86,43 @@ int duration;
}
#endif
-void xf86SetKbdLeds(leds)
-int leds;
+void
+xf86SetKbdLeds(int leds)
{
+#ifdef KBD_SET_LEDS
+ ioctl(xf86Info.consoleFd, KBD_SET_LEDS, &leds);
+#endif
}
-int xf86GetKbdLeds()
+int
+xf86GetKbdLeds()
{
+#ifdef KBD_SET_LEDS
+ int leds;
+
+ if (ioctl(xf86Info.consoleFd, KBD_SET_LEDS, &leds) < 0)
+ return 0;
+
+ return leds;
+#endif
return 0;
}
-void xf86SetKbdRepeat(char rad)
+void
+xf86SetKbdRepeat(char rad)
{
}
static struct termio kbdtty;
-void xf86KbdInit()
+void
+xf86KbdInit()
{
ioctl(xf86Info.consoleFd, TCGETA, &kbdtty);
}
-int xf86KbdOn()
+int
+xf86KbdOn()
{
struct termio nTty;
@@ -136,7 +144,8 @@ int xf86KbdOn()
return(xf86Info.consoleFd);
}
-int xf86KbdOff()
+int
+xf86KbdOff()
{
/* disable scan mode */
ioctl(xf86Info.consoleFd, TIO_DISSCANMODE, NULL);
@@ -144,29 +153,10 @@ int xf86KbdOff()
return(xf86Info.consoleFd);
}
-void xf86MouseInit(mouse)
-MouseDevPtr mouse;
-{
- return;
-}
+#include "xf86OSKbd.h"
-int xf86MouseOn(mouse)
-MouseDevPtr mouse;
+Bool
+xf86OSKbdPreInit(InputInfoPtr pInfo)
{
- if ((mouse->mseFd = open(mouse->mseDevice, O_RDWR | O_NDELAY)) < 0)
- {
- if (xf86AllowMouseOpenFail) {
- ErrorF("Cannot open mouse (%s) - Continuing...\n",
- strerror(errno));
- return(-2);
- }
- FatalError("Cannot open mouse (%s)\n", strerror(errno));
- }
-
- /* assert DTR */
- ioctl(mouse->mseFd, TIOCSDTR, NULL);
-
- xf86SetupMouse(mouse);
-
- return(mouse->mseFd);
+ return FALSE;
}
diff --git a/hw/xfree86/os-support/lynxos/lynx_mmap.c b/hw/xfree86/os-support/lynxos/lynx_mmap.c
index 621f42c5d..dcf734965 100644
--- a/hw/xfree86/os-support/lynxos/lynx_mmap.c
+++ b/hw/xfree86/os-support/lynxos/lynx_mmap.c
@@ -21,11 +21,9 @@
*
*/
-/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/lynxos/lynx_mmap.c,v 3.2 1996/09/29 13:38:29 dawes Exp $ */
+/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/lynxos/lynx_mmap.c,v 3.6 2000/02/11 22:36:02 dawes Exp $ */
#include "X.h"
-#include "input.h"
-#include "scrnintstr.h"
#include "xf86.h"
#include "xf86Priv.h"
@@ -35,26 +33,30 @@
* Read BIOS using smem_create facility
*/
-int xf86ReadBIOS(Base, Offset, Buf, Len)
-unsigned long Base;
-unsigned long Offset;
-unsigned char *Buf;
-int Len;
+int
+xf86ReadBIOS(unsigned long Base, unsigned long Offset, unsigned char *Buf,
+ int Len)
{
+#if defined(__powerpc__)
+ xf86Msg(X_WARNING, "xf86ReadBios: no BIOS-probe on PowerPC\n");
+ return(-1);
+#else
char *p;
int mlen;
- mlen = (Offset + Len + 4095) & ~4096;
+ mlen = (Offset + Len + 4095) & ~4095;
p = smem_create("BIOS-probe", (char *)Base, mlen, SM_READ);
if (p == NULL)
{
/* check if there is a stale segment around */
if (smem_remove("BIOS-probe") == 0) {
- ErrorF("xf86ReadBios: removed stale smem_ segment\n");
+ xf86Msg(X_INFO,
+ "xf86ReadBios: removed stale smem_ segment\n");
p = smem_create("BIOS-probe", (char *)Base, mlen, SM_READ);
}
if (p == NULL) {
- ErrorF("xf86ReadBios: Failed to smem_create Base %x len %x %s \n",
+ xf86Msg(X_WARNING, "xf86ReadBios: Failed to smem_create "
+ "Base %x len %x %s \n",
Base, mlen, strerror(errno));
return(-1);
}
@@ -63,4 +65,5 @@ int Len;
smem_create(NULL, p, 0, SM_DETACH);
smem_remove("BIOS-probe");
return(Len);
+#endif
}
diff --git a/hw/xfree86/os-support/lynxos/lynx_video.c b/hw/xfree86/os-support/lynxos/lynx_video.c
index 94b2f0ecd..c667994b3 100644
--- a/hw/xfree86/os-support/lynxos/lynx_video.c
+++ b/hw/xfree86/os-support/lynxos/lynx_video.c
@@ -21,7 +21,7 @@
*
*/
-/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/lynxos/lynx_video.c,v 3.2.4.1 1997/05/09 07:15:24 hohndel Exp $ */
+/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/lynxos/lynx_video.c,v 3.18 2002/12/14 04:41:14 dawes Exp $ */
#include "X.h"
#include "input.h"
@@ -30,6 +30,81 @@
#include "xf86.h"
#include "xf86Priv.h"
#include "xf86_OSlib.h"
+#include "xf86OSpriv.h"
+
+#if defined(__powerpc__)
+
+# if defined(USE_MACHINE_ABSOLUTE)
+# include <machine/absolute.h>
+# else
+# define __USER_SPACE_INCLUDE
+# include <hw_absolute.h>
+# endif
+
+void ppcPciIoMap(int bus);
+#endif
+
+#if 0
+#define DEBUG
+#endif
+
+#ifdef HAS_MTRR_SUPPORT
+#include <sys/memrange.h>
+#define X_MTRR_ID "XFree86"
+
+static pointer setWC(int, unsigned long, unsigned long, Bool, MessageType);
+static void undoWC(int, pointer);
+static Bool cleanMTRR(void);
+static int devMemFd = -1;
+#define MTRR_DEVICE "/dev/mtrr"
+#endif
+
+
+#if !defined(NO_MMAP)
+#include <sys/mman.h>
+
+int smem_remove(char *name)
+{
+ return(0);
+}
+
+char *smem_create(char *name, char *arg_addr, long size, int mode)
+{
+ int fd;
+ void *addr = 0;
+ char *retval;
+ size_t len = size;
+ int prot = PROT_READ|PROT_WRITE|PROT_UNCACHE;
+ int flags = MAP_SHARED;
+ off_t off = (off_t)arg_addr;
+
+ if ((fd = open("/dev/mem" , O_RDWR)) < 0)
+ {
+ retval = (char *)-1;
+ }
+ else
+ {
+ if (mode == SM_DETACH)
+ {
+ munmap(arg_addr, len);
+ retval = 0;
+ }
+ else
+ {
+ if ((retval = mmap (addr, len, prot, flags, fd, off) ) == MAP_FAILED)
+ {
+ retval = (char *)-1;
+ }
+ }
+
+ close(fd);
+ }
+
+ return(retval);
+}
+
+#endif
+
/***************************************************************************/
/* Video Memory Mapping section */
@@ -38,19 +113,24 @@
typedef struct
{
char name[16];
- pointer Base;
- long Size;
+ unsigned long Base;
+ unsigned long Size;
char *ptr;
int RefCnt;
}
_SMEMS;
-#define MAX_SMEMS 8
+#define MAX_SMEMS 16
static _SMEMS smems[MAX_SMEMS];
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)-1)
+#endif
+
static void
-smemCleanup()
+smemCleanup(void)
{
int i;
@@ -60,18 +140,15 @@ smemCleanup()
(void)smem_remove(smems[i].name);
*smems[i].name = '\0';
smems[i].ptr = NULL;
- smems[i].Base = NULL;
+ smems[i].Base = 0;
smems[i].Size = 0;
smems[i].RefCnt = 0;
}
}
}
-pointer xf86MapVidMem(ScreenNum, Region, Base, Size)
-int ScreenNum;
-int Region;
-pointer Base;
-unsigned long Size;
+static pointer
+MapVidMem(int ScreenNum, unsigned long Base, unsigned long Size, int flags)
{
static int once;
int free_slot = -1;
@@ -86,14 +163,15 @@ unsigned long Size;
{
if (!*smems[i].name && free_slot == -1)
free_slot = i;
- if (smems[i].Base == Base && smems[i].Size == Size && *smems[i].name) {
+ if (smems[i].Base == Base && smems[i].Size == Size
+ && *smems[i].name) {
smems[i].RefCnt++;
return smems[i].ptr;
}
}
if (i == MAX_SMEMS && free_slot == -1)
{
- FatalError("xf86MapVidMem: failed to smem_create Base %x Size %x (out of SMEMS entries)\n",
+ FatalError("MapVidMem: failed to smem_create Base %x Size %x (out of SMEMS entries)\n",
Base, Size);
}
@@ -101,53 +179,85 @@ unsigned long Size;
sprintf(smems[i].name, "Video-%d", i);
smems[i].Base = Base;
smems[i].Size = Size;
- smems[i].ptr = smem_create(smems[i].name, Base, Size, SM_READ|SM_WRITE);
+
+ xf86MsgVerb(X_INFO, 3, "MapVidMem: Base=0x%x Size=0x%x\n",
+ Base, Size);
+
+#if defined(__powerpc__)
+ if (((unsigned long)Base & PHYS_IO_MEM_START) != PHYS_IO_MEM_START) {
+ Base = Base | PHYS_IO_MEM_START;
+ }
+#endif
+
+ smems[i].ptr = smem_create(smems[i].name, (char *)Base, Size, SM_READ|SM_WRITE);
smems[i].RefCnt = 1;
if (smems[i].ptr == NULL)
{
/* check if there is a stale segment around */
if (smem_remove(smems[i].name) == 0) {
- ErrorF("xf86MapVidMem: removed stale smem_ segment %s\n",
- smems[i].name);
+ xf86Msg(X_INFO,
+ "MapVidMem: removed stale smem_ segment %s\n",
+ smems[i].name);
smems[i].ptr = smem_create(smems[i].name,
- Base, Size, SM_READ|SM_WRITE);
+ (char *)Base, Size, SM_READ|SM_WRITE);
}
if (smems[i].ptr == NULL) {
*smems[i].name = '\0';
- FatalError("xf86MapVidMem: failed to smem_create Base %x Size %x (%s)\n",
+ FatalError("MapVidMem: failed to smem_create Base %x Size %x (%s)\n",
Base, Size, strerror(errno));
}
}
+ xf86MsgVerb(X_INFO, 3, "MapVidMem: Base=0x%x Size=0x%x Ptr=0x%x\n",
+ Base, Size, smems[i].ptr);
return smems[i].ptr;
}
-void xf86UnMapVidMem(ScreenNum, Region, Base, Size)
-int ScreenNum;
-int Region;
-pointer Base;
-unsigned long Size;
+static void
+UnMapVidMem(int ScreenNum, pointer Base, unsigned long Size)
{
int i;
+ xf86MsgVerb(X_INFO, 3, "UnMapVidMem: Base/Ptr=0x%x Size=0x%x\n",
+ Base, Size);
for (i = 0; i < MAX_SMEMS; i++)
{
- if (*smems[i].name && smems[i].ptr == Base && smems[i].Size == Size)
+ if (*smems[i].name && smems[i].ptr == Base
+ && smems[i].Size == Size)
{
if (--smems[i].RefCnt > 0)
return;
+
(void)smem_create(NULL, smems[i].ptr, 0, SM_DETACH);
+ xf86MsgVerb(X_INFO, 3,
+ "UnMapVidMem: smem_create(%s, 0x%08x, ... "
+ "SM_DETACH)\n", smems[i].name, smems[i].ptr);
(void)smem_remove(smems[i].name);
*smems[i].name = '\0';
smems[i].RefCnt = 0;
return;
}
}
- ErrorF("xf86UnMapVidMem: no SMEM found for Base = %lx Size = %lx\n", Base, Size);
+ xf86MsgVerb(X_WARNING, 2,
+ "UnMapVidMem: no SMEM found for Base = %lx Size = %lx\n",
+ Base, Size);
}
-Bool xf86LinearVidMem()
+
+void
+xf86OSInitVidMem(VidMemInfoPtr pVidMem)
{
- return(TRUE);
+ pVidMem->linearSupported = TRUE;
+ pVidMem->mapMem = MapVidMem;
+ pVidMem->unmapMem = UnMapVidMem;
+ pVidMem->setWC = 0;
+ pVidMem->undoWC = 0;
+#ifdef HAS_MTRR_SUPPORT
+ if (cleanMTRR()) {
+ pVidMem->setWC = setWC;
+ pVidMem->undoWC = undoWC;
+ }
+#endif
+ pVidMem->initialised = TRUE;
}
@@ -155,13 +265,442 @@ Bool xf86LinearVidMem()
/* Interrupt Handling section */
/***************************************************************************/
-Bool xf86DisableInterrupts()
+Bool
+xf86DisableInterrupts()
{
return(TRUE);
}
-void xf86EnableInterrupts()
+void
+xf86EnableInterrupts()
+{
+ return;
+}
+
+/***************************************************************************/
+/* I/O Permissions section for PowerPC */
+/***************************************************************************/
+
+#if defined(__powerpc__)
+
+volatile unsigned char *ioBase = MAP_FAILED;
+volatile unsigned char *pciConfBase = MAP_FAILED;
+
+static int IOEnabled;
+
+
+static void
+removeIOSmem(void)
+{
+ smem_create(NULL, (char *) ioBase, 0, SM_DETACH);
+ smem_remove("IOBASE");
+ ioBase = MAP_FAILED;
+}
+
+void
+xf86EnableIO()
{
+ if (IOEnabled++ == 0) {
+ ioBase = (unsigned char *) smem_create("IOBASE",
+ (char *)PHYS_ISA_IO_SPACE, 64*1024, SM_READ|SM_WRITE);
+ if (ioBase == MAP_FAILED) {
+ --IOEnabled;
+ FatalError("xf86EnableIO: Failed to map I/O\n");
+ } else {
+#ifdef DEBUG
+ ErrorF("xf86EnableIO: mapped I/O at vaddr 0x%08x\n",
+ ioBase);
+#endif
+ atexit(removeIOSmem);
+ }
+ }
return;
}
+void
+xf86DisableIO()
+{
+ if (!IOEnabled)
+ return;
+
+ if (--IOEnabled == 0)
+ removeIOSmem();
+ return;
+}
+
+#if 0
+void
+xf86DisableIOPrivs(void)
+{
+ return;
+}
+#endif
+void
+ppcPciIoMap(int bus)
+{
+ xf86EnableIO();
+}
+
+#endif
+
+
+#ifdef HAS_MTRR_SUPPORT
+/* memory range (MTRR) support for LynxOS (taken from BSD MTRR support) */
+
+/*
+ * This code is experimental. Some parts may be overkill, and other parts
+ * may be incomplete.
+ */
+
+/*
+ * getAllRanges returns the full list of memory ranges with attributes set.
+ */
+
+static struct mem_range_desc *
+getAllRanges(int *nmr)
+{
+ struct mem_range_desc *mrd;
+ struct mem_range_op mro;
+
+ /*
+ * Find how many ranges there are. If this fails, then the kernel
+ * probably doesn't have MTRR support.
+ */
+ mro.mo_arg[0] = 0;
+ if (ioctl(devMemFd, MEMRANGE_GET, &mro))
+ return NULL;
+ *nmr = mro.mo_arg[0];
+ mrd = xnfalloc(*nmr * sizeof(struct mem_range_desc));
+ mro.mo_arg[0] = *nmr;
+ mro.mo_desc = mrd;
+ if (ioctl(devMemFd, MEMRANGE_GET, &mro)) {
+ xfree(mrd);
+ return NULL;
+ }
+ return mrd;
+}
+
+/*
+ * cleanMTRR removes any memory attribute that may be left by a previous
+ * X server. Normally there won't be any, but this takes care of the
+ * case where a server crashed without being able finish cleaning up.
+ */
+
+static Bool
+cleanMTRR()
+{
+ struct mem_range_desc *mrd;
+ struct mem_range_op mro;
+ int nmr, i;
+
+ /* This shouldn't happen */
+ if (devMemFd < 0) {
+ if ((devMemFd = open(MTRR_DEVICE, O_RDONLY)) < 0) {
+perror("open MTRR");
+ return FALSE;
+ }
+ }
+
+ if (!(mrd = getAllRanges(&nmr)))
+ return FALSE;
+
+ for (i = 0; i < nmr; i++) {
+ if (strcmp(mrd[i].mr_owner, X_MTRR_ID) == 0 &&
+ (mrd[i].mr_flags & MDF_ACTIVE)) {
+#ifdef DEBUG
+ ErrorF("Clean for (0x%lx,0x%lx)\n",
+ (unsigned long)mrd[i].mr_base,
+ (unsigned long)mrd[i].mr_len);
+#endif
+ if (mrd[i].mr_flags & MDF_FIXACTIVE) {
+ mro.mo_arg[0] = MEMRANGE_SET_UPDATE;
+ mrd[i].mr_flags = MDF_UNCACHEABLE;
+ } else {
+ mro.mo_arg[0] = MEMRANGE_SET_REMOVE;
+ }
+ mro.mo_desc = mrd + i;
+ ioctl(devMemFd, MEMRANGE_SET, &mro);
+ }
+ }
+#ifdef DEBUG
+ sleep(10);
+#endif
+ xfree(mrd);
+ 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;
+ xfree(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;
+ }
+ }
+ xfree(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 pointer
+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 pointer
+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 pointer
+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, pointer 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 */
+