1 1.1 riastrad /* $NetBSD: linux_io_mapping.c,v 1.1 2021/12/19 12:28:04 riastradh Exp $ */ 2 1.1 riastrad 3 1.1 riastrad /*- 4 1.1 riastrad * Copyright (c) 2013-2021 The NetBSD Foundation, Inc. 5 1.1 riastrad * All rights reserved. 6 1.1 riastrad * 7 1.1 riastrad * Redistribution and use in source and binary forms, with or without 8 1.1 riastrad * modification, are permitted provided that the following conditions 9 1.1 riastrad * are met: 10 1.1 riastrad * 1. Redistributions of source code must retain the above copyright 11 1.1 riastrad * notice, this list of conditions and the following disclaimer. 12 1.1 riastrad * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 riastrad * notice, this list of conditions and the following disclaimer in the 14 1.1 riastrad * documentation and/or other materials provided with the distribution. 15 1.1 riastrad * 16 1.1 riastrad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 1.1 riastrad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 1.1 riastrad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.1 riastrad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 1.1 riastrad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 1.1 riastrad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 1.1 riastrad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 1.1 riastrad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 1.1 riastrad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 1.1 riastrad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 1.1 riastrad * POSSIBILITY OF SUCH DAMAGE. 27 1.1 riastrad */ 28 1.1 riastrad 29 1.1 riastrad #include <sys/cdefs.h> 30 1.1 riastrad __KERNEL_RCSID(0, "$NetBSD: linux_io_mapping.c,v 1.1 2021/12/19 12:28:04 riastradh Exp $"); 31 1.1 riastrad 32 1.1 riastrad #include <sys/param.h> 33 1.1 riastrad #include <sys/bus.h> 34 1.1 riastrad #include <sys/kmem.h> 35 1.1 riastrad #include <sys/systm.h> 36 1.1 riastrad #include <sys/mman.h> 37 1.1 riastrad 38 1.1 riastrad #include <uvm/uvm_extern.h> 39 1.1 riastrad 40 1.1 riastrad #include <linux/io-mapping.h> 41 1.1 riastrad 42 1.1 riastrad bool 43 1.1 riastrad bus_space_io_mapping_init_wc(bus_space_tag_t bst, struct io_mapping *mapping, 44 1.1 riastrad bus_addr_t addr, bus_size_t size) 45 1.1 riastrad { 46 1.1 riastrad bus_size_t offset; 47 1.1 riastrad 48 1.1 riastrad KASSERT(PAGE_SIZE <= size); 49 1.1 riastrad KASSERT(0 == (size & (PAGE_SIZE - 1))); 50 1.1 riastrad KASSERT(__type_fit(off_t, size)); 51 1.1 riastrad 52 1.1 riastrad /* 53 1.1 riastrad * XXX For x86: Reserve the region (bus_space_reserve) and set 54 1.1 riastrad * an MTRR to make it write-combining. Doesn't matter if we 55 1.1 riastrad * have PAT and we use pmap_kenter_pa, but matters if we don't 56 1.1 riastrad * have PAT or if we later make this use direct map. 57 1.1 riastrad */ 58 1.1 riastrad 59 1.1 riastrad /* Make sure the region is mappable. */ 60 1.1 riastrad for (offset = 0; offset < size; offset += PAGE_SIZE) { 61 1.1 riastrad if (bus_space_mmap(bst, addr, offset, PROT_READ|PROT_WRITE, 62 1.1 riastrad BUS_SPACE_MAP_LINEAR|BUS_SPACE_MAP_PREFETCHABLE) 63 1.1 riastrad == (paddr_t)-1) 64 1.1 riastrad return false; 65 1.1 riastrad } 66 1.1 riastrad 67 1.1 riastrad /* Initialize the mapping record. */ 68 1.1 riastrad mapping->diom_bst = bst; 69 1.1 riastrad mapping->base = addr; 70 1.1 riastrad mapping->size = size; 71 1.1 riastrad mapping->diom_atomic = false; 72 1.1 riastrad 73 1.1 riastrad /* Allocate kva for one page. */ 74 1.1 riastrad mapping->diom_va = uvm_km_alloc(kernel_map, PAGE_SIZE, PAGE_SIZE, 75 1.1 riastrad UVM_KMF_VAONLY | UVM_KMF_WAITVA); 76 1.1 riastrad KASSERT(mapping->diom_va != 0); 77 1.1 riastrad 78 1.1 riastrad return true; 79 1.1 riastrad } 80 1.1 riastrad 81 1.1 riastrad void 82 1.1 riastrad io_mapping_fini(struct io_mapping *mapping) 83 1.1 riastrad { 84 1.1 riastrad 85 1.1 riastrad KASSERT(!mapping->diom_atomic); 86 1.1 riastrad 87 1.1 riastrad uvm_km_free(kernel_map, mapping->diom_va, PAGE_SIZE, UVM_KMF_VAONLY); 88 1.1 riastrad mapping->diom_va = 0; /* paranoia */ 89 1.1 riastrad } 90 1.1 riastrad 91 1.1 riastrad struct io_mapping * 92 1.1 riastrad bus_space_io_mapping_create_wc(bus_space_tag_t bst, bus_addr_t addr, 93 1.1 riastrad bus_size_t size) 94 1.1 riastrad { 95 1.1 riastrad struct io_mapping *mapping; 96 1.1 riastrad 97 1.1 riastrad mapping = kmem_alloc(sizeof(*mapping), KM_SLEEP); 98 1.1 riastrad if (!bus_space_io_mapping_init_wc(bst, mapping, addr, size)) { 99 1.1 riastrad kmem_free(mapping, sizeof(*mapping)); 100 1.1 riastrad return NULL; 101 1.1 riastrad } 102 1.1 riastrad 103 1.1 riastrad return mapping; 104 1.1 riastrad } 105 1.1 riastrad 106 1.1 riastrad void 107 1.1 riastrad io_mapping_free(struct io_mapping *mapping) 108 1.1 riastrad { 109 1.1 riastrad 110 1.1 riastrad io_mapping_fini(mapping); 111 1.1 riastrad kmem_free(mapping, sizeof(*mapping)); 112 1.1 riastrad } 113 1.1 riastrad 114 1.1 riastrad void * 115 1.1 riastrad io_mapping_map_wc(struct io_mapping *mapping, bus_addr_t offset, 116 1.1 riastrad bus_size_t size) 117 1.1 riastrad { 118 1.1 riastrad bus_size_t pg, npgs = size >> PAGE_SHIFT; 119 1.1 riastrad vaddr_t va; 120 1.1 riastrad paddr_t cookie; 121 1.1 riastrad 122 1.1 riastrad KASSERT(0 == (offset & (PAGE_SIZE - 1))); 123 1.1 riastrad KASSERT(PAGE_SIZE <= mapping->size); 124 1.1 riastrad KASSERT(offset <= (mapping->size - PAGE_SIZE)); 125 1.1 riastrad KASSERT(__type_fit(off_t, offset)); 126 1.1 riastrad 127 1.1 riastrad va = uvm_km_alloc(kernel_map, size, PAGE_SIZE, 128 1.1 riastrad UVM_KMF_VAONLY|UVM_KMF_WAITVA); 129 1.1 riastrad KASSERT(va != mapping->diom_va); 130 1.1 riastrad for (pg = 0; pg < npgs; pg++) { 131 1.1 riastrad cookie = bus_space_mmap(mapping->diom_bst, mapping->base, 132 1.1 riastrad offset + pg*PAGE_SIZE, 133 1.1 riastrad PROT_READ|PROT_WRITE, 134 1.1 riastrad BUS_SPACE_MAP_LINEAR|BUS_SPACE_MAP_PREFETCHABLE); 135 1.1 riastrad KASSERT(cookie != (paddr_t)-1); 136 1.1 riastrad 137 1.1 riastrad pmap_kenter_pa(va + pg*PAGE_SIZE, pmap_phys_address(cookie), 138 1.1 riastrad PROT_READ|PROT_WRITE, pmap_mmap_flags(cookie)); 139 1.1 riastrad } 140 1.1 riastrad pmap_update(pmap_kernel()); 141 1.1 riastrad 142 1.1 riastrad return (void *)va; 143 1.1 riastrad } 144 1.1 riastrad 145 1.1 riastrad void 146 1.1 riastrad io_mapping_unmap(struct io_mapping *mapping, void *ptr, bus_size_t size) 147 1.1 riastrad { 148 1.1 riastrad vaddr_t va = (vaddr_t)ptr; 149 1.1 riastrad 150 1.1 riastrad KASSERT(mapping->diom_va != va); 151 1.1 riastrad 152 1.1 riastrad pmap_kremove(va, size); 153 1.1 riastrad pmap_update(pmap_kernel()); 154 1.1 riastrad 155 1.1 riastrad uvm_km_free(kernel_map, va, size, UVM_KMF_VAONLY); 156 1.1 riastrad } 157 1.1 riastrad 158 1.1 riastrad void * 159 1.1 riastrad io_mapping_map_atomic_wc(struct io_mapping *mapping, bus_addr_t offset) 160 1.1 riastrad { 161 1.1 riastrad paddr_t cookie; 162 1.1 riastrad 163 1.1 riastrad KASSERT(0 == (offset & (PAGE_SIZE - 1))); 164 1.1 riastrad KASSERT(PAGE_SIZE <= mapping->size); 165 1.1 riastrad KASSERT(offset <= (mapping->size - PAGE_SIZE)); 166 1.1 riastrad KASSERT(__type_fit(off_t, offset)); 167 1.1 riastrad KASSERT(!mapping->diom_atomic); 168 1.1 riastrad 169 1.1 riastrad cookie = bus_space_mmap(mapping->diom_bst, mapping->base, offset, 170 1.1 riastrad PROT_READ|PROT_WRITE, 171 1.1 riastrad BUS_SPACE_MAP_LINEAR|BUS_SPACE_MAP_PREFETCHABLE); 172 1.1 riastrad KASSERT(cookie != (paddr_t)-1); 173 1.1 riastrad 174 1.1 riastrad pmap_kenter_pa(mapping->diom_va, pmap_phys_address(cookie), 175 1.1 riastrad PROT_READ|PROT_WRITE, pmap_mmap_flags(cookie)); 176 1.1 riastrad pmap_update(pmap_kernel()); 177 1.1 riastrad 178 1.1 riastrad mapping->diom_atomic = true; 179 1.1 riastrad return (void *)mapping->diom_va; 180 1.1 riastrad } 181 1.1 riastrad 182 1.1 riastrad void 183 1.1 riastrad io_mapping_unmap_atomic(struct io_mapping *mapping, void *ptr __diagused) 184 1.1 riastrad { 185 1.1 riastrad 186 1.1 riastrad KASSERT(mapping->diom_atomic); 187 1.1 riastrad KASSERT(mapping->diom_va == (vaddr_t)ptr); 188 1.1 riastrad 189 1.1 riastrad pmap_kremove(mapping->diom_va, PAGE_SIZE); 190 1.1 riastrad pmap_update(pmap_kernel()); 191 1.1 riastrad 192 1.1 riastrad mapping->diom_atomic = false; 193 1.1 riastrad } 194