1 1.102 thorpej /* $NetBSD: iommu.c,v 1.102 2023/12/01 05:22:01 thorpej Exp $ */ 2 1.1 pk 3 1.1 pk /* 4 1.1 pk * Copyright (c) 1996 5 1.3 abrown * The President and Fellows of Harvard College. All rights reserved. 6 1.1 pk * Copyright (c) 1995 Paul Kranenburg 7 1.1 pk * 8 1.1 pk * Redistribution and use in source and binary forms, with or without 9 1.1 pk * modification, are permitted provided that the following conditions 10 1.1 pk * are met: 11 1.1 pk * 1. Redistributions of source code must retain the above copyright 12 1.1 pk * notice, this list of conditions and the following disclaimer. 13 1.1 pk * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 pk * notice, this list of conditions and the following disclaimer in the 15 1.1 pk * documentation and/or other materials provided with the distribution. 16 1.1 pk * 3. All advertising materials mentioning features or use of this software 17 1.1 pk * must display the following acknowledgement: 18 1.1 pk * This product includes software developed by Aaron Brown and 19 1.1 pk * Harvard University. 20 1.1 pk * This product includes software developed by Paul Kranenburg. 21 1.1 pk * 4. Neither the name of the University nor the names of its contributors 22 1.1 pk * may be used to endorse or promote products derived from this software 23 1.1 pk * without specific prior written permission. 24 1.1 pk * 25 1.1 pk * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 1.1 pk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 1.1 pk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 1.1 pk * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 1.1 pk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 1.1 pk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 1.1 pk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 1.1 pk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 1.1 pk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 1.1 pk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 1.1 pk * SUCH DAMAGE. 36 1.1 pk * 37 1.1 pk */ 38 1.76 lukem 39 1.76 lukem #include <sys/cdefs.h> 40 1.102 thorpej __KERNEL_RCSID(0, "$NetBSD: iommu.c,v 1.102 2023/12/01 05:22:01 thorpej Exp $"); 41 1.76 lukem 42 1.62 darrenr #include "opt_sparc_arch.h" 43 1.1 pk 44 1.1 pk #include <sys/param.h> 45 1.18 pk #include <sys/malloc.h> 46 1.18 pk #include <sys/queue.h> 47 1.1 pk #include <sys/systm.h> 48 1.1 pk #include <sys/device.h> 49 1.58 chs #include <sys/proc.h> 50 1.102 thorpej #include <sys/vmem.h> 51 1.25 pk 52 1.31 pk #include <uvm/uvm.h> 53 1.1 pk 54 1.18 pk #define _SPARC_BUS_DMA_PRIVATE 55 1.93 dyoung #include <sys/bus.h> 56 1.1 pk #include <machine/autoconf.h> 57 1.1 pk #include <machine/ctlreg.h> 58 1.1 pk #include <sparc/sparc/asm.h> 59 1.1 pk #include <sparc/sparc/vaddrs.h> 60 1.9 pk #include <sparc/sparc/cpuvar.h> 61 1.1 pk #include <sparc/sparc/iommureg.h> 62 1.16 pk #include <sparc/sparc/iommuvar.h> 63 1.1 pk 64 1.1 pk struct iommu_softc { 65 1.1 pk struct iommureg *sc_reg; 66 1.1 pk u_int sc_pagesize; 67 1.1 pk u_int sc_range; 68 1.21 pk bus_addr_t sc_dvmabase; 69 1.1 pk iopte_t *sc_ptes; 70 1.80 pk int sc_cachecoherent; 71 1.33 pk /* 72 1.33 pk * Note: operations on the extent map are being protected with 73 1.33 pk * splhigh(), since we cannot predict at which interrupt priority 74 1.33 pk * our clients will run. 75 1.33 pk */ 76 1.67 thorpej struct sparc_bus_dma_tag sc_dmatag; 77 1.102 thorpej vmem_t *sc_dvmamap; 78 1.67 thorpej }; 79 1.1 pk 80 1.1 pk /* autoconfiguration driver */ 81 1.82 uwe int iommu_print(void *, const char *); 82 1.94 mrg void iommu_attach(device_t, device_t, void *); 83 1.94 mrg int iommu_match(device_t, cfdata_t, void *); 84 1.1 pk 85 1.60 darrenr #if defined(SUN4M) 86 1.82 uwe static void iommu_copy_prom_entries(struct iommu_softc *); 87 1.60 darrenr #endif 88 1.42 pk 89 1.94 mrg CFATTACH_DECL_NEW(iommu, sizeof(struct iommu_softc), 90 1.72 thorpej iommu_match, iommu_attach, NULL, NULL); 91 1.1 pk 92 1.18 pk /* IOMMU DMA map functions */ 93 1.82 uwe int iommu_dmamap_create(bus_dma_tag_t, bus_size_t, int, bus_size_t, 94 1.82 uwe bus_size_t, int, bus_dmamap_t *); 95 1.82 uwe int iommu_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *, 96 1.82 uwe bus_size_t, struct proc *, int); 97 1.82 uwe int iommu_dmamap_load_mbuf(bus_dma_tag_t, bus_dmamap_t, 98 1.82 uwe struct mbuf *, int); 99 1.82 uwe int iommu_dmamap_load_uio(bus_dma_tag_t, bus_dmamap_t, 100 1.82 uwe struct uio *, int); 101 1.82 uwe int iommu_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t, 102 1.82 uwe bus_dma_segment_t *, int, bus_size_t, int); 103 1.82 uwe void iommu_dmamap_unload(bus_dma_tag_t, bus_dmamap_t); 104 1.82 uwe void iommu_dmamap_sync(bus_dma_tag_t, bus_dmamap_t, bus_addr_t, 105 1.82 uwe bus_size_t, int); 106 1.82 uwe 107 1.82 uwe int iommu_dmamem_map(bus_dma_tag_t, bus_dma_segment_t *, 108 1.85 christos int, size_t, void **, int); 109 1.85 christos void iommu_dmamem_unmap(bus_dma_tag_t, void *, size_t); 110 1.82 uwe paddr_t iommu_dmamem_mmap(bus_dma_tag_t, bus_dma_segment_t *, 111 1.82 uwe int, off_t, int, int); 112 1.67 thorpej int iommu_dvma_alloc(struct iommu_softc *, bus_dmamap_t, vaddr_t, 113 1.67 thorpej bus_size_t, int, bus_addr_t *, bus_size_t *); 114 1.18 pk 115 1.1 pk /* 116 1.1 pk * Print the location of some iommu-attached device (called just 117 1.1 pk * before attaching that device). If `iommu' is not NULL, the 118 1.1 pk * device was found but not configured; print the iommu as well. 119 1.1 pk * Return UNCONF (config_find ignores this if the device was configured). 120 1.1 pk */ 121 1.1 pk int 122 1.82 uwe iommu_print(void *args, const char *iommu) 123 1.1 pk { 124 1.16 pk struct iommu_attach_args *ia = args; 125 1.1 pk 126 1.1 pk if (iommu) 127 1.74 thorpej aprint_normal("%s at %s", ia->iom_name, iommu); 128 1.1 pk return (UNCONF); 129 1.1 pk } 130 1.1 pk 131 1.1 pk int 132 1.94 mrg iommu_match(device_t parent, cfdata_t cf, void *aux) 133 1.1 pk { 134 1.16 pk struct mainbus_attach_args *ma = aux; 135 1.1 pk 136 1.65 thorpej if (CPU_ISSUN4 || CPU_ISSUN4C) 137 1.1 pk return (0); 138 1.68 thorpej return (strcmp(cf->cf_name, ma->ma_name) == 0); 139 1.1 pk } 140 1.1 pk 141 1.1 pk /* 142 1.1 pk * Attach the iommu. 143 1.1 pk */ 144 1.1 pk void 145 1.94 mrg iommu_attach(device_t parent, device_t self, void *aux) 146 1.1 pk { 147 1.4 pk #if defined(SUN4M) 148 1.94 mrg struct iommu_softc *sc = device_private(self); 149 1.16 pk struct mainbus_attach_args *ma = aux; 150 1.67 thorpej struct sparc_bus_dma_tag *dmat = &sc->sc_dmatag; 151 1.43 pk bus_space_handle_t bh; 152 1.21 pk int node; 153 1.53 uwe int js1_implicit_iommu; 154 1.42 pk int i, s; 155 1.43 pk u_int iopte_table_pa; 156 1.43 pk struct pglist mlist; 157 1.43 pk u_int size; 158 1.54 chs struct vm_page *m; 159 1.43 pk vaddr_t va; 160 1.1 pk 161 1.67 thorpej dmat->_cookie = sc; 162 1.67 thorpej dmat->_dmamap_create = iommu_dmamap_create; 163 1.67 thorpej dmat->_dmamap_destroy = _bus_dmamap_destroy; 164 1.67 thorpej dmat->_dmamap_load = iommu_dmamap_load; 165 1.67 thorpej dmat->_dmamap_load_mbuf = iommu_dmamap_load_mbuf; 166 1.67 thorpej dmat->_dmamap_load_uio = iommu_dmamap_load_uio; 167 1.67 thorpej dmat->_dmamap_load_raw = iommu_dmamap_load_raw; 168 1.67 thorpej dmat->_dmamap_unload = iommu_dmamap_unload; 169 1.67 thorpej dmat->_dmamap_sync = iommu_dmamap_sync; 170 1.67 thorpej 171 1.67 thorpej dmat->_dmamem_alloc = _bus_dmamem_alloc; 172 1.67 thorpej dmat->_dmamem_free = _bus_dmamem_free; 173 1.67 thorpej dmat->_dmamem_map = iommu_dmamem_map; 174 1.67 thorpej dmat->_dmamem_unmap = _bus_dmamem_unmap; 175 1.67 thorpej dmat->_dmamem_mmap = iommu_dmamem_mmap; 176 1.53 uwe 177 1.83 uwe /* 178 1.53 uwe * JS1/OF device tree does not have an iommu node and sbus 179 1.53 uwe * node is directly under root. mainbus_attach detects this 180 1.53 uwe * and calls us with sbus node instead so that we can attach 181 1.53 uwe * implicit iommu and attach that sbus node under it. 182 1.53 uwe */ 183 1.16 pk node = ma->ma_node; 184 1.78 pk if (strcmp(prom_getpropstring(node, "name"), "sbus") == 0) 185 1.53 uwe js1_implicit_iommu = 1; 186 1.53 uwe else 187 1.53 uwe js1_implicit_iommu = 0; 188 1.1 pk 189 1.1 pk /* 190 1.1 pk * Map registers into our space. The PROM may have done this 191 1.1 pk * already, but I feel better if we have our own copy. Plus, the 192 1.43 pk * prom doesn't map the entire register set. 193 1.1 pk * 194 1.1 pk * XXX struct iommureg is bigger than ra->ra_len; what are the 195 1.1 pk * other fields for? 196 1.1 pk */ 197 1.67 thorpej if (bus_space_map(ma->ma_bustag, ma->ma_paddr, 198 1.67 thorpej sizeof(struct iommureg), 0, &bh) != 0) { 199 1.16 pk printf("iommu_attach: cannot map registers\n"); 200 1.16 pk return; 201 1.16 pk } 202 1.16 pk sc->sc_reg = (struct iommureg *)bh; 203 1.1 pk 204 1.80 pk sc->sc_cachecoherent = js1_implicit_iommu ? 0 205 1.53 uwe : node_has_property(node, "cache-coherence?"); 206 1.9 pk if (CACHEINFO.c_enabled == 0) /* XXX - is this correct? */ 207 1.80 pk sc->sc_cachecoherent = 0; 208 1.1 pk 209 1.75 thorpej sc->sc_pagesize = js1_implicit_iommu ? PAGE_SIZE 210 1.78 pk : prom_getpropint(node, "page-size", PAGE_SIZE), 211 1.1 pk 212 1.1 pk /* 213 1.43 pk * Allocate memory for I/O pagetables. 214 1.43 pk * This takes 64K of contiguous physical memory to map 64M of 215 1.43 pk * DVMA space (starting at IOMMU_DVMA_BASE). 216 1.43 pk * The table must be aligned on a (-IOMMU_DVMA_BASE/pagesize) 217 1.43 pk * boundary (i.e. 64K for 64M of DVMA space). 218 1.1 pk */ 219 1.1 pk 220 1.43 pk size = ((0 - IOMMU_DVMA_BASE) / sc->sc_pagesize) * sizeof(iopte_t); 221 1.43 pk if (uvm_pglistalloc(size, vm_first_phys, vm_first_phys+vm_num_phys, 222 1.43 pk size, 0, &mlist, 1, 0) != 0) 223 1.43 pk panic("iommu_attach: no memory"); 224 1.43 pk 225 1.81 yamt va = uvm_km_alloc(kernel_map, size, 0, UVM_KMF_VAONLY); 226 1.43 pk if (va == 0) 227 1.43 pk panic("iommu_attach: no memory"); 228 1.43 pk 229 1.43 pk sc->sc_ptes = (iopte_t *)va; 230 1.43 pk 231 1.43 pk m = TAILQ_FIRST(&mlist); 232 1.43 pk iopte_table_pa = VM_PAGE_TO_PHYS(m); 233 1.43 pk 234 1.43 pk /* Map the pages */ 235 1.90 ad for (; m != NULL; m = TAILQ_NEXT(m,pageq.queue)) { 236 1.43 pk paddr_t pa = VM_PAGE_TO_PHYS(m); 237 1.92 cegger pmap_kenter_pa(va, pa | PMAP_NC, 238 1.92 cegger VM_PROT_READ | VM_PROT_WRITE, 0); 239 1.75 thorpej va += PAGE_SIZE; 240 1.43 pk } 241 1.55 chris pmap_update(pmap_kernel()); 242 1.1 pk 243 1.1 pk /* 244 1.42 pk * Copy entries from current IOMMU table. 245 1.42 pk * XXX - Why do we need to do this? 246 1.1 pk */ 247 1.42 pk iommu_copy_prom_entries(sc); 248 1.1 pk 249 1.1 pk /* 250 1.1 pk * Now we can install our new pagetable into the IOMMU 251 1.1 pk */ 252 1.22 pk sc->sc_range = 0 - IOMMU_DVMA_BASE; 253 1.22 pk sc->sc_dvmabase = IOMMU_DVMA_BASE; 254 1.1 pk 255 1.1 pk /* calculate log2(sc->sc_range/16MB) */ 256 1.1 pk i = ffs(sc->sc_range/(1 << 24)) - 1; 257 1.1 pk if ((1 << i) != (sc->sc_range/(1 << 24))) 258 1.69 provos panic("iommu: bad range: %d", i); 259 1.1 pk 260 1.1 pk s = splhigh(); 261 1.1 pk IOMMU_FLUSHALL(sc); 262 1.1 pk 263 1.43 pk /* Load range and physical address of PTEs */ 264 1.1 pk sc->sc_reg->io_cr = (sc->sc_reg->io_cr & ~IOMMU_CTL_RANGE) | 265 1.1 pk (i << IOMMU_CTL_RANGESHFT) | IOMMU_CTL_ME; 266 1.43 pk sc->sc_reg->io_bar = (iopte_table_pa >> 4) & IOMMU_BAR_IBA; 267 1.1 pk 268 1.1 pk IOMMU_FLUSHALL(sc); 269 1.1 pk splx(s); 270 1.1 pk 271 1.13 fair printf(": version 0x%x/0x%x, page-size %d, range %dMB\n", 272 1.1 pk (sc->sc_reg->io_cr & IOMMU_CTL_VER) >> 24, 273 1.1 pk (sc->sc_reg->io_cr & IOMMU_CTL_IMPL) >> 28, 274 1.1 pk sc->sc_pagesize, 275 1.1 pk sc->sc_range >> 20); 276 1.1 pk 277 1.102 thorpej sc->sc_dvmamap = vmem_create("iommudvma", 278 1.102 thorpej IOMMU_DVMA_BASE, 279 1.102 thorpej IOMMU_DVMA_END - IOMMU_DVMA_BASE, 280 1.102 thorpej PAGE_SIZE, /* quantum */ 281 1.102 thorpej NULL, /* importfn */ 282 1.102 thorpej NULL, /* releasefn */ 283 1.102 thorpej NULL, /* source */ 284 1.102 thorpej 0, /* qcache_max */ 285 1.102 thorpej VM_SLEEP, 286 1.102 thorpej IPL_VM); 287 1.53 uwe 288 1.101 thorpej devhandle_t selfh = device_handle(self); 289 1.101 thorpej 290 1.53 uwe /* 291 1.53 uwe * If we are attaching implicit iommu on JS1/OF we do not have 292 1.53 uwe * an iommu node to traverse, instead mainbus_attach passed us 293 1.53 uwe * sbus node in ma.ma_node. Attach it as the only iommu child. 294 1.53 uwe */ 295 1.53 uwe if (js1_implicit_iommu) { 296 1.53 uwe struct iommu_attach_args ia; 297 1.66 thorpej struct openprom_addr sbus_iommu_reg = { 0, 0x10001000, 0x28 }; 298 1.53 uwe 299 1.91 cegger memset(&ia, 0, sizeof ia); 300 1.53 uwe 301 1.53 uwe /* Propagate BUS & DMA tags */ 302 1.53 uwe ia.iom_bustag = ma->ma_bustag; 303 1.67 thorpej ia.iom_dmatag = &sc->sc_dmatag; 304 1.53 uwe 305 1.53 uwe ia.iom_name = "sbus"; 306 1.53 uwe ia.iom_node = node; 307 1.53 uwe ia.iom_reg = &sbus_iommu_reg; 308 1.53 uwe ia.iom_nreg = 1; 309 1.53 uwe 310 1.98 thorpej config_found(self, (void *)&ia, iommu_print, 311 1.101 thorpej CFARGS(.devhandle = prom_node_to_devhandle(selfh, node))); 312 1.53 uwe return; 313 1.53 uwe } 314 1.1 pk 315 1.1 pk /* 316 1.1 pk * Loop through ROM children (expect Sbus among them). 317 1.1 pk */ 318 1.1 pk for (node = firstchild(node); node; node = nextsibling(node)) { 319 1.16 pk struct iommu_attach_args ia; 320 1.16 pk 321 1.91 cegger memset(&ia, 0, sizeof ia); 322 1.78 pk ia.iom_name = prom_getpropstring(node, "name"); 323 1.16 pk 324 1.16 pk /* Propagate BUS & DMA tags */ 325 1.16 pk ia.iom_bustag = ma->ma_bustag; 326 1.67 thorpej ia.iom_dmatag = &sc->sc_dmatag; 327 1.27 pk 328 1.16 pk ia.iom_node = node; 329 1.27 pk 330 1.27 pk ia.iom_reg = NULL; 331 1.78 pk prom_getprop(node, "reg", sizeof(struct openprom_addr), 332 1.77 mrg &ia.iom_nreg, &ia.iom_reg); 333 1.27 pk 334 1.98 thorpej config_found(self, (void *)&ia, iommu_print, 335 1.101 thorpej CFARGS(.devhandle = prom_node_to_devhandle(selfh, node))); 336 1.27 pk if (ia.iom_reg != NULL) 337 1.27 pk free(ia.iom_reg, M_DEVBUF); 338 1.1 pk } 339 1.4 pk #endif 340 1.1 pk } 341 1.1 pk 342 1.60 darrenr #if defined(SUN4M) 343 1.42 pk static void 344 1.82 uwe iommu_copy_prom_entries(struct iommu_softc *sc) 345 1.42 pk { 346 1.42 pk u_int pbase, pa; 347 1.42 pk u_int range; 348 1.42 pk iopte_t *tpte_p; 349 1.42 pk u_int pagesz = sc->sc_pagesize; 350 1.42 pk int use_ac = (cpuinfo.cpu_impl == 4 && cpuinfo.mxcc); 351 1.42 pk u_int mmupcr_save; 352 1.42 pk 353 1.42 pk /* 354 1.42 pk * We read in the original table using MMU bypass and copy all 355 1.42 pk * of its entries to the appropriate place in our new table, 356 1.42 pk * even if the sizes are different. 357 1.42 pk * This is pretty easy since we know DVMA ends at 0xffffffff. 358 1.42 pk */ 359 1.42 pk 360 1.42 pk range = (1 << 24) << 361 1.42 pk ((sc->sc_reg->io_cr & IOMMU_CTL_RANGE) >> IOMMU_CTL_RANGESHFT); 362 1.42 pk 363 1.42 pk pbase = (sc->sc_reg->io_bar & IOMMU_BAR_IBA) << 364 1.42 pk (14 - IOMMU_BAR_IBASHFT); 365 1.42 pk 366 1.42 pk if (use_ac) { 367 1.42 pk /* 368 1.42 pk * Set MMU AC bit so we'll still read from the cache 369 1.42 pk * in by-pass mode. 370 1.42 pk */ 371 1.42 pk mmupcr_save = lda(SRMMU_PCR, ASI_SRMMU); 372 1.42 pk sta(SRMMU_PCR, ASI_SRMMU, mmupcr_save | VIKING_PCR_AC); 373 1.42 pk } else 374 1.86 msaitoh mmupcr_save = 0; /* XXX - avoid GCC `uninitialized' warning */ 375 1.42 pk 376 1.42 pk /* Flush entire IOMMU TLB before messing with the in-memory tables */ 377 1.42 pk IOMMU_FLUSHALL(sc); 378 1.42 pk 379 1.42 pk /* 380 1.42 pk * tpte_p = top of our PTE table 381 1.42 pk * pa = top of current PTE table 382 1.42 pk * Then work downwards and copy entries until we hit the bottom 383 1.42 pk * of either table. 384 1.42 pk */ 385 1.42 pk for (tpte_p = &sc->sc_ptes[((0 - IOMMU_DVMA_BASE)/pagesz) - 1], 386 1.42 pk pa = (u_int)pbase + (range/pagesz - 1)*sizeof(iopte_t); 387 1.42 pk tpte_p >= &sc->sc_ptes[0] && pa >= (u_int)pbase; 388 1.42 pk tpte_p--, pa -= sizeof(iopte_t)) { 389 1.42 pk 390 1.42 pk *tpte_p = lda(pa, ASI_BYPASS); 391 1.42 pk } 392 1.42 pk 393 1.42 pk if (use_ac) { 394 1.42 pk /* restore mmu after bug-avoidance */ 395 1.42 pk sta(SRMMU_PCR, ASI_SRMMU, mmupcr_save); 396 1.42 pk } 397 1.42 pk } 398 1.60 darrenr #endif 399 1.42 pk 400 1.67 thorpej static void 401 1.67 thorpej iommu_enter(struct iommu_softc *sc, bus_addr_t dva, paddr_t pa) 402 1.1 pk { 403 1.1 pk int pte; 404 1.1 pk 405 1.39 pk /* This routine relies on the fact that sc->sc_pagesize == PAGE_SIZE */ 406 1.39 pk 407 1.39 pk #ifdef DIAGNOSTIC 408 1.39 pk if (dva < sc->sc_dvmabase) 409 1.39 pk panic("iommu_enter: dva 0x%lx not in DVMA space", (long)dva); 410 1.1 pk #endif 411 1.1 pk 412 1.1 pk pte = atop(pa) << IOPTE_PPNSHFT; 413 1.1 pk pte &= IOPTE_PPN; 414 1.80 pk pte |= IOPTE_V | IOPTE_W | (sc->sc_cachecoherent ? IOPTE_C : 0); 415 1.39 pk sc->sc_ptes[atop(dva - sc->sc_dvmabase)] = pte; 416 1.39 pk IOMMU_FLUSHPAGE(sc, dva); 417 1.1 pk } 418 1.1 pk 419 1.1 pk /* 420 1.67 thorpej * iommu_remove: removes mappings created by iommu_enter 421 1.1 pk */ 422 1.67 thorpej static void 423 1.67 thorpej iommu_remove(struct iommu_softc *sc, bus_addr_t dva, bus_size_t len) 424 1.1 pk { 425 1.21 pk u_int pagesz = sc->sc_pagesize; 426 1.21 pk bus_addr_t base = sc->sc_dvmabase; 427 1.1 pk 428 1.1 pk #ifdef DEBUG 429 1.42 pk if (dva < base) 430 1.44 cjs panic("iommu_remove: va 0x%lx not in DVMA space", (long)dva); 431 1.1 pk #endif 432 1.1 pk 433 1.21 pk while ((long)len > 0) { 434 1.1 pk #ifdef notyet 435 1.1 pk #ifdef DEBUG 436 1.42 pk if ((sc->sc_ptes[atop(dva - base)] & IOPTE_V) == 0) 437 1.42 pk panic("iommu_remove: clearing invalid pte at dva 0x%lx", 438 1.42 pk (long)dva); 439 1.1 pk #endif 440 1.1 pk #endif 441 1.42 pk sc->sc_ptes[atop(dva - base)] = 0; 442 1.42 pk IOMMU_FLUSHPAGE(sc, dva); 443 1.21 pk len -= pagesz; 444 1.42 pk dva += pagesz; 445 1.1 pk } 446 1.1 pk } 447 1.1 pk 448 1.1 pk #if 0 /* These registers aren't there??? */ 449 1.1 pk void 450 1.82 uwe iommu_error(void) 451 1.1 pk { 452 1.1 pk struct iommu_softc *sc = X; 453 1.1 pk struct iommureg *iop = sc->sc_reg; 454 1.1 pk 455 1.13 fair printf("iommu: afsr 0x%x, afar 0x%x\n", iop->io_afsr, iop->io_afar); 456 1.13 fair printf("iommu: mfsr 0x%x, mfar 0x%x\n", iop->io_mfsr, iop->io_mfar); 457 1.1 pk } 458 1.82 uwe 459 1.1 pk int 460 1.82 uwe iommu_alloc(u_int va, u_int len) 461 1.1 pk { 462 1.1 pk struct iommu_softc *sc = X; 463 1.35 thorpej int off, tva, iovaddr, pte; 464 1.35 thorpej paddr_t pa; 465 1.1 pk 466 1.1 pk off = (int)va & PGOFSET; 467 1.1 pk len = round_page(len + off); 468 1.1 pk va -= off; 469 1.1 pk 470 1.1 pk if ((int)sc->sc_dvmacur + len > 0) 471 1.1 pk sc->sc_dvmacur = sc->sc_dvmabase; 472 1.1 pk 473 1.1 pk iovaddr = tva = sc->sc_dvmacur; 474 1.1 pk sc->sc_dvmacur += len; 475 1.1 pk while (len) { 476 1.35 thorpej (void) pmap_extract(pmap_kernel(), va, &pa); 477 1.1 pk 478 1.1 pk #define IOMMU_PPNSHIFT 8 479 1.1 pk #define IOMMU_V 0x00000002 480 1.1 pk #define IOMMU_W 0x00000004 481 1.1 pk 482 1.1 pk pte = atop(pa) << IOMMU_PPNSHIFT; 483 1.1 pk pte |= IOMMU_V | IOMMU_W; 484 1.1 pk sta(sc->sc_ptes + atop(tva - sc->sc_dvmabase), ASI_BYPASS, pte); 485 1.1 pk sc->sc_reg->io_flushpage = tva; 486 1.75 thorpej len -= PAGE_SIZE; 487 1.75 thorpej va += PAGE_SIZE; 488 1.75 thorpej tva += PAGE_SIZE; 489 1.1 pk } 490 1.1 pk return iovaddr + off; 491 1.1 pk } 492 1.1 pk #endif 493 1.18 pk 494 1.18 pk 495 1.18 pk /* 496 1.50 pk * IOMMU DMA map functions. 497 1.45 pk */ 498 1.45 pk int 499 1.82 uwe iommu_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments, 500 1.82 uwe bus_size_t maxsegsz, bus_size_t boundary, int flags, 501 1.82 uwe bus_dmamap_t *dmamp) 502 1.45 pk { 503 1.45 pk bus_dmamap_t map; 504 1.45 pk int error; 505 1.45 pk 506 1.45 pk if ((error = _bus_dmamap_create(t, size, nsegments, maxsegsz, 507 1.45 pk boundary, flags, &map)) != 0) 508 1.45 pk return (error); 509 1.45 pk 510 1.45 pk if ((flags & BUS_DMA_24BIT) != 0) { 511 1.45 pk /* Limit this map to the range usable by `24-bit' devices */ 512 1.45 pk map->_dm_ex_start = D24_DVMA_BASE; 513 1.102 thorpej map->_dm_ex_end = D24_DVMA_END - 1; 514 1.45 pk } else { 515 1.45 pk /* Enable allocations from the entire map */ 516 1.102 thorpej map->_dm_ex_start = VMEM_ADDR_MIN; 517 1.102 thorpej map->_dm_ex_end = VMEM_ADDR_MAX; 518 1.45 pk } 519 1.45 pk 520 1.45 pk *dmamp = map; 521 1.45 pk return (0); 522 1.45 pk } 523 1.45 pk 524 1.45 pk /* 525 1.41 pk * Internal routine to allocate space in the IOMMU map. 526 1.18 pk */ 527 1.18 pk int 528 1.82 uwe iommu_dvma_alloc(struct iommu_softc *sc, bus_dmamap_t map, 529 1.82 uwe vaddr_t va, bus_size_t len, int flags, 530 1.82 uwe bus_addr_t *dvap, bus_size_t *sgsizep) 531 1.18 pk { 532 1.26 pk bus_size_t sgsize; 533 1.102 thorpej u_long align, voff; 534 1.102 thorpej vmem_addr_t dvaddr; 535 1.102 thorpej int error; 536 1.41 pk int pagesz = PAGE_SIZE; 537 1.18 pk 538 1.18 pk /* 539 1.24 pk * Remember page offset, then truncate the buffer address to 540 1.24 pk * a page boundary. 541 1.24 pk */ 542 1.41 pk voff = va & (pagesz - 1); 543 1.41 pk va &= -pagesz; 544 1.24 pk 545 1.39 pk if (len > map->_dm_size) 546 1.18 pk return (EINVAL); 547 1.18 pk 548 1.41 pk sgsize = (len + voff + pagesz - 1) & -pagesz; 549 1.45 pk align = dvma_cachealign ? dvma_cachealign : map->_dm_align; 550 1.18 pk 551 1.102 thorpej const vm_flag_t vmflags = VM_BESTFIT | 552 1.102 thorpej ((flags & BUS_DMA_NOWAIT) ? VM_NOSLEEP : VM_SLEEP); 553 1.102 thorpej 554 1.102 thorpej error = vmem_xalloc(sc->sc_dvmamap, sgsize, 555 1.102 thorpej align, /* alignment */ 556 1.102 thorpej va & (align-1), /* phase */ 557 1.102 thorpej map->_dm_boundary, /* nocross */ 558 1.102 thorpej map->_dm_ex_start, /* minaddr */ 559 1.102 thorpej map->_dm_ex_end, /* maxaddr */ 560 1.102 thorpej vmflags, 561 1.102 thorpej &dvaddr); 562 1.102 thorpej 563 1.56 eeh *dvap = (bus_addr_t)dvaddr; 564 1.39 pk *sgsizep = sgsize; 565 1.39 pk return (error); 566 1.39 pk } 567 1.39 pk 568 1.39 pk /* 569 1.50 pk * Prepare buffer for DMA transfer. 570 1.39 pk */ 571 1.39 pk int 572 1.82 uwe iommu_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, 573 1.82 uwe void *buf, bus_size_t buflen, 574 1.82 uwe struct proc *p, int flags) 575 1.39 pk { 576 1.67 thorpej struct iommu_softc *sc = t->_cookie; 577 1.39 pk bus_size_t sgsize; 578 1.39 pk bus_addr_t dva; 579 1.39 pk vaddr_t va = (vaddr_t)buf; 580 1.41 pk int pagesz = PAGE_SIZE; 581 1.39 pk pmap_t pmap; 582 1.39 pk int error; 583 1.39 pk 584 1.39 pk /* 585 1.39 pk * Make sure that on error condition we return "no valid mappings". 586 1.39 pk */ 587 1.39 pk map->dm_nsegs = 0; 588 1.39 pk 589 1.39 pk /* Allocate IOMMU resources */ 590 1.67 thorpej if ((error = iommu_dvma_alloc(sc, map, va, buflen, flags, 591 1.39 pk &dva, &sgsize)) != 0) 592 1.33 pk return (error); 593 1.18 pk 594 1.87 macallan if ((sc->sc_cachecoherent == 0) || 595 1.88 macallan (curcpu()->cacheinfo.ec_totalsize == 0)) 596 1.80 pk cache_flush(buf, buflen); /* XXX - move to bus_dma_sync? */ 597 1.18 pk 598 1.18 pk /* 599 1.18 pk * We always use just one segment. 600 1.18 pk */ 601 1.18 pk map->dm_mapsize = buflen; 602 1.18 pk map->dm_nsegs = 1; 603 1.41 pk map->dm_segs[0].ds_addr = dva + (va & (pagesz - 1)); 604 1.26 pk map->dm_segs[0].ds_len = buflen; 605 1.41 pk map->dm_segs[0]._ds_sgsize = sgsize; 606 1.18 pk 607 1.18 pk if (p != NULL) 608 1.18 pk pmap = p->p_vmspace->vm_map.pmap; 609 1.18 pk else 610 1.18 pk pmap = pmap_kernel(); 611 1.18 pk 612 1.24 pk for (; sgsize != 0; ) { 613 1.35 thorpej paddr_t pa; 614 1.18 pk /* 615 1.18 pk * Get the physical address for this page. 616 1.18 pk */ 617 1.79 pk if (!pmap_extract(pmap, va, &pa)) { 618 1.79 pk iommu_dmamap_unload(t, map); 619 1.79 pk return (EFAULT); 620 1.79 pk } 621 1.18 pk 622 1.67 thorpej iommu_enter(sc, dva, pa); 623 1.24 pk 624 1.41 pk dva += pagesz; 625 1.41 pk va += pagesz; 626 1.41 pk sgsize -= pagesz; 627 1.18 pk } 628 1.24 pk 629 1.18 pk return (0); 630 1.18 pk } 631 1.18 pk 632 1.18 pk /* 633 1.18 pk * Like _bus_dmamap_load(), but for mbufs. 634 1.18 pk */ 635 1.18 pk int 636 1.82 uwe iommu_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, 637 1.82 uwe struct mbuf *m, int flags) 638 1.18 pk { 639 1.18 pk 640 1.41 pk panic("_bus_dmamap_load_mbuf: not implemented"); 641 1.18 pk } 642 1.18 pk 643 1.18 pk /* 644 1.18 pk * Like _bus_dmamap_load(), but for uios. 645 1.18 pk */ 646 1.18 pk int 647 1.82 uwe iommu_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map, 648 1.82 uwe struct uio *uio, int flags) 649 1.18 pk { 650 1.18 pk 651 1.18 pk panic("_bus_dmamap_load_uio: not implemented"); 652 1.18 pk } 653 1.18 pk 654 1.18 pk /* 655 1.18 pk * Like _bus_dmamap_load(), but for raw memory allocated with 656 1.18 pk * bus_dmamem_alloc(). 657 1.18 pk */ 658 1.18 pk int 659 1.82 uwe iommu_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map, 660 1.82 uwe bus_dma_segment_t *segs, int nsegs, bus_size_t size, 661 1.82 uwe int flags) 662 1.18 pk { 663 1.67 thorpej struct iommu_softc *sc = t->_cookie; 664 1.54 chs struct vm_page *m; 665 1.21 pk paddr_t pa; 666 1.24 pk bus_addr_t dva; 667 1.39 pk bus_size_t sgsize; 668 1.18 pk struct pglist *mlist; 669 1.40 pk int pagesz = PAGE_SIZE; 670 1.39 pk int error; 671 1.18 pk 672 1.39 pk map->dm_nsegs = 0; 673 1.18 pk 674 1.39 pk /* Allocate IOMMU resources */ 675 1.67 thorpej if ((error = iommu_dvma_alloc(sc, map, segs[0]._ds_va, size, 676 1.39 pk flags, &dva, &sgsize)) != 0) 677 1.33 pk return (error); 678 1.18 pk 679 1.18 pk /* 680 1.39 pk * Note DVMA address in case bus_dmamem_map() is called later. 681 1.39 pk * It can then insure cache coherency by choosing a KVA that 682 1.39 pk * is aligned to `ds_addr'. 683 1.18 pk */ 684 1.24 pk segs[0].ds_addr = dva; 685 1.18 pk segs[0].ds_len = size; 686 1.18 pk 687 1.39 pk map->dm_segs[0].ds_addr = dva; 688 1.39 pk map->dm_segs[0].ds_len = size; 689 1.41 pk map->dm_segs[0]._ds_sgsize = sgsize; 690 1.39 pk 691 1.39 pk /* Map physical pages into IOMMU */ 692 1.18 pk mlist = segs[0]._ds_mlist; 693 1.90 ad for (m = TAILQ_FIRST(mlist); m != NULL; m = TAILQ_NEXT(m,pageq.queue)) { 694 1.39 pk if (sgsize == 0) 695 1.39 pk panic("iommu_dmamap_load_raw: size botch"); 696 1.21 pk pa = VM_PAGE_TO_PHYS(m); 697 1.67 thorpej iommu_enter(sc, dva, pa); 698 1.40 pk dva += pagesz; 699 1.40 pk sgsize -= pagesz; 700 1.18 pk } 701 1.18 pk 702 1.39 pk map->dm_nsegs = 1; 703 1.39 pk map->dm_mapsize = size; 704 1.39 pk 705 1.18 pk return (0); 706 1.18 pk } 707 1.18 pk 708 1.18 pk /* 709 1.39 pk * Unload an IOMMU DMA map. 710 1.18 pk */ 711 1.18 pk void 712 1.82 uwe iommu_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map) 713 1.18 pk { 714 1.67 thorpej struct iommu_softc *sc = t->_cookie; 715 1.39 pk bus_dma_segment_t *segs = map->dm_segs; 716 1.39 pk int nsegs = map->dm_nsegs; 717 1.39 pk bus_addr_t dva; 718 1.18 pk bus_size_t len; 719 1.102 thorpej int i; 720 1.39 pk 721 1.39 pk for (i = 0; i < nsegs; i++) { 722 1.41 pk dva = segs[i].ds_addr & -PAGE_SIZE; 723 1.41 pk len = segs[i]._ds_sgsize; 724 1.39 pk 725 1.67 thorpej iommu_remove(sc, dva, len); 726 1.102 thorpej vmem_xfree(sc->sc_dvmamap, dva, len); 727 1.39 pk } 728 1.18 pk 729 1.39 pk /* Mark the mappings as invalid. */ 730 1.39 pk map->dm_mapsize = 0; 731 1.39 pk map->dm_nsegs = 0; 732 1.39 pk } 733 1.18 pk 734 1.39 pk /* 735 1.39 pk * DMA map synchronization. 736 1.39 pk */ 737 1.39 pk void 738 1.82 uwe iommu_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, 739 1.82 uwe bus_addr_t offset, bus_size_t len, int ops) 740 1.39 pk { 741 1.18 pk 742 1.18 pk /* 743 1.39 pk * XXX Should flush CPU write buffers. 744 1.18 pk */ 745 1.18 pk } 746 1.18 pk 747 1.18 pk /* 748 1.39 pk * Map DMA-safe memory. 749 1.18 pk */ 750 1.18 pk int 751 1.82 uwe iommu_dmamem_map(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs, 752 1.85 christos size_t size, void **kvap, int flags) 753 1.18 pk { 754 1.80 pk struct iommu_softc *sc = t->_cookie; 755 1.54 chs struct vm_page *m; 756 1.39 pk vaddr_t va; 757 1.18 pk bus_addr_t addr; 758 1.18 pk struct pglist *mlist; 759 1.18 pk int cbit; 760 1.18 pk u_long align; 761 1.40 pk int pagesz = PAGE_SIZE; 762 1.18 pk 763 1.18 pk if (nsegs != 1) 764 1.18 pk panic("iommu_dmamem_map: nsegs = %d", nsegs); 765 1.18 pk 766 1.80 pk cbit = sc->sc_cachecoherent ? 0 : PMAP_NC; 767 1.40 pk align = dvma_cachealign ? dvma_cachealign : pagesz; 768 1.18 pk 769 1.18 pk size = round_page(size); 770 1.18 pk 771 1.18 pk /* 772 1.39 pk * In case the segment has already been loaded by 773 1.39 pk * iommu_dmamap_load_raw(), find a region of kernel virtual 774 1.100 andvar * addresses that can accommodate our alignment requirements. 775 1.18 pk */ 776 1.40 pk va = _bus_dma_valloc_skewed(size, 0, align, 777 1.40 pk segs[0].ds_addr & (align - 1)); 778 1.39 pk if (va == 0) 779 1.18 pk return (ENOMEM); 780 1.18 pk 781 1.39 pk segs[0]._ds_va = va; 782 1.85 christos *kvap = (void *)va; 783 1.18 pk 784 1.39 pk /* 785 1.39 pk * Map the pages allocated in _bus_dmamem_alloc() to the 786 1.39 pk * kernel virtual address space. 787 1.39 pk */ 788 1.18 pk mlist = segs[0]._ds_mlist; 789 1.90 ad for (m = TAILQ_FIRST(mlist); m != NULL; m = TAILQ_NEXT(m,pageq.queue)) { 790 1.18 pk 791 1.18 pk if (size == 0) 792 1.18 pk panic("iommu_dmamem_map: size botch"); 793 1.18 pk 794 1.18 pk addr = VM_PAGE_TO_PHYS(m); 795 1.92 cegger pmap_kenter_pa(va, addr | cbit, 796 1.92 cegger VM_PROT_READ | VM_PROT_WRITE, 0); 797 1.18 pk #if 0 798 1.18 pk if (flags & BUS_DMA_COHERENT) 799 1.18 pk /* XXX */; 800 1.18 pk #endif 801 1.40 pk va += pagesz; 802 1.40 pk size -= pagesz; 803 1.18 pk } 804 1.55 chris pmap_update(pmap_kernel()); 805 1.18 pk 806 1.18 pk return (0); 807 1.18 pk } 808 1.18 pk 809 1.81 yamt void 810 1.85 christos iommu_dmamem_unmap(bus_dma_tag_t t, void *kva, size_t size) 811 1.81 yamt { 812 1.81 yamt 813 1.81 yamt #ifdef DIAGNOSTIC 814 1.81 yamt if ((u_long)kva & PAGE_MASK) 815 1.81 yamt panic("iommu_dmamem_unmap"); 816 1.81 yamt #endif 817 1.81 yamt 818 1.81 yamt size = round_page(size); 819 1.81 yamt pmap_kremove((vaddr_t)kva, size); 820 1.81 yamt pmap_update(pmap_kernel()); 821 1.81 yamt uvm_unmap(kernel_map, (vaddr_t)kva, (vaddr_t)kva + size); 822 1.81 yamt } 823 1.81 yamt 824 1.81 yamt 825 1.18 pk /* 826 1.39 pk * mmap(2)'ing DMA-safe memory. 827 1.18 pk */ 828 1.46 simonb paddr_t 829 1.82 uwe iommu_dmamem_mmap(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs, 830 1.82 uwe off_t off, int prot, int flags) 831 1.18 pk { 832 1.18 pk 833 1.18 pk panic("_bus_dmamem_mmap: not implemented"); 834 1.18 pk } 835