xref: /freebsd/sys/arm64/arm64/busdma_bounce.c (revision a77e1f0f)
1 /*-
2  * Copyright (c) 1997, 1998 Justin T. Gibbs.
3  * Copyright (c) 2015-2016 The FreeBSD Foundation
4  * All rights reserved.
5  *
6  * Portions of this software were developed by Andrew Turner
7  * under sponsorship of the FreeBSD Foundation.
8  *
9  * Portions of this software were developed by Semihalf
10  * under sponsorship of the FreeBSD Foundation.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions, and the following disclaimer,
17  *    without modification, immediately at the beginning of the file.
18  * 2. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
25  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/domainset.h>
37 #include <sys/malloc.h>
38 #include <sys/bus.h>
39 #include <sys/interrupt.h>
40 #include <sys/kernel.h>
41 #include <sys/ktr.h>
42 #include <sys/lock.h>
43 #include <sys/memdesc.h>
44 #include <sys/msan.h>
45 #include <sys/mutex.h>
46 #include <sys/proc.h>
47 #include <sys/sysctl.h>
48 #include <sys/uio.h>
49 
50 #include <vm/vm.h>
51 #include <vm/vm_extern.h>
52 #include <vm/vm_kern.h>
53 #include <vm/vm_page.h>
54 #include <vm/vm_map.h>
55 
56 #include <machine/atomic.h>
57 #include <machine/bus.h>
58 #include <machine/md_var.h>
59 #include <arm64/include/bus_dma_impl.h>
60 
61 #define MAX_BPAGES 4096
62 
63 enum {
64 	BF_COULD_BOUNCE		= 0x01,
65 	BF_MIN_ALLOC_COMP	= 0x02,
66 	BF_KMEM_ALLOC		= 0x04,
67 	BF_COHERENT		= 0x10,
68 };
69 
70 struct bounce_page;
71 struct bounce_zone;
72 
73 struct bus_dma_tag {
74 	struct bus_dma_tag_common common;
75 	size_t			alloc_size;
76 	size_t			alloc_alignment;
77 	int			map_count;
78 	int			bounce_flags;
79 	bus_dma_segment_t	*segments;
80 	struct bounce_zone	*bounce_zone;
81 };
82 
83 static SYSCTL_NODE(_hw, OID_AUTO, busdma, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
84     "Busdma parameters");
85 
86 struct sync_list {
87 	vm_offset_t	vaddr;		/* kva of client data */
88 	bus_addr_t	paddr;		/* physical address */
89 	vm_page_t	pages;		/* starting page of client data */
90 	bus_size_t	datacount;	/* client data count */
91 };
92 
93 struct bus_dmamap {
94 	STAILQ_HEAD(, bounce_page) bpages;
95 	int		       pagesneeded;
96 	int		       pagesreserved;
97 	bus_dma_tag_t	       dmat;
98 	struct memdesc	       mem;
99 	bus_dmamap_callback_t *callback;
100 	void		      *callback_arg;
101 	__sbintime_t	       queued_time;
102 	STAILQ_ENTRY(bus_dmamap) links;
103 	u_int			flags;
104 #define	DMAMAP_COHERENT		(1 << 0)
105 #define	DMAMAP_FROM_DMAMEM	(1 << 1)
106 #define	DMAMAP_MBUF		(1 << 2)
107 	int			sync_count;
108 #ifdef KMSAN
109 	struct memdesc	       kmsan_mem;
110 #endif
111 	struct sync_list	slist[];
112 };
113 
114 static bool _bus_dmamap_pagesneeded(bus_dma_tag_t dmat, bus_dmamap_t map,
115     vm_paddr_t buf, bus_size_t buflen, int *pagesneeded);
116 static void _bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map,
117     pmap_t pmap, void *buf, bus_size_t buflen, int flags);
118 static void _bus_dmamap_count_phys(bus_dma_tag_t dmat, bus_dmamap_t map,
119     vm_paddr_t buf, bus_size_t buflen, int flags);
120 
121 static MALLOC_DEFINE(M_BUSDMA, "busdma", "busdma metadata");
122 
123 #define	dmat_alignment(dmat)	((dmat)->common.alignment)
124 #define	dmat_bounce_flags(dmat)	((dmat)->bounce_flags)
125 #define	dmat_boundary(dmat)	((dmat)->common.boundary)
126 #define	dmat_domain(dmat)	((dmat)->common.domain)
127 #define	dmat_flags(dmat)	((dmat)->common.flags)
128 #define	dmat_highaddr(dmat)	((dmat)->common.highaddr)
129 #define	dmat_lowaddr(dmat)	((dmat)->common.lowaddr)
130 #define	dmat_lockfunc(dmat)	((dmat)->common.lockfunc)
131 #define	dmat_lockfuncarg(dmat)	((dmat)->common.lockfuncarg)
132 #define	dmat_maxsegsz(dmat)	((dmat)->common.maxsegsz)
133 #define	dmat_nsegments(dmat)	((dmat)->common.nsegments)
134 
135 #include "../../kern/subr_busdma_bounce.c"
136 
137 static int
bounce_bus_dma_zone_setup(bus_dma_tag_t dmat)138 bounce_bus_dma_zone_setup(bus_dma_tag_t dmat)
139 {
140 	struct bounce_zone *bz;
141 	bus_size_t maxsize;
142 	int error;
143 
144 	/*
145 	 * Round size up to a full page, and add one more page because
146 	 * there can always be one more boundary crossing than the
147 	 * number of pages in a transfer.
148 	 */
149 	maxsize = roundup2(dmat->common.maxsize, PAGE_SIZE) + PAGE_SIZE;
150 
151 	/* Must bounce */
152 	if ((error = alloc_bounce_zone(dmat)) != 0)
153 		return (error);
154 	bz = dmat->bounce_zone;
155 
156 	if (ptoa(bz->total_bpages) < maxsize) {
157 		int pages;
158 
159 		pages = atop(maxsize) + 1 - bz->total_bpages;
160 
161 		/* Add pages to our bounce pool */
162 		if (alloc_bounce_pages(dmat, pages) < pages)
163 			return (ENOMEM);
164 	}
165 	/* Performed initial allocation */
166 	dmat->bounce_flags |= BF_MIN_ALLOC_COMP;
167 
168 	return (error);
169 }
170 
171 /*
172  * Return true if the DMA should bounce because the start or end does not fall
173  * on a cacheline boundary (which would require a partial cacheline flush).
174  * COHERENT memory doesn't trigger cacheline flushes.  Memory allocated by
175  * bus_dmamem_alloc() is always aligned to cacheline boundaries, and there's a
176  * strict rule that such memory cannot be accessed by the CPU while DMA is in
177  * progress (or by multiple DMA engines at once), so that it's always safe to do
178  * full cacheline flushes even if that affects memory outside the range of a
179  * given DMA operation that doesn't involve the full allocated buffer.  If we're
180  * mapping an mbuf, that follows the same rules as a buffer we allocated.
181  */
182 static bool
cacheline_bounce(bus_dma_tag_t dmat,bus_dmamap_t map,bus_addr_t paddr,bus_size_t size)183 cacheline_bounce(bus_dma_tag_t dmat, bus_dmamap_t map, bus_addr_t paddr,
184     bus_size_t size)
185 {
186 
187 #define	DMAMAP_CACHELINE_FLAGS						\
188     (DMAMAP_FROM_DMAMEM | DMAMAP_COHERENT | DMAMAP_MBUF)
189 	if ((dmat->bounce_flags & BF_COHERENT) != 0)
190 		return (false);
191 	if (map != NULL && (map->flags & DMAMAP_CACHELINE_FLAGS) != 0)
192 		return (false);
193 	return (((paddr | size) & (dcache_line_size - 1)) != 0);
194 #undef DMAMAP_CACHELINE_FLAGS
195 }
196 
197 /*
198  * Return true if the given address does not fall on the alignment boundary.
199  */
200 static bool
alignment_bounce(bus_dma_tag_t dmat,bus_addr_t addr)201 alignment_bounce(bus_dma_tag_t dmat, bus_addr_t addr)
202 {
203 
204 	return (!vm_addr_align_ok(addr, dmat->common.alignment));
205 }
206 
207 static bool
might_bounce(bus_dma_tag_t dmat,bus_dmamap_t map,bus_addr_t paddr,bus_size_t size)208 might_bounce(bus_dma_tag_t dmat, bus_dmamap_t map, bus_addr_t paddr,
209     bus_size_t size)
210 {
211 
212 	/* Memory allocated by bounce_bus_dmamem_alloc won't bounce */
213 	if (map && (map->flags & DMAMAP_FROM_DMAMEM) != 0)
214 		return (false);
215 
216 	if ((dmat->bounce_flags & BF_COULD_BOUNCE) != 0)
217 		return (true);
218 
219 	if (cacheline_bounce(dmat, map, paddr, size))
220 		return (true);
221 
222 	if (alignment_bounce(dmat, paddr))
223 		return (true);
224 
225 	return (false);
226 }
227 
228 static bool
must_bounce(bus_dma_tag_t dmat,bus_dmamap_t map,bus_addr_t paddr,bus_size_t size)229 must_bounce(bus_dma_tag_t dmat, bus_dmamap_t map, bus_addr_t paddr,
230     bus_size_t size)
231 {
232 
233 	if (cacheline_bounce(dmat, map, paddr, size))
234 		return (true);
235 
236 	if ((dmat->bounce_flags & BF_COULD_BOUNCE) != 0 &&
237 	    addr_needs_bounce(dmat, paddr))
238 		return (true);
239 
240 	return (false);
241 }
242 
243 /*
244  * Allocate a device specific dma_tag.
245  */
246 static int
bounce_bus_dma_tag_create(bus_dma_tag_t parent,bus_size_t alignment,bus_addr_t boundary,bus_addr_t lowaddr,bus_addr_t highaddr,bus_size_t maxsize,int nsegments,bus_size_t maxsegsz,int flags,bus_dma_lock_t * lockfunc,void * lockfuncarg,bus_dma_tag_t * dmat)247 bounce_bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment,
248     bus_addr_t boundary, bus_addr_t lowaddr, bus_addr_t highaddr,
249     bus_size_t maxsize, int nsegments, bus_size_t maxsegsz, int flags,
250     bus_dma_lock_t *lockfunc, void *lockfuncarg, bus_dma_tag_t *dmat)
251 {
252 	bus_dma_tag_t newtag;
253 	int error;
254 
255 	*dmat = NULL;
256 	error = common_bus_dma_tag_create(parent != NULL ? &parent->common :
257 	    NULL, alignment, boundary, lowaddr, highaddr, maxsize, nsegments,
258 	    maxsegsz, flags, lockfunc, lockfuncarg,
259 	    sizeof (struct bus_dma_tag), (void **)&newtag);
260 	if (error != 0)
261 		return (error);
262 
263 	newtag->common.impl = &bus_dma_bounce_impl;
264 	newtag->map_count = 0;
265 	newtag->segments = NULL;
266 
267 	if ((flags & BUS_DMA_COHERENT) != 0) {
268 		newtag->bounce_flags |= BF_COHERENT;
269 	}
270 
271 	if (parent != NULL) {
272 		if ((parent->bounce_flags & BF_COULD_BOUNCE) != 0)
273 			newtag->bounce_flags |= BF_COULD_BOUNCE;
274 
275 		/* Copy some flags from the parent */
276 		newtag->bounce_flags |= parent->bounce_flags & BF_COHERENT;
277 	}
278 
279 	if ((newtag->bounce_flags & BF_COHERENT) != 0) {
280 		newtag->alloc_alignment = newtag->common.alignment;
281 		newtag->alloc_size = newtag->common.maxsize;
282 	} else {
283 		/*
284 		 * Ensure the buffer is aligned to a cacheline when allocating
285 		 * a non-coherent buffer. This is so we don't have any data
286 		 * that another CPU may be accessing around DMA buffer
287 		 * causing the cache to become dirty.
288 		 */
289 		newtag->alloc_alignment = MAX(newtag->common.alignment,
290 		    dcache_line_size);
291 		newtag->alloc_size = roundup2(newtag->common.maxsize,
292 		    dcache_line_size);
293 	}
294 
295 	if (newtag->common.lowaddr < ptoa((vm_paddr_t)Maxmem) ||
296 	    newtag->common.alignment > 1)
297 		newtag->bounce_flags |= BF_COULD_BOUNCE;
298 
299 	if ((flags & BUS_DMA_ALLOCNOW) != 0)
300 		error = bounce_bus_dma_zone_setup(newtag);
301 	else
302 		error = 0;
303 
304 	if (error != 0)
305 		free(newtag, M_DEVBUF);
306 	else
307 		*dmat = newtag;
308 	CTR4(KTR_BUSDMA, "%s returned tag %p tag flags 0x%x error %d",
309 	    __func__, newtag, (newtag != NULL ? newtag->common.flags : 0),
310 	    error);
311 	return (error);
312 }
313 
314 static int
bounce_bus_dma_tag_destroy(bus_dma_tag_t dmat)315 bounce_bus_dma_tag_destroy(bus_dma_tag_t dmat)
316 {
317 	int error = 0;
318 
319 	if (dmat != NULL) {
320 		if (dmat->map_count != 0) {
321 			error = EBUSY;
322 			goto out;
323 		}
324 		if (dmat->segments != NULL)
325 			free(dmat->segments, M_DEVBUF);
326 		free(dmat, M_DEVBUF);
327 	}
328 out:
329 	CTR3(KTR_BUSDMA, "%s tag %p error %d", __func__, dmat, error);
330 	return (error);
331 }
332 
333 /*
334  * Update the domain for the tag.  We may need to reallocate the zone and
335  * bounce pages.
336  */
337 static int
bounce_bus_dma_tag_set_domain(bus_dma_tag_t dmat)338 bounce_bus_dma_tag_set_domain(bus_dma_tag_t dmat)
339 {
340 
341 	KASSERT(dmat->map_count == 0,
342 	    ("bounce_bus_dma_tag_set_domain:  Domain set after use.\n"));
343 	if ((dmat->bounce_flags & BF_COULD_BOUNCE) == 0 ||
344 	    dmat->bounce_zone == NULL)
345 		return (0);
346 	dmat->bounce_flags &= ~BF_MIN_ALLOC_COMP;
347 	return (bounce_bus_dma_zone_setup(dmat));
348 }
349 
350 static bool
bounce_bus_dma_id_mapped(bus_dma_tag_t dmat,vm_paddr_t buf,bus_size_t buflen)351 bounce_bus_dma_id_mapped(bus_dma_tag_t dmat, vm_paddr_t buf, bus_size_t buflen)
352 {
353 
354 	if (!might_bounce(dmat, NULL, buf, buflen))
355 		return (true);
356 	return (!_bus_dmamap_pagesneeded(dmat, NULL, buf, buflen, NULL));
357 }
358 
359 static bus_dmamap_t
alloc_dmamap(bus_dma_tag_t dmat,int flags)360 alloc_dmamap(bus_dma_tag_t dmat, int flags)
361 {
362 	u_long mapsize;
363 	bus_dmamap_t map;
364 
365 	mapsize = sizeof(*map);
366 	mapsize += sizeof(struct sync_list) * dmat->common.nsegments;
367 	map = malloc_domainset(mapsize, M_DEVBUF,
368 	    DOMAINSET_PREF(dmat->common.domain), flags | M_ZERO);
369 	if (map == NULL)
370 		return (NULL);
371 
372 	/* Initialize the new map */
373 	STAILQ_INIT(&map->bpages);
374 
375 	return (map);
376 }
377 
378 /*
379  * Allocate a handle for mapping from kva/uva/physical
380  * address space into bus device space.
381  */
382 static int
bounce_bus_dmamap_create(bus_dma_tag_t dmat,int flags,bus_dmamap_t * mapp)383 bounce_bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp)
384 {
385 	struct bounce_zone *bz;
386 	int error, maxpages, pages;
387 
388 	error = 0;
389 
390 	if (dmat->segments == NULL) {
391 		dmat->segments = mallocarray_domainset(dmat->common.nsegments,
392 		    sizeof(bus_dma_segment_t), M_DEVBUF,
393 		    DOMAINSET_PREF(dmat->common.domain), M_NOWAIT);
394 		if (dmat->segments == NULL) {
395 			CTR3(KTR_BUSDMA, "%s: tag %p error %d",
396 			    __func__, dmat, ENOMEM);
397 			return (ENOMEM);
398 		}
399 	}
400 
401 	*mapp = alloc_dmamap(dmat, M_NOWAIT);
402 	if (*mapp == NULL) {
403 		CTR3(KTR_BUSDMA, "%s: tag %p error %d",
404 		    __func__, dmat, ENOMEM);
405 		return (ENOMEM);
406 	}
407 
408 	/*
409 	 * Bouncing might be required if the driver asks for an active
410 	 * exclusion region, a data alignment that is stricter than 1, and/or
411 	 * an active address boundary.
412 	 */
413 	if (dmat->bounce_zone == NULL) {
414 		if ((error = alloc_bounce_zone(dmat)) != 0) {
415 			free(*mapp, M_DEVBUF);
416 			return (error);
417 		}
418 	}
419 	bz = dmat->bounce_zone;
420 
421 	/*
422 	 * Attempt to add pages to our pool on a per-instance basis up to a sane
423 	 * limit. Even if the tag isn't subject of bouncing due to alignment
424 	 * and boundary constraints, it could still auto-bounce due to
425 	 * cacheline alignment, which requires at most two bounce pages.
426 	 */
427 	if (dmat->common.alignment > 1)
428 		maxpages = MAX_BPAGES;
429 	else
430 		maxpages = MIN(MAX_BPAGES, Maxmem -
431 		    atop(dmat->common.lowaddr));
432 	if ((dmat->bounce_flags & BF_MIN_ALLOC_COMP) == 0 ||
433 	    (bz->map_count > 0 && bz->total_bpages < maxpages)) {
434 		pages = atop(roundup2(dmat->common.maxsize, PAGE_SIZE)) + 1;
435 		pages = MIN(maxpages - bz->total_bpages, pages);
436 		pages = MAX(pages, 2);
437 		if (alloc_bounce_pages(dmat, pages) < pages)
438 			error = ENOMEM;
439 		if ((dmat->bounce_flags & BF_MIN_ALLOC_COMP) == 0) {
440 			if (error == 0) {
441 				dmat->bounce_flags |= BF_MIN_ALLOC_COMP;
442 			}
443 		} else
444 			error = 0;
445 	}
446 	bz->map_count++;
447 
448 	if (error == 0) {
449 		dmat->map_count++;
450 		if ((dmat->bounce_flags & BF_COHERENT) != 0)
451 			(*mapp)->flags |= DMAMAP_COHERENT;
452 	} else {
453 		free(*mapp, M_DEVBUF);
454 	}
455 	CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
456 	    __func__, dmat, dmat->common.flags, error);
457 	return (error);
458 }
459 
460 /*
461  * Destroy a handle for mapping from kva/uva/physical
462  * address space into bus device space.
463  */
464 static int
bounce_bus_dmamap_destroy(bus_dma_tag_t dmat,bus_dmamap_t map)465 bounce_bus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map)
466 {
467 
468 	/* Check we are destroying the correct map type */
469 	if ((map->flags & DMAMAP_FROM_DMAMEM) != 0)
470 		panic("bounce_bus_dmamap_destroy: Invalid map freed\n");
471 
472 	if (STAILQ_FIRST(&map->bpages) != NULL || map->sync_count != 0) {
473 		CTR3(KTR_BUSDMA, "%s: tag %p error %d", __func__, dmat, EBUSY);
474 		return (EBUSY);
475 	}
476 	if (dmat->bounce_zone)
477 		dmat->bounce_zone->map_count--;
478 	free(map, M_DEVBUF);
479 	dmat->map_count--;
480 	CTR2(KTR_BUSDMA, "%s: tag %p error 0", __func__, dmat);
481 	return (0);
482 }
483 
484 /*
485  * Allocate a piece of memory that can be efficiently mapped into
486  * bus device space based on the constraints lited in the dma tag.
487  * A dmamap to for use with dmamap_load is also allocated.
488  */
489 static int
bounce_bus_dmamem_alloc(bus_dma_tag_t dmat,void ** vaddr,int flags,bus_dmamap_t * mapp)490 bounce_bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags,
491     bus_dmamap_t *mapp)
492 {
493 	vm_memattr_t attr;
494 	int mflags;
495 
496 	if (flags & BUS_DMA_NOWAIT)
497 		mflags = M_NOWAIT;
498 	else
499 		mflags = M_WAITOK;
500 
501 	if (dmat->segments == NULL) {
502 		dmat->segments = mallocarray_domainset(dmat->common.nsegments,
503 		    sizeof(bus_dma_segment_t), M_DEVBUF,
504 		    DOMAINSET_PREF(dmat->common.domain), mflags);
505 		if (dmat->segments == NULL) {
506 			CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
507 			    __func__, dmat, dmat->common.flags, ENOMEM);
508 			return (ENOMEM);
509 		}
510 	}
511 	if (flags & BUS_DMA_ZERO)
512 		mflags |= M_ZERO;
513 	if (flags & BUS_DMA_NOCACHE)
514 		attr = VM_MEMATTR_UNCACHEABLE;
515 	else if ((flags & BUS_DMA_COHERENT) != 0 &&
516 	    (dmat->bounce_flags & BF_COHERENT) == 0)
517 		/*
518 		 * If we have a non-coherent tag, and are trying to allocate
519 		 * a coherent block of memory it needs to be uncached.
520 		 */
521 		attr = VM_MEMATTR_UNCACHEABLE;
522 	else
523 		attr = VM_MEMATTR_DEFAULT;
524 
525 	/*
526 	 * Create the map, but don't set the could bounce flag as
527 	 * this allocation should never bounce;
528 	 */
529 	*mapp = alloc_dmamap(dmat, mflags);
530 	if (*mapp == NULL) {
531 		CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
532 		    __func__, dmat, dmat->common.flags, ENOMEM);
533 		return (ENOMEM);
534 	}
535 
536 	/*
537 	 * Mark the map as coherent if we used uncacheable memory or the
538 	 * tag was already marked as coherent.
539 	 */
540 	if (attr == VM_MEMATTR_UNCACHEABLE ||
541 	    (dmat->bounce_flags & BF_COHERENT) != 0)
542 		(*mapp)->flags |= DMAMAP_COHERENT;
543 
544 	(*mapp)->flags |= DMAMAP_FROM_DMAMEM;
545 
546 	/*
547 	 * Allocate the buffer from the malloc(9) allocator if...
548 	 *  - It's small enough to fit into a single page.
549 	 *  - Its alignment requirement is also smaller than the page size.
550 	 *  - The low address requirement is fulfilled.
551 	 *  - Default cache attributes are requested (WB).
552 	 * else allocate non-contiguous pages if...
553 	 *  - The page count that could get allocated doesn't exceed
554 	 *    nsegments also when the maximum segment size is less
555 	 *    than PAGE_SIZE.
556 	 *  - The alignment constraint isn't larger than a page boundary.
557 	 *  - There are no boundary-crossing constraints.
558 	 * else allocate a block of contiguous pages because one or more of the
559 	 * constraints is something that only the contig allocator can fulfill.
560 	 *
561 	 * NOTE: The (dmat->common.alignment <= dmat->maxsize) check
562 	 * below is just a quick hack. The exact alignment guarantees
563 	 * of malloc(9) need to be nailed down, and the code below
564 	 * should be rewritten to take that into account.
565 	 *
566 	 * In the meantime warn the user if malloc gets it wrong.
567 	 */
568 	if (dmat->alloc_size <= PAGE_SIZE &&
569 	    dmat->alloc_alignment <= PAGE_SIZE &&
570 	    dmat->common.lowaddr >= ptoa((vm_paddr_t)Maxmem) &&
571 	    attr == VM_MEMATTR_DEFAULT) {
572 		*vaddr = malloc_domainset_aligned(dmat->alloc_size,
573 		    dmat->alloc_alignment, M_DEVBUF,
574 		    DOMAINSET_PREF(dmat->common.domain), mflags);
575 	} else if (dmat->common.nsegments >=
576 	    howmany(dmat->alloc_size, MIN(dmat->common.maxsegsz, PAGE_SIZE)) &&
577 	    dmat->alloc_alignment <= PAGE_SIZE &&
578 	    (dmat->common.boundary % PAGE_SIZE) == 0) {
579 		/* Page-based multi-segment allocations allowed */
580 		*vaddr = kmem_alloc_attr_domainset(
581 		    DOMAINSET_PREF(dmat->common.domain), dmat->alloc_size,
582 		    mflags, 0ul, dmat->common.lowaddr, attr);
583 		dmat->bounce_flags |= BF_KMEM_ALLOC;
584 	} else {
585 		*vaddr = kmem_alloc_contig_domainset(
586 		    DOMAINSET_PREF(dmat->common.domain), dmat->alloc_size,
587 		    mflags, 0ul, dmat->common.lowaddr,
588 		    dmat->alloc_alignment != 0 ? dmat->alloc_alignment : 1ul,
589 		    dmat->common.boundary, attr);
590 		dmat->bounce_flags |= BF_KMEM_ALLOC;
591 	}
592 	if (*vaddr == NULL) {
593 		CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
594 		    __func__, dmat, dmat->common.flags, ENOMEM);
595 		free(*mapp, M_DEVBUF);
596 		return (ENOMEM);
597 	} else if (!vm_addr_align_ok(vtophys(*vaddr), dmat->alloc_alignment)) {
598 		printf("bus_dmamem_alloc failed to align memory properly.\n");
599 	}
600 	dmat->map_count++;
601 	CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
602 	    __func__, dmat, dmat->common.flags, 0);
603 	return (0);
604 }
605 
606 /*
607  * Free a piece of memory and it's allociated dmamap, that was allocated
608  * via bus_dmamem_alloc.  Make the same choice for free/contigfree.
609  */
610 static void
bounce_bus_dmamem_free(bus_dma_tag_t dmat,void * vaddr,bus_dmamap_t map)611 bounce_bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map)
612 {
613 
614 	/*
615 	 * Check the map came from bounce_bus_dmamem_alloc, so the map
616 	 * should be NULL and the BF_KMEM_ALLOC flag cleared if malloc()
617 	 * was used and set if kmem_alloc_contig() was used.
618 	 */
619 	if ((map->flags & DMAMAP_FROM_DMAMEM) == 0)
620 		panic("bus_dmamem_free: Invalid map freed\n");
621 	if ((dmat->bounce_flags & BF_KMEM_ALLOC) == 0)
622 		free(vaddr, M_DEVBUF);
623 	else
624 		kmem_free(vaddr, dmat->alloc_size);
625 	free(map, M_DEVBUF);
626 	dmat->map_count--;
627 	CTR3(KTR_BUSDMA, "%s: tag %p flags 0x%x", __func__, dmat,
628 	    dmat->bounce_flags);
629 }
630 
631 static bool
_bus_dmamap_pagesneeded(bus_dma_tag_t dmat,bus_dmamap_t map,vm_paddr_t buf,bus_size_t buflen,int * pagesneeded)632 _bus_dmamap_pagesneeded(bus_dma_tag_t dmat, bus_dmamap_t map, vm_paddr_t buf,
633     bus_size_t buflen, int *pagesneeded)
634 {
635 	bus_addr_t curaddr;
636 	bus_size_t sgsize;
637 	int count;
638 
639 	/*
640 	 * Count the number of bounce pages needed in order to
641 	 * complete this transfer
642 	 */
643 	count = 0;
644 	curaddr = buf;
645 	while (buflen != 0) {
646 		sgsize = buflen;
647 		if (must_bounce(dmat, map, curaddr, sgsize)) {
648 			sgsize = MIN(sgsize,
649 			    PAGE_SIZE - (curaddr & PAGE_MASK));
650 			if (pagesneeded == NULL)
651 				return (true);
652 			count++;
653 		}
654 		curaddr += sgsize;
655 		buflen -= sgsize;
656 	}
657 
658 	if (pagesneeded != NULL)
659 		*pagesneeded = count;
660 	return (count != 0);
661 }
662 
663 static void
_bus_dmamap_count_phys(bus_dma_tag_t dmat,bus_dmamap_t map,vm_paddr_t buf,bus_size_t buflen,int flags)664 _bus_dmamap_count_phys(bus_dma_tag_t dmat, bus_dmamap_t map, vm_paddr_t buf,
665     bus_size_t buflen, int flags)
666 {
667 
668 	if (map->pagesneeded == 0) {
669 		_bus_dmamap_pagesneeded(dmat, map, buf, buflen,
670 		    &map->pagesneeded);
671 		CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded);
672 	}
673 }
674 
675 static void
_bus_dmamap_count_pages(bus_dma_tag_t dmat,bus_dmamap_t map,pmap_t pmap,void * buf,bus_size_t buflen,int flags)676 _bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map, pmap_t pmap,
677     void *buf, bus_size_t buflen, int flags)
678 {
679 	vm_offset_t vaddr;
680 	vm_offset_t vendaddr;
681 	bus_addr_t paddr;
682 	bus_size_t sg_len;
683 
684 	if (map->pagesneeded == 0) {
685 		CTR4(KTR_BUSDMA, "lowaddr= %d Maxmem= %d, boundary= %d, "
686 		    "alignment= %d", dmat->common.lowaddr,
687 		    ptoa((vm_paddr_t)Maxmem),
688 		    dmat->common.boundary, dmat->common.alignment);
689 		CTR2(KTR_BUSDMA, "map= %p, pagesneeded= %d", map,
690 		    map->pagesneeded);
691 		/*
692 		 * Count the number of bounce pages
693 		 * needed in order to complete this transfer
694 		 */
695 		vaddr = (vm_offset_t)buf;
696 		vendaddr = (vm_offset_t)buf + buflen;
697 
698 		while (vaddr < vendaddr) {
699 			sg_len = MIN(vendaddr - vaddr,
700 			    PAGE_SIZE - ((vm_offset_t)vaddr & PAGE_MASK));
701 			if (pmap == kernel_pmap)
702 				paddr = pmap_kextract(vaddr);
703 			else
704 				paddr = pmap_extract(pmap, vaddr);
705 			if (must_bounce(dmat, map, paddr, sg_len) != 0) {
706 				sg_len = roundup2(sg_len,
707 				    dmat->common.alignment);
708 				map->pagesneeded++;
709 			}
710 			vaddr += sg_len;
711 		}
712 		CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded);
713 	}
714 }
715 
716 /*
717  * Utility function to load a physical buffer.  segp contains
718  * the starting segment on entrace, and the ending segment on exit.
719  */
720 static int
bounce_bus_dmamap_load_phys(bus_dma_tag_t dmat,bus_dmamap_t map,vm_paddr_t buf,bus_size_t buflen,int flags,bus_dma_segment_t * segs,int * segp)721 bounce_bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmamap_t map,
722     vm_paddr_t buf, bus_size_t buflen, int flags, bus_dma_segment_t *segs,
723     int *segp)
724 {
725 	struct sync_list *sl;
726 	bus_size_t sgsize;
727 	bus_addr_t curaddr, sl_end;
728 	int error;
729 
730 	if (segs == NULL)
731 		segs = dmat->segments;
732 
733 	if (might_bounce(dmat, map, (bus_addr_t)buf, buflen)) {
734 		_bus_dmamap_count_phys(dmat, map, buf, buflen, flags);
735 		if (map->pagesneeded != 0) {
736 			error = _bus_dmamap_reserve_pages(dmat, map, flags);
737 			if (error)
738 				return (error);
739 		}
740 	}
741 
742 	sl = map->slist + map->sync_count - 1;
743 	sl_end = 0;
744 
745 	while (buflen > 0) {
746 		curaddr = buf;
747 		sgsize = buflen;
748 		if (map->pagesneeded != 0 &&
749 		    must_bounce(dmat, map, curaddr, sgsize)) {
750 			/*
751 			 * The attempt to split a physically continuous buffer
752 			 * seems very controversial, it's unclear whether we
753 			 * can do this in all cases. Also, memory for bounced
754 			 * buffers is allocated as pages, so we cannot
755 			 * guarantee multipage alignment.
756 			 */
757 			KASSERT(dmat->common.alignment <= PAGE_SIZE,
758 			    ("bounced buffer cannot have alignment bigger "
759 			    "than PAGE_SIZE: %lu", dmat->common.alignment));
760 			sgsize = MIN(sgsize, PAGE_SIZE - (curaddr & PAGE_MASK));
761 			curaddr = add_bounce_page(dmat, map, 0, curaddr,
762 			    sgsize);
763 		} else if ((map->flags & DMAMAP_COHERENT) == 0) {
764 			if (map->sync_count > 0)
765 				sl_end = sl->paddr + sl->datacount;
766 
767 			if (map->sync_count == 0 || curaddr != sl_end) {
768 				if (++map->sync_count > dmat->common.nsegments)
769 					break;
770 				sl++;
771 				sl->vaddr = 0;
772 				sl->paddr = curaddr;
773 				sl->pages = PHYS_TO_VM_PAGE(curaddr);
774 				KASSERT(sl->pages != NULL,
775 				    ("%s: page at PA:0x%08lx is not in "
776 				    "vm_page_array", __func__, curaddr));
777 				sl->datacount = sgsize;
778 			} else
779 				sl->datacount += sgsize;
780 		}
781 		if (!_bus_dmamap_addsegs(dmat, map, curaddr, sgsize, segs,
782 		    segp))
783 			break;
784 		buf += sgsize;
785 		buflen -= sgsize;
786 	}
787 
788 	/*
789 	 * Did we fit?
790 	 */
791 	if (buflen != 0) {
792 		bus_dmamap_unload(dmat, map);
793 		return (EFBIG); /* XXX better return value here? */
794 	}
795 	return (0);
796 }
797 
798 /*
799  * Utility function to load a linear buffer.  segp contains
800  * the starting segment on entrace, and the ending segment on exit.
801  */
802 static int
bounce_bus_dmamap_load_buffer(bus_dma_tag_t dmat,bus_dmamap_t map,void * buf,bus_size_t buflen,pmap_t pmap,int flags,bus_dma_segment_t * segs,int * segp)803 bounce_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
804     bus_size_t buflen, pmap_t pmap, int flags, bus_dma_segment_t *segs,
805     int *segp)
806 {
807 	struct sync_list *sl;
808 	bus_size_t sgsize;
809 	bus_addr_t curaddr, sl_pend;
810 	vm_offset_t kvaddr, vaddr, sl_vend;
811 	int error;
812 
813 	KASSERT((map->flags & DMAMAP_FROM_DMAMEM) != 0 ||
814 	    dmat->common.alignment <= PAGE_SIZE,
815 	    ("loading user buffer with alignment bigger than PAGE_SIZE is not "
816 	    "supported"));
817 
818 	if (segs == NULL)
819 		segs = dmat->segments;
820 
821 	if (flags & BUS_DMA_LOAD_MBUF)
822 		map->flags |= DMAMAP_MBUF;
823 
824 	if (might_bounce(dmat, map, (bus_addr_t)buf, buflen)) {
825 		_bus_dmamap_count_pages(dmat, map, pmap, buf, buflen, flags);
826 		if (map->pagesneeded != 0) {
827 			error = _bus_dmamap_reserve_pages(dmat, map, flags);
828 			if (error)
829 				return (error);
830 		}
831 	}
832 
833 	/*
834 	 * XXX Optimally we should parse input buffer for physically
835 	 * continuous segments first and then pass these segment into
836 	 * load loop.
837 	 */
838 	sl = map->slist + map->sync_count - 1;
839 	vaddr = (vm_offset_t)buf;
840 	sl_pend = 0;
841 	sl_vend = 0;
842 
843 	while (buflen > 0) {
844 		/*
845 		 * Get the physical address for this segment.
846 		 */
847 		if (__predict_true(pmap == kernel_pmap)) {
848 			curaddr = pmap_kextract(vaddr);
849 			kvaddr = vaddr;
850 		} else {
851 			curaddr = pmap_extract(pmap, vaddr);
852 			kvaddr = 0;
853 		}
854 
855 		/*
856 		 * Compute the segment size, and adjust counts.
857 		 */
858 		sgsize = buflen;
859 		if ((map->flags & DMAMAP_FROM_DMAMEM) == 0)
860 			sgsize = MIN(sgsize, PAGE_SIZE - (curaddr & PAGE_MASK));
861 
862 		if (map->pagesneeded != 0 &&
863 		    must_bounce(dmat, map, curaddr, sgsize)) {
864 			/* See comment in bounce_bus_dmamap_load_phys */
865 			KASSERT(dmat->common.alignment <= PAGE_SIZE,
866 			    ("bounced buffer cannot have alignment bigger "
867 			    "than PAGE_SIZE: %lu", dmat->common.alignment));
868 			curaddr = add_bounce_page(dmat, map, kvaddr, curaddr,
869 			    sgsize);
870 		} else if ((map->flags & DMAMAP_COHERENT) == 0) {
871 			if (map->sync_count > 0) {
872 				sl_pend = sl->paddr + sl->datacount;
873 				sl_vend = sl->vaddr + sl->datacount;
874 			}
875 
876 			if (map->sync_count == 0 ||
877 			    (kvaddr != 0 && kvaddr != sl_vend) ||
878 			    (curaddr != sl_pend)) {
879 				if (++map->sync_count > dmat->common.nsegments)
880 					break;
881 				sl++;
882 				sl->vaddr = kvaddr;
883 				sl->paddr = curaddr;
884 				if (kvaddr != 0) {
885 					sl->pages = NULL;
886 				} else {
887 					sl->pages = PHYS_TO_VM_PAGE(curaddr);
888 					KASSERT(sl->pages != NULL,
889 					    ("%s: page at PA:0x%08lx is not "
890 					    "in vm_page_array", __func__,
891 					    curaddr));
892 				}
893 				sl->datacount = sgsize;
894 			} else
895 				sl->datacount += sgsize;
896 		}
897 		if (!_bus_dmamap_addsegs(dmat, map, curaddr, sgsize, segs,
898 		    segp))
899 			break;
900 		vaddr += sgsize;
901 		buflen -= sgsize;
902 	}
903 
904 	/*
905 	 * Did we fit?
906 	 */
907 	if (buflen != 0) {
908 		bus_dmamap_unload(dmat, map);
909 		return (EFBIG); /* XXX better return value here? */
910 	}
911 	return (0);
912 }
913 
914 static void
bounce_bus_dmamap_waitok(bus_dma_tag_t dmat,bus_dmamap_t map,struct memdesc * mem,bus_dmamap_callback_t * callback,void * callback_arg)915 bounce_bus_dmamap_waitok(bus_dma_tag_t dmat, bus_dmamap_t map,
916     struct memdesc *mem, bus_dmamap_callback_t *callback, void *callback_arg)
917 {
918 
919 	map->mem = *mem;
920 	map->dmat = dmat;
921 	map->callback = callback;
922 	map->callback_arg = callback_arg;
923 }
924 
925 static bus_dma_segment_t *
bounce_bus_dmamap_complete(bus_dma_tag_t dmat,bus_dmamap_t map,bus_dma_segment_t * segs,int nsegs,int error)926 bounce_bus_dmamap_complete(bus_dma_tag_t dmat, bus_dmamap_t map,
927     bus_dma_segment_t *segs, int nsegs, int error)
928 {
929 
930 	if (segs == NULL)
931 		segs = dmat->segments;
932 	return (segs);
933 }
934 
935 /*
936  * Release the mapping held by map.
937  */
938 static void
bounce_bus_dmamap_unload(bus_dma_tag_t dmat,bus_dmamap_t map)939 bounce_bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map)
940 {
941 	free_bounce_pages(dmat, map);
942 	map->sync_count = 0;
943 	map->flags &= ~DMAMAP_MBUF;
944 }
945 
946 static void
dma_preread_safe(char * va,vm_size_t size)947 dma_preread_safe(char *va, vm_size_t size)
948 {
949 	/*
950 	 * Write back any partial cachelines immediately before and
951 	 * after the DMA region.
952 	 */
953 	if (!__is_aligned(va, dcache_line_size))
954 		cpu_dcache_wb_range(va, 1);
955 	if (!__is_aligned(va + size, dcache_line_size))
956 		cpu_dcache_wb_range(va + size, 1);
957 
958 	cpu_dcache_inv_range(va, size);
959 }
960 
961 static void
dma_dcache_sync(struct sync_list * sl,bus_dmasync_op_t op)962 dma_dcache_sync(struct sync_list *sl, bus_dmasync_op_t op)
963 {
964 	uint32_t len, offset;
965 	vm_page_t m;
966 	vm_paddr_t pa;
967 	vm_offset_t va, tempva;
968 	bus_size_t size;
969 
970 	offset = sl->paddr & PAGE_MASK;
971 	m = sl->pages;
972 	size = sl->datacount;
973 	pa = sl->paddr;
974 
975 	for ( ; size != 0; size -= len, pa += len, offset = 0, ++m) {
976 		tempva = 0;
977 		if (sl->vaddr == 0) {
978 			len = min(PAGE_SIZE - offset, size);
979 			tempva = pmap_quick_enter_page(m);
980 			va = tempva | offset;
981 			KASSERT(pa == (VM_PAGE_TO_PHYS(m) | offset),
982 			    ("unexpected vm_page_t phys: 0x%16lx != 0x%16lx",
983 			    VM_PAGE_TO_PHYS(m) | offset, pa));
984 		} else {
985 			len = sl->datacount;
986 			va = sl->vaddr;
987 		}
988 
989 		switch (op) {
990 		case BUS_DMASYNC_PREWRITE:
991 		case BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD:
992 			cpu_dcache_wb_range((void *)va, len);
993 			break;
994 		case BUS_DMASYNC_PREREAD:
995 			/*
996 			 * An mbuf may start in the middle of a cacheline. There
997 			 * will be no cpu writes to the beginning of that line
998 			 * (which contains the mbuf header) while dma is in
999 			 * progress.  Handle that case by doing a writeback of
1000 			 * just the first cacheline before invalidating the
1001 			 * overall buffer.  Any mbuf in a chain may have this
1002 			 * misalignment.  Buffers which are not mbufs bounce if
1003 			 * they are not aligned to a cacheline.
1004 			 */
1005 			dma_preread_safe((void *)va, len);
1006 			break;
1007 		case BUS_DMASYNC_POSTREAD:
1008 		case BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE:
1009 			cpu_dcache_inv_range((void *)va, len);
1010 			break;
1011 		default:
1012 			panic("unsupported combination of sync operations: "
1013                               "0x%08x\n", op);
1014 		}
1015 
1016 		if (tempva != 0)
1017 			pmap_quick_remove_page(tempva);
1018 	}
1019 }
1020 
1021 static void
bounce_bus_dmamap_sync(bus_dma_tag_t dmat,bus_dmamap_t map,bus_dmasync_op_t op)1022 bounce_bus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map,
1023     bus_dmasync_op_t op)
1024 {
1025 	struct bounce_page *bpage;
1026 	struct sync_list *sl, *end;
1027 	vm_offset_t datavaddr, tempvaddr;
1028 
1029 	if (op == BUS_DMASYNC_POSTWRITE)
1030 		return;
1031 
1032 	if ((op & BUS_DMASYNC_POSTREAD) != 0) {
1033 		/*
1034 		 * Wait for any DMA operations to complete before the bcopy.
1035 		 */
1036 		dsb(sy);
1037 	}
1038 
1039 	if ((bpage = STAILQ_FIRST(&map->bpages)) != NULL) {
1040 		CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x op 0x%x "
1041 		    "performing bounce", __func__, dmat, dmat->common.flags,
1042 		    op);
1043 
1044 		if ((op & BUS_DMASYNC_PREWRITE) != 0) {
1045 			while (bpage != NULL) {
1046 				tempvaddr = 0;
1047 				datavaddr = bpage->datavaddr;
1048 				if (datavaddr == 0) {
1049 					tempvaddr = pmap_quick_enter_page(
1050 					    bpage->datapage);
1051 					datavaddr = tempvaddr | bpage->dataoffs;
1052 				}
1053 
1054 				bcopy((void *)datavaddr,
1055 				    (void *)bpage->vaddr, bpage->datacount);
1056 				if (tempvaddr != 0)
1057 					pmap_quick_remove_page(tempvaddr);
1058 				if ((map->flags & DMAMAP_COHERENT) == 0)
1059 					cpu_dcache_wb_range((void *)bpage->vaddr,
1060 					    bpage->datacount);
1061 				bpage = STAILQ_NEXT(bpage, links);
1062 			}
1063 			dmat->bounce_zone->total_bounced++;
1064 		} else if ((op & BUS_DMASYNC_PREREAD) != 0) {
1065 			while (bpage != NULL) {
1066 				if ((map->flags & DMAMAP_COHERENT) == 0)
1067 					cpu_dcache_wbinv_range((void *)bpage->vaddr,
1068 					    bpage->datacount);
1069 				bpage = STAILQ_NEXT(bpage, links);
1070 			}
1071 		}
1072 
1073 		if ((op & BUS_DMASYNC_POSTREAD) != 0) {
1074 			while (bpage != NULL) {
1075 				if ((map->flags & DMAMAP_COHERENT) == 0)
1076 					cpu_dcache_inv_range((void *)bpage->vaddr,
1077 					    bpage->datacount);
1078 				tempvaddr = 0;
1079 				datavaddr = bpage->datavaddr;
1080 				if (datavaddr == 0) {
1081 					tempvaddr = pmap_quick_enter_page(
1082 					    bpage->datapage);
1083 					datavaddr = tempvaddr | bpage->dataoffs;
1084 				}
1085 
1086 				bcopy((void *)bpage->vaddr,
1087 				    (void *)datavaddr, bpage->datacount);
1088 
1089 				if (tempvaddr != 0)
1090 					pmap_quick_remove_page(tempvaddr);
1091 				bpage = STAILQ_NEXT(bpage, links);
1092 			}
1093 			dmat->bounce_zone->total_bounced++;
1094 		}
1095 	}
1096 
1097 	/*
1098 	 * Cache maintenance for normal (non-COHERENT non-bounce) buffers.
1099 	 */
1100 	if (map->sync_count != 0) {
1101 		sl = &map->slist[0];
1102 		end = &map->slist[map->sync_count];
1103 		CTR3(KTR_BUSDMA, "%s: tag %p op 0x%x "
1104 		    "performing sync", __func__, dmat, op);
1105 
1106 		for ( ; sl != end; ++sl)
1107 			dma_dcache_sync(sl, op);
1108 	}
1109 
1110 	if ((op & (BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE)) != 0) {
1111 		/*
1112 		 * Wait for the bcopy to complete before any DMA operations.
1113 		 */
1114 		dsb(sy);
1115 	}
1116 
1117 	kmsan_bus_dmamap_sync(&map->kmsan_mem, op);
1118 }
1119 
1120 #ifdef KMSAN
1121 static void
bounce_bus_dmamap_load_kmsan(bus_dmamap_t map,struct memdesc * mem)1122 bounce_bus_dmamap_load_kmsan(bus_dmamap_t map, struct memdesc *mem)
1123 {
1124 	if (map == NULL)
1125 		return;
1126 	memcpy(&map->kmsan_mem, mem, sizeof(map->kmsan_mem));
1127 }
1128 #endif
1129 
1130 struct bus_dma_impl bus_dma_bounce_impl = {
1131 	.tag_create = bounce_bus_dma_tag_create,
1132 	.tag_destroy = bounce_bus_dma_tag_destroy,
1133 	.tag_set_domain = bounce_bus_dma_tag_set_domain,
1134 	.id_mapped = bounce_bus_dma_id_mapped,
1135 	.map_create = bounce_bus_dmamap_create,
1136 	.map_destroy = bounce_bus_dmamap_destroy,
1137 	.mem_alloc = bounce_bus_dmamem_alloc,
1138 	.mem_free = bounce_bus_dmamem_free,
1139 	.load_phys = bounce_bus_dmamap_load_phys,
1140 	.load_buffer = bounce_bus_dmamap_load_buffer,
1141 	.load_ma = bus_dmamap_load_ma_triv,
1142 	.map_waitok = bounce_bus_dmamap_waitok,
1143 	.map_complete = bounce_bus_dmamap_complete,
1144 	.map_unload = bounce_bus_dmamap_unload,
1145 	.map_sync = bounce_bus_dmamap_sync,
1146 #ifdef KMSAN
1147 	.load_kmsan = bounce_bus_dmamap_load_kmsan,
1148 #endif
1149 };
1150