diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2012-05-27 14:27:11 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2012-05-27 14:27:11 +0000 |
commit | 94c758cad85dd5534431b713c81ce0ce8d74c4cf (patch) | |
tree | efbaa08d0f171af8fb8f1b788a5348af90626d72 /sys/arch/sgi | |
parent | f7d146e66a67cb374c59a64c9ba39c0f8f293978 (diff) |
Proper support for the so-called `fast mode' of the Indigo2 ECC memory
controller. In this mode, access to physical memory are not allowed to
bypass the cache, and this allows the memory subsystem to run faster.
Of course, some device drivers will require uncached memory access (e.g.
for proper HPC DMA descriptor operation).
New ip22-specific functions to switch between `fast mode' and `slow mode'
are introduced.
hpc(4) now provides read and write routines to fetch a dma descriptor from
uncached memory into a local copy, and update it from said modified copy.
On systems without the ECC MC, these will do nothing and operation will
continue to access the uncached memory directly. On systems with the ECC MC,
they will perform a copy, and the writeback will be done in slow mode.
bus_dmamem_map() requests for DMA memory with BUS_DMA_COHERENT set in flags,
which would return uncached memory, will now always fail on systems with
the ECC memory controller. Drivers which really need uncached memory, and
are aware of this particular setup, will now pass
BUS_DMA_COHERENT | BUS_DMA_BUS1, which will let the request succeed.
sq(4) will use all of the above to work mostly unmodified on ECC MC systems
in fast mode.
Finally, fast mode is enabled after autoconf.
Tested on IP22 and IP28.
Diffstat (limited to 'sys/arch/sgi')
-rw-r--r-- | sys/arch/sgi/hpc/hpc.c | 86 | ||||
-rw-r--r-- | sys/arch/sgi/hpc/hpcvar.h | 12 | ||||
-rw-r--r-- | sys/arch/sgi/hpc/if_sq.c | 67 | ||||
-rw-r--r-- | sys/arch/sgi/hpc/if_sqvar.h | 11 | ||||
-rw-r--r-- | sys/arch/sgi/include/autoconf.h | 5 | ||||
-rw-r--r-- | sys/arch/sgi/localbus/imcreg.h | 50 | ||||
-rw-r--r-- | sys/arch/sgi/sgi/bus_dma.c | 18 | ||||
-rw-r--r-- | sys/arch/sgi/sgi/ip22.h | 6 | ||||
-rw-r--r-- | sys/arch/sgi/sgi/ip22_machdep.c | 122 | ||||
-rw-r--r-- | sys/arch/sgi/sgi/machdep.c | 3 |
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; |