summaryrefslogtreecommitdiffstats
path: root/sys/arch/sgi/hpc/wdsc.c
diff options
context:
space:
mode:
authormiod <miod@openbsd.org>2012-03-28 20:44:23 +0000
committermiod <miod@openbsd.org>2012-03-28 20:44:23 +0000
commit89e78ff68dbb60985d19f72ea5384db19f165e9c (patch)
treece4bbedba0e946ef806252ab74d9ca08167b58a3 /sys/arch/sgi/hpc/wdsc.c
parentAllow dma map boundary smaller than the kernel page size to work in (diff)
downloadwireguard-openbsd-89e78ff68dbb60985d19f72ea5384db19f165e9c.tar.xz
wireguard-openbsd-89e78ff68dbb60985d19f72ea5384db19f165e9c.zip
Work in progress support for the SGI Indigo, Indigo 2 and Indy systems
(IP20, IP22, IP24) in 64-bit mode, adapated from NetBSD. Currently limited to headless operation, input and video drivers will get ported soon. Should work on all R4000, R4440 and R5000 based systems. L2 cache on R5000SC Indy not supported yet (coming soon), R4600 not supported yet either (coming soon as well). Tested to boot multiuser on: Indigo2 R4000SC, Indy R4000PC, Indy R4000SC, Indy R5000SC, Indigo2 R4400SC. There are still glitches in the Ethernet driver which are being looked at. Expansion support is limited to the GIO E++ board; GIO boards with PCI-GIO bridges not ported yet due to the lack of hardware, and this kind of driver does not port blindly. Most of this work comes from NetBSD, polishing and integration work, as well as putting as many ``R4x00 in 64-bit mode'' erratas as necessary, by yours truly. More work is coming, as well as trying to get some easy way to boot install kernels (as older PROM can only boot ECOFF binaries, which won't do for the kernel).
Diffstat (limited to 'sys/arch/sgi/hpc/wdsc.c')
-rw-r--r--sys/arch/sgi/hpc/wdsc.c290
1 files changed, 290 insertions, 0 deletions
diff --git a/sys/arch/sgi/hpc/wdsc.c b/sys/arch/sgi/hpc/wdsc.c
new file mode 100644
index 00000000000..101b5178819
--- /dev/null
+++ b/sys/arch/sgi/hpc/wdsc.c
@@ -0,0 +1,290 @@
+/* $OpenBSD: wdsc.c,v 1.1 2012/03/28 20:44:23 miod Exp $ */
+/* $NetBSD: wdsc.c,v 1.32 2011/07/01 18:53:47 dyoung Exp $ */
+
+/*
+ * Copyright (c) 2001 Wayne Knowles
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Wayne Knowles
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/buf.h>
+#include <sys/timeout.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+#include <mips64/archtype.h>
+
+#include <machine/autoconf.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <sgi/localbus/intvar.h>
+
+#include <sgi/hpc/hpcreg.h>
+#include <sgi/hpc/hpcvar.h>
+#include <sgi/hpc/hpcdma.h>
+
+#include <dev/ic/wd33c93reg.h>
+#include <dev/ic/wd33c93var.h>
+
+struct wdsc_softc {
+ struct wd33c93_softc sc_wd33c93; /* Must be first */
+ bus_dma_tag_t sc_dmat;
+ bus_dmamap_t sc_dmamap;
+ int sc_flags;
+#define WDSC_DMA_ACTIVE 0x1
+#define WDSC_DMA_MAPLOADED 0x2
+ struct hpc_dma_softc sc_hpcdma;
+};
+
+int wdsc_match(struct device *, void *, void *);
+void wdsc_attach(struct device *, struct device *, void *);
+
+const struct cfattach wdsc_ca = {
+ sizeof(struct wdsc_softc), wdsc_match, wdsc_attach
+};
+
+struct cfdriver wdsc_cd = {
+ NULL, "wdsc", DV_DULL
+};
+
+int wdsc_dmasetup(struct wd33c93_softc *, void ** ,size_t *, int, size_t *);
+int wdsc_dmago(struct wd33c93_softc *);
+void wdsc_dmastop(struct wd33c93_softc *);
+void wdsc_reset(struct wd33c93_softc *);
+
+struct scsi_adapter wdsc_switch = {
+ wd33c93_scsi_cmd,
+ scsi_minphys,
+ NULL,
+ NULL,
+};
+
+/*
+ * Match for SCSI devices on the onboard and GIO32 adapter WD33C93 chips
+ */
+int
+wdsc_match(struct device *parent, void *vcf, void *aux)
+{
+ struct hpc_attach_args *haa = aux;
+ struct cfdata *cf = vcf;
+ vaddr_t reset, asr;
+ uint32_t dummy;
+ uint8_t reg;
+
+ if (strcmp(haa->ha_name, cf->cf_driver->cd_name) != 0)
+ return 0;
+
+ reset = PHYS_TO_XKPHYS(haa->ha_sh + haa->ha_dmaoff +
+ haa->hpc_regs->scsi0_ctl, CCA_NC);
+ if (guarded_read_4(reset, &dummy) != 0)
+ return 0;
+ *(volatile uint32_t *)reset = haa->hpc_regs->scsi_dmactl_reset;
+ delay(1000);
+ *(volatile uint32_t *)reset = 0x0;
+ delay(1000);
+
+ asr = PHYS_TO_XKPHYS(haa->ha_sh + haa->ha_devoff + 3, CCA_NC);
+ if (guarded_read_1(asr, &reg) != 0)
+ return 0;
+ if ((reg & 0xff) != SBIC_ASR_INT)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * Attach the wdsc driver
+ */
+void
+wdsc_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct wdsc_softc *wsc = (struct wdsc_softc *)self;
+ struct wd33c93_softc *sc = &wsc->sc_wd33c93;
+ struct hpc_attach_args *haa = aux;
+ int err;
+
+ sc->sc_regt = haa->ha_st;
+ wsc->sc_dmat = haa->ha_dmat;
+
+ wsc->sc_hpcdma.hpc = haa->hpc_regs;
+
+ if ((err = bus_space_subregion(haa->ha_st, haa->ha_sh,
+ haa->ha_devoff + 3, 1, &sc->sc_asr_regh)) != 0) {
+ printf(": unable to map asr reg, err=%d\n", err);
+ return;
+ }
+
+ if ((err = bus_space_subregion(haa->ha_st, haa->ha_sh,
+ haa->ha_devoff + 3 + 4, 1, &sc->sc_data_regh)) != 0) {
+ printf(": unable to map asr reg, err=%d\n", err);
+ return;
+ }
+
+ if (bus_dmamap_create(wsc->sc_dmat, MAXPHYS,
+ wsc->sc_hpcdma.hpc->scsi_dma_segs,
+ wsc->sc_hpcdma.hpc->scsi_dma_segs_size,
+ wsc->sc_hpcdma.hpc->scsi_dma_segs_size,
+ BUS_DMA_WAITOK, &wsc->sc_dmamap) != 0) {
+ printf(": failed to create dmamap\n");
+ return;
+ }
+
+ sc->sc_dmasetup = wdsc_dmasetup;
+ sc->sc_dmago = wdsc_dmago;
+ sc->sc_dmastop = wdsc_dmastop;
+ sc->sc_reset = wdsc_reset;
+
+ sc->sc_id = 0; /* Host ID = 0 */
+ sc->sc_clkfreq = 200; /* 20MHz */
+ sc->sc_dmamode = SBIC_CTL_BURST_DMA;
+
+ if (int2_intr_establish(haa->ha_irq, IPL_BIO,
+ wd33c93_intr, wsc, self->dv_xname) == NULL) {
+ printf(": unable to establish interrupt!\n");
+ return;
+ }
+
+ hpcdma_init(haa, &wsc->sc_hpcdma, wsc->sc_hpcdma.hpc->scsi_dma_segs);
+ wd33c93_attach(sc, &wdsc_switch);
+}
+
+/*
+ * Prime the hardware for a DMA transfer
+ *
+ * Requires splbio() interrupts to be disabled by the caller
+ */
+int
+wdsc_dmasetup(struct wd33c93_softc *sc, void **addr, size_t *len, int datain,
+ size_t *dmasize)
+{
+ struct wdsc_softc *wsc = (struct wdsc_softc *)sc;
+ struct hpc_dma_softc *dsc = &wsc->sc_hpcdma;
+ int count, err;
+ void *vaddr;
+
+ KASSERT((wsc->sc_flags & WDSC_DMA_ACTIVE) == 0);
+
+ vaddr = *addr;
+ count = dsc->sc_dlen = *len;
+ if (count) {
+ KASSERT((wsc->sc_flags & WDSC_DMA_MAPLOADED) == 0);
+
+ /* Build list of physical addresses for this transfer */
+ if ((err = bus_dmamap_load(wsc->sc_dmat, wsc->sc_dmamap,
+ vaddr, count, NULL /* kernel address */,
+ BUS_DMA_NOWAIT)) != 0)
+ panic("%s: bus_dmamap_load err=%d",
+ sc->sc_dev.dv_xname, err);
+
+ hpcdma_sglist_create(dsc, wsc->sc_dmamap);
+ wsc->sc_flags |= WDSC_DMA_MAPLOADED;
+
+ if (datain) {
+ dsc->sc_dmacmd =
+ wsc->sc_hpcdma.hpc->scsi_dma_datain_cmd;
+ dsc->sc_flags |= HPCDMA_READ;
+ } else {
+ dsc->sc_dmacmd =
+ wsc->sc_hpcdma.hpc->scsi_dma_dataout_cmd;
+ dsc->sc_flags &= ~HPCDMA_READ;
+ }
+ }
+ return count;
+}
+
+/*
+ * Prime the hardware for the next DMA transfer
+ */
+int
+wdsc_dmago(struct wd33c93_softc *sc)
+{
+ struct wdsc_softc *wsc = (struct wdsc_softc *)sc;
+ struct hpc_dma_softc *dsc = &wsc->sc_hpcdma;
+
+ if (dsc->sc_dlen == 0)
+ return 0;
+
+ KASSERT((wsc->sc_flags & WDSC_DMA_ACTIVE) == 0);
+ KASSERT((wsc->sc_flags & WDSC_DMA_MAPLOADED));
+
+ wsc->sc_flags |= WDSC_DMA_ACTIVE;
+
+ bus_dmamap_sync(wsc->sc_dmat, wsc->sc_dmamap,
+ 0, wsc->sc_dmamap->dm_mapsize,
+ (dsc->sc_flags & HPCDMA_READ) ?
+ BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
+
+ hpcdma_cntl(dsc, dsc->sc_dmacmd); /* Thunderbirds are go! */
+
+ return wsc->sc_dmamap->dm_mapsize;
+}
+
+/*
+ * Stop DMA and unload active DMA maps
+ */
+void
+wdsc_dmastop(struct wd33c93_softc *sc)
+{
+ struct wdsc_softc *wsc = (struct wdsc_softc *)sc;
+ struct hpc_dma_softc *dsc = &wsc->sc_hpcdma;
+
+ if (wsc->sc_flags & WDSC_DMA_ACTIVE) {
+ if (dsc->sc_flags & HPCDMA_READ)
+ hpcdma_flush(dsc);
+ hpcdma_cntl(dsc, 0); /* Stop DMA */
+ bus_dmamap_sync(wsc->sc_dmat, wsc->sc_dmamap,
+ 0, wsc->sc_dmamap->dm_mapsize,
+ (dsc->sc_flags & HPCDMA_READ) ?
+ BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
+ }
+ if (wsc->sc_flags & WDSC_DMA_MAPLOADED)
+ bus_dmamap_unload(wsc->sc_dmat, wsc->sc_dmamap);
+ wsc->sc_flags &= ~(WDSC_DMA_ACTIVE | WDSC_DMA_MAPLOADED);
+}
+
+/*
+ * Reset the controller.
+ */
+void
+wdsc_reset(struct wd33c93_softc *sc)
+{
+ struct wdsc_softc *wsc = (struct wdsc_softc *)sc;
+ struct hpc_dma_softc *dsc = &wsc->sc_hpcdma;
+
+ hpcdma_reset(dsc);
+}