diff options
Diffstat (limited to 'sys/arch/sgi/localbus')
-rw-r--r-- | sys/arch/sgi/localbus/imc.c | 826 | ||||
-rw-r--r-- | sys/arch/sgi/localbus/imcreg.h | 143 | ||||
-rw-r--r-- | sys/arch/sgi/localbus/imcvar.h | 42 | ||||
-rw-r--r-- | sys/arch/sgi/localbus/int.c | 369 | ||||
-rw-r--r-- | sys/arch/sgi/localbus/intreg.h | 51 | ||||
-rw-r--r-- | sys/arch/sgi/localbus/intvar.h | 34 |
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); |