summaryrefslogtreecommitdiff
path: root/sys/arch/sgi
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/sgi')
-rw-r--r--sys/arch/sgi/hpc/hpc.c86
-rw-r--r--sys/arch/sgi/hpc/hpcvar.h12
-rw-r--r--sys/arch/sgi/hpc/if_sq.c67
-rw-r--r--sys/arch/sgi/hpc/if_sqvar.h11
-rw-r--r--sys/arch/sgi/include/autoconf.h5
-rw-r--r--sys/arch/sgi/localbus/imcreg.h50
-rw-r--r--sys/arch/sgi/sgi/bus_dma.c18
-rw-r--r--sys/arch/sgi/sgi/ip22.h6
-rw-r--r--sys/arch/sgi/sgi/ip22_machdep.c122
-rw-r--r--sys/arch/sgi/sgi/machdep.c3
10 files changed, 325 insertions, 55 deletions
diff --git a/sys/arch/sgi/hpc/hpc.c b/sys/arch/sgi/hpc/hpc.c
index 99c1cea1a64..6c21704dd51 100644
--- a/sys/arch/sgi/hpc/hpc.c
+++ b/sys/arch/sgi/hpc/hpc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: hpc.c,v 1.12 2012/05/17 19:38:59 miod Exp $ */
+/* $OpenBSD: hpc.c,v 1.13 2012/05/27 14:27:08 miod Exp $ */
/* $NetBSD: hpc.c,v 1.66 2011/07/01 18:53:46 dyoung Exp $ */
/* $NetBSD: ioc.c,v 1.9 2011/07/01 18:53:47 dyoung Exp $ */
@@ -363,6 +363,18 @@ void hpc_blink_ioc(void *);
int hpc_read_eeprom(int, bus_space_tag_t, bus_space_handle_t, uint8_t *,
size_t);
+struct hpc_dma_desc *hpc_read_dma_desc_par(struct hpc_dma_desc *,
+ struct hpc_dma_desc *);
+struct hpc_dma_desc *hpc_read_dma_desc_ecc(struct hpc_dma_desc *,
+ struct hpc_dma_desc *);
+void hpc_write_dma_desc_par(struct hpc_dma_desc *, struct hpc_dma_desc *);
+void hpc_write_dma_desc_ecc(struct hpc_dma_desc *, struct hpc_dma_desc *);
+
+/* globals since they depend upon the system type, not the hpc version */
+struct hpc_dma_desc *(*hpc_read_dma_desc_fn)(struct hpc_dma_desc *,
+ struct hpc_dma_desc *);
+void (*hpc_write_dma_desc_fn)(struct hpc_dma_desc *, struct hpc_dma_desc *);
+
const struct cfattach hpc_ca = {
sizeof(struct hpc_softc), hpc_match, hpc_attach
};
@@ -423,6 +435,17 @@ hpc_attach(struct device *parent, struct device *self, void *aux)
sc->sc_ch = PHYS_TO_XKPHYS(sc->sc_base, CCA_NC);
sc->sc_dmat = ga->ga_dmat;
+ /* setup HPC DMA helpers if not done already */
+ if (hpc_read_dma_desc_fn == NULL) {
+ if (ip22_ecc) {
+ hpc_read_dma_desc_fn = hpc_read_dma_desc_ecc;
+ hpc_write_dma_desc_fn = hpc_write_dma_desc_ecc;
+ } else {
+ hpc_read_dma_desc_fn = hpc_read_dma_desc_par;
+ hpc_write_dma_desc_fn = hpc_write_dma_desc_par;
+ }
+ }
+
switch (sys_config.system_type) {
case SGI_IP20:
sysmask = HPCDEV_IP20;
@@ -749,7 +772,7 @@ hpc_attach(struct device *parent, struct device *self, void *aux)
* o Indigo2, Challenge M
* One on-board HPC3.
*
- * All we really have to worry about is the IP22 case.
+ * All we really have to worry about is the IP24 case.
*/
int
hpc_revision(struct hpc_softc *sc, struct gio_attach_args *ga)
@@ -775,12 +798,16 @@ hpc_revision(struct hpc_softc *sc, struct gio_attach_args *ga)
case SGI_IP22:
case SGI_IP26:
case SGI_IP28:
+ if (ga->ga_addr == HPC_BASE_ADDRESS_0)
+ return 3;
+
+ if (sys_config.system_subtype == IP22_INDIGO2)
+ return 0;
+
/*
- * If IP22, probe slot 0 to determine if HPC1.5 or HPC3. Slot 1
+ * If IP24, probe slot 0 to determine if HPC1.5 or HPC3. Slot 1
* must be HPC1.5.
*/
- if (ga->ga_addr == HPC_BASE_ADDRESS_0)
- return 3;
if (ga->ga_addr == HPC_BASE_ADDRESS_2)
return 15;
@@ -943,3 +970,52 @@ hpc_read_eeprom(int hpctype, bus_space_tag_t t, bus_space_handle_t h,
return 0;
}
+
+/*
+ * Routines to copy and update HPC DMA descriptors in uncached memory.
+ */
+
+struct hpc_dma_desc *
+hpc_read_dma_desc(struct hpc_dma_desc *src, struct hpc_dma_desc *store)
+{
+ return (*hpc_read_dma_desc_fn)(src, store);
+}
+
+void
+hpc_write_dma_desc(struct hpc_dma_desc *dst, struct hpc_dma_desc *src)
+{
+ (*hpc_write_dma_desc_fn)(dst, src);
+}
+
+/* parity MC flavour: no copy */
+struct hpc_dma_desc *
+hpc_read_dma_desc_par(struct hpc_dma_desc *src, struct hpc_dma_desc *store)
+{
+ return src;
+}
+
+void
+hpc_write_dma_desc_par(struct hpc_dma_desc *dst, struct hpc_dma_desc *src)
+{
+}
+
+/* ECC MC flavour: copy, and update in slow mode */
+struct hpc_dma_desc *
+hpc_read_dma_desc_ecc(struct hpc_dma_desc *src, struct hpc_dma_desc *store)
+{
+ bcopy(src, store, sizeof(struct hpc_dma_desc));
+ return store;
+}
+
+void
+hpc_write_dma_desc_ecc(struct hpc_dma_desc *dst, struct hpc_dma_desc *src)
+{
+ uint32_t sr;
+ int mode;
+
+ sr = disableintr();
+ mode = ip22_slow_mode();
+ bcopy(src, dst, sizeof(struct hpc_dma_desc));
+ ip22_restore_mode(mode);
+ setsr(sr);
+}
diff --git a/sys/arch/sgi/hpc/hpcvar.h b/sys/arch/sgi/hpc/hpcvar.h
index 9a1e656c6b7..6c0f7a86aed 100644
--- a/sys/arch/sgi/hpc/hpcvar.h
+++ b/sys/arch/sgi/hpc/hpcvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: hpcvar.h,v 1.7 2012/04/30 21:30:33 miod Exp $ */
+/* $OpenBSD: hpcvar.h,v 1.8 2012/05/27 14:27:08 miod Exp $ */
/* $NetBSD: hpcvar.h,v 1.12 2011/01/25 12:21:04 tsutsui Exp $ */
/*
@@ -110,4 +110,14 @@ int hpc_is_intr_pending(int);
void hpc_intr_disable(void *);
void hpc_intr_enable(void *);
+/*
+ * Routines to copy and update HPC DMA descriptors in uncached memory;
+ * needed for proper operation on ECC MC systems.
+ */
+struct hpc_dma_desc;
+
+struct hpc_dma_desc *hpc_read_dma_desc(struct hpc_dma_desc *src,
+ struct hpc_dma_desc *store);
+void hpc_write_dma_desc(struct hpc_dma_desc *dst, struct hpc_dma_desc *src);
+
extern bus_space_t hpc3bus_tag;
diff --git a/sys/arch/sgi/hpc/if_sq.c b/sys/arch/sgi/hpc/if_sq.c
index e9fdd98218e..df697555416 100644
--- a/sys/arch/sgi/hpc/if_sq.c
+++ b/sys/arch/sgi/hpc/if_sq.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_sq.c,v 1.6 2012/05/22 19:53:40 miod Exp $ */
+/* $OpenBSD: if_sq.c,v 1.7 2012/05/27 14:27:08 miod Exp $ */
/* $NetBSD: if_sq.c,v 1.42 2011/07/01 18:53:47 dyoung Exp $ */
/*
@@ -229,9 +229,15 @@ sq_attach(struct device *parent, struct device *self, void *aux)
goto fail_0;
}
+ /*
+ * Note that we need to pass BUS_DMA_BUS1 in order to get this
+ * allocation to succeed on ECC MC systems. This code is
+ * uncached-write safe, as all updates of the DMA descriptors are
+ * handled in RCU style with hpc_{read,write}_dma_desc().
+ */
if ((rc = bus_dmamem_map(sc->sc_dmat, &sc->sc_cdseg, sc->sc_ncdseg,
sizeof(struct sq_control), (caddr_t *)&sc->sc_control,
- BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
+ BUS_DMA_NOWAIT | BUS_DMA_COHERENT | BUS_DMA_BUS1)) != 0) {
printf(": unable to map control data, error = %d\n", rc);
goto fail_1;
}
@@ -656,9 +662,10 @@ void
sq_start(struct ifnet *ifp)
{
struct sq_softc *sc = ifp->if_softc;
- uint32_t status;
struct mbuf *m0, *m;
+ struct hpc_dma_desc *txd, txd_store;
bus_dmamap_t dmamap;
+ uint32_t status;
int err, len, totlen, nexttx, firsttx, lasttx = -1, ofree, seg;
if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)
@@ -789,31 +796,31 @@ sq_start(struct ifnet *ifp)
for (nexttx = sc->sc_nexttx, seg = 0, totlen = 0;
seg < dmamap->dm_nsegs;
seg++, nexttx = SQ_NEXTTX(nexttx)) {
+ txd = hpc_read_dma_desc(sc->sc_txdesc + nexttx,
+ &txd_store);
if (sc->hpc_regs->revision == 3) {
- sc->sc_txdesc[nexttx].hpc3_hdd_bufptr =
+ txd->hpc3_hdd_bufptr =
dmamap->dm_segs[seg].ds_addr;
- sc->sc_txdesc[nexttx].hpc3_hdd_ctl =
- dmamap->dm_segs[seg].ds_len;
+ txd->hpc3_hdd_ctl = dmamap->dm_segs[seg].ds_len;
} else {
- sc->sc_txdesc[nexttx].hpc1_hdd_bufptr =
+ txd->hpc1_hdd_bufptr =
dmamap->dm_segs[seg].ds_addr;
- sc->sc_txdesc[nexttx].hpc1_hdd_ctl =
- dmamap->dm_segs[seg].ds_len;
+ txd->hpc1_hdd_ctl = dmamap->dm_segs[seg].ds_len;
}
- sc->sc_txdesc[nexttx].hdd_descptr =
- SQ_CDTXADDR(sc, SQ_NEXTTX(nexttx));
+ txd->hdd_descptr = SQ_CDTXADDR(sc, SQ_NEXTTX(nexttx));
+ hpc_write_dma_desc(sc->sc_txdesc + nexttx, txd);
lasttx = nexttx;
totlen += dmamap->dm_segs[seg].ds_len;
}
/* Last descriptor gets end-of-packet */
KASSERT(lasttx != -1);
+ /* txd = hpc_read_dma_desc(sc->sc_txdesc + lasttx, &txd_store); */
if (sc->hpc_regs->revision == 3)
- sc->sc_txdesc[lasttx].hpc3_hdd_ctl |=
- HPC3_HDD_CTL_EOPACKET;
+ txd->hpc3_hdd_ctl |= HPC3_HDD_CTL_EOPACKET;
else
- sc->sc_txdesc[lasttx].hpc1_hdd_ctl |=
- HPC1_HDD_CTL_EOPACKET;
+ txd->hpc1_hdd_ctl |= HPC1_HDD_CTL_EOPACKET;
+ hpc_write_dma_desc(sc->sc_txdesc + lasttx, txd);
SQ_DPRINTF(("%s: transmit %d-%d, len %d\n",
sc->sc_dev.dv_xname, sc->sc_nexttx, lasttx, totlen));
@@ -869,15 +876,15 @@ sq_start(struct ifnet *ifp)
* addition to HPC3_HDD_CTL_INTR to interrupt.
*/
KASSERT(lasttx != -1);
+ txd = hpc_read_dma_desc(sc->sc_txdesc + lasttx, &txd_store);
if (sc->hpc_regs->revision == 3) {
- sc->sc_txdesc[lasttx].hpc3_hdd_ctl |=
+ txd->hpc3_hdd_ctl |=
HPC3_HDD_CTL_INTR | HPC3_HDD_CTL_EOCHAIN;
} else {
- sc->sc_txdesc[lasttx].hpc1_hdd_ctl |= HPC1_HDD_CTL_INTR;
- sc->sc_txdesc[lasttx].hpc1_hdd_bufptr |=
- HPC1_HDD_CTL_EOCHAIN;
+ txd->hpc1_hdd_ctl |= HPC1_HDD_CTL_INTR;
+ txd->hpc1_hdd_bufptr |= HPC1_HDD_CTL_EOCHAIN;
}
-
+ hpc_write_dma_desc(sc->sc_txdesc + lasttx, txd);
SQ_CDTXSYNC(sc, lasttx, 1,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
@@ -898,17 +905,18 @@ sq_start(struct ifnet *ifp)
if ((status & sc->hpc_regs->enetx_ctl_active) != 0) {
SQ_TRACE(SQ_ADD_TO_DMA, sc, firsttx, status);
+ txd = hpc_read_dma_desc(sc->sc_txdesc +
+ SQ_PREVTX(firsttx), &txd_store);
/*
* NB: hpc3_hdd_ctl == hpc1_hdd_bufptr, and
* HPC1_HDD_CTL_EOCHAIN == HPC3_HDD_CTL_EOCHAIN
*/
- sc->sc_txdesc[SQ_PREVTX(firsttx)].hpc3_hdd_ctl &=
- ~HPC3_HDD_CTL_EOCHAIN;
-
+ txd->hpc3_hdd_ctl &= ~HPC3_HDD_CTL_EOCHAIN;
if (sc->hpc_regs->revision != 3)
- sc->sc_txdesc[SQ_PREVTX(firsttx)].hpc1_hdd_ctl
- &= ~HPC1_HDD_CTL_INTR;
+ txd->hpc1_hdd_ctl &= ~HPC1_HDD_CTL_INTR;
+ hpc_write_dma_desc(sc->sc_txdesc + SQ_PREVTX(firsttx),
+ txd);
SQ_CDTXSYNC(sc, SQ_PREVTX(firsttx), 1,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
} else if (sc->hpc_regs->revision == 3) {
@@ -1105,6 +1113,7 @@ sq_rxintr(struct sq_softc *sc)
{
struct ifnet *ifp = &sc->sc_ac.ac_if;
struct mbuf* m;
+ struct hpc_dma_desc *rxd, rxd_store;
int i, framelen;
uint8_t pktstat;
uint32_t status;
@@ -1206,12 +1215,16 @@ sq_rxintr(struct sq_softc *sc)
*/
new_end = SQ_PREVRX(i);
- sc->sc_rxdesc[new_end].hpc3_hdd_ctl |= HPC3_HDD_CTL_EOCHAIN;
+ rxd = hpc_read_dma_desc(sc->sc_rxdesc + new_end, &rxd_store);
+ rxd->hpc3_hdd_ctl |= HPC3_HDD_CTL_EOCHAIN;
+ hpc_write_dma_desc(sc->sc_rxdesc + new_end, rxd);
SQ_CDRXSYNC(sc, new_end,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
orig_end = SQ_PREVRX(sc->sc_nextrx);
- sc->sc_rxdesc[orig_end].hpc3_hdd_ctl &= ~HPC3_HDD_CTL_EOCHAIN;
+ rxd = hpc_read_dma_desc(sc->sc_rxdesc + orig_end, &rxd_store);
+ rxd->hpc3_hdd_ctl &= ~HPC3_HDD_CTL_EOCHAIN;
+ hpc_write_dma_desc(sc->sc_rxdesc + orig_end, rxd);
SQ_CDRXSYNC(sc, orig_end,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
diff --git a/sys/arch/sgi/hpc/if_sqvar.h b/sys/arch/sgi/hpc/if_sqvar.h
index 4f55053acc5..9bf5df1323b 100644
--- a/sys/arch/sgi/hpc/if_sqvar.h
+++ b/sys/arch/sgi/hpc/if_sqvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_sqvar.h,v 1.2 2012/04/30 21:31:03 miod Exp $ */
+/* $OpenBSD: if_sqvar.h,v 1.3 2012/05/27 14:27:08 miod Exp $ */
/* $NetBSD: sqvar.h,v 1.12 2011/01/25 13:12:39 tsutsui Exp $ */
/*
@@ -159,6 +159,7 @@ struct sq_softc {
#define SQ_CDTXADDR(sc, x) ((sc)->sc_cddma + SQ_CDTXOFF((x)))
#define SQ_CDRXADDR(sc, x) ((sc)->sc_cddma + SQ_CDRXOFF((x)))
+#if 0 /* not necessary as this memory is mapped uncached */
static inline void
SQ_CDTXSYNC(struct sq_softc *sc, int __x, int __n, int ops)
{
@@ -179,13 +180,18 @@ SQ_CDTXSYNC(struct sq_softc *sc, int __x, int __n, int ops)
#define SQ_CDRXSYNC(sc, x, ops) \
bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_cdmap, \
SQ_CDRXOFF((x)), sizeof(struct hpc_dma_desc), (ops))
+#else
+#define SQ_CDTXSYNC(sc, x, n, ops) do { } while (0)
+#define SQ_CDRXSYNC(sc, x, ops) do { } while (0)
+#endif
static inline void
SQ_INIT_RXDESC(struct sq_softc *sc, unsigned int x)
{
- struct hpc_dma_desc* __rxd = &(sc)->sc_rxdesc[(x)];
+ struct hpc_dma_desc *__rxd, rxd_store;
struct mbuf *__m = (sc)->sc_rxmbuf[(x)];
+ __rxd = hpc_read_dma_desc(&(sc)->sc_rxdesc[(x)], &rxd_store);
__m->m_data = __m->m_ext.ext_buf;
if (sc->hpc_regs->revision == 3) {
__rxd->hpc3_hdd_bufptr =
@@ -201,5 +207,6 @@ SQ_INIT_RXDESC(struct sq_softc *sc, unsigned int x)
HPC1_HDD_CTL_INTR | HPC1_HDD_CTL_EOPACKET;
}
__rxd->hdd_descptr = SQ_CDRXADDR((sc), SQ_NEXTRX((x)));
+ hpc_write_dma_desc(&(sc)->sc_rxdesc[(x)], __rxd);
SQ_CDRXSYNC((sc), (x), BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
}
diff --git a/sys/arch/sgi/include/autoconf.h b/sys/arch/sgi/include/autoconf.h
index eba8e8b5786..6fdb3a55034 100644
--- a/sys/arch/sgi/include/autoconf.h
+++ b/sys/arch/sgi/include/autoconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: autoconf.h,v 1.35 2012/04/21 12:20:30 miod Exp $ */
+/* $OpenBSD: autoconf.h,v 1.36 2012/05/27 14:27:10 miod Exp $ */
/*
* Copyright (c) 2001-2003 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -110,4 +110,7 @@ extern struct sgi_device_location console_output, console_input;
int location_match(struct sgi_device_location *,
struct sgi_device_location *);
+extern void (*md_halt)(int);
+void arcbios_halt(int);
+
#endif /* _MACHINE_AUTOCONF_H_ */
diff --git a/sys/arch/sgi/localbus/imcreg.h b/sys/arch/sgi/localbus/imcreg.h
index 14a437fe4f3..e340764794c 100644
--- a/sys/arch/sgi/localbus/imcreg.h
+++ b/sys/arch/sgi/localbus/imcreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: imcreg.h,v 1.2 2012/05/25 18:17:20 miod Exp $ */
+/* $OpenBSD: imcreg.h,v 1.3 2012/05/27 14:27:10 miod Exp $ */
/* $NetBSD: imcreg.h,v 1.4 2005/12/11 12:18:52 christos Exp $ */
/*
@@ -32,19 +32,19 @@
#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
+#define IMC_CPUCTRL0_REFMASK 0x0000000f /* # lines to refresh */
+#define IMC_CPUCTRL0_RFE 0x00000010 /* refresh enable */
+#define IMC_CPUCTRL0_GPR 0x00000020 /* GIO parity enable */
+#define IMC_CPUCTRL0_MPR 0x00000040 /* memory parity enable */
+#define IMC_CPUCTRL0_CPR 0x00000080 /* cpu bus parity enable */
+#define IMC_CPUCTRL0_WDOG 0x00000100 /* watchdog enable */
+#define IMC_CPUCTRL0_SIN 0x00000200 /* reset system */
+#define IMC_CPUCTRL0_GRR 0x00000400 /* graphics reset */
+#define IMC_CPUCTRL0_ENLOCK 0x00000800 /* enable EISA memory lock */
+#define IMC_CPUCTRL0_CMDPAR 0x00001000 /* SysCmd parity enable */
+#define IMC_CPUCTRL0_INTENA 0x00002000 /* enable CPU interrupts */
+#define IMC_CPUCTRL0_SNOOPENA 0x00004000 /* enable gfx DMA snoop */
+#define IMC_CPUCTRL0_PROM_WRENA 0x00008000 /* disable buserr on PROM
* writes */
#define IMC_CPUCTRL0_WRST 0x00010000 /* warm restart (reset cpu) */
/* Bit 17 reserved 0x00020000 */
@@ -143,4 +143,26 @@
#define IMC_GIO_ERRADDR 0xf4 /* GIO error address */
#define IMC_GIO_ERRSTAT 0xfc /* GIO error status */
+/* {CPU,GIO}_ERRSTAT bits in ECC mode */
+#define IMC_ECC_ERRSTAT_FUW 0x00000001 /* fast mode uncached write */
+#define IMC_ECC_ERRSTAT_MULTI 0x00000002 /* multi bit error */
+
#define IMC_RPSS 0x1004 /* RPSS counter */
+
+/*
+ * IP26/IP28 ECC Controller defines
+ */
+
+#define ECC_BASE 0x60000000
+/* control register */
+#define ECC_CTRL 0x00
+#define ECC_CTRL_ENABLE 0x00000000 /* fast mode */
+#define ECC_CTRL_DISABLE 0x00010000 /* slow mode */
+#define ECC_CTRL_WRITE 0x00020000 /* write low bits to chip */
+#define ECC_CTRL_INT_CLR 0x00030000 /* clear pending interrupts */
+#define ECC_CTRL_CHK_ENABLE 0x00050000 /* enable ECC err generation */
+#define ECC_CTRL_CHK_DISABLE 0x00060000 /* disable ECC err generation */
+
+/* ecc control chip modes */
+#define ECC_MODE_PASSTHROUGH 0x0002 /* error detection only */
+#define ECC_MODE_NORMAL 0x0003 /* error detection and correction */
diff --git a/sys/arch/sgi/sgi/bus_dma.c b/sys/arch/sgi/sgi/bus_dma.c
index 699fca6754d..924e64b5a34 100644
--- a/sys/arch/sgi/sgi/bus_dma.c
+++ b/sys/arch/sgi/sgi/bus_dma.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: bus_dma.c,v 1.28 2012/05/20 11:41:11 miod Exp $ */
+/* $OpenBSD: bus_dma.c,v 1.29 2012/05/27 14:27:10 miod Exp $ */
/*
* Copyright (c) 2003-2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -70,6 +70,10 @@
#include <machine/bus.h>
+#if defined(TGT_INDIGO2)
+#include <sgi/sgi/ip22.h>
+#endif
+
/*
* Common function for DMA map creation. May be called by bus-specific
* DMA map creation functions.
@@ -440,6 +444,18 @@ _dmamem_map(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs, size_t size,
bus_addr_t addr;
int curseg, error;
+#if defined(TGT_INDIGO2)
+ /*
+ * On ECC MC systems, which do not allow uncached writes to memory
+ * during regular operation, fail requests for uncached (coherent)
+ * memory, unless the caller tells us it is aware of this and will
+ * do the right thing, by passing BUS_DMA_BUS1 as well.
+ */
+ if ((flags & (BUS_DMA_COHERENT | BUS_DMA_BUS1)) == BUS_DMA_COHERENT &&
+ ip22_ecc)
+ return EINVAL;
+#endif
+
if (nsegs == 1) {
pa = (*t->_device_to_pa)(segs[0].ds_addr);
#ifndef TGT_COHERENT
diff --git a/sys/arch/sgi/sgi/ip22.h b/sys/arch/sgi/sgi/ip22.h
index e6531f9d959..974655933bd 100644
--- a/sys/arch/sgi/sgi/ip22.h
+++ b/sys/arch/sgi/sgi/ip22.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip22.h,v 1.5 2012/05/27 14:13:00 miod Exp $ */
+/* $OpenBSD: ip22.h,v 1.6 2012/05/27 14:27:10 miod Exp $ */
/*
* Copyright (c) 2012 Miodrag Vallat.
@@ -35,3 +35,7 @@
extern int hpc_old; /* nonzero if at least one HPC 1.x device found */
extern int bios_year;
extern int ip22_ecc; /* nonzero if runinng with an ECC memory system */
+
+int ip22_fast_mode(void);
+int ip22_slow_mode(void);
+int ip22_restore_mode(int);
diff --git a/sys/arch/sgi/sgi/ip22_machdep.c b/sys/arch/sgi/sgi/ip22_machdep.c
index 3a5542d346d..c5c52f89e5b 100644
--- a/sys/arch/sgi/sgi/ip22_machdep.c
+++ b/sys/arch/sgi/sgi/ip22_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip22_machdep.c,v 1.9 2012/05/27 14:13:00 miod Exp $ */
+/* $OpenBSD: ip22_machdep.c,v 1.10 2012/05/27 14:27:10 miod Exp $ */
/*
* Copyright (c) 2012 Miodrag Vallat.
@@ -56,6 +56,8 @@ int ip22_ecc = 0;
void ip22_arcbios_walk(void);
int ip22_arcbios_walk_component(arc_config_t *);
+void ip22_ecc_halt(int);
+void ip22_ecc_init(void);
void ip22_memory_setup(void);
void ip22_video_setup(void);
@@ -467,6 +469,11 @@ ip22_setup()
break;
}
+ if (ip22_ecc) {
+ ip22_ecc_init();
+ md_halt = ip22_ecc_halt;
+ }
+
/*
* Figure out how many TLB entries are available.
*/
@@ -542,4 +549,117 @@ ip22_post_autoconf()
bufhighpages = bufpages;
}
}
+
+ if (ip22_ecc) {
+ ip22_fast_mode();
+ }
+}
+
+/*
+ * ECC board specific routines
+ */
+
+#define sync() \
+ __asm__ __volatile__ ("sync" ::: "memory");
+
+#define ecc_write(o,v) \
+ *(volatile uint64_t *)PHYS_TO_XKPHYS(ECC_BASE + (o), CCA_NC) = (v)
+
+static __inline__ uint32_t ip22_ecc_map(void);
+static __inline__ void ip22_ecc_unmap(uint32_t);
+
+static int ip22_ecc_mode; /* 0 if slow mode, 1 if fast mode */
+
+static __inline__ uint32_t
+ip22_ecc_map()
+{
+ uint32_t omemc1, nmemc1;
+
+ omemc1 = imc_read(IMC_MEMCFG1);
+ nmemc1 = omemc1 & ~IMC_MEMC_BANK_MASK;
+ nmemc1 |= IMC_MEMC_VALID | (ECC_BASE >> IMC_MEMC_LSHIFT_HUGE);
+ imc_write(IMC_MEMCFG1, nmemc1);
+ (void)imc_read(IMC_MEMCFG1);
+ sync();
+
+ return omemc1;
+}
+
+static __inline__ void
+ip22_ecc_unmap(uint32_t omemc1)
+{
+ imc_write(IMC_MEMCFG1, omemc1);
+ (void)imc_read(IMC_MEMCFG1);
+ sync();
+}
+
+int
+ip22_fast_mode()
+{
+ uint32_t memc1;
+
+ if (ip22_ecc_mode == 0) {
+ memc1 = ip22_ecc_map();
+ ecc_write(ECC_CTRL, ECC_CTRL_ENABLE);
+ sync();
+ (void)imc_read(IMC_MEMCFG1);
+ imc_write(IMC_CPU_MEMACC, imc_read(IMC_CPU_MEMACC) & ~2);
+ ip22_ecc_unmap(memc1);
+ ip22_ecc_mode = 1;
+ return 0;
+ }
+
+ return 1;
+}
+
+int
+ip22_slow_mode()
+{
+ uint32_t memc1;
+
+ if (ip22_ecc_mode != 0) {
+ memc1 = ip22_ecc_map();
+ imc_write(IMC_CPU_MEMACC, imc_read(IMC_CPU_MEMACC) | 2);
+ ecc_write(ECC_CTRL, ECC_CTRL_DISABLE);
+ sync();
+ (void)imc_read(IMC_MEMCFG1);
+ ip22_ecc_unmap(memc1);
+ ip22_ecc_mode = 0;
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+ip22_restore_mode(int mode)
+{
+ return mode ? ip22_fast_mode() : ip22_slow_mode();
+}
+
+void
+ip22_ecc_init()
+{
+ uint32_t memc1;
+
+ memc1 = ip22_ecc_map();
+ imc_write(IMC_CPU_MEMACC, imc_read(IMC_CPU_MEMACC) | 2);
+ ecc_write(ECC_CTRL, ECC_CTRL_DISABLE);
+ sync();
+ (void)imc_read(IMC_MEMCFG1);
+ ecc_write(ECC_CTRL, ECC_CTRL_INT_CLR);
+ sync();
+ (void)imc_read(IMC_MEMCFG1);
+ ecc_write(ECC_CTRL, ECC_CTRL_CHK_DISABLE); /* XXX for now */
+ sync();
+ (void)imc_read(IMC_MEMCFG1);
+ ip22_ecc_unmap(memc1);
+ ip22_ecc_mode = 0;
+}
+
+void
+ip22_ecc_halt(int howto)
+{
+ ip22_slow_mode();
+ arcbios_halt(howto);
}
diff --git a/sys/arch/sgi/sgi/machdep.c b/sys/arch/sgi/sgi/machdep.c
index ddd67ad2b68..0247d1f44bc 100644
--- a/sys/arch/sgi/sgi/machdep.c
+++ b/sys/arch/sgi/sgi/machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: machdep.c,v 1.123 2012/05/10 21:28:31 miod Exp $ */
+/* $OpenBSD: machdep.c,v 1.124 2012/05/27 14:27:10 miod Exp $ */
/*
* Copyright (c) 2003-2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -126,7 +126,6 @@ void dumpconf(void);
static void dobootopts(int, void *);
-void arcbios_halt(int);
boolean_t is_memory_range(paddr_t, psize_t, psize_t);
void (*md_halt)(int) = arcbios_halt;