summaryrefslogtreecommitdiff
path: root/sys/arch
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2012-03-28 20:44:24 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2012-03-28 20:44:24 +0000
commit6ea0ed8392999d052b79785548a577d7e55b7184 (patch)
treeb4c5fb05563150bb09cc3d203971a18a2b5277bc /sys/arch
parentb71835f84a40d614f56816274c2400a719e82600 (diff)
Work in progress support for the SGI Indigo, Indigo 2 and Indy systems
(IP20, IP22, IP24) in 64-bit mode, adapated from NetBSD. Currently limited to headless operation, input and video drivers will get ported soon. Should work on all R4000, R4440 and R5000 based systems. L2 cache on R5000SC Indy not supported yet (coming soon), R4600 not supported yet either (coming soon as well). Tested to boot multiuser on: Indigo2 R4000SC, Indy R4000PC, Indy R4000SC, Indy R5000SC, Indigo2 R4400SC. There are still glitches in the Ethernet driver which are being looked at. Expansion support is limited to the GIO E++ board; GIO boards with PCI-GIO bridges not ported yet due to the lack of hardware, and this kind of driver does not port blindly. Most of this work comes from NetBSD, polishing and integration work, as well as putting as many ``R4x00 in 64-bit mode'' erratas as necessary, by yours truly. More work is coming, as well as trying to get some easy way to boot install kernels (as older PROM can only boot ECOFF binaries, which won't do for the kernel).
Diffstat (limited to 'sys/arch')
-rw-r--r--sys/arch/mips64/conf/files.mips643
-rw-r--r--sys/arch/mips64/include/arcbios.h3
-rw-r--r--sys/arch/mips64/include/cpu.h5
-rw-r--r--sys/arch/mips64/mips64/arcbios.c3
-rw-r--r--sys/arch/mips64/mips64/cache_r4k.c323
-rw-r--r--sys/arch/mips64/mips64/cp0access.S9
-rw-r--r--sys/arch/mips64/mips64/cpu.c28
-rw-r--r--sys/arch/mips64/mips64/exception.S7
-rw-r--r--sys/arch/mips64/mips64/lcore_access.S34
-rw-r--r--sys/arch/mips64/mips64/tlbhandler.S18
-rw-r--r--sys/arch/mips64/mips64/trap.c32
-rw-r--r--sys/arch/sgi/compile/.cvsignore3
-rw-r--r--sys/arch/sgi/conf/GENERIC-IP2285
-rw-r--r--sys/arch/sgi/conf/RAMDISK-IP2295
-rw-r--r--sys/arch/sgi/conf/files.sgi29
-rw-r--r--sys/arch/sgi/dev/dsrtc.c4
-rw-r--r--sys/arch/sgi/gio/Makefile8
-rw-r--r--sys/arch/sgi/gio/devlist2h.awk152
-rw-r--r--sys/arch/sgi/gio/files.gio31
-rw-r--r--sys/arch/sgi/gio/gio.c518
-rw-r--r--sys/arch/sgi/gio/giodevs21
-rw-r--r--sys/arch/sgi/gio/gioreg.h68
-rw-r--r--sys/arch/sgi/gio/giovar.h75
-rw-r--r--sys/arch/sgi/hpc/dpclock.c312
-rw-r--r--sys/arch/sgi/hpc/dsclock.c192
-rw-r--r--sys/arch/sgi/hpc/files.hpc56
-rw-r--r--sys/arch/sgi/hpc/hpc.c822
-rw-r--r--sys/arch/sgi/hpc/hpcdma.c208
-rw-r--r--sys/arch/sgi/hpc/hpcdma.h63
-rw-r--r--sys/arch/sgi/hpc/hpcreg.h450
-rw-r--r--sys/arch/sgi/hpc/hpcvar.h109
-rw-r--r--sys/arch/sgi/hpc/if_sq.c1348
-rw-r--r--sys/arch/sgi/hpc/if_sqvar.h200
-rw-r--r--sys/arch/sgi/hpc/iocreg.h122
-rw-r--r--sys/arch/sgi/hpc/wdsc.c290
-rw-r--r--sys/arch/sgi/hpc/z8530sc.c409
-rw-r--r--sys/arch/sgi/hpc/z8530sc.h199
-rw-r--r--sys/arch/sgi/hpc/z8530tty.c1663
-rw-r--r--sys/arch/sgi/hpc/zs.c712
-rw-r--r--sys/arch/sgi/include/autoconf.h3
-rw-r--r--sys/arch/sgi/include/eisa_machdep.h68
-rw-r--r--sys/arch/sgi/include/z8530var.h121
-rw-r--r--sys/arch/sgi/localbus/imc.c826
-rw-r--r--sys/arch/sgi/localbus/imcreg.h143
-rw-r--r--sys/arch/sgi/localbus/imcvar.h42
-rw-r--r--sys/arch/sgi/localbus/int.c369
-rw-r--r--sys/arch/sgi/localbus/intreg.h51
-rw-r--r--sys/arch/sgi/localbus/intvar.h34
-rw-r--r--sys/arch/sgi/sgi/autoconf.c45
-rw-r--r--sys/arch/sgi/sgi/conf.c12
-rw-r--r--sys/arch/sgi/sgi/ip22.h32
-rw-r--r--sys/arch/sgi/sgi/ip22_machdep.c277
-rw-r--r--sys/arch/sgi/sgi/ip30_machdep.c6
-rw-r--r--sys/arch/sgi/sgi/ip32_machdep.c6
-rw-r--r--sys/arch/sgi/sgi/machdep.c147
-rw-r--r--sys/arch/sgi/sgi/mainbus.c21
-rw-r--r--sys/arch/sgi/stand/Makefile5
57 files changed, 10839 insertions, 78 deletions
diff --git a/sys/arch/mips64/conf/files.mips64 b/sys/arch/mips64/conf/files.mips64
index def002b4c53..9383b21aadd 100644
--- a/sys/arch/mips64/conf/files.mips64
+++ b/sys/arch/mips64/conf/files.mips64
@@ -1,4 +1,4 @@
-# $OpenBSD: files.mips64,v 1.17 2010/10/24 15:40:03 miod Exp $
+# $OpenBSD: files.mips64,v 1.18 2012/03/28 20:44:23 miod Exp $
file arch/mips64/mips64/arcbios.c arcbios
file arch/mips64/mips64/clock.c
@@ -15,6 +15,7 @@ file arch/mips64/mips64/trap.c
file arch/mips64/mips64/vm_machdep.c
file arch/mips64/mips64/cache_loongson2.S cpu_loongson2
+file arch/mips64/mips64/cache_r4k.c cpu_r4000
file arch/mips64/mips64/cache_r5k.S cpu_r5000 | cpu_rm7000
file arch/mips64/mips64/cache_r10k.S cpu_r10000
file arch/mips64/mips64/cache_octeon.c cpu_octeon
diff --git a/sys/arch/mips64/include/arcbios.h b/sys/arch/mips64/include/arcbios.h
index 51e6f00b014..112bbaf2f2c 100644
--- a/sys/arch/mips64/include/arcbios.h
+++ b/sys/arch/mips64/include/arcbios.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: arcbios.h,v 1.18 2011/06/05 20:58:46 miod Exp $ */
+/* $OpenBSD: arcbios.h,v 1.19 2012/03/28 20:44:23 miod Exp $ */
/*-
* Copyright (c) 1996 M. Warner Losh. All rights reserved.
*
@@ -419,6 +419,7 @@ typedef struct arc_param_blk_64
#define ARCBIOS_PAGE_SIZE 4096
extern int bios_is_32bit;
+extern int bios_consrate;
extern char bios_enaddr[20];
extern char bios_console[30];
extern char bios_graphics[6];
diff --git a/sys/arch/mips64/include/cpu.h b/sys/arch/mips64/include/cpu.h
index 5a079b54e11..59b0760382b 100644
--- a/sys/arch/mips64/include/cpu.h
+++ b/sys/arch/mips64/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.77 2012/03/25 13:52:52 miod Exp $ */
+/* $OpenBSD: cpu.h,v 1.78 2012/03/28 20:44:23 miod Exp $ */
/*-
* Copyright (c) 1992, 1993
@@ -560,6 +560,7 @@ uint32_t cp0_get_config_2(void);
uint32_t cp0_get_config_3(void);
uint32_t cp0_get_prid(void);
void cp0_set_compare(u_int);
+void cp0_set_config(uint32_t);
u_int cp1_get_prid(void);
void tlb_set_page_mask(uint32_t);
void tlb_set_pid(int);
@@ -580,6 +581,8 @@ void save_fpu(void);
int fpe_branch_emulate(struct proc *, struct trap_frame *, uint32_t,
vaddr_t);
+int guarded_read_1(paddr_t, uint8_t *);
+int guarded_read_2(paddr_t, uint16_t *);
int guarded_read_4(paddr_t, uint32_t *);
int guarded_write_4(paddr_t, uint32_t);
diff --git a/sys/arch/mips64/mips64/arcbios.c b/sys/arch/mips64/mips64/arcbios.c
index e0704b8a504..dac9405f891 100644
--- a/sys/arch/mips64/mips64/arcbios.c
+++ b/sys/arch/mips64/mips64/arcbios.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: arcbios.c,v 1.31 2012/03/24 20:11:28 miod Exp $ */
+/* $OpenBSD: arcbios.c,v 1.32 2012/03/28 20:44:23 miod Exp $ */
/*-
* Copyright (c) 1996 M. Warner Losh. All rights reserved.
* Copyright (c) 1996-2004 Opsycon AB. All rights reserved.
@@ -50,6 +50,7 @@ int bios_is_32bit;
*/
char bios_enaddr[20] = "ff:ff:ff:ff:ff:ff";
+int bios_consrate; /* Serial console speed. */
char bios_console[30]; /* Primary console. */
char bios_graphics[6]; /* Graphics state. */
char bios_keyboard[6]; /* Keyboard layout. */
diff --git a/sys/arch/mips64/mips64/cache_r4k.c b/sys/arch/mips64/mips64/cache_r4k.c
new file mode 100644
index 00000000000..5d8aec81215
--- /dev/null
+++ b/sys/arch/mips64/mips64/cache_r4k.c
@@ -0,0 +1,323 @@
+/* $OpenBSD: cache_r4k.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+
+/*
+ * Copyright (c) 2012 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <mips64/cache.h>
+#include <machine/cpu.h>
+
+#define IndexInvalidate_I 0x00
+#define IndexWBInvalidate_D 0x01
+#define IndexWBInvalidate_S 0x03
+
+#define HitInvalidate_D 0x11
+#define HitInvalidate_S 0x13
+
+#define HitWBInvalidate_D 0x15
+#define HitWBInvalidate_S 0x17
+
+#define cache(op,addr) \
+ __asm__ __volatile__ ("cache %0, 0(%1)" :: "i"(op), "r"(addr) : "memory")
+#define sync() \
+ __asm__ __volatile__ ("sync" ::: "memory");
+
+void
+Mips4k_ConfigCache(struct cpu_info *ci)
+{
+ uint32_t cfg;
+
+ cfg = cp0_get_config();
+
+ if (cfg & (1 << 5)) /* IB */
+ ci->ci_l1instcacheline = 32;
+ else
+ ci->ci_l1instcacheline = 16;
+ ci->ci_l1instcachesize = (1 << 12) << ((cfg >> 9) & 0x07); /* IC */
+
+ if (cfg & (1 << 4)) /* DB */
+ ci->ci_l1datacacheline = 32;
+ else
+ ci->ci_l1datacacheline = 16;
+ ci->ci_l1datacachesize = (1 << 12) << ((cfg >> 6) & 0x07); /* DC */
+
+ /* R4000 and R4400 L1 caches are direct */
+ ci->ci_cacheways = 1;
+ ci->ci_l1instcacheset = ci->ci_l1instcachesize;
+ ci->ci_l1datacacheset = ci->ci_l1datacachesize;
+
+ CpuCacheAliasMask = (ci->ci_l1instcachesize | ci->ci_l1datacachesize) &
+ ~PAGE_MASK;
+
+ if ((cfg & (1 << 17)) == 0) { /* SC */
+ /*
+ * We expect the setup code to have set up ci->ci_l2size for
+ * us. Unfortunately we aren't allowed to panic() there,
+ * because the console is not available.
+ */
+
+ /* fixed 32KB aliasing to avoid VCE */
+ CpuCacheAliasMask |= ((1 << 15) - 1) & ~PAGE_MASK;
+ } else {
+ ci->ci_cacheconfiguration = 0;
+ ci->ci_l2size = 0;
+ }
+ ci->ci_l3size = 0;
+
+ if (CpuCacheAliasMask != 0)
+ CpuCacheAliasMask |= PAGE_MASK;
+
+ if ((cfg & 7) != CCA_CACHED) {
+ void (*fn)(uint32_t);
+ vaddr_t va;
+ paddr_t pa;
+
+ va = (vaddr_t)&cp0_set_config;
+ if (IS_XKPHYS(va)) {
+ pa = XKPHYS_TO_PHYS(va);
+ va = PHYS_TO_XKPHYS(pa, CCA_NC);
+ } else {
+ pa = CKSEG0_TO_PHYS(va);
+ va = PHYS_TO_CKSEG1(pa);
+ }
+ fn = (void (*)(uint32_t))va;
+
+ cfg = (cfg & ~7) | CCA_CACHED;
+ (*fn)(cfg);
+ }
+}
+
+/*
+ * Writeback and invalidate all caches.
+ */
+void
+Mips4k_SyncCache(struct cpu_info *ci)
+{
+ vaddr_t sva, eva;
+ uint64_t line;
+
+ sva = PHYS_TO_XKPHYS(0, CCA_CACHED);
+ eva = sva + ci->ci_l1instcachesize;
+ line = ci->ci_l1instcacheline;
+ while (sva != eva) {
+ cache(IndexInvalidate_I, sva);
+ sva += line;
+ }
+
+ sva = PHYS_TO_XKPHYS(0, CCA_CACHED);
+ eva = sva + ci->ci_l1datacachesize;
+ line = ci->ci_l1datacacheline;
+ while (sva != eva) {
+ cache(IndexWBInvalidate_D, sva);
+ sva += line;
+ }
+
+ if (ci->ci_l2size != 0) {
+ sva = PHYS_TO_XKPHYS(0, CCA_CACHED);
+ eva = sva + ci->ci_l2size;
+ line = ci->ci_cacheconfiguration; /* L2 line size */
+ while (sva != eva) {
+ cache(IndexWBInvalidate_S, sva);
+ sva += line;
+ }
+ }
+
+ sync();
+}
+
+/*
+ * Invalidate I$ for the given range.
+ */
+void
+Mips4k_InvalidateICache(struct cpu_info *ci, uint64_t _va, size_t _sz)
+{
+ vaddr_t va, sva, eva;
+ vsize_t sz;
+ uint64_t line;
+
+ line = ci->ci_l1instcacheline;
+ /* extend the range to integral cache lines */
+ if (line == 16) {
+ va = _va & ~(16UL - 1);
+ sz = ((_va + _sz + 16 - 1) & ~(16UL - 1)) - _va;
+ } else {
+ va = _va & ~(32UL - 1);
+ sz = ((_va + _sz + 32 - 1) & ~(32UL - 1)) - _va;
+ }
+
+ sva = PHYS_TO_XKPHYS(0, CCA_CACHED);
+ /* keep only the index bits */
+ sva += va & ((1UL << 15) - 1);
+ eva = sva + sz;
+ while (sva != eva) {
+ cache(IndexInvalidate_I, sva);
+ sva += line;
+ }
+
+ sync();
+}
+
+/*
+ * Writeback D$ for the given page.
+ */
+void
+Mips4k_SyncDCachePage(struct cpu_info *ci, uint64_t va)
+{
+ vaddr_t sva, eva;
+ uint64_t line;
+
+ line = ci->ci_l1datacacheline;
+ sva = PHYS_TO_XKPHYS(0, CCA_CACHED);
+ /* keep only the index bits */
+ sva += va & ((1UL << 15) - 1);
+ eva = sva + PAGE_SIZE;
+ while (sva != eva) {
+ cache(IndexWBInvalidate_D, sva);
+ sva += line;
+ }
+
+ if (ci->ci_l2size != 0) {
+ line = ci->ci_cacheconfiguration; /* L2 line size */
+ sva = PHYS_TO_XKPHYS(0, CCA_CACHED);
+ /* keep only the index bits */
+ sva += va & ((1UL << 22) - 1); /* largest L2 is 4MB */
+ eva = sva + PAGE_SIZE;
+ while (sva != eva) {
+ cache(IndexWBInvalidate_S, sva);
+ sva += line;
+ }
+ }
+
+ sync();
+}
+
+/*
+ * Writeback D$ for the given range. Range is expected to be currently
+ * mapped, allowing the use of `Hit' operations. This is less aggressive
+ * than using `Index' operations.
+ */
+void
+Mips4k_HitSyncDCache(struct cpu_info *ci, uint64_t _va, size_t _sz)
+{
+ vaddr_t va, sva, eva;
+ vsize_t sz;
+ uint64_t line;
+
+ line = ci->ci_l1datacacheline;
+ /* extend the range to integral cache lines */
+ if (line == 16) {
+ va = _va & ~(16UL - 1);
+ sz = ((_va + _sz + 16 - 1) & ~(16UL - 1)) - va;
+ } else {
+ va = _va & ~(32UL - 1);
+ sz = ((_va + _sz + 32 - 1) & ~(32UL - 1)) - va;
+ }
+
+ sva = va;
+ eva = sva + sz;
+ while (sva != eva) {
+ cache(HitWBInvalidate_D, sva);
+ sva += line;
+ }
+
+ if (ci->ci_l2size != 0) {
+ line = ci->ci_cacheconfiguration; /* L2 line size */
+ /* extend the range to integral cache lines */
+ va = _va & ~(line - 1);
+ sz = ((_va + _sz + line - 1) & ~(line - 1)) - va;
+
+ sva = va;
+ eva = sva + sz;
+ while (sva != eva) {
+ cache(HitWBInvalidate_S, sva);
+ sva += line;
+ }
+ }
+
+ sync();
+}
+
+/*
+ * Invalidate D$ for the given range. Range is expected to be currently
+ * mapped, allowing the use of `Hit' operations. This is less aggressive
+ * than using `Index' operations.
+ */
+void
+Mips4k_HitInvalidateDCache(struct cpu_info *ci, uint64_t _va, size_t _sz)
+{
+ vaddr_t va, sva, eva;
+ vsize_t sz;
+ uint64_t line;
+
+ line = ci->ci_l1datacacheline;
+ /* extend the range to integral cache lines */
+ if (line == 16) {
+ va = _va & ~(16UL - 1);
+ sz = ((_va + _sz + 16 - 1) & ~(16UL - 1)) - _va;
+ } else {
+ va = _va & ~(32UL - 1);
+ sz = ((_va + _sz + 32 - 1) & ~(32UL - 1)) - _va;
+ }
+
+ sva = va;
+ eva = sva + sz;
+ while (sva != eva) {
+ cache(HitInvalidate_D, sva);
+ sva += line;
+ }
+
+ if (ci->ci_l2size != 0) {
+ line = ci->ci_cacheconfiguration; /* L2 line size */
+ /* extend the range to integral cache lines */
+ va = _va & ~(line - 1);
+ sz = ((_va + _sz + line - 1) & ~(line - 1)) - va;
+
+ sva = va;
+ eva = sva + sz;
+ while (sva != eva) {
+ cache(HitInvalidate_S, sva);
+ sva += line;
+ }
+ }
+
+ sync();
+}
+
+/*
+ * Backend for bus_dmamap_sync(). Enforce coherency of the given range
+ * by performing the necessary cache writeback and/or invalidate
+ * operations.
+ */
+void
+Mips4k_IOSyncDCache(struct cpu_info *ci, uint64_t va, size_t sz, int how)
+{
+ switch (how) {
+ case CACHE_SYNC_R:
+ if (((va | sz) & (ci->ci_l1datacacheline - 1)) == 0) {
+ Mips4k_HitInvalidateDCache(ci, va, sz);
+ break;
+ }
+ /* FALLTHROUGH */
+ case CACHE_SYNC_X:
+ Mips4k_HitSyncDCache(ci, va, sz);
+ break;
+ case CACHE_SYNC_W:
+ Mips4k_HitSyncDCache(ci, va, sz);
+ break;
+ }
+}
diff --git a/sys/arch/mips64/mips64/cp0access.S b/sys/arch/mips64/mips64/cp0access.S
index 32866dce285..7bb04346f0c 100644
--- a/sys/arch/mips64/mips64/cp0access.S
+++ b/sys/arch/mips64/mips64/cp0access.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: cp0access.S,v 1.14 2010/09/11 11:29:50 syuu Exp $ */
+/* $OpenBSD: cp0access.S,v 1.15 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 2001-2003 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -154,6 +154,13 @@ LEAF(cp0_get_config, 0)
nop
END(cp0_get_config)
+/* WARNING! Needs to be invoked from uncached address. */
+LEAF(cp0_set_config, 0)
+ mtc0 a0, COP_0_CONFIG
+ j ra
+ nop
+END(cp0_set_config)
+
LEAF(cp0_get_prid, 0)
mfc0 v0, COP_0_PRID
j ra
diff --git a/sys/arch/mips64/mips64/cpu.c b/sys/arch/mips64/mips64/cpu.c
index 37240e67095..2a85adba26e 100644
--- a/sys/arch/mips64/mips64/cpu.c
+++ b/sys/arch/mips64/mips64/cpu.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.c,v 1.39 2011/04/10 17:16:51 miod Exp $ */
+/* $OpenBSD: cpu.c,v 1.40 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 1997-2004 Opsycon AB (www.opsycon.se)
@@ -112,14 +112,18 @@ cpuattach(struct device *parent, struct device *dev, void *aux)
printf(": ");
displayver = 1;
+ fptype = (ch->c1prid >> 8) & 0xff;
vers_maj = (ch->c0prid >> 4) & 0x0f;
vers_min = ch->c0prid & 0x0f;
switch (ch->type) {
case MIPS_R4000:
- if (ci->ci_l1instcachesize == 16384)
- printf("MIPS R4400 CPU");
- else
+ if (vers_maj < 4)
printf("MIPS R4000 CPU");
+ else {
+ vers_maj -= 3;
+ printf("MIPS R4400 CPU");
+ }
+ fptype = MIPS_R4000;
break;
case MIPS_R5000:
printf("MIPS R5000 CPU");
@@ -184,6 +188,7 @@ cpuattach(struct device *parent, struct device *dev, void *aux)
break;
case MIPS_OCTEON:
printf("Cavium OCTEON CPU");
+ fptype = MIPS_SOFT;
break;
default:
printf("Unknown CPU type (0x%x)", ch->type);
@@ -194,13 +199,8 @@ cpuattach(struct device *parent, struct device *dev, void *aux)
printf(" %d MHz, ", ch->clock / 1000000);
displayver = 1;
- if (ch->type == MIPS_OCTEON)
- fptype = MIPS_SOFT;
- else {
- fptype = (ch->c1prid >> 8) & 0xff;
- vers_maj = (ch->c1prid >> 4) & 0x0f;
- vers_min = ch->c1prid & 0x0f;
- }
+ vers_maj = (ch->c1prid >> 4) & 0x0f;
+ vers_min = ch->c1prid & 0x0f;
switch (fptype) {
case MIPS_SOFT:
printf("Software FP emulation");
@@ -267,7 +267,7 @@ cpuattach(struct device *parent, struct device *dev, void *aux)
printf("4 way");
break;
default:
- printf("1 way");
+ printf("direct");
break;
}
@@ -293,8 +293,10 @@ cpuattach(struct device *parent, struct device *dev, void *aux)
printf("\n");
#ifdef DEBUG
- printf("cpu%d: Setsize %d:%d\n", cpuno,
+ printf("cpu%d: L1 set size %d:%d\n", cpuno,
ci->ci_l1instcacheset, ci->ci_l1datacacheset);
+ printf("cpu%d: L1 line size %d:%d\n", cpuno,
+ ci->ci_l1instcacheline, ci->ci_l1datacacheline);
printf("cpu%d: Alias mask %p\n", cpuno, CpuCacheAliasMask);
printf("cpu%d: Config Register %08x\n", cpuno, cp0_get_config());
printf("cpu%d: Cache configuration %x\n",
diff --git a/sys/arch/mips64/mips64/exception.S b/sys/arch/mips64/mips64/exception.S
index a02a560136b..2626cf95a77 100644
--- a/sys/arch/mips64/mips64/exception.S
+++ b/sys/arch/mips64/mips64/exception.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: exception.S,v 1.32 2010/12/28 18:40:28 miod Exp $ */
+/* $OpenBSD: exception.S,v 1.33 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 2002-2003 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -129,6 +129,11 @@ u_exception_table:
* to the vector area and must thus be PIC and less than 128
* bytes long to fit. Only k0 and k1 may be used at this time.
*/
+ .globl cache_err
+cache_err:
+#ifdef CPU_R4000
+ nop
+#endif
.globl exception
exception:
.set noat
diff --git a/sys/arch/mips64/mips64/lcore_access.S b/sys/arch/mips64/mips64/lcore_access.S
index 4975d28094e..c48b44ef6fa 100644
--- a/sys/arch/mips64/mips64/lcore_access.S
+++ b/sys/arch/mips64/mips64/lcore_access.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: lcore_access.S,v 1.19 2010/01/31 19:39:04 miod Exp $ */
+/* $OpenBSD: lcore_access.S,v 1.20 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 2001-2003 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -286,10 +286,42 @@ _kcopyerr:
/*
* Guarded ``memory'' access routines
+ * int guarded_read_1(paddr_t address, uint8_t *dest);
+ * int guarded_read_2(paddr_t address, uint16_t *dest);
* int guarded_read_4(paddr_t address, uint32_t *dest);
* int guarded_write_4(paddr_t address, uint32_t src);
*/
+LEAF(guarded_read_1, 0)
+ GET_CPU_INFO(t1, t0)
+ PTR_L t3, CI_CURPROCPADDR(t1)
+ li v0, KT_GUARDERR
+ lw v1, PCB_ONFAULT(t3)
+ sw v0, PCB_ONFAULT(t3)
+
+ lb v0, 0(a0)
+ sb v0, 0(a1)
+
+ sw v1, PCB_ONFAULT(t3)
+ j ra
+ move v0, zero
+END(guarded_read_1)
+
+LEAF(guarded_read_2, 0)
+ GET_CPU_INFO(t1, t0)
+ PTR_L t3, CI_CURPROCPADDR(t1)
+ li v0, KT_GUARDERR
+ lw v1, PCB_ONFAULT(t3)
+ sw v0, PCB_ONFAULT(t3)
+
+ lh v0, 0(a0)
+ sh v0, 0(a1)
+
+ sw v1, PCB_ONFAULT(t3)
+ j ra
+ move v0, zero
+END(guarded_read_2)
+
LEAF(guarded_read_4, 0)
GET_CPU_INFO(t1, t0)
PTR_L t3, CI_CURPROCPADDR(t1)
diff --git a/sys/arch/mips64/mips64/tlbhandler.S b/sys/arch/mips64/mips64/tlbhandler.S
index d96e343d765..d78fe8cebc6 100644
--- a/sys/arch/mips64/mips64/tlbhandler.S
+++ b/sys/arch/mips64/mips64/tlbhandler.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: tlbhandler.S,v 1.32 2010/09/12 12:05:37 syuu Exp $ */
+/* $OpenBSD: tlbhandler.S,v 1.33 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 1995-2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -54,6 +54,22 @@
*/
.set noat
+#ifdef CPU_R4000
+ .globl xtlb_miss_err_r4k
+ .ent xtlb_miss_err_r4k, 0
+xtlb_miss_err_r4k:
+ /*
+ * R4000 errata: TLB miss exception may be invoked with BadVAddr
+ * being incorrect.
+ */
+ tlbp
+ mfc0 k1, COP_0_TLB_INDEX
+ bltz k1, xtlb_miss # missing!
+ nop
+ eret
+ nop
+ .end xtlb_miss_err_r4k
+#endif /* CPU_R4000 */
#if defined(CPU_R5000) || defined(CPU_RM7000)
.globl xtlb_miss_err_r5k
.ent xtlb_miss_err_r5k, 0
diff --git a/sys/arch/mips64/mips64/trap.c b/sys/arch/mips64/mips64/trap.c
index d906010b49a..73aa524bcf7 100644
--- a/sys/arch/mips64/mips64/trap.c
+++ b/sys/arch/mips64/mips64/trap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: trap.c,v 1.77 2011/11/16 20:50:19 deraadt Exp $ */
+/* $OpenBSD: trap.c,v 1.78 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 1988 University of Utah.
@@ -763,6 +763,36 @@ printf("SIG-BUSB @%p pc %p, ra %p\n", trapframe->badvaddr, trapframe->pc, trapfr
}
goto err;
+#ifdef CPU_R4000
+ case T_VCEI:
+ case T_VCEI+T_USER:
+ {
+ vaddr_t va = trapframe->badvaddr &
+ ~((vaddr_t)ci->ci_l1instcacheline - 1);
+#ifdef DEBUG
+ printf("VCEI trap, badvaddr %p\n", trapframe->badvaddr);
+#endif
+ /* HitWBInvalidate_S */
+ __asm__ __volatile__ ("cache 0x17, 0(%0)" :: "r"(va));
+ /* HitInvalidate_I */
+ __asm__ __volatile__ ("cache 0x10, 0(%0)" :: "r"(va));
+ }
+ return;
+ case T_VCED:
+ case T_VCED+T_USER:
+ {
+ vaddr_t va = trapframe->badvaddr &
+ ~((vaddr_t)ci->ci_l1datacacheline - 1);
+#ifdef DEBUG
+ printf("VCED trap, badvaddr %p\n", trapframe->badvaddr);
+#endif
+ /* HitWBInvalidate_S */
+ __asm__ __volatile__ ("cache 0x17, 0(%0)" :: "r"(va));
+ /* HitInvalidate_D */
+ __asm__ __volatile__ ("cache 0x11, 0(%0)" :: "r"(va));
+ }
+ return;
+#endif /* CPU_R4000 */
default:
err:
disableintr();
diff --git a/sys/arch/sgi/compile/.cvsignore b/sys/arch/sgi/compile/.cvsignore
index 8a0ebe82e75..db6b8d0fedd 100644
--- a/sys/arch/sgi/compile/.cvsignore
+++ b/sys/arch/sgi/compile/.cvsignore
@@ -1,7 +1,10 @@
+GENERIC-IP22
GENERIC-IP27
+GENERIC-IP27.MP
GENERIC-IP30
GENERIC-IP30.MP
GENERIC-IP32
+RAMDISK-IP22
RAMDISK-IP27
RAMDISK-IP30
RAMDISK-IP32
diff --git a/sys/arch/sgi/conf/GENERIC-IP22 b/sys/arch/sgi/conf/GENERIC-IP22
new file mode 100644
index 00000000000..c062b6c4cb4
--- /dev/null
+++ b/sys/arch/sgi/conf/GENERIC-IP22
@@ -0,0 +1,85 @@
+# $OpenBSD: GENERIC-IP22,v 1.1 2012/03/28 20:44:23 miod Exp $
+#
+# THIS KERNEL IS FOR INDIGO (IP20), INDY (IP22) AND INDIGO2 (IP24) SYSTEMS ONLY.
+#
+# For further information on compiling OpenBSD kernels, see the config(8)
+# man page.
+#
+# For further information on hardware support for this architecture, see
+# the intro(4) man page. For further information about kernel options
+# for this architecture, see the options(4) man page. For an explanation
+# of each device driver in this file see the section 4 man page for the
+# device.
+
+machine sgi mips64
+include "../../../conf/GENERIC"
+maxusers 32 # Estimated number of users
+
+# Make options
+makeoption LINK_ADDRESS="0xffffffff88100000"
+# Force use of 16KB pages. The R5000 Indy, which has the infamous XKPHYS
+# coherency bug wrt ll/sc instructions, can not have more than 256MB of
+# physical memory, all of it fitting within CKSEG0.
+option PAGE_SHIFT="14"
+
+#option WSDISPLAY_COMPAT_RAWKBD # Provide raw scancodes; needed for X11
+
+# Define what targets to support
+option TGT_INDIGO # R4x00 Indigo (IP20)
+option TGT_INDIGO2 # Indigo2 (IP22/IP26/IP28)
+option TGT_INDY # Indy (IP24)
+option ARCBIOS # mandatory
+option CPU_R4000 # R4000/R4400 support (IP20/IP22/IP24)
+#option CPU_R4600 # R4600 support (IP22/IP24)
+option CPU_R5000 # R5000 support (IP24)
+
+config bsd swap generic
+
+#
+# Definition of system
+#
+mainbus0 at root
+cpu* at mainbus0
+clock0 at mainbus0
+
+int0 at mainbus0 # Interrupt Controller
+imc0 at mainbus0 # Memory Controller
+gio0 at imc0
+#eisa0 at imc0
+
+hpc0 at gio? addr 0x1fb80000
+hpc1 at gio? addr 0x1fb00000
+hpc2 at gio? addr 0x1f980000
+
+dpclock0 at hpc0 # IP20
+dsclock0 at hpc0 # IP22/24
+sq* at hpc? # On-board Ethernet or E++ adapter
+wdsc* at hpc? # On-board SCSI or GIO32 SCSI adapter
+#haltwo* at hpc? # Indy/Indigo2 Audio
+#panel* at hpc? # Indy front panel buttons
+#pckbc* at hpc? # Indy/Indigo2 keyboard and mouse
+
+zs* at hpc?
+zstty* at zs? # Serial ports
+
+#newport* at gio? # Indy Newport graphics
+#wsdisplay* at newport?
+
+#grtwo* at gio? # Express (GR2) graphics
+#wsdisplay* at grtwo?
+
+#light* at gio? # Light/Starter/Entry (LG1/LG2) graphics
+#wsdisplay* at light?
+
+scsibus* at scsi?
+sd* at scsibus?
+st* at scsibus?
+cd* at scsibus?
+ch* at scsibus?
+safte* at scsibus?
+ses* at scsibus?
+uk* at scsibus?
+
+pseudo-device crypto 1
+#pseudo-device hotplug 1 # devices hot plugging
+#pseudo-device wsmux 2 # Mouse and keyboard multiplexor
diff --git a/sys/arch/sgi/conf/RAMDISK-IP22 b/sys/arch/sgi/conf/RAMDISK-IP22
new file mode 100644
index 00000000000..91e2e00f390
--- /dev/null
+++ b/sys/arch/sgi/conf/RAMDISK-IP22
@@ -0,0 +1,95 @@
+# $OpenBSD: RAMDISK-IP22,v 1.1 2012/03/28 20:44:23 miod Exp $
+#
+# THIS KERNEL IS FOR INDIGO (IP20), INDY (IP22) AND INDIGO2 (IP24) SYSTEMS ONLY.
+
+machine sgi mips64
+
+maxusers 4
+option TIMEZONE=0 # minutes west of GMT (for)
+option DST=0 # use daylight savings rules
+
+# Make options
+makeoption LINK_ADDRESS="0xffffffff88100000"
+# Force use of 16KB pages. The R5000 Indy, which has the infamous XKPHYS
+# coherency bug wrt ll/sc instructions, can not have more than 256MB of
+# physical memory, all of it fitting within CKSEG0.
+option PAGE_SHIFT="14"
+
+option DDB
+
+# Filesystem options
+option CD9660 # ISO 9660 + Rock Ridge file system
+option FIFO # POSIX fifo support (in all filesystems)
+option FFS # fast filesystem
+#option MSDOSFS # Ability to read write MS-Dos filesystem
+option NFSCLIENT # Sun NFS-compatible filesystem (client)
+
+# Networking options
+option INET # IP + ICMP + TCP + UDP
+option INET6 # IPv6 (needs INET)
+
+# RAMDISK stuff
+option MINIROOTSIZE=10240
+option RAMDISK_HOOKS
+
+# Define what targets to support
+option TGT_INDIGO # R4x00 Indigo (IP20)
+option TGT_INDIGO2 # Indigo2 (IP22/IP26/IP28)
+option TGT_INDY # Indy (IP24)
+option ARCBIOS # mandatory
+option CPU_R4000 # R4000/R4400 support (IP20/IP22/IP24)
+#option CPU_R4600 # R4600 support (IP22/IP24)
+option CPU_R5000 # R5000 support (IP24)
+
+# Specify storage configuration using ramdisk
+config bsd root on rd0a swap on rd0b
+
+#
+# Definition of system
+#
+mainbus0 at root
+cpu* at mainbus0
+clock0 at mainbus0
+
+int0 at mainbus0 # Interrupt Controller
+imc0 at mainbus0 # Memory Controller
+gio0 at imc0
+#eisa0 at imc0
+
+hpc0 at gio? addr 0x1fb80000
+hpc1 at gio? addr 0x1fb00000
+hpc2 at gio? addr 0x1f980000
+
+dpclock0 at hpc0 # IP20
+dsclock0 at hpc0 # IP22/24
+sq* at hpc? # On-board Ethernet or E++ adapter
+wdsc* at hpc? # On-board SCSI or GIO32 SCSI adapter
+#pckbc* at hpc? # Indy/Indigo2 keyboard and mouse
+
+zs* at hpc?
+zstty* at zs? # Serial ports
+
+#newport* at gio? # Indy Newport graphics
+#wsdisplay* at newport?
+
+#grtwo* at gio? # Express (GR2) graphics
+#wsdisplay* at grtwo?
+
+#light* at gio? # Light/Starter/Entry (LG1/LG2) graphics
+#wsdisplay* at light?
+
+scsibus* at scsi?
+sd* at scsibus?
+st* at scsibus?
+cd* at scsibus?
+#ch* at scsibus?
+#uk* at scsibus?
+
+#### PSEUDO Devices
+pseudo-device loop 1 # network loopback
+pseudo-device bpfilter 1 # packet filter ports
+
+pseudo-device rd 1 # Ram disk.
+pseudo-device bio 1 # ioctl multiplexing device
+
+option BOOT_CONFIG # add support for boot -c
diff --git a/sys/arch/sgi/conf/files.sgi b/sys/arch/sgi/conf/files.sgi
index 83953010ed9..a13ff36f3c7 100644
--- a/sys/arch/sgi/conf/files.sgi
+++ b/sys/arch/sgi/conf/files.sgi
@@ -1,4 +1,4 @@
-# $OpenBSD: files.sgi,v 1.46 2011/11/15 22:27:53 deraadt Exp $
+# $OpenBSD: files.sgi,v 1.47 2012/03/28 20:44:23 miod Exp $
#
# maxpartitions must be first item in files.${ARCH}
#
@@ -14,6 +14,8 @@ file arch/sgi/sgi/bus_dma.c
file arch/sgi/sgi/conf.c
file arch/sgi/sgi/disksubr.c disk
file arch/sgi/sgi/lock_machdep.c multiprocessor
+file arch/sgi/sgi/ip22_machdep.c tgt_indigo | tgt_indigo2 |
+ tgt_indy
file arch/sgi/sgi/ip27_machdep.c tgt_origin
file arch/sgi/sgi/ip30_machdep.c tgt_octane
file arch/sgi/sgi/ip30_nmi.S tgt_octane & ddb
@@ -56,6 +58,21 @@ device clock
attach clock at mainbus
#
+# IP20/22/24 specific devices
+#
+define giobus {}
+device imc: giobus, eisabus
+attach imc at mainbus
+file arch/sgi/localbus/imc.c imc
+
+device int
+attach int at mainbus
+file arch/sgi/localbus/int.c int
+
+include "arch/sgi/gio/files.gio"
+include "arch/sgi/hpc/files.hpc"
+
+#
# O2 MACE localbus autoconfiguration devices
#
define macebus {[base = -1]}
@@ -87,6 +104,13 @@ major {cd = 3}
include "dev/i2o/files.i2o"
#
+# EISA Bus support
+#
+
+include "dev/eisa/files.eisa"
+file arch/sgi/sgi/eisa_machdep.c eisa
+
+#
# PCI Bus support
#
@@ -132,9 +156,9 @@ file arch/sgi/dev/iockbc.c iockbc |
# DS1687 Time-Of-Day calendar device
device dsrtc
-attach dsrtc at macebus with dsrtc_macebus
attach dsrtc at ioc with dsrtc_ioc
attach dsrtc at iof with dsrtc_iof
+attach dsrtc at macebus with dsrtc_macebus
file arch/sgi/dev/dsrtc.c dsrtc
# GBE framebuffer
@@ -207,4 +231,3 @@ file arch/sgi/dev/owmem_subr.c owmac | owserial
# IP35 SPD memory information
attach spdmem at mainbus with spdmem_mainbus
file arch/sgi/dev/spdmem_mainbus.c spdmem_mainbus
-
diff --git a/sys/arch/sgi/dev/dsrtc.c b/sys/arch/sgi/dev/dsrtc.c
index 7132df8e5fd..8991abfe0bf 100644
--- a/sys/arch/sgi/dev/dsrtc.c
+++ b/sys/arch/sgi/dev/dsrtc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dsrtc.c,v 1.11 2009/11/07 14:49:01 miod Exp $ */
+/* $OpenBSD: dsrtc.c,v 1.12 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -122,7 +122,7 @@ dsrtc_attach_ioc(struct device *parent, struct device *self, void *aux)
bus_space_handle_t ih, ih2;
/*
- * The IOC3 RTC is either a Dallas (now Maxim) DS1386 or compatible
+ * The IOC3 RTC is either a Dallas (now Maxim) DS1397 or compatible
* (likely a more recent DS1687), or a DS1747 or compatible
* (itself being a Mostek MK48T35 clone).
*
diff --git a/sys/arch/sgi/gio/Makefile b/sys/arch/sgi/gio/Makefile
new file mode 100644
index 00000000000..130e520dcfb
--- /dev/null
+++ b/sys/arch/sgi/gio/Makefile
@@ -0,0 +1,8 @@
+# $OpenBSD: Makefile,v 1.1 2012/03/28 20:44:23 miod Exp $
+# $NetBSD: Makefile.giodevs,v 1.5 2008/10/19 22:05:21 apb Exp $
+
+AWK= awk
+
+giodevs.h giodevs_data.h: giodevs devlist2h.awk
+ /bin/rm -f giodevs.h giodevs_data.h
+ ${AWK} -f devlist2h.awk giodevs
diff --git a/sys/arch/sgi/gio/devlist2h.awk b/sys/arch/sgi/gio/devlist2h.awk
new file mode 100644
index 00000000000..361a2eb2a25
--- /dev/null
+++ b/sys/arch/sgi/gio/devlist2h.awk
@@ -0,0 +1,152 @@
+#! /usr/bin/awk -f
+# $OpenBSD: devlist2h.awk,v 1.1 2012/03/28 20:44:23 miod Exp $
+# $NetBSD: devlist2h.awk,v 1.5 2008/05/02 18:11:05 martin Exp $
+#
+# Copyright (c) 1998 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# This code is derived from software contributed to The NetBSD Foundation
+# by Christos Zoulas.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# Copyright (c) 1995, 1996 Christopher G. Demetriou
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Christopher G. Demetriou.
+# This product includes software developed by Christos Zoulas
+# 4. The name of the author(s) may not be used to endorse or promote products
+# derived from this software without specific prior written permission
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+function collectline(_f, _line) {
+ _oparen = 0
+ _line = ""
+ while (_f <= NF) {
+ if ($_f == "#") {
+ _line = _line "("
+ _oparen = 1
+ _f++
+ continue
+ }
+ if (_oparen) {
+ _line = _line $_f
+ if (_f < NF)
+ _line = _line " "
+ _f++
+ continue
+ }
+ _line = _line $_f
+ if (_f < NF)
+ _line = _line " "
+ _f++
+ }
+ if (_oparen)
+ _line = _line ")"
+ return _line
+}
+BEGIN {
+ nproducts = nvendors = blanklines = 0
+ dfile="giodevs_data.h"
+ hfile="giodevs.h"
+ line=""
+}
+NR == 1 {
+ VERSION = $0
+ gsub("\\$", "", VERSION)
+
+ printf("/*\n") > hfile
+ printf(" * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT.\n") \
+ > hfile
+ printf(" *\n") > hfile
+ printf(" * generated from:\n") > hfile
+ printf(" *\t%s\n", VERSION) > hfile
+ printf(" */\n\n") > hfile
+
+ printf("/*\n") > dfile
+ printf(" * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT.\n") \
+ > dfile
+ printf(" *\n") > dfile
+ printf(" * generated from:\n") > dfile
+ printf(" *\t%s\n", VERSION) > dfile
+ printf(" */\n\n") > dfile
+
+ next
+}
+NF > 0 && $1 == "product" {
+ nproducts++
+
+ products[nproducts, 1] = $2;
+ products[nproducts, 2] = $3
+ products[nproducts, 3] = collectline(4, line)
+
+ next
+}
+{
+ if ($0 == "")
+ blanklines++
+ if (blanklines < 2)
+ print $0 > dfile
+}
+END {
+ # print out the match tables
+
+ printf("\n") > dfile
+
+ printf("struct gio_knowndev {\n") > dfile
+ printf("\tint productid;\n") > dfile
+ printf("\tconst char *product;\n") > dfile
+ printf("};\n") > dfile
+ printf("\nstruct gio_knowndev gio_knowndevs[] = {\n") > dfile
+
+ printf("\n") > hfile
+ for (i = 1; i <= nproducts; i++) {
+ printf("#define %s\t%s\t/* %s */\n", products[i, 1], products[i,2], products[i, 3]) > hfile
+
+ printf("\t{ %s, \"%s\" },\n",
+ products[i, 2], products[i, 3]) > dfile
+ }
+ printf("\t{ 0, NULL }\n") > dfile
+ printf("};\n") > dfile
+ close(dfile)
+ close(hfile)
+}
diff --git a/sys/arch/sgi/gio/files.gio b/sys/arch/sgi/gio/files.gio
new file mode 100644
index 00000000000..fe393862625
--- /dev/null
+++ b/sys/arch/sgi/gio/files.gio
@@ -0,0 +1,31 @@
+# $OpenBSD: files.gio,v 1.1 2012/03/28 20:44:23 miod Exp $
+# $NetBSD: files.gio,v 1.11 2009/02/12 06:33:57 rumble Exp $
+
+device gio {[slot = -1], [addr = -1]}
+attach gio at giobus
+
+file arch/sgi/gio/gio.c gio needs-flag
+
+device hpc {[offset = -1]}: smc93cx6
+attach hpc at gio
+file arch/sgi/hpc/hpc.c hpc
+
+# XL graphics
+device newport: wsemuldisplaydev, rasops8
+attach newport at gio
+file arch/sgi/gio/newport.c newport needs-flag
+
+# GR2 graphics
+device grtwo: wsemuldisplaydev
+attach grtwo at gio
+file arch/sgi/gio/grtwo.c grtwo needs-flag
+
+# LG1/LG2 graphics
+device light: wsemuldisplaydev
+attach light at gio
+file arch/sgi/gio/light.c light needs-flag
+
+# PCI cards glued to the GIO bus
+device giopci: pcibus
+attach giopci at gio
+file arch/sgi/gio/pci_gio.c giopci
diff --git a/sys/arch/sgi/gio/gio.c b/sys/arch/sgi/gio/gio.c
new file mode 100644
index 00000000000..b201adab5b9
--- /dev/null
+++ b/sys/arch/sgi/gio/gio.c
@@ -0,0 +1,518 @@
+/* $OpenBSD: gio.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: gio.c,v 1.32 2011/07/01 18:53:46 dyoung Exp $ */
+
+/*
+ * Copyright (c) 2000 Soren S. Jorvang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the
+ * NetBSD Project. See http://www.NetBSD.org/ for
+ * information about NetBSD.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <mips64/archtype.h>
+
+#include <machine/autoconf.h>
+#include <machine/bus.h>
+
+#include <sgi/gio/gioreg.h>
+#include <sgi/gio/giovar.h>
+#include <sgi/gio/giodevs_data.h>
+
+#include <sgi/localbus/imcvar.h>
+#include <sgi/localbus/intvar.h>
+#include <sgi/sgi/ip22.h>
+
+int gio_match(struct device *, void *, void *);
+void gio_attach(struct device *, struct device *, void *);
+int gio_print(void *, const char *);
+int gio_print_fb(void *, const char *);
+int gio_search(struct device *, void *, void *);
+int gio_submatch(struct device *, void *, void *);
+uint32_t gio_id(paddr_t, int);
+
+struct gio_softc {
+ struct device sc_dev;
+
+ bus_space_tag_t sc_iot;
+ bus_dma_tag_t sc_dmat;
+};
+
+const struct cfattach gio_ca = {
+ sizeof(struct gio_softc), gio_match, gio_attach
+};
+
+struct cfdriver gio_cd = {
+ NULL, "gio", DV_DULL
+};
+
+struct gio_probe {
+ uint32_t slot;
+ uint64_t base;
+ uint32_t mach_type;
+ uint32_t mach_subtype;
+};
+
+/*
+ * Expansion Slot Base Addresses
+ *
+ * IP12, IP20 and IP24 have two GIO connectors: GIO_SLOT_EXP0 and
+ * GIO_SLOT_EXP1.
+ *
+ * On IP24 these slots exist on the graphics board or the IOPLUS
+ * "mezzanine" on Indy and Challenge S, respectively. The IOPLUS or
+ * graphics board connects to the mainboard via a single GIO64 connector.
+ *
+ * IP22 has either three or four physical connectors, but only two
+ * electrically distinct slots: GIO_SLOT_GFX and GIO_SLOT_EXP0.
+ *
+ * It should also be noted that DMA is (mostly) not supported in Challenge S's
+ * GIO_SLOT_EXP1. See gio(4) for the story.
+ */
+static const struct gio_probe slot_bases[] = {
+ { GIO_SLOT_GFX, 0x1f000000, SGI_IP22, IP22_INDIGO2 },
+
+ { GIO_SLOT_EXP0, 0x1f400000, SGI_IP20, -1 },
+ { GIO_SLOT_EXP0, 0x1f400000, SGI_IP22, -1 },
+
+ { GIO_SLOT_EXP1, 0x1f600000, SGI_IP20, -1 },
+ { GIO_SLOT_EXP1, 0x1f600000, SGI_IP22, IP22_INDY },
+
+ { 0, 0, 0, 0 }
+};
+
+/*
+ * Graphic Board Base Addresses
+ *
+ * Graphics boards are not treated like expansion slot cards. Their base
+ * addresses do not necessarily correspond to GIO slot addresses and they
+ * do not contain product identification words.
+ */
+static const struct gio_probe gfx_bases[] = {
+ /* grtwo, and newport on IP22 */
+ { -1, 0x1f000000, SGI_IP20, -1 },
+ { -1, 0x1f000000, SGI_IP22, -1 },
+
+ /* light */
+ { -1, 0x1f3f0000, SGI_IP20, -1 },
+
+ /* light (dual headed) */
+ { -1, 0x1f3f8000, SGI_IP20, -1 },
+
+ /* grtwo, and newport on IP22 */
+ { -1, 0x1f400000, SGI_IP20, -1 },
+ { -1, 0x1f400000, SGI_IP22, -1 },
+
+ /* grtwo */
+ { -1, 0x1f600000, SGI_IP20, -1 },
+ { -1, 0x1f600000, SGI_IP22, -1 },
+
+ /* newport */
+ { -1, 0x1f800000, SGI_IP22, IP22_INDIGO2 },
+
+ /* newport */
+ { -1, 0x1fc00000, SGI_IP22, IP22_INDIGO2 },
+
+ { 0, 0, 0, 0 }
+};
+
+/* maximum number of graphics boards possible (arbitrarily large estimate) */
+#define MAXGFX (nitems(gfx_bases) - 1)
+
+int
+gio_match(struct device *parent, void *match, void *aux)
+{
+ struct imc_attach_args *iaa = aux;
+
+ if (strcmp(iaa->iaa_name, gio_cd.cd_name) != 0)
+ return 0;
+
+ return 1;
+}
+
+void
+gio_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct gio_softc *sc = (struct gio_softc *)self;
+ struct imc_attach_args *iaa = (struct imc_attach_args *)aux;
+ struct gio_attach_args ga;
+ uint32_t gfx[MAXGFX];
+ uint i, j, ngfx;
+
+ printf("\n");
+
+ sc->sc_iot = iaa->iaa_st;
+ sc->sc_dmat = iaa->iaa_dmat;
+
+ ngfx = 0;
+ memset(gfx, 0, sizeof(gfx));
+
+ /*
+ * Try and attach graphics devices first.
+ * Unfortunately, they - not being GIO devices after all - do not
+ * contain a Product Identification Word, nor have a slot number.
+ *
+ * Record addresses to which graphics devices attach so that
+ * we do not confuse them with expansion slots, should the
+ * addresses coincide.
+ *
+ * Unfortunately graphics devices for which we have no configured
+ * driver, which address matches a regular slot number, will show
+ * up as rogue devices attached to real slots.
+ *
+ * If only the ARCBios component tree would be so kind as to give
+ * us the address of the frame buffer components...
+ */
+ for (i = 0; gfx_bases[i].base != 0; i++) {
+ /* skip slots that don't apply to us */
+ if (gfx_bases[i].mach_type != sys_config.system_type)
+ continue;
+
+ if (gfx_bases[i].mach_subtype != -1 &&
+ gfx_bases[i].mach_subtype != sys_config.system_subtype)
+ continue;
+
+ ga.ga_slot = -1;
+ ga.ga_addr = gfx_bases[i].base;
+ ga.ga_iot = sc->sc_iot;
+ ga.ga_ioh = PHYS_TO_XKPHYS(ga.ga_addr, CCA_NC);
+ ga.ga_dmat = sc->sc_dmat;
+ ga.ga_product = -1;
+
+ if (gio_id(ga.ga_ioh, 1) == 0)
+ continue;
+
+ if (config_found_sm(self, &ga, gio_print_fb, gio_submatch)) {
+ gfx[ngfx++] = gfx_bases[i].base;
+ }
+ }
+
+ /*
+ * Now attach any GIO expansion cards.
+ *
+ * Be sure to skip any addresses to which a graphics device has
+ * already been attached.
+ */
+ for (i = 0; slot_bases[i].base != 0; i++) {
+ int skip = 0;
+
+ /* skip slots that don't apply to us */
+ if (slot_bases[i].mach_type != sys_config.system_type)
+ continue;
+
+ if (slot_bases[i].mach_subtype != -1 &&
+ slot_bases[i].mach_subtype != sys_config.system_subtype)
+ continue;
+
+ for (j = 0; j < ngfx; j++) {
+ if (slot_bases[i].base == gfx[j]) {
+ skip = 1;
+ break;
+ }
+ }
+ if (skip)
+ continue;
+
+ ga.ga_slot = slot_bases[i].slot;
+ ga.ga_addr = slot_bases[i].base;
+ ga.ga_iot = sc->sc_iot;
+ ga.ga_ioh = PHYS_TO_XKPHYS(ga.ga_addr, CCA_NC);
+ ga.ga_dmat = sc->sc_dmat;
+
+ if (gio_id(ga.ga_ioh, 0) == 0)
+ continue;
+
+ ga.ga_product = bus_space_read_4(ga.ga_iot, ga.ga_ioh, 0);
+
+ config_found_sm(self, &ga, gio_print, gio_submatch);
+ }
+
+ config_search(gio_search, self, aux);
+}
+
+/*
+ * Try and figure out whether there is a device at the given slot address.
+ */
+uint32_t
+gio_id(paddr_t pa, int maybe_gfx)
+{
+ uint32_t id32;
+ uint16_t id16 = 0;
+ uint8_t id8 = 0;
+
+ if (guarded_read_4(pa, &id32) != 0)
+ return 0;
+
+ id16 = id32 ^ 0xffff;
+ (void)guarded_read_2(pa | 2, &id16);
+ id8 = id16 ^ 0xff;
+ (void)guarded_read_1(pa | 3, &id8);
+
+ /*
+ * If there is a real GIO device at this address (as opposed to
+ * a graphics card), then the low-order 8 bits of each read need
+ * to be consistent...
+ */
+ if (id8 == (id16 & 0xff) && id8 == (id32 & 0xff)) {
+ if (GIO_PRODUCT_32BIT_ID(id8)) {
+ if (id16 == (id32 & 0xffff))
+ return id32;
+ } else {
+ if (id8 != 0)
+ return id32;
+ }
+ }
+
+ if (maybe_gfx)
+ return 1;
+
+ return 0;
+}
+
+int
+gio_print(void *aux, const char *pnp)
+{
+ struct gio_attach_args *ga = aux;
+ const char *descr;
+ int product, revision;
+ uint i;
+
+ product = GIO_PRODUCT_PRODUCTID(ga->ga_product);
+ if (GIO_PRODUCT_32BIT_ID(ga->ga_product))
+ revision = GIO_PRODUCT_REVISION(ga->ga_product);
+ else
+ revision = 0;
+
+ descr = "unknown GIO card";
+ for (i = 0; gio_knowndevs[i].productid != 0; i++) {
+ if (gio_knowndevs[i].productid == product) {
+ descr = gio_knowndevs[i].product;
+ break;
+ }
+ }
+
+ if (pnp != NULL) {
+ printf("%s", descr);
+ if (ga->ga_product != -1)
+ printf(" (product 0x%02x revision 0x%02x)",
+ product, revision);
+ printf(" at %s", pnp);
+ }
+
+ if (ga->ga_slot != -1)
+ printf(" slot %d", ga->ga_slot);
+ printf(" addr 0x%lx", ga->ga_addr);
+
+ return UNCONF;
+}
+
+int
+gio_print_fb(void *aux, const char *pnp)
+{
+#if 0 /* once we can know for sure there really is a frame buffer here */
+ if (pnp != NULL)
+ printf("framebuffer at %s", pnp);
+
+ if (ga->ga_addr != (uint64_t)-1)
+ printf(" addr 0x%lx", ga->ga_addr);
+
+ return UNCONF;
+#else
+ return QUIET;
+#endif
+}
+
+int
+gio_search(struct device *parent, void *vcf, void *aux)
+{
+ struct gio_softc *sc = (struct gio_softc *)parent;
+ struct cfdata *cf = (struct cfdata *)vcf;
+ struct gio_attach_args ga;
+
+ /* Handled by direct configuration, so skip here */
+ if (cf->cf_loc[1 /*GIOCF_ADDR*/] == -1)
+ return 0;
+
+ ga.ga_product = -1;
+ ga.ga_slot = cf->cf_loc[0 /*GIOCF_SLOT*/];
+ ga.ga_addr = (uint64_t)cf->cf_loc[1 /*GIOCF_ADDR*/];
+ ga.ga_iot = sc->sc_iot;
+ ga.ga_ioh = PHYS_TO_XKPHYS(ga.ga_addr, CCA_NC);
+ ga.ga_dmat = sc->sc_dmat;
+
+ if ((*cf->cf_attach->ca_match)(parent, cf, &ga) == 0)
+ return 0;
+
+ config_attach(parent, cf, &ga, gio_print);
+
+ return 1;
+}
+
+int
+gio_submatch(struct device *parent, void *vcf, void *aux)
+{
+ struct cfdata *cf = (struct cfdata *)vcf;
+ struct gio_attach_args *ga = (struct gio_attach_args *)aux;
+
+ if (cf->cf_loc[0 /*GIOCF_SLOT*/] != -1 &&
+ cf->cf_loc[0 /*GIOCF_SLOT*/] != ga->ga_slot)
+ return 0;
+
+ if (cf->cf_loc[1 /*GIOCF_ADDR*/] != -1 &&
+ (uint64_t)cf->cf_loc[1 /*GIOCF_ADDR*/] != ga->ga_addr)
+ return 0;
+
+ return (*cf->cf_attach->ca_match)(parent, cf, aux);
+}
+
+#if 0 /* XXX involve wscons_machdep somehow */
+int
+gio_cnattach(void)
+{
+ extern struct machine_bus_dma_tag imc_bus_dma_tag; /* XXX */
+ extern bus_space_t imcbus_tag; /* XXX */
+ struct gio_attach_args ga;
+ uint32_t dummy;
+ int i;
+
+ for (i = 0; gfx_bases[i].base != 0; i++) {
+ /* skip bases that don't apply to us */
+ if (gfx_bases[i].mach_type != sys_config.system_type)
+ continue;
+
+ if (gfx_bases[i].mach_subtype != -1 &&
+ gfx_bases[i].mach_subtype != sys_config.system_subtype)
+ continue;
+
+ ga.ga_slot = -1;
+ ga.ga_addr = gfx_bases[i].base;
+ ga.ga_iot = &imcbus_tag; /* XXX */
+ ga.ga_ioh = PHYS_TO_XKPHYS(ga.ga_addr, CCA_NC);
+ ga.ga_dmat = &imc_bus_dma_tag; /* XXX */
+ ga.ga_product = -1;
+
+ if (gio_id(ga.ga_ioh, 1) == 0)
+ continue;
+
+#if NGRTWO > 0
+ if (grtwo_cnattach(&ga) == 0)
+ return 0;
+#endif
+
+#if NLIGHT > 0
+ if (light_cnattach(&ga) == 0)
+ return 0;
+#endif
+
+#if NNEWPORT > 0
+ if (newport_cnattach(&ga) == 0)
+ return 0;
+#endif
+
+ }
+
+ return ENXIO;
+}
+#endif
+
+/*
+ * Devices living in the expansion slots must enable or disable some
+ * GIO arbiter settings. This is accomplished via imc(4) registers.
+ */
+int
+gio_arb_config(int slot, uint32_t flags)
+{
+ if (flags == 0)
+ return (EINVAL);
+
+ if (flags & ~(GIO_ARB_RT | GIO_ARB_LB | GIO_ARB_MST | GIO_ARB_SLV |
+ GIO_ARB_PIPE | GIO_ARB_NOPIPE | GIO_ARB_32BIT | GIO_ARB_64BIT |
+ GIO_ARB_HPC2_32BIT | GIO_ARB_HPC2_64BIT))
+ return (EINVAL);
+
+ if (((flags & GIO_ARB_RT) && (flags & GIO_ARB_LB)) ||
+ ((flags & GIO_ARB_MST) && (flags & GIO_ARB_SLV)) ||
+ ((flags & GIO_ARB_PIPE) && (flags & GIO_ARB_NOPIPE)) ||
+ ((flags & GIO_ARB_32BIT) && (flags & GIO_ARB_64BIT)) ||
+ ((flags & GIO_ARB_HPC2_32BIT) && (flags & GIO_ARB_HPC2_64BIT)))
+ return (EINVAL);
+
+ return (imc_gio64_arb_config(slot, flags));
+}
+
+/*
+ * Establish an interrupt handler for the specified slot.
+ *
+ * Indy and Challenge S have an interrupt per GIO slot. Indigo and Indigo2
+ * share a single interrupt, however.
+ */
+void *
+gio_intr_establish(int slot, int level, int (*func)(void *), void *arg,
+ const char *what)
+{
+ int intr;
+
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ if (slot == GIO_SLOT_GFX)
+ return NULL;
+ intr = 6;
+ break;
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ if (sys_config.system_subtype == IP22_INDIGO2) {
+ if (slot == GIO_SLOT_EXP1)
+ return NULL;
+ intr = 6;
+ } else {
+ if (slot == GIO_SLOT_GFX)
+ return NULL;
+ intr = (slot == GIO_SLOT_EXP0) ? 22 : 23;
+ }
+ break;
+ default:
+ return NULL;
+ }
+
+ return int2_intr_establish(intr, level, func, arg, what);
+}
+
+const char *
+gio_product_string(int prid)
+{
+ int i;
+
+ for (i = 0; gio_knowndevs[i].product != NULL; i++)
+ if (gio_knowndevs[i].productid == prid)
+ return (gio_knowndevs[i].product);
+
+ return (NULL);
+}
diff --git a/sys/arch/sgi/gio/giodevs b/sys/arch/sgi/gio/giodevs
new file mode 100644
index 00000000000..8189affed20
--- /dev/null
+++ b/sys/arch/sgi/gio/giodevs
@@ -0,0 +1,21 @@
+$OpenBSD: giodevs,v 1.1 2012/03/28 20:44:23 miod Exp $
+/* $NetBSD: giodevs,v 1.8 2007/02/19 04:46:33 rumble Exp $ */
+
+product XPI 0x01 XPI low cost FDDI
+product GTR 0x02 GTR TokenRing
+product ISDN 0x04 Synchronous ISDN
+product CANON 0x06 Canon Interface
+product JPEG_D 0x08 JPEG (Double Wide)
+product JPEG_S 0x09 JPEG (Single Wide)
+product XPI_M0 0x0a XPI mez. FDDI device 0
+product XPI_M1 0x0b XPI mez. FDDI device 1
+product EP 0x0e E-Plex 8-port Ethernet
+product IVAS 0x30 Lyon Lamb IVAS
+product PHOBOS_G160 0x35 Phobos G160 10/100 Ethernet
+product PHOBOS_G130 0x36 Phobos G130 10/100 Ethernet
+product PHOBOS_G100 0x37 Phobos G100 100baseTX Fast Ethernet
+product SETENG_GFE 0x38 Set Engineering GFE 10/100 Ethernet
+product ATM 0x85 ATM board
+product SCSI 0x87 16 bit SCSI Card
+product SMPTE 0x8c SMPTE 259M Video
+product BABBLE 0x8d Babblefish Compression
diff --git a/sys/arch/sgi/gio/gioreg.h b/sys/arch/sgi/gio/gioreg.h
new file mode 100644
index 00000000000..a5bf76444e3
--- /dev/null
+++ b/sys/arch/sgi/gio/gioreg.h
@@ -0,0 +1,68 @@
+/* $OpenBSD: gioreg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: gioreg.h,v 1.4 2006/08/31 00:01:10 rumble Exp $ */
+
+/*
+ * Copyright (c) 2003 Ilpo Ruotsalainen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * <<Id: LICENSE_GC,v 1.1 2001/10/01 23:24:05 cgd Exp>>
+ */
+
+/*
+ * The GIO Product Identification Word is the first word (1 or 4 bytes)
+ * in each GIO device's address space. It is the same format for GIO32,
+ * GIO32-bis, and GIO64 devices. The macros below extract the following
+ * fields:
+ *
+ * Bits:
+ * 0-6 Product ID Code
+ * 7 Product Identification Word size (0: 8 bits, 1: 32 bits)
+ * 8-15 Product Revision
+ * 16 GIO Interface Size (0: 32, 1: 64; NB: GIO64 devices may be 32)
+ * 17 Rom Present (1: present)
+ * 18-31 Manufacturer-specific Code
+ *
+ * The upper three bytes containing the Product Revision, GIO Interface
+ * Size, Rom Presence indicator, and Manufacturer-specific Code are only
+ * valid if bit 7 is set in the Product ID Word. If it is not set, all
+ * values default to 0.
+ *
+ * If the Rom Present bit is set, the three words after the Product ID are
+ * reserved for three ROM registers:
+ * Board Serial Number Register (base_address + 0x4)
+ * ROM Index Register (base_address + 0x8)
+ * ROM Read Register (base_address + 0xc)
+ *
+ * The ROM Index Register is initialised by the CPU to 0 and incremented by
+ * 4 on each read from the ROM Read Register. The Board Serial Number
+ * Register contains a manufacturer-specific serial number.
+ */
+
+#define GIO_PRODUCT_32BIT_ID(x) ((x) & 0x80)
+#define GIO_PRODUCT_PRODUCTID(x) ((x) & 0x7f)
+#define GIO_PRODUCT_REVISION(x) (((x) >> 8) & 0xff)
+#define GIO_PRODUCT_IS_64BIT(x) (!!((x) & 0x8000))
+#define GIO_PRODUCT_HAS_ROM(x) (!!((x) & 0x10000))
+#define GIO_PRODUCT_MANUCODE(x) ((x) >> 18)
diff --git a/sys/arch/sgi/gio/giovar.h b/sys/arch/sgi/gio/giovar.h
new file mode 100644
index 00000000000..6c35c7561da
--- /dev/null
+++ b/sys/arch/sgi/gio/giovar.h
@@ -0,0 +1,75 @@
+/* $OpenBSD: giovar.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: giovar.h,v 1.10 2011/07/01 18:53:46 dyoung Exp $ */
+
+/*
+ * Copyright (c) 2000 Soren S. Jorvang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the
+ * NetBSD Project. See http://www.NetBSD.org/ for
+ * information about NetBSD.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * GIO 32/32-bis/64 bus
+ */
+
+struct gio_attach_args {
+ bus_space_tag_t ga_iot;
+ bus_space_handle_t ga_ioh;
+ bus_dma_tag_t ga_dmat;
+
+ int ga_slot; /* not valid if graphics */
+ u_int64_t ga_addr;
+
+ u_int32_t ga_product; /* not valid if graphics */
+};
+
+
+#define GIO_SLOT_GFX 0
+#define GIO_SLOT_EXP0 1
+#define GIO_SLOT_EXP1 2
+
+#define GIO_ARB_RT 0x001 /* real-time device */
+#define GIO_ARB_LB 0x002 /* long-burst device */
+
+#define GIO_ARB_MST 0x004 /* bus master enable */
+#define GIO_ARB_SLV 0x008 /* slave */
+
+#define GIO_ARB_PIPE 0x010 /* pipelining enable */
+#define GIO_ARB_NOPIPE 0x020 /* pipelining disable */
+
+#define GIO_ARB_32BIT 0x040 /* 32-bit transfers */
+#define GIO_ARB_64BIT 0x080 /* 64-bit transfers */
+
+#define GIO_ARB_HPC2_32BIT 0x100 /* 32-bit secondary HPC (ignores slot)*/
+#define GIO_ARB_HPC2_64BIT 0x200 /* 64-bit secondary HPC (ignores slot)*/
+
+int gio_cnattach(void);
+int gio_arb_config(int, uint32_t);
+void *gio_intr_establish(int, int, int (*)(void *), void *,
+ const char *);
+const char *gio_product_string(int);
diff --git a/sys/arch/sgi/hpc/dpclock.c b/sys/arch/sgi/hpc/dpclock.c
new file mode 100644
index 00000000000..600c3ede567
--- /dev/null
+++ b/sys/arch/sgi/hpc/dpclock.c
@@ -0,0 +1,312 @@
+/* $OpenBSD: dpclock.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: dpclock.c,v 1.3 2011/07/01 18:53:46 dyoung Exp $ */
+
+/*
+ * Copyright (c) 2012 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * Copyright (c) 2001 Erik Reid
+ * Copyright (c) 2001 Rafal K. Boni
+ * Copyright (c) 2001 Christopher Sekiya
+ * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Portions of this code are derived from software contributed to The
+ * NetBSD Foundation by Jason R. Thorpe of the Numerical Aerospace
+ * Simulation Facility, NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1982, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Utah $Hdr: clock.c 1.18 91/01/21$
+ *
+ * @(#)clock.c 8.2 (Berkeley) 1/12/94
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/autoconf.h>
+#include <machine/bus.h>
+
+#include <mips64/archtype.h>
+#include <mips64/dev/clockvar.h>
+
+#include <dev/ic/dp8573areg.h>
+#include <sgi/hpc/hpcvar.h>
+
+#define IRIX_BASE_YEAR 1940
+
+struct dpclock_softc {
+ struct device sc_dev;
+
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+};
+
+int dpclock_match(struct device *, void *, void *);
+void dpclock_attach(struct device *, struct device *, void *);
+
+struct cfdriver dpclock_cd = {
+ NULL, "dpclock", DV_DULL
+};
+
+const struct cfattach dpclock_ca = {
+ sizeof(struct dpclock_softc), dpclock_match, dpclock_attach
+};
+
+#define dpclock_read(sc,r) \
+ bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, ((r) << 2) + 3)
+#define dpclock_write(sc,r,v) \
+ bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, ((r) << 2) + 3, (v))
+
+static inline int frombcd(int);
+static inline int tobcd(int);
+static inline int leapyear(int year);
+
+static inline int
+frombcd(int x)
+{
+ return (x >> 4) * 10 + (x & 0xf);
+}
+static inline int
+tobcd(int x)
+{
+ return (x / 10 * 16) + (x % 10);
+}
+/*
+ * This inline avoids some unnecessary modulo operations
+ * as compared with the usual macro:
+ * ( ((year % 4) == 0 &&
+ * (year % 100) != 0) ||
+ * ((year % 400) == 0) )
+ * It is otherwise equivalent.
+ * (borrowed from kern/clock_subr.c)
+ */
+static inline int
+leapyear(int year)
+{
+ int rv = 0;
+
+ if ((year & 3) == 0) {
+ rv = 1;
+ if ((year % 100) == 0) {
+ rv = 0;
+ if ((year % 400) == 0)
+ rv = 1;
+ }
+ }
+ return (rv);
+}
+
+void dpclock_gettime(void *, time_t, struct tod_time *);
+void dpclock_settime(void *, struct tod_time *);
+
+int
+dpclock_match(struct device *parent, void *vcf, void *aux)
+{
+ struct hpc_attach_args *haa = aux;
+
+ if (strcmp(haa->ha_name, dpclock_cd.cd_name) != 0)
+ return 0;
+
+ return 1;
+}
+
+void
+dpclock_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct dpclock_softc *sc = (void *)self;
+ struct hpc_attach_args *haa = aux;
+ uint8_t st, r;
+
+ sc->sc_iot = haa->ha_st;
+ if (bus_space_subregion(haa->ha_st, haa->ha_sh, haa->ha_devoff,
+ 4 * DP8573A_NREG, &sc->sc_ioh) != 0) {
+ printf(": can't map registers\n");
+ return;
+ }
+
+ st = dpclock_read(sc, DP8573A_STATUS);
+ dpclock_write(sc, DP8573A_STATUS, st | DP8573A_STATUS_REGSEL);
+ r = dpclock_read(sc, DP8573A_RT_MODE);
+ if ((r & DP8573A_RT_MODE_CLKSS) == 0) {
+ printf(": clock stopped");
+ dpclock_write(sc, DP8573A_RT_MODE, r | DP8573A_RT_MODE_CLKSS);
+ dpclock_write(sc, DP8573A_INT0_CTL, 0);
+ dpclock_write(sc, DP8573A_INT1_CTL, DP8573A_INT1_CTL_PWRINT);
+ }
+ dpclock_write(sc, DP8573A_STATUS, st & ~DP8573A_STATUS_REGSEL);
+ r = dpclock_read(sc, DP8573A_PFLAG);
+ if (r & DP8573A_PFLAG_TESTMODE) {
+ dpclock_write(sc, DP8573A_RAM_1F, 0);
+ dpclock_write(sc, DP8573A_PFLAG, r & ~DP8573A_PFLAG_TESTMODE);
+ }
+
+ printf("\n");
+
+ sys_tod.tod_get = dpclock_gettime;
+ sys_tod.tod_set = dpclock_settime;
+ sys_tod.tod_cookie = self;
+}
+
+/*
+ * Get the time of day, based on the clock's value and/or the base value.
+ */
+void
+dpclock_gettime(void *cookie, time_t base, struct tod_time *ct)
+{
+ struct dpclock_softc *sc = (void *)cookie;
+ uint i;
+ uint8_t regs[DP8573A_NREG];
+
+ i = dpclock_read(sc, DP8573A_TIMESAVE_CTL);
+ dpclock_write(sc, DP8573A_TIMESAVE_CTL, i | DP8573A_TIMESAVE_CTL_EN);
+ dpclock_write(sc, DP8573A_TIMESAVE_CTL, i);
+
+ for (i = 0; i < DP8573A_NREG; i++)
+ regs[i] = dpclock_read(sc, i);
+
+ ct->sec = frombcd(regs[DP8573A_SAVE_SEC]);
+ ct->min = frombcd(regs[DP8573A_SAVE_MIN]);
+
+ if (regs[DP8573A_RT_MODE] & DP8573A_RT_MODE_1224) {
+ ct->hour = frombcd(regs[DP8573A_SAVE_HOUR] &
+ DP8573A_HOUR_12HR_MASK) +
+ ((regs[DP8573A_SAVE_HOUR] & DP8573A_RT_MODE_1224) ? 0 : 12);
+
+ /*
+ * In AM/PM mode, hour range is 01-12, so adding in 12 hours
+ * for PM gives us 01-24, whereas we want 00-23, so map hour
+ * 24 to hour 0.
+ */
+ if (ct->hour == 24)
+ ct->hour = 0;
+ } else {
+ ct->hour = frombcd(regs[DP8573A_SAVE_HOUR] &
+ DP8573A_HOUR_24HR_MASK);
+ }
+
+ ct->day = frombcd(regs[DP8573A_SAVE_DOM]);
+ ct->mon = frombcd(regs[DP8573A_SAVE_MONTH]);
+ ct->year = frombcd(regs[DP8573A_YEAR]) + (IRIX_BASE_YEAR - 1900);
+}
+
+/*
+ * Reset the TODR based on the time value.
+ */
+void
+dpclock_settime(void *cookie, struct tod_time *ct)
+{
+ struct dpclock_softc *sc = (void *)cookie;
+ uint i;
+ uint st, r, delta;
+ uint8_t regs[DP8573A_NREG];
+
+ r = dpclock_read(sc, DP8573A_TIMESAVE_CTL);
+ dpclock_write(sc, DP8573A_TIMESAVE_CTL, r | DP8573A_TIMESAVE_CTL_EN);
+ dpclock_write(sc, DP8573A_TIMESAVE_CTL, r);
+
+ for (i = 0; i < DP8573A_NREG; i++)
+ regs[i] = dpclock_read(sc, i);
+
+ regs[DP8573A_SUBSECOND] = 0;
+ regs[DP8573A_SECOND] = tobcd(ct->sec);
+ regs[DP8573A_MINUTE] = tobcd(ct->min);
+ regs[DP8573A_HOUR] = tobcd(ct->hour) & DP8573A_HOUR_24HR_MASK;
+ regs[DP8573A_DOW] = tobcd(ct->dow);
+ regs[DP8573A_DOM] = tobcd(ct->day);
+ regs[DP8573A_MONTH] = tobcd(ct->mon);
+ regs[DP8573A_YEAR] = tobcd(ct->year - (IRIX_BASE_YEAR - 1900));
+
+ st = dpclock_read(sc, DP8573A_STATUS);
+ dpclock_write(sc, DP8573A_STATUS, st | DP8573A_STATUS_REGSEL);
+ r = dpclock_read(sc, DP8573A_RT_MODE);
+ dpclock_write(sc, DP8573A_RT_MODE, r & ~DP8573A_RT_MODE_CLKSS);
+
+ for (i = 0; i < 10; i++)
+ dpclock_write(sc, DP8573A_COUNTERS + i,
+ regs[DP8573A_COUNTERS + i]);
+
+ /*
+ * We now need to set the leap year counter to the correct value.
+ * Unfortunately it is only two bits wide, while eight years can
+ * happen between two leap years. Skirting this is left as an
+ * exercise to the reader with an Indigo in working condition
+ * by year 2100.
+ */
+ delta = 0;
+ while (delta < 3 && !leapyear(ct->year - delta))
+ delta++;
+
+ r &= ~(DP8573A_RT_MODE_LYLSB | DP8573A_RT_MODE_LYMSB);
+ dpclock_write(sc, DP8573A_RT_MODE, r | delta | DP8573A_RT_MODE_CLKSS);
+
+ dpclock_write(sc, DP8573A_STATUS, st & ~DP8573A_STATUS_REGSEL);
+}
diff --git a/sys/arch/sgi/hpc/dsclock.c b/sys/arch/sgi/hpc/dsclock.c
new file mode 100644
index 00000000000..396d68ec9d9
--- /dev/null
+++ b/sys/arch/sgi/hpc/dsclock.c
@@ -0,0 +1,192 @@
+/* $OpenBSD: dsclock.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: dsclock.c,v 1.5 2011/07/01 18:53:46 dyoung Exp $ */
+
+/*
+ * Copyright (c) 2001 Rafal K. Boni
+ * Copyright (c) 2001 Christopher Sekiya
+ * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Portions of this code are derived from software contributed to The
+ * NetBSD Foundation by Jason R. Thorpe of the Numerical Aerospace
+ * Simulation Facility, NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/autoconf.h>
+#include <machine/bus.h>
+
+#include <mips64/archtype.h>
+#include <mips64/dev/clockvar.h>
+
+#include <dev/ic/ds1286reg.h>
+#include <sgi/hpc/hpcvar.h>
+
+#define IRIX_BASE_YEAR 1940
+
+struct dsclock_softc {
+ struct device sc_dev;
+
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+};
+
+int dsclock_match(struct device *, void *, void *);
+void dsclock_attach(struct device *, struct device *, void *);
+
+struct cfdriver dsclock_cd = {
+ NULL, "dsclock", DV_DULL
+};
+
+const struct cfattach dsclock_ca = {
+ sizeof(struct dsclock_softc), dsclock_match, dsclock_attach
+};
+
+#define ds1286_read(sc,r) \
+ bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, ((r) << 2) + 3)
+#define ds1286_write(sc,r,v) \
+ bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, ((r) << 2) + 3, (v))
+
+static inline int frombcd(int);
+static inline int tobcd(int);
+
+static inline int
+frombcd(int x)
+{
+ return (x >> 4) * 10 + (x & 0xf);
+}
+static inline int
+tobcd(int x)
+{
+ return (x / 10 * 16) + (x % 10);
+}
+
+void dsclock_gettime(void *, time_t, struct tod_time *);
+void dsclock_settime(void *, struct tod_time *);
+
+int
+dsclock_match(struct device *parent, void *vcf, void *aux)
+{
+ struct hpc_attach_args *haa = aux;
+
+ if (strcmp(haa->ha_name, dsclock_cd.cd_name) != 0)
+ return 0;
+
+ return 1;
+}
+
+void
+dsclock_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct dsclock_softc *sc = (void *)self;
+ struct hpc_attach_args *haa = aux;
+
+ sc->sc_iot = haa->ha_st;
+ if (bus_space_subregion(haa->ha_st, haa->ha_sh, haa->ha_devoff,
+ 4 * 8192, &sc->sc_ioh) != 0) {
+ printf(": can't map registers\n");
+ return;
+ }
+
+ printf("\n");
+
+ sys_tod.tod_get = dsclock_gettime;
+ sys_tod.tod_set = dsclock_settime;
+ sys_tod.tod_cookie = self;
+}
+
+/*
+ * Get the time of day, based on the clock's value and/or the base value.
+ */
+void
+dsclock_gettime(void *cookie, time_t base, struct tod_time *ct)
+{
+ struct dsclock_softc *sc = (void *)cookie;
+ ds1286_todregs regs;
+ int s;
+
+ s = splhigh();
+ DS1286_GETTOD(sc, &regs)
+ splx(s);
+
+ ct->sec = frombcd(regs[DS1286_SEC]);
+ ct->min = frombcd(regs[DS1286_MIN]);
+
+ if (regs[DS1286_HOUR] & DS1286_HOUR_12MODE) {
+ ct->hour = frombcd(regs[DS1286_HOUR] & DS1286_HOUR_12HR_MASK) +
+ ((regs[DS1286_HOUR] & DS1286_HOUR_12HR_PM) ? 12 : 0);
+
+ /*
+ * In AM/PM mode, hour range is 01-12, so adding in 12 hours
+ * for PM gives us 01-24, whereas we want 00-23, so map hour
+ * 24 to hour 0.
+ */
+ if (ct->hour == 24)
+ ct->hour = 0;
+ } else {
+ ct->hour = frombcd(regs[DS1286_HOUR] & DS1286_HOUR_24HR_MASK);
+ }
+
+ ct->day = frombcd(regs[DS1286_DOM]);
+ ct->mon = frombcd(regs[DS1286_MONTH] & DS1286_MONTH_MASK);
+ ct->year = frombcd(regs[DS1286_YEAR]) + (IRIX_BASE_YEAR - 1900);
+}
+
+/*
+ * Reset the TODR based on the time value.
+ */
+void
+dsclock_settime(void *cookie, struct tod_time *ct)
+{
+ struct dsclock_softc *sc = (void *)cookie;
+ ds1286_todregs regs;
+ int s;
+
+ s = splhigh();
+ DS1286_GETTOD(sc, &regs);
+ splx(s);
+
+ regs[DS1286_SUBSEC] = 0;
+ regs[DS1286_SEC] = tobcd(ct->sec);
+ regs[DS1286_MIN] = tobcd(ct->min);
+ regs[DS1286_HOUR] = tobcd(ct->hour) & DS1286_HOUR_24HR_MASK;
+ regs[DS1286_DOW] = tobcd(ct->dow);
+ regs[DS1286_DOM] = tobcd(ct->day);
+
+ /* Leave wave-generator bits as set originally */
+ regs[DS1286_MONTH] &= ~DS1286_MONTH_MASK;
+ regs[DS1286_MONTH] |= tobcd(ct->mon) & DS1286_MONTH_MASK;
+
+ regs[DS1286_YEAR] = tobcd(ct->year - (IRIX_BASE_YEAR - 1900));
+
+ s = splhigh();
+ DS1286_PUTTOD(sc, &regs);
+ splx(s);
+}
diff --git a/sys/arch/sgi/hpc/files.hpc b/sys/arch/sgi/hpc/files.hpc
new file mode 100644
index 00000000000..4463f066a45
--- /dev/null
+++ b/sys/arch/sgi/hpc/files.hpc
@@ -0,0 +1,56 @@
+# $OpenBSD: files.hpc,v 1.1 2012/03/28 20:44:23 miod Exp $
+# $NetBSD: files.hpc,v 1.14 2009/05/14 01:10:19 macallan Exp $
+
+# IP20 RTC
+device dpclock
+attach dpclock at hpc
+file arch/sgi/hpc/dpclock.c dpclock
+
+# IP22/24 RTC
+device dsclock
+attach dsclock at hpc
+file arch/sgi/hpc/dsclock.c dsclock
+
+device sq: ether, ifnet
+attach sq at hpc
+file arch/sgi/hpc/if_sq.c sq
+
+define hpcdma
+file arch/sgi/hpc/hpcdma.c hpcdma
+
+device wdsc: wd33c93, scsi, hpcdma
+attach wdsc at hpc
+file arch/sgi/hpc/wdsc.c wdsc
+
+device haltwo: audio, auconv, mulaw
+attach haltwo at hpc
+file arch/sgi/hpc/haltwo.c haltwo
+
+device zs {[channel = -1]}
+attach zs at hpc with zs_hpc
+file arch/sgi/hpc/zs.c zs needs-flag
+file arch/sgi/hpc/z8530sc.c zs
+
+device zstty: tty
+attach zstty at zs
+file arch/sgi/hpc/z8530tty.c zstty needs-flag
+
+device zskbd: wskbddev
+attach zskbd at zs
+file arch/sgi/hpc/zs_kbd.c zskbd needs-flag
+file arch/sgi/dev/wskbdmap_sgi.c zskbd
+
+device zsms: wsmousedev
+attach zsms at zs
+file arch/sgi/hpc/zs_ms.c zsms
+
+attach pckbc at hpc with pckbc_hpc
+file arch/sgi/hpc/pckbc_hpc.c pckbc_hpc
+
+#device pione
+#attach pione at hpc
+#file arch/sgi/hpc/pione.c pione
+
+device panel
+attach panel at hpc
+file arch/sgi/hpc/panel.c panel
diff --git a/sys/arch/sgi/hpc/hpc.c b/sys/arch/sgi/hpc/hpc.c
new file mode 100644
index 00000000000..ca2c31c06ed
--- /dev/null
+++ b/sys/arch/sgi/hpc/hpc.c
@@ -0,0 +1,822 @@
+/* $OpenBSD: hpc.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: hpc.c,v 1.66 2011/07/01 18:53:46 dyoung Exp $ */
+/* $NetBSD: ioc.c,v 1.9 2011/07/01 18:53:47 dyoung Exp $ */
+
+/*
+ * Copyright (c) 2003 Christopher Sekiya
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the
+ * NetBSD Project. See http://www.NetBSD.org/ for
+ * information about NetBSD.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2000 Soren S. Jorvang
+ * Copyright (c) 2001 Rafal K. Boni
+ * Copyright (c) 2001 Jason R. Thorpe
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the
+ * NetBSD Project. See http://www.NetBSD.org/ for
+ * information about NetBSD.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Combined driver for the HPC (High performance Peripheral Controller)
+ * and IOC2 (I/O Controller) chips.
+ *
+ * It would theoretically be better to attach an IOC driver to HPC on
+ * IOC systems (IP22/24/26/28), and attach the few onboard devices
+ * which attach directly to HPC on IP20, to IOC. But since IOC depends
+ * too much on HPC, the complexity this would introduce is not worth
+ * the hassle.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/timeout.h>
+
+#include <mips64/archtype.h>
+
+#include <machine/autoconf.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+
+#include <sgi/gio/gioreg.h>
+#include <sgi/gio/giovar.h>
+
+#include <sgi/hpc/hpcvar.h>
+#include <sgi/hpc/hpcreg.h>
+#include <sgi/hpc/iocreg.h>
+#include <sgi/sgi/ip22.h>
+
+#include <dev/ic/smc93cx6var.h>
+
+struct hpc_device {
+ const char *hd_name;
+ bus_addr_t hd_base;
+ bus_addr_t hd_devoff;
+ bus_addr_t hd_dmaoff;
+ int hd_irq;
+ int hd_sysmask;
+};
+
+static const struct hpc_device hpc1_devices[] = {
+ /* probe order is important for IP20 zs */
+
+ { "zs", /* Indigo serial 0/1 duart 1 */
+ HPC_BASE_ADDRESS_0,
+ 0x0d10, 0,
+ 5,
+ HPCDEV_IP20 },
+
+ { "zs", /* Indigo kbd/ms duart 0 */
+ HPC_BASE_ADDRESS_0,
+ 0x0d00, 0,
+ 5,
+ HPCDEV_IP20 },
+
+ { "sq", /* Indigo onboard ethernet */
+ HPC_BASE_ADDRESS_0,
+ HPC1_ENET_DEVREGS, HPC1_ENET_REGS,
+ 3,
+ HPCDEV_IP20 },
+
+ { "sq", /* E++ GIO adapter slot 0 (Indigo) */
+ HPC_BASE_ADDRESS_1,
+ HPC1_ENET_DEVREGS, HPC1_ENET_REGS,
+ 6,
+ HPCDEV_IP20 },
+
+ { "sq", /* E++ GIO adapter slot 0 (Indy) */
+ HPC_BASE_ADDRESS_1,
+ HPC1_ENET_DEVREGS, HPC1_ENET_REGS,
+ 16 + 6,
+ HPCDEV_IP24 },
+
+ { "sq", /* E++ GIO adapter slot 1 (Indigo) */
+ HPC_BASE_ADDRESS_2,
+ HPC1_ENET_DEVREGS, HPC1_ENET_REGS,
+ 6,
+ HPCDEV_IP20 },
+
+ { "sq", /* E++ GIO adapter slot 1 (Indy/Challenge S) */
+ HPC_BASE_ADDRESS_2,
+ HPC1_ENET_DEVREGS, HPC1_ENET_REGS,
+ 16 + 7,
+ HPCDEV_IP24 },
+
+ { "wdsc", /* Indigo onboard SCSI */
+ HPC_BASE_ADDRESS_0,
+ HPC1_SCSI0_DEVREGS, HPC1_SCSI0_REGS,
+ 2,
+ HPCDEV_IP20 },
+
+ { "wdsc", /* GIO32 SCSI adapter slot 0 (Indigo) */
+ HPC_BASE_ADDRESS_1,
+ HPC1_SCSI0_DEVREGS, HPC1_SCSI0_REGS,
+ 6,
+ HPCDEV_IP20 },
+
+ { "wdsc", /* GIO32 SCSI adapter slot 0 (Indy) */
+ HPC_BASE_ADDRESS_1,
+ HPC1_SCSI0_DEVREGS, HPC1_SCSI0_REGS,
+ 16 + 6,
+ HPCDEV_IP24 },
+
+ { "wdsc", /* GIO32 SCSI adapter slot 1 (Indigo) */
+ HPC_BASE_ADDRESS_2,
+ HPC1_SCSI0_DEVREGS, HPC1_SCSI0_REGS,
+ 6,
+ HPCDEV_IP20 },
+
+ { "wdsc", /* GIO32 SCSI adapter slot 1 (Indy/Challenge S) */
+ HPC_BASE_ADDRESS_2,
+ HPC1_SCSI0_DEVREGS, HPC1_SCSI0_REGS,
+ 16 + 7,
+ HPCDEV_IP24 },
+
+ { NULL,
+ 0,
+ 0, 0,
+ 0,
+ 0
+ }
+};
+
+static const struct hpc_device hpc3_devices[] = {
+ { "zs", /* serial 0/1 duart 0 */
+ HPC_BASE_ADDRESS_0,
+ /* XXX Magic numbers */
+ HPC3_PBUS_CH6_DEVREGS + IOC_SERIAL_REGS, 0,
+ 24 + 5,
+ HPCDEV_IP22 | HPCDEV_IP24 },
+
+ { "pckbc", /* Indigo2/Indy ps2 keyboard/mouse controller */
+ HPC_BASE_ADDRESS_0,
+ HPC3_PBUS_CH6_DEVREGS + IOC_KB_REGS, 0,
+ 24 + 4,
+ HPCDEV_IP22 | HPCDEV_IP24 },
+
+ { "sq", /* Indigo2/Indy/Challenge S/Challenge M onboard enet */
+ HPC_BASE_ADDRESS_0,
+ HPC3_ENET_DEVREGS, HPC3_ENET_REGS,
+ 3,
+ HPCDEV_IP22 | HPCDEV_IP24 },
+
+ { "sq", /* Challenge S IOPLUS secondary ethernet */
+ HPC_BASE_ADDRESS_1,
+ HPC3_ENET_DEVREGS, HPC3_ENET_REGS,
+ 0,
+ HPCDEV_IP24 },
+
+ { "wdsc", /* Indigo2/Indy/Challenge S/Challenge M onboard SCSI */
+ HPC_BASE_ADDRESS_0,
+ HPC3_SCSI0_DEVREGS, HPC3_SCSI0_REGS,
+ 1,
+ HPCDEV_IP22 | HPCDEV_IP24 },
+
+ { "wdsc", /* Indigo2/Challenge M secondary onboard SCSI */
+ HPC_BASE_ADDRESS_0,
+ HPC3_SCSI1_DEVREGS, HPC3_SCSI1_REGS,
+ 2,
+ HPCDEV_IP22 },
+
+ { "haltwo", /* Indigo2/Indy onboard audio */
+ HPC_BASE_ADDRESS_0,
+ HPC3_PBUS_CH0_DEVREGS, HPC3_PBUS_DMAREGS,
+ 8 + 4, /* really the HPC DMA complete interrupt */
+ HPCDEV_IP22 | HPCDEV_IP24 },
+
+ { "pione", /* Indigo2/Indy/Challenge S/Challenge M onboard pport */
+ HPC_BASE_ADDRESS_0,
+ HPC3_PBUS_CH6_DEVREGS + IOC_PLP_REGS, 0,
+ 5,
+ HPCDEV_IP22 | HPCDEV_IP24 },
+
+ { "panel", /* Indy front panel */
+ HPC_BASE_ADDRESS_0,
+ HPC3_PBUS_CH6_DEVREGS + IOC_PANEL, 0,
+ 9,
+ HPCDEV_IP24 },
+
+ { NULL,
+ 0,
+ 0, 0,
+ 0,
+ 0
+ }
+};
+
+struct hpc_softc {
+ struct device sc_dev;
+
+ bus_addr_t sc_base;
+
+ bus_space_tag_t sc_ct;
+ bus_space_handle_t sc_ch;
+ bus_dma_tag_t sc_dmat;
+
+ struct timeout sc_blink_tmo;
+};
+
+static struct hpc_values hpc1_values = {
+ .revision = 1,
+ .scsi0_regs = HPC1_SCSI0_REGS,
+ .scsi0_regs_size = HPC1_SCSI0_REGS_SIZE,
+ .scsi0_cbp = HPC1_SCSI0_CBP,
+ .scsi0_ndbp = HPC1_SCSI0_NDBP,
+ .scsi0_bc = HPC1_SCSI0_BC,
+ .scsi0_ctl = HPC1_SCSI0_CTL,
+ .scsi0_gio = HPC1_SCSI0_GIO,
+ .scsi0_dev = HPC1_SCSI0_DEV,
+ .scsi0_dmacfg = HPC1_SCSI0_DMACFG,
+ .scsi0_piocfg = HPC1_SCSI0_PIOCFG,
+ .scsi1_regs = 0,
+ .scsi1_regs_size = 0,
+ .scsi1_cbp = 0,
+ .scsi1_ndbp = 0,
+ .scsi1_bc = 0,
+ .scsi1_ctl = 0,
+ .scsi1_gio = 0,
+ .scsi1_dev = 0,
+ .scsi1_dmacfg = 0,
+ .scsi1_piocfg = 0,
+ .enet_regs = HPC1_ENET_REGS,
+ .enet_regs_size = HPC1_ENET_REGS_SIZE,
+ .enet_intdelay = HPC1_ENET_INTDELAY,
+ .enet_intdelayval = HPC1_ENET_INTDELAY_OFF,
+ .enetr_cbp = HPC1_ENETR_CBP,
+ .enetr_ndbp = HPC1_ENETR_NDBP,
+ .enetr_bc = HPC1_ENETR_BC,
+ .enetr_ctl = HPC1_ENETR_CTL,
+ .enetr_ctl_active = HPC1_ENETR_CTL_ACTIVE,
+ .enetr_reset = HPC1_ENETR_RESET,
+ .enetr_dmacfg = 0,
+ .enetr_piocfg = 0,
+ .enetx_cbp = HPC1_ENETX_CBP,
+ .enetx_ndbp = HPC1_ENETX_NDBP,
+ .enetx_bc = HPC1_ENETX_BC,
+ .enetx_ctl = HPC1_ENETX_CTL,
+ .enetx_ctl_active = HPC1_ENETX_CTL_ACTIVE,
+ .enetx_dev = 0,
+ .enetr_fifo = HPC1_ENETR_FIFO,
+ .enetr_fifo_size = HPC1_ENETR_FIFO_SIZE,
+ .enetx_fifo = HPC1_ENETX_FIFO,
+ .enetx_fifo_size = HPC1_ENETX_FIFO_SIZE,
+ .enet_dma_boundary = 4096,
+ .enet_devregs = HPC1_ENET_DEVREGS,
+ .enet_devregs_size = HPC1_ENET_DEVREGS_SIZE,
+ .pbus_fifo = 0,
+ .pbus_fifo_size = 0,
+ .pbus_bbram = 0,
+#define MAX_SCSI_XFER (roundup(MAXPHYS, PAGE_SIZE))
+ .scsi_dma_segs = (MAX_SCSI_XFER / 4096),
+ .scsi_dma_segs_size = 4096,
+ .scsi_dma_datain_cmd = (HPC1_SCSI_DMACTL_ACTIVE | HPC1_SCSI_DMACTL_DIR),
+ .scsi_dma_dataout_cmd = HPC1_SCSI_DMACTL_ACTIVE,
+ .scsi_dmactl_flush = HPC1_SCSI_DMACTL_FLUSH,
+ .scsi_dmactl_active = HPC1_SCSI_DMACTL_ACTIVE,
+ .scsi_dmactl_reset = HPC1_SCSI_DMACTL_RESET
+};
+
+static struct hpc_values hpc3_values = {
+ .revision = 3,
+ .scsi0_regs = HPC3_SCSI0_REGS,
+ .scsi0_regs_size = HPC3_SCSI0_REGS_SIZE,
+ .scsi0_cbp = HPC3_SCSI0_CBP,
+ .scsi0_ndbp = HPC3_SCSI0_NDBP,
+ .scsi0_bc = HPC3_SCSI0_BC,
+ .scsi0_ctl = HPC3_SCSI0_CTL,
+ .scsi0_gio = HPC3_SCSI0_GIO,
+ .scsi0_dev = HPC3_SCSI0_DEV,
+ .scsi0_dmacfg = HPC3_SCSI0_DMACFG,
+ .scsi0_piocfg = HPC3_SCSI0_PIOCFG,
+ .scsi1_regs = HPC3_SCSI1_REGS,
+ .scsi1_regs_size = HPC3_SCSI1_REGS_SIZE,
+ .scsi1_cbp = HPC3_SCSI1_CBP,
+ .scsi1_ndbp = HPC3_SCSI1_NDBP,
+ .scsi1_bc = HPC3_SCSI1_BC,
+ .scsi1_ctl = HPC3_SCSI1_CTL,
+ .scsi1_gio = HPC3_SCSI1_GIO,
+ .scsi1_dev = HPC3_SCSI1_DEV,
+ .scsi1_dmacfg = HPC3_SCSI1_DMACFG,
+ .scsi1_piocfg = HPC3_SCSI1_PIOCFG,
+ .enet_regs = HPC3_ENET_REGS,
+ .enet_regs_size = HPC3_ENET_REGS_SIZE,
+ .enet_intdelay = 0,
+ .enet_intdelayval = 0,
+ .enetr_cbp = HPC3_ENETR_CBP,
+ .enetr_ndbp = HPC3_ENETR_NDBP,
+ .enetr_bc = HPC3_ENETR_BC,
+ .enetr_ctl = HPC3_ENETR_CTL,
+ .enetr_ctl_active = HPC3_ENETR_CTL_ACTIVE,
+ .enetr_reset = HPC3_ENETR_RESET,
+ .enetr_dmacfg = HPC3_ENETR_DMACFG,
+ .enetr_piocfg = HPC3_ENETR_PIOCFG,
+ .enetx_cbp = HPC3_ENETX_CBP,
+ .enetx_ndbp = HPC3_ENETX_NDBP,
+ .enetx_bc = HPC3_ENETX_BC,
+ .enetx_ctl = HPC3_ENETX_CTL,
+ .enetx_ctl_active = HPC3_ENETX_CTL_ACTIVE,
+ .enetx_dev = HPC3_ENETX_DEV,
+ .enetr_fifo = HPC3_ENETR_FIFO,
+ .enetr_fifo_size = HPC3_ENETR_FIFO_SIZE,
+ .enetx_fifo = HPC3_ENETX_FIFO,
+ .enetx_fifo_size = HPC3_ENETX_FIFO_SIZE,
+ .enet_dma_boundary = 8192,
+ .enet_devregs = HPC3_ENET_DEVREGS,
+ .enet_devregs_size = HPC3_ENET_DEVREGS_SIZE,
+ .pbus_fifo = HPC3_PBUS_FIFO,
+ .pbus_fifo_size = HPC3_PBUS_FIFO_SIZE,
+ .pbus_bbram = HPC3_PBUS_BBRAM,
+ .scsi_dma_segs = (MAX_SCSI_XFER / 8192),
+ .scsi_dma_segs_size = 8192,
+ .scsi_dma_datain_cmd = HPC3_SCSI_DMACTL_ACTIVE,
+ .scsi_dma_dataout_cmd =(HPC3_SCSI_DMACTL_ACTIVE | HPC3_SCSI_DMACTL_DIR),
+ .scsi_dmactl_flush = HPC3_SCSI_DMACTL_FLUSH,
+ .scsi_dmactl_active = HPC3_SCSI_DMACTL_ACTIVE,
+ .scsi_dmactl_reset = HPC3_SCSI_DMACTL_RESET
+};
+
+int hpc_match(struct device *, void *, void *);
+void hpc_attach(struct device *, struct device *, void *);
+int hpc_print(void *, const char *);
+
+int hpc_revision(struct hpc_softc *, struct gio_attach_args *);
+int hpc_submatch(struct device *, void *, void *);
+int hpc_power_intr(void *);
+void hpc_blink(void *);
+void hpc_blink_ioc(void *);
+int hpc_read_eeprom(int, bus_space_tag_t, bus_space_handle_t, uint8_t *,
+ size_t);
+
+const struct cfattach hpc_ca = {
+ sizeof(struct hpc_softc), hpc_match, hpc_attach
+};
+
+struct cfdriver hpc_cd = {
+ NULL, "hpc", DV_DULL
+};
+
+uint8_t hpc_read_1(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+uint16_t hpc_read_2(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+void hpc_read_raw_2(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ uint8_t *, bus_size_t);
+void hpc_write_1(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint8_t);
+void hpc_write_2(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint16_t);
+void hpc_write_raw_2(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ const uint8_t *, bus_size_t);
+uint32_t hpc_read_4(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+uint64_t hpc_read_8(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+void hpc_write_4(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint32_t);
+void hpc_write_8(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint64_t);
+void hpc_read_raw_4(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ uint8_t *, bus_size_t);
+void hpc_write_raw_4(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ const uint8_t *, bus_size_t);
+void hpc_read_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ uint8_t *, bus_size_t);
+void hpc_write_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ const uint8_t *, bus_size_t);
+int hpc_space_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
+ bus_space_handle_t *);
+void hpc_space_unmap(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+int hpc_space_region(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ bus_size_t, bus_space_handle_t *);
+void *hpc_space_vaddr(bus_space_tag_t, bus_space_handle_t);
+void hpc_space_barrier(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ bus_size_t, int);
+
+int
+hpc_match(struct device *parent, void *vcf, void *aux)
+{
+ struct gio_attach_args* ga = aux;
+ uint32_t dummy;
+
+ /* Make sure it's actually there and readable */
+ if (guarded_read_4(PHYS_TO_XKPHYS(ga->ga_addr, CCA_NC), &dummy) == 0)
+ return 1;
+
+ return 0;
+}
+
+void
+hpc_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct hpc_softc *sc = (struct hpc_softc *)self;
+ struct gio_attach_args* ga = aux;
+ struct hpc_attach_args ha;
+ const struct hpc_device *hd;
+ uint32_t dummy;
+ uint32_t hpctype;
+ int isonboard;
+ int isioplus;
+ int sysmask = 0;
+
+ sc->sc_base = ga->ga_addr;
+ sc->sc_ct = ga->ga_iot;
+ sc->sc_ch = PHYS_TO_XKPHYS(sc->sc_base, CCA_NC);
+ sc->sc_dmat = ga->ga_dmat;
+
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ sysmask = HPCDEV_IP20;
+ break;
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ if (sys_config.system_subtype == IP22_INDIGO2)
+ sysmask = HPCDEV_IP22;
+ else
+ sysmask = HPCDEV_IP24;
+ break;
+ };
+
+ if ((hpctype = hpc_revision(sc, ga)) == 0) {
+ printf(": could not identify HPC revision\n");
+ return;
+ }
+
+ /* force big-endian mode */
+ if (hpctype == 15)
+ bus_space_write_4(sc->sc_ct, sc->sc_ch, HPC1_BIGENDIAN, 0);
+
+ /*
+ * All machines have only one HPC on the mainboard itself. ''Extra''
+ * HPCs require bus arbiter and other magic to run happily.
+ */
+ isonboard = (sc->sc_base == HPC_BASE_ADDRESS_0);
+ isioplus = (sc->sc_base == HPC_BASE_ADDRESS_1 && hpctype == 3 &&
+ sysmask == HPCDEV_IP24);
+
+ printf(": SGI HPC%d%s (%s)\n", (hpctype == 3) ? 3 : 1,
+ (hpctype == 15) ? ".5" : "", (isonboard) ? "onboard" :
+ (isioplus) ? "IOPLUS mezzanine" : "GIO slot");
+
+ /*
+ * Configure the IOC.
+ */
+ if (isonboard && sys_config.system_type != SGI_IP20) {
+ /* Reset IOC */
+ bus_space_write_4(sc->sc_ct, sc->sc_ch, IOC_BASE + IOC_RESET,
+ IOC_RESET_PARALLEL | IOC_RESET_PCKBC | IOC_RESET_EISA |
+ IOC_RESET_ISDN | IOC_RESET_LED_GREEN );
+
+ /*
+ * Set the 10BaseT port to use UTP cable, set autoselect mode
+ * for the Ethernet interface (AUI vs. TP), set the two serial
+ * ports to PC mode.
+ */
+ bus_space_write_4(sc->sc_ct, sc->sc_ch, IOC_BASE + IOC_WRITE,
+ IOC_WRITE_ENET_AUTO | IOC_WRITE_ENET_UTP |
+ IOC_WRITE_PC_UART2 | IOC_WRITE_PC_UART1);
+
+ /* XXX: the firmware should have taken care of this already */
+#if 0
+ if (sys_config.system_subtype == IP22_INDY) {
+ bus_space_write_4(sc->sc_ct, sc->sc_ch,
+ IOC_BASE + IOC_GCSEL, 0xff);
+ bus_space_write_4(sc->sc_ct, sc->sc_ch,
+ IOC_BASE + IOC_GCREG, 0xff);
+ }
+#endif
+ }
+
+ /*
+ * Configure the bus arbiter appropriately.
+ *
+ * In the case of Challenge S, we must tell the IOPLUS board which
+ * DMA channel to use (we steal it from one of the slots). SGI allows
+ * an HPC1.5 in slot 1, in which case IOPLUS must use EXP0, or any
+ * other DMA-capable board in slot 0, which leaves us to use EXP1. Of
+ * course, this means that only one GIO board may use DMA.
+ *
+ * Note that this never happens on Indigo2.
+ */
+ if (isioplus) {
+ int arb_slot;
+
+ if (guarded_read_4(PHYS_TO_XKPHYS(HPC_BASE_ADDRESS_2, CCA_NC),
+ &dummy) != 0)
+ arb_slot = GIO_SLOT_EXP1;
+ else
+ arb_slot = GIO_SLOT_EXP0;
+
+ if (gio_arb_config(arb_slot, GIO_ARB_LB | GIO_ARB_MST |
+ GIO_ARB_64BIT | GIO_ARB_HPC2_64BIT)) {
+ printf("%s: failed to configure GIO bus arbiter\n",
+ sc->sc_dev.dv_xname);
+ return;
+ }
+
+ printf("%s: using EXP%d's DMA channel\n",
+ sc->sc_dev.dv_xname,
+ (arb_slot == GIO_SLOT_EXP0) ? 0 : 1);
+
+ bus_space_write_4(sc->sc_ct, sc->sc_ch,
+ HPC3_PBUS_CFGPIO_REGS, 0x0003ffff);
+
+ if (arb_slot == GIO_SLOT_EXP0)
+ bus_space_write_4(sc->sc_ct, sc->sc_ch,
+ HPC3_PBUS_CH0_DEVREGS, 0x20202020);
+ else
+ bus_space_write_4(sc->sc_ct, sc->sc_ch,
+ HPC3_PBUS_CH0_DEVREGS, 0x30303030);
+ } else if (!isonboard) {
+ int arb_slot;
+
+ arb_slot = (sc->sc_base == HPC_BASE_ADDRESS_1) ?
+ GIO_SLOT_EXP0 : GIO_SLOT_EXP1;
+
+ if (gio_arb_config(arb_slot, GIO_ARB_RT | GIO_ARB_MST)) {
+ printf("%s: failed to configure GIO bus arbiter\n",
+ sc->sc_dev.dv_xname);
+ return;
+ }
+ }
+
+ hpc_read_eeprom(hpctype, sc->sc_ct, sc->sc_ch,
+ ha.hpc_eeprom, sizeof(ha.hpc_eeprom));
+
+ hd = hpctype == 3 ? hpc3_devices : hpc1_devices;
+ for (; hd->hd_name != NULL; hd++) {
+ if (!(hd->hd_sysmask & sysmask) || hd->hd_base != sc->sc_base)
+ continue;
+
+ ha.ha_name = hd->hd_name;
+ ha.ha_devoff = hd->hd_devoff;
+ ha.ha_dmaoff = hd->hd_dmaoff;
+ ha.ha_irq = hd->hd_irq;
+
+ ha.ha_st = sc->sc_ct;
+ ha.ha_sh = sc->sc_ch;
+ ha.ha_dmat = sc->sc_dmat;
+ if (hpctype == 3)
+ ha.hpc_regs = &hpc3_values;
+ else
+ ha.hpc_regs = &hpc1_values;
+ ha.hpc_regs->revision = hpctype;
+
+ /*
+ * XXX On hpc@gio boards such as the E++, this will cause
+ * XXX `wdsc not configured' messages (or sq on SCSI
+ * XXX boards. We need to move some device detection
+ * XXX in there, or figure out if there is a way to know
+ * XXX what is really connected.
+ */
+ config_found_sm(self, &ha, hpc_print, hpc_submatch);
+ }
+
+ /*
+ * Attach the clock chip as well if on hpc0.
+ */
+ if (isonboard) {
+ if (sys_config.system_type == SGI_IP20) {
+ ha.ha_name = "dpclock";
+ ha.ha_devoff = HPC1_PBUS_BBRAM;
+ } else {
+ ha.ha_name = "dsclock";
+ ha.ha_devoff = HPC3_PBUS_BBRAM;
+ }
+ ha.ha_dmaoff = 0;
+ ha.ha_irq = -1;
+ ha.ha_st = sc->sc_ct;
+ ha.ha_sh = sc->sc_ch;
+ ha.ha_dmat = sc->sc_dmat;
+ ha.hpc_regs = NULL;
+
+ config_found_sm(self, &ha, hpc_print, hpc_submatch);
+
+ if (sys_config.system_type == SGI_IP20) {
+ timeout_set(&sc->sc_blink_tmo, hpc_blink, sc);
+ hpc_blink(sc);
+ } else {
+ timeout_set(&sc->sc_blink_tmo, hpc_blink_ioc, sc);
+ hpc_blink_ioc(sc);
+ }
+ }
+}
+
+/*
+ * HPC revision detection isn't as simple as it should be. Devices probe
+ * differently depending on their slots, but luckily there is only one
+ * instance in which we have to decide the major revision (HPC1 vs HPC3).
+ *
+ * The HPC is found in the following configurations:
+ * o Indigo R4k
+ * One on-board HPC1 or HPC1.5.
+ * Up to two additional HPC1.5's in GIO slots 0 and 1.
+ * o Indy
+ * One on-board HPC3.
+ * Up to two additional HPC1.5's in GIO slots 0 and 1.
+ * o Challenge S
+ * One on-board HPC3.
+ * Up to one additional HPC3 on the IOPLUS board (if installed).
+ * Up to one additional HPC1.5 in slot 1 of the IOPLUS board.
+ * o Indigo2, Challenge M
+ * One on-board HPC3.
+ *
+ * All we really have to worry about is the IP22 case.
+ */
+int
+hpc_revision(struct hpc_softc *sc, struct gio_attach_args *ga)
+{
+ uint32_t reg;
+
+ /* No hardware ever supported the last hpc base address. */
+ if (ga->ga_addr == HPC_BASE_ADDRESS_3)
+ return 0;
+
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ if (guarded_read_4(PHYS_TO_XKPHYS(ga->ga_addr + HPC1_BIGENDIAN,
+ CCA_NC), &reg) != 0) {
+ if (((reg >> HPC1_REVSHIFT) & HPC1_REVMASK) ==
+ HPC1_REV15)
+ return 15;
+ else
+ return 1;
+ }
+ return 1;
+
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ /*
+ * If IP22, probe slot 0 to determine if HPC1.5 or HPC3. Slot 1
+ * must be HPC1.5.
+ */
+ if (ga->ga_addr == HPC_BASE_ADDRESS_0)
+ return 3;
+
+ if (ga->ga_addr == HPC_BASE_ADDRESS_2)
+ return 15;
+
+ /*
+ * Probe for it. We use one of the PBUS registers. Note
+ * that this probe succeeds with my E++ adapter in slot 1
+ * (bad), but it appears to always do the right thing in
+ * slot 0 (good!) and we're only worried about that one
+ * anyhow.
+ */
+ if (guarded_read_4(PHYS_TO_XKPHYS(ga->ga_addr +
+ HPC3_PBUS_CH7_BP, CCA_NC), &reg) != 0)
+ return 15;
+ else
+ return 3;
+ }
+
+ return 0;
+}
+
+int
+hpc_submatch(struct device *parent, void *vcf, void *aux)
+{
+ struct cfdata *cf = (struct cfdata *)vcf;
+ struct hpc_attach_args *ha = (struct hpc_attach_args *)aux;
+
+ if (cf->cf_loc[0 /*HPCCF_OFFSET*/] != -1 &&
+ (bus_addr_t)cf->cf_loc[0 /*HPCCF_OFFSET*/] != ha->ha_devoff)
+ return 0;
+
+ return (*cf->cf_attach->ca_match)(parent, cf, aux);
+}
+
+int
+hpc_print(void *aux, const char *pnp)
+{
+ struct hpc_attach_args *ha = aux;
+
+ if (pnp)
+ printf("%s at %s", ha->ha_name, pnp);
+
+ printf(" offset 0x%08lx", ha->ha_devoff);
+ if (ha->ha_irq >= 0)
+ printf(" irq %d", ha->ha_irq);
+
+ return UNCONF;
+}
+
+void
+hpc_blink(void *arg)
+{
+ struct hpc_softc *sc = arg;
+
+ bus_space_write_1(sc->sc_ct, sc->sc_ch, HPC1_AUX_REGS,
+ bus_space_read_1(sc->sc_ct, sc->sc_ch, HPC1_AUX_REGS) ^
+ HPC1_AUX_CONSLED);
+
+ timeout_add(&sc->sc_blink_tmo,
+ (((averunnable.ldavg[0] + FSCALE) * hz) >> (FSHIFT + 1)));
+}
+
+void
+hpc_blink_ioc(void *arg)
+{
+ struct hpc_softc *sc = arg;
+ uint32_t value;
+
+ /* This is a bit odd. To strobe the green LED, we have to toggle the
+ red control bit. */
+ value = bus_space_read_4(sc->sc_ct, sc->sc_ch, IOC_BASE + IOC_RESET) &
+ 0xff;
+ value ^= IOC_RESET_LED_RED;
+ bus_space_write_4(sc->sc_ct, sc->sc_ch, IOC_BASE + IOC_RESET, value);
+
+ timeout_add(&sc->sc_blink_tmo,
+ (((averunnable.ldavg[0] + FSCALE) * hz) >> (FSHIFT + 1)));
+}
+
+/*
+ * Read the eeprom associated with one of the HPC's.
+ *
+ * NB: An eeprom is not always present, but the HPC should be able to
+ * handle this gracefully. Any consumers should validate the data to
+ * ensure it's reasonable.
+ */
+int
+hpc_read_eeprom(int hpctype, bus_space_tag_t t, bus_space_handle_t h,
+ uint8_t *buf, size_t len)
+{
+ struct seeprom_descriptor sd;
+ bus_space_handle_t bsh;
+ bus_size_t offset;
+
+ if (!len || len & 0x1)
+ return (1);
+
+ offset = (hpctype == 3) ? HPC3_EEPROM_DATA : HPC1_AUX_REGS;
+
+ if (bus_space_subregion(t, h, offset, 1, &bsh) != 0)
+ return (1);
+
+ sd.sd_chip = C56_66;
+ sd.sd_tag = t;
+ sd.sd_bsh = bsh;
+ sd.sd_regsize = 1;
+ sd.sd_control_offset = 0;
+ sd.sd_status_offset = 0;
+ sd.sd_dataout_offset = 0;
+ sd.sd_DI = 0x10; /* EEPROM -> CPU */
+ sd.sd_DO = 0x08; /* CPU -> EEPROM */
+ sd.sd_CK = 0x04;
+ sd.sd_CS = 0x02;
+ sd.sd_MS = 0;
+ sd.sd_RDY = 0;
+
+ if (read_seeprom(&sd, (uint16_t *)buf, 0, len / 2) != 1)
+ return (1);
+
+ bus_space_unmap(t, bsh, 1);
+
+ return 0;
+}
diff --git a/sys/arch/sgi/hpc/hpcdma.c b/sys/arch/sgi/hpc/hpcdma.c
new file mode 100644
index 00000000000..53dc86994ce
--- /dev/null
+++ b/sys/arch/sgi/hpc/hpcdma.c
@@ -0,0 +1,208 @@
+/* $OpenBSD: hpcdma.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: hpcdma.c,v 1.21 2011/07/01 18:53:46 dyoung Exp $ */
+
+/*
+ * Copyright (c) 2001 Wayne Knowles
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Wayne Knowles
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Support for SCSI DMA provided by the HPC.
+ *
+ * Note: We use SCSI0 offsets, etc. here. Since the layout of SCSI0
+ * and SCSI1 are the same, this is no problem.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/buf.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/bus.h>
+
+#include <sgi/hpc/hpcreg.h>
+#include <sgi/hpc/hpcvar.h>
+#include <sgi/hpc/hpcdma.h>
+
+/*
+ * Allocate DMA Chain descriptor list
+ */
+void
+hpcdma_init(struct hpc_attach_args *haa, struct hpc_dma_softc *sc, int ndesc)
+{
+ bus_dma_segment_t seg;
+ int rseg, allocsz;
+
+ sc->sc_bst = haa->ha_st;
+ sc->sc_dmat = haa->ha_dmat;
+ sc->sc_ndesc = ndesc;
+ sc->sc_flags = 0;
+
+ if (bus_space_subregion(haa->ha_st, haa->ha_sh, haa->ha_dmaoff,
+ sc->hpc->scsi0_regs_size, &sc->sc_bsh) != 0) {
+ printf(": can't map DMA registers\n");
+ return;
+ }
+
+ /* Alloc 1 additional descriptor - needed for DMA bug fix */
+ allocsz = sizeof(struct hpc_dma_desc) * (ndesc + 1);
+
+ /*
+ * Allocate a block of memory for dma chaining pointers
+ */
+ if (bus_dmamem_alloc(sc->sc_dmat, allocsz, 0, 0, &seg, 1, &rseg,
+ BUS_DMA_NOWAIT)) {
+ printf(": can't allocate sglist\n");
+ return;
+ }
+ /* Map pages into kernel memory */
+ if (bus_dmamem_map(sc->sc_dmat, &seg, rseg, allocsz,
+ (caddr_t *)&sc->sc_desc_kva, BUS_DMA_NOWAIT)) {
+ printf(": can't map sglist\n");
+ bus_dmamem_free(sc->sc_dmat, &seg, rseg);
+ return;
+ }
+
+ if (bus_dmamap_create(sc->sc_dmat, allocsz, 1 /*seg*/, allocsz, 0,
+ BUS_DMA_WAITOK, &sc->sc_dmamap) != 0) {
+ printf(": failed to create dmamap\n");
+ return;
+ }
+
+ if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap,
+ sc->sc_desc_kva, allocsz, NULL, BUS_DMA_NOWAIT)) {
+ printf(": can't load sglist\n");
+ return;
+ }
+
+ sc->sc_desc_pa = sc->sc_dmamap->dm_segs[0].ds_addr;
+}
+
+
+void
+hpcdma_sglist_create(struct hpc_dma_softc *sc, bus_dmamap_t dmamap)
+{
+ struct hpc_dma_desc *hva;
+ bus_addr_t hpa;
+ bus_dma_segment_t *segp;
+ int i;
+
+ KASSERT(dmamap->dm_nsegs <= sc->sc_ndesc);
+
+ hva = sc->sc_desc_kva;
+ hpa = sc->sc_desc_pa;
+ segp = dmamap->dm_segs;
+
+#ifdef DMA_DEBUG
+ printf("DMA_SGLIST<");
+#endif
+ for (i = dmamap->dm_nsegs; i; i--) {
+#ifdef DMA_DEBUG
+ printf("%p:%ld, ", (void *)segp->ds_addr, segp->ds_len);
+#endif
+ hpa += sizeof(struct hpc_dma_desc); /* next chain desc */
+ if (sc->hpc->revision == 3) {
+ hva->hpc3_hdd_bufptr = segp->ds_addr;
+ hva->hpc3_hdd_ctl = segp->ds_len;
+ hva->hdd_descptr = hpa;
+ } else /* HPC 1/1.5 */ {
+ /*
+ * there doesn't seem to be any good way of doing this
+ * via an abstraction layer
+ */
+ hva->hpc1_hdd_bufptr = segp->ds_addr;
+ hva->hpc1_hdd_ctl = segp->ds_len;
+ hva->hdd_descptr = hpa;
+ }
+ ++hva;
+ ++segp;
+ }
+
+ /* Work around HPC3 DMA bug */
+ if (sc->hpc->revision == 3) {
+ hva->hpc3_hdd_bufptr = 0;
+ hva->hpc3_hdd_ctl = HPC3_HDD_CTL_EOCHAIN;
+ hva->hdd_descptr = 0;
+ } else {
+ hva--;
+ hva->hpc1_hdd_bufptr |= HPC1_HDD_CTL_EOCHAIN;
+ hva->hdd_descptr = 0;
+ }
+
+#ifdef DMA_DEBUG
+ printf(">\n");
+#endif
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
+ 0, sizeof(struct hpc_dma_desc) * (dmamap->dm_nsegs + 1),
+ BUS_DMASYNC_PREWRITE);
+
+ /* Load DMA Descriptor list */
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ndbp,
+ sc->sc_desc_pa);
+}
+
+void
+hpcdma_cntl(struct hpc_dma_softc *sc, uint32_t mode)
+{
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ctl, mode);
+}
+
+void
+hpcdma_reset(struct hpc_dma_softc *sc)
+{
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ctl,
+ sc->hpc->scsi_dmactl_reset);
+ delay(100);
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ctl, 0);
+ delay(1000);
+}
+
+void
+hpcdma_flush(struct hpc_dma_softc *sc)
+{
+ uint32_t mode;
+
+ mode = bus_space_read_4(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ctl);
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh,
+ sc->hpc->scsi0_ctl, mode | sc->hpc->scsi_dmactl_flush);
+
+ /* Wait for Active bit to drop */
+ while (bus_space_read_4(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ctl) &
+ sc->hpc->scsi_dmactl_active) {
+ bus_space_barrier(sc->sc_bst, sc->sc_bsh, sc->hpc->scsi0_ctl, 4,
+ BUS_SPACE_BARRIER_READ);
+ }
+}
diff --git a/sys/arch/sgi/hpc/hpcdma.h b/sys/arch/sgi/hpc/hpcdma.h
new file mode 100644
index 00000000000..bca5fc5b171
--- /dev/null
+++ b/sys/arch/sgi/hpc/hpcdma.h
@@ -0,0 +1,63 @@
+/* $OpenBSD: hpcdma.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: hpcdma.h,v 1.11 2011/07/01 18:53:46 dyoung Exp $ */
+
+/*
+ * Copyright (c) 2001 Wayne Knowles
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Wayne Knowles
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+struct hpc_dma_softc {
+ bus_space_tag_t sc_bst;
+ bus_space_handle_t sc_bsh;
+ bus_dma_tag_t sc_dmat;
+
+ uint32_t sc_flags;
+#define HPCDMA_READ 0x20 /* direction of transfer */
+#define HPCDMA_LOADED 0x40 /* bus_dmamap loaded */
+#define HPCDMA_ACTIVE 0x80 /* DMA engine is busy */
+ uint32_t sc_dmacmd;
+ int sc_ndesc;
+ bus_dmamap_t sc_dmamap;
+ struct hpc_dma_desc *sc_desc_kva; /* Virtual address */
+ bus_addr_t sc_desc_pa; /* DMA address */
+ ssize_t sc_dlen; /* number of bytes transfered */
+ struct hpc_values *hpc; /* constants for HPC1/3 */
+};
+
+
+void hpcdma_init(struct hpc_attach_args *, struct hpc_dma_softc *, int);
+void hpcdma_sglist_create(struct hpc_dma_softc *, bus_dmamap_t);
+void hpcdma_cntl(struct hpc_dma_softc *, uint32_t);
+void hpcdma_reset(struct hpc_dma_softc *);
+void hpcdma_flush(struct hpc_dma_softc *);
diff --git a/sys/arch/sgi/hpc/hpcreg.h b/sys/arch/sgi/hpc/hpcreg.h
new file mode 100644
index 00000000000..bce6a2d2245
--- /dev/null
+++ b/sys/arch/sgi/hpc/hpcreg.h
@@ -0,0 +1,450 @@
+/* $OpenBSD: hpcreg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: hpcreg.h,v 1.20 2011/01/25 12:21:04 tsutsui Exp $ */
+
+/*
+ * Copyright (c) 2001 Rafal K. Boni
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * HPC locations are identical across all HPC-supported
+ * platforms.
+ */
+#define HPC_BASE_ADDRESS_0 0x1fb80000 /* Primary onboard */
+#define HPC_BASE_ADDRESS_1 0x1fb00000
+#define HPC_BASE_ADDRESS_2 0x1f980000
+#define HPC_BASE_ADDRESS_3 0x1f900000 /* NB: Never supported in h/w */
+
+/*
+ * HPC3 descriptor layout.
+ */
+struct hpc_dma_desc {
+ uint32_t hdd_bufptr; /* Physical address of buffer */
+ uint32_t hdd_ctl; /* Control flags and byte count */
+ uint32_t hdd_descptr; /* Physical address of next descr. */
+ uint32_t hdd_pad; /* Pad out to quadword alignment */
+};
+
+/*
+ * The hdd_bufptr and hdd_ctl fields are swapped between HPC1 and
+ * HPC3. These fields are referenced by macro for readability.
+ */
+#define hpc1_hdd_ctl hdd_bufptr
+#define hpc1_hdd_bufptr hdd_ctl
+#define hpc3_hdd_ctl hdd_ctl
+#define hpc3_hdd_bufptr hdd_bufptr
+
+/*
+ * Control flags
+ */
+#define HPC3_HDD_CTL_EOCHAIN 0x80000000 /* End of descriptor chain */
+#define HPC3_HDD_CTL_EOPACKET 0x40000000 /* Ethernet: end of packet */
+#define HPC3_HDD_CTL_INTR 0x20000000 /* Interrupt when finished */
+#define HPC3_HDD_CTL_XMITDONE 0x00008000 /* Ethernet transmit done */
+#define HPC3_HDD_CTL_OWN 0x00004000 /* CPU owns this frame */
+
+#define HPC3_HDD_CTL_BYTECNT(x) ((x) & 0x3fff) /* Byte count: for ethernet
+ * rcv channel also doubles as
+ * length of packet received
+ */
+
+/*
+ * HPC memory map, as offsets from HPC base
+ *
+ * XXXrkb: should each section be used as a base and have the specific
+ * registers offset from there??
+ *
+ * XXX: define register values as well as their offsets.
+ *
+ */
+#define HPC3_PBUS_DMAREGS 0x00000000 /* DMA registers for PBus */
+#define HPC3_PBUS_DMAREGS_SIZE 0x0000ffff /* channels 0 - 7 */
+
+#define HPC3_PBUS_CH0_BP 0x00000000 /* Chan 0 Buffer Ptr */
+#define HPC3_PBUS_CH0_DP 0x00000004 /* Chan 0 Descriptor Ptr */
+#define HPC3_PBUS_CH0_CTL 0x00001000 /* Chan 0 Control Register */
+
+#define HPC3_PBUS_CH1_BP 0x00002000 /* Chan 1 Buffer Ptr */
+#define HPC3_PBUS_CH1_DP 0x00002004 /* Chan 1 Descriptor Ptr */
+#define HPC3_PBUS_CH1_CTL 0x00003000 /* Chan 1 Control Register */
+
+#define HPC3_PBUS_CH2_BP 0x00004000 /* Chan 2 Buffer Ptr */
+#define HPC3_PBUS_CH2_DP 0x00004004 /* Chan 2 Descriptor Ptr */
+#define HPC3_PBUS_CH2_CTL 0x00005000 /* Chan 2 Control Register */
+
+#define HPC3_PBUS_CH3_BP 0x00006000 /* Chan 3 Buffer Ptr */
+#define HPC3_PBUS_CH3_DP 0x00006004 /* Chan 3 Descriptor Ptr */
+#define HPC3_PBUS_CH3_CTL 0x00007000 /* Chan 3 Control Register */
+
+#define HPC3_PBUS_CH4_BP 0x00008000 /* Chan 4 Buffer Ptr */
+#define HPC3_PBUS_CH4_DP 0x00008004 /* Chan 4 Descriptor Ptr */
+#define HPC3_PBUS_CH4_CTL 0x00009000 /* Chan 4 Control Register */
+
+#define HPC3_PBUS_CH5_BP 0x0000a000 /* Chan 5 Buffer Ptr */
+#define HPC3_PBUS_CH5_DP 0x0000a004 /* Chan 5 Descriptor Ptr */
+#define HPC3_PBUS_CH5_CTL 0x0000b000 /* Chan 5 Control Register */
+
+#define HPC3_PBUS_CH6_BP 0x0000c000 /* Chan 6 Buffer Ptr */
+#define HPC3_PBUS_CH6_DP 0x0000c004 /* Chan 6 Descriptor Ptr */
+#define HPC3_PBUS_CH6_CTL 0x0000d000 /* Chan 6 Control Register */
+
+#define HPC3_PBUS_CH7_BP 0x0000e000 /* Chan 7 Buffer Ptr */
+#define HPC3_PBUS_CH7_DP 0x0000e004 /* Chan 7 Descriptor Ptr */
+#define HPC3_PBUS_CH7_CTL 0x0000f000 /* Chan 7 Control Register */
+
+#define HPC3_SCSI0_REGS 0x00010000 /* SCSI channel 0 registers */
+#define HPC3_SCSI0_REGS_SIZE 0x00001fff
+
+#define HPC3_SCSI0_CBP 0x00000000 /* Current buffer ptr */
+#define HPC3_SCSI0_NDBP 0x00000004 /* Next descriptor ptr */
+
+#define HPC3_SCSI0_BC 0x00001000 /* DMA byte count & flags */
+#define HPC3_SCSI0_CTL 0x00001004 /* DMA control flags */
+#define HPC3_SCSI0_GIO 0x00001008 /* GIO DMA FIFO pointer */
+#define HPC3_SCSI0_DEV 0x0000100c /* Device DMA FIFO pointer */
+#define HPC3_SCSI0_DMACFG 0x00001010 /* DMA configuration */
+#define HPC3_SCSI0_PIOCFG 0x00001014 /* PIO configuration */
+
+#define HPC3_SCSI1_REGS 0x00012000 /* SCSI channel 1 registers */
+#define HPC3_SCSI1_REGS_SIZE 0x00001fff
+
+#define HPC3_SCSI1_CBP 0x00000000 /* Current buffer ptr */
+#define HPC3_SCSI1_NDBP 0x00000004 /* Next descriptor ptr */
+
+#define HPC3_SCSI1_BC 0x00001000 /* DMA byte count & flags */
+#define HPC3_SCSI1_CTL 0x00001004 /* DMA control flags */
+#define HPC3_SCSI1_GIO 0x00001008 /* GIO DMA FIFO pointer */
+#define HPC3_SCSI1_DEV 0x0000100c /* Device DMA FIFO pointer */
+#define HPC3_SCSI1_DMACFG 0x00001010 /* DMA configuration */
+#define HPC3_SCSI1_PIOCFG 0x00001014 /* PIO configuration */
+
+/* HPC3_SCSIx_CTL "SCSI control register" flags: */
+#define HPC3_SCSI_DMACTL_IRQ 0x01 /* IRQ asserted, dma done or parity */
+#define HPC3_SCSI_DMACTL_ENDIAN 0x02 /* DMA endian mode, 0=BE, 1=LE */
+#define HPC3_SCSI_DMACTL_DIR 0x04 /* DMA direction, 0=dev->mem, 1=mem->dev */
+#define HPC3_SCSI_DMACTL_FLUSH 0x08 /* Flush DMA FIFO's */
+#define HPC3_SCSI_DMACTL_ACTIVE 0x10 /* DMA channel is active */
+#define HPC3_SCSI_DMACTL_AMASK 0x20 /* DMA active inhibits PIO */
+#define HPC3_SCSI_DMACTL_RESET 0x40 /* Reset dma channel and ext. controller */
+#define HPC3_SCSI_DMACTL_PERR 0x80 /* Parity error: interface to controller */
+
+/* HPC_PBUS_CHx_CTL read: */
+#define HPC3_PBUS_DMACTL_IRQ 0x01 /* IRQ asserted, DMA done */
+#define HPC3_PBUS_DMACTL_ISACT 0x02 /* DMA channel is active */
+
+/* HPC_PBUS_CHx_CTL write: */
+#define HPC3_PBUS_DMACTL_ENDIAN 0x02 /* DMA endianness, 0=BE 1=LE */
+#define HPC3_PBUS_DMACTL_RECEIVE 0x04 /* DMA direction, 1=dev->mem, 0=mem->dev*/
+#define HPC3_PBUS_DMACTL_FLUSH 0x08 /* Flush DMA FIFO */
+#define HPC3_PBUS_DMACTL_ACT 0x10 /* Activate DMA channel */
+#define HPC3_PBUS_DMACTL_ACT_LD 0x20 /* Load enable for ACT */
+#define HPC3_PBUS_DMACTL_RT 0x40 /* Enable real time GIO service for DMA */
+#define HPC3_PBUS_DMACTL_HIGHWATER_SHIFT 8
+#define HPC3_PBUS_DMACTL_FIFOBEG_SHIFT 16
+#define HPC3_PBUS_DMACTL_FIFOEND_SHIFT 24
+
+#define HPC3_ENET_REGS 0x00014000 /* Ethernet registers */
+#define HPC3_ENET_REGS_SIZE 0x00003fff
+
+#define HPC3_ENETR_CBP 0x00000000 /* Recv: Current buffer ptr */
+#define HPC3_ENETR_NDBP 0x00000004 /* Recv: Next descriptor ptr */
+
+#define HPC3_ENETR_BC 0x00001000 /* Recv: DMA byte cnt/flags */
+#define HPC3_ENETR_CTL 0x00001004 /* Recv: DMA control flags */
+
+#define HPC3_ENETR_CTL_STAT_5_0 0x003f /* Seeq irq status: bits 0-5 */
+#define HPC3_ENETR_CTL_STAT_6 0x0040 /* Irq status: late_rxdc */
+#define HPC3_ENETR_CTL_STAT_7 0x0080 /* Irq status: old/new bit */
+#define HPC3_ENETR_CTL_LENDIAN 0x0100 /* DMA channel endian mode */
+#define HPC3_ENETR_CTL_ACTIVE 0x0200 /* DMA channel active? */
+#define HPC3_ENETR_CTL_ACTIVE_MSK 0x0400 /* DMA channel active? */
+#define HPC3_ENETR_CTL_RBO 0x0800 /* Recv buffer overflow */
+
+#define HPC3_ENETR_GIO 0x00001008 /* Recv: GIO DMA FIFO ptr */
+#define HPC3_ENETR_DEV 0x0000100c /* Recv: Device DMA FIFO ptr */
+#define HPC3_ENETR_RESET 0x00001014 /* Recv: Ethernet chip reset */
+
+#define HPC3_ENETR_RESET_CH 0x0001 /* Reset controller & chan */
+#define HPC3_ENETR_RESET_CLRINT 0x0002 /* Clear channel interrupt */
+#define HPC3_ENETR_RESET_LOOPBK 0x0004 /* External loopback enable */
+#define HPC3_ENETR_RESET_CLRRBO 0x0008 /* Clear RBO condition (??) */
+
+#define HPC3_ENETR_DMACFG 0x00001018 /* Recv: DMA configuration */
+
+#define HPC3_ENETR_DMACFG_D1(_x) (((_x) << 0) & 0x000f) /* D1 gio_clk cycles */
+#define HPC3_ENETR_DMACFG_D2(_x) (((_x) << 4) & 0x00f0) /* D2 gio_clk cycles */
+#define HPC3_ENETR_DMACFG_D3(_x) (((_x) << 8) & 0x0f00) /* D3 gio_clk cycles */
+#define HPC3_ENETR_DMACFG_WRCTL 0x01000 /* Enable IPG write */
+
+/*
+ * The following three bits work around bugs in the Seeq 8003; if you
+ * don't set them, the Seeq gets wonky pretty often.
+ */
+#define HPC3_ENETR_DMACFG_FIX_RXDC 0x02000 /* Clear EOP bits on RXDC */
+#define HPC3_ENETR_DMACFG_FIX_EOP 0x04000 /* Enable rxintr timeout */
+#define HPC3_ENETR_DMACFG_FIX_INTR 0x08000 /* Enable EOP timeout */
+#define HPC3_ENETR_DMACFG_TIMEOUT 0x30000 /* Timeout value for above two*/
+
+#define HPC3_ENETR_PIOCFG 0x0000101c /* Recv: PIO configuration */
+
+#define HPC3_ENETR_PIOCFG_P1(_x) (((_x) << 0) & 0x000f) /* P1 gio_clk cycles */
+#define HPC3_ENETR_PIOCFG_P2(_x) (((_x) << 4) & 0x00f0) /* P2 gio_clk cycles */
+#define HPC3_ENETR_PIOCFG_P3(_x) (((_x) << 8) & 0x0f00) /* P3 gio_clk cycles */
+
+#define HPC3_ENETX_CBP 0x00002000 /* Xmit: Current buffer ptr */
+#define HPC3_ENETX_NDBP 0x00002004 /* Xmit: Next descriptor ptr */
+
+#define HPC3_ENETX_BC 0x00003000 /* Xmit: DMA byte cnt/flags */
+#define HPC3_ENETX_CTL 0x00003004 /* Xmit: DMA control flags */
+
+#define HPC3_ENETX_CTL_STAT_5_0 0x003f /* Seeq irq status: bits 0-5 */
+#define HPC3_ENETX_CTL_STAT_6 0x0040 /* Irq status: late_rxdc */
+#define HPC3_ENETX_CTL_STAT_7 0x0080 /* Irq status: old/new bit */
+#define HPC3_ENETX_CTL_LENDIAN 0x0100 /* DMA channel endian mode */
+#define HPC3_ENETX_CTL_ACTIVE 0x0200 /* DMA channel active? */
+#define HPC3_ENETX_CTL_ACTIVE_MSK 0x0400 /* DMA channel active? */
+#define HPC3_ENETX_CTL_RBO 0x0800 /* Recv buffer overflow */
+
+#define HPC3_ENETX_GIO 0x00003008 /* Xmit: GIO DMA FIFO ptr */
+#define HPC3_ENETX_DEV 0x0000300c /* Xmit: Device DMA FIFO ptr */
+
+#define HPC3_PBUS_FIFO 0x00020000 /* PBus DMA FIFO */
+#define HPC3_PBUS_FIFO_SIZE 0x00007fff /* PBus DMA FIFO size */
+
+#define HPC3_SCSI0_FIFO 0x00028000 /* SCSI0 DMA FIFO */
+#define HPC3_SCSI0_FIFO_SIZE 0x00001fff /* SCSI0 DMA FIFO size */
+
+#define HPC3_SCSI1_FIFO 0x0002a000 /* SCSI1 DMA FIFO */
+#define HPC3_SCSI1_FIFO_SIZE 0x00001fff /* SCSI1 DMA FIFO size */
+
+#define HPC3_ENETR_FIFO 0x0002c000 /* Ether recv DMA FIFO */
+#define HPC3_ENETR_FIFO_SIZE 0x00001fff /* Ether recv DMA FIFO size */
+
+#define HPC3_ENETX_FIFO 0x0002e000 /* Ether xmit DMA FIFO */
+#define HPC3_ENETX_FIFO_SIZE 0x00001fff /* Ether xmit DMA FIFO size */
+
+/*
+ * HPCBUG: The interrupt status is split amongst two registers, and they're
+ * not even consecutive in the HPC address space. This is documented as a
+ * bug by SGI.
+ */
+#define HPC3_INTRSTAT_40 0x00030000 /* Interrupt stat, bits 4:0 */
+#define HPC3_INTRSTAT_95 0x0003000c /* Interrupt stat, bits 9:5 */
+
+#define HPC3_GIO_MISC 0x00030004 /* GIO64 misc register */
+
+#define HPC3_EEPROM_DATA 0x0003000b /* Serial EEPROM data reg. */
+ /* (byte) */
+
+#define HPC3_GIO_BUSERR 0x00030010 /* GIO64 bus error intr stat */
+
+#define HPC3_SCSI0_DEVREGS 0x00044000 /* SCSI channel 0 chip regs */
+#define HPC3_SCSI1_DEVREGS 0x0004c000 /* SCSI channel 1 chip regs */
+
+#define HPC3_ENET_DEVREGS 0x00054000 /* Ethernet chip registers */
+#define HPC3_ENET_DEVREGS_SIZE 0x000004ff /* Size of chip registers */
+
+#define HPC3_PBUS_DEVREGS 0x00054000 /* PBus PIO chip registers */
+#define HPC3_PBUS_DEVREGS_SIZE 0x000003ff /* PBus PIO chip registers */
+
+#define HPC3_PBUS_CH0_DEVREGS 0x00058000 /* PBus ch. 0 chip registers */
+#define HPC3_PBUS_CH0_DEVREGS_SIZE 0x03ff
+
+#define HPC3_PBUS_CH1_DEVREGS 0x00058400 /* PBus ch. 1 chip registers */
+#define HPC3_PBUS_CH1_DEVREGS_SIZE 0x03ff
+
+#define HPC3_PBUS_CH2_DEVREGS 0x00058800 /* PBus ch. 2 chip registers */
+#define HPC3_PBUS_CH2_DEVREGS_SIZE 0x03ff
+
+#define HPC3_PBUS_CH3_DEVREGS 0x00058c00 /* PBus ch. 3 chip registers */
+#define HPC3_PBUS_CH3_DEVREGS_SIZE 0x03ff
+
+#define HPC3_PBUS_CH4_DEVREGS 0x00059000 /* PBus ch. 4 chip registers */
+#define HPC3_PBUS_CH4_DEVREGS_SIZE 0x03ff
+
+#define HPC3_PBUS_CH5_DEVREGS 0x00059400 /* PBus ch. 5 chip registers */
+#define HPC3_PBUS_CH5_DEVREGS_SIZE 0x03ff
+
+#define HPC3_PBUS_CH6_DEVREGS 0x00059800 /* PBus ch. 6 chip registers */
+#define HPC3_PBUS_CH6_DEVREGS_SIZE 0x03ff
+
+#define HPC3_PBUS_CH7_DEVREGS 0x00059c00 /* PBus ch. 7 chip registers */
+#define HPC3_PBUS_CH7_DEVREGS_SIZE 0x03ff
+
+#define HPC3_PBUS_CH8_DEVREGS 0x0005a000 /* PBus ch. 8 chip registers */
+#define HPC3_PBUS_CH8_DEVREGS_SIZE 0x03ff
+
+#define HPC3_PBUS_CH9_DEVREGS 0x0005a400 /* PBus ch. 9 chip registers */
+#define HPC3_PBUS_CH9_DEVREGS_SIZE 0x03ff
+
+#define HPC3_PBUS_CH8_DEVREGS_2 0x0005a800 /* PBus ch. 8 chip registers */
+#define HPC3_PBUS_CH8_DEVREGS_2_SIZE 0x03ff
+
+#define HPC3_PBUS_CH9_DEVREGS_2 0x0005ac00 /* PBus ch. 9 chip registers */
+#define HPC3_PBUS_CH9_DEVREGS_2_SIZE 0x03ff
+
+#define HPC3_PBUS_CH8_DEVREGS_3 0x0005b000 /* PBus ch. 8 chip registers */
+#define HPC3_PBUS_CH8_DEVREGS_3_SIZE 0x03ff
+
+#define HPC3_PBUS_CH9_DEVREGS_3 0x0005b400 /* PBus ch. 9 chip registers */
+#define HPC3_PBUS_CH9_DEVREGS_3_SIZE 0x03ff
+
+#define HPC3_PBUS_CH8_DEVREGS_4 0x0005b800 /* PBus ch. 8 chip registers */
+#define HPC3_PBUS_CH8_DEVREGS_4_SIZE 0x03ff
+
+#define HPC3_PBUS_CH9_DEVREGS_4 0x0005bc00 /* PBus ch. 9 chip registers */
+#define HPC3_PBUS_CH9_DEVREGS_4_SIZE 0x03ff
+
+#define HPC3_PBUS_CFGDMA_REGS 0x0005c000 /* PBus DMA config registers */
+#define HPC3_PBUS_CFGDMA_REGS_SIZE 0x0fff
+
+#define HPC3_PBUS_CH0_CFGDMA 0x0005c000 /* PBus Ch. 0 DMA config */
+#define HPC3_PBUS_CH0_CFGDMA_SIZE 0x01ff
+
+#define HPC3_PBUS_CH1_CFGDMA 0x0005c200 /* PBus Ch. 1 DMA config */
+#define HPC3_PBUS_CH1_CFGDMA_SIZE 0x01ff
+
+#define HPC3_PBUS_CH2_CFGDMA 0x0005c400 /* PBus Ch. 2 DMA config */
+#define HPC3_PBUS_CH2_CFGDMA_SIZE 0x01ff
+
+#define HPC3_PBUS_CH3_CFGDMA 0x0005c600 /* PBus Ch. 3 DMA config */
+#define HPC3_PBUS_CH3_CFGDMA_SIZE 0x01ff
+
+#define HPC3_PBUS_CH4_CFGDMA 0x0005c800 /* PBus Ch. 4 DMA config */
+#define HPC3_PBUS_CH4_CFGDMA_SIZE 0x01ff
+
+#define HPC3_PBUS_CH5_CFGDMA 0x0005ca00 /* PBus Ch. 5 DMA config */
+#define HPC3_PBUS_CH5_CFGDMA_SIZE 0x01ff
+
+#define HPC3_PBUS_CH6_CFGDMA 0x0005cc00 /* PBus Ch. 6 DMA config */
+#define HPC3_PBUS_CH6_CFGDMA_SIZE 0x01ff
+
+#define HPC3_PBUS_CH7_CFGDMA 0x0005ce00 /* PBus Ch. 7 DMA config */
+#define HPC3_PBUS_CH7_CFGDMA_SIZE 0x01ff
+
+#define HPC3_PBUS_CFGPIO_REGS 0x0005d000 /* PBus PIO config registers */
+#define HPC3_PBUS_CFGPIO_REGS_SIZE 0x0fff
+
+#define HPC3_PBUS_CH0_CFGPIO 0x0005d000 /* PBus Ch. 0 PIO config */
+#define HPC3_PBUS_CH1_CFGPIO 0x0005d100 /* PBus Ch. 1 PIO config */
+#define HPC3_PBUS_CH2_CFGPIO 0x0005d200 /* PBus Ch. 2 PIO config */
+#define HPC3_PBUS_CH3_CFGPIO 0x0005d300 /* PBus Ch. 3 PIO config */
+#define HPC3_PBUS_CH4_CFGPIO 0x0005d400 /* PBus Ch. 4 PIO config */
+#define HPC3_PBUS_CH5_CFGPIO 0x0005d500 /* PBus Ch. 5 PIO config */
+#define HPC3_PBUS_CH6_CFGPIO 0x0005d600 /* PBus Ch. 6 PIO config */
+#define HPC3_PBUS_CH7_CFGPIO 0x0005d700 /* PBus Ch. 7 PIO config */
+#define HPC3_PBUS_CH8_CFGPIO 0x0005d800 /* PBus Ch. 8 PIO config */
+#define HPC3_PBUS_CH9_CFGPIO 0x0005d900 /* PBus Ch. 9 PIO config */
+#define HPC3_PBUS_CH8_CFGPIO_2 0x0005da00 /* PBus Ch. 8 PIO config */
+#define HPC3_PBUS_CH9_CFGPIO_2 0x0005db00 /* PBus Ch. 9 PIO config */
+#define HPC3_PBUS_CH8_CFGPIO_3 0x0005dc00 /* PBus Ch. 8 PIO config */
+#define HPC3_PBUS_CH9_CFGPIO_3 0x0005dd00 /* PBus Ch. 9 PIO config */
+#define HPC3_PBUS_CH8_CFGPIO_4 0x0005de00 /* PBus Ch. 8 PIO config */
+#define HPC3_PBUS_CH9_CFGPIO_4 0x0005df00 /* PBus Ch. 9 PIO config */
+
+#define HPC3_PBUS_PROM_WE 0x0005e000 /* PBus boot-prom write
+ * enable register
+ */
+
+#define HPC3_PBUS_PROM_SWAP 0x0005e800 /* PBus boot-prom chip-select
+ * swap register
+ */
+
+#define HPC3_PBUS_GEN_OUT 0x0005f000 /* PBus general-purpose output
+ * register
+ */
+
+#define HPC3_PBUS_BBRAM 0x00060000 /* PBus battery-backed RAM
+ * external registers
+ */
+
+/* HPC1/HPC1.5 differs from HPC3 in several details. */
+
+#define HPC1_HDD_CTL_EOCHAIN 0x80000000 /* End of descriptor chain */
+#define HPC1_HDD_CTL_EOPACKET 0x80000000 /* Ethernet: end of packet */
+#define HPC1_HDD_CTL_INTR 0x00008000 /* Interrupt when finished */
+#define HPC1_HDD_CTL_OWN 0x40000000 /* CPU owns this frame */
+#define HPC1_HDD_CTL_BYTECNT(x) ((x) & 0x1fff) /* Byte count: for ethernet */
+#define HPC1_BIGENDIAN 0x000000c0 /* Endianness:5 revision:2 */
+#define HPC1_REVSHIFT 0x00000006 /* Revision rshft */
+#define HPC1_REVMASK 0x00000003 /* Revision mask */
+#define HPC1_REV15 0x00000001 /* HPC Revision 1.5 */
+#define HPC1_SCSI0_REGS 0x00000088
+#define HPC1_SCSI0_REGS_SIZE 0x00000018
+#define HPC1_SCSI0_CBP 0x00000004 /* Current buffer ptr */
+#define HPC1_SCSI0_NDBP 0x00000008 /* Next descriptor ptr */
+#define HPC1_SCSI0_BC 0x00000000 /* DMA byte count & flags */
+#define HPC1_SCSI0_CTL 0x0000000c /* DMA control flags */
+#define HPC1_SCSI0_DEV 0x00000014 /* Device DMA FIFO pointer */
+#define HPC1_SCSI0_DMACFG 0x00000010 /* DMA configuration */
+#define HPC1_SCSI0_GIO 0x00001008 /* GIO DMA FIFO pointer */
+#define HPC1_SCSI0_PIOCFG 0x00001014 /* PIO configuration */
+#define HPC1_SCSI_DMACTL_RESET 0x01 /* Reset dma channel and ext. controller */
+#define HPC1_SCSI_DMACTL_FLUSH 0x02 /* Flush DMA FIFO's */
+#define HPC1_SCSI_DMACTL_DIR 0x10 /* DMA direction: 1=dev->mem, 0=mem->dev */
+#define HPC1_SCSI_DMACTL_ACTIVE 0x80 /* DMA channel is active */
+#define HPC1_ENET_REGS 0x00000000 /* Ethernet registers */
+#define HPC1_ENET_REGS_SIZE 0x00000100
+#define HPC1_ENET_INTDELAY 0x0000002c /* Interrupt Delay Count */
+#define HPC1_ENET_INTDELAY_OFF 0x01000000 /* Disable Interrupt Delay */
+#define HPC1_ENETR_CBP 0x00000054 /* Recv: Current buffer ptr */
+#define HPC1_ENETR_NDBP 0x00000050 /* Recv: Next descriptor ptr */
+#define HPC1_ENETR_BC 0x00000048 /* Recv: DMA byte cnt/flags */
+#define HPC1_ENETR_CTL 0x00000038 /* Recv: DMA control flags */
+#define HPC1_ENETR_CTL_ACTIVE 0x00004000 /* DMA channel active? */
+#define HPC1_ENETR_RESET 0x0000003c /* Recv: Ethernet chip reset */
+#define HPC1_ENETR_RESET_CH 0x0001 /* Reset controller & chan */
+#define HPC1_ENETR_RESET_CLRINT 0x0002 /* Clear channel interrupt */
+#define HPC1_ENETR_RESET_LOOPBK 0x0004 /* External loopback enable */
+#define HPC1_ENETR_RESET_CLRRBO 0x0008 /* Clear RBO condition (??) */
+#define HPC1_ENETX_CBP 0x00000020 /* Xmit: Current buffer ptr */
+#define HPC1_ENETX_NDBP 0x00000010 /* Xmit: Next descriptor ptr */
+#define HPC1_ENETX_CFXBP 0x00000024 /* Xmit: Current first buf */
+#define HPC1_ENETX_PFXBP 0x00000028 /* Xmit: Prev. first buf */
+#define HPC1_ENETX_BC 0x00000014 /* Xmit: DMA byte cnt/flags */
+#define HPC1_ENETX_CTL 0x00000034 /* Xmit: DMA control flags */
+#define HPC1_ENETX_CTL_ACTIVE 0x00400000
+#define HPC1_ENETR_FIFO 0x0002c000 /* Ether recv DMA FIFO */
+#define HPC1_ENETR_FIFO_SIZE 0x00001fff /* Ether recv DMA FIFO size */
+#define HPC1_ENETX_FIFO 0x0002e000 /* Ether xmit DMA FIFO */
+#define HPC1_ENETX_FIFO_SIZE 0x00001fff /* Ether xmit DMA FIFO size */
+#define HPC1_SCSI0_DEVREGS 0x0000011f /* (actually 122) */
+#define HPC1_ENET_DEVREGS 0x00000100 /* Ethernet chip registers */
+#define HPC1_ENET_DEVREGS_SIZE 0x00000020 /* Size of chip registers */
+#define HPC1_PBUS_BBRAM 0x00000e00 /* PBus battery-backed RAM */
+#define HPC1_LPT_REGS 0x000000a8 /* LPT HPC Registers */
+#define HPC1_LPT_REGS_SIZE 0x00000018
+#define HPC1_LPT_BC 0x00000000 /* Byte Count */
+#define HPC1_LPT_CBP 0x00000004 /* Current Buffer Ptr */
+#define HPC1_LPT_NDBP 0x00000008 /* Next Buffer Ptr */
+#define HPC1_LPT_CTL 0x0000000c /* DMA Control Flags */
+#define HPC1_LPT_DEV 0x00000010 /* DMA Fifo Ptr */
+#define HPC1_LPT_DMACFG 0x00000014 /* DMA Configuration */
+#define HPC1_LPT_DEVREGS 0x00000132 /* Ext. Parallel Registers */
+#define HPC1_LPT_DEVREGS_SIZE 0x00000001 /* Size of External Registers */
+
+/* AUX regs on the primary HPC */
+#define HPC1_AUX_REGS 0x000001bf /* EEPROM/LED Control (byte) */
+#define HPC1_AUX_CONSLED 0x01 /* Console LED */
diff --git a/sys/arch/sgi/hpc/hpcvar.h b/sys/arch/sgi/hpc/hpcvar.h
new file mode 100644
index 00000000000..c79f284ff87
--- /dev/null
+++ b/sys/arch/sgi/hpc/hpcvar.h
@@ -0,0 +1,109 @@
+/* $OpenBSD: hpcvar.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: hpcvar.h,v 1.12 2011/01/25 12:21:04 tsutsui Exp $ */
+
+/*
+ * Copyright (c) 2001 Rafal K. Boni
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define HPCDEV_IP20 (1U << 1) /* Indigo R4k */
+#define HPCDEV_IP22 (1U << 2) /* Indigo2 */
+#define HPCDEV_IP24 (1U << 3) /* Indy */
+
+/* HPC 1.5/3 differ a bit, thus we need an abstraction layer */
+
+struct hpc_values {
+ int revision;
+ uint32_t scsi0_regs;
+ uint32_t scsi0_regs_size;
+ uint32_t scsi0_cbp;
+ uint32_t scsi0_ndbp;
+ uint32_t scsi0_bc;
+ uint32_t scsi0_ctl;
+ uint32_t scsi0_gio;
+ uint32_t scsi0_dev;
+ uint32_t scsi0_dmacfg;
+ uint32_t scsi0_piocfg;
+ uint32_t scsi1_regs;
+ uint32_t scsi1_regs_size;
+ uint32_t scsi1_cbp;
+ uint32_t scsi1_ndbp;
+ uint32_t scsi1_bc;
+ uint32_t scsi1_ctl;
+ uint32_t scsi1_gio;
+ uint32_t scsi1_dev;
+ uint32_t scsi1_dmacfg;
+ uint32_t scsi1_piocfg;
+ uint32_t enet_regs;
+ uint32_t enet_regs_size;
+ uint32_t enet_intdelay;
+ uint32_t enet_intdelayval;
+ uint32_t enetr_cbp;
+ uint32_t enetr_ndbp;
+ uint32_t enetr_bc;
+ uint32_t enetr_ctl;
+ uint32_t enetr_ctl_active;
+ uint32_t enetr_reset;
+ uint32_t enetr_dmacfg;
+ uint32_t enetr_piocfg;
+ uint32_t enetx_cbp;
+ uint32_t enetx_ndbp;
+ uint32_t enetx_bc;
+ uint32_t enetx_ctl;
+ uint32_t enetx_ctl_active;
+ uint32_t enetx_dev;
+ uint32_t enetr_fifo;
+ uint32_t enetr_fifo_size;
+ uint32_t enetx_fifo;
+ uint32_t enetx_fifo_size;
+ uint32_t enet_dma_boundary;
+ uint32_t enet_devregs;
+ uint32_t enet_devregs_size;
+ uint32_t pbus_fifo;
+ uint32_t pbus_fifo_size;
+ uint32_t pbus_bbram;
+ uint32_t scsi_dma_segs;
+ uint32_t scsi_dma_segs_size;
+ uint32_t scsi_dma_datain_cmd;
+ uint32_t scsi_dma_dataout_cmd;
+ uint32_t scsi_dmactl_flush;
+ uint32_t scsi_dmactl_active;
+ uint32_t scsi_dmactl_reset;
+};
+
+struct hpc_attach_args {
+ const char *ha_name; /* name of device */
+ bus_addr_t ha_devoff; /* offset of device */
+ bus_addr_t ha_dmaoff; /* offset of DMA regs */
+ int ha_irq; /* interrupt line */
+
+ bus_space_tag_t ha_st; /* HPC space tag */
+ bus_space_handle_t ha_sh; /* HPC space handle XXX */
+ bus_dma_tag_t ha_dmat; /* HPC DMA tag */
+
+ struct hpc_values *hpc_regs; /* HPC register definitions */
+
+ uint8_t hpc_eeprom[256];/* HPC eeprom contents */
+};
diff --git a/sys/arch/sgi/hpc/if_sq.c b/sys/arch/sgi/hpc/if_sq.c
new file mode 100644
index 00000000000..44521062c38
--- /dev/null
+++ b/sys/arch/sgi/hpc/if_sq.c
@@ -0,0 +1,1348 @@
+/* $OpenBSD: if_sq.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: if_sq.c,v 1.42 2011/07/01 18:53:47 dyoung Exp $ */
+
+/*
+ * Copyright (c) 2001 Rafal K. Boni
+ * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Portions of this code are derived from software contributed to The
+ * NetBSD Foundation by Jason R. Thorpe of the Numerical Aerospace
+ * Simulation Facility, NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/timeout.h>
+#include <sys/mbuf.h>
+#include <sys/pool.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#endif
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
+#include <netinet/if_ether.h>
+
+#include <machine/autoconf.h>
+#include <machine/bus.h>
+#include <machine/cpu.h> /* guarded_read_4 */
+#include <machine/intr.h>
+#include <mips64/arcbios.h> /* bios_enaddr */
+#include <sgi/localbus/intvar.h>
+
+#include <dev/ic/seeq8003reg.h>
+
+#include <sgi/hpc/hpcvar.h>
+#include <sgi/hpc/hpcreg.h>
+#include <sgi/hpc/if_sqvar.h>
+
+/*
+ * Short TODO list:
+ * (1) Do counters for bad-RX packets.
+ * (2) Allow multi-segment transmits, instead of copying to a single,
+ * contiguous mbuf.
+ * (3) Verify sq_stop() turns off enough stuff; I was still getting
+ * seeq interrupts after sq_stop().
+ * (4) Implement EDLC modes: especially packet auto-pad and simplex
+ * mode.
+ * (5) Should the driver filter out its own transmissions in non-EDLC
+ * mode?
+ * (6) Multicast support -- multicast filter, address management, ...
+ * (7) Deal with RB0 (recv buffer overflow) on reception. Will need
+ * to figure out if RB0 is read-only as stated in one spot in the
+ * HPC spec or read-write (ie, is the 'write a one to clear it')
+ * the correct thing?
+ */
+
+#if defined(SQ_DEBUG)
+int sq_debug = 0;
+#define SQ_DPRINTF(x) do { if (sq_debug) printf x; } while (0)
+#else
+#define SQ_DPRINTF(x) do { } while (0)
+#endif
+
+int sq_match(struct device *, void *, void *);
+void sq_attach(struct device *, struct device *, void *);
+int sq_init(struct ifnet *);
+void sq_start(struct ifnet *);
+void sq_stop(struct ifnet *);
+void sq_watchdog(struct ifnet *);
+int sq_ioctl(struct ifnet *, u_long, caddr_t);
+
+void sq_set_filter(struct sq_softc *);
+int sq_intr(void *);
+void sq_rxintr(struct sq_softc *);
+void sq_txintr(struct sq_softc *);
+void sq_txring_hpc1(struct sq_softc *);
+void sq_txring_hpc3(struct sq_softc *);
+void sq_reset(struct sq_softc *);
+int sq_add_rxbuf(struct sq_softc *, int);
+#ifdef SQ_DEBUG
+void sq_trace_dump(struct sq_softc *);
+#endif
+
+const struct cfattach sq_ca = {
+ sizeof(struct sq_softc), sq_match, sq_attach
+};
+
+struct cfdriver sq_cd = {
+ NULL, "sq", DV_IFNET
+};
+
+/* XXX these values should be moved to <net/if_ether.h> ? */
+#define ETHER_PAD_LEN (ETHER_MIN_LEN - ETHER_CRC_LEN)
+
+#define sq_seeq_read(sc, off) \
+ bus_space_read_1(sc->sc_regt, sc->sc_regh, ((off) << 2) | 3)
+#define sq_seeq_write(sc, off, val) \
+ bus_space_write_1(sc->sc_regt, sc->sc_regh, ((off) << 2) | 3, val)
+
+#define sq_hpc_read(sc, off) \
+ bus_space_read_4(sc->sc_hpct, sc->sc_hpch, off)
+#define sq_hpc_write(sc, off, val) \
+ bus_space_write_4(sc->sc_hpct, sc->sc_hpch, off, val)
+
+/* MAC address offset for non-onboard implementations */
+#define SQ_HPC_EEPROM_ENADDR 250
+
+#define SGI_OUI_0 0x08
+#define SGI_OUI_1 0x00
+#define SGI_OUI_2 0x69
+
+int
+sq_match(struct device *parent, void *vcf, void *aux)
+{
+ struct hpc_attach_args *ha = aux;
+ struct cfdata *cf = vcf;
+ vaddr_t reset, txstat;
+ uint32_t dummy;
+
+ if (strcmp(ha->ha_name, cf->cf_driver->cd_name) != 0)
+ return 0;
+
+ reset = PHYS_TO_XKPHYS(ha->ha_sh + ha->ha_dmaoff +
+ ha->hpc_regs->enetr_reset, CCA_NC);
+ txstat = PHYS_TO_XKPHYS(ha->ha_sh + ha->ha_devoff + (SEEQ_TXSTAT << 2),
+ CCA_NC);
+
+ if (guarded_read_4(reset, &dummy) != 0)
+ return 0;
+
+ *(volatile uint32_t *)reset = 0x1;
+ delay(20);
+ *(volatile uint32_t *)reset = 0x0;
+
+ if (guarded_read_4(txstat, &dummy) != 0)
+ return 0;
+
+ if ((*(volatile uint32_t *)txstat & 0xff) != TXSTAT_OLDNEW)
+ return 0;
+
+ return 1;
+}
+
+void
+sq_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct sq_softc *sc = (struct sq_softc *)self;
+ struct hpc_attach_args *haa = aux;
+ struct ifnet *ifp = &sc->sc_ac.ac_if;
+ int i, rc;
+
+ sc->sc_hpct = haa->ha_st;
+ sc->hpc_regs = haa->hpc_regs; /* HPC register definitions */
+
+ if ((rc = bus_space_subregion(haa->ha_st, haa->ha_sh,
+ haa->ha_dmaoff, sc->hpc_regs->enet_regs_size,
+ &sc->sc_hpch)) != 0) {
+ printf(": can't HPC DMA registers, error = %d\n", rc);
+ goto fail_0;
+ }
+
+ sc->sc_regt = haa->ha_st;
+ if ((rc = bus_space_subregion(haa->ha_st, haa->ha_sh,
+ haa->ha_devoff, sc->hpc_regs->enet_devregs_size,
+ &sc->sc_regh)) != 0) {
+ printf(": can't map Seeq registers, error = %d\n", rc);
+ goto fail_0;
+ }
+
+ sc->sc_dmat = haa->ha_dmat;
+
+ if ((rc = bus_dmamem_alloc(sc->sc_dmat, sizeof(struct sq_control),
+ sc->hpc_regs->enet_dma_boundary,
+ sc->hpc_regs->enet_dma_boundary, &sc->sc_cdseg, 1,
+ &sc->sc_ncdseg, BUS_DMA_NOWAIT)) != 0) {
+ printf(": unable to allocate control data, error = %d\n", rc);
+ goto fail_0;
+ }
+
+ if ((rc = bus_dmamem_map(sc->sc_dmat, &sc->sc_cdseg, sc->sc_ncdseg,
+ sizeof(struct sq_control), (caddr_t *)&sc->sc_control,
+ BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
+ printf(": unable to map control data, error = %d\n", rc);
+ goto fail_1;
+ }
+
+ if ((rc = bus_dmamap_create(sc->sc_dmat,
+ sizeof(struct sq_control), 1, sizeof(struct sq_control),
+ sc->hpc_regs->enet_dma_boundary, BUS_DMA_NOWAIT,
+ &sc->sc_cdmap)) != 0) {
+ printf(": unable to create DMA map for control data, error "
+ "= %d\n", rc);
+ goto fail_2;
+ }
+
+ if ((rc = bus_dmamap_load(sc->sc_dmat, sc->sc_cdmap,
+ sc->sc_control, sizeof(struct sq_control), NULL,
+ BUS_DMA_NOWAIT)) != 0) {
+ printf(": unable to load DMA map for control data, error "
+ "= %d\n", rc);
+ goto fail_3;
+ }
+
+ memset(sc->sc_control, 0, sizeof(struct sq_control));
+
+ /* Create transmit buffer DMA maps */
+ for (i = 0; i < SQ_NTXDESC; i++) {
+ if ((rc = bus_dmamap_create(sc->sc_dmat,
+ MCLBYTES, 1, MCLBYTES, 0,
+ BUS_DMA_NOWAIT, &sc->sc_txmap[i])) != 0) {
+ printf(": unable to create tx DMA map %d, error = %d\n",
+ i, rc);
+ goto fail_4;
+ }
+ }
+
+ /* Create receive buffer DMA maps */
+ for (i = 0; i < SQ_NRXDESC; i++) {
+ if ((rc = bus_dmamap_create(sc->sc_dmat,
+ MCLBYTES, 1, MCLBYTES, 0,
+ BUS_DMA_NOWAIT, &sc->sc_rxmap[i])) != 0) {
+ printf(": unable to create rx DMA map %d, error = %d\n",
+ i, rc);
+ goto fail_5;
+ }
+ }
+
+ /* Pre-allocate the receive buffers. */
+ for (i = 0; i < SQ_NRXDESC; i++) {
+ if ((rc = sq_add_rxbuf(sc, i)) != 0) {
+ printf(": unable to allocate or map rx buffer %d\n,"
+ " error = %d\n", i, rc);
+ goto fail_6;
+ }
+ }
+
+ bcopy(&haa->hpc_eeprom[SQ_HPC_EEPROM_ENADDR], sc->sc_ac.ac_enaddr,
+ ETHER_ADDR_LEN);
+
+ /*
+ * If our mac address is bogus, obtain it from ARCBIOS. This will
+ * be true of the onboard HPC3 on IP22, since there is no eeprom,
+ * but rather the DS1386 RTC's battery-backed ram is used.
+ */
+ if (sc->sc_ac.ac_enaddr[0] != SGI_OUI_0 ||
+ sc->sc_ac.ac_enaddr[1] != SGI_OUI_1 ||
+ sc->sc_ac.ac_enaddr[2] != SGI_OUI_2)
+ enaddr_aton(bios_enaddr, sc->sc_ac.ac_enaddr);
+
+ if ((int2_intr_establish(haa->ha_irq, IPL_NET, sq_intr, sc,
+ self->dv_xname)) == NULL) {
+ printf(": unable to establish interrupt!\n");
+ goto fail_6;
+ }
+
+ /* Reset the chip to a known state. */
+ sq_reset(sc);
+
+ /*
+ * Determine if we're an 8003 or 80c03 by setting the first
+ * MAC address register to non-zero, and then reading it back.
+ * If it's zero, we have an 80c03, because we will have read
+ * the TxCollLSB register.
+ */
+ sq_seeq_write(sc, SEEQ_TXCOLLS0, 0xa5);
+ if (sq_seeq_read(sc, SEEQ_TXCOLLS0) == 0)
+ sc->sc_type = SQ_TYPE_80C03;
+ else
+ sc->sc_type = SQ_TYPE_8003;
+ sq_seeq_write(sc, SEEQ_TXCOLLS0, 0x00);
+
+ printf(": Seeq %s, address %s\n",
+ sc->sc_type == SQ_TYPE_80C03 ? "80c03" : "8003",
+ ether_sprintf(sc->sc_ac.ac_enaddr));
+
+ bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
+ ifp->if_softc = sc;
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_start = sq_start;
+ ifp->if_ioctl = sq_ioctl;
+ ifp->if_watchdog = sq_watchdog;
+ ifp->if_flags = IFF_BROADCAST | IFF_NOTRAILERS | IFF_MULTICAST;
+ IFQ_SET_READY(&ifp->if_snd);
+
+ if_attach(ifp);
+ IFQ_SET_MAXLEN(&ifp->if_snd, SQ_NTXDESC - 1);
+ ether_ifattach(ifp);
+
+ /* Done! */
+ return;
+
+ /*
+ * Free any resources we've allocated during the failed attach
+ * attempt. Do this in reverse order and fall through.
+ */
+ fail_6:
+ for (i = 0; i < SQ_NRXDESC; i++) {
+ if (sc->sc_rxmbuf[i] != NULL) {
+ bus_dmamap_unload(sc->sc_dmat, sc->sc_rxmap[i]);
+ m_freem(sc->sc_rxmbuf[i]);
+ }
+ }
+ fail_5:
+ for (i = 0; i < SQ_NRXDESC; i++) {
+ if (sc->sc_rxmap[i] != NULL)
+ bus_dmamap_destroy(sc->sc_dmat, sc->sc_rxmap[i]);
+ }
+ fail_4:
+ for (i = 0; i < SQ_NTXDESC; i++) {
+ if (sc->sc_txmap[i] != NULL)
+ bus_dmamap_destroy(sc->sc_dmat, sc->sc_txmap[i]);
+ }
+ bus_dmamap_unload(sc->sc_dmat, sc->sc_cdmap);
+ fail_3:
+ bus_dmamap_destroy(sc->sc_dmat, sc->sc_cdmap);
+ fail_2:
+ bus_dmamem_unmap(sc->sc_dmat,
+ (void *)sc->sc_control, sizeof(struct sq_control));
+ fail_1:
+ bus_dmamem_free(sc->sc_dmat, &sc->sc_cdseg, sc->sc_ncdseg);
+ fail_0:
+ return;
+}
+
+/* Set up data to get the interface up and running. */
+int
+sq_init(struct ifnet *ifp)
+{
+ struct sq_softc *sc = ifp->if_softc;
+ int i;
+
+ /* Cancel any in-progress I/O */
+ sq_stop(ifp);
+
+ sc->sc_nextrx = 0;
+
+ sc->sc_nfreetx = SQ_NTXDESC;
+ sc->sc_nexttx = sc->sc_prevtx = 0;
+
+ SQ_TRACE(SQ_RESET, sc, 0, 0);
+
+ /* Set into 8003 mode, bank 0 to program ethernet address */
+ sq_seeq_write(sc, SEEQ_TXCMD, TXCMD_BANK0);
+
+ /* Now write the address */
+ for (i = 0; i < ETHER_ADDR_LEN; i++)
+ sq_seeq_write(sc, i, sc->sc_ac.ac_enaddr[i]);
+
+ sc->sc_rxcmd =
+ RXCMD_IE_CRC |
+ RXCMD_IE_DRIB |
+ RXCMD_IE_SHORT |
+ RXCMD_IE_END |
+ RXCMD_IE_GOOD;
+
+ /*
+ * Set the receive filter -- this will add some bits to the
+ * prototype RXCMD register. Do this before setting the
+ * transmit config register, since we might need to switch
+ * banks.
+ */
+ sq_set_filter(sc);
+
+ /* Set up Seeq transmit command register */
+ sq_seeq_write(sc, SEEQ_TXCMD,
+ TXCMD_IE_UFLOW | TXCMD_IE_COLL | TXCMD_IE_16COLL | TXCMD_IE_GOOD);
+
+ /* Now write the receive command register. */
+ sq_seeq_write(sc, SEEQ_RXCMD, sc->sc_rxcmd);
+
+ /*
+ * Set up HPC ethernet PIO and DMA configurations.
+ *
+ * The PROM appears to do most of this for the onboard HPC3, but
+ * not for the Challenge S's IOPLUS chip. We copy how the onboard
+ * chip is configured and assume that it's correct for both.
+ */
+ if (sc->hpc_regs->revision == 3) {
+ uint32_t dmareg, pioreg;
+
+ pioreg =
+ HPC3_ENETR_PIOCFG_P1(1) |
+ HPC3_ENETR_PIOCFG_P2(6) |
+ HPC3_ENETR_PIOCFG_P3(1);
+
+ dmareg =
+ HPC3_ENETR_DMACFG_D1(6) |
+ HPC3_ENETR_DMACFG_D2(2) |
+ HPC3_ENETR_DMACFG_D3(0) |
+ HPC3_ENETR_DMACFG_FIX_RXDC |
+ HPC3_ENETR_DMACFG_FIX_INTR |
+ HPC3_ENETR_DMACFG_FIX_EOP |
+ HPC3_ENETR_DMACFG_TIMEOUT;
+
+ sq_hpc_write(sc, HPC3_ENETR_PIOCFG, pioreg);
+ sq_hpc_write(sc, HPC3_ENETR_DMACFG, dmareg);
+ }
+
+ /* Pass the start of the receive ring to the HPC */
+ sq_hpc_write(sc, sc->hpc_regs->enetr_ndbp, SQ_CDRXADDR(sc, 0));
+
+ /* And turn on the HPC ethernet receive channel */
+ sq_hpc_write(sc, sc->hpc_regs->enetr_ctl,
+ sc->hpc_regs->enetr_ctl_active);
+
+ /*
+ * Turn off delayed receive interrupts on HPC1.
+ * (see Hollywood HPC Specification 2.1.4.3)
+ */
+ if (sc->hpc_regs->revision != 3)
+ sq_hpc_write(sc, HPC1_ENET_INTDELAY, HPC1_ENET_INTDELAY_OFF);
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+ sq_start(ifp);
+
+ return 0;
+}
+
+void
+sq_set_filter(struct sq_softc *sc)
+{
+ struct arpcom *ac = &sc->sc_ac;
+ struct ifnet *ifp = &sc->sc_ac.ac_if;
+ struct ether_multi *enm;
+ struct ether_multistep step;
+
+ /*
+ * Check for promiscuous mode. Also implies
+ * all-multicast.
+ */
+ if (ifp->if_flags & IFF_PROMISC) {
+ sc->sc_rxcmd |= RXCMD_REC_ALL;
+ ifp->if_flags |= IFF_ALLMULTI;
+ return;
+ }
+
+ /*
+ * The 8003 has no hash table. If we have any multicast
+ * addresses on the list, enable reception of all multicast
+ * frames.
+ *
+ * XXX The 80c03 has a hash table. We should use it.
+ */
+
+ ETHER_FIRST_MULTI(step, ac, enm);
+
+ if (enm == NULL) {
+ sc->sc_rxcmd &= ~RXCMD_REC_MASK;
+ sc->sc_rxcmd |= RXCMD_REC_BROAD;
+
+ ifp->if_flags &= ~IFF_ALLMULTI;
+ return;
+ }
+
+ sc->sc_rxcmd |= RXCMD_REC_MULTI;
+ ifp->if_flags |= IFF_ALLMULTI;
+}
+
+int
+sq_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+ struct sq_softc *sc = ifp->if_softc;
+ struct ifaddr *ifa = (struct ifaddr *)data;
+ int s, error = 0;
+
+ SQ_TRACE(SQ_IOCTL, sc, 0, 0);
+
+ s = splnet();
+
+ switch (cmd) {
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+ if (!(ifp->if_flags & IFF_RUNNING))
+ sq_init(ifp);
+#ifdef INET
+ if (ifa->ifa_addr->sa_family == AF_INET)
+ arp_ifinit(&sc->sc_ac, ifa);
+#endif
+ break;
+
+ case SIOCSIFFLAGS:
+ if (ifp->if_flags & IFF_UP) {
+ if (ifp->if_flags & IFF_RUNNING)
+ error = ENETRESET;
+ else
+ sq_init(ifp);
+ } else {
+ if (ifp->if_flags & IFF_RUNNING)
+ sq_stop(ifp);
+ }
+ break;
+
+ default:
+ error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
+ break;
+ }
+
+ if (error == ENETRESET) {
+ /*
+ * Multicast list has changed; set the hardware filter
+ * accordingly.
+ */
+ if (ifp->if_flags & IFF_RUNNING)
+ error = sq_init(ifp);
+ else
+ error = 0;
+ }
+
+ splx(s);
+ return error;
+}
+
+void
+sq_start(struct ifnet *ifp)
+{
+ struct sq_softc *sc = ifp->if_softc;
+ uint32_t status;
+ struct mbuf *m0, *m;
+ bus_dmamap_t dmamap;
+ int err, len, totlen, nexttx, firsttx, lasttx = -1, ofree, seg;
+
+ if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)
+ return;
+
+ /*
+ * Remember the previous number of free descriptors and
+ * the first descriptor we'll use.
+ */
+ ofree = sc->sc_nfreetx;
+ firsttx = sc->sc_nexttx;
+
+ /*
+ * Loop through the send queue, setting up transmit descriptors
+ * until we drain the queue, or use up all available transmit
+ * descriptors.
+ */
+ while (sc->sc_nfreetx != 0) {
+ /*
+ * Grab a packet off the queue.
+ */
+ IFQ_POLL(&ifp->if_snd, m0);
+ if (m0 == NULL)
+ break;
+ m = NULL;
+
+ dmamap = sc->sc_txmap[sc->sc_nexttx];
+
+ /*
+ * Load the DMA map. If this fails, the packet either
+ * didn't fit in the alloted number of segments, or we were
+ * short on resources. In this case, we'll copy and try
+ * again.
+ * Also copy it if we need to pad, so that we are sure there
+ * is room for the pad buffer.
+ * XXX the right way of doing this is to use a static buffer
+ * for padding and adding it to the transmit descriptor (see
+ * sys/dev/pci/if_tl.c for example). We can't do this here yet
+ * because we can't send packets with more than one fragment.
+ */
+ len = m0->m_pkthdr.len;
+ if (len < ETHER_PAD_LEN ||
+ bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, m0,
+ BUS_DMA_NOWAIT) != 0) {
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL) {
+ printf("%s: unable to allocate Tx mbuf\n",
+ sc->sc_dev.dv_xname);
+ break;
+ }
+ if (len > MHLEN) {
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ printf("%s: unable to allocate Tx "
+ "cluster\n",
+ sc->sc_dev.dv_xname);
+ m_freem(m);
+ break;
+ }
+ }
+
+ m_copydata(m0, 0, len, mtod(m, void *));
+ if (len < ETHER_PAD_LEN) {
+ memset(mtod(m, char *) + len, 0,
+ ETHER_PAD_LEN - len);
+ len = ETHER_PAD_LEN;
+ }
+ m->m_pkthdr.len = m->m_len = len;
+
+ if ((err = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap,
+ m, BUS_DMA_NOWAIT)) != 0) {
+ printf("%s: unable to load Tx buffer, "
+ "error = %d\n",
+ sc->sc_dev.dv_xname, err);
+ break;
+ }
+ }
+
+ /*
+ * Ensure we have enough descriptors free to describe
+ * the packet.
+ */
+ if (dmamap->dm_nsegs > sc->sc_nfreetx) {
+ /*
+ * Not enough free descriptors to transmit this
+ * packet. We haven't committed to anything yet,
+ * so just unload the DMA map, put the packet
+ * back on the queue, and punt. Notify the upper
+ * layer that there are no more slots left.
+ *
+ * XXX We could allocate an mbuf and copy, but
+ * XXX it is worth it?
+ */
+ ifp->if_flags |= IFF_OACTIVE;
+ bus_dmamap_unload(sc->sc_dmat, dmamap);
+ if (m != NULL)
+ m_freem(m);
+ break;
+ }
+
+ IFQ_DEQUEUE(&ifp->if_snd, m0);
+#if NBPFILTER > 0
+ /*
+ * Pass the packet to any BPF listeners.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
+#endif
+ if (m != NULL) {
+ m_freem(m0);
+ m0 = m;
+ }
+
+ /*
+ * WE ARE NOW COMMITTED TO TRANSMITTING THE PACKET.
+ */
+
+ SQ_TRACE(SQ_ENQUEUE, sc, sc->sc_nexttx, 0);
+
+ /* Sync the DMA map. */
+ bus_dmamap_sync(sc->sc_dmat, dmamap, 0, dmamap->dm_mapsize,
+ BUS_DMASYNC_PREWRITE);
+
+ /*
+ * Initialize the transmit descriptors.
+ */
+ for (nexttx = sc->sc_nexttx, seg = 0, totlen = 0;
+ seg < dmamap->dm_nsegs;
+ seg++, nexttx = SQ_NEXTTX(nexttx)) {
+ if (sc->hpc_regs->revision == 3) {
+ sc->sc_txdesc[nexttx].hpc3_hdd_bufptr =
+ dmamap->dm_segs[seg].ds_addr;
+ sc->sc_txdesc[nexttx].hpc3_hdd_ctl =
+ dmamap->dm_segs[seg].ds_len;
+ } else {
+ sc->sc_txdesc[nexttx].hpc1_hdd_bufptr =
+ dmamap->dm_segs[seg].ds_addr;
+ sc->sc_txdesc[nexttx].hpc1_hdd_ctl =
+ dmamap->dm_segs[seg].ds_len;
+ }
+ sc->sc_txdesc[nexttx].hdd_descptr =
+ SQ_CDTXADDR(sc, SQ_NEXTTX(nexttx));
+ lasttx = nexttx;
+ totlen += dmamap->dm_segs[seg].ds_len;
+ }
+
+ /* Last descriptor gets end-of-packet */
+ KASSERT(lasttx != -1);
+ if (sc->hpc_regs->revision == 3)
+ sc->sc_txdesc[lasttx].hpc3_hdd_ctl |=
+ HPC3_HDD_CTL_EOPACKET;
+ else
+ sc->sc_txdesc[lasttx].hpc1_hdd_ctl |=
+ HPC1_HDD_CTL_EOPACKET;
+
+ SQ_DPRINTF(("%s: transmit %d-%d, len %d\n",
+ sc->sc_dev.dv_xname, sc->sc_nexttx, lasttx, totlen));
+
+ if (ifp->if_flags & IFF_DEBUG) {
+ printf(" transmit chain:\n");
+ for (seg = sc->sc_nexttx;; seg = SQ_NEXTTX(seg)) {
+ printf(" descriptor %d:\n", seg);
+ printf(" hdd_bufptr: 0x%08x\n",
+ (sc->hpc_regs->revision == 3) ?
+ sc->sc_txdesc[seg].hpc3_hdd_bufptr :
+ sc->sc_txdesc[seg].hpc1_hdd_bufptr);
+ printf(" hdd_ctl: 0x%08x\n",
+ (sc->hpc_regs->revision == 3) ?
+ sc->sc_txdesc[seg].hpc3_hdd_ctl:
+ sc->sc_txdesc[seg].hpc1_hdd_ctl);
+ printf(" hdd_descptr: 0x%08x\n",
+ sc->sc_txdesc[seg].hdd_descptr);
+
+ if (seg == lasttx)
+ break;
+ }
+ }
+
+ /* Sync the descriptors we're using. */
+ SQ_CDTXSYNC(sc, sc->sc_nexttx, dmamap->dm_nsegs,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ /* Store a pointer to the packet so we can free it later */
+ sc->sc_txmbuf[sc->sc_nexttx] = m0;
+
+ /* Advance the tx pointer. */
+ sc->sc_nfreetx -= dmamap->dm_nsegs;
+ sc->sc_nexttx = nexttx;
+ }
+
+ /* All transmit descriptors used up, let upper layers know */
+ if (sc->sc_nfreetx == 0)
+ ifp->if_flags |= IFF_OACTIVE;
+
+ if (sc->sc_nfreetx != ofree) {
+ SQ_DPRINTF(("%s: %d packets enqueued, first %d, INTR on %d\n",
+ sc->sc_dev.dv_xname, lasttx - firsttx + 1,
+ firsttx, lasttx));
+
+ /*
+ * Cause a transmit interrupt to happen on the
+ * last packet we enqueued, mark it as the last
+ * descriptor.
+ *
+ * HPC1_HDD_CTL_INTR will generate an interrupt on
+ * HPC1. HPC3 requires HPC3_HDD_CTL_EOPACKET in
+ * addition to HPC3_HDD_CTL_INTR to interrupt.
+ */
+ KASSERT(lasttx != -1);
+ if (sc->hpc_regs->revision == 3) {
+ sc->sc_txdesc[lasttx].hpc3_hdd_ctl |=
+ HPC3_HDD_CTL_INTR | HPC3_HDD_CTL_EOCHAIN;
+ } else {
+ sc->sc_txdesc[lasttx].hpc1_hdd_ctl |= HPC1_HDD_CTL_INTR;
+ sc->sc_txdesc[lasttx].hpc1_hdd_bufptr |=
+ HPC1_HDD_CTL_EOCHAIN;
+ }
+
+ SQ_CDTXSYNC(sc, lasttx, 1,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ /*
+ * There is a potential race condition here if the HPC
+ * DMA channel is active and we try and either update
+ * the 'next descriptor' pointer in the HPC PIO space
+ * or the 'next descriptor' pointer in a previous desc-
+ * riptor.
+ *
+ * To avoid this, if the channel is active, we rely on
+ * the transmit interrupt routine noticing that there
+ * are more packets to send and restarting the HPC DMA
+ * engine, rather than mucking with the DMA state here.
+ */
+ status = sq_hpc_read(sc, sc->hpc_regs->enetx_ctl);
+
+ if ((status & sc->hpc_regs->enetx_ctl_active) != 0) {
+ SQ_TRACE(SQ_ADD_TO_DMA, sc, firsttx, status);
+
+ /*
+ * NB: hpc3_hdd_ctl == hpc1_hdd_bufptr, and
+ * HPC1_HDD_CTL_EOCHAIN == HPC3_HDD_CTL_EOCHAIN
+ */
+ sc->sc_txdesc[SQ_PREVTX(firsttx)].hpc3_hdd_ctl &=
+ ~HPC3_HDD_CTL_EOCHAIN;
+
+ if (sc->hpc_regs->revision != 3)
+ sc->sc_txdesc[SQ_PREVTX(firsttx)].hpc1_hdd_ctl
+ &= ~HPC1_HDD_CTL_INTR;
+
+ SQ_CDTXSYNC(sc, SQ_PREVTX(firsttx), 1,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+ } else if (sc->hpc_regs->revision == 3) {
+ SQ_TRACE(SQ_START_DMA, sc, firsttx, status);
+
+ sq_hpc_write(sc, HPC3_ENETX_NDBP, SQ_CDTXADDR(sc,
+ firsttx));
+
+ /* Kick DMA channel into life */
+ sq_hpc_write(sc, HPC3_ENETX_CTL, HPC3_ENETX_CTL_ACTIVE);
+ } else {
+ /*
+ * In the HPC1 case where transmit DMA is
+ * inactive, we can either kick off if
+ * the ring was previously empty, or call
+ * our transmit interrupt handler to
+ * figure out if the ring stopped short
+ * and restart at the right place.
+ */
+ if (ofree == SQ_NTXDESC) {
+ SQ_TRACE(SQ_START_DMA, sc, firsttx, status);
+
+ sq_hpc_write(sc, HPC1_ENETX_NDBP,
+ SQ_CDTXADDR(sc, firsttx));
+ sq_hpc_write(sc, HPC1_ENETX_CFXBP,
+ SQ_CDTXADDR(sc, firsttx));
+ sq_hpc_write(sc, HPC1_ENETX_CBP,
+ SQ_CDTXADDR(sc, firsttx));
+
+ /* Kick DMA channel into life */
+ sq_hpc_write(sc, HPC1_ENETX_CTL,
+ HPC1_ENETX_CTL_ACTIVE);
+ } else
+ sq_txring_hpc1(sc);
+ }
+
+ /* Set a watchdog timer in case the chip flakes out. */
+ ifp->if_timer = 5;
+ }
+}
+
+void
+sq_stop(struct ifnet *ifp)
+{
+ struct sq_softc *sc = ifp->if_softc;
+ int i;
+
+ ifp->if_timer = 0;
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+
+ for (i = 0; i < SQ_NTXDESC; i++) {
+ if (sc->sc_txmbuf[i] != NULL) {
+ bus_dmamap_unload(sc->sc_dmat, sc->sc_txmap[i]);
+ m_freem(sc->sc_txmbuf[i]);
+ sc->sc_txmbuf[i] = NULL;
+ }
+ }
+
+ /* Clear Seeq transmit/receive command registers */
+ sq_seeq_write(sc, SEEQ_TXCMD, 0);
+ sq_seeq_write(sc, SEEQ_RXCMD, 0);
+
+ sq_reset(sc);
+}
+
+/* Device timeout/watchdog routine. */
+void
+sq_watchdog(struct ifnet *ifp)
+{
+ struct sq_softc *sc = ifp->if_softc;
+ uint32_t status;
+
+ status = sq_hpc_read(sc, sc->hpc_regs->enetx_ctl);
+ log(LOG_ERR, "%s: device timeout (prev %d, next %d, free %d, "
+ "status %08x)\n", sc->sc_dev.dv_xname, sc->sc_prevtx,
+ sc->sc_nexttx, sc->sc_nfreetx, status);
+
+#ifdef SQ_DEBUG
+ sq_trace_dump(sc);
+#endif
+
+ ++ifp->if_oerrors;
+
+ sq_init(ifp);
+}
+
+#ifdef SQ_DEBUG
+void
+sq_trace_dump(struct sq_softc *sc)
+{
+ int i;
+ const char *act;
+
+ for (i = 0; i < sc->sq_trace_idx; i++) {
+ switch (sc->sq_trace[i].action) {
+ case SQ_RESET: act = "SQ_RESET"; break;
+ case SQ_ADD_TO_DMA: act = "SQ_ADD_TO_DMA"; break;
+ case SQ_START_DMA: act = "SQ_START_DMA"; break;
+ case SQ_DONE_DMA: act = "SQ_DONE_DMA"; break;
+ case SQ_RESTART_DMA: act = "SQ_RESTART_DMA"; break;
+ case SQ_TXINTR_ENTER: act = "SQ_TXINTR_ENTER"; break;
+ case SQ_TXINTR_EXIT: act = "SQ_TXINTR_EXIT"; break;
+ case SQ_TXINTR_BUSY: act = "SQ_TXINTR_BUSY"; break;
+ case SQ_IOCTL: act = "SQ_IOCTL"; break;
+ case SQ_ENQUEUE: act = "SQ_ENQUEUE"; break;
+ default: act = "UNKNOWN";
+ }
+
+ printf("%s: [%03d] action %-16s buf %03d free %03d "
+ "status %08x line %d\n", sc->sc_dev.dv_xname, i, act,
+ sc->sq_trace[i].bufno, sc->sq_trace[i].freebuf,
+ sc->sq_trace[i].status, sc->sq_trace[i].line);
+ }
+
+ memset(&sc->sq_trace, 0, sizeof(sc->sq_trace));
+ sc->sq_trace_idx = 0;
+}
+#endif
+
+int
+sq_intr(void *arg)
+{
+ struct sq_softc *sc = arg;
+ struct ifnet *ifp = &sc->sc_ac.ac_if;
+ uint32_t stat;
+
+ stat = sq_hpc_read(sc, sc->hpc_regs->enetr_reset);
+
+ if ((stat & 2) == 0) {
+ SQ_DPRINTF(("%s: Unexpected interrupt!\n",
+ sc->sc_dev.dv_xname));
+ } else
+ sq_hpc_write(sc, sc->hpc_regs->enetr_reset, (stat | 2));
+
+ /*
+ * If the interface isn't running, the interrupt couldn't
+ * possibly have come from us.
+ */
+ if ((ifp->if_flags & IFF_RUNNING) == 0)
+ return 0;
+
+ /* Always check for received packets */
+ sq_rxintr(sc);
+
+ /* Only handle transmit interrupts if we actually sent something */
+ if (sc->sc_nfreetx < SQ_NTXDESC)
+ sq_txintr(sc);
+
+ /*
+ * XXX Always claim the interrupt, even if we did nothing.
+ * XXX There seem to be extra interrupts when the receiver becomes
+ * XXX idle.
+ */
+ return 1;
+}
+
+void
+sq_rxintr(struct sq_softc *sc)
+{
+ struct ifnet *ifp = &sc->sc_ac.ac_if;
+ struct mbuf* m;
+ int i, framelen;
+ uint8_t pktstat;
+ uint32_t status;
+ uint32_t ctl_reg;
+ int new_end, orig_end;
+
+ for (i = sc->sc_nextrx; ; i = SQ_NEXTRX(i)) {
+ SQ_CDRXSYNC(sc, i,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ /*
+ * If this is a CPU-owned buffer, we're at the end of the list.
+ */
+ if (sc->hpc_regs->revision == 3)
+ ctl_reg =
+ sc->sc_rxdesc[i].hpc3_hdd_ctl & HPC3_HDD_CTL_OWN;
+ else
+ ctl_reg =
+ sc->sc_rxdesc[i].hpc1_hdd_ctl & HPC1_HDD_CTL_OWN;
+
+ if (ctl_reg) {
+#if defined(SQ_DEBUG)
+ uint32_t reg;
+
+ reg = sq_hpc_read(sc, sc->hpc_regs->enetr_ctl);
+ SQ_DPRINTF(("%s: rxintr: done at %d (ctl %08x)\n",
+ sc->sc_dev.dv_xname, i, reg));
+#endif
+ break;
+ }
+
+ m = sc->sc_rxmbuf[i];
+ framelen = m->m_ext.ext_size - 3;
+ if (sc->hpc_regs->revision == 3)
+ framelen -=
+ HPC3_HDD_CTL_BYTECNT(sc->sc_rxdesc[i].hpc3_hdd_ctl);
+ else
+ framelen -=
+ HPC1_HDD_CTL_BYTECNT(sc->sc_rxdesc[i].hpc1_hdd_ctl);
+
+ /* Now sync the actual packet data */
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[i], 0,
+ sc->sc_rxmap[i]->dm_mapsize, BUS_DMASYNC_POSTREAD);
+
+ pktstat = *((uint8_t *)m->m_data + framelen + 2);
+
+ if ((pktstat & RXSTAT_GOOD) == 0) {
+ ifp->if_ierrors++;
+
+ if (pktstat & RXSTAT_OFLOW)
+ printf("%s: receive FIFO overflow\n",
+ sc->sc_dev.dv_xname);
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[i], 0,
+ sc->sc_rxmap[i]->dm_mapsize, BUS_DMASYNC_PREREAD);
+ SQ_INIT_RXDESC(sc, i);
+ SQ_DPRINTF(("%s: sq_rxintr: buf %d no RXSTAT_GOOD\n",
+ sc->sc_dev.dv_xname, i));
+ continue;
+ }
+
+ if (sq_add_rxbuf(sc, i) != 0) {
+ ifp->if_ierrors++;
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[i], 0,
+ sc->sc_rxmap[i]->dm_mapsize, BUS_DMASYNC_PREREAD);
+ SQ_INIT_RXDESC(sc, i);
+ SQ_DPRINTF(("%s: sq_rxintr: buf %d sq_add_rxbuf() "
+ "failed\n", sc->sc_dev.dv_xname, i));
+ continue;
+ }
+
+
+ m->m_data += 2;
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = m->m_len = framelen;
+
+ ifp->if_ipackets++;
+
+ SQ_DPRINTF(("%s: sq_rxintr: buf %d len %d\n",
+ sc->sc_dev.dv_xname, i, framelen));
+
+#if NBPFILTER > 0
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
+#endif
+
+ ether_input_mbuf(ifp, m);
+ }
+
+
+ /* If anything happened, move ring start/end pointers to new spot */
+ if (i != sc->sc_nextrx) {
+ /*
+ * NB: hpc3_hdd_ctl == hpc1_hdd_bufptr, and
+ * HPC1_HDD_CTL_EOCHAIN == HPC3_HDD_CTL_EOCHAIN
+ */
+
+ new_end = SQ_PREVRX(i);
+ sc->sc_rxdesc[new_end].hpc3_hdd_ctl |= HPC3_HDD_CTL_EOCHAIN;
+ SQ_CDRXSYNC(sc, new_end,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ orig_end = SQ_PREVRX(sc->sc_nextrx);
+ sc->sc_rxdesc[orig_end].hpc3_hdd_ctl &= ~HPC3_HDD_CTL_EOCHAIN;
+ SQ_CDRXSYNC(sc, orig_end,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ sc->sc_nextrx = i;
+ }
+
+ status = sq_hpc_read(sc, sc->hpc_regs->enetr_ctl);
+
+ /* If receive channel is stopped, restart it... */
+ if ((status & sc->hpc_regs->enetr_ctl_active) == 0) {
+ /* Pass the start of the receive ring to the HPC */
+ sq_hpc_write(sc, sc->hpc_regs->enetr_ndbp,
+ SQ_CDRXADDR(sc, sc->sc_nextrx));
+
+ /* And turn on the HPC ethernet receive channel */
+ sq_hpc_write(sc, sc->hpc_regs->enetr_ctl,
+ sc->hpc_regs->enetr_ctl_active);
+ }
+}
+
+void
+sq_txintr(struct sq_softc *sc)
+{
+ struct ifnet *ifp = &sc->sc_ac.ac_if;
+ uint shift = 0;
+ uint32_t status, tmp;
+
+ if (sc->hpc_regs->revision != 3)
+ shift = 16;
+
+ status = sq_hpc_read(sc, sc->hpc_regs->enetx_ctl) >> shift;
+
+ SQ_TRACE(SQ_TXINTR_ENTER, sc, sc->sc_prevtx, status);
+
+ tmp = (sc->hpc_regs->enetx_ctl_active >> shift) | TXSTAT_GOOD;
+ if ((status & tmp) == 0) {
+ if (status & TXSTAT_COLL)
+ ifp->if_collisions++;
+
+ if (status & TXSTAT_UFLOW) {
+ printf("%s: transmit underflow\n",
+ sc->sc_dev.dv_xname);
+ ifp->if_oerrors++;
+#ifdef SQ_DEBUG
+ sq_trace_dump(sc);
+#endif
+ sq_init(ifp);
+ return;
+ }
+
+ if (status & TXSTAT_16COLL) {
+ printf("%s: max collisions reached\n",
+ sc->sc_dev.dv_xname);
+ ifp->if_oerrors++;
+ ifp->if_collisions += 16;
+ }
+ }
+
+ /* prevtx now points to next xmit packet not yet finished */
+ if (sc->hpc_regs->revision == 3)
+ sq_txring_hpc3(sc);
+ else
+ sq_txring_hpc1(sc);
+
+ /* If we have buffers free, let upper layers know */
+ if (sc->sc_nfreetx > 0)
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ /* If all packets have left the coop, cancel watchdog */
+ if (sc->sc_nfreetx == SQ_NTXDESC)
+ ifp->if_timer = 0;
+
+ SQ_TRACE(SQ_TXINTR_EXIT, sc, sc->sc_prevtx, status);
+ sq_start(ifp);
+}
+
+/*
+ * Reclaim used transmit descriptors and restart the transmit DMA
+ * engine if necessary.
+ */
+void
+sq_txring_hpc1(struct sq_softc *sc)
+{
+ /*
+ * HPC1 doesn't tag transmitted descriptors, however,
+ * the NDBP register points to the next descriptor that
+ * has not yet been processed. If DMA is not in progress,
+ * we can safely reclaim all descriptors up to NDBP, and,
+ * if necessary, restart DMA at NDBP. Otherwise, if DMA
+ * is active, we can only safely reclaim up to CBP.
+ *
+ * For now, we'll only reclaim on inactive DMA and assume
+ * that a sufficiently large ring keeps us out of trouble.
+ */
+ struct ifnet *ifp = &sc->sc_ac.ac_if;
+ uint32_t reclaimto, status;
+ int reclaimall, i = sc->sc_prevtx;
+
+ status = sq_hpc_read(sc, HPC1_ENETX_CTL);
+ if (status & HPC1_ENETX_CTL_ACTIVE) {
+ SQ_TRACE(SQ_TXINTR_BUSY, sc, i, status);
+ return;
+ } else
+ reclaimto = sq_hpc_read(sc, HPC1_ENETX_NDBP);
+
+ if (sc->sc_nfreetx == 0 && SQ_CDTXADDR(sc, i) == reclaimto)
+ reclaimall = 1;
+ else
+ reclaimall = 0;
+
+ while (sc->sc_nfreetx < SQ_NTXDESC) {
+ if (SQ_CDTXADDR(sc, i) == reclaimto && !reclaimall)
+ break;
+
+ SQ_CDTXSYNC(sc, i, sc->sc_txmap[i]->dm_nsegs,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ /* Sync the packet data, unload DMA map, free mbuf */
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_txmap[i],
+ 0, sc->sc_txmap[i]->dm_mapsize, BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->sc_dmat, sc->sc_txmap[i]);
+ m_freem(sc->sc_txmbuf[i]);
+ sc->sc_txmbuf[i] = NULL;
+
+ ifp->if_opackets++;
+ sc->sc_nfreetx++;
+
+ SQ_TRACE(SQ_DONE_DMA, sc, i, status);
+
+ i = SQ_NEXTTX(i);
+ }
+
+ if (sc->sc_nfreetx < SQ_NTXDESC) {
+ SQ_TRACE(SQ_RESTART_DMA, sc, i, status);
+
+ KASSERT(reclaimto == SQ_CDTXADDR(sc, i));
+
+ sq_hpc_write(sc, HPC1_ENETX_CFXBP, reclaimto);
+ sq_hpc_write(sc, HPC1_ENETX_CBP, reclaimto);
+
+ /* Kick DMA channel into life */
+ sq_hpc_write(sc, HPC1_ENETX_CTL, HPC1_ENETX_CTL_ACTIVE);
+
+ /*
+ * Set a watchdog timer in case the chip
+ * flakes out.
+ */
+ ifp->if_timer = 5;
+ }
+
+ sc->sc_prevtx = i;
+}
+
+/*
+ * Reclaim used transmit descriptors and restart the transmit DMA
+ * engine if necessary.
+ */
+void
+sq_txring_hpc3(struct sq_softc *sc)
+{
+ /*
+ * HPC3 tags descriptors with a bit once they've been
+ * transmitted. We need only free each XMITDONE'd
+ * descriptor, and restart the DMA engine if any
+ * descriptors are left over.
+ */
+ struct ifnet *ifp = &sc->sc_ac.ac_if;
+ int i;
+ uint32_t status = 0;
+
+ i = sc->sc_prevtx;
+ while (sc->sc_nfreetx < SQ_NTXDESC) {
+ /*
+ * Check status first so we don't end up with a case of
+ * the buffer not being finished while the DMA channel
+ * has gone idle.
+ */
+ status = sq_hpc_read(sc, HPC3_ENETX_CTL);
+
+ SQ_CDTXSYNC(sc, i, sc->sc_txmap[i]->dm_nsegs,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ /* Check for used descriptor and restart DMA chain if needed */
+ if ((sc->sc_txdesc[i].hpc3_hdd_ctl &
+ HPC3_HDD_CTL_XMITDONE) == 0) {
+ if ((status & HPC3_ENETX_CTL_ACTIVE) == 0) {
+ SQ_TRACE(SQ_RESTART_DMA, sc, i, status);
+
+ sq_hpc_write(sc, HPC3_ENETX_NDBP,
+ SQ_CDTXADDR(sc, i));
+
+ /* Kick DMA channel into life */
+ sq_hpc_write(sc, HPC3_ENETX_CTL,
+ HPC3_ENETX_CTL_ACTIVE);
+
+ /*
+ * Set a watchdog timer in case the chip
+ * flakes out.
+ */
+ ifp->if_timer = 5;
+ } else
+ SQ_TRACE(SQ_TXINTR_BUSY, sc, i, status);
+ break;
+ }
+
+ /* Sync the packet data, unload DMA map, free mbuf */
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_txmap[i],
+ 0, sc->sc_txmap[i]->dm_mapsize, BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->sc_dmat, sc->sc_txmap[i]);
+ m_freem(sc->sc_txmbuf[i]);
+ sc->sc_txmbuf[i] = NULL;
+
+ ifp->if_opackets++;
+ sc->sc_nfreetx++;
+
+ SQ_TRACE(SQ_DONE_DMA, sc, i, status);
+ i = SQ_NEXTTX(i);
+ }
+
+ sc->sc_prevtx = i;
+}
+
+void
+sq_reset(struct sq_softc *sc)
+{
+ /* Stop HPC dma channels */
+ sq_hpc_write(sc, sc->hpc_regs->enetr_ctl, 0);
+ sq_hpc_write(sc, sc->hpc_regs->enetx_ctl, 0);
+
+ sq_hpc_write(sc, sc->hpc_regs->enetr_reset, 3);
+ delay(20);
+ sq_hpc_write(sc, sc->hpc_regs->enetr_reset, 0);
+}
+
+/* sq_add_rxbuf: Add a receive buffer to the indicated descriptor. */
+int
+sq_add_rxbuf(struct sq_softc *sc, int idx)
+{
+ int err;
+ struct mbuf *m;
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ return ENOBUFS;
+
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ m_freem(m);
+ return ENOBUFS;
+ }
+
+ if (sc->sc_rxmbuf[idx] != NULL)
+ bus_dmamap_unload(sc->sc_dmat, sc->sc_rxmap[idx]);
+
+ sc->sc_rxmbuf[idx] = m;
+
+ if ((err = bus_dmamap_load(sc->sc_dmat, sc->sc_rxmap[idx],
+ m->m_ext.ext_buf, m->m_ext.ext_size, NULL, BUS_DMA_NOWAIT)) != 0) {
+ printf("%s: can't load rx DMA map %d, error = %d\n",
+ sc->sc_dev.dv_xname, idx, err);
+ panic("sq_add_rxbuf"); /* XXX */
+ }
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[idx],
+ 0, sc->sc_rxmap[idx]->dm_mapsize, BUS_DMASYNC_PREREAD);
+
+ SQ_INIT_RXDESC(sc, idx);
+
+ return 0;
+}
diff --git a/sys/arch/sgi/hpc/if_sqvar.h b/sys/arch/sgi/hpc/if_sqvar.h
new file mode 100644
index 00000000000..657025771f7
--- /dev/null
+++ b/sys/arch/sgi/hpc/if_sqvar.h
@@ -0,0 +1,200 @@
+/* $OpenBSD: if_sqvar.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: sqvar.h,v 1.12 2011/01/25 13:12:39 tsutsui Exp $ */
+
+/*
+ * Copyright (c) 2001 Rafal K. Boni
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Note, these must be powers of two for the magic NEXT/PREV macros to work */
+#define SQ_NRXDESC 64
+#define SQ_NTXDESC 64
+
+#define SQ_NRXDESC_MASK (SQ_NRXDESC - 1)
+#define SQ_NEXTRX(x) ((x + 1) & SQ_NRXDESC_MASK)
+#define SQ_PREVRX(x) ((x - 1) & SQ_NRXDESC_MASK)
+
+#define SQ_NTXDESC_MASK (SQ_NTXDESC - 1)
+#define SQ_NEXTTX(x) ((x + 1) & SQ_NTXDESC_MASK)
+#define SQ_PREVTX(x) ((x - 1) & SQ_NTXDESC_MASK)
+
+/*
+ * We pack all DMA control structures into one container so we can alloc just
+ * one chunk of DMA-safe memory and pack them into it. Otherwise, we'd have to
+ * allocate a page for each descriptor, since the bus_dmamem_alloc() interface
+ * does not allow us to allocate smaller chunks.
+ */
+struct sq_control {
+ /* Receive descriptors */
+ struct hpc_dma_desc rx_desc[SQ_NRXDESC];
+
+ /* Transmit descriptors */
+ struct hpc_dma_desc tx_desc[SQ_NTXDESC];
+};
+
+#define SQ_CDOFF(x) offsetof(struct sq_control, x)
+#define SQ_CDTXOFF(x) SQ_CDOFF(tx_desc[(x)])
+#define SQ_CDRXOFF(x) SQ_CDOFF(rx_desc[(x)])
+
+#define SQ_TYPE_8003 0
+#define SQ_TYPE_80C03 1
+
+/* Trace Actions */
+#define SQ_RESET 1
+#define SQ_ADD_TO_DMA 2
+#define SQ_START_DMA 3
+#define SQ_DONE_DMA 4
+#define SQ_RESTART_DMA 5
+#define SQ_TXINTR_ENTER 6
+#define SQ_TXINTR_EXIT 7
+#define SQ_TXINTR_BUSY 8
+#define SQ_IOCTL 9
+#define SQ_ENQUEUE 10
+
+struct sq_action_trace {
+ int action;
+ int line;
+ int bufno;
+ int status;
+ int freebuf;
+};
+
+#ifdef SQ_DEBUG
+#define SQ_TRACEBUF_SIZE 100
+
+#define SQ_TRACE(act, sc, buf, stat) do { \
+ (sc)->sq_trace[(sc)->sq_trace_idx].action = (act); \
+ (sc)->sq_trace[(sc)->sq_trace_idx].line = __LINE__; \
+ (sc)->sq_trace[(sc)->sq_trace_idx].bufno = (buf); \
+ (sc)->sq_trace[(sc)->sq_trace_idx].status = (stat); \
+ (sc)->sq_trace[(sc)->sq_trace_idx].freebuf = (sc)->sc_nfreetx; \
+ if (++(sc)->sq_trace_idx == SQ_TRACEBUF_SIZE) \
+ (sc)->sq_trace_idx = 0; \
+} while (/* CONSTCOND */0)
+#else
+#define SQ_TRACE(act, sc, buf, stat) do { } while (/* CONSTCOND */0)
+#endif
+
+struct sq_softc {
+ struct device sc_dev;
+
+ /* HPC registers */
+ bus_space_tag_t sc_hpct;
+ bus_space_handle_t sc_hpch;
+
+ /* HPC external Ethernet registers: aka Seeq 8003 registers */
+ bus_space_tag_t sc_regt;
+ bus_space_handle_t sc_regh;
+
+ bus_dma_tag_t sc_dmat;
+
+ struct arpcom sc_ac;
+ uint8_t sc_enaddr[ETHER_ADDR_LEN];
+
+ int sc_type;
+
+ struct sq_control* sc_control;
+#define sc_rxdesc sc_control->rx_desc
+#define sc_txdesc sc_control->tx_desc
+
+ /* DMA structures for control data (DMA RX/TX descriptors) */
+ int sc_ncdseg;
+ bus_dma_segment_t sc_cdseg;
+ bus_dmamap_t sc_cdmap;
+#define sc_cddma sc_cdmap->dm_segs[0].ds_addr
+
+ int sc_nextrx;
+
+ /* DMA structures for RX packet data */
+ bus_dma_segment_t sc_rxseg[SQ_NRXDESC];
+ bus_dmamap_t sc_rxmap[SQ_NRXDESC];
+ struct mbuf* sc_rxmbuf[SQ_NRXDESC];
+
+ int sc_nexttx;
+ int sc_prevtx;
+ int sc_nfreetx;
+
+ /* DMA structures for TX packet data */
+ bus_dma_segment_t sc_txseg[SQ_NTXDESC];
+ bus_dmamap_t sc_txmap[SQ_NTXDESC];
+ struct mbuf* sc_txmbuf[SQ_NTXDESC];
+
+ uint8_t sc_rxcmd; /* prototype rxcmd */
+
+ struct hpc_values *hpc_regs; /* HPC register definitions */
+
+#ifdef SQ_DEBUG
+ int sq_trace_idx;
+ struct sq_action_trace sq_trace[SQ_TRACEBUF_SIZE];
+#endif
+};
+
+#define SQ_CDTXADDR(sc, x) ((sc)->sc_cddma + SQ_CDTXOFF((x)))
+#define SQ_CDRXADDR(sc, x) ((sc)->sc_cddma + SQ_CDRXOFF((x)))
+
+static inline void
+SQ_CDTXSYNC(struct sq_softc *sc, int __x, int __n, int ops)
+{
+ /* If it will wrap around, sync to the end of the ring. */
+ if ((__x + __n) > SQ_NTXDESC) {
+ bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_cdmap,
+ SQ_CDTXOFF(__x), sizeof(struct hpc_dma_desc) *
+ (SQ_NTXDESC - __x), (ops));
+ __n -= (SQ_NTXDESC - __x);
+ __x = 0;
+ }
+
+ /* Now sync whatever is left. */
+ bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_cdmap,
+ SQ_CDTXOFF(__x), sizeof(struct hpc_dma_desc) * __n, (ops));
+}
+
+#define SQ_CDRXSYNC(sc, x, ops) \
+ bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_cdmap, \
+ SQ_CDRXOFF((x)), sizeof(struct hpc_dma_desc), (ops))
+
+static inline void
+SQ_INIT_RXDESC(struct sq_softc *sc, unsigned int x)
+{
+ struct hpc_dma_desc* __rxd = &(sc)->sc_rxdesc[(x)];
+ struct mbuf *__m = (sc)->sc_rxmbuf[(x)];
+
+ __m->m_data = __m->m_ext.ext_buf;
+ if (sc->hpc_regs->revision == 3) {
+ __rxd->hpc3_hdd_bufptr =
+ (sc)->sc_rxmap[(x)]->dm_segs[0].ds_addr;
+ __rxd->hpc3_hdd_ctl = __m->m_ext.ext_size | HPC3_HDD_CTL_OWN |
+ HPC3_HDD_CTL_INTR | HPC3_HDD_CTL_EOPACKET |
+ ((x) == (SQ_NRXDESC - 1) ? HPC3_HDD_CTL_EOCHAIN : 0);
+ } else {
+ __rxd->hpc1_hdd_bufptr =
+ (sc)->sc_rxmap[(x)]->dm_segs[0].ds_addr |
+ ((x) == (SQ_NRXDESC - 1) ? HPC1_HDD_CTL_EOCHAIN : 0);
+ __rxd->hpc1_hdd_ctl = __m->m_ext.ext_size | HPC1_HDD_CTL_OWN |
+ HPC1_HDD_CTL_INTR | HPC1_HDD_CTL_EOPACKET;
+ }
+ __rxd->hdd_descptr = SQ_CDRXADDR((sc), SQ_NEXTRX((x)));
+ SQ_CDRXSYNC((sc), (x), BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+}
diff --git a/sys/arch/sgi/hpc/iocreg.h b/sys/arch/sgi/hpc/iocreg.h
new file mode 100644
index 00000000000..274454e4ddf
--- /dev/null
+++ b/sys/arch/sgi/hpc/iocreg.h
@@ -0,0 +1,122 @@
+/* $OpenBSD: iocreg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: iocreg.h,v 1.2 2005/12/11 12:18:53 christos Exp $ */
+
+/*
+ * Copyright (c) 2003 Christopher Sekiya
+ * Copyright (c) 2001 Rafal K. Boni
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * IOC1/2 memory map.
+ *
+ * The IOC1/2 is connected to the HPC#0, PBus channel 6, so these registers
+ * are based from the external register window for PBus channel 6 on HPC#0.
+ *
+ */
+
+#define IOC_BASE HPC3_PBUS_CH6_DEVREGS
+
+#define IOC_PLP_REGS 0x00 /* Parallel port registers */
+#define IOC_PLP_REGS_SIZE 0x2c
+
+#define IOC_PLP_DATA 0x00 /* Data register */
+#define IOC_PLP_CTL 0x04 /* Control register */
+#define IOC_PLP_STAT 0x08 /* Status register */
+#define IOC_PLP_DMACTL 0x0c /* DMA control register */
+#define IOC_PLP_INTSTAT 0x10 /* Interrupt status register */
+#define IOC_PLP_INTMASK 0x14 /* Interrupt mask register */
+#define IOC_PLP_TIMER1 0x18 /* Timer 1 register */
+#define IOC_PLP_TIMER2 0x1c /* Timer 2 register */
+#define IOC_PLP_TIMER3 0x20 /* Timer 3 register */
+#define IOC_PLP_TIMER4 0x24 /* Timer 4 register */
+
+#define IOC_SERIAL_REGS 0x30 /* Serial port registers */
+#define IOC_SERIAL_REGS_SIZE 0x0c
+
+#define IOC_SERIAL_PORT1_CMD 0x00 /* Port 1 command transfer */
+#define IOC_SERIAL_PORT1_DATA 0x04 /* Port 1 data transfer */
+#define IOC_SERIAL_PORT2_CMD 0x08 /* Port 2 command transfer */
+#define IOC_SERIAL_PORT2_DATA 0x0c /* Port 2 data transfer */
+
+#define IOC_KB_REGS 0x40 /* Keyboard/mouse registers */
+#define IOC_KB_REGS_SIZE 0x08
+
+/* Miscellaneous registers */
+
+#define IOC_MISC_REGS 0x48 /* Misc. IOC regs */
+#define IOC_MISC_REGS_SIZE 0x34
+
+#define IOC_GCSEL 0x48 /* General select register */
+
+#define IOC_GCREG 0x4c /* General control register */
+
+#define IOC_PANEL 0x50 /* Front Panel register */
+#define IOC_PANEL_POWER_STATE 0x01
+#define IOC_PANEL_POWER_IRQ 0x02
+#define IOC_PANEL_VDOWN_IRQ 0x10
+#define IOC_PANEL_VDOWN_HOLD 0x20
+#define IOC_PANEL_VUP_IRQ 0x40
+#define IOC_PANEL_VUP_HOLD 0x80
+
+#define IOC_SYSID 0x58 /* System ID register */
+#define IOC_SYSID_SYSTYPE 0x01 /* 0: Sapphire, 1: Full House */
+#define IOC_SYSID_BOARDREV 0x1e
+#define IOC_SYSID_BOARDREV_SHIFT 1
+#define IOC_SYSID_CHIPREV 0xe0
+#define IOC_SYSID_CHIPREV_SHIFT 5
+
+#define IOC_READ 0x60 /* Read register */
+#define IOC_READ_SCSI0_POWER 0x10
+#define IOC_READ_SCSI1_POWER 0x20
+#define IOC_READ_ENET_POWER 0x40
+#define IOC_READ_ENET_LINK 0x80
+
+#define IOC_DMASEL 0x68 /* DMA select register */
+#define IOC_DMASEL_ISDN_B 0x01
+#define IOC_DMASEL_ISDN_A 0x02
+#define IOC_DMASEL_PARALLEL 0x04
+#define IOC_DMASEL_SERIAL_10MHZ 0x00
+#define IOC_DMASEL_SERIAL_6MHZ 0x10
+#define IOC_DMASEL_SERIAL_EXTERNAL 0x20
+
+#define IOC_RESET 0x70 /* Reset register */
+#define IOC_RESET_PARALLEL 0x01
+#define IOC_RESET_PCKBC 0x02
+#define IOC_RESET_EISA 0x04
+#define IOC_RESET_ISDN 0x08
+#define IOC_RESET_LED_GREEN 0x10
+#define IOC_RESET_LED_RED 0x20
+#define IOC_RESET_LED_ORANGE 0x40
+
+#define IOC_WRITE 0x78 /* Write register */
+#define IOC_WRITE_ENET_NTH 0x01
+#define IOC_WRITE_ENET_UTP 0x02
+#define IOC_WRITE_ENET_AUI 0x04
+#define IOC_WRITE_ENET_AUTO 0x08
+#define IOC_WRITE_PC_UART2 0x10
+#define IOC_WRITE_PC_UART1 0x20
+#define IOC_WRITE_MARGIN_LOW 0x40
+#define IOC_WRITE_MARGIN_HIGH 0x80
diff --git a/sys/arch/sgi/hpc/wdsc.c b/sys/arch/sgi/hpc/wdsc.c
new file mode 100644
index 00000000000..101b5178819
--- /dev/null
+++ b/sys/arch/sgi/hpc/wdsc.c
@@ -0,0 +1,290 @@
+/* $OpenBSD: wdsc.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: wdsc.c,v 1.32 2011/07/01 18:53:47 dyoung Exp $ */
+
+/*
+ * Copyright (c) 2001 Wayne Knowles
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Wayne Knowles
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/buf.h>
+#include <sys/timeout.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+#include <mips64/archtype.h>
+
+#include <machine/autoconf.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <sgi/localbus/intvar.h>
+
+#include <sgi/hpc/hpcreg.h>
+#include <sgi/hpc/hpcvar.h>
+#include <sgi/hpc/hpcdma.h>
+
+#include <dev/ic/wd33c93reg.h>
+#include <dev/ic/wd33c93var.h>
+
+struct wdsc_softc {
+ struct wd33c93_softc sc_wd33c93; /* Must be first */
+ bus_dma_tag_t sc_dmat;
+ bus_dmamap_t sc_dmamap;
+ int sc_flags;
+#define WDSC_DMA_ACTIVE 0x1
+#define WDSC_DMA_MAPLOADED 0x2
+ struct hpc_dma_softc sc_hpcdma;
+};
+
+int wdsc_match(struct device *, void *, void *);
+void wdsc_attach(struct device *, struct device *, void *);
+
+const struct cfattach wdsc_ca = {
+ sizeof(struct wdsc_softc), wdsc_match, wdsc_attach
+};
+
+struct cfdriver wdsc_cd = {
+ NULL, "wdsc", DV_DULL
+};
+
+int wdsc_dmasetup(struct wd33c93_softc *, void ** ,size_t *, int, size_t *);
+int wdsc_dmago(struct wd33c93_softc *);
+void wdsc_dmastop(struct wd33c93_softc *);
+void wdsc_reset(struct wd33c93_softc *);
+
+struct scsi_adapter wdsc_switch = {
+ wd33c93_scsi_cmd,
+ scsi_minphys,
+ NULL,
+ NULL,
+};
+
+/*
+ * Match for SCSI devices on the onboard and GIO32 adapter WD33C93 chips
+ */
+int
+wdsc_match(struct device *parent, void *vcf, void *aux)
+{
+ struct hpc_attach_args *haa = aux;
+ struct cfdata *cf = vcf;
+ vaddr_t reset, asr;
+ uint32_t dummy;
+ uint8_t reg;
+
+ if (strcmp(haa->ha_name, cf->cf_driver->cd_name) != 0)
+ return 0;
+
+ reset = PHYS_TO_XKPHYS(haa->ha_sh + haa->ha_dmaoff +
+ haa->hpc_regs->scsi0_ctl, CCA_NC);
+ if (guarded_read_4(reset, &dummy) != 0)
+ return 0;
+ *(volatile uint32_t *)reset = haa->hpc_regs->scsi_dmactl_reset;
+ delay(1000);
+ *(volatile uint32_t *)reset = 0x0;
+ delay(1000);
+
+ asr = PHYS_TO_XKPHYS(haa->ha_sh + haa->ha_devoff + 3, CCA_NC);
+ if (guarded_read_1(asr, &reg) != 0)
+ return 0;
+ if ((reg & 0xff) != SBIC_ASR_INT)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * Attach the wdsc driver
+ */
+void
+wdsc_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct wdsc_softc *wsc = (struct wdsc_softc *)self;
+ struct wd33c93_softc *sc = &wsc->sc_wd33c93;
+ struct hpc_attach_args *haa = aux;
+ int err;
+
+ sc->sc_regt = haa->ha_st;
+ wsc->sc_dmat = haa->ha_dmat;
+
+ wsc->sc_hpcdma.hpc = haa->hpc_regs;
+
+ if ((err = bus_space_subregion(haa->ha_st, haa->ha_sh,
+ haa->ha_devoff + 3, 1, &sc->sc_asr_regh)) != 0) {
+ printf(": unable to map asr reg, err=%d\n", err);
+ return;
+ }
+
+ if ((err = bus_space_subregion(haa->ha_st, haa->ha_sh,
+ haa->ha_devoff + 3 + 4, 1, &sc->sc_data_regh)) != 0) {
+ printf(": unable to map asr reg, err=%d\n", err);
+ return;
+ }
+
+ if (bus_dmamap_create(wsc->sc_dmat, MAXPHYS,
+ wsc->sc_hpcdma.hpc->scsi_dma_segs,
+ wsc->sc_hpcdma.hpc->scsi_dma_segs_size,
+ wsc->sc_hpcdma.hpc->scsi_dma_segs_size,
+ BUS_DMA_WAITOK, &wsc->sc_dmamap) != 0) {
+ printf(": failed to create dmamap\n");
+ return;
+ }
+
+ sc->sc_dmasetup = wdsc_dmasetup;
+ sc->sc_dmago = wdsc_dmago;
+ sc->sc_dmastop = wdsc_dmastop;
+ sc->sc_reset = wdsc_reset;
+
+ sc->sc_id = 0; /* Host ID = 0 */
+ sc->sc_clkfreq = 200; /* 20MHz */
+ sc->sc_dmamode = SBIC_CTL_BURST_DMA;
+
+ if (int2_intr_establish(haa->ha_irq, IPL_BIO,
+ wd33c93_intr, wsc, self->dv_xname) == NULL) {
+ printf(": unable to establish interrupt!\n");
+ return;
+ }
+
+ hpcdma_init(haa, &wsc->sc_hpcdma, wsc->sc_hpcdma.hpc->scsi_dma_segs);
+ wd33c93_attach(sc, &wdsc_switch);
+}
+
+/*
+ * Prime the hardware for a DMA transfer
+ *
+ * Requires splbio() interrupts to be disabled by the caller
+ */
+int
+wdsc_dmasetup(struct wd33c93_softc *sc, void **addr, size_t *len, int datain,
+ size_t *dmasize)
+{
+ struct wdsc_softc *wsc = (struct wdsc_softc *)sc;
+ struct hpc_dma_softc *dsc = &wsc->sc_hpcdma;
+ int count, err;
+ void *vaddr;
+
+ KASSERT((wsc->sc_flags & WDSC_DMA_ACTIVE) == 0);
+
+ vaddr = *addr;
+ count = dsc->sc_dlen = *len;
+ if (count) {
+ KASSERT((wsc->sc_flags & WDSC_DMA_MAPLOADED) == 0);
+
+ /* Build list of physical addresses for this transfer */
+ if ((err = bus_dmamap_load(wsc->sc_dmat, wsc->sc_dmamap,
+ vaddr, count, NULL /* kernel address */,
+ BUS_DMA_NOWAIT)) != 0)
+ panic("%s: bus_dmamap_load err=%d",
+ sc->sc_dev.dv_xname, err);
+
+ hpcdma_sglist_create(dsc, wsc->sc_dmamap);
+ wsc->sc_flags |= WDSC_DMA_MAPLOADED;
+
+ if (datain) {
+ dsc->sc_dmacmd =
+ wsc->sc_hpcdma.hpc->scsi_dma_datain_cmd;
+ dsc->sc_flags |= HPCDMA_READ;
+ } else {
+ dsc->sc_dmacmd =
+ wsc->sc_hpcdma.hpc->scsi_dma_dataout_cmd;
+ dsc->sc_flags &= ~HPCDMA_READ;
+ }
+ }
+ return count;
+}
+
+/*
+ * Prime the hardware for the next DMA transfer
+ */
+int
+wdsc_dmago(struct wd33c93_softc *sc)
+{
+ struct wdsc_softc *wsc = (struct wdsc_softc *)sc;
+ struct hpc_dma_softc *dsc = &wsc->sc_hpcdma;
+
+ if (dsc->sc_dlen == 0)
+ return 0;
+
+ KASSERT((wsc->sc_flags & WDSC_DMA_ACTIVE) == 0);
+ KASSERT((wsc->sc_flags & WDSC_DMA_MAPLOADED));
+
+ wsc->sc_flags |= WDSC_DMA_ACTIVE;
+
+ bus_dmamap_sync(wsc->sc_dmat, wsc->sc_dmamap,
+ 0, wsc->sc_dmamap->dm_mapsize,
+ (dsc->sc_flags & HPCDMA_READ) ?
+ BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
+
+ hpcdma_cntl(dsc, dsc->sc_dmacmd); /* Thunderbirds are go! */
+
+ return wsc->sc_dmamap->dm_mapsize;
+}
+
+/*
+ * Stop DMA and unload active DMA maps
+ */
+void
+wdsc_dmastop(struct wd33c93_softc *sc)
+{
+ struct wdsc_softc *wsc = (struct wdsc_softc *)sc;
+ struct hpc_dma_softc *dsc = &wsc->sc_hpcdma;
+
+ if (wsc->sc_flags & WDSC_DMA_ACTIVE) {
+ if (dsc->sc_flags & HPCDMA_READ)
+ hpcdma_flush(dsc);
+ hpcdma_cntl(dsc, 0); /* Stop DMA */
+ bus_dmamap_sync(wsc->sc_dmat, wsc->sc_dmamap,
+ 0, wsc->sc_dmamap->dm_mapsize,
+ (dsc->sc_flags & HPCDMA_READ) ?
+ BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
+ }
+ if (wsc->sc_flags & WDSC_DMA_MAPLOADED)
+ bus_dmamap_unload(wsc->sc_dmat, wsc->sc_dmamap);
+ wsc->sc_flags &= ~(WDSC_DMA_ACTIVE | WDSC_DMA_MAPLOADED);
+}
+
+/*
+ * Reset the controller.
+ */
+void
+wdsc_reset(struct wd33c93_softc *sc)
+{
+ struct wdsc_softc *wsc = (struct wdsc_softc *)sc;
+ struct hpc_dma_softc *dsc = &wsc->sc_hpcdma;
+
+ hpcdma_reset(dsc);
+}
diff --git a/sys/arch/sgi/hpc/z8530sc.c b/sys/arch/sgi/hpc/z8530sc.c
new file mode 100644
index 00000000000..fbec53846b4
--- /dev/null
+++ b/sys/arch/sgi/hpc/z8530sc.c
@@ -0,0 +1,409 @@
+/* $OpenBSD: z8530sc.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: z8530sc.c,v 1.30 2009/05/22 03:51:30 mrg Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)zs.c 8.1 (Berkeley) 7/19/93
+ */
+
+/*
+ * Copyright (c) 1994 Gordon W. Ross
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)zs.c 8.1 (Berkeley) 7/19/93
+ */
+
+/*
+ * Zilog Z8530 Dual UART driver (common part)
+ *
+ * This file contains the machine-independent parts of the
+ * driver common to tty and keyboard/mouse sub-drivers.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/device.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/tty.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+
+#include <dev/ic/z8530reg.h>
+#include <machine/z8530var.h>
+
+void
+zs_break(struct zs_chanstate *cs, int set)
+{
+
+ if (set) {
+ cs->cs_preg[5] |= ZSWR5_BREAK;
+ cs->cs_creg[5] |= ZSWR5_BREAK;
+ } else {
+ cs->cs_preg[5] &= ~ZSWR5_BREAK;
+ cs->cs_creg[5] &= ~ZSWR5_BREAK;
+ }
+ zs_write_reg(cs, 5, cs->cs_creg[5]);
+}
+
+
+/*
+ * drain on-chip fifo
+ */
+void
+zs_iflush(struct zs_chanstate *cs)
+{
+ uint8_t c, rr0, rr1;
+ int i;
+
+ /*
+ * Count how many times we loop. Some systems, such as some
+ * Apple PowerBooks, claim to have SCC's which they really don't.
+ */
+ for (i = 0; i < 32; i++) {
+ /* Is there input available? */
+ rr0 = zs_read_csr(cs);
+ if ((rr0 & ZSRR0_RX_READY) == 0)
+ break;
+
+ /*
+ * First read the status, because reading the data
+ * destroys the status of this char.
+ */
+ rr1 = zs_read_reg(cs, 1);
+ c = zs_read_data(cs);
+
+ if (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) {
+ /* Clear the receive error. */
+ zs_write_csr(cs, ZSWR0_RESET_ERRORS);
+ }
+ }
+}
+
+
+/*
+ * Write the given register set to the given zs channel in the proper order.
+ * The channel must not be transmitting at the time. The receiver will
+ * be disabled for the time it takes to write all the registers.
+ * Call this with interrupts disabled.
+ */
+void
+zs_loadchannelregs(struct zs_chanstate *cs)
+{
+ uint8_t *reg, v;
+
+ zs_write_csr(cs, ZSM_RESET_ERR); /* XXX: reset error condition */
+
+#if 1
+ /*
+ * XXX: Is this really a good idea?
+ * XXX: Should go elsewhere! -gwr
+ */
+ zs_iflush(cs); /* XXX */
+#endif
+
+ if (cs->cs_ctl_chan != NULL)
+ v = ((cs->cs_ctl_chan->cs_creg[5] & (ZSWR5_RTS | ZSWR5_DTR)) !=
+ (cs->cs_ctl_chan->cs_preg[5] & (ZSWR5_RTS | ZSWR5_DTR)));
+ else
+ v = 0;
+
+ if (memcmp((void *)cs->cs_preg, (void *)cs->cs_creg, 16) == 0 && !v)
+ return; /* only change if values are different */
+
+ /* Copy "pending" regs to "current" */
+ memcpy((void *)cs->cs_creg, (void *)cs->cs_preg, 16);
+ reg = cs->cs_creg; /* current regs */
+
+ /* disable interrupts */
+ zs_write_reg(cs, 1, reg[1] & ~ZSWR1_IMASK);
+
+ /* baud clock divisor, stop bits, parity */
+ zs_write_reg(cs, 4, reg[4]);
+
+ /* misc. TX/RX control bits */
+ zs_write_reg(cs, 10, reg[10]);
+
+ /* char size, enable (RX/TX) */
+ zs_write_reg(cs, 3, reg[3] & ~ZSWR3_RX_ENABLE);
+ zs_write_reg(cs, 5, reg[5] & ~ZSWR5_TX_ENABLE);
+
+ /* synchronous mode stuff */
+ zs_write_reg(cs, 6, reg[6]);
+ zs_write_reg(cs, 7, reg[7]);
+
+#if 0
+ /*
+ * Registers 2 and 9 are special because they are
+ * actually common to both channels, but must be
+ * programmed through channel A. The "zsc" attach
+ * function takes care of setting these registers
+ * and they should not be touched thereafter.
+ */
+ /* interrupt vector */
+ zs_write_reg(cs, 2, reg[2]);
+ /* master interrupt control */
+ zs_write_reg(cs, 9, reg[9]);
+#endif
+
+ /* Shut down the BRG */
+ zs_write_reg(cs, 14, reg[14] & ~ZSWR14_BAUD_ENA);
+
+#ifdef ZS_MD_SETCLK
+ /* Let the MD code setup any external clock. */
+ ZS_MD_SETCLK(cs);
+#endif /* ZS_MD_SETCLK */
+
+ /* clock mode control */
+ zs_write_reg(cs, 11, reg[11]);
+
+ /* baud rate (lo/hi) */
+ zs_write_reg(cs, 12, reg[12]);
+ zs_write_reg(cs, 13, reg[13]);
+
+ /* Misc. control bits */
+ zs_write_reg(cs, 14, reg[14]);
+
+ /* which lines cause status interrupts */
+ zs_write_reg(cs, 15, reg[15]);
+
+ /*
+ * Zilog docs recommend resetting external status twice at this
+ * point. Mainly as the status bits are latched, and the first
+ * interrupt clear might unlatch them to new values, generating
+ * a second interrupt request.
+ */
+ zs_write_csr(cs, ZSM_RESET_STINT);
+ zs_write_csr(cs, ZSM_RESET_STINT);
+
+ /* char size, enable (RX/TX)*/
+ zs_write_reg(cs, 3, reg[3]);
+ zs_write_reg(cs, 5, reg[5]);
+
+ /* Write the status bits on the alternate channel also. */
+ if (cs->cs_ctl_chan != NULL) {
+ v = cs->cs_ctl_chan->cs_preg[5];
+ cs->cs_ctl_chan->cs_creg[5] = v;
+ zs_write_reg(cs->cs_ctl_chan, 5, v);
+ }
+
+ /* interrupt enables: RX, TX, STATUS */
+ zs_write_reg(cs, 1, reg[1]);
+}
+
+/*
+ * ZS hardware interrupt. Scan all ZS channels. NB: we know here that
+ * channels are kept in (A,B) pairs.
+ *
+ * Do just a little, then get out; set a software interrupt if more
+ * work is needed.
+ *
+ * We deliberately ignore the vectoring Zilog gives us, and match up
+ * only the number of `reset interrupt under service' operations, not
+ * the order.
+ */
+int
+zsc_intr_hard(void *arg)
+{
+ struct zsc_softc *zsc = arg;
+ struct zs_chanstate *cs0, *cs1;
+ int handled;
+ uint8_t rr3;
+
+ handled = 0;
+
+ /* First look at channel A. */
+ cs0 = zsc->zsc_cs[0];
+ cs1 = zsc->zsc_cs[1];
+
+ /*
+ * We have to clear interrupt first to avoid a race condition,
+ * but it will be done in each MD handler.
+ */
+ for (;;) {
+ /* Note: only channel A has an RR3 */
+ rr3 = zs_read_reg(cs0, 3);
+
+ if ((rr3 & (ZSRR3_IP_A_RX | ZSRR3_IP_A_TX | ZSRR3_IP_A_STAT |
+ ZSRR3_IP_B_RX | ZSRR3_IP_B_TX | ZSRR3_IP_B_STAT)) == 0) {
+ break;
+ }
+ handled = 1;
+
+ /* First look at channel A. */
+ if (rr3 & (ZSRR3_IP_A_RX | ZSRR3_IP_A_TX | ZSRR3_IP_A_STAT))
+ zs_write_csr(cs0, ZSWR0_CLR_INTR);
+
+ if (rr3 & ZSRR3_IP_A_RX)
+ (*cs0->cs_ops->zsop_rxint)(cs0);
+ if (rr3 & ZSRR3_IP_A_STAT)
+ (*cs0->cs_ops->zsop_stint)(cs0, 0);
+ if (rr3 & ZSRR3_IP_A_TX)
+ (*cs0->cs_ops->zsop_txint)(cs0);
+
+ /* Now look at channel B. */
+ if (rr3 & (ZSRR3_IP_B_RX | ZSRR3_IP_B_TX | ZSRR3_IP_B_STAT))
+ zs_write_csr(cs1, ZSWR0_CLR_INTR);
+
+ if (rr3 & ZSRR3_IP_B_RX)
+ (*cs1->cs_ops->zsop_rxint)(cs1);
+ if (rr3 & ZSRR3_IP_B_STAT)
+ (*cs1->cs_ops->zsop_stint)(cs1, 0);
+ if (rr3 & ZSRR3_IP_B_TX)
+ (*cs1->cs_ops->zsop_txint)(cs1);
+ }
+
+ /* Note: caller will check cs_x->cs_softreq and DTRT. */
+ return handled;
+}
+
+
+/*
+ * ZS software interrupt. Scan all channels for deferred interrupts.
+ */
+int
+zsc_intr_soft(void *arg)
+{
+ struct zsc_softc *zsc = arg;
+ struct zs_chanstate *cs;
+ int rval, chan;
+
+ rval = 0;
+ for (chan = 0; chan < 2; chan++) {
+ cs = zsc->zsc_cs[chan];
+
+ /*
+ * The softint flag can be safely cleared once
+ * we have decided to call the softint routine.
+ * (No need to do splzs() first.)
+ */
+ if (cs->cs_softreq) {
+ cs->cs_softreq = 0;
+ (*cs->cs_ops->zsop_softint)(cs);
+ rval++;
+ }
+ }
+ return (rval);
+}
+
+/*
+ * Provide a null zs "ops" vector.
+ */
+
+static void zsnull_rxint (struct zs_chanstate *);
+static void zsnull_stint (struct zs_chanstate *, int);
+static void zsnull_txint (struct zs_chanstate *);
+static void zsnull_softint(struct zs_chanstate *);
+
+static void
+zsnull_rxint(struct zs_chanstate *cs)
+{
+
+ /* Ask for softint() call. */
+ cs->cs_softreq = 1;
+}
+
+static void
+zsnull_stint(struct zs_chanstate *cs, int force)
+{
+
+ /* Ask for softint() call. */
+ cs->cs_softreq = 1;
+}
+
+static void
+zsnull_txint(struct zs_chanstate *cs)
+{
+
+ /* Ask for softint() call. */
+ cs->cs_softreq = 1;
+}
+
+static void
+zsnull_softint(struct zs_chanstate *cs)
+{
+
+ zs_write_reg(cs, 1, 0);
+ zs_write_reg(cs, 15, 0);
+}
+
+struct zsops zsops_null = {
+ zsnull_rxint, /* receive char available */
+ zsnull_stint, /* external/status */
+ zsnull_txint, /* xmit buffer empty */
+ zsnull_softint, /* process software interrupt */
+};
diff --git a/sys/arch/sgi/hpc/z8530sc.h b/sys/arch/sgi/hpc/z8530sc.h
new file mode 100644
index 00000000000..d4b707ad518
--- /dev/null
+++ b/sys/arch/sgi/hpc/z8530sc.h
@@ -0,0 +1,199 @@
+/* $OpenBSD: z8530sc.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: z8530sc.h,v 1.26 2009/05/22 03:51:30 mrg Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)zsvar.h 8.1 (Berkeley) 6/11/93
+ */
+
+/*
+ * Copyright (c) 1994 Gordon W. Ross
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)zsvar.h 8.1 (Berkeley) 6/11/93
+ */
+
+/*
+ * Function vector - per channel
+ */
+struct zs_chanstate;
+struct zsops {
+ void (*zsop_rxint)(struct zs_chanstate *);
+ /* receive char available */
+ void (*zsop_stint)(struct zs_chanstate *, int);
+ /* external/status */
+ void (*zsop_txint)(struct zs_chanstate *);
+ /* xmit buffer empty */
+ void (*zsop_softint)(struct zs_chanstate *);
+ /* process software interrupt */
+};
+
+extern struct zsops zsops_null;
+
+
+/*
+ * Software state, per zs channel.
+ */
+struct zs_chanstate {
+
+ /* Pointers to the device registers. */
+ volatile uint8_t *cs_reg_csr; /* ctrl, status, and reg. number. */
+ volatile uint8_t *cs_reg_data; /* data or numbered register */
+
+ int cs_channel; /* sub-unit number */
+ void *cs_private; /* sub-driver data pointer */
+ struct zsops *cs_ops;
+
+ int cs_brg_clk; /* BAUD Rate Generator clock
+ * (usually PCLK / 16) */
+ int cs_defspeed; /* default baud rate */
+ int cs_defcflag; /* default cflag */
+
+ /*
+ * We must keep a copy of the write registers as they are
+ * mostly write-only and we sometimes need to set and clear
+ * individual bits (e.g., in WR3). Not all of these are
+ * needed but 16 bytes is cheap and this makes the addressing
+ * simpler. Unfortunately, we can only write to some registers
+ * when the chip is not actually transmitting, so whenever
+ * we are expecting a `transmit done' interrupt the preg array
+ * is allowed to `get ahead' of the current values. In a
+ * few places we must change the current value of a register,
+ * rather than (or in addition to) the pending value; for these
+ * cs_creg[] contains the current value.
+ */
+ uint8_t cs_creg[16]; /* current values */
+ uint8_t cs_preg[16]; /* pending values */
+ int cs_heldchange; /* change pending (creg != preg) */
+
+ uint8_t cs_rr0; /* last rr0 processed */
+ uint8_t cs_rr0_delta; /* rr0 changes at status intr. */
+ uint8_t cs_rr0_mask; /* rr0 bits that stop output */
+ uint8_t cs_rr0_dcd; /* which bit to read as DCD */
+ uint8_t cs_rr0_cts; /* which bit to read as CTS */
+ uint8_t cs_rr0_pps; /* which bit to use for PPS */
+ /* the above is set only while CRTSCTS is enabled. */
+
+ uint8_t cs_wr5_dtr; /* which bit to write as DTR */
+ uint8_t cs_wr5_rts; /* which bit to write as RTS */
+ /* the above is set only while CRTSCTS is enabled. */
+
+ volatile uint8_t cs_softreq; /* need soft interrupt call */
+ char cs_cua; /* CUA mode flag */
+
+ /*
+ * For strange systems that have oddly wired serial ports, we
+ * provide a pointer to the channel state of the port that has
+ * our status lines on it.
+ */
+ struct zs_chanstate *cs_ctl_chan;
+
+ /* power management hooks */
+ int (*enable)(struct zs_chanstate *);
+ void (*disable)(struct zs_chanstate *);
+ int enabled;
+
+ /* MD code might define a larger variant of this. */
+};
+
+struct consdev;
+struct zsc_attach_args {
+ int channel; /* two serial channels per zsc */
+ int hwflags; /* see definitions below */
+ /* `consdev' is only valid if ZS_HWFLAG_USE_CONSDEV is set */
+ struct consdev *consdev;
+};
+
+/* In case of split console devices, use these: */
+#define ZS_HWFLAG_CONSOLE_INPUT 1
+#define ZS_HWFLAG_CONSOLE_OUTPUT 2
+#define ZS_HWFLAG_CONSOLE \
+ (ZS_HWFLAG_CONSOLE_INPUT | ZS_HWFLAG_CONSOLE_OUTPUT)
+#define ZS_HWFLAG_NO_DCD 4 /* Ignore the DCD bit */
+#define ZS_HWFLAG_NO_CTS 8 /* Ignore the CTS bit */
+#define ZS_HWFLAG_RAW 16 /* advise raw mode */
+#define ZS_HWFLAG_USE_CONSDEV 32 /* Use console ops from `consdev' */
+#define ZS_HWFLAG_NORESET 64 /* Don't reset at attach time */
+
+extern int zs_major;
+
+int zsc_intr_soft(void *);
+int zsc_intr_hard(void *);
+
+void zs_abort(struct zs_chanstate *);
+void zs_break(struct zs_chanstate *, int);
+void zs_iflush(struct zs_chanstate *);
+void zs_loadchannelregs(struct zs_chanstate *);
+int zs_set_speed(struct zs_chanstate *, int);
+int zs_set_modes(struct zs_chanstate *, int);
diff --git a/sys/arch/sgi/hpc/z8530tty.c b/sys/arch/sgi/hpc/z8530tty.c
new file mode 100644
index 00000000000..4108ed6ea10
--- /dev/null
+++ b/sys/arch/sgi/hpc/z8530tty.c
@@ -0,0 +1,1663 @@
+/* $OpenBSD: z8530tty.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: z8530tty.c,v 1.128 2011/04/24 16:27:00 rmind Exp $ */
+
+/*-
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998, 1999
+ * Charles M. Hannum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Charles M. Hannum.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)zs.c 8.1 (Berkeley) 7/19/93
+ */
+
+/*
+ * Copyright (c) 1994 Gordon W. Ross
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)zs.c 8.1 (Berkeley) 7/19/93
+ */
+
+/*
+ * Zilog Z8530 Dual UART driver (tty interface)
+ *
+ * This is the "slave" driver that will be attached to
+ * the "zsc" driver for plain "tty" async. serial lines.
+ *
+ * Credits, history:
+ *
+ * The original version of this code was the sparc/dev/zs.c driver
+ * as distributed with the Berkeley 4.4 Lite release. Since then,
+ * Gordon Ross reorganized the code into the current parent/child
+ * driver scheme, separating the Sun keyboard and mouse support
+ * into independent child drivers.
+ *
+ * RTS/CTS flow-control support was a collaboration of:
+ * Gordon Ross <gwr@NetBSD.org>,
+ * Bill Studenmund <wrstuden@loki.stanford.edu>
+ * Ian Dall <Ian.Dall@dsto.defence.gov.au>
+ *
+ * The driver was massively overhauled in November 1997 by Charles Hannum,
+ * fixing *many* bugs, and substantially improving performance.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/device.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/malloc.h>
+#include <sys/tty.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+
+#include <dev/ic/z8530reg.h>
+#include <machine/z8530var.h>
+
+#include <dev/cons.h>
+
+/*
+ * How many input characters we can buffer.
+ * The port-specific var.h may override this.
+ * Note: must be a power of two!
+ */
+#ifndef ZSTTY_RING_SIZE
+#define ZSTTY_RING_SIZE 2048
+#endif
+
+struct cfdriver zstty_cd = {
+ NULL, "zstty", DV_TTY
+};
+
+/*
+ * Make this an option variable one can patch.
+ * But be warned: this must be a power of 2!
+ */
+u_int zstty_rbuf_size = ZSTTY_RING_SIZE;
+
+/* Stop input when 3/4 of the ring is full; restart when only 1/4 is full. */
+u_int zstty_rbuf_hiwat = (ZSTTY_RING_SIZE * 1) / 4;
+u_int zstty_rbuf_lowat = (ZSTTY_RING_SIZE * 3) / 4;
+
+struct zstty_softc {
+ struct device zst_dev; /* required first: base device */
+ struct tty *zst_tty;
+ struct zs_chanstate *zst_cs;
+
+ struct timeout zst_diag_ch;
+
+ u_int zst_overflows,
+ zst_floods,
+ zst_errors;
+
+ int zst_hwflags, /* see z8530var.h */
+ zst_swflags; /* TIOCFLAG_SOFTCAR, ... <ttycom.h> */
+
+ u_int zst_r_hiwat,
+ zst_r_lowat;
+ uint8_t *volatile zst_rbget,
+ *volatile zst_rbput;
+ volatile u_int zst_rbavail;
+ uint8_t *zst_rbuf,
+ *zst_ebuf;
+
+ /*
+ * The transmit byte count and address are used for pseudo-DMA
+ * output in the hardware interrupt code. PDMA can be suspended
+ * to get pending changes done; heldtbc is used for this. It can
+ * also be stopped for ^S; this sets TS_TTSTOP in tp->t_state.
+ */
+ uint8_t *zst_tba; /* transmit buffer address */
+ u_int zst_tbc, /* transmit byte count */
+ zst_heldtbc; /* held tbc while xmission stopped */
+
+ /* Flags to communicate with zstty_softint() */
+ volatile uint8_t zst_rx_flags, /* receiver blocked */
+#define RX_TTY_BLOCKED 0x01
+#define RX_TTY_OVERFLOWED 0x02
+#define RX_IBUF_BLOCKED 0x04
+#define RX_IBUF_OVERFLOWED 0x08
+#define RX_ANY_BLOCK 0x0f
+ zst_tx_busy, /* working on an output chunk */
+ zst_tx_done, /* done with one output chunk */
+ zst_tx_stopped, /* H/W level stop (lost CTS) */
+ zst_st_check, /* got a status interrupt */
+ zst_rx_ready;
+
+ /* PPS signal on DCD, with or without inkernel clock disciplining */
+ uint8_t zst_ppsmask; /* pps signal mask */
+ uint8_t zst_ppsassert; /* pps leading edge */
+ uint8_t zst_ppsclear; /* pps trailing edge */
+};
+
+/* Definition of the driver for autoconfig. */
+int zstty_match(struct device *, void *, void *);
+void zstty_attach(struct device *, struct device *, void *);
+
+const struct cfattach zstty_ca = {
+ sizeof(struct zstty_softc), zstty_match, zstty_attach
+};
+
+cdev_decl(zs);
+
+struct zsops zsops_tty;
+
+void zs_shutdown(struct zstty_softc *);
+void zsstart(struct tty *);
+int zsparam(struct tty *, struct termios *);
+void zs_modem(struct zstty_softc *, int);
+void tiocm_to_zs(struct zstty_softc *, u_long, int);
+int zs_to_tiocm(struct zstty_softc *);
+int zshwiflow(struct tty *, int);
+void zs_hwiflow(struct zstty_softc *);
+void zs_maskintr(struct zstty_softc *);
+
+struct zstty_softc *zs_device_lookup(struct cfdriver *, int);
+
+/* Low-level routines. */
+void zstty_rxint (struct zs_chanstate *);
+void zstty_stint (struct zs_chanstate *, int);
+void zstty_txint (struct zs_chanstate *);
+void zstty_softint(struct zs_chanstate *);
+void zstty_diag(void *);
+
+#define ZSUNIT(x) (minor(x) & 0x7f)
+#define ZSDIALOUT(x) (minor(x) & 0x80)
+
+struct zstty_softc *
+zs_device_lookup(struct cfdriver *cf, int unit)
+{
+ return (struct zstty_softc *)device_lookup(cf, unit);
+}
+
+/*
+ * zstty_match: how is this zs channel configured?
+ */
+int
+zstty_match(struct device *parent, void *vcf, void *aux)
+{
+ struct cfdata *cf = vcf;
+ struct zsc_attach_args *args = aux;
+
+ /* Exact match is better than wildcard. */
+ if (cf->cf_loc[0] == args->channel)
+ return 2;
+
+ /* This driver accepts wildcard. */
+ if (cf->cf_loc[0] == -1)
+ return 1;
+
+ return 0;
+}
+
+void
+zstty_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct zsc_softc *zsc = (struct zsc_softc *)parent;
+ struct zstty_softc *zst = (struct zstty_softc *)self;
+ struct cfdata *cf = self->dv_cfdata;
+ struct zsc_attach_args *args = aux;
+ struct zs_chanstate *cs;
+ struct tty *tp;
+ int channel, s, tty_unit;
+ dev_t dev;
+ const char *i, *o;
+ int dtr_on;
+ int resetbit;
+
+ timeout_set(&zst->zst_diag_ch, zstty_diag, zst);
+
+ tty_unit = zst->zst_dev.dv_unit;
+ channel = args->channel;
+ cs = zsc->zsc_cs[channel];
+ cs->cs_private = zst;
+ cs->cs_ops = &zsops_tty;
+
+ zst->zst_cs = cs;
+ zst->zst_swflags = cf->cf_flags; /* softcar, etc. */
+ zst->zst_hwflags = args->hwflags;
+ dev = makedev(zs_major, tty_unit);
+
+ if (zst->zst_swflags)
+ printf(" flags 0x%x", zst->zst_swflags);
+
+ /*
+ * Check whether we serve as a console device.
+ * XXX - split console input/output channels aren't
+ * supported yet on /dev/console
+ */
+ i = o = NULL;
+ if ((zst->zst_hwflags & ZS_HWFLAG_CONSOLE_INPUT) != 0) {
+ i = " input";
+ if ((args->hwflags & ZS_HWFLAG_USE_CONSDEV) != 0) {
+ args->consdev->cn_dev = dev;
+ cn_tab->cn_pollc = args->consdev->cn_pollc;
+ cn_tab->cn_getc = args->consdev->cn_getc;
+ }
+ cn_tab->cn_dev = dev;
+ }
+ if ((zst->zst_hwflags & ZS_HWFLAG_CONSOLE_OUTPUT) != 0) {
+ o = " output";
+ if ((args->hwflags & ZS_HWFLAG_USE_CONSDEV) != 0) {
+ cn_tab->cn_putc = args->consdev->cn_putc;
+ }
+ cn_tab->cn_dev = dev;
+ }
+ if (i != NULL || o != NULL)
+ printf(": console%s", i ? (o ? "" : i) : o);
+
+#ifdef KGDB
+ if (zs_check_kgdb(cs, dev)) {
+ /*
+ * Allow kgdb to "take over" this port. Returns true
+ * if this serial port is in-use by kgdb.
+ */
+ printf(" (kgdb)\n");
+ /*
+ * This is the kgdb port (exclusive use)
+ * so skip the normal attach code.
+ */
+ return;
+ }
+#endif
+
+ printf("\n");
+
+ tp = ttymalloc(0);
+ tp->t_dev = dev;
+ tp->t_oproc = zsstart;
+ tp->t_param = zsparam;
+ tp->t_hwiflow = zshwiflow;
+
+ zst->zst_tty = tp;
+ zst->zst_rbuf = malloc(zstty_rbuf_size << 1, M_DEVBUF, M_WAITOK);
+ zst->zst_ebuf = zst->zst_rbuf + (zstty_rbuf_size << 1);
+ /* Disable the high water mark. */
+ zst->zst_r_hiwat = 0;
+ zst->zst_r_lowat = 0;
+ zst->zst_rbget = zst->zst_rbput = zst->zst_rbuf;
+ zst->zst_rbavail = zstty_rbuf_size;
+
+ /* if there are no enable/disable functions, assume the device
+ is always enabled */
+ if (!cs->enable)
+ cs->enabled = 1;
+
+ /*
+ * Hardware init
+ */
+ dtr_on = 0;
+ resetbit = 0;
+ if (ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE)) {
+ /* Call zsparam similar to open. */
+ struct termios t;
+
+ /* Wait a while for previous console output to complete */
+ DELAY(10000);
+
+ /* Setup the "new" parameters in t. */
+ t.c_ispeed = 0;
+ t.c_ospeed = cs->cs_defspeed;
+ t.c_cflag = cs->cs_defcflag;
+
+ s = splzs();
+
+ /*
+ * Turn on receiver and status interrupts.
+ * We defer the actual write of the register to zsparam(),
+ * but we must make sure status interrupts are turned on by
+ * the time zsparam() reads the initial rr0 state.
+ */
+ SET(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE);
+
+ splx(s);
+
+ /* Make sure zsparam will see changes. */
+ tp->t_ospeed = 0;
+ (void)zsparam(tp, &t);
+
+ /* Make sure DTR is on now. */
+ dtr_on = 1;
+ } else if (!ISSET(zst->zst_hwflags, ZS_HWFLAG_NORESET)) {
+ /* Not the console; may need reset. */
+ resetbit = (channel == 0) ? ZSWR9_A_RESET : ZSWR9_B_RESET;
+ }
+
+ s = splzs();
+ if (resetbit)
+ zs_write_reg(cs, 9, resetbit);
+ zs_modem(zst, dtr_on);
+ splx(s);
+}
+
+
+/*
+ * Return pointer to our tty.
+ */
+struct tty *
+zstty(dev_t dev)
+{
+ struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev));
+
+ return (zst->zst_tty);
+}
+
+
+void
+zs_shutdown(struct zstty_softc *zst)
+{
+ struct zs_chanstate *cs = zst->zst_cs;
+ struct tty *tp = zst->zst_tty;
+ int s;
+
+ s = splzs();
+
+ /* If we were asserting flow control, then deassert it. */
+ SET(zst->zst_rx_flags, RX_IBUF_BLOCKED);
+ zs_hwiflow(zst);
+
+ /* Clear any break condition set with TIOCSBRK. */
+ zs_break(cs, 0);
+
+ /* Turn off PPS capture on last close. */
+ zst->zst_ppsmask = 0;
+
+ /*
+ * Hang up if necessary. Wait a bit, so the other side has time to
+ * notice even if we immediately open the port again.
+ */
+ if (ISSET(tp->t_cflag, HUPCL) || ISSET(tp->t_state, TS_WOPEN)) {
+ zs_modem(zst, 0);
+ /* hold low for 1 second */
+ (void)tsleep(cs, TTIPRI, ttclos, hz);
+ }
+
+ /* Turn off interrupts if not the console. */
+ if (!ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE)) {
+ CLR(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_TIE | ZSWR1_SIE);
+ cs->cs_creg[1] = cs->cs_preg[1];
+ zs_write_reg(cs, 1, cs->cs_creg[1]);
+ }
+
+ /* Call the power management hook. */
+ if (cs->disable) {
+#ifdef DIAGNOSTIC
+ if (!cs->enabled)
+ panic("%s: not enabled?", __func__);
+#endif
+ (*cs->disable)(zst->zst_cs);
+ }
+
+ splx(s);
+}
+
+/*
+ * Open a zs serial (tty) port.
+ */
+int
+zsopen(dev_t dev, int flags, int mode, struct proc *p)
+{
+ struct zstty_softc *zst;
+ struct zs_chanstate *cs;
+ struct tty *tp;
+ int s, s2;
+ int error;
+
+ zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev));
+ if (zst == NULL)
+ return (ENXIO);
+
+ tp = zst->zst_tty;
+ cs = zst->zst_cs;
+
+ /* If KGDB took the line, then tp==NULL */
+ if (tp == NULL)
+ return (EBUSY);
+
+ if (ISSET(tp->t_state, TS_ISOPEN) &&
+ ISSET(tp->t_state, TS_XCLUDE) &&
+ suser(p, 0) != 0)
+ return (EBUSY);
+
+ s = spltty();
+
+ /*
+ * Do the following iff this is a first open.
+ */
+ if (!ISSET(tp->t_state, TS_ISOPEN)) {
+ struct termios t;
+
+ tp->t_dev = dev;
+
+ /* Call the power management hook. */
+ if (cs->enable) {
+ if ((*cs->enable)(cs)) {
+ splx(s);
+ printf("%s: device enable failed\n",
+ zst->zst_dev.dv_xname);
+ return (EIO);
+ }
+ }
+
+ /*
+ * Initialize the termios status to the defaults. Add in the
+ * sticky bits from TIOCSFLAGS.
+ */
+ t.c_ispeed = 0;
+ t.c_ospeed = cs->cs_defspeed;
+ t.c_cflag = cs->cs_defcflag;
+ if (ISSET(zst->zst_swflags, TIOCFLAG_CLOCAL))
+ SET(t.c_cflag, CLOCAL);
+ if (ISSET(zst->zst_swflags, TIOCFLAG_CRTSCTS))
+ SET(t.c_cflag, CRTSCTS);
+ if (ISSET(zst->zst_swflags, TIOCFLAG_MDMBUF))
+ SET(t.c_cflag, MDMBUF);
+
+ s2 = splzs();
+
+ /*
+ * Turn on receiver and status interrupts.
+ * We defer the actual write of the register to zsparam(),
+ * but we must make sure status interrupts are turned on by
+ * the time zsparam() reads the initial rr0 state.
+ */
+ SET(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE);
+
+ /* Clear PPS capture state on first open. */
+ zst->zst_ppsmask = 0;
+
+ splx(s2);
+
+ /* Make sure zsparam will see changes. */
+ tp->t_ospeed = 0;
+ (void)zsparam(tp, &t);
+
+ /*
+ * Note: zsparam has done: cflag, ispeed, ospeed
+ * so we just need to do: iflag, oflag, lflag, cc
+ * For "raw" mode, just leave all zeros.
+ */
+ if (!ISSET(zst->zst_hwflags, ZS_HWFLAG_RAW)) {
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_lflag = TTYDEF_LFLAG;
+ } else {
+ tp->t_iflag = 0;
+ tp->t_oflag = 0;
+ tp->t_lflag = 0;
+ }
+ ttychars(tp);
+ ttsetwater(tp);
+
+ if (ZSDIALOUT(dev))
+ SET(tp->t_state, TS_CARR_ON);
+ else
+ CLR(tp->t_state, TS_CARR_ON);
+
+ s2 = splzs();
+
+ /* Clear the input ring, and unblock. */
+ zst->zst_rbget = zst->zst_rbput = zst->zst_rbuf;
+ zst->zst_rbavail = zstty_rbuf_size;
+ zs_iflush(cs);
+ CLR(zst->zst_rx_flags, RX_ANY_BLOCK);
+ zs_hwiflow(zst);
+
+ splx(s2);
+ }
+
+ if (ZSDIALOUT(dev)) {
+ if (ISSET(tp->t_state, TS_ISOPEN)) {
+ /* someone already is dialed in... */
+ splx(s);
+ return EBUSY;
+ }
+ cs->cs_cua = 1;
+ }
+
+ error = 0;
+ /* wait for carrier if necessary */
+ if (ISSET(flags, O_NONBLOCK)) {
+ if (!ZSDIALOUT(dev) && cs->cs_cua) {
+ /* Opening TTY non-blocking... but the CUA is busy */
+ error = EBUSY;
+ }
+ } else
+ while (cs->cs_cua ||
+ (!ISSET(tp->t_cflag, CLOCAL) && !ISSET(tp->t_state, TS_CARR_ON))) {
+ int rr0;
+
+ error = 0;
+ SET(tp->t_state, TS_WOPEN);
+
+ if (!ZSDIALOUT(dev) && !cs->cs_cua) {
+ /*
+ * Turn on DTR. We must always do this on non-CUA
+ * devices, even if carrier is not present, because
+ * otherwise we'd have to use TIOCSDTR immediately
+ * after setting CLOCAL, which applications do not
+ * expect. We always assert DTR while the device is
+ * open unless explicitly requested to deassert it.
+ */
+ s2 = splzs();
+ zs_modem(zst, 1);
+ rr0 = zs_read_csr(cs);
+ splx(s2);
+
+ /* loop, turning on the device, until carrier present */
+ if (ISSET(rr0, ZSRR0_DCD) ||
+ ISSET(zst->zst_swflags, TIOCFLAG_SOFTCAR))
+ SET(tp->t_state, TS_CARR_ON);
+ }
+
+ if ((ISSET(tp->t_cflag, CLOCAL) ||
+ ISSET(tp->t_state, TS_CARR_ON)) && !cs->cs_cua)
+ break;
+
+ error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
+ ttopen, 0);
+
+ if (!ZSDIALOUT(dev) && cs->cs_cua && error == EINTR) {
+ error = 0;
+ continue;
+ }
+
+ if (error) {
+ if (!ISSET(tp->t_state, TS_ISOPEN)) {
+ s2 = splzs();
+ zs_modem(zst, 0);
+ splx(s2);
+ CLR(tp->t_state, TS_WOPEN);
+ ttwakeup(tp);
+ }
+ if (ZSDIALOUT(dev))
+ cs->cs_cua = 0;
+ CLR(tp->t_state, TS_WOPEN);
+ break;
+ }
+ if (!ZSDIALOUT(dev) && cs->cs_cua)
+ continue;
+ }
+
+ splx(s);
+
+ if (error == 0)
+ error = ((*linesw[tp->t_line].l_open)(dev, tp, p));
+ if (error)
+ goto bad;
+
+ return (0);
+
+bad:
+ if (!ISSET(tp->t_state, TS_ISOPEN)) {
+ /*
+ * We failed to open the device, and nobody else had it opened.
+ * Clean up the state as appropriate.
+ */
+ zs_shutdown(zst);
+ }
+
+ return (error);
+}
+
+/*
+ * Close a zs serial port.
+ */
+int
+zsclose(dev_t dev, int flags, int mode, struct proc *p)
+{
+ struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev));
+ struct zs_chanstate *cs = zst->zst_cs;
+ struct tty *tp = zst->zst_tty;
+ int s;
+
+ /* XXX This is for cons.c. */
+ if (!ISSET(tp->t_state, TS_ISOPEN))
+ return 0;
+
+ (*linesw[tp->t_line].l_close)(tp, flags, p);
+
+ s = spltty();
+ cs->cs_cua = 0;
+ ttyclose(tp);
+ splx(s);
+
+ if (!ISSET(tp->t_state, TS_ISOPEN)) {
+ /*
+ * Although we got a last close, the device may still be in
+ * use; e.g. if this was the dialout node, and there are still
+ * processes waiting for carrier on the non-dialout node.
+ */
+ zs_shutdown(zst);
+ }
+
+ return (0);
+}
+
+/*
+ * Read/write zs serial port.
+ */
+int
+zsread(dev_t dev, struct uio *uio, int flags)
+{
+ struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev));
+ struct tty *tp = zst->zst_tty;
+
+ return (*linesw[tp->t_line].l_read)(tp, uio, flags);
+}
+
+int
+zswrite(dev_t dev, struct uio *uio, int flags)
+{
+ struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev));
+ struct tty *tp = zst->zst_tty;
+
+ return (*linesw[tp->t_line].l_write)(tp, uio, flags);
+}
+
+int
+zsioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+ struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev));
+ struct zs_chanstate *cs = zst->zst_cs;
+ struct tty *tp = zst->zst_tty;
+ int error;
+ int s;
+
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return (error);
+
+ error = ttioctl(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return (error);
+
+#ifdef ZS_MD_IOCTL
+ error = ZS_MD_IOCTL;
+ if (error >= 0)
+ return (error);
+#endif /* ZS_MD_IOCTL */
+
+ error = 0;
+
+ s = splzs();
+
+ switch (cmd) {
+ case TIOCSBRK:
+ zs_break(cs, 1);
+ break;
+
+ case TIOCCBRK:
+ zs_break(cs, 0);
+ break;
+
+ case TIOCGFLAGS:
+ *(int *)data = zst->zst_swflags;
+ break;
+
+ case TIOCSFLAGS:
+ error = suser(p, 0);
+ if (error)
+ break;
+ zst->zst_swflags = *(int *)data;
+ break;
+
+ case TIOCSDTR:
+ zs_modem(zst, 1);
+ break;
+
+ case TIOCCDTR:
+ zs_modem(zst, 0);
+ break;
+
+ case TIOCMSET:
+ case TIOCMBIS:
+ case TIOCMBIC:
+ tiocm_to_zs(zst, cmd, *(int *)data);
+ break;
+
+ case TIOCMGET:
+ *(int *)data = zs_to_tiocm(zst);
+ break;
+
+ default:
+ error = ENOTTY;
+ break;
+ }
+
+ splx(s);
+
+ return (error);
+}
+
+/*
+ * Start or restart transmission.
+ */
+void
+zsstart(struct tty *tp)
+{
+ struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(tp->t_dev));
+ struct zs_chanstate *cs = zst->zst_cs;
+ u_char *tba;
+ int tbc;
+ int s;
+
+ s = spltty();
+ if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
+ goto out;
+ if (zst->zst_tx_stopped)
+ goto out;
+
+ ttwakeupwr(tp);
+ if (tp->t_outq.c_cc == 0)
+ goto out;
+
+ /* Grab the first contiguous region of buffer space. */
+ tba = tp->t_outq.c_cf;
+ tbc = ndqb(&tp->t_outq, 0);
+
+ (void)splzs();
+
+ zst->zst_tba = tba;
+ zst->zst_tbc = tbc;
+ SET(tp->t_state, TS_BUSY);
+ zst->zst_tx_busy = 1;
+
+ /* Enable transmit completion interrupts if necessary. */
+ if (!ISSET(cs->cs_preg[1], ZSWR1_TIE)) {
+ SET(cs->cs_preg[1], ZSWR1_TIE);
+ cs->cs_creg[1] = cs->cs_preg[1];
+ zs_write_reg(cs, 1, cs->cs_creg[1]);
+ }
+
+ /* Output the first character of the contiguous buffer. */
+ zs_write_data(cs, *zst->zst_tba);
+ zst->zst_tbc--;
+ zst->zst_tba++;
+
+out:
+ splx(s);
+}
+
+/*
+ * Stop output, e.g., for ^S or output flush.
+ */
+int
+zsstop(struct tty *tp, int flag)
+{
+ struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(tp->t_dev));
+ int s;
+
+ s = splzs();
+ if (ISSET(tp->t_state, TS_BUSY)) {
+ /* Stop transmitting at the next chunk. */
+ zst->zst_tbc = 0;
+ zst->zst_heldtbc = 0;
+ if (!ISSET(tp->t_state, TS_TTSTOP))
+ SET(tp->t_state, TS_FLUSH);
+ }
+ splx(s);
+ return 0;
+}
+
+/*
+ * Set ZS tty parameters from termios.
+ * XXX - Should just copy the whole termios after
+ * making sure all the changes could be done.
+ */
+int
+zsparam(struct tty *tp, struct termios *t)
+{
+ struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(tp->t_dev));
+ struct zs_chanstate *cs = zst->zst_cs;
+ int ospeed;
+ tcflag_t cflag;
+ uint8_t tmp3, tmp4, tmp5;
+ int s, error;
+
+ ospeed = t->c_ospeed;
+ cflag = t->c_cflag;
+
+ /* Check requested parameters. */
+ if (ospeed < 0)
+ return (EINVAL);
+ if (t->c_ispeed && t->c_ispeed != ospeed)
+ return (EINVAL);
+
+ /*
+ * For the console, always force CLOCAL and !HUPCL, so that the port
+ * is always active.
+ */
+ if (ISSET(zst->zst_swflags, TIOCFLAG_SOFTCAR) ||
+ ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE)) {
+ SET(cflag, CLOCAL);
+ CLR(cflag, HUPCL);
+ }
+
+ /*
+ * Only whack the UART when params change.
+ * Some callers need to clear tp->t_ospeed
+ * to make sure initialization gets done.
+ */
+ if (tp->t_ospeed == ospeed &&
+ tp->t_cflag == cflag)
+ return (0);
+
+ /*
+ * Call MD functions to deal with changed
+ * clock modes or H/W flow control modes.
+ * The BRG divisor is set now. (reg 12,13)
+ */
+ error = zs_set_speed(cs, ospeed);
+ if (error)
+ return (error);
+ error = zs_set_modes(cs, cflag);
+ if (error)
+ return (error);
+
+ /*
+ * Block interrupts so that state will not
+ * be altered until we are done setting it up.
+ *
+ * Initial values in cs_preg are set before
+ * our attach routine is called. The master
+ * interrupt enable is handled by zsc.c
+ *
+ */
+ s = splzs();
+
+ /*
+ * Recalculate which status ints to enable.
+ */
+ zs_maskintr(zst);
+
+ /* Recompute character size bits. */
+ tmp3 = cs->cs_preg[3];
+ tmp5 = cs->cs_preg[5];
+ CLR(tmp3, ZSWR3_RXSIZE);
+ CLR(tmp5, ZSWR5_TXSIZE);
+ switch (ISSET(cflag, CSIZE)) {
+ case CS5:
+ SET(tmp3, ZSWR3_RX_5);
+ SET(tmp5, ZSWR5_TX_5);
+ break;
+ case CS6:
+ SET(tmp3, ZSWR3_RX_6);
+ SET(tmp5, ZSWR5_TX_6);
+ break;
+ case CS7:
+ SET(tmp3, ZSWR3_RX_7);
+ SET(tmp5, ZSWR5_TX_7);
+ break;
+ case CS8:
+ SET(tmp3, ZSWR3_RX_8);
+ SET(tmp5, ZSWR5_TX_8);
+ break;
+ }
+ cs->cs_preg[3] = tmp3;
+ cs->cs_preg[5] = tmp5;
+
+ /*
+ * Recompute the stop bits and parity bits. Note that
+ * zs_set_speed() may have set clock selection bits etc.
+ * in wr4, so those must preserved.
+ */
+ tmp4 = cs->cs_preg[4];
+ CLR(tmp4, ZSWR4_SBMASK | ZSWR4_PARMASK);
+ if (ISSET(cflag, CSTOPB))
+ SET(tmp4, ZSWR4_TWOSB);
+ else
+ SET(tmp4, ZSWR4_ONESB);
+ if (!ISSET(cflag, PARODD))
+ SET(tmp4, ZSWR4_EVENP);
+ if (ISSET(cflag, PARENB))
+ SET(tmp4, ZSWR4_PARENB);
+ cs->cs_preg[4] = tmp4;
+
+ /* And copy to tty. */
+ tp->t_ispeed = 0;
+ tp->t_ospeed = ospeed;
+ tp->t_cflag = cflag;
+
+ /*
+ * If nothing is being transmitted, set up new current values,
+ * else mark them as pending.
+ */
+ if (!cs->cs_heldchange) {
+ if (zst->zst_tx_busy) {
+ zst->zst_heldtbc = zst->zst_tbc;
+ zst->zst_tbc = 0;
+ cs->cs_heldchange = 1;
+ } else
+ zs_loadchannelregs(cs);
+ }
+
+ /*
+ * If hardware flow control is disabled, turn off the buffer water
+ * marks and unblock any soft flow control state. Otherwise, enable
+ * the water marks.
+ */
+ if (!ISSET(cflag, CHWFLOW)) {
+ zst->zst_r_hiwat = 0;
+ zst->zst_r_lowat = 0;
+ if (ISSET(zst->zst_rx_flags, RX_TTY_OVERFLOWED)) {
+ CLR(zst->zst_rx_flags, RX_TTY_OVERFLOWED);
+ zst->zst_rx_ready = 1;
+ cs->cs_softreq = 1;
+ }
+ if (ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED)) {
+ CLR(zst->zst_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED);
+ zs_hwiflow(zst);
+ }
+ } else {
+ zst->zst_r_hiwat = zstty_rbuf_hiwat;
+ zst->zst_r_lowat = zstty_rbuf_lowat;
+ }
+
+ /*
+ * Force a recheck of the hardware carrier and flow control status,
+ * since we may have changed which bits we're looking at.
+ */
+ zstty_stint(cs, 1);
+
+ splx(s);
+
+ /*
+ * If hardware flow control is disabled, unblock any hard flow control
+ * state.
+ */
+ if (!ISSET(cflag, CHWFLOW)) {
+ if (zst->zst_tx_stopped) {
+ zst->zst_tx_stopped = 0;
+ zsstart(tp);
+ }
+ }
+
+ zstty_softint(cs);
+
+ return (0);
+}
+
+/*
+ * Compute interrupt enable bits and set in the pending bits. Called both
+ * in zsparam() and when PPS (pulse per second timing) state changes.
+ * Must be called at splzs().
+ */
+void
+zs_maskintr(struct zstty_softc *zst)
+{
+ struct zs_chanstate *cs = zst->zst_cs;
+ uint8_t tmp15;
+
+ cs->cs_rr0_mask = cs->cs_rr0_cts | cs->cs_rr0_dcd;
+ if (zst->zst_ppsmask != 0)
+ cs->cs_rr0_mask |= cs->cs_rr0_pps;
+ tmp15 = cs->cs_preg[15];
+ if (ISSET(cs->cs_rr0_mask, ZSRR0_DCD))
+ SET(tmp15, ZSWR15_DCD_IE);
+ else
+ CLR(tmp15, ZSWR15_DCD_IE);
+ if (ISSET(cs->cs_rr0_mask, ZSRR0_CTS))
+ SET(tmp15, ZSWR15_CTS_IE);
+ else
+ CLR(tmp15, ZSWR15_CTS_IE);
+ cs->cs_preg[15] = tmp15;
+}
+
+
+/*
+ * Raise or lower modem control (DTR/RTS) signals. If a character is
+ * in transmission, the change is deferred.
+ * Called at splzs().
+ */
+void
+zs_modem(struct zstty_softc *zst, int onoff)
+{
+ struct zs_chanstate *cs = zst->zst_cs, *ccs;
+
+ if (cs->cs_wr5_dtr == 0)
+ return;
+
+ ccs = (cs->cs_ctl_chan != NULL ? cs->cs_ctl_chan : cs);
+
+ if (onoff)
+ SET(ccs->cs_preg[5], cs->cs_wr5_dtr);
+ else
+ CLR(ccs->cs_preg[5], cs->cs_wr5_dtr);
+
+ if (!cs->cs_heldchange) {
+ if (zst->zst_tx_busy) {
+ zst->zst_heldtbc = zst->zst_tbc;
+ zst->zst_tbc = 0;
+ cs->cs_heldchange = 1;
+ } else
+ zs_loadchannelregs(cs);
+ }
+}
+
+/*
+ * Set modem bits.
+ * Called at splzs().
+ */
+void
+tiocm_to_zs(struct zstty_softc *zst, u_long how, int ttybits)
+{
+ struct zs_chanstate *cs = zst->zst_cs, *ccs;
+ uint8_t zsbits;
+
+ ccs = (cs->cs_ctl_chan != NULL ? cs->cs_ctl_chan : cs);
+
+ zsbits = 0;
+ if (ISSET(ttybits, TIOCM_DTR))
+ SET(zsbits, ZSWR5_DTR);
+ if (ISSET(ttybits, TIOCM_RTS))
+ SET(zsbits, ZSWR5_RTS);
+
+ switch (how) {
+ case TIOCMBIC:
+ CLR(ccs->cs_preg[5], zsbits);
+ break;
+
+ case TIOCMBIS:
+ SET(ccs->cs_preg[5], zsbits);
+ break;
+
+ case TIOCMSET:
+ CLR(ccs->cs_preg[5], ZSWR5_RTS | ZSWR5_DTR);
+ SET(ccs->cs_preg[5], zsbits);
+ break;
+ }
+
+ if (!cs->cs_heldchange) {
+ if (zst->zst_tx_busy) {
+ zst->zst_heldtbc = zst->zst_tbc;
+ zst->zst_tbc = 0;
+ cs->cs_heldchange = 1;
+ } else
+ zs_loadchannelregs(cs);
+ }
+}
+
+/*
+ * Get modem bits.
+ * Called at splzs().
+ */
+int
+zs_to_tiocm(struct zstty_softc *zst)
+{
+ struct zs_chanstate *cs = zst->zst_cs, *ccs;
+ uint8_t zsbits;
+ int ttybits = 0;
+
+ ccs = (cs->cs_ctl_chan != NULL ? cs->cs_ctl_chan : cs);
+
+ zsbits = ccs->cs_preg[5];
+ if (ISSET(zsbits, ZSWR5_DTR))
+ SET(ttybits, TIOCM_DTR);
+ if (ISSET(zsbits, ZSWR5_RTS))
+ SET(ttybits, TIOCM_RTS);
+
+ zsbits = cs->cs_rr0;
+ if (ISSET(zsbits, ZSRR0_DCD))
+ SET(ttybits, TIOCM_CD);
+ if (ISSET(zsbits, ZSRR0_CTS))
+ SET(ttybits, TIOCM_CTS);
+
+ return (ttybits);
+}
+
+/*
+ * Try to block or unblock input using hardware flow-control.
+ * This is called by kern/tty.c if MDMBUF|CRTSCTS is set, and
+ * if this function returns non-zero, the TS_TBLOCK flag will
+ * be set or cleared according to the "block" arg passed.
+ */
+int
+zshwiflow(struct tty *tp, int block)
+{
+ struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(tp->t_dev));
+ struct zs_chanstate *cs = zst->zst_cs;
+ int s;
+
+ if (cs->cs_wr5_rts == 0)
+ return (0);
+
+ s = splzs();
+ if (block) {
+ if (!ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED)) {
+ SET(zst->zst_rx_flags, RX_TTY_BLOCKED);
+ zs_hwiflow(zst);
+ }
+ } else {
+ if (ISSET(zst->zst_rx_flags, RX_TTY_OVERFLOWED)) {
+ CLR(zst->zst_rx_flags, RX_TTY_OVERFLOWED);
+ zst->zst_rx_ready = 1;
+ cs->cs_softreq = 1;
+ }
+ if (ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED)) {
+ CLR(zst->zst_rx_flags, RX_TTY_BLOCKED);
+ zs_hwiflow(zst);
+ }
+ }
+ splx(s);
+ return (1);
+}
+
+/*
+ * Internal version of zshwiflow
+ * Called at splzs()
+ */
+void
+zs_hwiflow(struct zstty_softc *zst)
+{
+ struct zs_chanstate *cs = zst->zst_cs, *ccs;
+
+ if (cs->cs_wr5_rts == 0)
+ return;
+
+ ccs = (cs->cs_ctl_chan != NULL ? cs->cs_ctl_chan : cs);
+
+ if (ISSET(zst->zst_rx_flags, RX_ANY_BLOCK)) {
+ CLR(ccs->cs_preg[5], cs->cs_wr5_rts);
+ CLR(ccs->cs_creg[5], cs->cs_wr5_rts);
+ } else {
+ SET(ccs->cs_preg[5], cs->cs_wr5_rts);
+ SET(ccs->cs_creg[5], cs->cs_wr5_rts);
+ }
+ zs_write_reg(ccs, 5, ccs->cs_creg[5]);
+}
+
+
+/****************************************************************
+ * Interface to the lower layer (zscc)
+ ****************************************************************/
+
+#define integrate static inline
+integrate void zstty_rxsoft(struct zstty_softc *, struct tty *);
+integrate void zstty_txsoft(struct zstty_softc *, struct tty *);
+integrate void zstty_stsoft(struct zstty_softc *, struct tty *);
+void zstty_diag(void *);
+
+/*
+ * Receiver Ready interrupt.
+ * Called at splzs().
+ */
+void
+zstty_rxint(struct zs_chanstate *cs)
+{
+ struct zstty_softc *zst = cs->cs_private;
+ uint8_t *put, *end;
+ u_int cc;
+ uint8_t rr0, rr1, c;
+
+ end = zst->zst_ebuf;
+ put = zst->zst_rbput;
+ cc = zst->zst_rbavail;
+
+ while (cc > 0) {
+ /*
+ * First read the status, because reading the received char
+ * destroys the status of this char.
+ */
+ rr1 = zs_read_reg(cs, 1);
+ c = zs_read_data(cs);
+
+ if (ISSET(rr1, ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) {
+ /* Clear the receive error. */
+ zs_write_csr(cs, ZSWR0_RESET_ERRORS);
+ }
+
+ put[0] = c;
+ put[1] = rr1;
+ put += 2;
+ if (put >= end)
+ put = zst->zst_rbuf;
+ cc--;
+
+ rr0 = zs_read_csr(cs);
+ if (!ISSET(rr0, ZSRR0_RX_READY))
+ break;
+ }
+
+ /*
+ * Current string of incoming characters ended because
+ * no more data was available or we ran out of space.
+ * Schedule a receive event if any data was received.
+ * If we're out of space, turn off receive interrupts.
+ */
+ zst->zst_rbput = put;
+ zst->zst_rbavail = cc;
+ if (!ISSET(zst->zst_rx_flags, RX_TTY_OVERFLOWED)) {
+ zst->zst_rx_ready = 1;
+ cs->cs_softreq = 1;
+ }
+
+ /*
+ * See if we are in danger of overflowing a buffer. If
+ * so, use hardware flow control to ease the pressure.
+ */
+ if (!ISSET(zst->zst_rx_flags, RX_IBUF_BLOCKED) &&
+ cc < zst->zst_r_hiwat) {
+ SET(zst->zst_rx_flags, RX_IBUF_BLOCKED);
+ zs_hwiflow(zst);
+ }
+
+ /*
+ * If we're out of space, disable receive interrupts
+ * until the queue has drained a bit.
+ */
+ if (!cc) {
+ SET(zst->zst_rx_flags, RX_IBUF_OVERFLOWED);
+ CLR(cs->cs_preg[1], ZSWR1_RIE);
+ cs->cs_creg[1] = cs->cs_preg[1];
+ zs_write_reg(cs, 1, cs->cs_creg[1]);
+ }
+}
+
+/*
+ * Transmitter Ready interrupt.
+ * Called at splzs().
+ */
+void
+zstty_txint(struct zs_chanstate *cs)
+{
+ struct zstty_softc *zst = cs->cs_private;
+
+ zs_write_csr(cs, ZSWR0_RESET_TXINT);
+
+ /*
+ * If we've delayed a parameter change, do it now, and restart
+ * output.
+ */
+ if (cs->cs_heldchange) {
+ zs_loadchannelregs(cs);
+ cs->cs_heldchange = 0;
+ zst->zst_tbc = zst->zst_heldtbc;
+ zst->zst_heldtbc = 0;
+ }
+
+ /* Output the next character in the buffer, if any. */
+ if (zst->zst_tbc > 0) {
+ zs_write_data(cs, *zst->zst_tba);
+ zst->zst_tbc--;
+ zst->zst_tba++;
+ } else {
+ /* Disable transmit completion interrupts if necessary. */
+ if (ISSET(cs->cs_preg[1], ZSWR1_TIE)) {
+ CLR(cs->cs_preg[1], ZSWR1_TIE);
+ cs->cs_creg[1] = cs->cs_preg[1];
+ zs_write_reg(cs, 1, cs->cs_creg[1]);
+ }
+ if (zst->zst_tx_busy) {
+ zst->zst_tx_busy = 0;
+ zst->zst_tx_done = 1;
+ cs->cs_softreq = 1;
+ }
+ }
+}
+
+#ifdef DDB
+#include <ddb/db_var.h>
+#define DB_CONSOLE db_console
+#else
+#define DB_CONSOLE 1
+#endif
+
+/*
+ * Status Change interrupt.
+ * Called at splzs().
+ */
+void
+zstty_stint(struct zs_chanstate *cs, int force)
+{
+ struct zstty_softc *zst = cs->cs_private;
+ struct tty *tp = zst->zst_tty;
+ uint8_t rr0, delta;
+
+ rr0 = zs_read_csr(cs);
+ zs_write_csr(cs, ZSWR0_RESET_STATUS);
+
+ /*
+ * Check here for console break, so that we can abort
+ * even when interrupts are locking up the machine.
+ */
+ if ((zst->zst_hwflags & ZS_HWFLAG_CONSOLE_INPUT) &&
+ ISSET(rr0, ZSRR0_BREAK) && DB_CONSOLE)
+ zs_abort(cs);
+
+ if (!force)
+ delta = rr0 ^ cs->cs_rr0;
+ else
+ delta = cs->cs_rr0_mask;
+
+ ttytstamp(tp, cs->cs_rr0 & ZSRR0_CTS, rr0 & ZSRR0_CTS,
+ cs->cs_rr0 & ZSRR0_DCD, rr0 & ZSRR0_DCD);
+
+ cs->cs_rr0 = rr0;
+
+ if (ISSET(delta, cs->cs_rr0_mask)) {
+ SET(cs->cs_rr0_delta, delta);
+
+ /*
+ * Stop output immediately if we lose the output
+ * flow control signal or carrier detect.
+ */
+ if (ISSET(~rr0, cs->cs_rr0_mask)) {
+ zst->zst_tbc = 0;
+ zst->zst_heldtbc = 0;
+ }
+
+ zst->zst_st_check = 1;
+ cs->cs_softreq = 1;
+ }
+}
+
+void
+zstty_diag(void *arg)
+{
+ struct zstty_softc *zst = arg;
+ int overflows, floods;
+ int s;
+
+ s = splzs();
+ overflows = zst->zst_overflows;
+ zst->zst_overflows = 0;
+ floods = zst->zst_floods;
+ zst->zst_floods = 0;
+ zst->zst_errors = 0;
+ splx(s);
+
+ log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf flood%s\n",
+ zst->zst_dev.dv_xname,
+ overflows, overflows == 1 ? "" : "s",
+ floods, floods == 1 ? "" : "s");
+}
+
+integrate void
+zstty_rxsoft(struct zstty_softc *zst, struct tty *tp)
+{
+ struct zs_chanstate *cs = zst->zst_cs;
+ int (*rint)(int, struct tty *) = linesw[tp->t_line].l_rint;
+ uint8_t *get, *end;
+ u_int cc, scc;
+ uint8_t rr1;
+ int code;
+ int s;
+
+ end = zst->zst_ebuf;
+ get = zst->zst_rbget;
+ scc = cc = zstty_rbuf_size - zst->zst_rbavail;
+
+ if (cc == zstty_rbuf_size) {
+ zst->zst_floods++;
+ if (zst->zst_errors++ == 0)
+ timeout_add_sec(&zst->zst_diag_ch, 60);
+ }
+
+ /* If not yet open, drop the entire buffer content here */
+ if (!ISSET(tp->t_state, TS_ISOPEN)) {
+ get += cc << 1;
+ if (get >= end)
+ get -= zstty_rbuf_size << 1;
+ cc = 0;
+ }
+ while (cc) {
+ code = get[0];
+ rr1 = get[1];
+ if (ISSET(rr1, ZSRR1_DO | ZSRR1_FE | ZSRR1_PE)) {
+ if (ISSET(rr1, ZSRR1_DO)) {
+ zst->zst_overflows++;
+ if (zst->zst_errors++ == 0)
+ timeout_add_sec(&zst->zst_diag_ch, 60);
+ }
+ if (ISSET(rr1, ZSRR1_FE))
+ SET(code, TTY_FE);
+ if (ISSET(rr1, ZSRR1_PE))
+ SET(code, TTY_PE);
+ }
+ if ((*rint)(code, tp) == -1) {
+ /*
+ * The line discipline's buffer is out of space.
+ */
+ if (!ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED)) {
+ /*
+ * We're either not using flow control, or the
+ * line discipline didn't tell us to block for
+ * some reason. Either way, we have no way to
+ * know when there's more space available, so
+ * just drop the rest of the data.
+ */
+ get += cc << 1;
+ if (get >= end)
+ get -= zstty_rbuf_size << 1;
+ cc = 0;
+ } else {
+ /*
+ * Don't schedule any more receive processing
+ * until the line discipline tells us there's
+ * space available (through comhwiflow()).
+ * Leave the rest of the data in the input
+ * buffer.
+ */
+ SET(zst->zst_rx_flags, RX_TTY_OVERFLOWED);
+ }
+ break;
+ }
+ get += 2;
+ if (get >= end)
+ get = zst->zst_rbuf;
+ cc--;
+ }
+
+ if (cc != scc) {
+ zst->zst_rbget = get;
+ s = splzs();
+ cc = zst->zst_rbavail += scc - cc;
+ /* Buffers should be ok again, release possible block. */
+ if (cc >= zst->zst_r_lowat) {
+ if (ISSET(zst->zst_rx_flags, RX_IBUF_OVERFLOWED)) {
+ CLR(zst->zst_rx_flags, RX_IBUF_OVERFLOWED);
+ SET(cs->cs_preg[1], ZSWR1_RIE);
+ cs->cs_creg[1] = cs->cs_preg[1];
+ zs_write_reg(cs, 1, cs->cs_creg[1]);
+ }
+ if (ISSET(zst->zst_rx_flags, RX_IBUF_BLOCKED)) {
+ CLR(zst->zst_rx_flags, RX_IBUF_BLOCKED);
+ zs_hwiflow(zst);
+ }
+ }
+ splx(s);
+ }
+}
+
+integrate void
+zstty_txsoft(struct zstty_softc *zst, struct tty *tp)
+{
+ int s;
+
+ CLR(tp->t_state, TS_BUSY);
+ if (ISSET(tp->t_state, TS_FLUSH))
+ CLR(tp->t_state, TS_FLUSH);
+ else {
+ s = splzs();
+ ndflush(&tp->t_outq, (int)(zst->zst_tba - tp->t_outq.c_cf));
+ splx(s);
+ }
+ (*linesw[tp->t_line].l_start)(tp);
+}
+
+integrate void
+zstty_stsoft(struct zstty_softc *zst, struct tty *tp)
+{
+ struct zs_chanstate *cs = zst->zst_cs;
+ uint8_t rr0, delta;
+ int s;
+
+ s = splzs();
+ rr0 = cs->cs_rr0;
+ delta = cs->cs_rr0_delta;
+ cs->cs_rr0_delta = 0;
+ splx(s);
+
+ if (ISSET(delta, cs->cs_rr0_dcd)) {
+ /*
+ * Inform the tty layer that carrier detect changed.
+ */
+ (void)(*linesw[tp->t_line].l_modem)(tp, ISSET(rr0, ZSRR0_DCD));
+ }
+
+ if (ISSET(delta, cs->cs_rr0_cts)) {
+ /* Block or unblock output according to flow control. */
+ if (ISSET(rr0, cs->cs_rr0_cts)) {
+ zst->zst_tx_stopped = 0;
+ (*linesw[tp->t_line].l_start)(tp);
+ } else {
+ zst->zst_tx_stopped = 1;
+ }
+ }
+}
+
+/*
+ * Software interrupt. Called at zssoft
+ *
+ * The main job to be done here is to empty the input ring
+ * by passing its contents up to the tty layer. The ring is
+ * always emptied during this operation, therefore the ring
+ * must not be larger than the space after "high water" in
+ * the tty layer, or the tty layer might drop our input.
+ *
+ * Note: an "input blockage" condition is assumed to exist if
+ * EITHER the TS_TBLOCK flag or zst_rx_blocked flag is set.
+ */
+void
+zstty_softint(struct zs_chanstate *cs)
+{
+ struct zstty_softc *zst = cs->cs_private;
+ struct tty *tp = zst->zst_tty;
+ int s;
+
+ s = spltty();
+
+ if (zst->zst_rx_ready) {
+ zst->zst_rx_ready = 0;
+ zstty_rxsoft(zst, tp);
+ }
+
+ if (zst->zst_st_check) {
+ zst->zst_st_check = 0;
+ zstty_stsoft(zst, tp);
+ }
+
+ if (zst->zst_tx_done) {
+ zst->zst_tx_done = 0;
+ zstty_txsoft(zst, tp);
+ }
+
+ splx(s);
+}
+
+struct zsops zsops_tty = {
+ zstty_rxint, /* receive char available */
+ zstty_stint, /* external/status */
+ zstty_txint, /* xmit buffer empty */
+ zstty_softint, /* process software interrupt */
+};
diff --git a/sys/arch/sgi/hpc/zs.c b/sys/arch/sgi/hpc/zs.c
new file mode 100644
index 00000000000..c8ce8b74102
--- /dev/null
+++ b/sys/arch/sgi/hpc/zs.c
@@ -0,0 +1,712 @@
+/* $OpenBSD: zs.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: zs.c,v 1.37 2011/02/20 07:59:50 matt Exp $ */
+
+/*-
+ * Copyright (c) 1996, 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Gordon W. Ross and Wayne Knowles
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Zilog Z8530 Dual UART driver (machine-dependent part)
+ *
+ * Runs two serial lines per chip using slave drivers.
+ * Plain tty/async lines use the zs_async slave.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/device.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/tty.h>
+#include <sys/time.h>
+#include <sys/syslog.h>
+
+#include <mips64/archtype.h>
+#include <mips64/arcbios.h>
+
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+#include <machine/z8530var.h>
+
+#include <dev/cons.h>
+
+#include <dev/ic/z8530reg.h>
+
+#include <sgi/hpc/hpcvar.h>
+#include <sgi/hpc/hpcreg.h>
+#include <sgi/localbus/intvar.h>
+
+/*
+ * Some warts needed by z8530tty.c -
+ * The default parity REALLY needs to be the same as the PROM uses,
+ * or you can not see messages done with printf during boot-up...
+ */
+int zs_def_cflag = (CREAD | CS8 | HUPCL);
+int zs_major = 19;
+
+#define PCLK 3672000 /* PCLK pin input clock rate */
+
+#ifndef ZS_DEFSPEED
+#define ZS_DEFSPEED 9600
+#endif
+
+/*
+ * Define interrupt levels.
+ */
+#define ZSHARD_PRI 64
+
+/* SGI shouldn't need ZS_DELAY() as recovery time is done in hardware? */
+#define ZS_DELAY() delay(3)
+
+/* The layout of this is hardware-dependent (padding, order). */
+struct zschan {
+ uint8_t pad1[3];
+ volatile uint8_t zc_csr; /* ctrl,status, and indirect access */
+ uint8_t pad2[3];
+ volatile uint8_t zc_data; /* data */
+};
+
+struct zsdevice {
+ struct zschan zs_chan_b;
+ struct zschan zs_chan_a;
+};
+
+/* Return the byte offset of element within a structure */
+#define OFFSET(struct_def, el) ((size_t)&((struct_def *)0)->el)
+
+#define ZS_CHAN_A OFFSET(struct zsdevice, zs_chan_a)
+#define ZS_CHAN_B OFFSET(struct zsdevice, zs_chan_b)
+#define ZS_REG_CSR 3
+#define ZS_REG_DATA 7
+static int zs_chan_offset[] = {ZS_CHAN_A, ZS_CHAN_B};
+
+cons_decl(zs);
+struct consdev zs_cn = {
+ zscnprobe,
+ zscninit,
+ zscngetc,
+ zscnputc,
+ zscnpollc,
+ NULL
+};
+
+
+/* Flags from cninit() */
+static int zs_consunit = -1;
+static int zs_conschan = -1;
+
+/* Default speed for all channels */
+static int zs_defspeed = ZS_DEFSPEED;
+
+static uint8_t zs_init_reg[16] = {
+ 0, /* 0: CMD (reset, etc.) */
+ 0, /* 1: No interrupts yet. */
+ ZSHARD_PRI, /* 2: IVECT */
+ ZSWR3_RX_8 | ZSWR3_RX_ENABLE,
+ ZSWR4_CLK_X16 | ZSWR4_ONESB,
+ ZSWR5_TX_8 | ZSWR5_TX_ENABLE,
+ 0, /* 6: TXSYNC/SYNCLO */
+ 0, /* 7: RXSYNC/SYNCHI */
+ 0, /* 8: alias for data port */
+ ZSWR9_MASTER_IE,
+ 0, /*10: Misc. TX/RX control bits */
+ ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD | ZSWR11_TRXC_OUT_ENA,
+ BPS_TO_TCONST(PCLK/16, ZS_DEFSPEED), /*12: BAUDLO (default=9600) */
+ 0, /*13: BAUDHI (default=9600) */
+ ZSWR14_BAUD_ENA,
+ ZSWR15_BREAK_IE,
+};
+
+
+/****************************************************************
+ * Autoconfig
+ ****************************************************************/
+
+/* Definition of the driver for autoconfig. */
+int zs_hpc_match(struct device *, void *, void *);
+void zs_hpc_attach(struct device *, struct device *, void *);
+int zs_print(void *, const char *name);
+
+struct cfdriver zs_cd = {
+ NULL, "zs", DV_TTY
+};
+
+struct cfattach zs_hpc_ca = {
+ sizeof(struct zsc_softc), zs_hpc_match, zs_hpc_attach
+};
+
+int zshard(void *);
+void zssoft(void *);
+struct zschan *zs_get_chan_addr(int, int);
+int zs_getc(void *);
+void zs_putc(void *, int);
+
+/*
+ * Is the zs chip present?
+ */
+int
+zs_hpc_match(struct device *parent, void *vcf, void *aux)
+{
+ struct cfdata *cf = vcf;
+ struct hpc_attach_args *ha = aux;
+
+ if (strcmp(ha->ha_name, cf->cf_driver->cd_name) == 0)
+ return (1);
+
+ return (0);
+}
+
+/*
+ * Attach a found zs.
+ *
+ * Match slave number to zs unit number, so that misconfiguration will
+ * not set up the keyboard as ttya, etc.
+ */
+void
+zs_hpc_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct zsc_softc *zsc = (void *)self;
+ struct hpc_attach_args *haa = aux;
+ struct zsc_attach_args zsc_args;
+ struct zs_chanstate *cs;
+ struct zs_channel *ch;
+ int zs_unit, channel, err, s;
+
+ zsc->zsc_bustag = haa->ha_st;
+ if ((err = bus_space_subregion(haa->ha_st, haa->ha_sh,
+ haa->ha_devoff, 0x10,
+ &zsc->zsc_base)) != 0) {
+ printf(": unable to map 85c30 registers, error = %d\n",
+ err);
+ return;
+ }
+
+ zs_unit = zsc->zsc_dev.dv_unit;
+ printf("\n");
+
+ /*
+ * Initialize software state for each channel.
+ *
+ * Done in reverse order of channels since the first serial port
+ * is actually attached to the *second* channel, and vice versa.
+ * Doing it this way should force a 'zstty*' to attach zstty0 to
+ * channel 1 and zstty1 to channel 0. They couldn't have wired
+ * it up in a more sensible fashion, could they?
+ */
+ for (channel = 1; channel >= 0; channel--) {
+ zsc_args.channel = channel;
+ ch = &zsc->zsc_cs_store[channel];
+ cs = zsc->zsc_cs[channel] = (struct zs_chanstate *)ch;
+
+ cs->cs_reg_csr = NULL;
+ cs->cs_reg_data = NULL;
+ cs->cs_channel = channel;
+ cs->cs_private = NULL;
+ cs->cs_ops = &zsops_null;
+ cs->cs_brg_clk = PCLK / 16;
+
+ if (bus_space_subregion(zsc->zsc_bustag, zsc->zsc_base,
+ zs_chan_offset[channel],
+ sizeof(struct zschan),
+ &ch->cs_regs) != 0) {
+ printf("%s: cannot map regs\n", self->dv_xname);
+ return;
+ }
+ ch->cs_bustag = zsc->zsc_bustag;
+
+ memcpy(cs->cs_creg, zs_init_reg, 16);
+ memcpy(cs->cs_preg, zs_init_reg, 16);
+
+ /* If console, don't stomp speed, let zstty know */
+ if (zs_unit == zs_consunit && channel == zs_conschan) {
+ zsc_args.consdev = &zs_cn;
+ zsc_args.hwflags = ZS_HWFLAG_CONSOLE;
+ cs->cs_defspeed = bios_consrate;
+ } else {
+ zsc_args.consdev = NULL;
+ zsc_args.hwflags = 0;
+ cs->cs_defspeed = zs_defspeed;
+ }
+
+ cs->cs_defcflag = zs_def_cflag;
+
+ /* Make these correspond to cs_defcflag (-crtscts) */
+ cs->cs_rr0_dcd = ZSRR0_DCD;
+ cs->cs_rr0_cts = 0;
+ cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS;
+ cs->cs_wr5_rts = 0;
+
+ /*
+ * Clear the master interrupt enable.
+ * The INTENA is common to both channels,
+ * so just do it on the A channel.
+ */
+ if (channel == 0) {
+ zs_write_reg(cs, 9, 0);
+ }
+ /*
+ * Look for a child driver for this channel.
+ * The child attach will setup the hardware.
+ */
+ if (!config_found(self, (void *)&zsc_args, zs_print)) {
+ /* No sub-driver. Just reset it. */
+ uint8_t reset = (channel == 0) ?
+ ZSWR9_A_RESET : ZSWR9_B_RESET;
+
+ s = splhigh();
+ zs_write_reg(cs, 9, reset);
+ splx(s);
+ }
+ }
+
+
+ zsc->sc_si = softintr_establish(SI_SOFTTTY, zssoft, zsc);
+ int2_intr_establish(haa->ha_irq, IPL_TTY, zshard, zsc, self->dv_xname);
+
+ /*
+ * Set the master interrupt enable and interrupt vector.
+ * (common to both channels, do it on A)
+ */
+ cs = zsc->zsc_cs[0];
+ s = splhigh();
+ /* interrupt vector */
+ zs_write_reg(cs, 2, zs_init_reg[2]);
+ /* master interrupt control (enable) */
+ zs_write_reg(cs, 9, zs_init_reg[9]);
+ splx(s);
+}
+
+int
+zs_print(void *aux, const char *name)
+{
+ struct zsc_attach_args *args = aux;
+
+ if (name != NULL)
+ printf("%s: ", name);
+
+ if (args->channel != -1)
+ printf(" channel %d", args->channel);
+
+ return UNCONF;
+}
+
+/*
+ * Our ZS chips all share a common, autovectored interrupt,
+ * so we have to look at all of them on each interrupt.
+ */
+int
+zshard(void *arg)
+{
+ struct zsc_softc *zsc = arg;
+ int rr3, rval;
+
+ rval = 0;
+ while ((rr3 = zsc_intr_hard(zsc))) {
+ rval |= rr3;
+ }
+
+ if (zsc->zsc_cs[0]->cs_softreq ||
+ zsc->zsc_cs[1]->cs_softreq)
+ softintr_schedule(zsc->sc_si);
+
+ return rval;
+}
+
+/*
+ * Similar scheme as for zshard (look at all of them)
+ */
+void
+zssoft(void *arg)
+{
+ struct zsc_softc *zsc = arg;
+ int s;
+
+ /* Make sure we call the tty layer at spltty. */
+ s = spltty();
+ (void) zsc_intr_soft(zsc);
+ splx(s);
+}
+
+
+/*
+ * MD functions for setting the baud rate and control modes.
+ */
+int
+zs_set_speed(struct zs_chanstate *cs, int bps)
+{
+ int tconst, real_bps;
+
+ if (bps == 0)
+ return (0);
+
+#ifdef DIAGNOSTIC
+ if (cs->cs_brg_clk == 0)
+ panic("zs_set_speed");
+#endif
+
+ tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps);
+ if (tconst < 0)
+ return (EINVAL);
+
+ /* Convert back to make sure we can do it. */
+ real_bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst);
+
+#if 0 /* PCLK is too small, 9600bps really yields 9562 */
+ /* XXX - Allow some tolerance here? */
+ if (real_bps != bps)
+ return (EINVAL);
+#endif
+
+ cs->cs_preg[12] = tconst;
+ cs->cs_preg[13] = tconst >> 8;
+
+ /* Caller will stuff the pending registers. */
+ return (0);
+}
+
+int
+zs_set_modes(struct zs_chanstate *cs, int cflag)
+{
+ int s;
+
+ /*
+ * Output hardware flow control on the chip is horrendous:
+ * if carrier detect drops, the receiver is disabled, and if
+ * CTS drops, the transmitter is stoped IN MID CHARACTER!
+ * Therefore, NEVER set the HFC bit, and instead use the
+ * status interrupt to detect CTS changes.
+ */
+ s = splzs();
+ cs->cs_rr0_pps = 0;
+ if ((cflag & (CLOCAL | MDMBUF)) != 0) {
+ cs->cs_rr0_dcd = 0;
+ if ((cflag & MDMBUF) == 0)
+ cs->cs_rr0_pps = ZSRR0_DCD;
+ } else
+ cs->cs_rr0_dcd = ZSRR0_DCD;
+ if ((cflag & CRTSCTS) != 0) {
+ cs->cs_wr5_dtr = ZSWR5_DTR;
+ cs->cs_wr5_rts = ZSWR5_RTS;
+ cs->cs_rr0_cts = ZSRR0_CTS;
+ } else if ((cflag & MDMBUF) != 0) {
+ cs->cs_wr5_dtr = 0;
+ cs->cs_wr5_rts = ZSWR5_DTR;
+ cs->cs_rr0_cts = ZSRR0_DCD;
+ } else {
+ cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS;
+ cs->cs_wr5_rts = 0;
+ cs->cs_rr0_cts = 0;
+ }
+ splx(s);
+
+ /* Caller will stuff the pending registers. */
+ return (0);
+}
+
+
+/*
+ * Read or write the chip with suitable delays.
+ */
+
+uint8_t
+zs_read_reg(struct zs_chanstate *cs, uint8_t reg)
+{
+ uint8_t val;
+ struct zs_channel *zsc = (struct zs_channel *)cs;
+
+ bus_space_write_1(zsc->cs_bustag, zsc->cs_regs, ZS_REG_CSR, reg);
+ ZS_DELAY();
+ val = bus_space_read_1(zsc->cs_bustag, zsc->cs_regs, ZS_REG_CSR);
+ ZS_DELAY();
+ return val;
+}
+
+void
+zs_write_reg(struct zs_chanstate *cs, uint8_t reg, uint8_t val)
+{
+ struct zs_channel *zsc = (struct zs_channel *)cs;
+
+ bus_space_write_1(zsc->cs_bustag, zsc->cs_regs, ZS_REG_CSR, reg);
+ ZS_DELAY();
+ bus_space_write_1(zsc->cs_bustag, zsc->cs_regs, ZS_REG_CSR, val);
+ ZS_DELAY();
+}
+
+uint8_t
+zs_read_csr(struct zs_chanstate *cs)
+{
+ struct zs_channel *zsc = (struct zs_channel *)cs;
+ uint8_t val;
+
+ val = bus_space_read_1(zsc->cs_bustag, zsc->cs_regs, ZS_REG_CSR);
+ ZS_DELAY();
+ return val;
+}
+
+void
+zs_write_csr(struct zs_chanstate *cs, uint8_t val)
+{
+ struct zs_channel *zsc = (struct zs_channel *)cs;
+
+ bus_space_write_1(zsc->cs_bustag, zsc->cs_regs, ZS_REG_CSR, val);
+ ZS_DELAY();
+}
+
+uint8_t
+zs_read_data(struct zs_chanstate *cs)
+{
+ struct zs_channel *zsc = (struct zs_channel *)cs;
+ uint8_t val;
+
+ val = bus_space_read_1(zsc->cs_bustag, zsc->cs_regs, ZS_REG_DATA);
+ ZS_DELAY();
+ return val;
+}
+
+void
+zs_write_data(struct zs_chanstate *cs, uint8_t val)
+{
+ struct zs_channel *zsc = (struct zs_channel *)cs;
+
+ bus_space_write_1(zsc->cs_bustag, zsc->cs_regs, ZS_REG_DATA, val);
+ ZS_DELAY();
+}
+
+void
+zs_abort(struct zs_chanstate *cs)
+{
+#if defined(KGDB)
+ zskgdb(cs);
+#elif defined(DDB)
+ Debugger();
+#endif
+}
+
+
+/*********************************************************/
+/* Polled character I/O functions for console and KGDB */
+/*********************************************************/
+
+struct zschan *
+zs_get_chan_addr(int zs_unit, int channel)
+{
+#if 0
+ static int dumped_addr = 0;
+#endif
+ struct zsdevice *addr = NULL;
+ struct zschan *zc;
+
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ switch (zs_unit) {
+ case 0:
+ addr = (struct zsdevice *)
+ PHYS_TO_XKPHYS(0x1fb80d00, CCA_NC);
+ break;
+ case 1:
+ addr = (struct zsdevice *)
+ PHYS_TO_XKPHYS(0x1fb80d10, CCA_NC);
+ break;
+ }
+ break;
+
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ if (zs_unit == 0)
+ addr = (struct zsdevice *)
+ PHYS_TO_XKPHYS(0x1fbd9830, CCA_NC);
+ break;
+ }
+ if (addr == NULL)
+ panic("zs_get_chan_addr: bad zs_unit %d\n", zs_unit);
+
+ /*
+ * We need to swap serial ports to match reality on
+ * non-keyboard channels.
+ */
+ if (sys_config.system_type != SGI_IP20) {
+ if (channel == 0)
+ zc = &addr->zs_chan_b;
+ else
+ zc = &addr->zs_chan_a;
+ } else {
+ if (zs_unit == 0) {
+ if (channel == 0)
+ zc = &addr->zs_chan_a;
+ else
+ zc = &addr->zs_chan_b;
+ } else {
+ if (channel == 0)
+ zc = &addr->zs_chan_b;
+ else
+ zc = &addr->zs_chan_a;
+ }
+ }
+
+#if 0
+ if (dumped_addr == 0) {
+ dumped_addr++;
+ printf("zs unit %d, channel %d had address %p\n",
+ zs_unit, channel, zc);
+ }
+#endif
+
+ return (zc);
+}
+
+int
+zs_getc(void *arg)
+{
+ register volatile struct zschan *zc = arg;
+ register int s, c, rr0;
+
+ s = splzs();
+ /* Wait for a character to arrive. */
+ do {
+ rr0 = zc->zc_csr;
+ ZS_DELAY();
+ } while ((rr0 & ZSRR0_RX_READY) == 0);
+
+ c = zc->zc_data;
+ ZS_DELAY();
+ splx(s);
+
+ return (c);
+}
+
+/*
+ * Polled output char.
+ */
+void
+zs_putc(void *arg, int c)
+{
+ register volatile struct zschan *zc = arg;
+ register int s, rr0;
+
+ s = splzs();
+ /* Wait for transmitter to become ready. */
+ do {
+ rr0 = zc->zc_csr;
+ ZS_DELAY();
+ } while ((rr0 & ZSRR0_TX_READY) == 0);
+
+ zc->zc_data = c;
+ __asm__ __volatile__ ("sync" ::: "memory"); /* wbflush(); */
+ ZS_DELAY();
+ splx(s);
+}
+
+/***************************************************************/
+
+static int cons_port;
+
+void
+zscnprobe(struct consdev *cp)
+{
+ cp->cn_dev = makedev(zs_major, 0);
+ cp->cn_pri = CN_DEAD;
+
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ if (strlen(bios_console) == 9 &&
+ strncmp(bios_console, "serial", 6) == 0)
+ cp->cn_pri = CN_FORCED;
+ else
+ cp->cn_pri = CN_MIDPRI;
+ break;
+ }
+}
+
+void
+zscninit(struct consdev *cn)
+{
+ if (strlen(bios_console) == 9 &&
+ strncmp(bios_console, "serial", 6) != 0)
+ cons_port = bios_console[7] - '0';
+
+ /* Mark this unit as the console */
+ zs_consunit = 0;
+
+ /* SGI hardware wires serial port 1 to channel B, port 2 to A */
+ if (cons_port == 0)
+ zs_conschan = 1;
+ else
+ zs_conschan = 0;
+}
+
+int
+zscngetc(dev_t dev)
+{
+ struct zschan *zs;
+
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ zs = zs_get_chan_addr(1, cons_port);
+ break;
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ default:
+ zs = zs_get_chan_addr(0, cons_port);
+ break;
+ }
+
+ return zs_getc(zs);
+}
+
+void
+zscnputc(dev_t dev, int c)
+{
+ struct zschan *zs;
+
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ zs = zs_get_chan_addr(1, cons_port);
+ break;
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ default:
+ zs = zs_get_chan_addr(0, cons_port);
+ break;
+ }
+
+ zs_putc(zs, c);
+}
+
+void
+zscnpollc(dev_t dev, int on)
+{
+}
diff --git a/sys/arch/sgi/include/autoconf.h b/sys/arch/sgi/include/autoconf.h
index b71366edba6..d3db14d94e5 100644
--- a/sys/arch/sgi/include/autoconf.h
+++ b/sys/arch/sgi/include/autoconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: autoconf.h,v 1.32 2012/03/25 13:52:52 miod Exp $ */
+/* $OpenBSD: autoconf.h,v 1.33 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 2001-2003 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -93,6 +93,7 @@ void arcs_device_register(struct device *, void *);
void dksc_device_register(struct device *, void *);
extern void (*_device_register)(struct device *, void *);
+void ip22_setup(void);
void ip27_setup(void);
void ip27_autoconf(struct device *);
void ip30_setup(void);
diff --git a/sys/arch/sgi/include/eisa_machdep.h b/sys/arch/sgi/include/eisa_machdep.h
new file mode 100644
index 00000000000..93ba8c4c4e8
--- /dev/null
+++ b/sys/arch/sgi/include/eisa_machdep.h
@@ -0,0 +1,68 @@
+/* $OpenBSD: eisa_machdep.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: eisa_machdep.h,v 1.4 1997/06/06 23:12:52 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Christopher G. Demetriou
+ * for the NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Machine-specific definitions for EISA autoconfiguration.
+ */
+
+/*
+ * EISA spaces memory layout
+ */
+
+#define EISA_IO_BASE 0x00080000
+#define EISA_IO_END 0x00090000
+
+#define EISA_MEM0_BASE 0x00100000
+#define EISA_MEM0_END 0x08000000
+
+#define EISA_MEM1_BASE 0x80000000
+#define EISA_MEM1_END 0x100000000UL
+
+/*
+ * Types provided to machine-independent EISA code.
+ */
+typedef void *eisa_chipset_tag_t;
+typedef int eisa_intr_handle_t;
+
+/*
+ * Functions provided to machine-independent EISA code.
+ */
+void eisa_attach_hook(struct device *, struct device *,
+ struct eisabus_attach_args *);
+int eisa_maxslots(eisa_chipset_tag_t);
+int eisa_intr_map(eisa_chipset_tag_t, u_int,
+ eisa_intr_handle_t *);
+const char *eisa_intr_string(eisa_chipset_tag_t, eisa_intr_handle_t);
+void *eisa_intr_establish(eisa_chipset_tag_t, eisa_intr_handle_t,
+ int, int, int (*)(void *), void *, char *);
+void eisa_intr_disestablish(eisa_chipset_tag_t, void *);
diff --git a/sys/arch/sgi/include/z8530var.h b/sys/arch/sgi/include/z8530var.h
new file mode 100644
index 00000000000..5fab516b720
--- /dev/null
+++ b/sys/arch/sgi/include/z8530var.h
@@ -0,0 +1,121 @@
+/* $OpenBSD: z8530var.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: z8530var.h,v 1.10 2011/07/01 21:00:21 dyoung Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)zsvar.h 8.1 (Berkeley) 6/11/93
+ */
+
+/*
+ * Copyright (c) 1994 Gordon W. Ross
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)zsvar.h 8.1 (Berkeley) 6/11/93
+ */
+
+#include <machine/bus.h>
+#include <sgi/hpc/z8530sc.h>
+
+struct zs_channel {
+ struct zs_chanstate cs_zscs; /* Required: soft state */
+ bus_space_tag_t cs_bustag; /* Machine-dependent */
+ bus_space_handle_t cs_regs;
+};
+
+struct zsc_softc {
+ struct device zsc_dev; /* required: base device */
+ struct zs_chanstate *zsc_cs[2]; /* channel soft state */
+ struct zs_channel zsc_cs_store[2];
+ /* Machine-dependent part follows... */
+ bus_space_tag_t zsc_bustag; /* Bus type */
+ bus_space_handle_t zsc_base; /* Device base address */
+ void *sc_si; /* Softinterrupt handle */
+};
+
+/*
+ * Functions to read and write individual registers in a channel.
+ * The SCC chip requires 3-4 PCLK cycles recovery time between accesses
+ */
+
+uint8_t zs_read_reg(struct zs_chanstate *, uint8_t);
+uint8_t zs_read_csr(struct zs_chanstate *);
+uint8_t zs_read_data(struct zs_chanstate *);
+
+void zs_write_reg(struct zs_chanstate *, uint8_t, uint8_t);
+void zs_write_csr(struct zs_chanstate *, uint8_t);
+void zs_write_data(struct zs_chanstate *, uint8_t);
+
+/* Zilog Serial hardware interrupts (level 0) */
+#define splzs() spltty()
+#define IPL_ZS IPL_TTY
diff --git a/sys/arch/sgi/localbus/imc.c b/sys/arch/sgi/localbus/imc.c
new file mode 100644
index 00000000000..c8544aa8788
--- /dev/null
+++ b/sys/arch/sgi/localbus/imc.c
@@ -0,0 +1,826 @@
+/* $OpenBSD: imc.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: imc.c,v 1.32 2011/07/01 18:53:46 dyoung Exp $ */
+
+/*
+ * Copyright (c) 2012 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * Copyright (c) 2001 Rafal K. Boni
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/systm.h>
+
+#include <mips64/archtype.h>
+
+#include <machine/autoconf.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+
+#include <sgi/sgi/ip22.h>
+#include <sgi/localbus/imcreg.h>
+#include <sgi/localbus/imcvar.h>
+
+#include <sgi/hpc/hpcreg.h>
+#include <sgi/gio/giovar.h>
+
+#include "eisa.h"
+
+#if NEISA > 0
+#include <dev/eisa/eisavar.h>
+#endif
+
+int imc_match(struct device *, void *, void *);
+void imc_attach(struct device *, struct device *, void *);
+int imc_print(void *, const char *);
+
+const struct cfattach imc_ca = {
+ sizeof(struct device), imc_match, imc_attach
+};
+
+struct cfdriver imc_cd = {
+ NULL, "imc", DV_DULL
+};
+
+uint32_t imc_bus_error(uint32_t, struct trap_frame *);
+void imc_bus_reset(void);
+int imc_watchdog_cb(void *, int);
+
+uint8_t imc_read_1(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+uint16_t imc_read_2(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+void imc_read_raw_2(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ uint8_t *, bus_size_t);
+void imc_write_1(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint8_t);
+void imc_write_2(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint16_t);
+void imc_write_raw_2(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ const uint8_t *, bus_size_t);
+uint32_t imc_read_4(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+uint64_t imc_read_8(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+void imc_write_4(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint32_t);
+void imc_write_8(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint64_t);
+void imc_read_raw_4(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ uint8_t *, bus_size_t);
+void imc_write_raw_4(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ const uint8_t *, bus_size_t);
+void imc_read_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ uint8_t *, bus_size_t);
+void imc_write_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ const uint8_t *, bus_size_t);
+int imc_space_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
+ bus_space_handle_t *);
+void imc_space_unmap(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+int imc_space_region(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ bus_size_t, bus_space_handle_t *);
+void *imc_space_vaddr(bus_space_tag_t, bus_space_handle_t);
+void imc_space_barrier(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ bus_size_t, int);
+
+bus_space_t imcbus_tag = {/* not static for gio_cnattch() */
+ PHYS_TO_XKPHYS(0, CCA_NC),
+ NULL,
+ imc_read_1, imc_write_1,
+ imc_read_2, imc_write_2,
+ imc_read_4, imc_write_4,
+ imc_read_8, imc_write_8,
+ imc_read_raw_2, imc_write_raw_2,
+ imc_read_raw_4, imc_write_raw_4,
+ imc_read_raw_8, imc_write_raw_8,
+ imc_space_map, imc_space_unmap, imc_space_region,
+ imc_space_vaddr, imc_space_barrier
+};
+
+#if NEISA > 0
+int imc_eisa_io_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
+ bus_space_handle_t *);
+int imc_eisa_io_region(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ bus_size_t, bus_space_handle_t *);
+int imc_eisa_mem_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
+ bus_space_handle_t *);
+int imc_eisa_mem_region(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ bus_size_t, bus_space_handle_t *);
+
+static bus_space_t imcbus_eisa_io_tag = {
+ PHYS_TO_XKPHYS(EISA_IO_BASE, CCA_NC),
+ NULL,
+ imc_read_1, imc_write_1,
+ imc_read_2, imc_write_2,
+ imc_read_4, imc_write_4,
+ imc_read_8, imc_write_8,
+ imc_read_raw_2, imc_write_raw_2,
+ imc_read_raw_4, imc_write_raw_4,
+ imc_read_raw_8, imc_write_raw_8,
+ imc_eisa_io_map, imc_space_unmap, imc_eisa_io_region,
+ imc_space_vaddr, imc_space_barrier
+};
+static bus_space_t imcbus_eisa_mem_tag = {
+ PHYS_TO_XKPHYS(0, CCA_NC),
+ NULL,
+ imc_read_1, imc_write_1,
+ imc_read_2, imc_write_2,
+ imc_read_4, imc_write_4,
+ imc_read_8, imc_write_8,
+ imc_read_raw_2, imc_write_raw_2,
+ imc_read_raw_4, imc_write_raw_4,
+ imc_read_raw_8, imc_write_raw_8,
+ imc_eisa_mem_map, imc_space_unmap, imc_eisa_mem_region,
+ imc_space_vaddr, imc_space_barrier
+};
+#endif
+
+bus_addr_t imc_pa_to_device(paddr_t);
+paddr_t imc_device_to_pa(bus_addr_t);
+
+struct machine_bus_dma_tag imc_bus_dma_tag = {/* not static for gio_cnattch() */
+ NULL, /* _cookie */
+ _dmamap_create,
+ _dmamap_destroy,
+ _dmamap_load,
+ _dmamap_load_mbuf,
+ _dmamap_load_uio,
+ _dmamap_load_raw,
+ _dmamap_load_buffer,
+ _dmamap_unload,
+ _dmamap_sync,
+ _dmamem_alloc,
+ _dmamem_free,
+ _dmamem_map,
+ _dmamem_unmap,
+ _dmamem_mmap,
+ imc_pa_to_device,
+ imc_device_to_pa,
+ 0
+};
+
+/*
+ * Bus access primitives.
+ */
+
+uint8_t
+imc_read_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
+{
+ return *(volatile uint8_t *)(h + o);
+}
+
+uint16_t
+imc_read_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
+{
+ return *(volatile uint16_t *)(h + o);
+}
+
+uint32_t
+imc_read_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
+{
+ return *(volatile uint32_t *)(h + o);
+}
+
+uint64_t
+imc_read_8(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
+{
+ return *(volatile uint64_t *)(h + o);
+}
+
+void
+imc_write_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint8_t v)
+{
+ *(volatile uint8_t *)(h + o) = v;
+}
+
+void
+imc_write_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint16_t v)
+{
+ *(volatile uint16_t *)(h + o) = v;
+}
+
+void
+imc_write_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint32_t v)
+{
+ *(volatile uint32_t *)(h + o) = v;
+}
+
+void
+imc_write_8(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint64_t v)
+{
+ *(volatile uint64_t *)(h + o) = v;
+}
+
+void
+imc_read_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
+ uint8_t *buf, bus_size_t len)
+{
+ volatile uint16_t *addr = (volatile uint16_t *)(h + o);
+ len >>= 1;
+ while (len-- != 0) {
+ *(uint16_t *)buf = *addr;
+ buf += 2;
+ }
+}
+
+void
+imc_write_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
+ const uint8_t *buf, bus_size_t len)
+{
+ volatile uint16_t *addr = (volatile uint16_t *)(h + o);
+ len >>= 1;
+ while (len-- != 0) {
+ *addr = *(uint16_t *)buf;
+ buf += 2;
+ }
+}
+
+void
+imc_read_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
+ uint8_t *buf, bus_size_t len)
+{
+ volatile uint32_t *addr = (volatile uint32_t *)(h + o);
+ len >>= 2;
+ while (len-- != 0) {
+ *(uint32_t *)buf = *addr;
+ buf += 4;
+ }
+}
+
+void
+imc_write_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
+ const uint8_t *buf, bus_size_t len)
+{
+ volatile uint32_t *addr = (volatile uint32_t *)(h + o);
+ len >>= 2;
+ while (len-- != 0) {
+ *addr = *(uint32_t *)buf;
+ buf += 4;
+ }
+}
+
+void
+imc_read_raw_8(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
+ uint8_t *buf, bus_size_t len)
+{
+ volatile uint64_t *addr = (volatile uint64_t *)(h + o);
+ len >>= 3;
+ while (len-- != 0) {
+ *(uint64_t *)buf = *addr;
+ buf += 8;
+ }
+}
+
+void
+imc_write_raw_8(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
+ const uint8_t *buf, bus_size_t len)
+{
+ volatile uint64_t *addr = (volatile uint64_t *)(h + o);
+ len >>= 3;
+ while (len-- != 0) {
+ *addr = *(uint64_t *)buf;
+ buf += 8;
+ }
+}
+
+int
+imc_space_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size,
+ int flags, bus_space_handle_t *bshp)
+{
+ *bshp = t->bus_base + offs;
+ return 0;
+}
+
+void
+imc_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size)
+{
+}
+
+int
+imc_space_region(bus_space_tag_t t, bus_space_handle_t bsh,
+ bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp)
+{
+ *nbshp = bsh + offset;
+ return 0;
+}
+
+void *
+imc_space_vaddr(bus_space_tag_t t, bus_space_handle_t h)
+{
+ return (void *)h;
+}
+
+void
+imc_space_barrier(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offs,
+ bus_size_t len, int flags)
+{
+ __asm__ __volatile__ ("sync" ::: "memory");
+}
+
+#if NEISA > 0
+int
+imc_eisa_io_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, int flags,
+ bus_space_handle_t *bshp)
+{
+ if (offs + size > EISA_IO_END - EISA_IO_BASE)
+ return EINVAL;
+
+ *bshp = t->bus_base + offs;
+ return 0;
+}
+
+int
+imc_eisa_io_region(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
+ bus_size_t size, bus_space_handle_t *nbshp)
+{
+ if ((bsh - t->bus_base) + offset + size > EISA_IO_END - EISA_IO_BASE)
+ return EINVAL;
+
+ *nbshp = bsh + offset;
+ return 0;
+}
+
+int
+imc_eisa_mem_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, int flags,
+ bus_space_handle_t *bshp)
+{
+ if ((offs >= EISA_MEM0_BASE && offs + size <= EISA_MEM0_END) ||
+ (offs >= EISA_MEM1_BASE && offs + size <= EISA_MEM1_END)) {
+ *bshp = t->bus_base + offs;
+ return 0;
+ }
+
+ return EINVAL;
+}
+
+int
+imc_eisa_mem_region(bus_space_tag_t t, bus_space_handle_t bsh,
+ bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp)
+{
+ bus_addr_t orig = bsh - t->bus_base;
+
+ if ((orig >= EISA_MEM0_BASE && orig + offset + size <= EISA_MEM0_END) ||
+ (orig >= EISA_MEM1_BASE && orig + offset + size <= EISA_MEM1_END)) {
+ *nbshp = t->bus_base + offset;
+ return 0;
+ }
+
+ return EINVAL;
+}
+#endif
+
+bus_addr_t
+imc_pa_to_device(paddr_t pa)
+{
+ return (bus_addr_t)pa;
+}
+
+paddr_t
+imc_device_to_pa(bus_addr_t addr)
+{
+ return (paddr_t)addr;
+}
+
+/*
+ * Autoconf glue.
+ */
+
+int
+imc_match(struct device *parent, void *match, void *aux)
+{
+ struct mainbus_attach_args *maa = (void *)aux;
+
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ break;
+ default:
+ return 0;
+ }
+
+ return strcmp(maa->maa_name, imc_cd.cd_name) == 0;
+}
+
+void
+imc_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct imc_attach_args iaa;
+#if NEISA > 0
+ struct eisabus_attach_args eba;
+#endif
+ uint32_t reg;
+ uint32_t id, rev;
+ int have_eisa;
+
+ id = imc_read(IMC_SYSID);
+ rev = id & IMC_SYSID_REVMASK;
+
+ /* EISA exists on Indigo2 only */
+ if (sys_config.system_type != SGI_IP20 &&
+ sys_config.system_subtype == IP22_INDIGO2)
+ have_eisa = (id & IMC_SYSID_HAVEISA) != 0;
+ else
+ have_eisa = 0;
+
+ printf(": revision %d\n", rev);
+
+ /* Clear CPU/GIO error status registers to clear any leftover bits. */
+ imc_bus_reset();
+
+ /* Disable watchdog if leftover from previous reboot */
+ imc_watchdog_cb(self, 0);
+
+ /* Hook the bus error handler into the ISR */
+ set_intr(INTPRI_BUSERR, CR_INT_4, imc_bus_error);
+
+ /*
+ * Enable parity reporting on GIO/main memory transactions.
+ * Disable parity checking on CPU bus transactions (as turning
+ * it on seems to cause spurious bus errors), but enable parity
+ * checking on CPU reads from main memory (note that this bit
+ * has the opposite sense... Turning it on turns the checks off!).
+ * Finally, turn on interrupt writes to the CPU from the MC.
+ */
+ reg = imc_read(IMC_CPUCTRL0);
+ reg &= ~IMC_CPUCTRL0_NCHKMEMPAR;
+ reg |= (IMC_CPUCTRL0_GPR | IMC_CPUCTRL0_MPR | IMC_CPUCTRL0_INTENA);
+ imc_write(IMC_CPUCTRL0, reg);
+
+ /* Setup the MC write buffer depth */
+ reg = imc_read(IMC_CPUCTRL1);
+ reg = (reg & ~IMC_CPUCTRL1_MCHWMSK) | 13;
+
+ /*
+ * Force endianness on the onboard HPC and both slots.
+ * This should be safe for Fullhouse, but leave it conditional
+ * for now.
+ */
+ switch (sys_config.system_type) {
+ case SGI_IP22:
+ if (sys_config.system_subtype != IP22_INDY)
+ break;
+ /* FALLTHROUGH */
+ case SGI_IP20:
+ reg |= IMC_CPUCTRL1_HPCFX;
+ reg |= IMC_CPUCTRL1_EXP0FX;
+ reg |= IMC_CPUCTRL1_EXP1FX;
+ reg &= ~IMC_CPUCTRL1_HPCLITTLE;
+ reg &= ~IMC_CPUCTRL1_EXP0LITTLE;
+ reg &= ~IMC_CPUCTRL1_EXP1LITTLE;
+ break;
+ }
+ imc_write(IMC_CPUCTRL1, reg);
+
+ /*
+ * Set GIO64 arbitrator configuration register:
+ *
+ * Preserve PROM-set graphics-related bits, as they seem to depend
+ * on the graphics variant present and I'm not sure how to figure
+ * that out or 100% sure what the correct settings are for each.
+ */
+ reg = imc_read(IMC_GIO64ARB);
+ reg &= (IMC_GIO64ARB_GRX64 | IMC_GIO64ARB_GRXRT | IMC_GIO64ARB_GRXMST);
+
+ /*
+ * Rest of settings are machine/board dependent
+ * XXX I wonder if this even works as advertized. The logic apparently
+ * XXX comes from Linux, but the EISA settings look horribly broken to
+ * XXX me -- miod
+ */
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ reg |= IMC_GIO64ARB_ONEGIO;
+ reg |= IMC_GIO64ARB_EXP0RT | IMC_GIO64ARB_EXP1RT;
+ reg |= IMC_GIO64ARB_EXP0MST | IMC_GIO64ARB_EXP1MST;
+ reg &= ~(IMC_GIO64ARB_HPC64 |
+ IMC_GIO64ARB_HPCEXP64 | IMC_GIO64ARB_EISA64 |
+ IMC_GIO64ARB_EXP064 | IMC_GIO64ARB_EXP164 |
+ IMC_GIO64ARB_EXP0PIPE | IMC_GIO64ARB_EXP1PIPE);
+ break;
+ default:
+ /*
+ * GIO64 invariant for all IP22 platforms: one GIO bus,
+ * HPC1 @ 64
+ */
+ reg |= IMC_GIO64ARB_ONEGIO | IMC_GIO64ARB_HPC64;
+
+ switch (sys_config.system_subtype) {
+ default:
+ case IP22_INDY:
+ /* XXX is MST mutually exclusive? */
+ reg |= IMC_GIO64ARB_EXP0RT | IMC_GIO64ARB_EXP1RT;
+ reg |= IMC_GIO64ARB_EXP0MST | IMC_GIO64ARB_EXP1MST;
+
+ /* EISA can bus-master, is 64-bit */
+ reg |= IMC_GIO64ARB_EISAMST | IMC_GIO64ARB_EISA64;
+ break;
+
+ case IP22_INDIGO2:
+ /*
+ * All Fullhouse boards have a 64-bit HPC2 and pipelined
+ * EXP0 slot.
+ */
+ reg |= IMC_GIO64ARB_HPCEXP64 | IMC_GIO64ARB_EXP0PIPE;
+
+ if (rev < 2) {
+ /* EXP0 realtime, EXP1 can master */
+ reg |= IMC_GIO64ARB_EXP0RT |
+ IMC_GIO64ARB_EXP1MST;
+ } else {
+ /* EXP1 pipelined as well, EISA masters */
+ reg |= IMC_GIO64ARB_EXP1PIPE |
+ IMC_GIO64ARB_EISAMST;
+ }
+ break;
+ }
+ }
+
+ imc_write(IMC_GIO64ARB, reg);
+
+#if NEISA > 0
+ if (have_eisa) {
+ memset(&eba, 0, sizeof(eba));
+ eba.eba_busname = "eisa";
+ eba.eba_iot = &imcbus_eisa_io_tag;
+ eba.eba_memt = &imcbus_eisa_mem_tag;
+ eba.eba_dmat = &imc_bus_dma_tag;
+ eba.eba_ec = NULL;
+ config_found(self, &eba, imc_print);
+ }
+#endif
+
+ memset(&iaa, 0, sizeof(iaa));
+ iaa.iaa_name = "gio";
+ iaa.iaa_st = &imcbus_tag;
+ iaa.iaa_dmat = &imc_bus_dma_tag;
+ config_found(self, &iaa, imc_print);
+
+ /* Clear CPU/GIO error status registers to clear any leftover bits. */
+ imc_bus_reset();
+
+ /* Register watchdog */
+ wdog_register(self, imc_watchdog_cb);
+}
+
+int
+imc_print(void *aux, const char *name)
+{
+ struct imc_attach_args *iaa = aux;
+
+ if (name != NULL)
+ printf("%s at %s", iaa->iaa_name, name);
+
+ return UNCONF;
+}
+
+void
+imc_bus_reset()
+{
+ imc_write(IMC_CPU_ERRSTAT, 0);
+ imc_write(IMC_GIO_ERRSTAT, 0);
+}
+
+uint32_t
+imc_bus_error(uint32_t hwpend, struct trap_frame *tf)
+{
+ printf("bus error: cpu_stat %08x addr %08x, gio_stat %08x addr %08x\n",
+ imc_read(IMC_CPU_ERRSTAT),
+ imc_read(IMC_CPU_ERRADDR),
+ imc_read(IMC_GIO_ERRSTAT),
+ imc_read(IMC_GIO_ERRADDR));
+ imc_bus_reset();
+
+ return hwpend;
+}
+
+int
+imc_watchdog_cb(void *v, int period)
+{
+ uint32_t reg;
+
+ if (period == 0) {
+ /* reset... */
+ imc_write(IMC_WDOG, 0);
+ /* ...and disable */
+ reg = imc_read(IMC_CPUCTRL0);
+ reg &= ~(IMC_CPUCTRL0_WDOG);
+ imc_write(IMC_CPUCTRL0, reg);
+
+ return 0;
+ } else {
+ /* enable... */
+ reg = imc_read(IMC_CPUCTRL0);
+ reg |= IMC_CPUCTRL0_WDOG;
+ imc_write(IMC_CPUCTRL0, reg);
+ /* ...and reset */
+ imc_write(IMC_WDOG, 0);
+
+ /*
+ * The watchdog period is not controllable; it will fire
+ * when the 20 bit counter, running on a 64 usec clock,
+ * overflows.
+ */
+ return (64 << 20) / 1000000;
+ }
+}
+
+/* intended to be called from gio/gio.c only */
+int
+imc_gio64_arb_config(int slot, uint32_t flags)
+{
+ uint32_t reg;
+
+ if (sys_config.system_type == SGI_IP20 ||
+ sys_config.system_subtype != IP22_INDIGO2) {
+ /* GIO_SLOT_GFX is only usable on Fullhouse */
+ if (slot == GIO_SLOT_GFX)
+ return EINVAL;
+ } else {
+ /* GIO_SLOT_EXP1 is unusable on Fullhouse */
+ if (slot == GIO_SLOT_EXP1)
+ return EINVAL;
+ }
+
+ /* GIO_SLOT_GFX is always pipelined */
+ if (slot == GIO_SLOT_GFX && (flags & GIO_ARB_NOPIPE))
+ return EINVAL;
+
+ /* IP20 does not support pipelining (XXX what about Indy?) */
+ if (((flags & GIO_ARB_PIPE) || (flags & GIO_ARB_NOPIPE)) &&
+ sys_config.system_type == SGI_IP20)
+ return EINVAL;
+
+ reg = imc_read(IMC_GIO64ARB);
+
+ if (flags & GIO_ARB_RT) {
+ if (slot == GIO_SLOT_EXP0)
+ reg |= IMC_GIO64ARB_EXP0RT;
+ else if (slot == GIO_SLOT_EXP1)
+ reg |= IMC_GIO64ARB_EXP1RT;
+ else if (slot == GIO_SLOT_GFX)
+ reg |= IMC_GIO64ARB_GRXRT;
+ }
+
+ if (flags & GIO_ARB_MST) {
+ if (slot == GIO_SLOT_EXP0)
+ reg |= IMC_GIO64ARB_EXP0MST;
+ else if (slot == GIO_SLOT_EXP1)
+ reg |= IMC_GIO64ARB_EXP1MST;
+ else if (slot == GIO_SLOT_GFX)
+ reg |= IMC_GIO64ARB_GRXMST;
+ }
+
+ if (flags & GIO_ARB_PIPE) {
+ if (slot == GIO_SLOT_EXP0)
+ reg |= IMC_GIO64ARB_EXP0PIPE;
+ else if (slot == GIO_SLOT_EXP1)
+ reg |= IMC_GIO64ARB_EXP1PIPE;
+ }
+
+ if (flags & GIO_ARB_LB) {
+ if (slot == GIO_SLOT_EXP0)
+ reg &= ~IMC_GIO64ARB_EXP0RT;
+ else if (slot == GIO_SLOT_EXP1)
+ reg &= ~IMC_GIO64ARB_EXP1RT;
+ else if (slot == GIO_SLOT_GFX)
+ reg &= ~IMC_GIO64ARB_GRXRT;
+ }
+
+ if (flags & GIO_ARB_SLV) {
+ if (slot == GIO_SLOT_EXP0)
+ reg &= ~IMC_GIO64ARB_EXP0MST;
+ else if (slot == GIO_SLOT_EXP1)
+ reg &= ~IMC_GIO64ARB_EXP1MST;
+ else if (slot == GIO_SLOT_GFX)
+ reg &= ~IMC_GIO64ARB_GRXMST;
+ }
+
+ if (flags & GIO_ARB_NOPIPE) {
+ if (slot == GIO_SLOT_EXP0)
+ reg &= ~IMC_GIO64ARB_EXP0PIPE;
+ else if (slot == GIO_SLOT_EXP1)
+ reg &= ~IMC_GIO64ARB_EXP1PIPE;
+ }
+
+ if (flags & GIO_ARB_32BIT) {
+ if (slot == GIO_SLOT_EXP0)
+ reg &= ~IMC_GIO64ARB_EXP064;
+ else if (slot == GIO_SLOT_EXP1)
+ reg &= ~IMC_GIO64ARB_EXP164;
+ }
+
+ if (flags & GIO_ARB_64BIT) {
+ if (slot == GIO_SLOT_EXP0)
+ reg |= IMC_GIO64ARB_EXP064;
+ else if (slot == GIO_SLOT_EXP1)
+ reg |= IMC_GIO64ARB_EXP164;
+ }
+
+ if (flags & GIO_ARB_HPC2_32BIT)
+ reg &= ~IMC_GIO64ARB_HPCEXP64;
+
+ if (flags & GIO_ARB_HPC2_64BIT)
+ reg |= IMC_GIO64ARB_HPCEXP64;
+
+ imc_write(IMC_GIO64ARB, reg);
+
+ return 0;
+}
+
+/*
+ * According to chapter 19 of the "IRIX Device Driver Programmer's Guide",
+ * some GIO devices, which do not drive all data lines, may cause false
+ * memory read parity errors on the SysAD bus. The workaround is to disable
+ * parity checking.
+ */
+void
+imc_disable_sysad_parity(void)
+{
+ uint32_t reg;
+
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ break;
+ default:
+ return;
+ }
+
+ reg = imc_read(IMC_CPUCTRL0);
+ reg |= IMC_CPUCTRL0_NCHKMEMPAR;
+ imc_write(IMC_CPUCTRL0, reg);
+}
+
+void
+imc_enable_sysad_parity(void)
+{
+ uint32_t reg;
+
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ break;
+ default:
+ return;
+ }
+
+ reg = imc_read(IMC_CPUCTRL0);
+ reg &= ~IMC_CPUCTRL0_NCHKMEMPAR;
+ imc_write(IMC_CPUCTRL0, reg);
+}
+
+#if 0
+int
+imc_is_sysad_parity_enabled(void)
+{
+ uint32_t reg;
+
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ break;
+ default:
+ return 0;
+ }
+
+ reg = imc_read(IMC_CPUCTRL0);
+
+ return reg & IMC_CPUCTRL0_NCHKMEMPAR;
+}
+#endif
diff --git a/sys/arch/sgi/localbus/imcreg.h b/sys/arch/sgi/localbus/imcreg.h
new file mode 100644
index 00000000000..fd27ff4c9be
--- /dev/null
+++ b/sys/arch/sgi/localbus/imcreg.h
@@ -0,0 +1,143 @@
+/* $OpenBSD: imcreg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: imcreg.h,v 1.4 2005/12/11 12:18:52 christos Exp $ */
+
+/*
+ * Copyright (c) 2001 Rafal K. Boni
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define IMC_BASE 0x1fa00000
+
+#define IMC_CPUCTRL0 0x04 /* CPU control, register 0 */
+
+#define IMC_CPUCTRL0_REFMASK 0x000f /* # lines to refresh */
+#define IMC_CPUCTRL0_RFE 0x0010 /* refresh enable */
+#define IMC_CPUCTRL0_GPR 0x0020 /* GIO parity enable */
+#define IMC_CPUCTRL0_MPR 0x0040 /* memory parity enable */
+#define IMC_CPUCTRL0_CPR 0x0080 /* cpu bus parity enable */
+#define IMC_CPUCTRL0_WDOG 0x0100 /* watchdog enable */
+#define IMC_CPUCTRL0_SIN 0x0200 /* reset system */
+#define IMC_CPUCTRL0_GRR 0x0400 /* graphics reset */
+#define IMC_CPUCTRL0_ENLOCK 0x0800 /* enable EISA memory lock */
+#define IMC_CPUCTRL0_CMDPAR 0x1000 /* SysCmd parity enable */
+#define IMC_CPUCTRL0_INTENA 0x2000 /* enable CPU interrupts */
+#define IMC_CPUCTRL0_SNOOPENA 0x4000 /* enable gfx DMA snoop */
+#define IMC_CPUCTRL0_PROM_WRENA 0x8000 /* disable buserr on PROM
+ * writes */
+#define IMC_CPUCTRL0_WRST 0x00010000 /* warm restart (reset cpu) */
+/* Bit 17 reserved 0x00020000 */
+#define IMC_CPUCTRL0_LITTLE 0x00040000 /* MC little-endian toggle */
+#define IMC_CPUCTRL0_WRRST 0x00080000 /* cpu warm reset */
+#define IMC_CPUCTRL0_MUXHWMSK 0x01f00000 /* MUX fifo high-water mask */
+#define IMC_CPUCTRL0_BADPAR 0x02000000 /* generate bad parity on
+ * CPU->memory writes */
+#define IMC_CPUCTRL0_NCHKMEMPAR 0x04000000 /* disable CPU parity check
+ * on memory reads. */
+#define IMC_CPUCTRL0_BACK2 0x08000000 /* enable back2back GIO wrt */
+#define IMC_CPUCTRL0_BUSRTMSK 0xf0000000 /* stall cycle for berr data */
+
+#define IMC_CPUCTRL1 0x0c /* CPU control, register 1 */
+#define IMC_CPUCTRL1_MCHWMSK 0x0000000f /* MC FIFO high water mask */
+#define IMC_CPUCTRL1_ABORTEN 0x00000010 /* Enable GIO bus timeouts */
+/* Bits 5 - 11 reserved 0x00000fe0 */
+#define IMC_CPUCTRL1_HPCFX 0x00001000 /* HPC endian fix */
+#define IMC_CPUCTRL1_HPCLITTLE 0x00002000 /* HPC DMA is little-endian */
+#define IMC_CPUCTRL1_EXP0FX 0x00004000 /* EXP0 endian fix */
+#define IMC_CPUCTRL1_EXP0LITTLE 0x00008000 /* EXP0 DMA is little-endian */
+#define IMC_CPUCTRL1_EXP1FX 0x00010000 /* EXP1 endian fix */
+#define IMC_CPUCTRL1_EXP1LITTLE 0x00020000 /* EXP1 DMA is little-endian */
+
+#define IMC_WDOG 0x14 /* Watchdog counter */
+#define IMC_WDOG_MASK 0x001fffff /* counter mask */
+
+#define IMC_SYSID 0x1c /* MC revision register */
+#define IMC_SYSID_REVMASK 0x0000000f /* MC revision mask */
+#define IMC_SYSID_HAVEISA 0x00000010 /* EISA present */
+
+#define IMC_RPSSDIV 0x2c /* RPSS divider */
+#define IMC_RPSSDIV_DIVMSK 0x000000ff /* RPC divider mask */
+#define IMC_RPSSDIV_INCMSK 0x0000ff00 /* RPC increment mask */
+
+#define IMC_EEPROM 0x34 /* EEPROM serial interface */
+/* Bit 1 is reserved 0x00000001 */
+#define IMC_EEPROM_CS 0x00000002 /* EEPROM chip select */
+#define IMC_EEPROM_SCK 0x00000004 /* EEPROM serial clock */
+#define IMC_EEPROM_SO 0x00000008 /* Serial data to EEPROM */
+#define IMC_EEPROM_SI 0x00000010 /* Serial data from EEPROM */
+
+#define IMC_CTRLD 0x44 /* Refresh counter preload */
+#define IMC_CTRLD_MSK 0x000000ff /* Counter preload mask */
+
+#define IMC_REFCTR 0x4c /* Refresh counter */
+#define IMC_REFCTR_MSK 0x000000ff /* Refresh counter mask */
+
+#define IMC_GIO64ARB 0x84 /* GIO64 arbitration params */
+#define IMC_GIO64ARB_HPC64 0x00000001 /* HPC addr size (32/64bit) */
+#define IMC_GIO64ARB_GRX64 0x00000002 /* Gfx addr size (32/64bit) */
+#define IMC_GIO64ARB_EXP064 0x00000004 /* EXP0 addr size (32/64bit) */
+#define IMC_GIO64ARB_EXP164 0x00000008 /* EXP0 addr size (32/64bit) */
+#define IMC_GIO64ARB_EISA64 0x00000010 /* EISA addr size (32/64bit) */
+#define IMC_GIO64ARB_HPCEXP64 0x00000020 /* HPC2 addr size (32/64bit) */
+#define IMC_GIO64ARB_GRXRT 0x00000040 /* Gfx is realtime device */
+#define IMC_GIO64ARB_EXP0RT 0x00000080 /* EXP0 is realtime device */
+#define IMC_GIO64ARB_EXP1RT 0x00000100 /* EXP1 is realtime device */
+#define IMC_GIO64ARB_EISAMST 0x00000200 /* EISA can be busmaster */
+#define IMC_GIO64ARB_ONEGIO 0x00000400 /* Only one GIO64 bus */
+#define IMC_GIO64ARB_GRXMST 0x00000800 /* Gfx can be busmaster */
+#define IMC_GIO64ARB_EXP0MST 0x00001000 /* EXP0 can be busmaster */
+#define IMC_GIO64ARB_EXP1MST 0x00002000 /* EXP1 can be busmaster */
+#define IMC_GIO64ARB_EXP0PIPE 0x00004000 /* EXP0 is pipelined */
+#define IMC_GIO64ARB_EXP1PIPE 0x00008000 /* EXP1 is pipelined */
+
+#define IMC_CPUTIME 0x8c /* Arbiter CPU time period */
+
+#define IMC_LBTIME 0x9c /* Arbiter long-burst time */
+
+#define IMC_MEMCFG0 0xc4 /* Mem config, register 0 */
+#define IMC_MEMCFG1 0xcc /* Mem config, register 1 */
+#define IMC_MEMC_BANK_MASK 0x0000ffff
+#define IMC_MEMC_BANK_SHIFT 16
+#define IMC_MEMC_ADDR_MASK 0x00ff
+#define IMC_MEMC_ADDR_SHIFT 0
+#define IMC_MEMC_SIZE_MASK 0x1f00
+#define IMC_MEMC_SIZE_SHIFT 8
+#define IMC_MEMC_LSHIFT 22 /* 4MB units */
+#define IMC_MEMC_LSHIFT_HUGE 24 /* 16MB units */
+#define IMC_MEMC_VALID 0x2000
+#define IMC_MEMC_SUBBANKS 0x4000
+
+#define IMC_CPU_MEMACC 0xd4 /* CPU mem access config */
+
+#define IMC_GIO_MEMACC 0xdc /* GIO mem access config */
+
+#define IMC_CPU_ERRADDR 0xe4 /* CPU error address */
+
+#define IMC_CPU_ERRSTAT 0xec /* CPU error status */
+
+#define IMC_GIO_ERRADDR 0xf4 /* GIO error address */
+
+#define IMC_GIO_ERRSTAT 0xfc /* GIO error status */
+
+#define IMC_RPSS 0x1004 /* RPSS counter */
diff --git a/sys/arch/sgi/localbus/imcvar.h b/sys/arch/sgi/localbus/imcvar.h
new file mode 100644
index 00000000000..651d23f9d3e
--- /dev/null
+++ b/sys/arch/sgi/localbus/imcvar.h
@@ -0,0 +1,42 @@
+/* $OpenBSD: imcvar.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: imcvar.h,v 1.1 2006/08/30 23:44:52 rumble Exp $ */
+
+/*
+ * Copyright (c) 2006 Stephen M. Rumble
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+struct imc_attach_args {
+ const char *iaa_name;
+ bus_space_tag_t iaa_st;
+ bus_dma_tag_t iaa_dmat;
+};
+
+int imc_gio64_arb_config(int, uint32_t);
+void imc_disable_sysad_parity(void);
+void imc_enable_sysad_parity(void);
+int imc_is_sysad_parity_enabled(void);
+
+#define imc_read(o) \
+ *(volatile uint32_t *)PHYS_TO_XKPHYS(IMC_BASE + (o), CCA_NC)
+#define imc_write(o,v) \
+ *(volatile uint32_t *)PHYS_TO_XKPHYS(IMC_BASE + (o), CCA_NC) = (v)
diff --git a/sys/arch/sgi/localbus/int.c b/sys/arch/sgi/localbus/int.c
new file mode 100644
index 00000000000..01e8b2a5dde
--- /dev/null
+++ b/sys/arch/sgi/localbus/int.c
@@ -0,0 +1,369 @@
+/* $OpenBSD: int.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: int.c,v 1.24 2011/07/01 18:53:46 dyoung Exp $ */
+
+/*
+ * Copyright (c) 2009 Stephen M. Rumble
+ * Copyright (c) 2004 Christopher SEKIYA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * INT2 (IP20, IP22) /INT3 (IP24) interrupt controllers
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+
+#include <mips64/archtype.h>
+
+#include <machine/autoconf.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/intr.h>
+
+#include <dev/ic/i8253reg.h>
+
+#include <sgi/localbus/intreg.h>
+#include <sgi/localbus/intvar.h>
+#include <sgi/sgi/ip22.h>
+
+int int2_match(struct device *, void *, void *);
+void int2_attach(struct device *, struct device *, void *);
+int int2_mappable_intr(void *);
+
+const struct cfattach int_ca = {
+ sizeof(struct device), int2_match, int2_attach
+};
+
+struct cfdriver int_cd = {
+ NULL, "int", DV_DULL
+};
+
+paddr_t int2_base;
+
+#define int2_read(r) *(volatile uint8_t *)(int2_base + (r))
+#define int2_write(r, v) *(volatile uint8_t *)(int2_base + (r)) = (v)
+
+/*
+ * INT2 Interrupt handling declarations: 16 local sources on 2 levels.
+ * (we don't use the i8254 timer interrupts)
+ *
+ * In addition to this, INT3 provides 8 so-called mappable interrupts, which
+ * are cascaded to either one of the unused two INT2 VME interrupts.
+ * To make things easier from a software viewpoint, we pretend there are
+ * 16 of them - one set of 8 per cascaded interrupt. This allows for
+ * faster recognition on where to connect these interrupts - as long as
+ * interrupt vector assignment makes sure no mappable interrupt is
+ * registered on both cascaded interrupts.
+ */
+
+#define INT2_NINTS (8 + 8 + 2 * 8)
+struct intrhand *int2_intrhand[INT2_NINTS];
+
+uint32_t int2_intem;
+uint8_t int2_l0imask[NIPLS], int2_l1imask[NIPLS];
+
+void int2_splx(int);
+uint32_t int2_l0intr(uint32_t, struct trap_frame *);
+void int2_l0makemasks(void);
+uint32_t int2_l1intr(uint32_t, struct trap_frame *);
+void int2_l1makemasks(void);
+
+/*
+ * Level 0 interrupt handler.
+ */
+
+uint32_t save_l0imr, save_l0isr, save_l0ipl;
+#define INTR_FUNCTIONNAME int2_l0intr
+#define MASK_FUNCTIONNAME int2_l0makemasks
+
+#define INTR_LOCAL_DECLS
+#define MASK_LOCAL_DECLS
+#define INTR_GETMASKS \
+do { \
+ isr = int2_read(INT2_LOCAL0_STATUS); \
+ imr = int2_read(INT2_LOCAL0_MASK); \
+ bit = 7; \
+save_l0isr = isr; save_l0imr = imr; save_l0ipl = frame->ipl; \
+} while (0)
+#define INTR_MASKPENDING \
+ int2_write(INT2_LOCAL0_MASK, imr & ~isr)
+#define INTR_IMASK(ipl) int2_l0imask[ipl]
+#define INTR_HANDLER(bit) int2_intrhand[bit + 0]
+#define INTR_SPURIOUS(bit) \
+do { \
+ printf("spurious int2 interrupt %d\n", bit); \
+} while (0)
+#define INTR_MASKRESTORE \
+ int2_write(INT2_LOCAL0_MASK, imr)
+#define INTR_MASKSIZE 8
+
+#include <sgi/sgi/intr_template.c>
+
+/*
+ * Level 1 interrupt handler.
+ */
+
+uint32_t save_l1imr, save_l1isr, save_l1ipl;
+#define INTR_FUNCTIONNAME int2_l1intr
+#define MASK_FUNCTIONNAME int2_l1makemasks
+
+#define INTR_LOCAL_DECLS
+#define MASK_LOCAL_DECLS
+#define INTR_GETMASKS \
+do { \
+ isr = int2_read(INT2_LOCAL1_STATUS); \
+ imr = int2_read(INT2_LOCAL1_MASK); \
+ bit = 7; \
+save_l1isr = isr; save_l1imr = imr; save_l1ipl = frame->ipl; \
+} while (0)
+#define INTR_MASKPENDING \
+ int2_write(INT2_LOCAL1_MASK, imr & ~isr)
+#define INTR_IMASK(ipl) int2_l1imask[ipl]
+#define INTR_HANDLER(bit) int2_intrhand[bit + 8]
+#define INTR_SPURIOUS(bit) \
+do { \
+ printf("spurious int2 interrupt %d\n", bit + 8); \
+} while (0)
+#define INTR_MASKRESTORE \
+ int2_write(INT2_LOCAL1_MASK, imr)
+#define INTR_MASKSIZE 8
+
+#include <sgi/sgi/intr_template.c>
+
+void *
+int2_intr_establish(int irq, int level, int (*ih_fun) (void *),
+ void *ih_arg, const char *ih_what)
+{
+ struct intrhand **p, *q, *ih;
+ int s;
+
+#ifdef DIAGNOSTIC
+ if (irq < 0 || irq >= INT2_NINTS)
+ panic("int2_intr_establish: illegal irq %d", irq);
+#endif
+
+ ih = malloc(sizeof *ih, M_DEVBUF, M_NOWAIT);
+ if (ih == NULL)
+ return NULL;
+
+ ih->ih_next = NULL;
+ ih->ih_fun = ih_fun;
+ ih->ih_arg = ih_arg;
+ ih->ih_level = level;
+ ih->ih_irq = irq;
+ if (ih_what != NULL)
+ evcount_attach(&ih->ih_count, ih_what, &ih->ih_irq);
+
+ s = splhigh();
+
+ for (p = &int2_intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
+ ;
+ *p = ih;
+
+ int2_intem |= 1 << irq;
+ switch (irq >> 3) {
+ case 0:
+ int2_l0makemasks();
+ break;
+ case 1:
+ int2_l1makemasks();
+ break;
+ /*
+ * We do not maintain masks for mappable interrupts. They are
+ * masked as a whole, by the level 0 or 1 interrupt they cascade to.
+ */
+ case 2:
+ int2_write(INT2_MAP_MASK0,
+ int2_read(INT2_MAP_MASK0) | (1 << (irq & 7)));
+ break;
+ case 3:
+ int2_write(INT2_MAP_MASK1,
+ int2_read(INT2_MAP_MASK1) | (1 << (irq & 7)));
+ break;
+ }
+
+ splx(s); /* will cause hardware mask update */
+
+ return ih;
+}
+
+void
+int2_splx(int newipl)
+{
+ struct cpu_info *ci = curcpu();
+ uint32_t sr;
+
+ __asm__ ("\t.set noreorder\n");
+ ci->ci_ipl = newipl;
+ __asm__ ("sync\n\t.set reorder\n");
+
+ sr = disableintr(); /* XXX overkill? */
+ int2_write(INT2_LOCAL1_MASK, (int2_intem >> 8) & ~int2_l1imask[newipl]);
+ int2_write(INT2_LOCAL0_MASK, int2_intem & ~int2_l0imask[newipl]);
+ setsr(sr);
+
+ if (ci->ci_softpending != 0 && newipl < IPL_SOFTINT)
+ setsoftintr0();
+}
+
+/*
+ * Mappable interrupts handler.
+ */
+
+int
+int2_mappable_intr(void *arg)
+{
+ uint which = (unsigned long)arg;
+ uint64_t imr, isr;
+ uint i, intnum;
+ struct intrhand *ih;
+ int rc, ret;
+
+ isr = int2_read(INT2_MAP_STATUS);
+ imr = int2_read(INT2_MAP_MASK0 + (which << 2));
+
+ isr &= imr;
+ if (isr == 0)
+ return 0; /* not for us */
+
+ /*
+ * Don't bother masking sources here - all mappable interrupts are
+ * tied to either a level 1 or level 0 interrupt, and the dispatcher
+ * is registered at IPL_TTY, so we can safely assume we are running
+ * at IPL_TTY now.
+ */
+
+ for (i = 0; i < 8; i++) {
+ intnum = i + 16 + (which << 3);
+ if (isr & (1 << i)) {
+ rc = 0;
+ for (ih = int2_intrhand[intnum]; ih != NULL;
+ ih = ih->ih_next) {
+ ret = (*ih->ih_fun)(ih->ih_arg);
+ if (ret != 0) {
+ rc = 1;
+ atomic_add_uint64(&ih->ih_count.ec_count,
+ 1);
+ }
+ if (ret == 1)
+ break;
+ }
+ if (rc == 0)
+ printf("spurious int2 mapped interrupt %d\n",
+ i);
+ }
+ }
+
+ return 1;
+}
+
+int
+int2_match(struct device *parent, void *match, void *aux)
+{
+ struct mainbus_attach_args *maa = (void *)aux;
+
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ break;
+ default:
+ return 0;
+ }
+
+ return !strcmp(maa->maa_name, int_cd.cd_name);
+}
+
+void
+int2_attach(struct device *parent, struct device *self, void *aux)
+{
+ uint32_t address;
+
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ address = INT2_IP20;
+ break;
+ default:
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ if (sys_config.system_subtype == IP22_INDIGO2)
+ address = INT2_IP22;
+ else
+ address = INT2_IP24;
+ break;
+ }
+
+ printf(" addr 0x%x\n", address);
+ int2_base = PHYS_TO_XKPHYS((uint64_t)address, CCA_NC);
+
+ /* Clean out interrupt masks */
+ int2_write(INT2_LOCAL0_MASK, 0);
+ int2_write(INT2_LOCAL1_MASK, 0);
+ int2_write(INT2_MAP_MASK0, 0);
+ int2_write(INT2_MAP_MASK1, 0);
+
+ /* Reset timer interrupts */
+ int2_write(INT2_TIMER_CONTROL,
+ TIMER_SEL0 | TIMER_16BIT | TIMER_SWSTROBE);
+ int2_write(INT2_TIMER_CONTROL,
+ TIMER_SEL1 | TIMER_16BIT | TIMER_SWSTROBE);
+ int2_write(INT2_TIMER_CONTROL,
+ TIMER_SEL2 | TIMER_16BIT | TIMER_SWSTROBE);
+ __asm__ __volatile__ ("sync" ::: "memory");
+ delay(4);
+ int2_write(INT2_TIMER_CLEAR, 0x03);
+
+ set_intr(INTPRI_L1, CR_INT_1, int2_l1intr);
+ set_intr(INTPRI_L0, CR_INT_0, int2_l0intr);
+ register_splx_handler(int2_splx);
+
+ if (sys_config.system_type != SGI_IP20) {
+ /* Wire interrupts 7, 11 to mappable interrupt 0,1 handlers */
+ int2_intr_establish(7, IPL_TTY, int2_mappable_intr,
+ (void *)0, NULL);
+ int2_intr_establish(8 + 3, IPL_TTY, int2_mappable_intr,
+ (void *)1, NULL);
+ }
+}
+
+/*
+ * Wait for the FIFO Full interrupt condition (Local 0 bit 0) to clear.
+ */
+void
+int2_wait_fifo(uint32_t flag)
+{
+ if (int2_base == 0)
+ delay(5000); /* XXX */
+ else
+ while (int2_read(INT2_LOCAL0_STATUS) & flag)
+ ;
+}
diff --git a/sys/arch/sgi/localbus/intreg.h b/sys/arch/sgi/localbus/intreg.h
new file mode 100644
index 00000000000..c6deca4e933
--- /dev/null
+++ b/sys/arch/sgi/localbus/intreg.h
@@ -0,0 +1,51 @@
+/* $OpenBSD: intreg.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: int2reg.h,v 1.5 2009/02/12 06:33:57 rumble Exp $ */
+
+/*
+ * Copyright (c) 2004 Christopher SEKIYA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* The INT has known locations on all SGI machines */
+#define INT2_IP20 0x1fb801c0
+#define INT2_IP22 0x1fbd9000
+#define INT2_IP24 0x1fbd9880
+
+/* The following registers are all 8 bit. */
+#define INT2_LOCAL0_STATUS 0x03
+#define INT2_LOCAL0_STATUS_FIFO 0x01
+#define INT2_LOCAL0_MASK 0x07
+#define INT2_LOCAL1_STATUS 0x0b
+#define INT2_LOCAL1_MASK 0x0f
+#define INT2_MAP_STATUS 0x13
+#define INT2_MAP_MASK0 0x17
+#define INT2_MAP_MASK1 0x1b
+#define INT2_MAP_POL 0x1f
+#define INT2_TIMER_CLEAR 0x23
+#define INT2_ERROR_STATUS 0x27
+#define INT2_TIMER_0 0x33
+#define INT2_TIMER_1 0x37
+#define INT2_TIMER_2 0x3b
+#define INT2_TIMER_CONTROL 0x3f
diff --git a/sys/arch/sgi/localbus/intvar.h b/sys/arch/sgi/localbus/intvar.h
new file mode 100644
index 00000000000..c8f6a133862
--- /dev/null
+++ b/sys/arch/sgi/localbus/intvar.h
@@ -0,0 +1,34 @@
+/* $OpenBSD: intvar.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: int2var.h,v 1.3 2008/08/23 17:25:54 tsutsui Exp $ */
+
+/*
+ * Copyright (c) 2004 Christopher SEKIYA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+void *int2_intr_establish(int, int, int (*)(void *),
+ void *, const char *);
+
+void int2_wait_fifo(uint32_t);
diff --git a/sys/arch/sgi/sgi/autoconf.c b/sys/arch/sgi/sgi/autoconf.c
index 6416fa757d7..0c18a9b1e0a 100644
--- a/sys/arch/sgi/sgi/autoconf.c
+++ b/sys/arch/sgi/sgi/autoconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: autoconf.c,v 1.33 2011/05/30 22:25:22 oga Exp $ */
+/* $OpenBSD: autoconf.c,v 1.34 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 2009, 2010 Miodrag Vallat.
*
@@ -238,7 +238,8 @@ device_register(struct device *dev, void *aux)
(*_device_register)(dev, aux);
}
-#if defined(TGT_O2) || defined(TGT_OCTANE)
+#if defined(TGT_INDIGO) || defined(TGT_INDY) || defined(TGT_INDIGO2) || \
+ defined(TGT_O2) || defined(TGT_OCTANE)
/*
* ARCS boot path traversal
@@ -324,6 +325,7 @@ arcs_device_register(struct device *dev, void *aux)
{
static struct device *lastparent = NULL;
static struct device *pciparent = NULL;
+ static struct device *wdscparent = NULL;
static int component_pos = 0;
struct device *parent = dev->dv_parent;
@@ -409,22 +411,45 @@ arcs_device_register(struct device *dev, void *aux)
if (parent == lastparent)
goto found_advance;
+ if (component_pos == 0)
+ switch (sys_config.system_type) {
#ifdef TGT_O2
/*
* On O2, the pci(0) component may be omitted from
* the bootpath, in which case we fake the missing
* pci(0) component.
*/
- if (sys_config.system_type == SGI_O2 &&
- component_pos == 0) {
+ case SGI_O2:
if (parent->dv_parent != NULL &&
strcmp(parent->dv_parent->dv_cfdata->cf_driver->cd_name,
"pci") == 0) {
pciparent = parent->dv_parent;
goto found_advance;
}
- }
+ break;
#endif
+#if defined(TGT_INDIGO) || defined(TGT_INDY) || defined(TGT_INDIGO2)
+ /*
+ * On Ind{igo,y,i^2} systems, the bootpath
+ * starts at scsi().
+ */
+ case SGI_IP20:
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ if (strcmp(parent->dv_cfdata->cf_driver->cd_name,
+ "wdsc") == 0 &&
+ parent->dv_parent != NULL &&
+ strcmp(parent->dv_parent->dv_cfdata->cf_driver->cd_name,
+ "hpc") == 0) {
+ wdscparent = parent;
+ goto found_advance;
+ }
+ break;
+#endif
+ default:
+ break;
+ }
}
if (parent == lastparent) {
@@ -434,6 +459,12 @@ arcs_device_register(struct device *dev, void *aux)
if (unit == paa->pa_device -
(sys_config.system_type == SGI_O2 ? 1 : 0))
goto found;
+ } else
+ if (parent == wdscparent) {
+ /* XXX is there any better information to use
+ XXX than the attachment number? */
+ if (unit == parent->dv_unit)
+ goto found;
}
/*
* in case scsi() can follow something else then
@@ -473,7 +504,7 @@ found:
lastparent = dev;
}
-#endif /* defined(TGT_O2) || defined(TGT_OCTANE) */
+#endif /* IP20/22/24/26/28/30/32 */
#ifdef TGT_ORIGIN
@@ -647,7 +678,7 @@ dksc_device_register(struct device *dev, void *aux)
}
}
-#endif
+#endif /* IP27/35 */
struct nam2blk nam2blk[] = {
{ "sd", 0 },
diff --git a/sys/arch/sgi/sgi/conf.c b/sys/arch/sgi/sgi/conf.c
index 9a229de9161..0da5395e126 100644
--- a/sys/arch/sgi/sgi/conf.c
+++ b/sys/arch/sgi/sgi/conf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.c,v 1.29 2011/10/06 20:49:28 deraadt Exp $ */
+/* $OpenBSD: conf.c,v 1.30 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -97,6 +97,8 @@ cdev_decl(fd);
#include "tun.h"
#include "com.h"
cdev_decl(com);
+#include "zs.h"
+cdev_decl(zs);
#include "lpt.h"
cdev_decl(lpt);
#include "ch.h"
@@ -154,7 +156,7 @@ struct cdevsw cdevsw[] =
cdev_lpt_init(NLPT,lpt), /* 16: Parallel printer interface */
cdev_tty_init(NCOM,com), /* 17: 16C450 serial interface */
cdev_disk_init(NWD,wd), /* 18: ST506/ESDI/IDE disk */
- cdev_notdef(), /* 19: */
+ cdev_tty_init(NZS,zs), /* 19: Z8530 serial interface */
cdev_notdef(), /* 20: */
cdev_notdef(), /* 21: */
cdev_disk_init(NRD,rd), /* 22: ramdisk device */
@@ -294,8 +296,9 @@ int nchrtoblktbl = nitems(chrtoblktbl);
#include <dev/cons.h>
-cons_decl(ws);
cons_decl(com);
+cons_decl(ws);
+cons_decl(zs);
struct consdev constab[] = {
#if NWSDISPLAY > 0
@@ -304,5 +307,8 @@ struct consdev constab[] = {
#if NCOM > 0
cons_init(com),
#endif
+#if NZS > 0
+ cons_init(zs),
+#endif
{ 0 },
};
diff --git a/sys/arch/sgi/sgi/ip22.h b/sys/arch/sgi/sgi/ip22.h
new file mode 100644
index 00000000000..9fd00054f77
--- /dev/null
+++ b/sys/arch/sgi/sgi/ip22.h
@@ -0,0 +1,32 @@
+/* $OpenBSD: ip22.h,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+
+/*
+ * Copyright (c) 2012 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * IP20/IP22/IP24 definitions
+ */
+
+/* IP22 system types */
+
+#define IP22_INDY 0 /* Indy, Challenge S */
+#define IP22_INDIGO2 1 /* Indigo 2 */
+
+/* Interrupt handling priority */
+
+#define INTPRI_BUSERR (INTPRI_CLOCK + 1)
+#define INTPRI_L1 (INTPRI_BUSERR + 1)
+#define INTPRI_L0 (INTPRI_L1 + 1)
diff --git a/sys/arch/sgi/sgi/ip22_machdep.c b/sys/arch/sgi/sgi/ip22_machdep.c
new file mode 100644
index 00000000000..dbe7ccbd330
--- /dev/null
+++ b/sys/arch/sgi/sgi/ip22_machdep.c
@@ -0,0 +1,277 @@
+/* $OpenBSD: ip22_machdep.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+
+/*
+ * Copyright (c) 2012 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/autoconf.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/memconf.h>
+
+#include <mips64/arcbios.h>
+#include <mips64/archtype.h>
+
+#include <sgi/sgi/ip22.h>
+#include <sgi/localbus/imcreg.h>
+#include <sgi/localbus/imcvar.h>
+#include <sgi/hpc/hpcreg.h>
+#include <sgi/hpc/iocreg.h>
+
+extern char *hw_prod;
+
+void ip22_arcbios_walk(void);
+int ip22_arcbios_walk_component(arc_config_t *);
+void ip22_memory_setup(void);
+
+/*
+ * Walk the ARCBios component tree to get L2 cache information.
+ * This is the only way we can get the L2 cache size.
+ */
+
+int
+ip22_arcbios_walk_component(arc_config_t *cf)
+{
+ struct cpu_info *ci = curcpu();
+ arc_config_t *child;
+
+ /*
+ * Split secondary caches are not supported.
+ * No IP22 processor module uses them anyway.
+ */
+ if (cf->class == arc_CacheClass && cf->type == arc_SecondaryCache) {
+ /*
+ * Secondary cache information is encoded as WWLLSSSS, where
+ * WW is the number of ways (should be 01)
+ * LL is Log2(line size) (should be 04 or 05)
+ * SS is Log2(cache size in 4KB units) (should be 0007)
+ */
+ ci->ci_l2size = (1 << 12) << (cf->key & 0x0000ffff);
+ /* L2 line size */
+ ci->ci_cacheconfiguration = 1 << ((cf->key >> 16) & 0xff);
+ return 0; /* abort walk */
+ }
+
+ /*
+ * It is safe to assume we have a 32-bit ARCBios, until
+ * IP26 and IP28 support is added, hence unconditional
+ * use of arc_config_t.
+ */
+ for (child = (arc_config_t *)Bios_GetChild(cf); child != NULL;
+ child = (arc_config_t *)Bios_GetPeer(child)) {
+ if (ip22_arcbios_walk_component(child) == 0)
+ return 0;
+ }
+
+ return 1; /* continue walk */
+}
+
+void
+ip22_arcbios_walk()
+{
+ (void)ip22_arcbios_walk_component((arc_config_t *)Bios_GetChild(NULL));
+}
+
+#define IMC_NREGION 3
+
+void
+ip22_memory_setup()
+{
+ uint i, bank, shift;
+ uint32_t memc0, memc1;
+ uint32_t memc;
+ paddr_t base[IMC_NREGION], size[IMC_NREGION], limit;
+ paddr_t start0, end0, start1, end1;
+ struct phys_mem_desc *mem;
+
+ /*
+ * Figure out the top of memory, as reported by ARCBios.
+ */
+
+ limit = 0;
+ for (i = 0, mem = mem_layout; i < MAXMEMSEGS; i++, mem++) {
+ if (mem->mem_last_page > limit)
+ limit = mem->mem_last_page;
+ }
+ limit = ptoa(limit);
+
+ /*
+ * Figure out where the memory controller has put memory.
+ */
+
+ memc0 = imc_read(IMC_MEMCFG0);
+ memc1 = imc_read(IMC_MEMCFG1);
+
+ shift = IMC_MEMC_LSHIFT;
+ /* Revision D onwards uses larger units, to allow for more memory */
+ if ((imc_read(IMC_SYSID) & IMC_SYSID_REVMASK) >= 5)
+ shift = IMC_MEMC_LSHIFT_HUGE;
+
+ for (bank = 0; bank < IMC_NREGION; bank++) {
+ memc = (bank & 2) ? memc1 : memc0;
+ if ((bank & 1) == 0)
+ memc >>= IMC_MEMC_BANK_SHIFT;
+ memc &= IMC_MEMC_BANK_MASK;
+
+ if ((memc & IMC_MEMC_VALID) == 0) {
+ base[bank] = size[bank] = 0;
+ continue;
+ }
+
+ base[bank] = (memc & IMC_MEMC_ADDR_MASK) >> IMC_MEMC_ADDR_SHIFT;
+ base[bank] <<= shift;
+
+ size[bank] = (memc & IMC_MEMC_SIZE_MASK) >> IMC_MEMC_SIZE_SHIFT;
+ size[bank]++;
+ size[bank] <<= shift;
+ }
+
+ /*
+ * Perform sanity checks on the above data..
+ */
+
+ /* memory should not start below 128MB */
+ for (bank = 0; bank < IMC_NREGION; bank++)
+ if (size[bank] != 0 && base[bank] < (1ULL << 27))
+ goto dopanic;
+
+ /* banks should not overlap */
+ for (bank = 1; bank < IMC_NREGION; bank++) {
+ if (size[bank] == 0)
+ continue;
+ start0 = base[bank];
+ end0 = base[bank] + size[bank];
+ for (i = 0; i < bank; i++) {
+ if (size[i] == 0)
+ continue;
+ start1 = base[i];
+ end1 = base[i] + size[i];
+ if (end0 > start1 && start0 < end1)
+ goto dopanic;
+ }
+ }
+
+ /*
+ * Now register all the memory beyond what ARCBios stopped at.
+ */
+
+ for (bank = 0; bank < IMC_NREGION; bank++) {
+ if (size[bank] == 0)
+ continue;
+
+ start0 = base[bank];
+ end0 = base[bank] + size[bank];
+ if (end0 <= limit)
+ continue;
+
+ if (start0 < limit)
+ start0 = limit;
+
+ memrange_register(atop(start0), atop(end0), 0);
+ }
+
+ return;
+
+dopanic:
+ bios_printf("** UNEXPECTED MEMORY CONFIGURATION **\n");
+ bios_printf("MEMC0 %08x MEMC1 %08x\n", memc0, memc1);
+ bios_printf("Please contact <sgi@openbsd.org>\n"
+ "Halting system.\n");
+ Bios_Halt();
+ for (;;) ;
+}
+
+void
+ip22_setup()
+{
+ u_long cpuspeed;
+ volatile uint32_t *sysid;
+
+ /*
+ * Get CPU information.
+ */
+ bootcpu_hwinfo.c0prid = cp0_get_prid();
+ bootcpu_hwinfo.c1prid = cp1_get_prid();
+ cpuspeed = bios_getenvint("cpufreq");
+ if (sys_config.system_type == SGI_IP20)
+ cpuspeed <<= 1;
+ if (cpuspeed < 100)
+ cpuspeed = 100; /* reasonable default */
+ bootcpu_hwinfo.clock = cpuspeed * 1000000;
+ bootcpu_hwinfo.type = (bootcpu_hwinfo.c0prid >> 8) & 0xff;
+
+ /*
+ * Figure out what critter we are running on.
+ */
+ switch (sys_config.system_type) {
+ case SGI_IP20:
+ hw_prod = "Indigo";
+ break;
+ case SGI_IP22:
+ sysid = (volatile uint32_t *)
+ PHYS_TO_XKPHYS(HPC_BASE_ADDRESS_0 + IOC_BASE + IOC_SYSID,
+ CCA_NC);
+ if (*sysid & 0x01) {
+ sys_config.system_subtype = IP22_INDIGO2;
+ hw_prod = "Indigo2";
+ } else {
+ sys_config.system_subtype = IP22_INDY;
+ hw_prod = "Indy";
+ }
+ break;
+ case SGI_IP26:
+ sys_config.system_subtype = IP22_INDIGO2;
+ hw_prod = "POWER Indigo2 R8000";
+ break;
+ case SGI_IP28:
+ sys_config.system_subtype = IP22_INDIGO2;
+ hw_prod = "POWER Indigo2 R10000";
+ break;
+ }
+
+ /*
+ * Figure out how many TLB entries are available.
+ */
+ switch (bootcpu_hwinfo.type) {
+#ifdef CPU_R10000
+ case MIPS_R10000:
+ bootcpu_hwinfo.tlbsize = 64;
+ break;
+#endif
+ default: /* R4x00, R5000 */
+ bootcpu_hwinfo.tlbsize = 48;
+ break;
+ }
+
+ /*
+ * Compute memory layout. ARCBios may not report all memory (on
+ * Indigo, it seems to only report up to 128MB, and on Indigo2,
+ * up to 256MB).
+ */
+ ip22_memory_setup();
+
+ /*
+ * Scan ARCBios component list for L2 cache information.
+ */
+ ip22_arcbios_walk();
+
+ _device_register = arcs_device_register;
+}
diff --git a/sys/arch/sgi/sgi/ip30_machdep.c b/sys/arch/sgi/sgi/ip30_machdep.c
index 4a2d5dc02e2..c5077d31438 100644
--- a/sys/arch/sgi/sgi/ip30_machdep.c
+++ b/sys/arch/sgi/sgi/ip30_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip30_machdep.c,v 1.50 2012/03/25 13:52:52 miod Exp $ */
+/* $OpenBSD: ip30_machdep.c,v 1.51 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 2008, 2009 Miodrag Vallat.
@@ -168,9 +168,7 @@ ip30_setup()
comconsaddr = IOC3_UARTA_BASE;
comconsfreq = 22000000 / 3;
comconsiot = &sys_config.console_io;
- comconsrate = bios_getenvint("dbaud");
- if (comconsrate < 50 || comconsrate > 115200)
- comconsrate = 9600;
+ comconsrate = bios_consrate;
#ifdef DDB
/*
diff --git a/sys/arch/sgi/sgi/ip32_machdep.c b/sys/arch/sgi/sgi/ip32_machdep.c
index e3760cbd031..611f3f2d058 100644
--- a/sys/arch/sgi/sgi/ip32_machdep.c
+++ b/sys/arch/sgi/sgi/ip32_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip32_machdep.c,v 1.17 2012/03/15 18:57:22 miod Exp $ */
+/* $OpenBSD: ip32_machdep.c,v 1.18 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 2003-2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -198,9 +198,7 @@ ip32_setup()
comconsaddr = MACE_ISA_SER1_OFFS;
comconsfreq = 1843200;
comconsiot = &macebus_tag;
- comconsrate = bios_getenvint("dbaud");
- if (comconsrate < 50 || comconsrate > 115200)
- comconsrate = 9600;
+ comconsrate = bios_consrate;
}
/* not sure if there is a way to tell O2 and O2+ apart */
diff --git a/sys/arch/sgi/sgi/machdep.c b/sys/arch/sgi/sgi/machdep.c
index 0d4f8811c2a..52405982621 100644
--- a/sys/arch/sgi/sgi/machdep.c
+++ b/sys/arch/sgi/sgi/machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: machdep.c,v 1.114 2012/03/25 13:52:52 miod Exp $ */
+/* $OpenBSD: machdep.c,v 1.115 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 2003-2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -141,11 +141,11 @@ caddr_t
mips_init(int argc, void *argv, caddr_t boot_esym)
{
char *cp;
- int i;
+ int i, guessed;
u_int cputype;
vaddr_t xtlb_handler;
extern char start[], edata[], end[];
- extern char exception[], e_exception[];
+ extern char cache_err[], exception[], e_exception[];
extern char *hw_vendor;
#ifdef MULTIPROCESSOR
@@ -222,6 +222,34 @@ mips_init(int argc, void *argv, caddr_t boot_esym)
*/
hw_vendor = "SGI";
switch (sys_config.system_type) {
+#ifdef TGT_INDIGO
+ case SGI_IP20:
+ bios_printf("Found SGI-IP20, setting up.\n");
+ /* IP22 is intentional, we use the same kernel */
+ strlcpy(cpu_model, "IP22", sizeof(cpu_model));
+ ip22_setup();
+ break;
+#endif
+#if defined(TGT_INDY) || defined(TGT_INDIGO2)
+ case SGI_IP22:
+ bios_printf("Found SGI-IP22, setting up.\n");
+ strlcpy(cpu_model, "IP22", sizeof(cpu_model));
+ ip22_setup();
+ break;
+#endif
+#ifdef TGT_INDIGO2
+ case SGI_IP26:
+ bios_printf("Found SGI-IP26, setting up.\n");
+ /* IP28 is intentional, we will probably use the same kernel */
+ strlcpy(cpu_model, "IP28", sizeof(cpu_model));
+ ip22_setup();
+ break;
+ case SGI_IP28:
+ bios_printf("Found SGI-IP28, setting up.\n");
+ strlcpy(cpu_model, "IP28", sizeof(cpu_model));
+ ip22_setup();
+ break;
+#endif
#ifdef TGT_O2
case SGI_O2:
bios_printf("Found SGI-IP32, setting up.\n");
@@ -253,10 +281,14 @@ mips_init(int argc, void *argv, caddr_t boot_esym)
break;
#endif
default:
- bios_printf("Kernel doesn't support this system type!\n");
+ bios_printf("There is no support for this system type "
+ "(%02x) in this kernel.\n"
+ "Are you sure you have booted the right kernel "
+ "for this machine?\n",
+ sys_config.system_type);
bios_printf("Halting system.\n");
Bios_Halt();
- while(1);
+ for (;;) ;
}
/*
@@ -277,20 +309,16 @@ mips_init(int argc, void *argv, caddr_t boot_esym)
"The kernel might not be able to find out its root device.\n");
/*
- * Read platform-specific environment variables.
+ * Read platform-specific environment variables from ARCBios.
+ * (Note these may not exist on all systems)
*/
- switch (sys_config.system_type) {
-#ifdef TGT_O2
- case SGI_O2:
- /* Get Ethernet address from ARCBIOS. */
- cp = Bios_GetEnvironmentVariable("eaddr");
- if (cp != NULL && strlen(cp) > 0)
- strlcpy(bios_enaddr, cp, sizeof bios_enaddr);
- break;
-#endif
- default:
- break;
- }
+ /* onboard Ethernet address (does not exist on IP27/IP35) */
+ cp = Bios_GetEnvironmentVariable("eaddr");
+ if (cp != NULL && strlen(cp) > 0)
+ strlcpy(bios_enaddr, cp, sizeof bios_enaddr);
+ bios_consrate = bios_getenvint("dbaud");
+ if (bios_consrate < 50 || bios_consrate > 115200)
+ bios_consrate = 9600; /* sane default */
/*
* Set pagesize to enable use of page macros and functions.
@@ -345,6 +373,7 @@ mips_init(int argc, void *argv, caddr_t boot_esym)
/*
* Configure cache.
*/
+ guessed = 0;
switch (bootcpu_hwinfo.type) {
#ifdef CPU_R10000
case MIPS_R10000:
@@ -353,6 +382,16 @@ mips_init(int argc, void *argv, caddr_t boot_esym)
cputype = MIPS_R10000;
break;
#endif
+#ifdef CPU_R4000
+ case MIPS_R4000:
+ cputype = MIPS_R4000;
+ break;
+#endif
+#ifdef CPU_R4600
+ case MIPS_R4600:
+ cputype = MIPS_R5000;
+ break;
+#endif
#ifdef CPU_R5000
case MIPS_R5000:
case MIPS_RM52X0:
@@ -369,24 +408,52 @@ mips_init(int argc, void *argv, caddr_t boot_esym)
/*
* If we can't identify the cpu type, it must be
* r10k-compatible on Octane and Origin families, and
- * it is likely to be r5k-compatible on O2.
+ * it is likely to be r5k-compatible on O2 and
+ * r4k-compatible on Ind{igo*,y}.
*/
+ guessed = 1;
switch (sys_config.system_type) {
+ case SGI_IP20:
+ case SGI_IP22:
+ bios_printf("Unrecognized processor type, assuming"
+ " R4000 compatible\n");
+ cputype = MIPS_R4000;
+ break;
case SGI_O2:
+ bios_printf("Unrecognized processor type, assuming"
+ " R5000 compatible\n");
cputype = MIPS_R5000;
break;
+ case SGI_IP26:
+ bios_printf("Unrecognized processor type, assuming"
+ " R8000 compatible\n");
+ cputype = MIPS_R8000;
+ break;
default:
- case SGI_OCTANE:
case SGI_IP27:
+ case SGI_IP28:
+ case SGI_OCTANE:
case SGI_IP35:
+ bios_printf("Unrecognized processor type, assuming"
+ " R10000 compatible\n");
cputype = MIPS_R10000;
break;
}
break;
}
switch (cputype) {
- default:
-#if defined(CPU_R5000) || defined(CPU_RM7000)
+#ifdef CPU_R4000
+ case MIPS_R4000:
+ Mips4k_ConfigCache(curcpu());
+ sys_config._SyncCache = Mips4k_SyncCache;
+ sys_config._InvalidateICache = Mips4k_InvalidateICache;
+ sys_config._SyncDCachePage = Mips4k_SyncDCachePage;
+ sys_config._HitSyncDCache = Mips4k_HitSyncDCache;
+ sys_config._IOSyncDCache = Mips4k_IOSyncDCache;
+ sys_config._HitInvalidateDCache = Mips4k_HitInvalidateDCache;
+ break;
+#endif
+#if defined(CPU_R4600) || defined(CPU_R5000) || defined(CPU_RM7000)
case MIPS_R5000:
Mips5k_ConfigCache(curcpu());
sys_config._SyncCache = Mips5k_SyncCache;
@@ -408,6 +475,20 @@ mips_init(int argc, void *argv, caddr_t boot_esym)
sys_config._HitInvalidateDCache = Mips10k_HitInvalidateDCache;
break;
#endif
+ default:
+ if (guessed) {
+ bios_printf("There is no support for this processor "
+ "family in this kernel.\n"
+ "Are you sure you have booted the right kernel "
+ "for this machine?\n");
+ } else {
+ bios_printf("There is no support for this processor "
+ "family (%02x) in this kernel.\n", cputype);
+ }
+ bios_printf("Halting system.\n");
+ Bios_Halt();
+ for (;;) ;
+ break;
}
/*
@@ -449,13 +530,21 @@ mips_init(int argc, void *argv, caddr_t boot_esym)
/*
* Copy down exception vector code.
*/
- bcopy(exception, (char *)CACHE_ERR_EXC_VEC, e_exception - exception);
+ bcopy(exception, (char *)CACHE_ERR_EXC_VEC, e_exception - cache_err);
bcopy(exception, (char *)GEN_EXC_VEC, e_exception - exception);
/*
* Build proper TLB refill handler trampolines.
*/
switch (cputype) {
+#ifdef CPU_R4000
+ case MIPS_R4000:
+ {
+ extern void xtlb_miss_err_r4k;
+ xtlb_handler = (vaddr_t)&xtlb_miss_err_r4k;
+ }
+ break;
+#endif
#if defined(CPU_R5000) || defined(CPU_RM7000)
case MIPS_R5000:
{
@@ -744,9 +833,17 @@ arcbios_halt(int howto)
#endif
if (howto & RB_HALT) {
- if (howto & RB_POWERDOWN)
+ if (howto & RB_POWERDOWN) {
+#ifdef TGT_INDY
+ /*
+ * ARCBios needs to use the FPU on Indy during
+ * shutdown.
+ */
+ if (sys_config.system_type == SGI_IP22)
+ setsr(getsr() | SR_COP_1_BIT);
+#endif
Bios_PowerDown();
- else
+ } else
Bios_EnterInteractiveMode();
} else
Bios_Reboot();
diff --git a/sys/arch/sgi/sgi/mainbus.c b/sys/arch/sgi/sgi/mainbus.c
index 5d8e411d0d1..018bbd372a4 100644
--- a/sys/arch/sgi/sgi/mainbus.c
+++ b/sys/arch/sgi/sgi/mainbus.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mainbus.c,v 1.8 2010/01/09 20:33:16 miod Exp $ */
+/* $OpenBSD: mainbus.c,v 1.9 2012/03/28 20:44:23 miod Exp $ */
/*
* Copyright (c) 2001-2003 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -89,9 +89,9 @@ mbattach(struct device *parent, struct device *self, void *aux)
}
/*
- * On other systems, attach the CPU we are running on early;
- * other processors, if any, will get attached as they are
- * discovered.
+ * On other systems, attach the CPU, its clock, and the
+ * mainbus here.
+ * XXX Would be worth doing as ipXX_autoconf() too.
*/
bzero(&caa, sizeof caa);
@@ -103,6 +103,19 @@ mbattach(struct device *parent, struct device *self, void *aux)
config_found(self, &caa.caa_maa, mbprint);
switch (sys_config.system_type) {
+#if defined(TGT_INDIGO) || defined(TGT_INDY) || defined(TGT_INDIGO2)
+ case SGI_IP20:
+ case SGI_IP22:
+ case SGI_IP26:
+ case SGI_IP28:
+ /* Interrupt Controller */
+ caa.caa_maa.maa_name = "int";
+ config_found(self, &caa.caa_maa, mbprint);
+ /* Memory Controller */
+ caa.caa_maa.maa_name = "imc";
+ config_found(self, &caa.caa_maa, mbprint);
+ break;
+#endif
#ifdef TGT_O2
case SGI_O2:
caa.caa_maa.maa_name = "macebus";
diff --git a/sys/arch/sgi/stand/Makefile b/sys/arch/sgi/stand/Makefile
index 62a19908f9c..d18503c5228 100644
--- a/sys/arch/sgi/stand/Makefile
+++ b/sys/arch/sgi/stand/Makefile
@@ -1,11 +1,10 @@
-# $OpenBSD: Makefile,v 1.7 2012/03/19 17:38:29 miod Exp $
+# $OpenBSD: Makefile,v 1.8 2012/03/28 20:44:23 miod Exp $
SUBDIR= sgivol
.if ${MACHINE} == "sgi"
SUBDIR+= libsa libsa32 libz libz32
-SUBDIR+= boot64 boot32
-#SUBDIR+= bootecoff
+SUBDIR+= boot64 boot32 bootecoff
.endif
.include <bsd.subdir.mk>