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/cache.h> 48 #include <machine/bus.h> 49 50 #include <vm/vm.h> 51 #include <vm/pmap.h> 52 #include <vm/vm_extern.h> 53 #include <vm/vm_page.h> 54 55 #ifdef FDT 56 #include <dev/fdt/fdt_common.h> 57 #include <dev/ofw/ofw_bus.h> 58 #include <dev/ofw/ofw_bus_subr.h> 59 #endif 60 61 #include <dev/xdma/xdma.h> 62 #include "xdma_if.h" 63 64 void 65 xdma_iommu_remove_entry(xdma_channel_t *xchan, vm_offset_t va) 66 { 67 struct xdma_iommu *xio; 68 69 xio = &xchan->xio; 70 71 va &= ~(PAGE_SIZE - 1); 72 pmap_remove(&xio->p, va, va + PAGE_SIZE); 73 74 XDMA_IOMMU_REMOVE(xio->dev, xio, va); 75 76 vmem_free(xio->vmem, va, PAGE_SIZE); 77 } 78 79 static void 80 xdma_iommu_enter(struct xdma_iommu *xio, vm_offset_t va, 81 vm_paddr_t pa, vm_size_t size, vm_prot_t prot) 82 { 83 vm_page_t m; 84 pmap_t p; 85 86 p = &xio->p; 87 88 KASSERT((size & PAGE_MASK) == 0, 89 ("%s: device mapping not page-sized", __func__)); 90 91 for (; size > 0; size -= PAGE_SIZE) { 92 m = PHYS_TO_VM_PAGE(pa); 93 pmap_enter(p, va, m, prot, prot | PMAP_ENTER_WIRED, 0); 94 95 XDMA_IOMMU_ENTER(xio->dev, xio, va, pa); 96 97 va += PAGE_SIZE; 98 pa += PAGE_SIZE; 99 } 100 } 101 102 void 103 xdma_iommu_add_entry(xdma_channel_t *xchan, vm_offset_t *va, 104 vm_paddr_t pa, vm_size_t size, vm_prot_t prot) 105 { 106 struct xdma_iommu *xio; 107 vm_offset_t addr; 108 109 size = roundup2(size, PAGE_SIZE); 110 xio = &xchan->xio; 111 112 if (vmem_alloc(xio->vmem, size, 113 M_FIRSTFIT | M_NOWAIT, &addr)) { 114 panic("Could not allocate virtual address.\n"); 115 } 116 117 addr |= pa & (PAGE_SIZE - 1); 118 119 if (va) 120 *va = addr; 121 122 xdma_iommu_enter(xio, addr, pa, size, prot); 123 } 124 125 int 126 xdma_iommu_init(struct xdma_iommu *xio) 127 { 128 #ifdef FDT 129 phandle_t mem_node, node; 130 pcell_t mem_handle; 131 #endif 132 133 pmap_pinit(&xio->p); 134 135 #ifdef FDT 136 node = ofw_bus_get_node(xio->dev); 137 if (!OF_hasprop(node, "va-region")) 138 return (ENXIO); 139 140 if (OF_getencprop(node, "va-region", (void *)&mem_handle, 141 sizeof(mem_handle)) <= 0) 142 return (ENXIO); 143 #endif 144 145 xio->vmem = vmem_create("xDMA vmem", 0, 0, PAGE_SIZE, 146 PAGE_SIZE, M_FIRSTFIT | M_WAITOK); 147 if (xio->vmem == NULL) 148 return (ENXIO); 149 150 #ifdef FDT 151 mem_node = OF_node_from_xref(mem_handle); 152 if (xdma_handle_mem_node(xio->vmem, mem_node) != 0) { 153 vmem_destroy(xio->vmem); 154 return (ENXIO); 155 } 156 #endif 157 158 XDMA_IOMMU_INIT(xio->dev, xio); 159 160 return (0); 161 } 162 163 int 164 xdma_iommu_release(struct xdma_iommu *xio) 165 { 166 167 pmap_release(&xio->p); 168 169 vmem_destroy(xio->vmem); 170 171 XDMA_IOMMU_RELEASE(xio->dev, xio); 172 173 return (0); 174 } 175