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