summaryrefslogtreecommitdiff
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);