diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2015-03-30 20:30:23 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2015-03-30 20:30:23 +0000 |
commit | 8c7e1004ced14a54cdf61791cb3360053dae0a8b (patch) | |
tree | 389e67513a96c94a9cebe1c0c01755c592a41336 /sys/arch/sparc | |
parent | 84138cd9465fea40a211fcf8f0871790b20d6c79 (diff) |
Add a bus_dma_tag_t for DVMA usage, suitable for use for devices not sitting
behind a sun4m iommu.
Move the existing dvma routines from vm_machdep.c to this new dvma.c; this
allows for a few declarations to be removed from public headers.
Extend the device attachment arguments (struct confargs) to pass a
bus_dma_tag_t. mainbus receives the dvma bus_dma_tag_t, and devices pass the
tag unchanged to their children, except for iommu(4) which replaces it with
its own.
Change the few sun4m-only drivers to pick the bus_dma_tag_t from confargs
rather than assume iommu; this allows qlw(4) to attach and work on sun4c.
ok kettenis@
Diffstat (limited to 'sys/arch/sparc')
-rw-r--r-- | sys/arch/sparc/conf/SUN4C | 4 | ||||
-rw-r--r-- | sys/arch/sparc/conf/files.sparc | 3 | ||||
-rw-r--r-- | sys/arch/sparc/dev/dma.c | 27 | ||||
-rw-r--r-- | sys/arch/sparc/dev/fga.c | 11 | ||||
-rw-r--r-- | sys/arch/sparc/dev/lebuffer.c | 11 | ||||
-rw-r--r-- | sys/arch/sparc/dev/obio.c | 14 | ||||
-rw-r--r-- | sys/arch/sparc/dev/qec.c | 9 | ||||
-rw-r--r-- | sys/arch/sparc/dev/qlw_sbus.c | 11 | ||||
-rw-r--r-- | sys/arch/sparc/dev/sbus.c | 109 | ||||
-rw-r--r-- | sys/arch/sparc/dev/sbusvar.h | 22 | ||||
-rw-r--r-- | sys/arch/sparc/include/autoconf.h | 32 | ||||
-rw-r--r-- | sys/arch/sparc/include/bus.h | 21 | ||||
-rw-r--r-- | sys/arch/sparc/include/param.h | 5 | ||||
-rw-r--r-- | sys/arch/sparc/include/vmparam.h | 6 | ||||
-rw-r--r-- | sys/arch/sparc/sparc/autoconf.c | 15 | ||||
-rw-r--r-- | sys/arch/sparc/sparc/dvma.c | 653 | ||||
-rw-r--r-- | sys/arch/sparc/sparc/iommu.c | 8 | ||||
-rw-r--r-- | sys/arch/sparc/sparc/machdep.c | 20 | ||||
-rw-r--r-- | sys/arch/sparc/sparc/vm_machdep.c | 191 |
19 files changed, 812 insertions, 360 deletions
diff --git a/sys/arch/sparc/conf/SUN4C b/sys/arch/sparc/conf/SUN4C index 6c48b8e4f14..7a788fba7bc 100644 --- a/sys/arch/sparc/conf/SUN4C +++ b/sys/arch/sparc/conf/SUN4C @@ -1,4 +1,4 @@ -# $OpenBSD: SUN4C,v 1.68 2014/10/25 18:21:01 miod Exp $ +# $OpenBSD: SUN4C,v 1.69 2015/03/30 20:30:20 miod Exp $ # $NetBSD: GENERIC,v 1.48 1997/08/23 19:19:01 mjacob Exp $ # Machine architecture; required by config(8) @@ -95,6 +95,8 @@ esp* at dma? flags 0x00ff000f # depending on model #sun4c, sun4m isp* at sbus? +qlw* at sbus? +#qla* at sbus? # sun4/300 and sun4c Ethernet - an AMD 7990 LANCE le0 at sbus0 # sun4c on-board diff --git a/sys/arch/sparc/conf/files.sparc b/sys/arch/sparc/conf/files.sparc index c0566e0a9b0..e30debbc07c 100644 --- a/sys/arch/sparc/conf/files.sparc +++ b/sys/arch/sparc/conf/files.sparc @@ -1,4 +1,4 @@ -# $OpenBSD: files.sparc,v 1.98 2015/02/28 17:54:54 miod Exp $ +# $OpenBSD: files.sparc,v 1.99 2015/03/30 20:30:20 miod Exp $ # $NetBSD: files.sparc,v 1.44 1997/08/31 21:29:16 pk Exp $ # @(#)files.sparc 8.1 (Berkeley) 7/19/93 @@ -296,6 +296,7 @@ file arch/sparc/sparc/cache.c file arch/sparc/sparc/conf.c file arch/sparc/sparc/consinit.c file arch/sparc/sparc/disksubr.c +file arch/sparc/sparc/dvma.c file arch/sparc/sparc/emul.c file arch/sparc/sparc/in_cksum.c inet file arch/sparc/sparc/intr.c diff --git a/sys/arch/sparc/dev/dma.c b/sys/arch/sparc/dev/dma.c index 351b4b7a5d6..346b8368615 100644 --- a/sys/arch/sparc/dev/dma.c +++ b/sys/arch/sparc/dev/dma.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dma.c,v 1.30 2014/07/28 18:31:39 miod Exp $ */ +/* $OpenBSD: dma.c,v 1.31 2015/03/30 20:30:22 miod Exp $ */ /* $NetBSD: dma.c,v 1.46 1997/08/27 11:24:16 bouyer Exp $ */ /* @@ -38,8 +38,8 @@ #include <sys/buf.h> #include <sys/proc.h> -#include <sparc/autoconf.h> -#include <sparc/cpu.h> +#include <machine/autoconf.h> +#include <machine/cpu.h> #include <sparc/sparc/cpuvar.h> @@ -236,15 +236,18 @@ dmaattach(parent, self, aux) /* search through children */ node = firstchild(devnode); - if (node != 0) do { - name = getpropstring(node, "name"); - if (!romprop(&oca.ca_ra, name, node)) - continue; - - sbus_translate(parent, &oca); - oca.ca_bustype = BUS_SBUS; - (void) config_found(&sc->sc_dev, (void *)&oca, dmaprint); - } while ((node = nextsibling(node)) != 0); else + if (node != 0) { + do { + name = getpropstring(node, "name"); + if (!romprop(&oca.ca_ra, name, node)) + continue; + + sbus_translate(parent, &oca); + oca.ca_bustype = BUS_SBUS; + oca.ca_dmat = ca->ca_dmat; + config_found(&sc->sc_dev, (void *)&oca, dmaprint); + } while ((node = nextsibling(node)) != 0); + } else #endif /* SUN4C || SUN4D || SUN4E || SUN4M */ if (strcmp(ca->ca_ra.ra_name, "dma") == 0) { diff --git a/sys/arch/sparc/dev/fga.c b/sys/arch/sparc/dev/fga.c index 102a995725a..8c325bd0a11 100644 --- a/sys/arch/sparc/dev/fga.c +++ b/sys/arch/sparc/dev/fga.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fga.c,v 1.17 2010/11/11 17:46:58 miod Exp $ */ +/* $OpenBSD: fga.c,v 1.18 2015/03/30 20:30:22 miod Exp $ */ /* * Copyright (c) 1999 Jason L. Wright (jason@thought.net) @@ -43,13 +43,11 @@ #include <sys/device.h> #include <sys/malloc.h> #include <uvm/uvm_extern.h> -#include <machine/pmap.h> #include <machine/autoconf.h> +#include <machine/bus.h> #include <sparc/cpu.h> #include <sparc/sparc/cpuvar.h> -#include <sparc/dev/sbusvar.h> -#include <sparc/dev/dmareg.h> /* for SBUS_BURST_* */ #include <sparc/dev/fgareg.h> #include <sparc/dev/fgavar.h> @@ -81,6 +79,7 @@ struct fga_softc { int sc_nrange; /* number of sbus ranges */ struct rom_range *sc_range; /* sbus range data */ u_int8_t sc_established; /* which hw intrs installed */ + bus_dma_tag_t sc_dmat; }; int fgaopen(dev_t, int, int, struct proc *); @@ -163,6 +162,7 @@ fgaattach(parent, self, aux) ca->ca_ra.ra_reg[0].rr_len); sc->sc_node = ca->ca_ra.ra_node; + sc->sc_dmat = ca->ca_dmat; i = opennode("/iommu/sbus"); if (i == 0) { @@ -285,6 +285,7 @@ fga_vmerangemap(sc, vmebase, vmelen, vmecap, sbusslot, sbusoffset, oca) oca->ca_ra.ra_reg[1].rr_iospace = vmecap; oca->ca_ra.ra_reg[1].rr_paddr = (void *)vmebase; oca->ca_ra.ra_reg[1].rr_len = vmelen; + oca->ca_dmat = sc->sc_dmat; /* 1. Setup slot select register for this range. */ switch (sbusslot) { @@ -329,7 +330,7 @@ fga_vmerangemap(sc, vmebase, vmelen, vmecap, sbusslot, sbusoffset, oca) ~(VME_MASTER_CAP_DATA | VME_MASTER_CAP_ADDR); regs->vme_master_cap[range] |= vmecap; - (void)config_found(&sc->sc_dev, oca, fgaprint); + config_found(&sc->sc_dev, oca, fgaprint); return (0); } diff --git a/sys/arch/sparc/dev/lebuffer.c b/sys/arch/sparc/dev/lebuffer.c index 65c16196158..702d3fd84f6 100644 --- a/sys/arch/sparc/dev/lebuffer.c +++ b/sys/arch/sparc/dev/lebuffer.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lebuffer.c,v 1.9 2010/07/10 19:32:24 miod Exp $ */ +/* $OpenBSD: lebuffer.c,v 1.10 2015/03/30 20:30:22 miod Exp $ */ /* $NetBSD: lebuffer.c,v 1.3 1997/05/24 20:16:28 pk Exp $ */ /* @@ -41,8 +41,8 @@ #include <sys/buf.h> #include <sys/proc.h> -#include <sparc/autoconf.h> -#include <sparc/cpu.h> +#include <machine/autoconf.h> +#include <machine/cpu.h> #include <sparc/dev/sbusvar.h> #include <sparc/dev/lebuffervar.h> @@ -83,7 +83,7 @@ lebufmatch(parent, vcf, aux) { struct cfdata *cf = vcf; struct confargs *ca = aux; - register struct romaux *ra = &ca->ca_ra; + struct romaux *ra = &ca->ca_ra; if (strcmp(cf->cf_driver->cd_name, ra->ra_name)) return(0); @@ -155,7 +155,8 @@ lebufattach(parent, self, aux) sbus_translate(parent, &oca); oca.ca_bustype = BUS_SBUS; - (void) config_found(&sc->sc_dev, (void *)&oca, lebufprint); + oca.ca_dmat = ca->ca_dmat; + config_found(&sc->sc_dev, (void *)&oca, lebufprint); } #endif /* SUN4C || SUN4D || SUN4E || SUN4M */ } diff --git a/sys/arch/sparc/dev/obio.c b/sys/arch/sparc/dev/obio.c index 23ceb723622..ed7c4af6475 100644 --- a/sys/arch/sparc/dev/obio.c +++ b/sys/arch/sparc/dev/obio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: obio.c,v 1.24 2015/03/26 18:13:56 miod Exp $ */ +/* $OpenBSD: obio.c,v 1.25 2015/03/30 20:30:22 miod Exp $ */ /* $NetBSD: obio.c,v 1.37 1997/07/29 09:58:11 fair Exp $ */ /* @@ -273,7 +273,8 @@ obioattach(parent, self, args) sbus_translate(self, &oca); oca.ca_bustype = BUS_OBIO; - (void) config_found(self, (void *)&oca, busprint); + oca.ca_dmat = ca->ca_dmat; + config_found(self, (void *)&oca, busprint); } for (node = node0; node; node = nextsibling(node)) { @@ -292,7 +293,8 @@ obioattach(parent, self, args) /* Translate into parent address spaces */ sbus_translate(self, &oca); oca.ca_bustype = BUS_OBIO; - (void) config_found(self, (void *)&oca, busprint); + oca.ca_dmat = ca->ca_dmat; + config_found(self, (void *)&oca, busprint); } #endif } @@ -388,11 +390,13 @@ vmeattach(parent, self, aux) oca.ca_ra.ra_name = "vmes"; oca.ca_bustype = BUS_MAIN; - (void)config_found(self, (void *)&oca, vmeprint); + oca.ca_dmat = ca->ca_dmat; + config_found(self, (void *)&oca, vmeprint); oca.ca_ra.ra_name = "vmel"; oca.ca_bustype = BUS_MAIN; - (void)config_found(self, (void *)&oca, vmeprint); + oca.ca_dmat = ca->ca_dmat; + config_found(self, (void *)&oca, vmeprint); } void diff --git a/sys/arch/sparc/dev/qec.c b/sys/arch/sparc/dev/qec.c index a887e51732d..65e9c41ba89 100644 --- a/sys/arch/sparc/dev/qec.c +++ b/sys/arch/sparc/dev/qec.c @@ -1,4 +1,4 @@ -/* $OpenBSD: qec.c,v 1.23 2015/03/29 10:59:47 mpi Exp $ */ +/* $OpenBSD: qec.c,v 1.24 2015/03/30 20:30:22 miod Exp $ */ /* * Copyright (c) 1998 Theo de Raadt and Jason L. Wright. @@ -47,8 +47,8 @@ #include <netinet/in.h> #include <netinet/if_ether.h> -#include <sparc/autoconf.h> -#include <sparc/cpu.h> +#include <machine/autoconf.h> +#include <machine/cpu.h> #include <sparc/dev/sbusvar.h> #include <sparc/dev/dmareg.h> @@ -190,7 +190,8 @@ qecattach(parent, self, aux) qec_translate(sc, &oca); oca.ca_bustype = BUS_SBUS; - (void) config_found(&sc->sc_dev, (void *)&oca, qecprint); + oca.ca_dmat = ca->ca_dmat; + config_found(&sc->sc_dev, (void *)&oca, qecprint); } } diff --git a/sys/arch/sparc/dev/qlw_sbus.c b/sys/arch/sparc/dev/qlw_sbus.c index c0c92487737..3f13fc1274f 100644 --- a/sys/arch/sparc/dev/qlw_sbus.c +++ b/sys/arch/sparc/dev/qlw_sbus.c @@ -1,4 +1,4 @@ -/* $OpenBSD: qlw_sbus.c,v 1.2 2014/10/25 18:21:01 miod Exp $ */ +/* $OpenBSD: qlw_sbus.c,v 1.3 2015/03/30 20:30:22 miod Exp $ */ /* * Copyright (c) 2014 Mark Kettenis * @@ -20,10 +20,9 @@ #include <sys/malloc.h> #include <sys/systm.h> +#include <machine/autoconf.h> #include <machine/bus.h> #include <machine/intr.h> -#include <machine/autoconf.h> -extern struct sparc_bus_dma_tag *iommu_dmatag; #include <sparc/dev/sbusvar.h> #include <sparc/dev/dmareg.h> @@ -59,10 +58,6 @@ qlw_sbus_match(struct device *parent, void *cf, void *aux) struct confargs *ca = aux; struct romaux *ra = &ca->ca_ra; - /* XXX this assumes dma through sun4m's iommu */ - if (!CPU_ISSUN4M) - return 0; - if (strcmp("ptisp", ra->ra_name) == 0 || strcmp("PTI,ptisp", ra->ra_name) == 0 || strcmp("SUNW,isp", ra->ra_name) == 0 || @@ -129,7 +124,7 @@ qlw_sbus_attach(struct device *parent, struct device *self, void *aux) qsc->qsc_rr = ra->ra_reg[0]; sc->sc_iot = &qsc->qsc_rr; sc->sc_ios = ra->ra_reg[0].rr_len; - sc->sc_dmat = iommu_dmatag; + sc->sc_dmat = ca->ca_dmat; sc->sc_isp_gen = QLW_GEN_ISP1000; sc->sc_isp_type = QLW_ISP1000; diff --git a/sys/arch/sparc/dev/sbus.c b/sys/arch/sparc/dev/sbus.c index d0b7bba97cc..6489bb27530 100644 --- a/sys/arch/sparc/dev/sbus.c +++ b/sys/arch/sparc/dev/sbus.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sbus.c,v 1.20 2015/03/21 19:55:31 miod Exp $ */ +/* $OpenBSD: sbus.c,v 1.21 2015/03/30 20:30:22 miod Exp $ */ /* $NetBSD: sbus.c,v 1.17 1997/06/01 22:10:39 pk Exp $ */ /* @@ -75,42 +75,49 @@ struct cfdriver sbus_cd = { }; /* + * SBus driver attach arguments. + * We carry a few more information than a mere struct confargs internally, + * for the sake of sbus_match() and sbus_print(). + */ +struct sbus_attach_args { + struct confargs sa_ca; + int sa_slave_only; + int sa_unsupported; +}; + +static /*const*/ char *sl = "slave-only"; + +/* * Print the location of some sbus-attached device (called just * before attaching that device). If `sbus' is not NULL, the * device was found but not configured; print the sbus as well. * Return UNCONF (config_find ignores this if the device was configured). */ int -sbus_print(args, sbus) - void *args; - const char *sbus; +sbus_print(void *args, const char *sbus) { - struct confargs *ca = args; + struct sbus_attach_args *sa = args; char *class; - static char *sl = "slave-only"; if (sbus != NULL) { - printf("\"%s\" at %s", ca->ca_ra.ra_name, sbus); - class = getpropstring(ca->ca_ra.ra_node, "device_type"); + printf("\"%s\" at %s", sa->sa_ca.ca_ra.ra_name, sbus); + class = getpropstring(sa->sa_ca.ca_ra.ra_node, "device_type"); if (*class != '\0') printf(" class %s", class); } - /* Check root node for 'slave-only' property */ - if (getpropint(0, sl, 0) & (1 << ca->ca_slot)) + if (sa->sa_slave_only) printf(" %s", sl); - printf(" slot %d offset 0x%x", ca->ca_slot, ca->ca_offset); + printf(" slot %d offset 0x%x", sa->sa_ca.ca_slot, sa->sa_ca.ca_offset); - return ca->ca_bustype < 0 ? UNSUPP : UNCONF; + return sa->sa_unsupported != 0 ? UNSUPP : UNCONF; } int -sbus_match(parent, vcf, aux) - struct device *parent; - void *vcf, *aux; +sbus_match(struct device *parent, void *vcf, void *aux) { - register struct cfdata *cf = vcf; - register struct confargs *ca = aux; - register struct romaux *ra = &ca->ca_ra; + struct cfdata *cf = vcf; + struct confargs *ca = aux; + struct romaux *ra = &ca->ca_ra; if (CPU_ISSUN4) return (0); @@ -134,17 +141,14 @@ sbus_match(parent, vcf, aux) * Attach an SBus. */ void -sbus_attach(parent, self, aux) - struct device *parent; - struct device *self; - void *aux; +sbus_attach(struct device *parent, struct device *self, void *aux) { - register struct sbus_softc *sc = (struct sbus_softc *)self; + struct sbus_softc *sc = (struct sbus_softc *)self; struct confargs *ca = aux; - register struct romaux *ra = &ca->ca_ra; - register int node; - register char *name; - struct confargs oca; + struct romaux *ra = &ca->ca_ra; + int node; + char *name; + struct sbus_attach_args saa; int rlen; /* @@ -180,23 +184,29 @@ sbus_attach(parent, self, aux) sc->sc_nrange = xsc->sc_nrange; sc->sc_range = xsc->sc_range; xsc->sc_attached = 2; + + sc->sc_slave_only = getpropint(node, sl, 0); } else { - if (ra->ra_bp != NULL && strcmp(ra->ra_bp->name, "sbus") == 0) - oca.ca_ra.ra_bp = ra->ra_bp + 1; - else - oca.ca_ra.ra_bp = NULL; + /* Check root node for 'slave-only' property */ + sc->sc_slave_only = getpropint(0, sl, 0); rlen = getproplen(node, "ranges"); if (rlen > 0) { sc->sc_nrange = rlen / sizeof(struct rom_range); sc->sc_range = - (struct rom_range *)malloc(rlen, M_DEVBUF, M_NOWAIT); - if (sc->sc_range == 0) + (struct rom_range *)malloc(rlen, M_DEVBUF, M_NOWAIT); + if (sc->sc_range == NULL) panic("sbus: PROM ranges too large: %d", rlen); (void)getprop(node, "ranges", sc->sc_range, rlen); } } + if (ca->ca_bustype != BUS_XBOX && ra->ra_bp != NULL && + strcmp(ra->ra_bp->name, "sbus") == 0) + saa.sa_ca.ca_ra.ra_bp = ra->ra_bp + 1; + else + saa.sa_ca.ca_ra.ra_bp = NULL; + /* * Loop through ROM children, fixing any relative addresses * and then configuring each device. @@ -207,15 +217,16 @@ sbus_attach(parent, self, aux) if (CPU_ISSUN4E && strcmp(name, "vm") == 0) continue; #endif - if (!romprop(&oca.ca_ra, name, node)) + if (!romprop(&saa.sa_ca.ca_ra, name, node)) continue; - if (sbus_translate(self, &oca) == 0) - oca.ca_bustype = BUS_SBUS; - else - oca.ca_bustype = -1; /* force attach to fail */ + saa.sa_ca.ca_bustype = BUS_SBUS; + saa.sa_ca.ca_dmat = ca->ca_dmat; + saa.sa_unsupported = sbus_translate(self, &saa.sa_ca) != 0; + saa.sa_slave_only = + sc->sc_slave_only & (1 << saa.sa_ca.ca_slot); - config_found_sm(&sc->sc_dev, (void *)&oca, sbus_print, + config_found_sm(&sc->sc_dev, (void *)&saa, sbus_print, sbus_search); } } @@ -224,18 +235,16 @@ int sbus_search(struct device *parent, void *vcf, void *args) { struct cfdata *cf = vcf; - struct confargs *oca = args; + struct sbus_attach_args *saa = args; - if (oca->ca_bustype < 0) + if (saa->sa_unsupported != 0) return 0; - return (cf->cf_attach->ca_match)(parent, cf, oca); + return (cf->cf_attach->ca_match)(parent, cf, &saa->sa_ca); } int -sbus_translate(dev, ca) - struct device *dev; - struct confargs *ca; +sbus_translate(struct device *dev, struct confargs *ca) { struct sbus_softc *sc = (struct sbus_softc *)dev; int base, slot; @@ -293,17 +302,11 @@ sbus_translate(dev, ca) * Returns true if this sbus slot is capable of dma */ int -sbus_testdma(sc, ca) - struct sbus_softc *sc; - struct confargs *ca; +sbus_testdma(struct sbus_softc *sc, struct confargs *ca) { struct romaux *ra = &ca->ca_ra; - /* - * XXX how to handle more than one sbus? - */ - - if (getpropint(0, "slave-only", 0) & (1 << ca->ca_slot)) { + if (sc->sc_slave_only & (1 << ca->ca_slot)) { printf("%s: dma card found in non-dma sbus slot %d" ": not supported\n", ra->ra_name, ca->ca_slot); return (0); diff --git a/sys/arch/sparc/dev/sbusvar.h b/sys/arch/sparc/dev/sbusvar.h index f365feece5d..df91eb71ee7 100644 --- a/sys/arch/sparc/dev/sbusvar.h +++ b/sys/arch/sparc/dev/sbusvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sbusvar.h,v 1.10 2015/03/21 19:55:31 miod Exp $ */ +/* $OpenBSD: sbusvar.h,v 1.11 2015/03/30 20:30:22 miod Exp $ */ /* $NetBSD: sbusvar.h,v 1.4 1996/04/22 02:35:05 abrown Exp $ */ /* @@ -42,25 +42,17 @@ */ /* - * S-bus variables. + * SBus variables. */ -/* - * SBus driver attach arguments. - */ -struct sbus_attach_args { - struct romaux sa_ra; /* name, node, addr, etc */ - int sa_slot; /* SBus slot number */ - int sa_offset; /* offset within slot */ -}; - /* variables per SBus */ struct sbus_softc { - struct device sc_dev; /* base device */ - int sc_clockfreq; /* clock frequency (in Hz) */ + struct device sc_dev; /* base device */ + int sc_clockfreq; /* clock frequency (in Hz) */ struct rom_range *sc_range; - int sc_nrange; - int sc_burst; /* burst transfer sizes supported */ + int sc_nrange; + int sc_burst; /* burst transfer sizes supported */ + int sc_slave_only; }; int sbus_translate(struct device *, struct confargs *); diff --git a/sys/arch/sparc/include/autoconf.h b/sys/arch/sparc/include/autoconf.h index f3b3088d138..ab1cc549ad8 100644 --- a/sys/arch/sparc/include/autoconf.h +++ b/sys/arch/sparc/include/autoconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: autoconf.h,v 1.18 2010/06/29 21:28:08 miod Exp $ */ +/* $OpenBSD: autoconf.h,v 1.19 2015/03/30 20:30:22 miod Exp $ */ /* $NetBSD: autoconf.h,v 1.20 1997/05/24 20:03:03 pk Exp $ */ /* @@ -95,12 +95,25 @@ struct rom_range { /* Only used on v3 PROMs */ u_int32_t size; /* Size in bytes of this range */ }; +/* + * mapiodev maps an I/O device to a virtual address, returning the address. + * mapdev does the real work: you can supply a special virtual address and + * it will use that instead of creating one, but you must only do this if + * you get it from ../sparc/vaddrs.h. + */ +void *mapdev(struct rom_reg *pa, int va, int offset, int size); +#define mapiodev(pa, offset, size) \ + mapdev(pa, 0, offset, size) + +#include <machine/bus.h> struct confargs { - int ca_bustype; - struct romaux ca_ra; - int ca_slot; - int ca_offset; + int ca_bustype; + struct romaux ca_ra; + int ca_slot; + int ca_offset; + + bus_dma_tag_t ca_dmat; }; #define BUS_MAIN 0 #define BUS_OBIO 1 @@ -120,15 +133,6 @@ struct confargs { #define BUS_FGA_A32D32 15 /* - * mapiodev maps an I/O device to a virtual address, returning the address. - * mapdev does the real work: you can supply a special virtual address and - * it will use that instead of creating one, but you must only do this if - * you get it from ../sparc/vaddrs.h. - */ -void *mapdev(struct rom_reg *pa, int va, int offset, int size); -#define mapiodev(pa, offset, size) \ - mapdev(pa, 0, offset, size) -/* * REG2PHYS is provided for drivers with a `d_mmap' function. */ #define REG2PHYS(rr, offset) \ diff --git a/sys/arch/sparc/include/bus.h b/sys/arch/sparc/include/bus.h index ec723213110..962be540393 100644 --- a/sys/arch/sparc/include/bus.h +++ b/sys/arch/sparc/include/bus.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bus.h,v 1.13 2011/09/27 20:47:30 miod Exp $ */ +/* $OpenBSD: bus.h,v 1.14 2015/03/30 20:30:22 miod Exp $ */ /* * Copyright (c) 2003, Miodrag Vallat. * @@ -39,19 +39,17 @@ #ifndef _MACHINE_BUS_H_ #define _MACHINE_BUS_H_ -#include <machine/autoconf.h> - -#include <uvm/uvm_extern.h> - -#include <machine/pmap.h> - -typedef u_long bus_space_handle_t; - +typedef u_long bus_space_handle_t; /* * bus_space_tag_t are pointer to *modified* rom_reg structures. * rr_iospace is used to also carry bus endianness information. */ -typedef struct rom_reg *bus_space_tag_t; +typedef struct rom_reg *bus_space_tag_t; +typedef struct sparc_bus_dma_tag *bus_dma_tag_t; +typedef struct sparc_bus_dmamap *bus_dmamap_t; + +#include <machine/autoconf.h> +#include <uvm/uvm_extern.h> #define TAG_LITTLE_ENDIAN 0x80000000 @@ -526,9 +524,6 @@ struct uio; #define BUS_DMASYNC_PREWRITE 0x04 /* pre-write synchronization */ #define BUS_DMASYNC_POSTWRITE 0x08 /* post-write synchronization */ -typedef struct sparc_bus_dma_tag *bus_dma_tag_t; -typedef struct sparc_bus_dmamap *bus_dmamap_t; - /* * bus_dma_segment_t * diff --git a/sys/arch/sparc/include/param.h b/sys/arch/sparc/include/param.h index 7c8abf3a9ff..532961f5906 100644 --- a/sys/arch/sparc/include/param.h +++ b/sys/arch/sparc/include/param.h @@ -1,4 +1,4 @@ -/* $OpenBSD: param.h,v 1.50 2015/03/18 20:56:40 miod Exp $ */ +/* $OpenBSD: param.h,v 1.51 2015/03/30 20:30:22 miod Exp $ */ /* * Copyright (c) 1992, 1993 @@ -112,10 +112,9 @@ #define NKMEMPAGES_MAX_DEFAULT ((4 * 1024 * 1024) >> PAGE_SHIFT) #ifndef _LOCORE -extern vaddr_t dvma_base; -extern vaddr_t dvma_end; extern struct extent *dvmamap_extent; +extern void dvma_init(void); extern caddr_t kdvma_mapin(caddr_t, int, int); extern caddr_t dvma_malloc_space(size_t, void *, int, int); extern void dvma_free(caddr_t, size_t, void *); diff --git a/sys/arch/sparc/include/vmparam.h b/sys/arch/sparc/include/vmparam.h index b7356412985..139e61a0dcc 100644 --- a/sys/arch/sparc/include/vmparam.h +++ b/sys/arch/sparc/include/vmparam.h @@ -1,4 +1,4 @@ -/* $OpenBSD: vmparam.h,v 1.44 2015/03/27 20:25:39 miod Exp $ */ +/* $OpenBSD: vmparam.h,v 1.45 2015/03/30 20:30:22 miod Exp $ */ /* $NetBSD: vmparam.h,v 1.13 1997/07/12 16:20:03 perry Exp $ */ /* @@ -129,11 +129,7 @@ extern vsize_t vm_kernel_space_size; #define VM_PHYSSEG_NOADD /* can't add RAM after vm_mem_init */ #if defined (_KERNEL) -struct vm_map; -#define dvma_mapin(map,va,len,canwait) dvma_mapin_space(map,va,len,canwait,0) -vaddr_t dvma_mapin_space(struct vm_map *, vaddr_t, int, int, int); void dvma_mapout(vaddr_t, vaddr_t, int); - #endif #endif /* _MACHINE_VMPARAM_H_ */ diff --git a/sys/arch/sparc/sparc/autoconf.c b/sys/arch/sparc/sparc/autoconf.c index 7b33c80842d..a89f223e79c 100644 --- a/sys/arch/sparc/sparc/autoconf.c +++ b/sys/arch/sparc/sparc/autoconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: autoconf.c,v 1.99 2015/03/27 20:25:39 miod Exp $ */ +/* $OpenBSD: autoconf.c,v 1.100 2015/03/30 20:30:22 miod Exp $ */ /* $NetBSD: autoconf.c,v 1.73 1997/07/29 09:41:53 fair Exp $ */ /* @@ -802,6 +802,7 @@ cpu_configure() register char *cp; int s; extern struct user *proc0paddr; + extern struct sparc_bus_dma_tag dvma_dmatag; /* build the bootpath */ bootpath_build(); @@ -859,6 +860,7 @@ cpu_configure() oca.ca_ra.ra_node = node; oca.ca_ra.ra_name = cp = "mainbus"; + oca.ca_dmat = &dvma_dmatag; if (config_rootfound(cp, (void *)&oca) == NULL) panic("mainbus not configured"); @@ -1213,11 +1215,13 @@ mainbus_attach(parent, dev, aux) /* Configure the CPU. */ bzero(&oca, sizeof(oca)); oca.ca_ra.ra_name = "cpu"; - (void)config_found(dev, (void *)&oca, mbprint); + oca.ca_dmat = ca->ca_dmat; + config_found(dev, (void *)&oca, mbprint); /* Start at the beginning of the bootpath */ bzero(&oca, sizeof(oca)); oca.ca_ra.ra_bp = bootpath; + oca.ca_dmat = ca->ca_dmat; oca.ca_bustype = BUS_MAIN; oca.ca_ra.ra_name = "obio"; @@ -1227,7 +1231,7 @@ mainbus_attach(parent, dev, aux) for (ssp = oldmon_special; (sp = *ssp) != NULL; ssp++) { oca.ca_bustype = BUS_MAIN; oca.ca_ra.ra_name = sp; - (void)config_found(dev, (void *)&oca, mbprint); + config_found(dev, (void *)&oca, mbprint); } return; } @@ -1275,6 +1279,7 @@ mainbus_attach(parent, dev, aux) oca.ca_ra.ra_name = "cpu"; oca.ca_ra.ra_paddr = 0; oca.ca_ra.ra_nreg = 0; + oca.ca_dmat = ca->ca_dmat; config_found(dev, (void *)&oca, mbprint); } } @@ -1284,6 +1289,7 @@ mainbus_attach(parent, dev, aux) oca.ca_ra.ra_name = "cpu"; oca.ca_ra.ra_paddr = 0; oca.ca_ra.ra_nreg = 0; + oca.ca_dmat = ca->ca_dmat; config_found(dev, (void *)&oca, mbprint); } @@ -1354,7 +1360,7 @@ mainbus_attach(parent, dev, aux) splx(11 << 8); /*XXX*/ #endif oca.ca_bustype = BUS_MAIN; - (void) config_found(dev, (void *)&oca, mbprint); + config_found(dev, (void *)&oca, mbprint); } } @@ -1369,6 +1375,7 @@ mainbus_attach(parent, dev, aux) bzero(&oca, sizeof(oca)); oca.ca_bustype = BUS_MAIN; oca.ca_ra.ra_name = "led"; + oca.ca_dmat = ca->ca_dmat; config_found(dev, (void *)&oca, mbprint); } #endif diff --git a/sys/arch/sparc/sparc/dvma.c b/sys/arch/sparc/sparc/dvma.c new file mode 100644 index 00000000000..c5ffdb91bdc --- /dev/null +++ b/sys/arch/sparc/sparc/dvma.c @@ -0,0 +1,653 @@ +/* $OpenBSD: dvma.c,v 1.1 2015/03/30 20:30:22 miod Exp $ */ + +/* + * Copyright (c) 1996 + * The President and Fellows of Harvard College. All rights reserved. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * This product includes software developed by Harvard University. + * + * 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 Harvard University. + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)vm_machdep.c 8.2 (Berkeley) 9/23/93 + */ + +#include <sys/param.h> +#include <sys/extent.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/proc.h> + +#include <uvm/uvm_extern.h> + +#include <machine/bus.h> +#include <machine/cpu.h> + +/* + * dvmamap_extent is used to manage DVMA memory. + */ +vaddr_t dvma_base, dvma_end; +struct extent *dvmamap_extent; + +vaddr_t dvma_mapin_space(struct vm_map *, vaddr_t, int, int, int); + +void +dvma_init(void) +{ + dvma_base = CPU_ISSUN4M ? DVMA4M_BASE : DVMA_BASE; + dvma_end = CPU_ISSUN4M ? DVMA4M_END : DVMA_END; + dvmamap_extent = extent_create("dvmamap", dvma_base, dvma_end, + M_DEVBUF, NULL, 0, EX_NOWAIT); + if (dvmamap_extent == NULL) + panic("unable to allocate extent for dvma"); +} + +/* + * Wrapper for dvma_mapin_space() in kernel space, + * so drivers need not include VM goo to get at kernel_map. + */ +caddr_t +kdvma_mapin(va, len, canwait) + caddr_t va; + int len, canwait; +{ + return (caddr_t)dvma_mapin_space(kernel_map, (vaddr_t)va, len, canwait, + 0); +} + +#if defined(SUN4M) /* XXX iommu.c */ +extern int has_iocache; +#endif + +caddr_t +dvma_malloc_space(len, kaddr, flags, space) + size_t len; + void *kaddr; + int flags; +{ + vaddr_t kva; + vaddr_t dva; + + len = round_page(len); + kva = (vaddr_t)malloc(len, M_DEVBUF, flags); + if (kva == 0) + return (NULL); + +#if defined(SUN4M) + if (!has_iocache) +#endif + kvm_uncache((caddr_t)kva, atop(len)); + + *(vaddr_t *)kaddr = kva; + dva = dvma_mapin_space(kernel_map, kva, len, (flags & M_NOWAIT) ? 0 : 1, space); + if (dva == 0) { + free((void *)kva, M_DEVBUF, 0); + return (NULL); + } + return (caddr_t)dva; +} + +void +dvma_free(dva, len, kaddr) + caddr_t dva; + size_t len; + void *kaddr; +{ + vaddr_t kva = *(vaddr_t *)kaddr; + + len = round_page(len); + + dvma_mapout((vaddr_t)dva, kva, len); + /* + * Even if we're freeing memory here, we can't be sure that it will + * be unmapped, so we must recache the memory range to avoid impact + * on other kernel subsystems. + */ +#if defined(SUN4M) + if (!has_iocache) +#endif + kvm_recache(kaddr, atop(len)); + free((void *)kva, M_DEVBUF, 0); +} + +u_long dvma_cachealign = 0; + +/* + * Map a range [va, va+len] of wired virtual addresses in the given map + * to a valid DVMA address. On non-SRMMU systems, this establish a + * second mapping of that range. + */ +vaddr_t +dvma_mapin_space(map, va, len, canwait, space) + struct vm_map *map; + vaddr_t va; + int len, canwait, space; +{ + vaddr_t kva, tva; + int npf, s; + paddr_t pa; + vaddr_t off; + vaddr_t ova; + int olen; + int error; + + if (dvma_cachealign == 0) + dvma_cachealign = PAGE_SIZE; + + ova = va; + olen = len; + + off = va & PAGE_MASK; + va &= ~PAGE_MASK; + len = round_page(len + off); + npf = atop(len); + + s = splhigh(); + if (space & M_SPACE_D24) + error = extent_alloc_subregion(dvmamap_extent, + DVMA_D24_BASE, DVMA_D24_END, len, dvma_cachealign, + va & (dvma_cachealign - 1), 0, + canwait ? EX_WAITSPACE : EX_NOWAIT, &tva); + else + error = extent_alloc(dvmamap_extent, len, dvma_cachealign, + va & (dvma_cachealign - 1), 0, + canwait ? EX_WAITSPACE : EX_NOWAIT, &tva); + splx(s); + if (error) + return 0; + kva = tva; + + while (npf--) { + if (pmap_extract(vm_map_pmap(map), va, &pa) == FALSE) + panic("dvma_mapin: null page frame"); + pa = trunc_page(pa); + +#if defined(SUN4M) + if (CPU_ISSUN4M) { + iommu_enter(tva, pa); + } else +#endif + { + /* + * pmap_enter distributes this mapping to all + * contexts... maybe we should avoid this extra work + */ +#ifdef notyet +#if defined(SUN4) + if (have_iocache) + pa |= PG_IOC; +#endif +#endif + pmap_kenter_pa(tva, pa | PMAP_NC, + PROT_READ | PROT_WRITE); + } + + tva += PAGE_SIZE; + va += PAGE_SIZE; + } + pmap_update(pmap_kernel()); + + /* + * XXX Only have to do this on write. + */ + if (CACHEINFO.c_vactype == VAC_WRITEBACK) /* XXX */ + cpuinfo.cache_flush((caddr_t)ova, olen); /* XXX */ + + return kva + off; +} + +/* + * Remove DVMA mapping of `va' in DVMA space at `dva'. + */ +void +dvma_mapout(dva, va, len) + vaddr_t dva, va; + int len; +{ + int s, off; + int error; + int dlen; + + off = (int)dva & PGOFSET; + dva -= off; + dlen = round_page(len + off); + +#if defined(SUN4M) + if (CPU_ISSUN4M) + iommu_remove(dva, dlen); + else +#endif + { + pmap_kremove(dva, dlen); + pmap_update(pmap_kernel()); + } + + s = splhigh(); + error = extent_free(dvmamap_extent, dva, dlen, EX_NOWAIT); + if (error) + printf("dvma_mapout: extent_free failed\n"); + splx(s); + + if (CACHEINFO.c_vactype != VAC_NONE) + cpuinfo.cache_flush((caddr_t)va, len); +} + +int dvma_dmamap_create(bus_dma_tag_t, bus_size_t, int, bus_size_t, + bus_size_t, int, bus_dmamap_t *); +int dvma_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *, bus_size_t, + struct proc *, int); +int dvma_dmamap_load_mbuf(bus_dma_tag_t, bus_dmamap_t, struct mbuf *, int); +int dvma_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t, bus_dma_segment_t *, + int, bus_size_t, int); +void dvma_dmamap_unload(bus_dma_tag_t, bus_dmamap_t); +void dvma_dmamap_sync(bus_dma_tag_t, bus_dmamap_t, bus_addr_t, bus_size_t, + int); + +int dvma_dmamem_map(bus_dma_tag_t, bus_dma_segment_t *, int, size_t, + caddr_t *, int); +void dvma_dmamem_unmap(bus_dma_tag_t, void *, size_t); + +int dvma_dmamap_load_buffer(bus_dma_tag_t, bus_dmamap_t, void *, bus_size_t, + struct proc *, int); + +int dvma_alloc(bus_dmamap_t, vaddr_t, bus_size_t, int, bus_addr_t *, + bus_size_t *); + +struct sparc_bus_dma_tag dvma_dmatag = { + ._cookie = NULL, + ._dmamap_create = dvma_dmamap_create, + ._dmamap_destroy = _bus_dmamap_destroy, + ._dmamap_load = dvma_dmamap_load, + ._dmamap_load_mbuf = dvma_dmamap_load_mbuf, + ._dmamap_load_uio = _bus_dmamap_load_uio, + ._dmamap_load_raw = dvma_dmamap_load_raw, + ._dmamap_unload = dvma_dmamap_unload, + ._dmamap_sync = dvma_dmamap_sync, + + ._dmamem_alloc = _bus_dmamem_alloc, + ._dmamem_free = _bus_dmamem_free, + ._dmamem_map = dvma_dmamem_map, + ._dmamem_unmap = _bus_dmamem_unmap, + ._dmamem_mmap = _bus_dmamem_mmap, +}; + +/* + * DVMA DMA map functions. + */ +int +dvma_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments, + bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamp) +{ + bus_dmamap_t map; + int error; + + if ((error = _bus_dmamap_create(t, size, nsegments, maxsegsz, boundary, + flags, &map)) != 0) + return (error); + + /* Enable allocations from the entire map */ + map->_dm_ex_start = DVMA_BASE; + map->_dm_ex_end = DVMA_END; + + *dmamp = map; + return (0); +} + +/* + * Internal routine to allocate space in the DVMA extent. + */ +int +dvma_alloc(bus_dmamap_t map, vaddr_t va, bus_size_t len, int flags, + bus_addr_t *dvap, bus_size_t *sgsizep) +{ + bus_size_t sgsize; + u_long align, voff, dvaddr; + int s, error; + int pagesz = PAGE_SIZE; + + /* + * Remember page offset, then truncate the buffer address to + * a page boundary. + */ + voff = va & (pagesz - 1); + va &= -pagesz; + + if (len > map->_dm_size) + return (EINVAL); + + sgsize = (len + voff + pagesz - 1) & -pagesz; + align = dvma_cachealign ? dvma_cachealign : map->_dm_align; + + s = splhigh(); + error = extent_alloc_subregion(dvmamap_extent, map->_dm_ex_start, + map->_dm_ex_end, sgsize, align, va & (align-1), map->_dm_boundary, + (flags & BUS_DMA_NOWAIT) == 0 ? EX_WAITOK : EX_NOWAIT, &dvaddr); + splx(s); + *dvap = (bus_addr_t)dvaddr; + *sgsizep = sgsize; + return (error); +} + +int +dvma_dmamap_load_buffer(bus_dma_tag_t t, bus_dmamap_t map, void *buf, + bus_size_t buflen, struct proc *p, int flags) +{ + bus_size_t sgsize; + bus_addr_t dva; + vaddr_t va = (vaddr_t)buf; + int pagesz = PAGE_SIZE; + pmap_t pmap; + int error; + + if (map->dm_nsegs >= map->_dm_segcnt) + return (EFBIG); + + /* Allocate DVMA resources */ + if ((error = dvma_alloc(map, va, buflen, flags, &dva, &sgsize)) != 0) + return (error); + + if ((CACHEINFO.ec_totalsize == 0)) + cpuinfo.cache_flush(buf, buflen); /* XXX - move to bus_dma_sync? */ + + /* + * We always use just one segment. + */ + map->dm_segs[map->dm_nsegs].ds_addr = dva + (va & (pagesz - 1)); + map->dm_segs[map->dm_nsegs].ds_len = buflen; + map->dm_segs[map->dm_nsegs]._ds_sgsize = sgsize; + map->dm_nsegs++; + + if (p != NULL) + pmap = p->p_vmspace->vm_map.pmap; + else + pmap = pmap_kernel(); + + for (; buflen != 0; ) { + paddr_t pa; + /* + * Get the physical address for this page. + */ + if (!pmap_extract(pmap, va, &pa)) { + pmap_update(pmap_kernel()); + return (EFAULT); + } + + /* + * Compute the segment size, and adjust counts. + */ + sgsize = pagesz - (va & (pagesz - 1)); + if (buflen < sgsize) + sgsize = buflen; + +#ifdef notyet +#if defined(SUN4) + if (have_iocache) + pa |= PG_IOC; +#endif +#endif + pmap_kenter_pa(dva, (pa & -pagesz) | PMAP_NC, + PROT_READ | PROT_WRITE); + + dva += pagesz; + va += sgsize; + buflen -= sgsize; + } + pmap_update(pmap_kernel()); + + return (0); +} + +/* + * Prepare buffer for DMA transfer. + */ +int +dvma_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf, + bus_size_t buflen, struct proc *p, int flags) +{ + int error; + + /* + * Make sure that on error condition we return "no valid mappings". + */ + map->dm_mapsize = buflen; + map->dm_nsegs = 0; + + error = dvma_dmamap_load_buffer(t, map, buf, buflen, p, flags); + if (error) + dvma_dmamap_unload(t, map); + + return (error); +} + +/* + * Like _bus_dmamap_load(), but for mbufs. + */ +int +dvma_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, struct mbuf *m0, + int flags) +{ + struct mbuf *m; + int error = 0; + + /* + * Make sure that on error condition we return "no valid mappings". + */ + map->dm_mapsize = m0->m_pkthdr.len; + map->dm_nsegs = 0; + + for (m = m0; m != NULL && error == 0; m = m->m_next) { + if (m->m_len == 0) + continue; + error = dvma_dmamap_load_buffer(t, map, m->m_data, m->m_len, + NULL, flags); + } + + if (error) + dvma_dmamap_unload(t, map); + + return (error); +} + +/* + * Like _bus_dmamap_load(), but for raw memory allocated with + * bus_dmamem_alloc(). + */ +int +dvma_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map, bus_dma_segment_t *segs, + int nsegs, bus_size_t size, int flags) +{ + struct vm_page *m; + paddr_t pa; + bus_addr_t dva; + bus_size_t sgsize; + struct pglist *mlist; + int pagesz = PAGE_SIZE; + int error; + + map->dm_nsegs = 0; + + /* Allocate DVMA resources */ + if ((error = dvma_alloc(map, segs[0]._ds_va, size, flags, &dva, + &sgsize)) != 0) + return (error); + + /* + * Note DVMA address in case bus_dmamem_map() is called later. + * It can then insure cache coherency by choosing a KVA that + * is aligned to `ds_addr'. + */ + segs[0].ds_addr = dva; + segs[0].ds_len = size; + + map->dm_segs[0].ds_addr = dva; + map->dm_segs[0].ds_len = size; + map->dm_segs[0]._ds_sgsize = sgsize; + + /* Map physical pages into the DVMA address space */ + mlist = segs[0]._ds_mlist; + for (m = TAILQ_FIRST(mlist); m != NULL; m = TAILQ_NEXT(m,pageq)) { + if (sgsize == 0) + panic("dvma_dmamap_load_raw: size botch"); + pa = VM_PAGE_TO_PHYS(m); + +#ifdef notyet +#if defined(SUN4) + if (have_iocache) + pa |= PG_IOC; +#endif +#endif + pmap_kenter_pa(dva, (pa & -pagesz) | PMAP_NC, + PROT_READ | PROT_WRITE); + + dva += pagesz; + sgsize -= pagesz; + } + pmap_update(pmap_kernel()); + + map->dm_nsegs = 1; + map->dm_mapsize = size; + + return (0); +} + +/* + * Unload a DVMA DMA map. + */ +void +dvma_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map) +{ + bus_dma_segment_t *segs = map->dm_segs; + int nsegs = map->dm_nsegs; + bus_addr_t dva; + bus_size_t len; + int i, s, error; + + for (i = 0; i < nsegs; i++) { + dva = segs[i].ds_addr & -PAGE_SIZE; + len = segs[i]._ds_sgsize; + + pmap_kremove(dva, len); + s = splhigh(); + error = extent_free(dvmamap_extent, dva, len, EX_NOWAIT); + splx(s); + if (error != 0) + printf("warning: %ld of DVMA space lost\n", (long)len); + } + pmap_update(pmap_kernel()); + + /* Mark the mappings as invalid. */ + map->dm_mapsize = 0; + map->dm_nsegs = 0; +} + +/* + * DMA map synchronization. + */ +void +dvma_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset, + bus_size_t len, int ops) +{ + + /* + * XXX Should flush CPU write buffers. + */ +} + +/* + * Map DMA-safe memory. + */ +int +dvma_dmamem_map(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs, + size_t size, caddr_t *kvap, int flags) +{ + struct vm_page *m; + vaddr_t va; + bus_addr_t addr; + struct pglist *mlist; + u_long align; + int pagesz = PAGE_SIZE; + const struct kmem_dyn_mode *kd; + + if (nsegs != 1) + panic("dvma_dmamem_map: nsegs = %d", nsegs); + + align = dvma_cachealign ? dvma_cachealign : pagesz; + + size = round_page(size); + + kd = flags & BUS_DMA_NOWAIT ? &kd_trylock : &kd_waitok; + va = (vaddr_t)km_alloc(size, &kv_any, &kp_none, kd); + if (va == 0) + return (ENOMEM); + + segs[0]._ds_va = va; + *kvap = (void *)va; + + /* + * Map the pages allocated in _bus_dmamem_alloc() to the + * kernel virtual address space. + */ + mlist = segs[0]._ds_mlist; + for (m = TAILQ_FIRST(mlist); m != NULL; m = TAILQ_NEXT(m,pageq)) { + + if (size == 0) + panic("dvma_dmamem_map: size botch"); + + addr = VM_PAGE_TO_PHYS(m); + pmap_kenter_pa(va, addr | PMAP_NC, PROT_READ | PROT_WRITE); + + va += pagesz; + size -= pagesz; + } + pmap_update(pmap_kernel()); + + return (0); +} + +void +dvma_dmamem_unmap(bus_dma_tag_t t, void *kva, size_t size) +{ + +#ifdef DIAGNOSTIC + if ((u_long)kva & PAGE_MASK) + panic("dvma_dmamem_unmap"); +#endif + + km_free(kva, round_page(size), &kv_any, &kp_none); +} diff --git a/sys/arch/sparc/sparc/iommu.c b/sys/arch/sparc/sparc/iommu.c index b93bcd48ab7..db721210be4 100644 --- a/sys/arch/sparc/sparc/iommu.c +++ b/sys/arch/sparc/sparc/iommu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: iommu.c,v 1.28 2014/11/16 12:30:58 deraadt Exp $ */ +/* $OpenBSD: iommu.c,v 1.29 2015/03/30 20:30:22 miod Exp $ */ /* $NetBSD: iommu.c,v 1.13 1997/07/29 09:42:04 fair Exp $ */ /* @@ -46,8 +46,6 @@ #include <uvm/uvm_extern.h> -#include <machine/pmap.h> - #include <machine/autoconf.h> #include <machine/bus.h> #include <machine/ctlreg.h> @@ -335,12 +333,14 @@ iommu_attach(parent, self, aux) /* * Loop through ROM children (expect SBus among them). */ + oca.ca_dmat = dmat; for (node = firstchild(node); node; node = nextsibling(node)) { name = getpropstring(node, "name"); if (!romprop(&oca.ca_ra, name, node)) continue; oca.ca_bustype = BUS_MAIN; /* ??? */ - (void) config_found(&sc->sc_dev, (void *)&oca, iommu_print); + oca.ca_dmat = dmat; + config_found(&sc->sc_dev, (void *)&oca, iommu_print); } #endif } diff --git a/sys/arch/sparc/sparc/machdep.c b/sys/arch/sparc/sparc/machdep.c index 45390ce5772..c66a7174613 100644 --- a/sys/arch/sparc/sparc/machdep.c +++ b/sys/arch/sparc/sparc/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.170 2015/03/27 20:25:39 miod Exp $ */ +/* $OpenBSD: machdep.c,v 1.171 2015/03/30 20:30:22 miod Exp $ */ /* $NetBSD: machdep.c,v 1.85 1997/09/12 08:55:02 pk Exp $ */ /* @@ -116,12 +116,6 @@ int sparc_led_blink = 1; */ int safepri = 0; -/* - * dvmamap_extent is used to manage DVMA memory. - */ -vaddr_t dvma_base, dvma_end; -struct extent *dvmamap_extent; - void dumpsys(void); void stackdump(void); @@ -194,17 +188,7 @@ cpu_startup() exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 16*NCARGS, VM_MAP_PAGEABLE, FALSE, NULL); - /* - * Allocate a map for physio. Others use a submap of the kernel - * map, but we want one completely separate, even though it uses - * the same pmap. - */ - dvma_base = CPU_ISSUN4M ? DVMA4M_BASE : DVMA_BASE; - dvma_end = CPU_ISSUN4M ? DVMA4M_END : DVMA_END; - dvmamap_extent = extent_create("dvmamap", dvma_base, dvma_end, - M_DEVBUF, NULL, 0, EX_NOWAIT); - if (dvmamap_extent == NULL) - panic("unable to allocate extent for dvma"); + dvma_init(); #ifdef DEBUG pmapdebug = opmapdebug; diff --git a/sys/arch/sparc/sparc/vm_machdep.c b/sys/arch/sparc/sparc/vm_machdep.c index afcab31befd..d0d611dce3c 100644 --- a/sys/arch/sparc/sparc/vm_machdep.c +++ b/sys/arch/sparc/sparc/vm_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vm_machdep.c,v 1.58 2014/11/16 12:30:59 deraadt Exp $ */ +/* $OpenBSD: vm_machdep.c,v 1.59 2015/03/30 20:30:22 miod Exp $ */ /* $NetBSD: vm_machdep.c,v 1.30 1997/03/10 23:55:40 pk Exp $ */ /* @@ -70,195 +70,6 @@ #include <sparc/sparc/cpuvar.h> /* - * Wrapper for dvma_mapin() in kernel space, - * so drivers need not include VM goo to get at kernel_map. - */ -caddr_t -kdvma_mapin(va, len, canwait) - caddr_t va; - int len, canwait; -{ - return ((caddr_t)dvma_mapin(kernel_map, (vaddr_t)va, len, canwait)); -} - -#if defined(SUN4M) -extern int has_iocache; -#endif - -caddr_t -dvma_malloc_space(len, kaddr, flags, space) - size_t len; - void *kaddr; - int flags; -{ - vaddr_t kva; - vaddr_t dva; - - len = round_page(len); - kva = (vaddr_t)malloc(len, M_DEVBUF, flags); - if (kva == 0) - return (NULL); - -#if defined(SUN4M) - if (!has_iocache) -#endif - kvm_uncache((caddr_t)kva, atop(len)); - - *(vaddr_t *)kaddr = kva; - dva = dvma_mapin_space(kernel_map, kva, len, (flags & M_NOWAIT) ? 0 : 1, space); - if (dva == 0) { - free((void *)kva, M_DEVBUF, 0); - return (NULL); - } - return (caddr_t)dva; -} - -void -dvma_free(dva, len, kaddr) - caddr_t dva; - size_t len; - void *kaddr; -{ - vaddr_t kva = *(vaddr_t *)kaddr; - - len = round_page(len); - - dvma_mapout((vaddr_t)dva, kva, len); - /* - * Even if we're freeing memory here, we can't be sure that it will - * be unmapped, so we must recache the memory range to avoid impact - * on other kernel subsystems. - */ -#if defined(SUN4M) - if (!has_iocache) -#endif - kvm_recache(kaddr, atop(len)); - free((void *)kva, M_DEVBUF, 0); -} - -u_long dvma_cachealign = 0; - -/* - * Map a range [va, va+len] of wired virtual addresses in the given map - * to a valid DVMA address. On non-SRMMU systems, this establish a - * second mapping of that range. - */ -vaddr_t -dvma_mapin_space(map, va, len, canwait, space) - struct vm_map *map; - vaddr_t va; - int len, canwait, space; -{ - vaddr_t kva, tva; - int npf, s; - paddr_t pa; - vaddr_t off; - vaddr_t ova; - int olen; - int error; - - if (dvma_cachealign == 0) - dvma_cachealign = PAGE_SIZE; - - ova = va; - olen = len; - - off = va & PAGE_MASK; - va &= ~PAGE_MASK; - len = round_page(len + off); - npf = atop(len); - - s = splhigh(); - if (space & M_SPACE_D24) - error = extent_alloc_subregion(dvmamap_extent, - DVMA_D24_BASE, DVMA_D24_END, len, dvma_cachealign, - va & (dvma_cachealign - 1), 0, - canwait ? EX_WAITSPACE : EX_NOWAIT, &tva); - else - error = extent_alloc(dvmamap_extent, len, dvma_cachealign, - va & (dvma_cachealign - 1), 0, - canwait ? EX_WAITSPACE : EX_NOWAIT, &tva); - splx(s); - if (error) - return 0; - kva = tva; - - while (npf--) { - if (pmap_extract(vm_map_pmap(map), va, &pa) == FALSE) - panic("dvma_mapin: null page frame"); - pa = trunc_page(pa); - -#if defined(SUN4M) - if (CPU_ISSUN4M) { - iommu_enter(tva, pa); - } else -#endif - { - /* - * pmap_enter distributes this mapping to all - * contexts... maybe we should avoid this extra work - */ -#ifdef notyet -#if defined(SUN4) - if (have_iocache) - pa |= PG_IOC; -#endif -#endif - pmap_kenter_pa(tva, pa | PMAP_NC, - PROT_READ | PROT_WRITE); - } - - tva += PAGE_SIZE; - va += PAGE_SIZE; - } - pmap_update(pmap_kernel()); - - /* - * XXX Only have to do this on write. - */ - if (CACHEINFO.c_vactype == VAC_WRITEBACK) /* XXX */ - cpuinfo.cache_flush((caddr_t)ova, olen); /* XXX */ - - return kva + off; -} - -/* - * Remove DVMA mapping of `va' in DVMA space at `dva'. - */ -void -dvma_mapout(dva, va, len) - vaddr_t dva, va; - int len; -{ - int s, off; - int error; - int dlen; - - off = (int)dva & PGOFSET; - dva -= off; - dlen = round_page(len + off); - -#if defined(SUN4M) - if (CPU_ISSUN4M) - iommu_remove(dva, dlen); - else -#endif - { - pmap_kremove(dva, dlen); - pmap_update(pmap_kernel()); - } - - s = splhigh(); - error = extent_free(dvmamap_extent, dva, dlen, EX_NOWAIT); - if (error) - printf("dvma_mapout: extent_free failed\n"); - splx(s); - - if (CACHEINFO.c_vactype != VAC_NONE) - cpuinfo.cache_flush((caddr_t)va, len); -} - -/* * Map an IO request into kernel virtual address space. */ void |