diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2009-04-12 17:56:59 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2009-04-12 17:56:59 +0000 |
commit | aa9adddfca7778c5667f7860a75baa5bb033974b (patch) | |
tree | 7dec8c6dffa27bc6479cb6a3e68ebadaff05e334 /sys | |
parent | 2829c2629cd9ab9ba5ca8dd4c7a45d3e3755098e (diff) |
Interrupt support for IOC3 and its subdevices (currently limited to the
SuperIO part, the Ethernet part needs a whole driver); kernel now boot
single user (or bsd.rd). Joint work with jsing@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/sgi/conf/files.sgi | 19 | ||||
-rw-r--r-- | sys/arch/sgi/dev/com_ioc.c | 8 | ||||
-rw-r--r-- | sys/arch/sgi/pci/ioc.c | 227 | ||||
-rw-r--r-- | sys/arch/sgi/pci/iocreg.h | 34 | ||||
-rw-r--r-- | sys/arch/sgi/pci/iocvar.h | 7 |
5 files changed, 265 insertions, 30 deletions
diff --git a/sys/arch/sgi/conf/files.sgi b/sys/arch/sgi/conf/files.sgi index 32b91e8b92c..edb7841f249 100644 --- a/sys/arch/sgi/conf/files.sgi +++ b/sys/arch/sgi/conf/files.sgi @@ -1,4 +1,4 @@ -# $OpenBSD: files.sgi,v 1.22 2008/04/07 22:36:26 miod Exp $ +# $OpenBSD: files.sgi,v 1.23 2009/04/12 17:56:56 miod Exp $ # # maxpartitions must be first item in files.${ARCH} # @@ -64,10 +64,10 @@ device xbow attach xbow at mainbus file arch/sgi/xbow/xbow.c xbow -include "dev/onewire/files.onewire" - include "arch/sgi/xbow/files.xbow" +include "dev/onewire/files.onewire" + # # PCI Bus bridges # @@ -86,7 +86,7 @@ include "dev/i2o/files.i2o" include "dev/pci/files.pci" # IOC3 -define ioc {[base = -1], [irq = -1]} +define ioc {[base = -1], [dev = -1]} device ioc: onewirebus attach ioc at pci file arch/sgi/pci/ioc.c ioc @@ -106,10 +106,20 @@ device gbe: wsemuldisplaydev, rasops8, rasops16, rasops32 attach gbe at mainbus file arch/sgi/dev/gbe.c gbe needs-flag +# Impact graphics +device impact: wsemuldisplaydev, rasops8, rasops16, rasops32 +attach impact at xbow +file arch/sgi/xbow/impact.c impact needs-flag + # 16[45]50-based "com" ports on localbus attach com at macebus with com_macebus file arch/sgi/localbus/com_lbus.c com_macebus +# IOC Ethernet +device ef: ether, ifnet, ifmedia, mii +attach ef at ioc +file arch/sgi/dev/if_ef.c ef + # MACE MAC-110 ethernet device mec: ether, ifnet, ifmedia, mii attach mec at macebus @@ -156,6 +166,7 @@ include "dev/usb/files.usb" device owmac attach owmac at onewire file arch/sgi/dev/owmac.c owmac + # Serial numbers device owserial attach owserial at onewire diff --git a/sys/arch/sgi/dev/com_ioc.c b/sys/arch/sgi/dev/com_ioc.c index 8381fe4e3ea..fdbd0743e74 100644 --- a/sys/arch/sgi/dev/com_ioc.c +++ b/sys/arch/sgi/dev/com_ioc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: com_ioc.c,v 1.3 2008/09/17 01:29:39 jsing Exp $ */ +/* $OpenBSD: com_ioc.c,v 1.4 2009/04/12 17:56:58 miod Exp $ */ /* * Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -106,8 +106,6 @@ com_ioc_attach(struct device *parent, struct device *self, void *aux) com_attach_subr(sc); -#ifdef notyet - ioc_intr_establish(NULL, iaa->iaa_intr, IST_EDGE, IPL_TTY, - comintr, (void *)sc, sc->sc_dev.dv_xname); -#endif + ioc_intr_establish(parent, iaa->iaa_dev, IPL_TTY, comintr, + (void *)sc, sc->sc_dev.dv_xname); } diff --git a/sys/arch/sgi/pci/ioc.c b/sys/arch/sgi/pci/ioc.c index b02d4abb9ea..e00a3bc59d0 100644 --- a/sys/arch/sgi/pci/ioc.c +++ b/sys/arch/sgi/pci/ioc.c @@ -1,8 +1,8 @@ -/* $OpenBSD: ioc.c,v 1.2 2009/03/29 21:53:52 sthen Exp $ */ +/* $OpenBSD: ioc.c,v 1.3 2009/04/12 17:56:58 miod Exp $ */ /* * Copyright (c) 2008 Joel Sing. - * Copyright (c) 2008 Miodrag Vallat. + * Copyright (c) 2008, 2009 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 @@ -41,6 +41,7 @@ #include <dev/onewire/onewirereg.h> #include <dev/onewire/onewirevar.h> +#include <sgi/dev/if_efreg.h> #include <sgi/dev/owmacvar.h> #include <sgi/xbow/xbow.h> @@ -51,6 +52,16 @@ int ioc_search_onewire(struct device *, void *, void *); int ioc_search_mundane(struct device *, void *, void *); int ioc_print(void *, const char *); +struct ioc_intr { + struct ioc_softc *ii_ioc; + + int (*ii_func)(void *); + void *ii_arg; + + struct evcount ii_count; + int ii_level; +}; + struct ioc_softc { struct device sc_dev; @@ -59,6 +70,11 @@ struct ioc_softc { bus_space_tag_t sc_memt; bus_space_handle_t sc_memh; bus_dma_tag_t sc_dmat; + pci_chipset_tag_t sc_pc; + + void *sc_sih; /* SuperIO interrupt */ + void *sc_eih; /* Ethernet interrupt */ + struct ioc_intr *sc_intr[IOC_NDEVS]; struct onewire_bus sc_bus; @@ -73,6 +89,10 @@ struct cfdriver ioc_cd = { NULL, "ioc", DV_DULL, }; +void ioc_intr_dispatch(struct ioc_softc *, int); +int ioc_intr_ethernet(void *); +int ioc_intr_superio(void *); + int iocow_reset(void *); int iocow_read_bit(struct ioc_softc *); int iocow_send_bit(void *, int); @@ -102,8 +122,8 @@ ioc_print(void *aux, const char *iocname) if (iaa->iaa_base != 0) printf(" base 0x%08x", iaa->iaa_base); - if (iaa->iaa_intr != 0) - printf(" irq %d", iaa->iaa_intr); + if (iaa->iaa_dev != 0) + printf(" dev %d", iaa->iaa_dev); return (UNCONF); } @@ -113,9 +133,12 @@ ioc_attach(struct device *parent, struct device *self, void *aux) { struct ioc_softc *sc = (struct ioc_softc *)self; struct pci_attach_args *pa = aux; + pci_intr_handle_t sih, eih; bus_space_tag_t memt; bus_space_handle_t memh; bus_size_t memsize; + uint32_t data; + int dev; if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_MEM, 0, &memt, &memh, NULL, &memsize, 0)) { @@ -123,9 +146,66 @@ ioc_attach(struct device *parent, struct device *self, void *aux) return; } + sc->sc_pc = pa->pa_pc; sc->sc_dmat = pa->pa_dmat; /* + * Initialise IOC3 ASIC. + */ + data = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); + data |= PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_PARITY_ENABLE | + PCI_COMMAND_SERR_ENABLE; + pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, data); + + /* + * IOC3 is not a real PCI device - it's a poor wrapper over a set + * of convenience chips. And it actually needs to use two interrupts, + * one for the superio chip, and the other for the Ethernet chip. + * + * Since our pci layer doesn't handle this, we cheat and compute + * the superio interrupt cookie ourselves. This is ugly, and + * depends on xbridge knowledge. + * + * (What the above means is that you should wear peril-sensitive + * sunglasses from now on). + * + * To make things ever worse, some IOC3 boards (real boards, not + * on-board components) lack the Ethernet component. We should + * eventually handle them there, but it's not worth doing yet... + * (and we'll need to parse the ownum serial numbers to know + * this anyway) + */ + + if (pci_intr_map(pa, &eih) != 0) { + printf(": failed to map interrupt!\n"); + goto unmap; + } + sih = eih + 2; /* XXX ACK GAG BARF */ + + /* + * Register the superio interrupt. + */ + sc->sc_sih = pci_intr_establish(sc->sc_pc, sih, IPL_TTY, + ioc_intr_superio, sc, self->dv_xname); + if (sc->sc_sih == NULL) { + printf(": failed to establish superio interrupt!\n"); + goto unmap; + } + + /* + * Register the ethernet interrupt. + */ + sc->sc_eih = pci_intr_establish(sc->sc_pc, eih, IPL_NET, + ioc_intr_ethernet, sc, self->dv_xname); + if (sc->sc_eih == NULL) { + printf(": failed to establish ethernet interrupt!\n"); + goto unregister; + } + + printf(": superio %s", pci_intr_string(sc->sc_pc, sih)); + printf(", ethernet %s", pci_intr_string(sc->sc_pc, eih)); + + /* * Build a suitable bus_space_handle by rebasing the xbridge * inherited one to our BAR, and restoring the original * non-swapped subword access methods. @@ -137,9 +217,8 @@ ioc_attach(struct device *parent, struct device *self, void *aux) sc->sc_mem_bus_space = malloc(sizeof (*sc->sc_mem_bus_space), M_DEVBUF, M_NOWAIT); if (sc->sc_mem_bus_space == NULL) { - bus_space_unmap(memt, memh, memsize); printf(": can't allocate bus_space\n"); - return; + goto unregister2; } bcopy(memt, sc->sc_mem_bus_space, sizeof(*sc->sc_mem_bus_space)); @@ -152,7 +231,17 @@ ioc_attach(struct device *parent, struct device *self, void *aux) sc->sc_memt = sc->sc_mem_bus_space; sc->sc_memh = memh; - printf("\n"); + /* Initialise interrupt handling structures. */ + for (dev = 0; dev < IOC_NDEVS; dev++) + sc->sc_intr[dev] = NULL; + + /* + * Acknowledge all pending interrupts, and disable them. + */ + bus_space_write_4(sc->sc_memt, sc->sc_memh, IOC3_SIO_IEC, ~0x0); + bus_space_write_4(sc->sc_memt, sc->sc_memh, IOC3_SIO_IES, 0x0); + bus_space_write_4(sc->sc_memt, sc->sc_memh, IOC3_SIO_IR, + bus_space_read_4(sc->sc_memt, sc->sc_memh, IOC3_SIO_IR)); /* * Attach the 1-Wire interface first, other sub-devices may @@ -164,6 +253,15 @@ ioc_attach(struct device *parent, struct device *self, void *aux) * Attach other sub-devices. */ config_search(ioc_search_mundane, self, aux); + + return; + +unregister2: + pci_intr_disestablish(sc->sc_pc, sc->sc_eih); +unregister: + pci_intr_disestablish(sc->sc_pc, sc->sc_sih); +unmap: + bus_space_unmap(memt, memh, memsize); } int @@ -185,9 +283,9 @@ ioc_search_mundane(struct device *parent, void *vcf, void *args) else iaa.iaa_base = cf->cf_loc[0]; if (cf->cf_loc[1] == -1) - iaa.iaa_intr = 0; + iaa.iaa_dev = 0; else - iaa.iaa_intr = cf->cf_loc[1]; + iaa.iaa_dev = cf->cf_loc[1]; if (sc->sc_owmac != NULL) memcpy(iaa.iaa_enaddr, sc->sc_owmac->sc_enaddr, 6); @@ -231,7 +329,7 @@ ioc_search_onewire(struct device *parent, void *vcf, void *args) oba.oba_bus = &sc->sc_bus; oba.oba_flags = ONEWIRE_SCAN_NOW | ONEWIRE_NO_PERIODIC_SCAN; - /* in case onewire is disabled in UKC */ + /* In case onewire is disabled in UKC... */ if ((*cf->cf_attach->ca_match)(parent, cf, &oba) == 0) return 0; @@ -333,3 +431,112 @@ iocow_pulse(struct ioc_softc *sc, int pulse, int data) return (mcr_value & 1); } + +/* + * Interrupt handling. + */ + +/* + * List of interrupt bits to enable for each device. + * + * We intentionnaly mask the RX high water bits, as they apparently never + * clear on some machines regardless of what we do. + */ +const uint32_t ioc_intrbits[IOC_NDEVS] = { + 0x000001ff & ~0x00000004, /* serial A */ + 0x0003fe00 & ~0x00000800, /* serial B */ + 0x003c0000, /* parallel port */ + 0x00400000, /* PS/2 port */ + 0x08000000, /* rtc */ + 0x00000000 /* Ethernet (handled differently) */ +}; + +void * +ioc_intr_establish(void *cookie, u_long dev, int level, int (*func)(void *), + void *arg, char *name) +{ + struct ioc_softc *sc = cookie; + struct ioc_intr *ii; + + dev--; + if (dev < 0 || dev >= IOC_NDEVS) + return NULL; + + ii = (struct ioc_intr *)malloc(sizeof(*ii), M_DEVBUF, M_NOWAIT); + if (ii == NULL) + return NULL; + + ii->ii_ioc = sc; + ii->ii_func = func; + ii->ii_arg = arg; + ii->ii_level = level; + + evcount_attach(&ii->ii_count, name, &ii->ii_level, &evcount_intr); + sc->sc_intr[dev] = ii; + + /* enable hardware source if necessary */ + bus_space_write_4(sc->sc_memt, sc->sc_memh, IOC3_SIO_IES, + ioc_intrbits[dev]); + + return (ii); +} + +int +ioc_intr_superio(void *v) +{ + struct ioc_softc *sc = (struct ioc_softc *)v; + uint32_t pending; + int dev; + + pending = bus_space_read_4(sc->sc_memt, sc->sc_memh, IOC3_SIO_IR) & + bus_space_read_4(sc->sc_memt, sc->sc_memh, IOC3_SIO_IES); + + if (pending == 0) + return 0; + + /* Disable pending interrupts */ + bus_space_write_4(sc->sc_memt, sc->sc_memh, IOC3_SIO_IEC, pending); + + for (dev = 0; dev < IOC_NDEVS - 1 /* skip Ethernet */; dev++) { + if (pending & ioc_intrbits[dev]) { + ioc_intr_dispatch(sc, dev); + + /* Ack, then reenable, pending interrupts */ + bus_space_write_4(sc->sc_memt, sc->sc_memh, + IOC3_SIO_IR, pending & ioc_intrbits[dev]); + bus_space_write_4(sc->sc_memt, sc->sc_memh, + IOC3_SIO_IES, pending & ioc_intrbits[dev]); + } + } + + return 1; +} + +int +ioc_intr_ethernet(void *v) +{ + struct ioc_softc *sc = (struct ioc_softc *)v; + uint32_t stat; + + stat = bus_space_read_4(sc->sc_memt, sc->sc_memh, EF_INTR_STATUS); + + if (stat == 0) + return 0; + + ioc_intr_dispatch(sc, IOCDEV_EF); + bus_space_write_4(sc->sc_memt, sc->sc_memh, EF_INTR_STATUS, stat); + + return 1; +} + +void +ioc_intr_dispatch(struct ioc_softc *sc, int dev) +{ + struct ioc_intr *ii; + + /* Call registered interrupt function. */ + if ((ii = sc->sc_intr[dev]) != NULL && ii->ii_func != NULL) { + if ((*ii->ii_func)(ii->ii_arg) != 0) + ii->ii_count.ec_count++; + } +} diff --git a/sys/arch/sgi/pci/iocreg.h b/sys/arch/sgi/pci/iocreg.h index 83505242507..a55f2ba61ce 100644 --- a/sys/arch/sgi/pci/iocreg.h +++ b/sys/arch/sgi/pci/iocreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: iocreg.h,v 1.1 2008/04/07 22:53:00 miod Exp $ */ +/* $OpenBSD: iocreg.h,v 1.2 2009/04/12 17:56:58 miod Exp $ */ /* * Copyright (c) 2008 Joel Sing. @@ -20,14 +20,30 @@ * Register definitions for SGI IOC ASIC. */ -#define IOC3_MCR 0x00030 +#define IOC_NDEVS 6 -#define IOC3_RTC_BASE 0x20168 +#define IOCDEV_SERIAL_A 0 +#define IOCDEV_SERIAL_B 1 +#define IOCDEV_PARPORT 2 +#define IOCDEV_KEYBOARD 3 +#define IOCDEV_RTC 4 +#define IOCDEV_EF 5 -#define IOC3_UARTA_BASE 0x20178 -#define IOC3_UARTB_BASE 0x20170 +#define IOC3_SIO_IR 0x0000001c +#define IOC3_SIO_IES 0x00000020 +#define IOC3_SIO_IEC 0x00000024 +#define IOC3_SIO_CR 0x00000028 +#define IOC3_MCR 0x00000030 -#define IOC3_BYTEBUS_0 0x80000 -#define IOC3_BYTEBUS_1 0xa0000 -#define IOC3_BYTEBUS_2 0xc0000 -#define IOC3_BYTEBUS_3 0xe0000 +#define IOC3_EF_BASE 0x000000f0 +#define IOC3_EF_SIZE 0x60 + +#define IOC3_RTC_BASE 0x00020168 + +#define IOC3_UARTA_BASE 0x00020178 +#define IOC3_UARTB_BASE 0x00020170 + +#define IOC3_BYTEBUS_0 0x00080000 +#define IOC3_BYTEBUS_1 0x000a0000 +#define IOC3_BYTEBUS_2 0x000c0000 +#define IOC3_BYTEBUS_3 0x000e0000 diff --git a/sys/arch/sgi/pci/iocvar.h b/sys/arch/sgi/pci/iocvar.h index b625d712797..e59a2ac783d 100644 --- a/sys/arch/sgi/pci/iocvar.h +++ b/sys/arch/sgi/pci/iocvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: iocvar.h,v 1.1 2008/04/07 22:53:00 miod Exp $ */ +/* $OpenBSD: iocvar.h,v 1.2 2009/04/12 17:56:58 miod Exp $ */ /* * Copyright (c) 2008 Miodrag Vallat. @@ -23,7 +23,10 @@ struct ioc_attach_args { bus_dma_tag_t iaa_dmat; bus_addr_t iaa_base; - int iaa_intr; + int iaa_dev; uint8_t iaa_enaddr[6]; }; + +void *ioc_intr_establish(void *, u_long, int, int (*)(void *), + void *, char *); |