summaryrefslogtreecommitdiff
path: root/sys/arch/sparc
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2015-03-30 20:30:23 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2015-03-30 20:30:23 +0000
commit8c7e1004ced14a54cdf61791cb3360053dae0a8b (patch)
tree389e67513a96c94a9cebe1c0c01755c592a41336 /sys/arch/sparc
parent84138cd9465fea40a211fcf8f0871790b20d6c79 (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/SUN4C4
-rw-r--r--sys/arch/sparc/conf/files.sparc3
-rw-r--r--sys/arch/sparc/dev/dma.c27
-rw-r--r--sys/arch/sparc/dev/fga.c11
-rw-r--r--sys/arch/sparc/dev/lebuffer.c11
-rw-r--r--sys/arch/sparc/dev/obio.c14
-rw-r--r--sys/arch/sparc/dev/qec.c9
-rw-r--r--sys/arch/sparc/dev/qlw_sbus.c11
-rw-r--r--sys/arch/sparc/dev/sbus.c109
-rw-r--r--sys/arch/sparc/dev/sbusvar.h22
-rw-r--r--sys/arch/sparc/include/autoconf.h32
-rw-r--r--sys/arch/sparc/include/bus.h21
-rw-r--r--sys/arch/sparc/include/param.h5
-rw-r--r--sys/arch/sparc/include/vmparam.h6
-rw-r--r--sys/arch/sparc/sparc/autoconf.c15
-rw-r--r--sys/arch/sparc/sparc/dvma.c653
-rw-r--r--sys/arch/sparc/sparc/iommu.c8
-rw-r--r--sys/arch/sparc/sparc/machdep.c20
-rw-r--r--sys/arch/sparc/sparc/vm_machdep.c191
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