summaryrefslogtreecommitdiff
path: root/sys/arch/sgi/localbus
diff options
context:
space:
mode:
authorPer Fogelstrom <pefo@cvs.openbsd.org>2004-08-06 21:12:20 +0000
committerPer Fogelstrom <pefo@cvs.openbsd.org>2004-08-06 21:12:20 +0000
commit925b1250f6b872a48c9a2aa6bc2f6177da057b1a (patch)
treee6e77d6b0c34da676f47a343a20fd219381b233c /sys/arch/sgi/localbus
parentc15733015711563a770a7a71ad99d8158fc36663 (diff)
initial sgi import
Diffstat (limited to 'sys/arch/sgi/localbus')
-rw-r--r--sys/arch/sgi/localbus/com_lbus.c135
-rw-r--r--sys/arch/sgi/localbus/crimebus.h77
-rw-r--r--sys/arch/sgi/localbus/macebus.c782
-rw-r--r--sys/arch/sgi/localbus/macebus.h120
-rw-r--r--sys/arch/sgi/localbus/macectrl.S55
5 files changed, 1169 insertions, 0 deletions
diff --git a/sys/arch/sgi/localbus/com_lbus.c b/sys/arch/sgi/localbus/com_lbus.c
new file mode 100644
index 00000000000..3e45d1f8ec2
--- /dev/null
+++ b/sys/arch/sgi/localbus/com_lbus.c
@@ -0,0 +1,135 @@
+/* $OpenBSD: com_lbus.c,v 1.1 2004/08/06 21:12:19 pefo Exp $ */
+
+/*
+ * Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
+ *
+ * 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 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 <sys/tty.h>
+
+#include <machine/autoconf.h>
+#include <mips64/archtype.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/ic/comreg.h>
+#include <dev/ic/comvar.h>
+#include <dev/ic/ns16550reg.h>
+
+int com_localbus_probe(struct device *, void *, void *);
+void com_localbus_attach(struct device *, struct device *, void *);
+
+
+struct cfattach com_localbus_ca = {
+ sizeof(struct com_softc), com_localbus_probe, com_localbus_attach
+};
+
+extern void com_raisedtr(void *);
+extern struct timeout compoll_to;
+
+int
+com_localbus_probe(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ int iobase;
+ int rv;
+ struct cfdata *cf = match;
+ struct confargs *ca = aux;
+
+ /*
+ * Check if this is our com. If low nibble is 0 match
+ * against system CLASS. Else a perfect match is checked.
+ */
+ if ((ca->ca_sys & 0x000f) == 0) {
+ if (ca->ca_sys != (sys_config.system_type & 0xfff0))
+ return 0;
+ } else if (ca->ca_sys != sys_config.system_type) {
+ return 0;
+ }
+
+ iobase = (bus_addr_t)sys_config.cons_ioaddr[cf->cf_unit];
+ if(iobase == 0) {
+ rv = 0; /* Not present */
+ }
+ else {
+ iot = sys_config.cons_iot;
+ /* if it's in use as console, it's there. */
+ if (!(iobase == comconsaddr && !comconsattached)) {
+ bus_space_map(iot, iobase, COM_NPORTS, 0, &ioh);
+ rv = comprobe1(iot, ioh);
+ }
+ else {
+ rv = 1;
+ }
+ }
+ return (rv);
+}
+
+void
+com_localbus_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct com_softc *sc = (void *)self;
+ int iobase, intr;
+ bus_space_handle_t ioh;
+ struct confargs *ca = aux;
+
+ sc->sc_hwflags = 0;
+ sc->sc_swflags = 0;
+ iobase = (bus_addr_t)sys_config.cons_ioaddr[sc->sc_dev.dv_unit];
+ intr = ca->ca_intr;
+ sc->sc_iobase = iobase;
+ sc->sc_frequency = sys_config.cons_baudclk;
+
+ sc->sc_iot = sys_config.cons_iot;
+
+ /* if it's in use as console, it's there. */
+ if (!(iobase == comconsaddr && !comconsattached)) {
+ if (bus_space_map(sc->sc_iot, iobase, COM_NPORTS, 0, &ioh)) {
+ panic("unexpected bus_space_map failure");
+ }
+ }
+ else {
+ ioh = comconsioh;
+ }
+
+ sc->sc_ioh = ioh;
+
+ com_attach_subr(sc);
+
+ /* Enable IE pin. Some boards are not edge sensitive */
+ SET(sc->sc_mcr, MCR_IENABLE);
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, com_mcr, sc->sc_mcr);
+
+ BUS_INTR_ESTABLISH(ca, NULL, intr, IST_EDGE, IPL_TTY,
+ comintr, (void *)sc, sc->sc_dev.dv_xname);
+
+}
diff --git a/sys/arch/sgi/localbus/crimebus.h b/sys/arch/sgi/localbus/crimebus.h
new file mode 100644
index 00000000000..ca4fabd0167
--- /dev/null
+++ b/sys/arch/sgi/localbus/crimebus.h
@@ -0,0 +1,77 @@
+/* $OpenBSD*/
+
+/*
+ * Copyright (c) 2003-2004 Opsycon AB (www.opsycon.se).
+ *
+ * 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 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.
+ *
+ */
+
+#ifndef _CRIMEBUS_H_
+#define _CRIMEBUS_H_
+
+#include <machine/bus.h>
+
+#define CRIMEBUS_BASE 0x14000000
+
+#define CRIME_REVISION 0x0000
+
+#define CRIME_CONTROL 0x0008
+#define CRIME_CTRL_TRITON_SYSADC 0x2000
+#define CRIME_CTRL_CRIME_SYSADC 0x1000
+#define CRIME_CTRL_HARD_RESET 0x0800
+#define CRIME_CTRL_SOFT_RESET 0x0400
+#define CRIME_CTRL_DOG_ENABLE 0x0200
+#define CRIME_CTRL_ENDIAN_BIG 0x0100
+
+#define CRIME_INT_STAT 0x0010
+#define CRIME_INT_MASK 0x0018
+#define CRIME_INT_SOFT 0x0020
+#define CRIME_INT_HARD 0x0028
+
+#define CRIME_KICK_DOG 0x0030
+#define CRIME_TIMER 0x0038
+
+#define CRIME_CPU_ERROR_ADDR 0x0040
+#define CRIME_CPU_ERROR_STAT 0x0048
+#define CRIME_CPU_ERROR_ENAB 0x0050
+
+#define CRIME_MEM_ERROR_STAT 0x0250
+#define CRIME_MEM_ERROR_ADDR 0x0258
+
+extern bus_space_t crimebus_tag;
+
+u_int8_t crime_read_1(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+u_int16_t crime_read_2(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+u_int32_t crime_read_4(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+u_int64_t crime_read_8(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+
+void crime_write_1(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int8_t);
+void crime_write_2(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int16_t);
+void crime_write_4(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t);
+void crime_write_8(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int64_t);
+
+int crime_space_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, bus_space_handle_t *);
+void crime_space_unmap(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+int crime_space_region(bus_space_tag_t, bus_space_handle_t, bus_size_t, bus_size_t, bus_space_handle_t *);
+
+#endif /* _CRIMEBUS_H_ */
diff --git a/sys/arch/sgi/localbus/macebus.c b/sys/arch/sgi/localbus/macebus.c
new file mode 100644
index 00000000000..e2e6897c195
--- /dev/null
+++ b/sys/arch/sgi/localbus/macebus.c
@@ -0,0 +1,782 @@
+/* $OpenBSD: macebus.c,v 1.1 2004/08/06 21:12:19 pefo Exp $ */
+
+/*
+ * Copyright (c) 2000-2004 Opsycon AB (www.opsycon.se)
+ *
+ * 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 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.
+ *
+ */
+
+/*
+ * This is a combined macebus/crimebus driver. It handles
+ * configuration of all devices on the processor bus.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/tty.h>
+#include <sys/extent.h>
+#include <net/netisr.h>
+#include <uvm/uvm_extern.h>
+
+#include <dev/pci/pcidevs.h>
+#include <dev/pci/pcivar.h>
+
+#include <dev/ic/comvar.h>
+
+#include <mips64/archtype.h>
+
+#include <machine/autoconf.h>
+#include <machine/intr.h>
+
+#include <sgi/localbus/macebus.h>
+#include <sgi/localbus/crimebus.h>
+
+int macebusmatch(struct device *, void *, void *);
+void macebusattach(struct device *, struct device *, void *);
+int macebusprint(void *, const char *);
+int macebusscan(struct device *, void *, void *);
+
+void *macebus_intr_establish(void *, u_long, int, int,
+ int (*)(void *), void *, char *);
+void macebus_intr_disestablish(void *, void *);
+void macebus_intr_makemasks(void);
+void macebus_do_pending_int(void);
+intrmask_t macebus_iointr(intrmask_t, struct trap_frame *);
+intrmask_t macebus_aux(intrmask_t, struct trap_frame *);
+
+long mace_ext_storage[EXTENT_FIXED_STORAGE_SIZE(8) / sizeof (long)];
+long crime_ext_storage[EXTENT_FIXED_STORAGE_SIZE(8) / sizeof (long)];
+
+int maceticks; /* Time tracker for special events */
+
+struct cfattach macebus_ca = {
+ sizeof(struct device), macebusmatch, macebusattach
+};
+
+struct cfdriver macebus_cd = {
+ NULL, "macebus", DV_DULL, 1
+};
+
+bus_space_t macebus_tag = {
+ NULL,
+ (bus_addr_t)MACEBUS_BASE,
+ NULL,
+ 0,
+ mace_read_1, mace_write_1,
+ mace_read_2, mace_write_2,
+ mace_read_4, mace_write_4,
+ mace_read_8, mace_write_8,
+ mace_space_map, mace_space_unmap, mace_space_region,
+};
+
+bus_space_t crimebus_tag = {
+ NULL,
+ (bus_addr_t)CRIMEBUS_BASE,
+ NULL,
+ 0,
+ mace_read_1, mace_write_1,
+ mace_read_2, mace_write_2,
+ mace_read_4, mace_write_4,
+ mace_read_8, mace_write_8,
+ mace_space_map, mace_space_unmap, mace_space_region,
+};
+
+bus_space_handle_t crime_h;
+bus_space_handle_t mace_h;
+
+
+/*
+ * Match bus only to targets which have this bus.
+ */
+int
+macebusmatch(parent, match, aux)
+ struct device *parent;
+ void *match;
+ void *aux;
+{
+ if (sys_config.system_type == SGI_O2) {
+ return (1);
+ }
+ return(0);
+}
+
+int
+macebusprint(aux, macebus)
+ void *aux;
+ const char *macebus;
+{
+/* XXXX print flags */
+ return (QUIET);
+}
+
+
+int
+macebusscan(struct device *parent, void *child, void *args)
+{
+ struct device *dev = child;
+ struct cfdata *cf = dev->dv_cfdata;
+ struct confargs lba;
+ struct abus lbus;
+
+ if (cf->cf_fstate == FSTATE_STAR) {
+ printf("macebus '*' devs not allowed!\n");
+ return 0;
+ }
+
+ lba.ca_sys = cf->cf_loc[0];
+ if (cf->cf_loc[1] == -1) {
+ lba.ca_baseaddr = 0;
+ } else {
+ lba.ca_baseaddr = cf->cf_loc[1];
+ }
+ if (cf->cf_loc[2] == -1) {
+ lba.ca_intr = 0;
+ lba.ca_nintr = 0;
+ } else {
+ lba.ca_intr= cf->cf_loc[2];
+ lba.ca_nintr = 1;
+ }
+
+ lba.ca_bus = &lbus;
+
+ /* Fill in what is needed for probing */
+ lba.ca_bus->ab_type = BUS_LOCAL;
+ lba.ca_bus->ab_matchname = NULL;
+ lba.ca_name = cf->cf_driver->cd_name;
+ lba.ca_num = dev->dv_unit;
+ lba.ca_iot = &macebus_tag;
+ lba.ca_memt = &macebus_tag;
+
+ return (*cf->cf_attach->ca_match)(parent, cf, &lba);
+}
+
+void
+macebusattach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct device *dev;
+ struct confargs lba;
+ struct abus lbus;
+ u_int32_t creg;
+ u_int64_t mask;
+
+ /*
+ * Create an extent for the localbus control registers.
+ */
+ macebus_tag.bus_extent = extent_create("mace_space",
+ macebus_tag.bus_base, macebus_tag.bus_base + 0x00400000,
+ M_DEVBUF, (caddr_t)mace_ext_storage,
+ sizeof(mace_ext_storage), EX_NOCOALESCE|EX_NOWAIT);
+
+ crimebus_tag.bus_extent = extent_create("crime_space",
+ crimebus_tag.bus_base, crimebus_tag.bus_base + 0x00400000,
+ M_DEVBUF, (caddr_t)crime_ext_storage,
+ sizeof(crime_ext_storage), EX_NOCOALESCE|EX_NOWAIT);
+
+ /*
+ * Map and set up CRIME control registers.
+ */
+ if (bus_space_map(&crimebus_tag, 0x00000000, 0x400, 0, &crime_h)) {
+ printf("UH-OH! Can't map CRIME control registers!\n");
+ return;
+ }
+ hwmask_addr = (void *)(PHYS_TO_KSEG1(CRIMEBUS_BASE)+CRIME_INT_MASK);
+
+ creg = bus_space_read_8(&crimebus_tag, crime_h, CRIME_REVISION);
+ printf(" Crime revision %d.%d\n", (creg & 0xf0) >> 4, creg & 0xf);
+
+ bus_space_write_8(&crimebus_tag, crime_h, CRIME_CPU_ERROR_STAT, 0);
+ bus_space_write_8(&crimebus_tag, crime_h, CRIME_MEM_ERROR_STAT, 0);
+
+ mask = 0;
+ bus_space_write_8(&crimebus_tag, crime_h, CRIME_INT_MASK, mask);
+ bus_space_write_8(&crimebus_tag, crime_h, CRIME_INT_SOFT, 0);
+ bus_space_write_8(&crimebus_tag, crime_h, CRIME_INT_HARD, 0);
+ bus_space_write_8(&crimebus_tag, crime_h, CRIME_INT_STAT, 0);
+
+
+ /*
+ * Map and set up MACE ISA control registers.
+ */
+ if (bus_space_map(&macebus_tag, MACE_ISA_OFFS, 0x400, 0, &mace_h)) {
+ printf("UH-OH! Can't map MACE ISA control registers!\n");
+ return;
+ }
+
+ bus_space_write_8(&macebus_tag, mace_h, MACE_ISA_INT_MASK, 0xffffffff);
+ bus_space_write_8(&macebus_tag, mace_h, MACE_ISA_INT_STAT, 0);
+
+ /*
+ * Now attach all devices to macebus in proper order.
+ */
+ memset(&lba, 0, sizeof(lba));
+ memset(&lbus, 0, sizeof(lbus));
+ lba.ca_bus = &lbus;
+ lba.ca_bus->ab_type = BUS_LOCAL;
+ lba.ca_bus->ab_matchname = NULL;
+ lba.ca_iot = &macebus_tag;
+ lba.ca_memt = &macebus_tag;
+
+ /*
+ * On O2 systems all interrupts are handled by the
+ * macebus interrupt handler. Register all except clock.
+ */
+ switch(sys_config.system_type) {
+
+ case SGI_O2:
+ set_intr(INTPRI_MACEIO, CR_INT_0, macebus_iointr);
+ lba.ca_bus->ab_intr_establish = macebus_intr_establish;
+ lba.ca_bus->ab_intr_disestablish = macebus_intr_disestablish;
+ register_pending_int_handler(macebus_do_pending_int);
+ break;
+
+ default:
+ panic("macebusscan: unknown macebus type!");
+ }
+
+ /* DEBUG: Set up a handler called when clock interrupts go off. */
+ set_intr(INTPRI_MACEAUX, CR_INT_5, macebus_aux);
+
+
+ while ((dev = config_search(macebusscan, self, aux)) != NULL) {
+ struct cfdata *cf;
+
+ cf = dev->dv_cfdata;
+ lba.ca_sys = cf->cf_loc[0];
+ if (cf->cf_loc[1] == -1) {
+ lba.ca_baseaddr = 0;
+ } else {
+ lba.ca_baseaddr = cf->cf_loc[1];
+ }
+ if (cf->cf_loc[2] == -1) {
+ lba.ca_intr = 0;
+ lba.ca_nintr = 0;
+ } else {
+ lba.ca_intr= cf->cf_loc[2];
+ lba.ca_nintr = 1;
+ }
+ lba.ca_name = cf->cf_driver->cd_name;
+ lba.ca_num = dev->dv_unit;
+
+ config_attach(self, dev, &lba, macebusprint);
+ }
+}
+
+
+/*
+ * Bus access primitives. These are really ugly...
+ */
+
+u_int8_t
+mace_read_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
+{
+ return *(volatile u_int8_t *)(h + (o << 8) + 7);
+}
+
+u_int16_t
+mace_read_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
+{
+ panic("mace_read_2");
+}
+
+u_int32_t
+mace_read_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
+{
+ return *(volatile u_int32_t *)(h + o);
+}
+
+u_int64_t
+mace_read_8(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
+{
+ return lp32_read8((u_int64_t *)(h + o));
+}
+
+void
+mace_write_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, u_int8_t v)
+{
+ *(volatile u_int8_t *)(h + (o << 8) + 7) = v;
+}
+
+void
+mace_write_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, u_int16_t v)
+{
+ panic("mace_write_2");
+}
+
+void
+mace_write_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, u_int32_t v)
+{
+ *(volatile u_int32_t *)(h + o) = v;
+}
+
+void
+mace_write_8(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, u_int64_t v)
+{
+ lp32_write8((u_int64_t *)(h + o), v);
+}
+
+int
+mace_space_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size,
+ int cacheable, bus_space_handle_t *bshp)
+{
+ bus_addr_t bpa;
+ int error;
+
+ bpa = t->bus_base + offs;
+
+ /* Handle special mapping separately */
+ if ((bpa >= 0x1f380000 && (bpa+size) <= 0x1f3a0000) ) {
+ *bshp = PHYS_TO_KSEG1(bpa);
+ return 0;
+ }
+
+ if ((error = extent_alloc_region(t->bus_extent, bpa, size,
+ EX_NOWAIT | EX_MALLOCOK))) {
+ return error;
+ }
+
+ if ((error = bus_mem_add_mapping(bpa, size, cacheable, bshp))) {
+ if (extent_free(t->bus_extent, bpa, size, EX_NOWAIT |
+ ((phys_map != NULL) ? EX_MALLOCOK : 0))) {
+ printf("bus_space_map: pa %p, size %p\n", bpa, size);
+ printf("bus_space_map: can't free region\n");
+ }
+ }
+ return 0;
+}
+
+void
+mace_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size)
+{
+ bus_addr_t sva;
+ bus_size_t off, len;
+ bus_addr_t paddr;
+
+ /* should this verify that the proper size is freed? */
+ sva = trunc_page(bsh);
+ off = bsh - sva;
+ len = size+off;
+
+ paddr = KSEG1_TO_PHYS(bsh);
+ if (paddr >= 0x1f380000 && (paddr+size) <= 0x1f3a0000)
+ return;
+
+ if (pmap_extract(pmap_kernel(), bsh, (void *)&paddr) == 0) {
+ printf("bus_space_unmap: no pa for va %p\n", bsh);
+ return;
+ }
+
+ if (phys_map != NULL &&
+ ((sva >= VM_MIN_KERNEL_ADDRESS) && (sva < VM_MAX_KERNEL_ADDRESS))) {
+ /* do not free memory which was stolen from the vm system */
+ uvm_km_free(kernel_map, sva, len);
+ }
+
+ if (extent_free(t->bus_extent, paddr, size, EX_NOWAIT |
+ ((phys_map != NULL) ? EX_MALLOCOK : 0))) {
+ printf("bus_space_map: pa %p, size %p\n", paddr, size);
+ printf("bus_space_map: can't free region\n");
+ }
+}
+
+int
+mace_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);
+}
+
+/*
+ * Macebus interrupt handler driver.
+ */
+
+
+intrmask_t mace_intem = 0x0;
+static intrmask_t intrtype[INTMASKSIZE];
+static intrmask_t intrmask[INTMASKSIZE];
+static intrmask_t intrlevel[INTMASKSIZE];
+struct intrhand *intrhand[INTMASKSIZE];
+
+static int fakeintr __P((void *));
+static int fakeintr(void *a) {return 0;}
+
+/*
+ * Establish an interrupt handler called from the dispatcher.
+ * The interrupt function established should return zero if
+ * there was nothing to serve (no int) and non zero when an
+ * interrupt was serviced.
+ * Interrupts are numbered from 1 and up where 1 maps to HW int 0.
+ */
+void *
+macebus_intr_establish(icp, irq, type, level, ih_fun, ih_arg, ih_what)
+ void *icp;
+ u_long irq; /* XXX pci_intr_handle_t compatible XXX */
+ int type;
+ int level;
+ int (*ih_fun) __P((void *));
+ void *ih_arg;
+ char *ih_what;
+{
+ struct intrhand **p, *q, *ih;
+ static struct intrhand fakehand = {NULL, fakeintr};
+ int edge;
+extern int cold;
+
+static int initialized = 0;
+
+ if(!initialized) {
+/*INIT CODE HERE*/
+ initialized = 1;
+ }
+
+ if(irq > 62 || irq < 1) {
+ panic("intr_establish: illegal irq %d\n", irq);
+ }
+ irq -= 1; /* Adjust for 1 being first (0 is no int) */
+
+ /* no point in sleeping unless someone can free memory. */
+ ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
+ if (ih == NULL)
+ panic("intr_establish: can't malloc handler info");
+
+ if(type == IST_NONE || type == IST_PULSE)
+ panic("intr_establish: bogus type");
+
+ switch (intrtype[irq]) {
+ case IST_EDGE:
+ case IST_LEVEL:
+ if (type == intrtype[irq])
+ break;
+ }
+
+ switch (type) {
+ case IST_EDGE:
+ edge |= 1 << irq;
+ break;
+ case IST_LEVEL:
+ edge &= ~(1 << irq);
+ break;
+ }
+
+ /*
+ * Figure out where to put the handler.
+ * This is O(N^2), but we want to preserve the order, and N is
+ * generally small.
+ */
+ for (p = &intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
+ ;
+
+ /*
+ * Actually install a fake handler momentarily, since we might be doing
+ * this with interrupts enabled and don't want the real routine called
+ * until masking is set up.
+ */
+ fakehand.ih_level = level;
+ *p = &fakehand;
+
+ macebus_intr_makemasks();
+
+ /*
+ * Poke the real handler in now.
+ */
+ ih->ih_fun = ih_fun;
+ ih->ih_arg = ih_arg;
+ ih->ih_count = 0;
+ ih->ih_next = NULL;
+ ih->ih_level = level;
+ ih->ih_irq = irq;
+ ih->ih_what = ih_what;
+ *p = ih;
+
+ return (ih);
+}
+
+void
+macebus_intr_disestablish(void *p1, void *p2)
+{
+}
+
+/*
+ * Regenerate interrupt masks to reflect reality.
+ */
+void
+macebus_intr_makemasks()
+{
+ int irq, level;
+ struct intrhand *q;
+
+ /* First, figure out which levels each IRQ uses. */
+ for (irq = 0; irq < INTMASKSIZE; irq++) {
+ int levels = 0;
+ for (q = intrhand[irq]; q; q = q->ih_next)
+ levels |= 1 << q->ih_level;
+ intrlevel[irq] = levels;
+ }
+
+ /* Then figure out which IRQs use each level. */
+ for (level = 0; level < 5; level++) {
+ int irqs = 0;
+ for (irq = 0; irq < INTMASKSIZE; irq++)
+ if (intrlevel[irq] & (1 << level))
+ irqs |= 1 << irq;
+ imask[level] = irqs | SINT_ALLMASK;
+ }
+
+ /*
+ * There are tty, network and disk drivers that use free() at interrupt
+ * time, so imp > (tty | net | bio).
+ */
+ imask[IPL_VM] |= imask[IPL_TTY] | imask[IPL_NET] | imask[IPL_BIO];
+
+ /*
+ * Enforce a hierarchy that gives slow devices a better chance at not
+ * dropping data.
+ */
+ imask[IPL_TTY] |= imask[IPL_NET] | imask[IPL_BIO];
+ imask[IPL_NET] |= imask[IPL_BIO];
+
+ /*
+ * These are pseudo-levels.
+ */
+ imask[IPL_NONE] = 0;
+ imask[IPL_HIGH] = -1;
+
+ /* And eventually calculate the complete masks. */
+ for (irq = 0; irq < INTMASKSIZE; irq++) {
+ int irqs = 1 << irq;
+ for (q = intrhand[irq]; q; q = q->ih_next)
+ irqs |= imask[q->ih_level];
+ intrmask[irq] = irqs | SINT_ALLMASK;
+ }
+
+ /* Lastly, determine which IRQs are actually in use. */
+ irq = 0;
+ for (level = 0; level < INTMASKSIZE; level++) {
+ if (intrhand[level]) {
+ irq |= 1 << level;
+ }
+ }
+ mace_intem = irq & 0x0000ffff;
+ hw_setintrmask(0);
+}
+
+void
+macebus_do_pending_int()
+{
+ struct intrhand *ih;
+ int vector;
+ intrmask_t pcpl;
+ intrmask_t hwpend;
+ struct trap_frame cf;
+static volatile int processing;
+
+ /* Don't recurse... */
+ if (processing)
+ return;
+ processing = 1;
+
+/* XXX interrupt vulnerable when changing ipending */
+ pcpl = splhigh(); /* Turn off all */
+
+ /* XXX Fake a trapframe for clock pendings... */
+ cf.pc = (int)&macebus_do_pending_int;
+ cf.sr = 0;
+ cf.cpl = pcpl;
+
+ hwpend = ipending & ~pcpl; /* Do now unmasked pendings */
+ hwpend &= ~(SINT_ALLMASK);
+ ipending &= ~hwpend;
+ while (hwpend) {
+ vector = ffs(hwpend) - 1;
+ hwpend &= ~(1L << vector);
+ ih = intrhand[vector];
+ while (ih) {
+ ih->frame = &cf;
+ if((*ih->ih_fun)(ih->ih_arg)) {
+ ih->ih_count++;
+ }
+ ih = ih->ih_next;
+ }
+ }
+ if ((ipending & SINT_CLOCKMASK) & ~pcpl) {
+ ipending &= ~SINT_CLOCKMASK;
+ softclock();
+ }
+ if ((ipending & SINT_NETMASK) & ~pcpl) {
+ extern int netisr;
+ int isr = netisr;
+ netisr = 0;
+ ipending &= ~SINT_NETMASK;
+#ifdef INET
+#include "ether.h"
+ if (NETHER > 0 && isr & (1 << NETISR_ARP)) {
+ arpintr();
+ }
+
+ if (isr & (1 << NETISR_IP)) {
+ ipintr();
+ }
+#endif
+#ifdef INET6
+ if(isr & (1 << NETISR_IPV6)) {
+ ip6intr();
+ }
+#endif
+#ifdef NETATALK
+ if (isr & (1 << NETISR_ATALK)) {
+ atintr();
+ }
+#endif
+#ifdef IMP
+ if (isr & (1 << NETISR_IMP)) {
+ impintr();
+ }
+#endif
+#ifdef NS
+ if (isr & (1 << NETISR_NS)) {
+ nsintr();
+ }
+#endif
+#ifdef ISO
+ if (isr & (1 << NETISR_ISO)) {
+ clnlintr();
+ }
+#endif
+#ifdef CCITT
+ if (isr & (1 << NETISR_CCITT)) {
+ ccittintr();
+ }
+#endif
+#include "ppp.h"
+ if (NPPP > 0 && isr & (1 << NETISR_PPP)) {
+ pppintr();
+ }
+
+#include "bridge.h"
+ if (NBRIDGE > 0 && isr & (1 << NETISR_BRIDGE)) {
+ bridgeintr();
+ }
+ }
+
+#ifdef NOTYET
+ if ((ipending & SINT_TTYMASK) & ~pcpl) {
+ ipending &= ~SINT_TTYMASK;
+ compoll(NULL);
+ }
+#endif
+
+ cpl = pcpl; /* Don't use splx... we are here already! */
+ hw_setintrmask(pcpl);
+
+ processing = 0;
+}
+
+/*
+ * Process interrupts. The parameter pending has non-masked interrupts.
+ */
+intrmask_t
+macebus_iointr(intrmask_t hwpend, struct trap_frame *cf)
+{
+ struct intrhand *ih;
+ intrmask_t catched, vm;
+ int v;
+ intrmask_t pending;
+ u_int64_t intstat, isastat, mask;
+
+ intstat = bus_space_read_8(&crimebus_tag, crime_h, CRIME_INT_STAT);
+ intstat &= 0x0000ffff;
+ isastat = bus_space_read_8(&macebus_tag, mace_h, MACE_ISA_INT_STAT);
+ catched = 0;
+
+ /* Mask off masked interrupts and save them as pending */
+ if (intstat & cf->cpl) {
+ ipending |= intstat & cf->cpl;
+ mask = bus_space_read_8(&crimebus_tag, crime_h, CRIME_INT_MASK);
+ mask &= ~ipending;
+ bus_space_write_8(&crimebus_tag, crime_h, CRIME_INT_MASK, mask);
+ catched++;
+ }
+
+ /* Scan the first 16 for now */
+ pending = intstat & ~cf->cpl;
+
+ for (v = 0, vm = 1; pending != 0 && v < 16 ; v++, vm <<= 1) {
+ if (pending & vm) {
+ ih = intrhand[v];
+
+ while (ih) {
+ ih->frame = cf;
+ if ((*ih->ih_fun)(ih->ih_arg)) {
+ catched |= vm;
+ ih->ih_count++;
+ }
+ ih = ih->ih_next;
+ }
+ }
+ }
+ if (catched) {
+ return CR_INT_0;
+ }
+
+ return 0; /* Non found here */
+}
+
+
+/*
+ * Macebus auxilary functions run each clock interrupt.
+ */
+intrmask_t
+macebus_aux(intrmask_t hwpend, struct trap_frame *cf)
+{
+ u_int64_t mask;
+extern char idle[];
+extern char e_idle[];
+
+ mask = bus_space_read_8(&macebus_tag, mace_h, MACE_ISA_MISC_REG);
+ mask |= MACE_ISA_MISC_RLED_OFF | MACE_ISA_MISC_GLED_OFF;
+
+ /* GREEN - User mode */
+ /* AMBER - System mode */
+ /* RED - IDLE */
+ if (cf->sr & SR_KSU_USER) {
+ mask &= ~MACE_ISA_MISC_GLED_OFF;
+ } else if (cf->pc >= (long)idle && cf->pc < (long)e_idle) {
+ mask &= ~MACE_ISA_MISC_RLED_OFF;
+ } else {
+ mask &= ~(MACE_ISA_MISC_RLED_OFF | MACE_ISA_MISC_GLED_OFF);
+ }
+ bus_space_write_8(&macebus_tag, mace_h, MACE_ISA_MISC_REG, mask);
+
+ if (maceticks++ > 100*15) {
+ maceticks = 0;
+ }
+
+ return 0; /* Real clock int handler registers */
+}
diff --git a/sys/arch/sgi/localbus/macebus.h b/sys/arch/sgi/localbus/macebus.h
new file mode 100644
index 00000000000..d5a3438ebc3
--- /dev/null
+++ b/sys/arch/sgi/localbus/macebus.h
@@ -0,0 +1,120 @@
+/* $OpenBSD*/
+
+/*
+ * Copyright (c) 2003-2004 Opsycon AB (www.opsycon.com).
+ *
+ * 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 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.
+ *
+ */
+
+#ifndef _MACEBUS_H_
+#define _MACEBUS_H_ 1
+
+#include <machine/bus.h>
+
+/*
+ * Physical address of MACEBUS.
+ */
+#define MACEBUS_BASE 0x1f000000
+
+/*
+ * Offsets for various I/O sections on MACEBUS
+ */
+#define MACE_PCI_OFFS 0x00080000
+#define MACE_VIN1_OFFS 0x00100000
+#define MACE_VIN2_OFFS 0x00180000
+#define MACE_VOUT_OFFS 0x00200000
+#define MACE_IO_OFFS 0x00300000
+#define MACE_ISAX_OFFS 0x00380000
+
+/*
+ * PCI control registers (relative MACE_PCI_OFFS)
+ */
+#define MACE_PCI_ERROR_ADDRESS 0x0000
+#define MACE_PCI_ERROR_FLAGS 0x0004
+#define MACE_PCI_CONTROL 0x0008
+#define MACE_PCI_REVISION 0x000c
+#define MACE_PCI_FLUSH 0x000c
+#define MACE_PCI_CFGADDR 0x0cf8
+#define MACE_PCI_CFGDATA 0x0cfc
+
+#define MACE_PCI_INTCTRL 0x000000ff /* Interrupt control mask */
+
+/* PCI_ERROR_FLAGS Bits */
+#define PERR_MASTER_ABORT 0x80000000
+#define PERR_TARGET_ABORT 0x40000000
+#define PERR_DATA_PARITY_ERR 0x20000000
+#define PERR_RETRY_ERR 0x10000000
+#define PERR_ILLEGAL_CMD 0x08000000
+#define PERR_SYSTEM_ERR 0x04000000
+#define PERR_INTERRUPT_TEST 0x02000000
+#define PERR_PARITY_ERR 0x01000000
+#define PERR_OVERRUN 0x00800000
+#define PERR_RSVD 0x00400000
+#define PERR_MEMORY_ADDR 0x00200000
+#define PERR_CONFIG_ADDR 0x00100000
+#define PERR_MASTER_ABORT_ADDR_VALID 0x00080000
+#define PERR_TARGET_ABORT_ADDR_VALID 0x00040000
+#define PERR_DATA_PARITY_ADDR_VALID 0x00020000
+#define PERR_RETRY_ADDR_VALID 0x00010000
+
+
+/*
+ * MACE ISA definitions.
+ */
+#define MACE_ISA_OFFS (MACE_IO_OFFS+0x00010000)
+
+#define MACE_ISA_MISC_REG 0x0008 /* Various status and controls */
+#define MACE_ISA_INT_STAT 0x0010
+#define MACE_ISA_INT_MASK 0x0018
+
+/* MACE_ISA_MISC_REG definitions */
+#define MACE_ISA_MISC_RLED_OFF 0x0010 /* Turns off RED LED */
+#define MACE_ISA_MISC_GLED_OFF 0x0020 /* Turns off GREEN LED */
+
+
+/* ISA Periferials */
+#define MACE_ISA_EPP_OFFS (MACE_ISAX_OFFS+0x00000000)
+#define MACE_ISA_ECP_OFFS (MACE_ISAX_OFFS+0x00008000)
+#define MACE_ISA_SER1_OFFS (MACE_ISAX_OFFS+0x00010000)
+#define MACE_ISA_SER2_OFFS (MACE_ISAX_OFFS+0x00018000)
+#define MACE_ISA_RTC_OFFS (MACE_ISAX_OFFS+0x00020000)
+#define MACE_ISA_GAME_OFFS (MACE_ISAX_OFFS+0x00030000)
+
+
+extern bus_space_t macebus_tag;
+
+u_int8_t mace_read_1(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+u_int16_t mace_read_2(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+u_int32_t mace_read_4(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+u_int64_t mace_read_8(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+
+void mace_write_1(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int8_t);
+void mace_write_2(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int16_t);
+void mace_write_4(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t);
+void mace_write_8(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int64_t);
+
+int mace_space_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, bus_space_handle_t *);
+void mace_space_unmap(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+int mace_space_region(bus_space_tag_t, bus_space_handle_t, bus_size_t, bus_size_t, bus_space_handle_t *);
+
+#endif /* _MACEBUS_H_ */
diff --git a/sys/arch/sgi/localbus/macectrl.S b/sys/arch/sgi/localbus/macectrl.S
new file mode 100644
index 00000000000..879032928aa
--- /dev/null
+++ b/sys/arch/sgi/localbus/macectrl.S
@@ -0,0 +1,55 @@
+/* $OpenBSD: macectrl.S,v 1.1 2004/08/06 21:12:19 pefo Exp $ */
+
+/*
+ * Copyright (c) 2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
+ *
+ * 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 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 <machine/param.h>
+#include <machine/psl.h>
+#include <machine/asm.h>
+#include <machine/cpu.h>
+#include <machine/regnum.h>
+
+#include "assym.h"
+
+ .set mips3
+ .set noreorder # Noreorder is default style!
+
+ .globl hw_setintrmask
+LEAF(hw_setintrmask)
+ lw v0, mace_intem
+ PTR_L v1, hwmask_addr
+ nor a0, zero, a0
+ beqz v1, 1f # addr not set, skip.
+ and v0, a0
+ jr ra
+ sd v0, 0(v1)
+1:
+ jr ra
+ nop
+END(hw_setintrmask)
+
+ .data
+ .globl hwmask_addr
+hwmask_addr: .long 0