1 1.11 riastrad /* $NetBSD: rumpdev_bus_dma.c,v 1.11 2022/02/13 19:20:41 riastradh Exp $ */ 2 1.1 pooka 3 1.1 pooka /*- 4 1.1 pooka * Copyright (c) 2013 Antti Kantee 5 1.1 pooka * All rights reserved. 6 1.1 pooka * 7 1.1 pooka * Redistribution and use in source and binary forms, with or without 8 1.1 pooka * modification, are permitted provided that the following conditions 9 1.1 pooka * are met: 10 1.1 pooka * 1. Redistributions of source code must retain the above copyright 11 1.1 pooka * notice, this list of conditions and the following disclaimer. 12 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 pooka * notice, this list of conditions and the following disclaimer in the 14 1.1 pooka * documentation and/or other materials provided with the distribution. 15 1.1 pooka * 16 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS 17 1.1 pooka * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 1.1 pooka * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.1 pooka * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 1.1 pooka * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 1.1 pooka * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 1.1 pooka * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 1.1 pooka * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 1.1 pooka * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 1.1 pooka * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 1.1 pooka * POSSIBILITY OF SUCH DAMAGE. 27 1.1 pooka */ 28 1.1 pooka 29 1.1 pooka /*- 30 1.1 pooka * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc. 31 1.1 pooka * All rights reserved. 32 1.1 pooka * 33 1.1 pooka * This code is derived from software contributed to The NetBSD Foundation 34 1.1 pooka * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 35 1.1 pooka * NASA Ames Research Center. 36 1.1 pooka * 37 1.1 pooka * Redistribution and use in source and binary forms, with or without 38 1.1 pooka * modification, are permitted provided that the following conditions 39 1.1 pooka * are met: 40 1.1 pooka * 1. Redistributions of source code must retain the above copyright 41 1.1 pooka * notice, this list of conditions and the following disclaimer. 42 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright 43 1.1 pooka * notice, this list of conditions and the following disclaimer in the 44 1.1 pooka * documentation and/or other materials provided with the distribution. 45 1.1 pooka * 46 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 47 1.1 pooka * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 48 1.1 pooka * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 49 1.1 pooka * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 50 1.1 pooka * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 51 1.1 pooka * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 52 1.1 pooka * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 53 1.1 pooka * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 54 1.1 pooka * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 55 1.1 pooka * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 56 1.1 pooka * POSSIBILITY OF SUCH DAMAGE. 57 1.1 pooka */ 58 1.1 pooka 59 1.1 pooka /* 60 1.1 pooka * bus_dma(9) implementation which runs on top of rump kernel hypercalls. 61 1.1 pooka * It's essentially the same as the PowerPC implementation its based on, 62 1.1 pooka * except with some indirection and PowerPC MD features removed. 63 1.1 pooka * This should/could be expected to run on x86, other archs may need 64 1.1 pooka * some cache flushing hooks. 65 1.1 pooka * 66 1.1 pooka * From sys/arch/powerpc/powerpc/bus_dma.c: 67 1.1 pooka * NetBSD: bus_dma.c,v 1.46 2012/02/01 09:54:03 matt Exp 68 1.1 pooka */ 69 1.1 pooka 70 1.7 alnsn #include <sys/cdefs.h> 71 1.11 riastrad __KERNEL_RCSID(0, "$NetBSD: rumpdev_bus_dma.c,v 1.11 2022/02/13 19:20:41 riastradh Exp $"); 72 1.7 alnsn 73 1.1 pooka #include <sys/param.h> 74 1.1 pooka #include <sys/systm.h> 75 1.1 pooka #include <sys/kernel.h> 76 1.1 pooka #include <sys/device.h> 77 1.1 pooka #include <sys/kmem.h> 78 1.1 pooka #include <sys/proc.h> 79 1.1 pooka #include <sys/mbuf.h> 80 1.1 pooka #include <sys/bus.h> 81 1.1 pooka #include <sys/intr.h> 82 1.1 pooka 83 1.1 pooka #include "pci_user.h" 84 1.1 pooka 85 1.1 pooka int _bus_dmamap_load_buffer (bus_dma_tag_t, bus_dmamap_t, void *, 86 1.1 pooka bus_size_t, struct vmspace *, int, paddr_t *, int *, int); 87 1.1 pooka 88 1.1 pooka /* 89 1.1 pooka * Common function for DMA map creation. May be called by bus-specific 90 1.1 pooka * DMA map creation functions. 91 1.1 pooka */ 92 1.1 pooka int 93 1.1 pooka bus_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments, 94 1.1 pooka bus_size_t maxsegsz, bus_size_t boundary, int flags, 95 1.1 pooka bus_dmamap_t *dmamp) 96 1.1 pooka { 97 1.1 pooka bus_dmamap_t map; 98 1.1 pooka void *mapstore; 99 1.1 pooka size_t mapsize; 100 1.1 pooka 101 1.1 pooka /* 102 1.1 pooka * Allocate and initialize the DMA map. The end of the map 103 1.1 pooka * is a variable-sized array of segments, so we allocate enough 104 1.1 pooka * room for them in one shot. 105 1.1 pooka * 106 1.1 pooka * Note we don't preserve the WAITOK or NOWAIT flags. Preservation 107 1.1 pooka * of ALLOCNOW notifies others that we've reserved these resources, 108 1.1 pooka * and they are not to be freed. 109 1.1 pooka * 110 1.1 pooka * The bus_dmamap_t includes one bus_dma_segment_t, hence 111 1.1 pooka * the (nsegments - 1). 112 1.1 pooka */ 113 1.1 pooka mapsize = sizeof(*map) + sizeof(bus_dma_segment_t [nsegments - 1]); 114 1.1 pooka if ((mapstore = kmem_intr_alloc(mapsize, 115 1.1 pooka (flags & BUS_DMA_NOWAIT) ? KM_NOSLEEP : KM_SLEEP)) == NULL) 116 1.1 pooka return (ENOMEM); 117 1.1 pooka 118 1.1 pooka memset(mapstore, 0, mapsize); 119 1.1 pooka map = (void *)mapstore; 120 1.1 pooka map->_dm_size = size; 121 1.1 pooka map->_dm_segcnt = nsegments; 122 1.1 pooka map->_dm_maxmaxsegsz = maxsegsz; 123 1.1 pooka map->_dm_boundary = boundary; 124 1.1 pooka map->_dm_bounce_thresh = 0; 125 1.1 pooka map->_dm_flags = flags & ~(BUS_DMA_WAITOK|BUS_DMA_NOWAIT); 126 1.1 pooka map->dm_maxsegsz = maxsegsz; 127 1.1 pooka map->dm_mapsize = 0; /* no valid mappings */ 128 1.1 pooka map->dm_nsegs = 0; 129 1.1 pooka 130 1.1 pooka *dmamp = map; 131 1.1 pooka return (0); 132 1.1 pooka } 133 1.1 pooka 134 1.1 pooka /* 135 1.1 pooka * Common function for DMA map destruction. May be called by bus-specific 136 1.1 pooka * DMA map destruction functions. 137 1.1 pooka */ 138 1.1 pooka void 139 1.1 pooka bus_dmamap_destroy(bus_dma_tag_t t, bus_dmamap_t map) 140 1.1 pooka { 141 1.1 pooka 142 1.1 pooka size_t mapsize = sizeof(*map) 143 1.1 pooka + sizeof(bus_dma_segment_t [map->_dm_segcnt - 1]); 144 1.1 pooka kmem_intr_free(map, mapsize); 145 1.1 pooka } 146 1.1 pooka 147 1.1 pooka /* 148 1.1 pooka * Utility function to load a linear buffer. lastaddrp holds state 149 1.1 pooka * between invocations (for multiple-buffer loads). segp contains 150 1.1 pooka * the starting segment on entrance, and the ending segment on exit. 151 1.1 pooka * first indicates if this is the first invocation of this function. 152 1.1 pooka */ 153 1.1 pooka int 154 1.1 pooka _bus_dmamap_load_buffer(bus_dma_tag_t t, bus_dmamap_t map, 155 1.1 pooka void *buf, bus_size_t buflen, struct vmspace *vm, int flags, 156 1.1 pooka paddr_t *lastaddrp, int *segp, int first) 157 1.1 pooka { 158 1.1 pooka bus_size_t sgsize; 159 1.1 pooka bus_addr_t curaddr, lastaddr, baddr, bmask; 160 1.1 pooka vaddr_t vaddr = (vaddr_t)buf; 161 1.1 pooka int seg; 162 1.1 pooka 163 1.1 pooka // printf("%s(%p,%p,%p,%u,%p,%#x,%p,%p,%u)\n", __func__, 164 1.1 pooka // t, map, buf, buflen, vm, flags, lastaddrp, segp, first); 165 1.1 pooka 166 1.1 pooka lastaddr = *lastaddrp; 167 1.1 pooka bmask = ~(map->_dm_boundary - 1); 168 1.1 pooka 169 1.1 pooka for (seg = *segp; buflen > 0 ; ) { 170 1.1 pooka /* 171 1.1 pooka * Get the physical address for this segment. 172 1.1 pooka */ 173 1.1 pooka if (!VMSPACE_IS_KERNEL_P(vm)) 174 1.1 pooka (void) pmap_extract(vm_map_pmap(&vm->vm_map), 175 1.1 pooka vaddr, (void *)&curaddr); 176 1.1 pooka else 177 1.1 pooka curaddr = vtophys(vaddr); 178 1.1 pooka 179 1.1 pooka /* 180 1.1 pooka * If we're beyond the bounce threshold, notify 181 1.1 pooka * the caller. 182 1.1 pooka */ 183 1.1 pooka if (map->_dm_bounce_thresh != 0 && 184 1.1 pooka curaddr >= map->_dm_bounce_thresh) 185 1.1 pooka return (EINVAL); 186 1.1 pooka 187 1.1 pooka /* 188 1.1 pooka * Compute the segment size, and adjust counts. 189 1.1 pooka */ 190 1.1 pooka sgsize = PAGE_SIZE - ((u_long)vaddr & PGOFSET); 191 1.1 pooka if (buflen < sgsize) 192 1.1 pooka sgsize = buflen; 193 1.10 christos sgsize = MIN(sgsize, map->dm_maxsegsz); 194 1.1 pooka 195 1.1 pooka /* 196 1.1 pooka * Make sure we don't cross any boundaries. 197 1.1 pooka */ 198 1.1 pooka if (map->_dm_boundary > 0) { 199 1.1 pooka baddr = (curaddr + map->_dm_boundary) & bmask; 200 1.1 pooka if (sgsize > (baddr - curaddr)) 201 1.1 pooka sgsize = (baddr - curaddr); 202 1.1 pooka } 203 1.1 pooka 204 1.1 pooka /* 205 1.1 pooka * Insert chunk into a segment, coalescing with 206 1.1 pooka * the previous segment if possible. 207 1.1 pooka */ 208 1.1 pooka if (first) { 209 1.2 pooka map->dm_segs[seg].ds_addr 210 1.2 pooka = rumpcomp_pci_virt_to_mach((void *)curaddr); 211 1.1 pooka map->dm_segs[seg].ds_len = sgsize; 212 1.1 pooka first = 0; 213 1.1 pooka } else { 214 1.1 pooka if (curaddr == lastaddr && 215 1.1 pooka (map->dm_segs[seg].ds_len + sgsize) <= 216 1.1 pooka map->dm_maxsegsz && 217 1.1 pooka (map->_dm_boundary == 0 || 218 1.1 pooka (map->dm_segs[seg].ds_addr & bmask) == 219 1.2 pooka (rumpcomp_pci_virt_to_mach((void*)curaddr)&bmask))) 220 1.1 pooka map->dm_segs[seg].ds_len += sgsize; 221 1.1 pooka else { 222 1.1 pooka if (++seg >= map->_dm_segcnt) 223 1.1 pooka break; 224 1.1 pooka map->dm_segs[seg].ds_addr = 225 1.2 pooka rumpcomp_pci_virt_to_mach((void *)curaddr); 226 1.1 pooka map->dm_segs[seg].ds_len = sgsize; 227 1.1 pooka } 228 1.1 pooka } 229 1.1 pooka 230 1.1 pooka lastaddr = curaddr + sgsize; 231 1.1 pooka vaddr += sgsize; 232 1.1 pooka buflen -= sgsize; 233 1.1 pooka } 234 1.1 pooka 235 1.1 pooka *segp = seg; 236 1.1 pooka *lastaddrp = lastaddr; 237 1.1 pooka 238 1.1 pooka /* 239 1.1 pooka * Did we fit? 240 1.1 pooka */ 241 1.1 pooka if (buflen != 0) 242 1.1 pooka return (EFBIG); /* XXX better return value here? */ 243 1.1 pooka 244 1.1 pooka return (0); 245 1.1 pooka } 246 1.1 pooka 247 1.1 pooka /* 248 1.1 pooka * Common function for loading a DMA map with a linear buffer. May 249 1.1 pooka * be called by bus-specific DMA map load functions. 250 1.1 pooka */ 251 1.1 pooka int 252 1.1 pooka bus_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, 253 1.1 pooka void *buf, bus_size_t buflen, struct proc *p, int flags) 254 1.1 pooka { 255 1.1 pooka paddr_t lastaddr = 0; 256 1.1 pooka int seg, error; 257 1.1 pooka struct vmspace *vm; 258 1.1 pooka 259 1.1 pooka /* 260 1.1 pooka * Make sure that on error condition we return "no valid mappings". 261 1.1 pooka */ 262 1.1 pooka map->dm_mapsize = 0; 263 1.1 pooka map->dm_nsegs = 0; 264 1.1 pooka KASSERT(map->dm_maxsegsz <= map->_dm_maxmaxsegsz); 265 1.1 pooka 266 1.1 pooka if (buflen > map->_dm_size) 267 1.1 pooka return (EINVAL); 268 1.1 pooka 269 1.1 pooka if (p != NULL) { 270 1.1 pooka vm = p->p_vmspace; 271 1.1 pooka } else { 272 1.1 pooka vm = vmspace_kernel(); 273 1.1 pooka } 274 1.1 pooka 275 1.1 pooka seg = 0; 276 1.1 pooka error = _bus_dmamap_load_buffer(t, map, buf, buflen, vm, flags, 277 1.1 pooka &lastaddr, &seg, 1); 278 1.1 pooka if (error == 0) { 279 1.1 pooka map->dm_mapsize = buflen; 280 1.1 pooka map->dm_nsegs = seg + 1; 281 1.1 pooka } 282 1.1 pooka return (error); 283 1.1 pooka } 284 1.1 pooka 285 1.1 pooka /* 286 1.1 pooka * Like _bus_dmamap_load(), but for mbufs. 287 1.1 pooka */ 288 1.1 pooka int 289 1.1 pooka bus_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, 290 1.1 pooka struct mbuf *m0, int flags) 291 1.1 pooka { 292 1.1 pooka paddr_t lastaddr = 0; 293 1.1 pooka int seg, error, first; 294 1.1 pooka struct mbuf *m; 295 1.1 pooka 296 1.1 pooka /* 297 1.1 pooka * Make sure that on error condition we return "no valid mappings." 298 1.1 pooka */ 299 1.1 pooka map->dm_mapsize = 0; 300 1.1 pooka map->dm_nsegs = 0; 301 1.1 pooka KASSERT(map->dm_maxsegsz <= map->_dm_maxmaxsegsz); 302 1.1 pooka 303 1.1 pooka #ifdef DIAGNOSTIC 304 1.1 pooka if ((m0->m_flags & M_PKTHDR) == 0) 305 1.1 pooka panic("_bus_dmamap_load_mbuf: no packet header"); 306 1.1 pooka #endif 307 1.1 pooka 308 1.1 pooka if (m0->m_pkthdr.len > map->_dm_size) 309 1.1 pooka return (EINVAL); 310 1.1 pooka 311 1.1 pooka first = 1; 312 1.1 pooka seg = 0; 313 1.1 pooka error = 0; 314 1.1 pooka for (m = m0; m != NULL && error == 0; m = m->m_next, first = 0) { 315 1.1 pooka if (m->m_len == 0) 316 1.1 pooka continue; 317 1.1 pooka #ifdef POOL_VTOPHYS 318 1.1 pooka /* XXX Could be better about coalescing. */ 319 1.1 pooka /* XXX Doesn't check boundaries. */ 320 1.6 maxv switch (m->m_flags & (M_EXT|M_EXT_CLUSTER)) { 321 1.6 maxv case M_EXT|M_EXT_CLUSTER: 322 1.1 pooka /* XXX KDASSERT */ 323 1.1 pooka KASSERT(m->m_ext.ext_paddr != M_PADDR_INVALID); 324 1.1 pooka lastaddr = m->m_ext.ext_paddr + 325 1.1 pooka (m->m_data - m->m_ext.ext_buf); 326 1.1 pooka have_addr: 327 1.1 pooka if (first == 0 && ++seg >= map->_dm_segcnt) { 328 1.1 pooka error = EFBIG; 329 1.1 pooka continue; 330 1.1 pooka } 331 1.1 pooka map->dm_segs[seg].ds_addr = 332 1.2 pooka rumpcomp_pci_virt_to_mach((void *)lastaddr); 333 1.1 pooka map->dm_segs[seg].ds_len = m->m_len; 334 1.1 pooka lastaddr += m->m_len; 335 1.1 pooka continue; 336 1.1 pooka 337 1.1 pooka case 0: 338 1.1 pooka lastaddr = m->m_paddr + M_BUFOFFSET(m) + 339 1.1 pooka (m->m_data - M_BUFADDR(m)); 340 1.1 pooka goto have_addr; 341 1.1 pooka 342 1.1 pooka default: 343 1.1 pooka break; 344 1.1 pooka } 345 1.1 pooka #endif 346 1.1 pooka error = _bus_dmamap_load_buffer(t, map, m->m_data, 347 1.1 pooka m->m_len, vmspace_kernel(), flags, &lastaddr, &seg, first); 348 1.1 pooka } 349 1.1 pooka if (error == 0) { 350 1.1 pooka map->dm_mapsize = m0->m_pkthdr.len; 351 1.1 pooka map->dm_nsegs = seg + 1; 352 1.1 pooka } 353 1.1 pooka return (error); 354 1.1 pooka } 355 1.1 pooka 356 1.1 pooka /* 357 1.1 pooka * Like _bus_dmamap_load(), but for uios. 358 1.1 pooka */ 359 1.1 pooka int 360 1.1 pooka bus_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map, 361 1.1 pooka struct uio *uio, int flags) 362 1.1 pooka { 363 1.1 pooka paddr_t lastaddr = 0; 364 1.1 pooka int seg, i, error, first; 365 1.1 pooka bus_size_t minlen, resid; 366 1.1 pooka struct iovec *iov; 367 1.1 pooka void *addr; 368 1.1 pooka 369 1.1 pooka /* 370 1.1 pooka * Make sure that on error condition we return "no valid mappings." 371 1.1 pooka */ 372 1.1 pooka map->dm_mapsize = 0; 373 1.1 pooka map->dm_nsegs = 0; 374 1.1 pooka KASSERT(map->dm_maxsegsz <= map->_dm_maxmaxsegsz); 375 1.1 pooka 376 1.1 pooka resid = uio->uio_resid; 377 1.1 pooka iov = uio->uio_iov; 378 1.1 pooka 379 1.1 pooka first = 1; 380 1.1 pooka seg = 0; 381 1.1 pooka error = 0; 382 1.1 pooka for (i = 0; i < uio->uio_iovcnt && resid != 0 && error == 0; i++) { 383 1.1 pooka /* 384 1.1 pooka * Now at the first iovec to load. Load each iovec 385 1.1 pooka * until we have exhausted the residual count. 386 1.1 pooka */ 387 1.1 pooka minlen = resid < iov[i].iov_len ? resid : iov[i].iov_len; 388 1.1 pooka addr = (void *)iov[i].iov_base; 389 1.1 pooka 390 1.1 pooka error = _bus_dmamap_load_buffer(t, map, addr, minlen, 391 1.1 pooka uio->uio_vmspace, flags, &lastaddr, &seg, first); 392 1.1 pooka first = 0; 393 1.1 pooka 394 1.1 pooka resid -= minlen; 395 1.1 pooka } 396 1.1 pooka if (error == 0) { 397 1.1 pooka map->dm_mapsize = uio->uio_resid; 398 1.1 pooka map->dm_nsegs = seg + 1; 399 1.1 pooka } 400 1.1 pooka return (error); 401 1.1 pooka } 402 1.1 pooka 403 1.1 pooka /* 404 1.1 pooka * Like _bus_dmamap_load(), but for raw memory allocated with 405 1.1 pooka * bus_dmamem_alloc(). 406 1.1 pooka */ 407 1.1 pooka int 408 1.1 pooka bus_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map, 409 1.1 pooka bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags) 410 1.1 pooka { 411 1.1 pooka 412 1.1 pooka panic("_bus_dmamap_load_raw: not implemented"); 413 1.1 pooka } 414 1.1 pooka 415 1.1 pooka /* 416 1.1 pooka * Common function for unloading a DMA map. May be called by 417 1.1 pooka * chipset-specific DMA map unload functions. 418 1.1 pooka */ 419 1.1 pooka void 420 1.1 pooka bus_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map) 421 1.1 pooka { 422 1.1 pooka 423 1.1 pooka /* 424 1.1 pooka * No resources to free; just mark the mappings as 425 1.1 pooka * invalid. 426 1.1 pooka */ 427 1.1 pooka map->dm_maxsegsz = map->_dm_maxmaxsegsz; 428 1.1 pooka map->dm_mapsize = 0; 429 1.1 pooka map->dm_nsegs = 0; 430 1.1 pooka } 431 1.1 pooka 432 1.1 pooka void 433 1.1 pooka bus_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, 434 1.1 pooka bus_addr_t offset, bus_size_t len, int ops) 435 1.1 pooka { 436 1.1 pooka 437 1.1 pooka /* XXX: this might need some MD tweaks */ 438 1.1 pooka membar_sync(); 439 1.1 pooka } 440 1.1 pooka 441 1.1 pooka /* 442 1.1 pooka * Common function for freeing DMA-safe memory. May be called by 443 1.1 pooka * bus-specific DMA memory free functions. 444 1.1 pooka */ 445 1.1 pooka void 446 1.1 pooka bus_dmamem_free(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs) 447 1.1 pooka { 448 1.5 pooka #ifdef RUMPCOMP_USERFEATURE_PCI_DMAFREE 449 1.4 pooka vaddr_t vacookie = segs[0]._ds_vacookie; 450 1.4 pooka bus_size_t sizecookie = segs[0]._ds_sizecookie; 451 1.1 pooka 452 1.5 pooka rumpcomp_pci_dmafree(vacookie, sizecookie); 453 1.4 pooka #else 454 1.1 pooka panic("bus_dmamem_free not implemented"); 455 1.4 pooka #endif 456 1.1 pooka } 457 1.1 pooka 458 1.1 pooka /* 459 1.1 pooka * Don't have hypercall for mapping scatter-gather memory. 460 1.1 pooka * So just simply fail if there's more than one segment to map 461 1.1 pooka */ 462 1.1 pooka int 463 1.1 pooka bus_dmamem_map(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs, 464 1.1 pooka size_t size, void **kvap, int flags) 465 1.1 pooka { 466 1.3 pooka struct rumpcomp_pci_dmaseg *dss; 467 1.3 pooka size_t allocsize = nsegs * sizeof(*dss); 468 1.3 pooka int rv, i; 469 1.1 pooka 470 1.3 pooka /* 471 1.3 pooka * Though rumpcomp_pci_dmaseg "accidentally" matches the 472 1.3 pooka * bus_dma segment descriptor (at least for now), act 473 1.3 pooka * proper and actually translate it. 474 1.3 pooka */ 475 1.3 pooka dss = kmem_alloc(allocsize, KM_SLEEP); 476 1.3 pooka for (i = 0; i < nsegs; i++) { 477 1.3 pooka dss[i].ds_pa = segs[i].ds_addr; 478 1.3 pooka dss[i].ds_len = segs[i].ds_len; 479 1.3 pooka dss[i].ds_vacookie = segs[i]._ds_vacookie; 480 1.3 pooka } 481 1.3 pooka rv = rumpcomp_pci_dmamem_map(dss, nsegs, size, kvap); 482 1.3 pooka kmem_free(dss, allocsize); 483 1.1 pooka 484 1.3 pooka return rv; 485 1.1 pooka } 486 1.1 pooka 487 1.1 pooka /* 488 1.1 pooka * Common function for unmapping DMA-safe memory. May be called by 489 1.1 pooka * bus-specific DMA memory unmapping functions. 490 1.1 pooka */ 491 1.1 pooka void 492 1.1 pooka bus_dmamem_unmap(bus_dma_tag_t t, void *kva, size_t size) 493 1.1 pooka { 494 1.1 pooka 495 1.1 pooka /* nothing to do as long as bus_dmamem_map() is what it is */ 496 1.1 pooka } 497 1.1 pooka 498 1.1 pooka paddr_t 499 1.1 pooka bus_dmamem_mmap(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs, 500 1.1 pooka off_t off, int prot, int flags) 501 1.1 pooka { 502 1.1 pooka 503 1.1 pooka panic("bus_dmamem_mmap not supported"); 504 1.1 pooka } 505 1.1 pooka 506 1.1 pooka /* 507 1.1 pooka * Allocate physical memory from the given physical address range. 508 1.1 pooka * Called by DMA-safe memory allocation methods. 509 1.1 pooka */ 510 1.1 pooka int 511 1.1 pooka bus_dmamem_alloc(bus_dma_tag_t t, bus_size_t size, bus_size_t alignment, 512 1.1 pooka bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs, 513 1.1 pooka int flags) 514 1.1 pooka { 515 1.1 pooka paddr_t curaddr, lastaddr, pa; 516 1.3 pooka vaddr_t vacookie; 517 1.4 pooka size_t sizecookie; 518 1.1 pooka int curseg, error; 519 1.1 pooka 520 1.1 pooka /* Always round the size. */ 521 1.1 pooka size = round_page(size); 522 1.1 pooka 523 1.4 pooka sizecookie = size; 524 1.4 pooka 525 1.1 pooka /* 526 1.1 pooka * Allocate pages from the VM system. 527 1.1 pooka */ 528 1.1 pooka #if 0 529 1.1 pooka error = uvm_pglistalloc(size, low, high, alignment, boundary, 530 1.1 pooka &mlist, nsegs, (flags & BUS_DMA_NOWAIT) == 0); 531 1.1 pooka #else 532 1.1 pooka /* XXX: ignores boundary, nsegs, etc. */ 533 1.1 pooka //printf("dma allocation %lx %lx %d\n", alignment, boundary, nsegs); 534 1.3 pooka error = rumpcomp_pci_dmalloc(size, alignment, &pa, &vacookie); 535 1.1 pooka #endif 536 1.1 pooka if (error) 537 1.1 pooka return (error); 538 1.1 pooka 539 1.1 pooka /* 540 1.1 pooka * Compute the location, size, and number of segments actually 541 1.1 pooka * returned by the VM code. 542 1.1 pooka */ 543 1.1 pooka curseg = 0; 544 1.1 pooka lastaddr = segs[curseg].ds_addr = pa; 545 1.1 pooka segs[curseg].ds_len = PAGE_SIZE; 546 1.3 pooka segs[curseg]._ds_vacookie = vacookie; 547 1.4 pooka segs[curseg]._ds_sizecookie = sizecookie; 548 1.1 pooka size -= PAGE_SIZE; 549 1.1 pooka pa += PAGE_SIZE; 550 1.3 pooka vacookie += PAGE_SIZE; 551 1.1 pooka 552 1.3 pooka for (; size; 553 1.3 pooka pa += PAGE_SIZE, vacookie += PAGE_SIZE, size -= PAGE_SIZE) { 554 1.1 pooka curaddr = pa; 555 1.1 pooka if (curaddr == (lastaddr + PAGE_SIZE) && 556 1.1 pooka (lastaddr & boundary) == (curaddr & boundary)) { 557 1.1 pooka segs[curseg].ds_len += PAGE_SIZE; 558 1.1 pooka } else { 559 1.1 pooka curseg++; 560 1.1 pooka if (curseg >= nsegs) 561 1.1 pooka return EFBIG; 562 1.1 pooka segs[curseg].ds_addr = curaddr; 563 1.1 pooka segs[curseg].ds_len = PAGE_SIZE; 564 1.3 pooka segs[curseg]._ds_vacookie = vacookie; 565 1.4 pooka segs[curseg]._ds_sizecookie = sizecookie; 566 1.1 pooka } 567 1.1 pooka lastaddr = curaddr; 568 1.1 pooka } 569 1.1 pooka *rsegs = curseg + 1; 570 1.1 pooka 571 1.1 pooka return (0); 572 1.1 pooka } 573