summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2009-04-12 17:56:59 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2009-04-12 17:56:59 +0000
commitaa9adddfca7778c5667f7860a75baa5bb033974b (patch)
tree7dec8c6dffa27bc6479cb6a3e68ebadaff05e334 /sys
parent2829c2629cd9ab9ba5ca8dd4c7a45d3e3755098e (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.sgi19
-rw-r--r--sys/arch/sgi/dev/com_ioc.c8
-rw-r--r--sys/arch/sgi/pci/ioc.c227
-rw-r--r--sys/arch/sgi/pci/iocreg.h34
-rw-r--r--sys/arch/sgi/pci/iocvar.h7
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 *);