summaryrefslogtreecommitdiff
path: root/sys/arch/sgi/localbus
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/sgi/localbus')
-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
6 files changed, 1465 insertions, 0 deletions
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);