1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2019 Ruslan Bukin <br@bsdpad.com> 5 * 6 * This software was developed by SRI International and the University of 7 * Cambridge Computer Laboratory (Department of Computer Science and 8 * Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the 9 * DARPA SSITH research programme. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 36 #include "opt_platform.h" 37 #include <sys/param.h> 38 #include <sys/conf.h> 39 #include <sys/bus.h> 40 #include <sys/kernel.h> 41 #include <sys/lock.h> 42 #include <sys/malloc.h> 43 #include <sys/mbuf.h> 44 #include <sys/mutex.h> 45 #include <sys/rwlock.h> 46 47 #include <machine/bus.h> 48 49 #include <vm/vm.h> 50 #include <vm/pmap.h> 51 #include <vm/vm_extern.h> 52 #include <vm/vm_page.h> 53 54 #ifdef FDT 55 #include <dev/fdt/fdt_common.h> 56 #include <dev/ofw/ofw_bus.h> 57 #include <dev/ofw/ofw_bus_subr.h> 58 #endif 59 60 #include <dev/xdma/xdma.h> 61 #include "xdma_if.h" 62 63 void 64 xdma_iommu_remove_entry(xdma_channel_t *xchan, vm_offset_t va) 65 { 66 struct xdma_iommu *xio; 67 68 xio = &xchan->xio; 69 70 va &= ~(PAGE_SIZE - 1); 71 pmap_remove(&xio->p, va, va + PAGE_SIZE); 72 73 XDMA_IOMMU_REMOVE(xio->dev, xio, va); 74 75 vmem_free(xio->vmem, va, PAGE_SIZE); 76 } 77 78 static void 79 xdma_iommu_enter(struct xdma_iommu *xio, vm_offset_t va, 80 vm_paddr_t pa, vm_size_t size, vm_prot_t prot) 81 { 82 vm_page_t m; 83 pmap_t p; 84 85 p = &xio->p; 86 87 KASSERT((size & PAGE_MASK) == 0, 88 ("%s: device mapping not page-sized", __func__)); 89 90 for (; size > 0; size -= PAGE_SIZE) { 91 m = PHYS_TO_VM_PAGE(pa); 92 pmap_enter(p, va, m, prot, prot | PMAP_ENTER_WIRED, 0); 93 94 XDMA_IOMMU_ENTER(xio->dev, xio, va, pa); 95 96 va += PAGE_SIZE; 97 pa += PAGE_SIZE; 98 } 99 } 100 101 void 102 xdma_iommu_add_entry(xdma_channel_t *xchan, vm_offset_t *va, 103 vm_paddr_t pa, vm_size_t size, vm_prot_t prot) 104 { 105 struct xdma_iommu *xio; 106 vm_offset_t addr; 107 108 size = roundup2(size, PAGE_SIZE); 109 xio = &xchan->xio; 110 111 if (vmem_alloc(xio->vmem, size, 112 M_FIRSTFIT | M_NOWAIT, &addr)) { 113 panic("Could not allocate virtual address.\n"); 114 } 115 116 addr |= pa & (PAGE_SIZE - 1); 117 118 if (va) 119 *va = addr; 120 121 xdma_iommu_enter(xio, addr, pa, size, prot); 122 } 123 124 int 125 xdma_iommu_init(struct xdma_iommu *xio) 126 { 127 #ifdef FDT 128 phandle_t mem_node, node; 129 pcell_t mem_handle; 130 #endif 131 132 pmap_pinit(&xio->p); 133 134 #ifdef FDT 135 node = ofw_bus_get_node(xio->dev); 136 if (!OF_hasprop(node, "va-region")) 137 return (ENXIO); 138 139 if (OF_getencprop(node, "va-region", (void *)&mem_handle, 140 sizeof(mem_handle)) <= 0) 141 return (ENXIO); 142 #endif 143 144 xio->vmem = vmem_create("xDMA vmem", 0, 0, PAGE_SIZE, 145 PAGE_SIZE, M_FIRSTFIT | M_WAITOK); 146 if (xio->vmem == NULL) 147 return (ENXIO); 148 149 #ifdef FDT 150 mem_node = OF_node_from_xref(mem_handle); 151 if (xdma_handle_mem_node(xio->vmem, mem_node) != 0) { 152 vmem_destroy(xio->vmem); 153 return (ENXIO); 154 } 155 #endif 156 157 XDMA_IOMMU_INIT(xio->dev, xio); 158 159 return (0); 160 } 161 162 int 163 xdma_iommu_release(struct xdma_iommu *xio) 164 { 165 166 pmap_release(&xio->p); 167 168 vmem_destroy(xio->vmem); 169 170 XDMA_IOMMU_RELEASE(xio->dev, xio); 171 172 return (0); 173 } 174