about summary refs log tree commit diff
path: root/sysdeps/unix/sysv/linux/alpha/ioperm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/unix/sysv/linux/alpha/ioperm.c')
-rw-r--r--sysdeps/unix/sysv/linux/alpha/ioperm.c275
1 files changed, 173 insertions, 102 deletions
diff --git a/sysdeps/unix/sysv/linux/alpha/ioperm.c b/sysdeps/unix/sysv/linux/alpha/ioperm.c
index 306c86b96a..b9630a8273 100644
--- a/sysdeps/unix/sysv/linux/alpha/ioperm.c
+++ b/sysdeps/unix/sysv/linux/alpha/ioperm.c
@@ -35,31 +35,35 @@ I/O address space that's 512MB large!).  */
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
-#include <unistd.h>
+#include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #include <sys/types.h>
 #include <sys/mman.h>
 
-#include <asm/io.h>
 #include <asm/page.h>
 #include <asm/system.h>
 
-#undef inb
-#undef inw
-#undef inl
-#undef outb
-#undef outw
-#undef outl
-
-#define PATH_CPUINFO	"/proc/cpuinfo"
+#define PATH_ALPHA_SYSTYPE	"/etc/alpha_systype"
+#define PATH_CPUINFO		"/proc/cpuinfo"
 
 #define MAX_PORT	0x10000
 #define vuip		volatile unsigned int *
 
