svn commit: r350212 - in head/sys: conf dev/altera/msgdma dev/xdma mips/beri

Ruslan Bukin br at FreeBSD.org
Mon Jul 22 16:01:22 UTC 2019


Author: br
Date: Mon Jul 22 16:01:20 2019
New Revision: 350212
URL: https://svnweb.freebsd.org/changeset/base/350212

Log:
  o Add support for BERI IOMMU device
  o Add an experimental IOMMU support to xDMA framework
  
  The BERI IOMMU device is the part of CHERI device-model project [1]. It
  translates memory addresses for various BERI peripherals modelled in
  software. It accepts FreeBSD/mips64 page directories format and manages
  BERI TLB.
  
  1. https://github.com/CTSRD-CHERI/device-model
  
  Sponsored by:	DARPA, AFRL

Added:
  head/sys/dev/xdma/xdma_iommu.c   (contents, props changed)
  head/sys/mips/beri/beri_iommu.c   (contents, props changed)
Modified:
  head/sys/conf/files
  head/sys/dev/altera/msgdma/msgdma.c
  head/sys/dev/xdma/xdma.c
  head/sys/dev/xdma/xdma.h
  head/sys/dev/xdma/xdma_if.m
  head/sys/dev/xdma/xdma_sg.c
  head/sys/mips/beri/files.beri

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files	Mon Jul 22 10:37:56 2019	(r350211)
+++ head/sys/conf/files	Mon Jul 22 16:01:20 2019	(r350212)
@@ -3431,6 +3431,7 @@ dev/xdma/xdma_bank.c		optional xdma
 dev/xdma/xdma_bio.c		optional xdma
 dev/xdma/xdma_fdt_test.c	optional xdma xdma_test fdt
 dev/xdma/xdma_if.m		optional xdma
+dev/xdma/xdma_iommu.c		optional xdma
 dev/xdma/xdma_mbuf.c		optional xdma
 dev/xdma/xdma_queue.c		optional xdma
 dev/xdma/xdma_sg.c		optional xdma

Modified: head/sys/dev/altera/msgdma/msgdma.c
==============================================================================
--- head/sys/dev/altera/msgdma/msgdma.c	Mon Jul 22 10:37:56 2019	(r350211)
+++ head/sys/dev/altera/msgdma/msgdma.c	Mon Jul 22 16:01:20 2019	(r350212)
@@ -414,7 +414,8 @@ msgdma_channel_alloc(device_t dev, struct xdma_channel
 		if (chan->used == 0) {
 			chan->xchan = xchan;
 			xchan->chan = (void *)chan;
-			xchan->caps |= XCHAN_CAP_BUSDMA;
+			if ((xchan->caps & XCHAN_CAP_IOMMU) == 0)
+				xchan->caps |= XCHAN_CAP_BUSDMA;
 			chan->index = i;
 			chan->sc = sc;
 			chan->used = 1;

Modified: head/sys/dev/xdma/xdma.c
==============================================================================
--- head/sys/dev/xdma/xdma.c	Mon Jul 22 10:37:56 2019	(r350211)
+++ head/sys/dev/xdma/xdma.c	Mon Jul 22 16:01:20 2019	(r350212)
@@ -70,6 +70,39 @@ static struct mtx xdma_mtx;
 
 #define	FDT_REG_CELLS	4
 
+#ifdef FDT
+static int
+xdma_get_iommu_fdt(xdma_controller_t *xdma, xdma_channel_t *xchan)
+{
+	struct xdma_iommu *xio;
+	phandle_t node;
+	pcell_t prop;
+	size_t len;
+
+	node = ofw_bus_get_node(xdma->dma_dev);
+	if (OF_getproplen(node, "xdma,iommu") <= 0)
+		return (0);
+
+	len = OF_getencprop(node, "xdma,iommu", &prop, sizeof(prop));
+	if (len != sizeof(prop)) {
+		device_printf(xdma->dev,
+		    "%s: Can't get iommu device node\n", __func__);
+		return (0);
+	}
+
+	xio = &xchan->xio;
+	xio->dev = OF_device_from_xref(prop);
+	if (xio->dev == NULL) {
+		device_printf(xdma->dev,
+		    "%s: Can't get iommu device\n", __func__);
+		return (0);
+	}
+
+	/* Found */
+	return (1);
+}
+#endif
+
 /*
  * Allocate virtual xDMA channel.
  */
@@ -81,6 +114,13 @@ xdma_channel_alloc(xdma_controller_t *xdma, uint32_t c
 
 	xchan = malloc(sizeof(xdma_channel_t), M_XDMA, M_WAITOK | M_ZERO);
 	xchan->xdma = xdma;
+
+#ifdef FDT
+	/* Check if this DMA controller supports IOMMU. */
+	if (xdma_get_iommu_fdt(xdma, xchan))
+		caps |= XCHAN_CAP_IOMMU | XCHAN_CAP_NOSEG;
+#endif
+
 	xchan->caps = caps;
 
 	XDMA_LOCK();
@@ -109,6 +149,9 @@ xdma_channel_alloc(xdma_controller_t *xdma, uint32_t c
 	TAILQ_INIT(&xchan->queue_out);
 	TAILQ_INIT(&xchan->processing);
 
+	if (xchan->caps & XCHAN_CAP_IOMMU)
+		xdma_iommu_init(&xchan->xio);
+
 	TAILQ_INSERT_TAIL(&xdma->channels, xchan, xchan_next);
 
 	XDMA_UNLOCK();
@@ -139,6 +182,9 @@ xdma_channel_free(xdma_channel_t *xchan)
 	if (xchan->flags & XCHAN_TYPE_SG)
 		xdma_channel_free_sg(xchan);
 
+	if (xchan->caps & XCHAN_CAP_IOMMU)
+		xdma_iommu_release(&xchan->xio);
+
 	xdma_teardown_all_intr(xchan);
 
 	mtx_destroy(&xchan->mtx_lock);
@@ -306,7 +352,7 @@ xdma_ofw_md_data(xdma_controller_t *xdma, pcell_t *cel
 	return (ret);
 }
 
-static int
+int
 xdma_handle_mem_node(vmem_t *vmem, phandle_t memory)
 {
 	pcell_t reg[FDT_REG_CELLS * FDT_MEM_REGIONS];

Modified: head/sys/dev/xdma/xdma.h
==============================================================================
--- head/sys/dev/xdma/xdma.h	Mon Jul 22 10:37:56 2019	(r350211)
+++ head/sys/dev/xdma/xdma.h	Mon Jul 22 16:01:20 2019	(r350212)
@@ -37,6 +37,14 @@
 #include <sys/proc.h>
 #include <sys/vmem.h>
 
+#ifdef FDT
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#endif
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
 enum xdma_direction {
 	XDMA_MEM_TO_MEM,
 	XDMA_MEM_TO_DEV,
@@ -121,6 +129,12 @@ struct xdma_sglist {
 	bool				last;
 };
 
+struct xdma_iommu {
+	struct pmap p;
+	vmem_t *vmem;		/* VA space */
+	device_t dev;		/* IOMMU device */
+};
+
 struct xdma_channel {
 	xdma_controller_t		*xdma;
 	vmem_t				*vmem;
@@ -138,6 +152,7 @@ struct xdma_channel {
 #define	XCHAN_CAP_BUSDMA		(1 << 0)
 #define	XCHAN_CAP_NOSEG			(1 << 1)
 #define	XCHAN_CAP_BOUNCE		(1 << 2)
+#define	XCHAN_CAP_IOMMU			(1 << 3)
 
 	/* A real hardware driver channel. */
 	void				*chan;
@@ -171,6 +186,9 @@ struct xdma_channel {
 	TAILQ_HEAD(, xdma_request)	queue_in;
 	TAILQ_HEAD(, xdma_request)	queue_out;
 	TAILQ_HEAD(, xdma_request)	processing;
+
+	/* iommu */
+	struct xdma_iommu		xio;
 };
 
 typedef struct xdma_channel xdma_channel_t;
@@ -216,6 +234,9 @@ xdma_controller_t *xdma_ofw_get(device_t dev, const ch
 int xdma_put(xdma_controller_t *xdma);
 vmem_t * xdma_get_memory(device_t dev);
 void xdma_put_memory(vmem_t *vmem);
+#ifdef FDT
+int xdma_handle_mem_node(vmem_t *vmem, phandle_t memory);
+#endif
 
 /* xDMA channel ops */
 xdma_channel_t * xdma_channel_alloc(xdma_controller_t *, uint32_t caps);
@@ -270,5 +291,12 @@ void xchan_bank_init(xdma_channel_t *xchan);
 int xchan_bank_free(xdma_channel_t *xchan);
 struct xdma_request * xchan_bank_get(xdma_channel_t *xchan);
 int xchan_bank_put(xdma_channel_t *xchan, struct xdma_request *xr);
+
+/* IOMMU */
+void xdma_iommu_add_entry(xdma_channel_t *xchan, vm_offset_t *va,
+    vm_paddr_t pa, vm_size_t size, vm_prot_t prot);
+void xdma_iommu_remove_entry(xdma_channel_t *xchan, vm_offset_t va);
+int xdma_iommu_init(struct xdma_iommu *xio);
+int xdma_iommu_release(struct xdma_iommu *xio);
 
 #endif /* !_DEV_XDMA_XDMA_H_ */

Modified: head/sys/dev/xdma/xdma_if.m
==============================================================================
--- head/sys/dev/xdma/xdma_if.m	Mon Jul 22 10:37:56 2019	(r350211)
+++ head/sys/dev/xdma/xdma_if.m	Mon Jul 22 16:01:20 2019	(r350212)
@@ -1,5 +1,5 @@
 #-
-# Copyright (c) 2016-2018 Ruslan Bukin <br at bsdpad.com>
+# Copyright (c) 2016-2019 Ruslan Bukin <br at bsdpad.com>
 # All rights reserved.
 #
 # This software was developed by SRI International and the University of
@@ -112,4 +112,41 @@ METHOD int channel_control {
 	device_t dev;
 	struct xdma_channel *xchan;
 	int cmd;
+};
+
+# IOMMU interface
+
+#
+# pmap is initialized
+#
+METHOD int iommu_init {
+	device_t dev;
+	struct xdma_iommu *xio;
+};
+
+#
+# pmap is released
+#
+METHOD int iommu_release {
+	device_t dev;
+	struct xdma_iommu *xio;
+};
+
+#
+# Mapping entered
+#
+METHOD int iommu_enter {
+	device_t dev;
+	struct xdma_iommu *xio;
+	vm_offset_t va;
+	vm_offset_t pa;
+};
+
+#
+# Mapping removed
+#
+METHOD int iommu_remove {
+	device_t dev;
+	struct xdma_iommu *xio;
+	vm_offset_t va;
 };

Added: head/sys/dev/xdma/xdma_iommu.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/xdma/xdma_iommu.c	Mon Jul 22 16:01:20 2019	(r350212)
@@ -0,0 +1,174 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Ruslan Bukin <br at bsdpad.com>
+ *
+ * This software was developed by SRI International and the University of
+ * Cambridge Computer Laboratory (Department of Computer Science and
+ * Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the
+ * DARPA SSITH research programme.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_platform.h"
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/mutex.h>
+#include <sys/rwlock.h>
+
+#include <machine/cache.h>
+#include <machine/bus.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_page.h>
+
+#ifdef FDT
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#endif
+
+#include <dev/xdma/xdma.h>
+#include "xdma_if.h"
+
+void
+xdma_iommu_remove_entry(xdma_channel_t *xchan, vm_offset_t va)
+{
+	struct xdma_iommu *xio;
+
+	xio = &xchan->xio;
+
+	va &= ~(PAGE_SIZE - 1);
+	pmap_remove(&xio->p, va, va + PAGE_SIZE);
+
+	XDMA_IOMMU_REMOVE(xio->dev, xio, va);
+
+	vmem_free(xio->vmem, va, PAGE_SIZE);
+}
+
+static void
+xdma_iommu_enter(struct xdma_iommu *xio, vm_offset_t va,
+    vm_paddr_t pa, vm_size_t size, vm_prot_t prot)
+{
+	vm_page_t m;
+	pmap_t p;
+
+	p = &xio->p;
+
+	KASSERT((size & PAGE_MASK) == 0,
+	    ("%s: device mapping not page-sized", __func__));
+
+	for (; size > 0; size -= PAGE_SIZE) {
+		m = PHYS_TO_VM_PAGE(pa);
+		pmap_enter(p, va, m, prot, prot | PMAP_ENTER_WIRED, 0);
+
+		XDMA_IOMMU_ENTER(xio->dev, xio, va, pa);
+
+		va += PAGE_SIZE;
+		pa += PAGE_SIZE;
+	}
+}
+
+void
+xdma_iommu_add_entry(xdma_channel_t *xchan, vm_offset_t *va,
+    vm_paddr_t pa, vm_size_t size, vm_prot_t prot)
+{
+	struct xdma_iommu *xio;
+	vm_offset_t addr;
+
+	size = roundup2(size, PAGE_SIZE);
+	xio = &xchan->xio;
+
+	if (vmem_alloc(xio->vmem, size,
+	    M_FIRSTFIT | M_NOWAIT, &addr)) {
+		panic("Could not allocate virtual address.\n");
+	}
+
+	addr |= pa & (PAGE_SIZE - 1);
+
+	if (va)
+		*va = addr;
+
+	xdma_iommu_enter(xio, addr, pa, size, prot);
+}
+
+int
+xdma_iommu_init(struct xdma_iommu *xio)
+{
+#ifdef FDT
+	phandle_t mem_node, node;
+	pcell_t mem_handle;
+#endif
+
+	pmap_pinit(&xio->p);
+
+#ifdef FDT
+	node = ofw_bus_get_node(xio->dev);
+	if (!OF_hasprop(node, "va-region"))
+		return (ENXIO);
+
+	if (OF_getencprop(node, "va-region", (void *)&mem_handle,
+	    sizeof(mem_handle)) <= 0)
+		return (ENXIO);
+#endif
+
+	xio->vmem = vmem_create("xDMA vmem", 0, 0, PAGE_SIZE,
+	    PAGE_SIZE, M_FIRSTFIT | M_WAITOK);
+	if (xio->vmem == NULL)
+		return (ENXIO);
+
+#ifdef FDT
+	mem_node = OF_node_from_xref(mem_handle);
+	if (xdma_handle_mem_node(xio->vmem, mem_node) != 0) {
+		vmem_destroy(xio->vmem);
+		return (ENXIO);
+	}
+#endif
+
+	XDMA_IOMMU_INIT(xio->dev, xio);
+
+	return (0);
+}
+
+int
+xdma_iommu_release(struct xdma_iommu *xio)
+{
+
+	pmap_release(&xio->p);
+
+	vmem_destroy(xio->vmem);
+
+	XDMA_IOMMU_RELEASE(xio->dev, xio);
+
+	return (0);
+}

Modified: head/sys/dev/xdma/xdma_sg.c
==============================================================================
--- head/sys/dev/xdma/xdma_sg.c	Mon Jul 22 10:37:56 2019	(r350211)
+++ head/sys/dev/xdma/xdma_sg.c	Mon Jul 22 16:01:20 2019	(r350212)
@@ -327,6 +327,7 @@ xchan_seg_done(xdma_channel_t *xchan,
 	struct xdma_request *xr;
 	xdma_controller_t *xdma;
 	struct xchan_buf *b;
+	bus_addr_t addr;
 
 	xdma = xchan->xdma;
 
@@ -352,6 +353,12 @@ xchan_seg_done(xdma_channel_t *xchan,
 			    xr->direction == XDMA_DEV_TO_MEM)
 				m_copyback(xr->m, 0, st->transferred,
 				    (void *)xr->buf.vaddr);
+		} else if (xchan->caps & XCHAN_CAP_IOMMU) {
+			if (xr->direction == XDMA_MEM_TO_DEV)
+				addr = xr->src_addr;
+			else
+				addr = xr->dst_addr;
+			xdma_iommu_remove_entry(xchan, addr);
 		}
 		xr->status.error = st->error;
 		xr->status.transferred = st->transferred;
@@ -484,11 +491,17 @@ _xdma_load_data(xdma_channel_t *xchan, struct xdma_req
 	xdma_controller_t *xdma;
 	struct mbuf *m;
 	uint32_t nsegs;
+	vm_offset_t va, addr;
+	bus_addr_t pa;
+	vm_prot_t prot;
 
 	xdma = xchan->xdma;
 
 	m = xr->m;
 
+	KASSERT(xchan->caps & XCHAN_CAP_NOSEG,
+	    ("Handling segmented data is not implemented here."));
+
 	nsegs = 1;
 
 	switch (xr->req_type) {
@@ -498,6 +511,27 @@ _xdma_load_data(xdma_channel_t *xchan, struct xdma_req
 				m_copydata(m, 0, m->m_pkthdr.len,
 				    (void *)xr->buf.vaddr);
 			seg[0].ds_addr = (bus_addr_t)xr->buf.paddr;
+		} else if (xchan->caps & XCHAN_CAP_IOMMU) {
+			addr = mtod(m, bus_addr_t);
+			pa = vtophys(addr);
+
+			if (xr->direction == XDMA_MEM_TO_DEV)
+				prot = VM_PROT_READ;
+			else
+				prot = VM_PROT_WRITE;
+
+			xdma_iommu_add_entry(xchan, &va,
+			    pa, m->m_pkthdr.len, prot);
+
+			/*
+			 * Save VA so we can unload data later
+			 * after completion of this transfer.
+			 */
+			if (xr->direction == XDMA_MEM_TO_DEV)
+				xr->src_addr = va;
+			else
+				xr->dst_addr = va;
+			seg[0].ds_addr = va;
 		} else
 			seg[0].ds_addr = mtod(m, bus_addr_t);
 		seg[0].ds_len = m->m_pkthdr.len;

Added: head/sys/mips/beri/beri_iommu.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/mips/beri/beri_iommu.c	Mon Jul 22 16:01:20 2019	(r350212)
@@ -0,0 +1,237 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Ruslan Bukin <br at bsdpad.com>
+ *
+ * This software was developed by SRI International and the University of
+ * Cambridge Computer Laboratory (Department of Computer Science and
+ * Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the
+ * DARPA SSITH research programme.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+#include <sys/timeet.h>
+#include <sys/timetc.h>
+#include <sys/conf.h>
+#include <sys/uio.h>
+#include <sys/endian.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <machine/cache.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/intr.h>
+
+#include <dev/xdma/xdma.h>
+
+#include "xdma_if.h"
+
+#define	IOMMU_INVALIDATE	0x00
+#define	IOMMU_SET_BASE		0x08
+
+struct beri_iommu_softc {
+	struct resource		*res[1];
+	device_t		dev;
+	bus_space_tag_t		bst_data;
+	bus_space_handle_t	bsh_data;
+	uint32_t		offs;
+};
+
+static struct resource_spec beri_iommu_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ -1, 0 }
+};
+
+static void
+beri_iommu_invalidate(struct beri_iommu_softc *sc, vm_offset_t addr)
+{
+
+	bus_write_8(sc->res[0], IOMMU_INVALIDATE, htole64(addr));
+}
+
+static void
+beri_iommu_set_base(struct beri_iommu_softc *sc, vm_offset_t addr)
+{
+
+	bus_write_8(sc->res[0], IOMMU_SET_BASE, htole64(addr));
+}
+
+static int
+beri_iommu_release(device_t dev, struct xdma_iommu *xio)
+{
+	struct beri_iommu_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	beri_iommu_set_base(sc, 0);
+
+	return (0);
+}
+
+static int
+beri_iommu_init(device_t dev, struct xdma_iommu *xio)
+{
+	struct beri_iommu_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	beri_iommu_set_base(sc, (uintptr_t)xio->p.pm_segtab);
+
+	return (0);
+}
+
+static int
+beri_iommu_remove(device_t dev, struct xdma_iommu *xio, vm_offset_t va)
+{
+	struct beri_iommu_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	beri_iommu_invalidate(sc, va);
+
+	return (0);
+}
+
+static int
+beri_iommu_enter(device_t dev, struct xdma_iommu *xio, vm_offset_t va,
+    vm_paddr_t pa)
+{
+	struct beri_iommu_softc *sc;
+	pt_entry_t opte, npte;
+	pt_entry_t *pte;
+	pmap_t p;
+
+	sc = device_get_softc(dev);
+	p = &xio->p;
+
+	pte = pmap_pte(p, va);
+	if (pte == NULL)
+		panic("pte is NULL\n");
+
+	/* Make pte uncacheable. */
+	opte = *pte;
+	npte = opte & ~PTE_C_MASK;
+	npte |= PTE_C(VM_MEMATTR_UNCACHEABLE);
+	*pte = npte;
+
+	/* Write back, invalidate pte. */
+	mips_dcache_wbinv_range((vm_offset_t)pte, sizeof(vm_offset_t));
+
+	/* Invalidate the entry. */
+	if (pte_test(&opte, PTE_V) && opte != npte)
+		beri_iommu_invalidate(sc, va);
+
+	return (0);
+}
+
+static int
+beri_iommu_probe(device_t dev)
+{
+
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (!ofw_bus_is_compatible(dev, "beri,iommu"))
+		return (ENXIO);
+
+	device_set_desc(dev, "BERI IOMMU");
+
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+beri_iommu_attach(device_t dev)
+{
+	struct beri_iommu_softc *sc;
+	phandle_t xref, node;
+
+	sc = device_get_softc(dev);
+	sc->dev = dev;
+
+	if (bus_alloc_resources(dev, beri_iommu_spec, sc->res)) {
+		device_printf(dev, "could not allocate resources\n");
+		return (ENXIO);
+	}
+
+	/* Memory interface */
+	sc->bst_data = rman_get_bustag(sc->res[0]);
+	sc->bsh_data = rman_get_bushandle(sc->res[0]);
+
+	node = ofw_bus_get_node(dev);
+	xref = OF_xref_from_node(node);
+	OF_device_register_xref(xref, dev);
+
+	return (0);
+}
+
+static int
+beri_iommu_detach(device_t dev)
+{
+	struct beri_iommu_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	bus_release_resources(dev, beri_iommu_spec, sc->res);
+
+	return (0);
+}
+
+static device_method_t beri_iommu_methods[] = {
+
+	/* xDMA IOMMU interface */
+	DEVMETHOD(xdma_iommu_init,	beri_iommu_init),
+	DEVMETHOD(xdma_iommu_release,	beri_iommu_release),
+	DEVMETHOD(xdma_iommu_enter,	beri_iommu_enter),
+	DEVMETHOD(xdma_iommu_remove,	beri_iommu_remove),
+
+	/* Device interface */
+	DEVMETHOD(device_probe,		beri_iommu_probe),
+	DEVMETHOD(device_attach,	beri_iommu_attach),
+	DEVMETHOD(device_detach,	beri_iommu_detach),
+
+	{ 0, 0 }
+};
+
+static driver_t beri_iommu_driver = {
+	"beri_iommu",
+	beri_iommu_methods,
+	sizeof(struct beri_iommu_softc),
+};
+
+static devclass_t beri_iommu_devclass;
+
+DRIVER_MODULE(beri_iommu, simplebus, beri_iommu_driver,
+    beri_iommu_devclass, 0, 0);

Modified: head/sys/mips/beri/files.beri
==============================================================================
--- head/sys/mips/beri/files.beri	Mon Jul 22 10:37:56 2019	(r350211)
+++ head/sys/mips/beri/files.beri	Mon Jul 22 16:01:20 2019	(r350212)
@@ -20,6 +20,7 @@ dev/terasic/mtl/terasic_mtl_reg.c	optional terasic_mtl
 dev/terasic/mtl/terasic_mtl_syscons.c	optional terasic_mtl sc
 dev/terasic/mtl/terasic_mtl_text.c	optional terasic_mtl
 dev/terasic/mtl/terasic_mtl_vt.c	optional terasic_mtl vt
+mips/beri/beri_iommu.c			optional xdma
 mips/beri/beri_machdep.c		standard
 mips/beri/beri_mp.c			optional smp
 mips/beri/beri_pic.c			optional fdt


More information about the svn-src-all mailing list