-#define JENSEN_IO_BASE		(IDENT_ADDR + 0x0300000000UL)
-#define APECS_IO_BASE		(IDENT_ADDR + 0x01c0000000UL)
-#define ALCOR_IO_BASE		(IDENT_ADDR + 0x8580000000UL)
+#define JENSEN_IO_BASE		(0xfffffc0300000000UL)
+#define JENSEN_MEM		(0xfffffc0200000000UL)	/* sparse!! */
+
+/*
+ * With respect to the I/O architecture, APECS and LCA are identical,
+ * so the following defines apply to LCA as well.
+ */
+#define APECS_IO_BASE		(0xfffffc01c0000000UL)
+#define APECS_DENSE_MEM		(0xfffffc0300000000UL)
+
+#define ALCOR_IO_BASE		(0xfffffc8580000000UL)
+#define ALCOR_DENSE_MEM		(0xfffffc8600000000UL)
+
 
 enum {
   IOSYS_JENSEN = 0, IOSYS_APECS = 1, IOSYS_ALCOR = 2
@@ -78,58 +82,75 @@ struct ioswtch {
 static struct platform {
   const char	*name;
   int		io_sys;
+  unsigned long	bus_memory_base;
 } platform[] = {
-  {"Alcor",		IOSYS_ALCOR},
-  {"Avanti",		IOSYS_APECS},
-  {"Cabriolet",		IOSYS_APECS},
-  {"EB64+",		IOSYS_APECS},
-  {"EB66",		IOSYS_APECS},
-  {"EB66P",		IOSYS_APECS},
-  {"Jensen",		IOSYS_JENSEN},
-  {"Mustang",		IOSYS_APECS},
-  {"Noname",		IOSYS_APECS},
+  {"Alcor",	IOSYS_ALCOR,	ALCOR_DENSE_MEM},
+  {"Avanti",	IOSYS_APECS,	APECS_DENSE_MEM},
+  {"Cabriolet",	IOSYS_APECS,	APECS_DENSE_MEM},
+  {"EB164",	IOSYS_ALCOR,	ALCOR_DENSE_MEM},
+  {"EB64+",	IOSYS_APECS,	APECS_DENSE_MEM},
+  {"EB66",	IOSYS_APECS,	APECS_DENSE_MEM},	/* LCA same as APECS */
+  {"EB66P",	IOSYS_APECS,	APECS_DENSE_MEM},	/* LCA same as APECS */
+  {"Jensen",	IOSYS_JENSEN,	JENSEN_MEM},
+  {"Mustang",	IOSYS_APECS,	APECS_DENSE_MEM},
+  {"Noname",	IOSYS_APECS,	APECS_DENSE_MEM},	/* LCA same as APECS */
 };
 
 
 static struct {
-  struct hae		hae;
+  struct hae {
+    unsigned long	cache;
+    unsigned long *	reg;
+  } hae;
   unsigned long		base;
   struct ioswtch *	swp;
   int			sys;
 } io;
 
+static unsigned long bus_memory_base = -1;
+
+extern void __sethae (unsigned long);	/* we can't use asm/io.h */
+
 
 static inline unsigned long
 port_to_cpu_addr (unsigned long port, int iosys, int size)
 {
-  if (iosys == IOSYS_JENSEN) {
-    return (port << 7) + ((size - 1) << 4) + io.base;
-  } else {
-    return (port << 5) + ((size - 1) << 3) + io.base;
-  }
+  if (iosys == IOSYS_JENSEN)
+    {
+      return (port << 7) + ((size - 1) << 4) + io.base;
+    }
+  else
+    {
+      return (port << 5) + ((size - 1) << 3) + io.base;
+    }
 }
 
 
 static inline void
 inline_sethae (unsigned long addr, int iosys)
 {
-  if (iosys == IOSYS_JENSEN) {
-    /* hae on the Jensen is bits 31:25 shifted right */
-    addr >>= 25;
-    if (addr != io.hae.cache) {
-	__sethae (addr);
-	io.hae.cache = addr;
+  if (iosys == IOSYS_JENSEN)
+    {
+      /* hae on the Jensen is bits 31:25 shifted right */
+      addr >>= 25;
+      if (addr != io.hae.cache)
+	{
+	  __sethae (addr);
+	  io.hae.cache = addr;
+	}
     }
-  } else {
-    unsigned long msb;
-
-    /* no need to set hae if msb is 0: */
-    msb = addr & 0xf8000000;
-    if (msb && msb != io.hae.cache) {
-	__sethae (msb);
-	io.hae.cache = msb;
+  else
+    {
+      unsigned long msb;
+
+      /* no need to set hae if msb is 0: */
+      msb = addr & 0xf8000000;
+      if (msb && msb != io.hae.cache)
+	{
+	  __sethae (msb);
+	  io.hae.cache = msb;
+	}
     }
-  }
 }
 
 
@@ -263,22 +284,56 @@ struct ioswtch ioswtch[] = {
 };
 
 
+/*
+ * Initialize I/O system.  To determine what I/O system we're dealing
+ * with, we first try to read the value of symlink PATH_ALPHA_SYSTYPE,
+ * if that fails, we lookup the "system type" field in /proc/cpuinfo.
+ * If that fails as well, we give up.
+ */
 static int
 init_iosys (void)
 {
-  char name[256], value[256];
-  FILE * fp;
-  int i;
+  char systype[256];
+  int i, n;
 
-  fp = fopen (PATH_CPUINFO, "r");
-  if (!fp)
-    return -1;
+  n = readlink(PATH_ALPHA_SYSTYPE, systype, sizeof(systype) - 1);
+  if (n > 0)
+    {
+      systype[n] = '\0';
+    }
+  else
+    {
+      char name[256];
+      FILE * fp;
+
+      fp = fopen (PATH_CPUINFO, "r");
+      if (!fp)
+	return -1;
+      while ((n = fscanf (fp, "%256[^:]: %256[^\n]\n", name, systype)) != EOF)
+	{
+	  if (n == 2 && strncmp (name, "system type", 11) == 0) {
+	    break;
+	  }
+	}
+      fclose(fp);
+
+      if (n == EOF)
+	{
+	  /* this can happen if the format of /proc/cpuinfo changes...  */
+	  fprintf(stderr,
+		  "ioperm.init_iosys(): Unable to determine system type.\n"
+		  "\t(May need " PATH_ALPHA_SYSTYPE " symlink?)\n");
+	  errno = ENODEV;
+	  return -1;
+	}
+    }
 
-  while (fscanf (fp, "%256[^:]: %256[^\n]\n", name, value) == 2) {
-    if (strncmp (name, "system type", 11) == 0) {
-      for (i = 0; i < sizeof (platform) / sizeof (platform[0]); ++i) {
-	if (strcmp (platform[i].name, value) == 0) {
-	  fclose (fp);
+  /* translate systype name into i/o system: */
+  for (i = 0; i < sizeof (platform) / sizeof (platform[0]); ++i)
+    {
+      if (strcmp (platform[i].name, systype) == 0)
+	{
+	  bus_memory_base = platform[i].bus_memory_base;
 	  io.sys = platform[i].io_sys;
 	  if (io.sys == IOSYS_JENSEN)
 	    io.swp = &ioswtch[0];
@@ -286,11 +341,10 @@ init_iosys (void)
 	    io.swp = &ioswtch[1];
 	  return 0;
 	}
-      }
     }
-  }
-  fclose (fp);
-  errno = ENODEV;
+
+  /* systype is not a know platform name... */
+  errno = EINVAL;
   return -1;
 }
 
@@ -305,49 +359,55 @@ _ioperm (unsigned long from, unsigned long num, int turn_on)
     return -1;
 
   /* this test isn't as silly as it may look like; consider overflows! */
-  if (from >= MAX_PORT || from + num > MAX_PORT) {
-    errno = EINVAL;
-    return -1;
-  }
+  if (from >= MAX_PORT || from + num > MAX_PORT)
+    {
+      errno = EINVAL;
+      return -1;
+    }
 
-  if (turn_on) {
-    if (!io.base) {
-      unsigned long base;
-      int fd;
-
-      io.hae.reg   = 0;		/* not used in user-level */
-      io.hae.cache = 0;
-      __sethae (io.hae.cache);	/* synchronize with hw */
-
-      fd = open ("/dev/mem", O_RDWR);
-      if (fd < 0)
-	return fd;
-
-      switch (io.sys) {
-      case IOSYS_JENSEN:	base = JENSEN_IO_BASE; break;
-      case IOSYS_APECS:		base = APECS_IO_BASE; break;
-      case IOSYS_ALCOR:		base = ALCOR_IO_BASE; break;
-      default:
-	errno = ENODEV;
-	return -1;
-      }
-      addr  = port_to_cpu_addr (from, io.sys, 1);
-      addr &= PAGE_MASK;
-      len = port_to_cpu_addr (MAX_PORT, io.sys, 1) - addr;
-      io.base =
-	  (unsigned long) __mmap (0, len, PROT_NONE, MAP_SHARED, fd, base);
-      close (fd);
-      if ((long) io.base == -1)
-	return -1;
+  if (turn_on)
+    {
+      if (!io.base)
+	{
+	  unsigned long base;
+	  int fd;
+
+	  io.hae.reg   = 0;		/* not used in user-level */
+	  io.hae.cache = 0;
+	  __sethae (io.hae.cache);	/* synchronize with hw */
+
+	  fd = open ("/dev/mem", O_RDWR);
+	  if (fd < 0)
+	    return fd;
+
+	  switch (io.sys)
+	    {
+	    case IOSYS_JENSEN:	base = JENSEN_IO_BASE; break;
+	    case IOSYS_APECS:	base = APECS_IO_BASE; break;
+	    case IOSYS_ALCOR:	base = ALCOR_IO_BASE; break;
+	    default:
+	      errno = ENODEV;
+	      return -1;
+	    }
+	  addr  = port_to_cpu_addr (from, io.sys, 1);
+	  addr &= PAGE_MASK;
+	  len = port_to_cpu_addr (MAX_PORT, io.sys, 1) - addr;
+	  io.base =
+	    (unsigned long) __mmap (0, len, PROT_NONE, MAP_SHARED, fd, base);
+	  close (fd);
+	  if ((long) io.base == -1)
+	    return -1;
+	}
+      prot = PROT_READ | PROT_WRITE;
     }
-    prot = PROT_READ | PROT_WRITE;
-  } else {
-    if (!io.base)
-      return 0;	/* never was turned on... */
+  else
+    {
+      if (!io.base)
+	return 0;	/* never was turned on... */
 
-    /* turnoff access to relevant pages: */
-    prot = PROT_NONE;
-  }
+      /* turnoff access to relevant pages: */
+      prot = PROT_NONE;
+    }
   addr  = port_to_cpu_addr (from, io.sys, 1);
   addr &= PAGE_MASK;
   len = port_to_cpu_addr (from + num, io.sys, 1) - addr;
@@ -358,13 +418,15 @@ _ioperm (unsigned long from, unsigned long num, int turn_on)
 int
 _iopl (unsigned int level)
 {
-    if (level > 3) {
+    if (level > 3)
+      {
 	errno = EINVAL;
 	return -1;
-    }
-    if (level) {
+      }
+    if (level)
+      {
 	return _ioperm (0, MAX_PORT, 1);
-    }
+      }
     return 0;
 }
 
@@ -430,6 +492,14 @@ _inl (unsigned long port)
 }
 
 
+unsigned long
+_bus_base(void)
+{
+  if (!io.swp && init_iosys () < 0)
+    return -1;
+  return bus_memory_base;
+}
+
 weak_alias (_sethae, sethae);
 weak_alias (_ioperm, ioperm);
 weak_alias (_iopl, iopl);
@@ -439,3 +509,4 @@ weak_alias (_inl, inl);
 weak_alias (_outb, outb);
 weak_alias (_outw, outw);
 weak_alias (_outl, outl);
+weak_alias (_bus_base, bus_base);