busdma_machdep-v6.c revision 239597
1/*-
2 * Copyright (c) 2010 Mark Tinguely
3 * Copyright (c) 2004 Olivier Houchard
4 * Copyright (c) 2002 Peter Grehan
5 * Copyright (c) 1997, 1998 Justin T. Gibbs.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions, and the following disclaimer,
13 *    without modification, immediately at the beginning of the file.
14 * 2. The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 *  From i386/busdma_machdep.c 191438 2009-04-23 20:24:19Z jhb
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD: head/sys/arm/arm/busdma_machdep-v6.c 239597 2012-08-22 22:48:50Z gonzo $");
34
35#define _ARM32_BUS_DMA_PRIVATE
36#include <sys/param.h>
37#include <sys/kdb.h>
38#include <ddb/ddb.h>
39#include <ddb/db_output.h>
40#include <sys/systm.h>
41#include <sys/malloc.h>
42#include <sys/bus.h>
43#include <sys/interrupt.h>
44#include <sys/kernel.h>
45#include <sys/ktr.h>
46#include <sys/lock.h>
47#include <sys/proc.h>
48#include <sys/mutex.h>
49#include <sys/mbuf.h>
50#include <sys/uio.h>
51#include <sys/sysctl.h>
52
53#include <vm/vm.h>
54#include <vm/vm_page.h>
55#include <vm/vm_map.h>
56
57#include <machine/atomic.h>
58#include <machine/bus.h>
59#include <machine/cpufunc.h>
60#include <machine/md_var.h>
61
62#define MAX_BPAGES 64
63#define BUS_DMA_COULD_BOUNCE	BUS_DMA_BUS3
64#define BUS_DMA_MIN_ALLOC_COMP	BUS_DMA_BUS4
65
66#define FIX_DMAP_BUS_DMASYNC_POSTREAD
67
68struct bounce_zone;
69
70struct bus_dma_tag {
71	bus_dma_tag_t	  parent;
72	bus_size_t	  alignment;
73	bus_size_t	  boundary;
74	bus_addr_t	  lowaddr;
75	bus_addr_t	  highaddr;
76	bus_dma_filter_t *filter;
77	void		 *filterarg;
78	bus_size_t	  maxsize;
79	u_int		  nsegments;
80	bus_size_t	  maxsegsz;
81	int		  flags;
82	int		  ref_count;
83	int		  map_count;
84	bus_dma_lock_t	 *lockfunc;
85	void		 *lockfuncarg;
86	bus_dma_segment_t *segments;
87	struct bounce_zone *bounce_zone;
88	/*
89	 * DMA range for this tag.  If the page doesn't fall within
90	 * one of these ranges, an error is returned.  The caller
91	 * may then decide what to do with the transfer.  If the
92	 * range pointer is NULL, it is ignored.
93	 */
94	struct arm32_dma_range	*ranges;
95	int			_nranges;
96
97};
98
99struct bounce_page {
100	vm_offset_t	vaddr;		/* kva of bounce buffer */
101	bus_addr_t	busaddr;	/* Physical address */
102	vm_offset_t	datavaddr;	/* kva of client data */
103	bus_size_t	datacount;	/* client data count */
104	STAILQ_ENTRY(bounce_page) links;
105};
106
107struct sync_list {
108	vm_offset_t	vaddr;		/* kva of bounce buffer */
109	bus_addr_t	busaddr;	/* Physical address */
110	bus_size_t	datacount;	/* client data count */
111	STAILQ_ENTRY(sync_list) slinks;
112};
113
114int busdma_swi_pending;
115
116struct bounce_zone {
117	STAILQ_ENTRY(bounce_zone) links;
118	STAILQ_HEAD(bp_list, bounce_page) bounce_page_list;
119	int		total_bpages;
120	int		free_bpages;
121	int		reserved_bpages;
122	int		active_bpages;
123	int		total_bounced;
124	int		total_deferred;
125	int		map_count;
126	bus_size_t	alignment;
127	bus_addr_t	lowaddr;
128	char		zoneid[8];
129	char		lowaddrid[20];
130	struct sysctl_ctx_list sysctl_tree;
131	struct sysctl_oid *sysctl_tree_top;
132};
133
134static struct mtx bounce_lock;
135static int total_bpages;
136static int busdma_zonecount;
137static STAILQ_HEAD(, bounce_zone) bounce_zone_list;
138
139SYSCTL_NODE(_hw, OID_AUTO, busdma, CTLFLAG_RD, 0, "Busdma parameters");
140SYSCTL_INT(_hw_busdma, OID_AUTO, total_bpages, CTLFLAG_RD, &total_bpages, 0,
141	   "Total bounce pages");
142
143struct bus_dmamap {
144	struct bp_list	       bpages;
145	int		       pagesneeded;
146	int		       pagesreserved;
147	bus_dma_tag_t	       dmat;
148	void		      *buf;		/* unmapped buffer pointer */
149	bus_size_t	       buflen;		/* unmapped buffer length */
150	pmap_t		       pmap;
151	bus_dmamap_callback_t *callback;
152	void		      *callback_arg;
153	STAILQ_ENTRY(bus_dmamap) links;
154	STAILQ_HEAD(,sync_list)	slist;
155};
156
157static STAILQ_HEAD(, bus_dmamap) bounce_map_waitinglist;
158static STAILQ_HEAD(, bus_dmamap) bounce_map_callbacklist;
159
160static void init_bounce_pages(void *dummy);
161static int alloc_bounce_zone(bus_dma_tag_t dmat);
162static int alloc_bounce_pages(bus_dma_tag_t dmat, u_int numpages);
163static int reserve_bounce_pages(bus_dma_tag_t dmat, bus_dmamap_t map,
164				int commit);
165static bus_addr_t add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map,
166				   vm_offset_t vaddr, bus_size_t size);
167static void free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage);
168int run_filter(bus_dma_tag_t dmat, bus_addr_t paddr);
169static int _bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map,
170    void *buf, bus_size_t buflen, int flags);
171
172static __inline int
173_bus_dma_can_bounce(vm_offset_t lowaddr, vm_offset_t highaddr)
174{
175	int i;
176	for (i = 0; phys_avail[i] && phys_avail[i + 1]; i += 2) {
177		if ((lowaddr >= phys_avail[i] && lowaddr <= phys_avail[i + 1])
178		    || (lowaddr < phys_avail[i] &&
179		    highaddr > phys_avail[i]))
180			return (1);
181	}
182	return (0);
183}
184
185static __inline struct arm32_dma_range *
186_bus_dma_inrange(struct arm32_dma_range *ranges, int nranges,
187    bus_addr_t curaddr)
188{
189	struct arm32_dma_range *dr;
190	int i;
191
192	for (i = 0, dr = ranges; i < nranges; i++, dr++) {
193		if (curaddr >= dr->dr_sysbase &&
194		    round_page(curaddr) <= (dr->dr_sysbase + dr->dr_len))
195			return (dr);
196	}
197
198	return (NULL);
199}
200
201/*
202 * Return true if a match is made.
203 *
204 * To find a match walk the chain of bus_dma_tag_t's looking for 'paddr'.
205 *
206 * If paddr is within the bounds of the dma tag then call the filter callback
207 * to check for a match, if there is no filter callback then assume a match.
208 */
209int
210run_filter(bus_dma_tag_t dmat, bus_addr_t paddr)
211{
212	int retval;
213
214	retval = 0;
215
216	do {
217		if (((paddr > dmat->lowaddr && paddr <= dmat->highaddr)
218		 || ((paddr & (dmat->alignment - 1)) != 0))
219		 && (dmat->filter == NULL
220		  || (*dmat->filter)(dmat->filterarg, paddr) != 0))
221			retval = 1;
222
223		dmat = dmat->parent;
224	} while (retval == 0 && dmat != NULL);
225	return (retval);
226}
227
228/*
229 * Convenience function for manipulating driver locks from busdma (during
230 * busdma_swi, for example).  Drivers that don't provide their own locks
231 * should specify &Giant to dmat->lockfuncarg.  Drivers that use their own
232 * non-mutex locking scheme don't have to use this at all.
233 */
234void
235busdma_lock_mutex(void *arg, bus_dma_lock_op_t op)
236{
237	struct mtx *dmtx;
238
239	dmtx = (struct mtx *)arg;
240	switch (op) {
241	case BUS_DMA_LOCK:
242		mtx_lock(dmtx);
243		break;
244	case BUS_DMA_UNLOCK:
245		mtx_unlock(dmtx);
246		break;
247	default:
248		panic("Unknown operation 0x%x for busdma_lock_mutex!", op);
249	}
250}
251
252/*
253 * dflt_lock should never get called.  It gets put into the dma tag when
254 * lockfunc == NULL, which is only valid if the maps that are associated
255 * with the tag are meant to never be defered.
256 * XXX Should have a way to identify which driver is responsible here.
257 */
258static void
259dflt_lock(void *arg, bus_dma_lock_op_t op)
260{
261	panic("driver error: busdma dflt_lock called");
262}
263
264/*
265 * Allocate a device specific dma_tag.
266 */
267int
268bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment,
269		   bus_size_t boundary, bus_addr_t lowaddr,
270		   bus_addr_t highaddr, bus_dma_filter_t *filter,
271		   void *filterarg, bus_size_t maxsize, int nsegments,
272		   bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc,
273		   void *lockfuncarg, bus_dma_tag_t *dmat)
274{
275	bus_dma_tag_t newtag;
276	int error = 0;
277
278#if 0
279	if (!parent)
280		parent = arm_root_dma_tag;
281#endif
282
283	/* Basic sanity checking */
284	if (boundary != 0 && boundary < maxsegsz)
285		maxsegsz = boundary;
286
287	/* Return a NULL tag on failure */
288	*dmat = NULL;
289
290	if (maxsegsz == 0) {
291		return (EINVAL);
292	}
293
294	newtag = (bus_dma_tag_t)malloc(sizeof(*newtag), M_DEVBUF,
295	    M_ZERO | M_NOWAIT);
296	if (newtag == NULL) {
297		CTR4(KTR_BUSDMA, "%s returned tag %p tag flags 0x%x error %d",
298		    __func__, newtag, 0, error);
299		return (ENOMEM);
300	}
301
302	newtag->parent = parent;
303	newtag->alignment = alignment;
304	newtag->boundary = boundary;
305	newtag->lowaddr = trunc_page((vm_paddr_t)lowaddr) + (PAGE_SIZE - 1);
306	newtag->highaddr = trunc_page((vm_paddr_t)highaddr) +
307	    (PAGE_SIZE - 1);
308	newtag->filter = filter;
309	newtag->filterarg = filterarg;
310	newtag->maxsize = maxsize;
311	newtag->nsegments = nsegments;
312	newtag->maxsegsz = maxsegsz;
313	newtag->flags = flags;
314	newtag->ref_count = 1; /* Count ourself */
315	newtag->map_count = 0;
316	newtag->ranges = bus_dma_get_range();
317	newtag->_nranges = bus_dma_get_range_nb();
318	if (lockfunc != NULL) {
319		newtag->lockfunc = lockfunc;
320		newtag->lockfuncarg = lockfuncarg;
321	} else {
322		newtag->lockfunc = dflt_lock;
323		newtag->lockfuncarg = NULL;
324	}
325	newtag->segments = NULL;
326
327	/* Take into account any restrictions imposed by our parent tag */
328	if (parent != NULL) {
329		newtag->lowaddr = MIN(parent->lowaddr, newtag->lowaddr);
330		newtag->highaddr = MAX(parent->highaddr, newtag->highaddr);
331		if (newtag->boundary == 0)
332			newtag->boundary = parent->boundary;
333		else if (parent->boundary != 0)
334			newtag->boundary = MIN(parent->boundary,
335					       newtag->boundary);
336		if ((newtag->filter != NULL) ||
337		    ((parent->flags & BUS_DMA_COULD_BOUNCE) != 0))
338			newtag->flags |= BUS_DMA_COULD_BOUNCE;
339		if (newtag->filter == NULL) {
340			/*
341			 * Short circuit looking at our parent directly
342			 * since we have encapsulated all of its information
343			 */
344			newtag->filter = parent->filter;
345			newtag->filterarg = parent->filterarg;
346			newtag->parent = parent->parent;
347		}
348		if (newtag->parent != NULL)
349			atomic_add_int(&parent->ref_count, 1);
350	}
351
352	if (_bus_dma_can_bounce(newtag->lowaddr, newtag->highaddr)
353	 || newtag->alignment > 1)
354		newtag->flags |= BUS_DMA_COULD_BOUNCE;
355
356	if (((newtag->flags & BUS_DMA_COULD_BOUNCE) != 0) &&
357	    (flags & BUS_DMA_ALLOCNOW) != 0) {
358		struct bounce_zone *bz;
359
360		/* Must bounce */
361
362		if ((error = alloc_bounce_zone(newtag)) != 0) {
363			free(newtag, M_DEVBUF);
364			return (error);
365		}
366		bz = newtag->bounce_zone;
367
368		if (ptoa(bz->total_bpages) < maxsize) {
369			int pages;
370
371			pages = atop(maxsize) - bz->total_bpages;
372
373			/* Add pages to our bounce pool */
374			if (alloc_bounce_pages(newtag, pages) < pages)
375				error = ENOMEM;
376		}
377		/* Performed initial allocation */
378		newtag->flags |= BUS_DMA_MIN_ALLOC_COMP;
379	} else
380		newtag->bounce_zone = NULL;
381
382	if (error != 0) {
383		free(newtag, M_DEVBUF);
384	} else {
385		*dmat = newtag;
386	}
387	CTR4(KTR_BUSDMA, "%s returned tag %p tag flags 0x%x error %d",
388	    __func__, newtag, (newtag != NULL ? newtag->flags : 0), error);
389	return (error);
390}
391
392int
393bus_dma_tag_destroy(bus_dma_tag_t dmat)
394{
395	bus_dma_tag_t dmat_copy;
396	int error;
397
398	error = 0;
399	dmat_copy = dmat;
400
401	if (dmat != NULL) {
402
403		if (dmat->map_count != 0) {
404			error = EBUSY;
405			goto out;
406		}
407
408		while (dmat != NULL) {
409			bus_dma_tag_t parent;
410
411			parent = dmat->parent;
412			atomic_subtract_int(&dmat->ref_count, 1);
413			if (dmat->ref_count == 0) {
414				if (dmat->segments != NULL)
415					free(dmat->segments, M_DEVBUF);
416				free(dmat, M_DEVBUF);
417				/*
418				 * Last reference count, so
419				 * release our reference
420				 * count on our parent.
421				 */
422				dmat = parent;
423			} else
424				dmat = NULL;
425		}
426	}
427out:
428	CTR3(KTR_BUSDMA, "%s tag %p error %d", __func__, dmat_copy, error);
429	return (error);
430}
431
432/*
433 * Allocate a handle for mapping from kva/uva/physical
434 * address space into bus device space.
435 */
436int
437bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp)
438{
439	int error;
440
441	error = 0;
442
443	*mapp = (bus_dmamap_t)malloc(sizeof(**mapp), M_DEVBUF,
444					     M_NOWAIT | M_ZERO);
445	if (*mapp == NULL) {
446		CTR3(KTR_BUSDMA, "%s: tag %p error %d", __func__, dmat, ENOMEM);
447		return (ENOMEM);
448	}
449	STAILQ_INIT(&((*mapp)->slist));
450
451	if (dmat->segments == NULL) {
452		dmat->segments = (bus_dma_segment_t *)malloc(
453		    sizeof(bus_dma_segment_t) * dmat->nsegments, M_DEVBUF,
454		    M_NOWAIT);
455		if (dmat->segments == NULL) {
456			CTR3(KTR_BUSDMA, "%s: tag %p error %d",
457			    __func__, dmat, ENOMEM);
458			free(*mapp, M_DEVBUF);
459			*mapp = NULL;
460			return (ENOMEM);
461		}
462	}
463	/*
464	 * Bouncing might be required if the driver asks for an active
465	 * exclusion region, a data alignment that is stricter than 1, and/or
466	 * an active address boundary.
467	 */
468	if (dmat->flags & BUS_DMA_COULD_BOUNCE) {
469
470		/* Must bounce */
471		struct bounce_zone *bz;
472		int maxpages;
473
474		if (dmat->bounce_zone == NULL) {
475			if ((error = alloc_bounce_zone(dmat)) != 0) {
476				free(*mapp, M_DEVBUF);
477				*mapp = NULL;
478				return (error);
479			}
480		}
481		bz = dmat->bounce_zone;
482
483		/* Initialize the new map */
484		STAILQ_INIT(&((*mapp)->bpages));
485
486		/*
487		 * Attempt to add pages to our pool on a per-instance
488		 * basis up to a sane limit.
489		 */
490		maxpages = MAX_BPAGES;
491		if ((dmat->flags & BUS_DMA_MIN_ALLOC_COMP) == 0
492		 || (bz->map_count > 0 && bz->total_bpages < maxpages)) {
493			int pages;
494
495			pages = MAX(atop(dmat->maxsize), 1);
496			pages = MIN(maxpages - bz->total_bpages, pages);
497			pages = MAX(pages, 1);
498			if (alloc_bounce_pages(dmat, pages) < pages)
499				error = ENOMEM;
500
501			if ((dmat->flags & BUS_DMA_MIN_ALLOC_COMP) == 0) {
502				if (error == 0)
503					dmat->flags |= BUS_DMA_MIN_ALLOC_COMP;
504			} else {
505				error = 0;
506			}
507		}
508		bz->map_count++;
509	}
510	if (error == 0)
511		dmat->map_count++;
512	CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
513	    __func__, dmat, dmat->flags, error);
514	return (error);
515}
516
517/*
518 * Destroy a handle for mapping from kva/uva/physical
519 * address space into bus device space.
520 */
521int
522bus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map)
523{
524	if (STAILQ_FIRST(&map->bpages) != NULL ||
525	    STAILQ_FIRST(&map->slist) != NULL) {
526		CTR3(KTR_BUSDMA, "%s: tag %p error %d",
527		    __func__, dmat, EBUSY);
528		return (EBUSY);
529	}
530	if (dmat->bounce_zone)
531		dmat->bounce_zone->map_count--;
532	free(map, M_DEVBUF);
533	dmat->map_count--;
534	CTR2(KTR_BUSDMA, "%s: tag %p error 0", __func__, dmat);
535	return (0);
536}
537
538
539/*
540 * Allocate a piece of memory that can be efficiently mapped into
541 * bus device space based on the constraints lited in the dma tag.
542 * A dmamap to for use with dmamap_load is also allocated.
543 */
544int
545bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags,
546		 bus_dmamap_t *mapp)
547{
548	int mflags, len;
549
550	if (flags & BUS_DMA_NOWAIT)
551		mflags = M_NOWAIT;
552	else
553		mflags = M_WAITOK;
554
555	/* ARM non-snooping caches need a map for the VA cache sync structure */
556
557	*mapp = (bus_dmamap_t)malloc(sizeof(**mapp), M_DEVBUF,
558					     M_NOWAIT | M_ZERO);
559	if (*mapp == NULL) {
560		CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
561		    __func__, dmat, dmat->flags, ENOMEM);
562		return (ENOMEM);
563	}
564
565	STAILQ_INIT(&((*mapp)->slist));
566
567	if (dmat->segments == NULL) {
568		dmat->segments = (bus_dma_segment_t *)malloc(
569		    sizeof(bus_dma_segment_t) * dmat->nsegments, M_DEVBUF,
570		    mflags);
571		if (dmat->segments == NULL) {
572			CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
573			    __func__, dmat, dmat->flags, ENOMEM);
574			free(*mapp, M_DEVBUF);
575			*mapp = NULL;
576			return (ENOMEM);
577		}
578	}
579
580	if (flags & BUS_DMA_ZERO)
581		mflags |= M_ZERO;
582
583	/*
584	 * XXX:
585	 * (dmat->alignment < dmat->maxsize) is just a quick hack; the exact
586	 * alignment guarantees of malloc need to be nailed down, and the
587	 * code below should be rewritten to take that into account.
588	 *
589	 * In the meantime, we'll warn the user if malloc gets it wrong.
590	 *
591	 * allocate at least a cache line. This should help avoid cache
592	 * corruption.
593	 */
594	len = max(dmat->maxsize, arm_dcache_align);
595        if (len <= PAGE_SIZE &&
596	   (dmat->alignment < len) &&
597	   !_bus_dma_can_bounce(dmat->lowaddr, dmat->highaddr)) {
598		*vaddr = malloc(len, M_DEVBUF, mflags);
599	} else {
600		/*
601		 * XXX Use Contigmalloc until it is merged into this facility
602		 *     and handles multi-seg allocations.  Nobody is doing
603		 *     multi-seg allocations yet though.
604		 * XXX Certain AGP hardware does.
605		 */
606		*vaddr = contigmalloc(len, M_DEVBUF, mflags,
607		    0ul, dmat->lowaddr, dmat->alignment? dmat->alignment : 1ul,
608		    dmat->boundary);
609	}
610	if (*vaddr == NULL) {
611		CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
612		    __func__, dmat, dmat->flags, ENOMEM);
613		free(*mapp, M_DEVBUF);
614		*mapp = NULL;
615		return (ENOMEM);
616	} else if ((uintptr_t)*vaddr & (dmat->alignment - 1)) {
617		printf("bus_dmamem_alloc failed to align memory properly.\n");
618	}
619	dmat->map_count++;
620
621	CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
622	    __func__, dmat, dmat->flags, 0);
623	return (0);
624}
625
626/*
627 * Free a piece of memory and it's allociated dmamap, that was allocated
628 * via bus_dmamem_alloc.  Make the same choice for free/contigfree.
629 */
630void
631bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map)
632{
633	int len;
634
635#ifdef mftnotyet
636	pmap_change_attr((vm_offset_t)vaddr, dmat->maxsize, ARM_WRITE_BACK);
637#endif
638	len = max(dmat->maxsize, arm_dcache_align);
639        if (len <= PAGE_SIZE &&
640	   (dmat->alignment < len) &&
641	   !_bus_dma_can_bounce(dmat->lowaddr, dmat->highaddr))
642		free(vaddr, M_DEVBUF);
643	else {
644		contigfree(vaddr, len, M_DEVBUF);
645	}
646	dmat->map_count--;
647	free(map, M_DEVBUF);
648	CTR3(KTR_BUSDMA, "%s: tag %p flags 0x%x", __func__, dmat, dmat->flags);
649}
650
651static int
652_bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map,
653    void *buf, bus_size_t buflen, int flags)
654{
655	vm_offset_t vaddr;
656	vm_offset_t vendaddr;
657	bus_addr_t paddr;
658
659	if (map->pagesneeded == 0) {
660		CTR5(KTR_BUSDMA, "lowaddr= %d, boundary= %d, alignment= %d"
661		    " map= %p, pagesneeded= %d",
662		    dmat->lowaddr, dmat->boundary, dmat->alignment,
663		    map, map->pagesneeded);
664		/*
665		 * Count the number of bounce pages
666		 * needed in order to complete this transfer
667		 */
668		vaddr = (vm_offset_t)buf;
669		vendaddr = (vm_offset_t)buf + buflen;
670
671		while (vaddr < vendaddr) {
672			if (__predict_true(map->pmap == pmap_kernel()))
673				paddr = pmap_kextract(vaddr);
674			else
675				paddr = pmap_extract(map->pmap, vaddr);
676			if (((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0) &&
677			    run_filter(dmat, paddr) != 0) {
678				map->pagesneeded++;
679			}
680			vaddr += (PAGE_SIZE - ((vm_offset_t)vaddr & PAGE_MASK));
681
682		}
683		CTR1(KTR_BUSDMA, "pagesneeded= %d", map->pagesneeded);
684	}
685
686	/* Reserve Necessary Bounce Pages */
687	if (map->pagesneeded != 0) {
688		mtx_lock(&bounce_lock);
689		if (flags & BUS_DMA_NOWAIT) {
690			if (reserve_bounce_pages(dmat, map, 0) != 0) {
691				map->pagesneeded = 0;
692				mtx_unlock(&bounce_lock);
693				return (ENOMEM);
694			}
695		} else {
696			if (reserve_bounce_pages(dmat, map, 1) != 0) {
697				/* Queue us for resources */
698				map->dmat = dmat;
699				map->buf = buf;
700				map->buflen = buflen;
701				STAILQ_INSERT_TAIL(&bounce_map_waitinglist,
702				    map, links);
703				mtx_unlock(&bounce_lock);
704				return (EINPROGRESS);
705			}
706		}
707		mtx_unlock(&bounce_lock);
708	}
709
710	return (0);
711}
712
713/*
714 * Utility function to load a linear buffer. lastaddrp holds state
715 * between invocations (for multiple-buffer loads).  segp contains
716 * the starting segment on entrace, and the ending segment on exit.
717 * first indicates if this is the first invocation of this function.
718 */
719static __inline int
720_bus_dmamap_load_buffer(bus_dma_tag_t dmat,
721			bus_dmamap_t map,
722			void *buf, bus_size_t buflen,
723			int flags,
724			bus_addr_t *lastaddrp,
725			bus_dma_segment_t *segs,
726			int *segp,
727			int first)
728{
729	bus_size_t sgsize;
730	bus_addr_t curaddr, lastaddr, baddr, bmask;
731	vm_offset_t vaddr;
732	struct sync_list *sl;
733	int seg, error;
734
735	if ((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0) {
736		error = _bus_dmamap_count_pages(dmat, map, buf, buflen, flags);
737		if (error)
738			return (error);
739	}
740
741	sl = NULL;
742	vaddr = (vm_offset_t)buf;
743	lastaddr = *lastaddrp;
744	bmask = ~(dmat->boundary - 1);
745
746	for (seg = *segp; buflen > 0 ; ) {
747		/*
748		 * Get the physical address for this segment.
749		 */
750		if (__predict_true(map->pmap == pmap_kernel()))
751			curaddr = pmap_kextract(vaddr);
752		else
753			curaddr = pmap_extract(map->pmap, vaddr);
754
755		/*
756		 * Compute the segment size, and adjust counts.
757		 */
758		sgsize = PAGE_SIZE - ((u_long)curaddr & PAGE_MASK);
759		if (sgsize > dmat->maxsegsz)
760			sgsize = dmat->maxsegsz;
761		if (buflen < sgsize)
762			sgsize = buflen;
763
764		/*
765		 * Make sure we don't cross any boundaries.
766		 */
767		if (dmat->boundary > 0) {
768			baddr = (curaddr + dmat->boundary) & bmask;
769			if (sgsize > (baddr - curaddr))
770				sgsize = (baddr - curaddr);
771		}
772
773		if (((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0) &&
774		    map->pagesneeded != 0 && run_filter(dmat, curaddr)) {
775			curaddr = add_bounce_page(dmat, map, vaddr, sgsize);
776		} else {
777			/* add_sync_list(dmat, map, vaddr, sgsize, cflag); */
778			sl = (struct sync_list *)malloc(sizeof(struct sync_list),
779						M_DEVBUF, M_NOWAIT | M_ZERO);
780			if (sl == NULL)
781				goto cleanup;
782			STAILQ_INSERT_TAIL(&(map->slist), sl, slinks);
783			sl->vaddr = vaddr;
784			sl->datacount = sgsize;
785			sl->busaddr = curaddr;
786		}
787
788
789		if (dmat->ranges) {
790			struct arm32_dma_range *dr;
791
792			dr = _bus_dma_inrange(dmat->ranges, dmat->_nranges,
793			    curaddr);
794			if (dr == NULL) {
795				_bus_dmamap_unload(dmat, map);
796				return (EINVAL);
797			}
798			/*
799			 * In a valid DMA range.  Translate the physical
800			 * memory address to an address in the DMA window.
801			 */
802			curaddr = (curaddr - dr->dr_sysbase) + dr->dr_busbase;
803		}
804
805		/*
806		 * Insert chunk into a segment, coalescing with
807		 * previous segment if possible.
808		 */
809		if (first) {
810			segs[seg].ds_addr = curaddr;
811			segs[seg].ds_len = sgsize;
812			first = 0;
813		} else {
814			if (curaddr == lastaddr &&
815			    (segs[seg].ds_len + sgsize) <= dmat->maxsegsz &&
816			    (dmat->boundary == 0 ||
817			     (segs[seg].ds_addr & bmask) == (curaddr & bmask)))
818				segs[seg].ds_len += sgsize;
819			else {
820				if (++seg >= dmat->nsegments)
821					break;
822				segs[seg].ds_addr = curaddr;
823				segs[seg].ds_len = sgsize;
824			}
825		}
826
827		lastaddr = curaddr + sgsize;
828		vaddr += sgsize;
829		buflen -= sgsize;
830	}
831
832	*segp = seg;
833	*lastaddrp = lastaddr;
834cleanup:
835	/*
836	 * Did we fit?
837	 */
838	if (buflen != 0) {
839		_bus_dmamap_unload(dmat, map);
840		return(EFBIG); /* XXX better return value here? */
841	}
842	return (0);
843}
844
845/*
846 * Map the buffer buf into bus space using the dmamap map.
847 */
848int
849bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
850		bus_size_t buflen, bus_dmamap_callback_t *callback,
851		void *callback_arg, int flags)
852{
853	bus_addr_t		lastaddr = 0;
854	int			error, nsegs = 0;
855
856	flags |= BUS_DMA_WAITOK;
857	map->callback = callback;
858	map->callback_arg = callback_arg;
859	map->pmap = kernel_pmap;
860
861	error = _bus_dmamap_load_buffer(dmat, map, buf, buflen, flags,
862		     &lastaddr, dmat->segments, &nsegs, 1);
863
864	CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
865	    __func__, dmat, dmat->flags, error, nsegs + 1);
866
867	if (error == EINPROGRESS) {
868		return (error);
869	}
870
871	if (error)
872		(*callback)(callback_arg, dmat->segments, 0, error);
873	else
874		(*callback)(callback_arg, dmat->segments, nsegs + 1, 0);
875
876	/*
877	 * Return ENOMEM to the caller so that it can pass it up the stack.
878	 * This error only happens when NOWAIT is set, so deferal is disabled.
879	 */
880	if (error == ENOMEM)
881		return (error);
882
883	return (0);
884}
885
886
887/*
888 * Like _bus_dmamap_load(), but for mbufs.
889 */
890static __inline int
891_bus_dmamap_load_mbuf_sg(bus_dma_tag_t dmat, bus_dmamap_t map,
892			struct mbuf *m0, bus_dma_segment_t *segs, int *nsegs,
893			int flags)
894{
895	int error;
896
897	M_ASSERTPKTHDR(m0);
898	map->pmap = kernel_pmap;
899
900	flags |= BUS_DMA_NOWAIT;
901	*nsegs = 0;
902	error = 0;
903	if (m0->m_pkthdr.len <= dmat->maxsize) {
904		int first = 1;
905		bus_addr_t lastaddr = 0;
906		struct mbuf *m;
907
908		for (m = m0; m != NULL && error == 0; m = m->m_next) {
909			if (m->m_len > 0) {
910				error = _bus_dmamap_load_buffer(dmat, map,
911						m->m_data, m->m_len,
912						flags, &lastaddr,
913						segs, nsegs, first);
914				first = 0;
915			}
916		}
917	} else {
918		error = EINVAL;
919	}
920
921	/* XXX FIXME: Having to increment nsegs is really annoying */
922	++*nsegs;
923	CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
924	    __func__, dmat, dmat->flags, error, *nsegs);
925	return (error);
926}
927
928int
929bus_dmamap_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map,
930		     struct mbuf *m0,
931		     bus_dmamap_callback2_t *callback, void *callback_arg,
932		     int flags)
933{
934	int nsegs, error;
935
936	error = _bus_dmamap_load_mbuf_sg(dmat, map, m0, dmat->segments, &nsegs,
937		    flags);
938
939	if (error) {
940		/* force "no valid mappings" in callback */
941		(*callback)(callback_arg, dmat->segments, 0, 0, error);
942	} else {
943		(*callback)(callback_arg, dmat->segments,
944			    nsegs, m0->m_pkthdr.len, error);
945	}
946	CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
947	    __func__, dmat, dmat->flags, error, nsegs);
948
949	return (error);
950}
951
952int
953bus_dmamap_load_mbuf_sg(bus_dma_tag_t dmat, bus_dmamap_t map,
954			struct mbuf *m0, bus_dma_segment_t *segs, int *nsegs,
955			int flags)
956{
957	return (_bus_dmamap_load_mbuf_sg(dmat, map, m0, segs, nsegs, flags));
958}
959
960/*
961 * Like _bus_dmamap_load(), but for uios.
962 */
963int
964bus_dmamap_load_uio(bus_dma_tag_t dmat, bus_dmamap_t map,
965		    struct uio *uio,
966		    bus_dmamap_callback2_t *callback, void *callback_arg,
967		    int flags)
968{
969	bus_addr_t lastaddr;
970	int nsegs, error, first, i;
971	bus_size_t resid;
972	struct iovec *iov;
973
974	flags |= BUS_DMA_NOWAIT;
975	resid = uio->uio_resid;
976	iov = uio->uio_iov;
977
978	if (uio->uio_segflg == UIO_USERSPACE) {
979		KASSERT(uio->uio_td != NULL,
980			("bus_dmamap_load_uio: USERSPACE but no proc"));
981		map->pmap = vmspace_pmap(uio->uio_td->td_proc->p_vmspace);
982	} else
983		map->pmap = kernel_pmap;
984
985	nsegs = 0;
986	error = 0;
987	first = 1;
988	lastaddr = (bus_addr_t) 0;
989	for (i = 0; i < uio->uio_iovcnt && resid != 0 && !error; i++) {
990		/*
991		 * Now at the first iovec to load.  Load each iovec
992		 * until we have exhausted the residual count.
993		 */
994		bus_size_t minlen =
995			resid < iov[i].iov_len ? resid : iov[i].iov_len;
996		caddr_t addr = (caddr_t) iov[i].iov_base;
997
998		if (minlen > 0) {
999			error = _bus_dmamap_load_buffer(dmat, map,
1000					addr, minlen, flags, &lastaddr,
1001					dmat->segments, &nsegs, first);
1002			first = 0;
1003			resid -= minlen;
1004		}
1005	}
1006
1007	if (error) {
1008		/* force "no valid mappings" in callback */
1009		(*callback)(callback_arg, dmat->segments, 0, 0, error);
1010	} else {
1011		(*callback)(callback_arg, dmat->segments,
1012			    nsegs+1, uio->uio_resid, error);
1013	}
1014	CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
1015	    __func__, dmat, dmat->flags, error, nsegs + 1);
1016	return (error);
1017}
1018
1019/*
1020 * Release the mapping held by map.
1021 */
1022void
1023_bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map)
1024{
1025	struct bounce_page *bpage;
1026	struct bounce_zone *bz;
1027	struct sync_list *sl;
1028
1029        while ((sl = STAILQ_FIRST(&map->slist)) != NULL) {
1030                STAILQ_REMOVE_HEAD(&map->slist, slinks);
1031                free(sl, M_DEVBUF);
1032        }
1033
1034	if ((bz = dmat->bounce_zone) != NULL) {
1035		while ((bpage = STAILQ_FIRST(&map->bpages)) != NULL) {
1036			STAILQ_REMOVE_HEAD(&map->bpages, links);
1037			free_bounce_page(dmat, bpage);
1038		}
1039
1040		bz = dmat->bounce_zone;
1041		bz->free_bpages += map->pagesreserved;
1042		bz->reserved_bpages -= map->pagesreserved;
1043		map->pagesreserved = 0;
1044		map->pagesneeded = 0;
1045	}
1046}
1047
1048#ifdef notyetbounceuser
1049	/* If busdma uses user pages, then the interrupt handler could
1050	 * be use the kernel vm mapping. Both bounce pages and sync list
1051	 * do not cross page boundaries.
1052	 * Below is a rough sequence that a person would do to fix the
1053	 * user page reference in the kernel vmspace. This would be
1054	 * done in the dma post routine.
1055	 */
1056void
1057_bus_dmamap_fix_user(vm_offset_t buf, bus_size_t len,
1058			pmap_t pmap, int op)
1059{
1060	bus_size_t sgsize;
1061	bus_addr_t curaddr;
1062	vm_offset_t va;
1063
1064		/* each synclist entry is contained within a single page.
1065		 *
1066		 * this would be needed if BUS_DMASYNC_POSTxxxx was implemented
1067		*/
1068	curaddr = pmap_extract(pmap, buf);
1069	va = pmap_dma_map(curaddr);
1070	switch (op) {
1071	case SYNC_USER_INV:
1072		cpu_dcache_wb_range(va, sgsize);
1073		break;
1074
1075	case SYNC_USER_COPYTO:
1076		bcopy((void *)va, (void *)bounce, sgsize);
1077		break;
1078
1079	case SYNC_USER_COPYFROM:
1080		bcopy((void *) bounce, (void *)va, sgsize);
1081		break;
1082
1083	default:
1084		break;
1085	}
1086
1087	pmap_dma_unmap(va);
1088}
1089#endif
1090
1091#ifdef ARM_L2_PIPT
1092#define l2cache_wb_range(va, pa, size) cpu_l2cache_wb_range(pa, size)
1093#define l2cache_wbinv_range(va, pa, size) cpu_l2cache_wbinv_range(pa, size)
1094#define l2cache_inv_range(va, pa, size) cpu_l2cache_inv_range(pa, size)
1095#else
1096#define l2cache_wb_range(va, pa, size) cpu_l2cache_wb_range(va, size)
1097#define l2cache_wbinv_range(va, pa, size) cpu_l2cache_wbinv_range(va, size)
1098#define l2cache_inv_range(va, pa, size) cpu_l2cache_wbinv_range(va, size)
1099#endif
1100
1101void
1102_bus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dmasync_op_t op)
1103{
1104	struct bounce_page *bpage;
1105	struct sync_list *sl;
1106	bus_size_t len, unalign;
1107	vm_offset_t buf, ebuf;
1108#ifdef FIX_DMAP_BUS_DMASYNC_POSTREAD
1109	vm_offset_t bbuf;
1110	char _tmp_cl[arm_dcache_align], _tmp_clend[arm_dcache_align];
1111#endif
1112	int listcount = 0;
1113
1114		/* if buffer was from user space, it it possible that this
1115		 * is not the same vm map. The fix is to map each page in
1116		 * the buffer into the current address space (KVM) and then
1117		 * do the bounce copy or sync list cache operation.
1118		 *
1119		 * The sync list entries are already broken into
1120		 * their respective physical pages.
1121		 */
1122	if (!pmap_dmap_iscurrent(map->pmap))
1123		printf("_bus_dmamap_sync: wrong user map: %p %x\n", map->pmap, op);
1124
1125	if ((bpage = STAILQ_FIRST(&map->bpages)) != NULL) {
1126
1127		/* Handle data bouncing. */
1128		CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x op 0x%x "
1129		    "performing bounce", __func__, dmat, dmat->flags, op);
1130
1131		if (op & BUS_DMASYNC_PREWRITE) {
1132			while (bpage != NULL) {
1133				bcopy((void *)bpage->datavaddr,
1134				      (void *)bpage->vaddr,
1135				      bpage->datacount);
1136				cpu_dcache_wb_range((vm_offset_t)bpage->vaddr,
1137					bpage->datacount);
1138				l2cache_wb_range((vm_offset_t)bpage->vaddr,
1139				    (vm_offset_t)bpage->busaddr,
1140				    bpage->datacount);
1141				bpage = STAILQ_NEXT(bpage, links);
1142			}
1143			dmat->bounce_zone->total_bounced++;
1144		}
1145
1146		if (op & BUS_DMASYNC_POSTREAD) {
1147			if (!pmap_dmap_iscurrent(map->pmap))
1148			    panic("_bus_dmamap_sync: wrong user map. apply fix");
1149
1150			cpu_dcache_inv_range((vm_offset_t)bpage->vaddr,
1151					bpage->datacount);
1152			l2cache_inv_range((vm_offset_t)bpage->vaddr,
1153			    (vm_offset_t)bpage->busaddr,
1154			    bpage->datacount);
1155			while (bpage != NULL) {
1156				vm_offset_t startv;
1157				vm_paddr_t startp;
1158				int len;
1159
1160				startv = bpage->vaddr &~ arm_dcache_align_mask;
1161				startp = bpage->busaddr &~ arm_dcache_align_mask;
1162				len = bpage->datacount;
1163
1164				if (startv != bpage->vaddr)
1165					len += bpage->vaddr & arm_dcache_align_mask;
1166				if (len & arm_dcache_align_mask)
1167					len = (len -
1168					    (len & arm_dcache_align_mask)) +
1169					    arm_dcache_align;
1170				cpu_dcache_inv_range(startv, len);
1171				l2cache_inv_range(startv, startp, len);
1172				bcopy((void *)bpage->vaddr,
1173				      (void *)bpage->datavaddr,
1174				      bpage->datacount);
1175				bpage = STAILQ_NEXT(bpage, links);
1176			}
1177			dmat->bounce_zone->total_bounced++;
1178		}
1179	}
1180
1181	sl = STAILQ_FIRST(&map->slist);
1182	while (sl) {
1183		listcount++;
1184		sl = STAILQ_NEXT(sl, slinks);
1185	}
1186	if ((sl = STAILQ_FIRST(&map->slist)) != NULL) {
1187		/* ARM caches are not self-snooping for dma */
1188
1189		CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x op 0x%x "
1190		    "performing sync", __func__, dmat, dmat->flags, op);
1191
1192		switch (op) {
1193		case BUS_DMASYNC_PREWRITE:
1194			while (sl != NULL) {
1195			    cpu_dcache_wb_range(sl->vaddr, sl->datacount);
1196			    l2cache_wb_range(sl->vaddr, sl->busaddr,
1197				sl->datacount);
1198			    sl = STAILQ_NEXT(sl, slinks);
1199			}
1200			break;
1201
1202		case BUS_DMASYNC_PREREAD:
1203			while (sl != NULL) {
1204					/* write back the unaligned portions */
1205				vm_paddr_t physaddr = sl->busaddr, ephysaddr;
1206				buf = sl->vaddr;
1207				len = sl->datacount;
1208				ebuf = buf + len;	/* end of buffer */
1209				ephysaddr = physaddr + len;
1210				unalign = buf & arm_dcache_align_mask;
1211				if (unalign) {
1212						/* wbinv leading fragment */
1213					buf &= ~arm_dcache_align_mask;
1214					physaddr &= ~arm_dcache_align_mask;
1215					cpu_dcache_wbinv_range(buf,
1216							arm_dcache_align);
1217					l2cache_wbinv_range(buf, physaddr,
1218					    arm_dcache_align);
1219					buf += arm_dcache_align;
1220					physaddr += arm_dcache_align;
1221					/* number byte in buffer wbinv */
1222					unalign = arm_dcache_align - unalign;
1223					if (len > unalign)
1224						len -= unalign;
1225					else
1226						len = 0;
1227				}
1228				unalign = ebuf & arm_dcache_align_mask;
1229				if (ebuf > buf && unalign) {
1230						/* wbinv trailing fragment */
1231					len -= unalign;
1232					ebuf -= unalign;
1233					ephysaddr -= unalign;
1234					cpu_dcache_wbinv_range(ebuf,
1235							arm_dcache_align);
1236					l2cache_wbinv_range(ebuf, ephysaddr,
1237					    arm_dcache_align);
1238				}
1239				if (ebuf > buf) {
1240					cpu_dcache_inv_range(buf, len);
1241					l2cache_inv_range(buf, physaddr, len);
1242				}
1243				sl = STAILQ_NEXT(sl, slinks);
1244			}
1245			break;
1246
1247		case BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD:
1248			while (sl != NULL) {
1249				cpu_dcache_wbinv_range(sl->vaddr, sl->datacount);
1250				l2cache_wbinv_range(sl->vaddr,
1251				    sl->busaddr, sl->datacount);
1252				sl = STAILQ_NEXT(sl, slinks);
1253			}
1254			break;
1255
1256#ifdef FIX_DMAP_BUS_DMASYNC_POSTREAD
1257		case BUS_DMASYNC_POSTREAD:
1258			if (!pmap_dmap_iscurrent(map->pmap))
1259			     panic("_bus_dmamap_sync: wrong user map. apply fix");
1260			while (sl != NULL) {
1261					/* write back the unaligned portions */
1262				vm_paddr_t physaddr;
1263				buf = sl->vaddr;
1264				len = sl->datacount;
1265				physaddr = sl->busaddr;
1266				bbuf = buf & ~arm_dcache_align_mask;
1267				ebuf = buf + len;
1268				physaddr = physaddr & ~arm_dcache_align_mask;
1269				unalign = buf & arm_dcache_align_mask;
1270				if (unalign) {
1271					memcpy(_tmp_cl, (void *)bbuf, unalign);
1272					len += unalign; /* inv entire cache line */
1273				}
1274				unalign = ebuf & arm_dcache_align_mask;
1275				if (unalign) {
1276					unalign = arm_dcache_align - unalign;
1277					memcpy(_tmp_clend, (void *)ebuf, unalign);
1278					len += unalign; /* inv entire cache line */
1279				}
1280					/* inv are cache length aligned */
1281				cpu_dcache_inv_range(bbuf, len);
1282				l2cache_inv_range(bbuf, physaddr, len);
1283
1284				unalign = (vm_offset_t)buf & arm_dcache_align_mask;
1285				if (unalign) {
1286					memcpy((void *)bbuf, _tmp_cl, unalign);
1287				}
1288				unalign = ebuf & arm_dcache_align_mask;
1289				if (unalign) {
1290					unalign = arm_dcache_align - unalign;
1291					memcpy((void *)ebuf, _tmp_clend, unalign);
1292				}
1293				sl = STAILQ_NEXT(sl, slinks);
1294			}
1295				break;
1296#endif /* FIX_DMAP_BUS_DMASYNC_POSTREAD */
1297
1298		default:
1299			break;
1300		}
1301	}
1302}
1303
1304static void
1305init_bounce_pages(void *dummy __unused)
1306{
1307
1308	total_bpages = 0;
1309	STAILQ_INIT(&bounce_zone_list);
1310	STAILQ_INIT(&bounce_map_waitinglist);
1311	STAILQ_INIT(&bounce_map_callbacklist);
1312	mtx_init(&bounce_lock, "bounce pages lock", NULL, MTX_DEF);
1313}
1314SYSINIT(bpages, SI_SUB_LOCK, SI_ORDER_ANY, init_bounce_pages, NULL);
1315
1316static struct sysctl_ctx_list *
1317busdma_sysctl_tree(struct bounce_zone *bz)
1318{
1319	return (&bz->sysctl_tree);
1320}
1321
1322static struct sysctl_oid *
1323busdma_sysctl_tree_top(struct bounce_zone *bz)
1324{
1325	return (bz->sysctl_tree_top);
1326}
1327
1328static int
1329alloc_bounce_zone(bus_dma_tag_t dmat)
1330{
1331	struct bounce_zone *bz;
1332
1333	/* Check to see if we already have a suitable zone */
1334	STAILQ_FOREACH(bz, &bounce_zone_list, links) {
1335		if ((dmat->alignment <= bz->alignment)
1336		 && (dmat->lowaddr >= bz->lowaddr)) {
1337			dmat->bounce_zone = bz;
1338			return (0);
1339		}
1340	}
1341
1342	if ((bz = (struct bounce_zone *)malloc(sizeof(*bz), M_DEVBUF,
1343	    M_NOWAIT | M_ZERO)) == NULL)
1344		return (ENOMEM);
1345
1346	STAILQ_INIT(&bz->bounce_page_list);
1347	bz->free_bpages = 0;
1348	bz->reserved_bpages = 0;
1349	bz->active_bpages = 0;
1350	bz->lowaddr = dmat->lowaddr;
1351	bz->alignment = MAX(dmat->alignment, PAGE_SIZE);
1352	bz->map_count = 0;
1353	snprintf(bz->zoneid, 8, "zone%d", busdma_zonecount);
1354	busdma_zonecount++;
1355	snprintf(bz->lowaddrid, 18, "%#jx", (uintmax_t)bz->lowaddr);
1356	STAILQ_INSERT_TAIL(&bounce_zone_list, bz, links);
1357	dmat->bounce_zone = bz;
1358
1359	sysctl_ctx_init(&bz->sysctl_tree);
1360	bz->sysctl_tree_top = SYSCTL_ADD_NODE(&bz->sysctl_tree,
1361	    SYSCTL_STATIC_CHILDREN(_hw_busdma), OID_AUTO, bz->zoneid,
1362	    CTLFLAG_RD, 0, "");
1363	if (bz->sysctl_tree_top == NULL) {
1364		sysctl_ctx_free(&bz->sysctl_tree);
1365		return (0);	/* XXX error code? */
1366	}
1367
1368	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
1369	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
1370	    "total_bpages", CTLFLAG_RD, &bz->total_bpages, 0,
1371	    "Total bounce pages");
1372	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
1373	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
1374	    "free_bpages", CTLFLAG_RD, &bz->free_bpages, 0,
1375	    "Free bounce pages");
1376	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
1377	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
1378	    "reserved_bpages", CTLFLAG_RD, &bz->reserved_bpages, 0,
1379	    "Reserved bounce pages");
1380	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
1381	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
1382	    "active_bpages", CTLFLAG_RD, &bz->active_bpages, 0,
1383	    "Active bounce pages");
1384	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
1385	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
1386	    "total_bounced", CTLFLAG_RD, &bz->total_bounced, 0,
1387	    "Total bounce requests");
1388	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
1389	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
1390	    "total_deferred", CTLFLAG_RD, &bz->total_deferred, 0,
1391	    "Total bounce requests that were deferred");
1392	SYSCTL_ADD_STRING(busdma_sysctl_tree(bz),
1393	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
1394	    "lowaddr", CTLFLAG_RD, bz->lowaddrid, 0, "");
1395	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
1396	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
1397	    "alignment", CTLFLAG_RD, &bz->alignment, 0, "");
1398
1399	return (0);
1400}
1401
1402static int
1403alloc_bounce_pages(bus_dma_tag_t dmat, u_int numpages)
1404{
1405	struct bounce_zone *bz;
1406	int count;
1407
1408	bz = dmat->bounce_zone;
1409	count = 0;
1410	while (numpages > 0) {
1411		struct bounce_page *bpage;
1412
1413		bpage = (struct bounce_page *)malloc(sizeof(*bpage), M_DEVBUF,
1414						     M_NOWAIT | M_ZERO);
1415
1416		if (bpage == NULL)
1417			break;
1418		bpage->vaddr = (vm_offset_t)contigmalloc(PAGE_SIZE, M_DEVBUF,
1419							 M_NOWAIT, 0ul,
1420							 bz->lowaddr,
1421							 PAGE_SIZE,
1422							 0);
1423		if (bpage->vaddr == 0) {
1424			free(bpage, M_DEVBUF);
1425			break;
1426		}
1427		bpage->busaddr = pmap_kextract(bpage->vaddr);
1428		mtx_lock(&bounce_lock);
1429		STAILQ_INSERT_TAIL(&bz->bounce_page_list, bpage, links);
1430		total_bpages++;
1431		bz->total_bpages++;
1432		bz->free_bpages++;
1433		mtx_unlock(&bounce_lock);
1434		count++;
1435		numpages--;
1436	}
1437	return (count);
1438}
1439
1440static int
1441reserve_bounce_pages(bus_dma_tag_t dmat, bus_dmamap_t map, int commit)
1442{
1443	struct bounce_zone *bz;
1444	int pages;
1445
1446	mtx_assert(&bounce_lock, MA_OWNED);
1447	bz = dmat->bounce_zone;
1448	pages = MIN(bz->free_bpages, map->pagesneeded - map->pagesreserved);
1449	if (commit == 0 && map->pagesneeded > (map->pagesreserved + pages))
1450		return (map->pagesneeded - (map->pagesreserved + pages));
1451	bz->free_bpages -= pages;
1452	bz->reserved_bpages += pages;
1453	map->pagesreserved += pages;
1454	pages = map->pagesneeded - map->pagesreserved;
1455
1456	return (pages);
1457}
1458
1459static bus_addr_t
1460add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, vm_offset_t vaddr,
1461		bus_size_t size)
1462{
1463	struct bounce_zone *bz;
1464	struct bounce_page *bpage;
1465
1466	printf("add bounce page\n");
1467	KASSERT(dmat->bounce_zone != NULL, ("no bounce zone in dma tag"));
1468	KASSERT(map != NULL,
1469	    ("add_bounce_page: bad map %p", map));
1470
1471	bz = dmat->bounce_zone;
1472	if (map->pagesneeded == 0)
1473		panic("add_bounce_page: map doesn't need any pages");
1474	map->pagesneeded--;
1475
1476	if (map->pagesreserved == 0)
1477		panic("add_bounce_page: map doesn't need any pages");
1478	map->pagesreserved--;
1479
1480	mtx_lock(&bounce_lock);
1481	bpage = STAILQ_FIRST(&bz->bounce_page_list);
1482	if (bpage == NULL)
1483		panic("add_bounce_page: free page list is empty");
1484
1485	STAILQ_REMOVE_HEAD(&bz->bounce_page_list, links);
1486	bz->reserved_bpages--;
1487	bz->active_bpages++;
1488	mtx_unlock(&bounce_lock);
1489
1490	if (dmat->flags & BUS_DMA_KEEP_PG_OFFSET) {
1491		/* Page offset needs to be preserved. */
1492		bpage->vaddr |= vaddr & PAGE_MASK;
1493		bpage->busaddr |= vaddr & PAGE_MASK;
1494	}
1495	bpage->datavaddr = vaddr;
1496	bpage->datacount = size;
1497	STAILQ_INSERT_TAIL(&(map->bpages), bpage, links);
1498	return (bpage->busaddr);
1499}
1500
1501static void
1502free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage)
1503{
1504	struct bus_dmamap *map;
1505	struct bounce_zone *bz;
1506
1507	bz = dmat->bounce_zone;
1508	bpage->datavaddr = 0;
1509	bpage->datacount = 0;
1510	if (dmat->flags & BUS_DMA_KEEP_PG_OFFSET) {
1511		/*
1512		 * Reset the bounce page to start at offset 0.  Other uses
1513		 * of this bounce page may need to store a full page of
1514		 * data and/or assume it starts on a page boundary.
1515		 */
1516		bpage->vaddr &= ~PAGE_MASK;
1517		bpage->busaddr &= ~PAGE_MASK;
1518	}
1519
1520	mtx_lock(&bounce_lock);
1521	STAILQ_INSERT_HEAD(&bz->bounce_page_list, bpage, links);
1522	bz->free_bpages++;
1523	bz->active_bpages--;
1524	if ((map = STAILQ_FIRST(&bounce_map_waitinglist)) != NULL) {
1525		if (reserve_bounce_pages(map->dmat, map, 1) == 0) {
1526			STAILQ_REMOVE_HEAD(&bounce_map_waitinglist, links);
1527			STAILQ_INSERT_TAIL(&bounce_map_callbacklist,
1528					   map, links);
1529			busdma_swi_pending = 1;
1530			bz->total_deferred++;
1531			swi_sched(vm_ih, 0);
1532		}
1533	}
1534	mtx_unlock(&bounce_lock);
1535}
1536
1537void
1538busdma_swi(void)
1539{
1540	bus_dma_tag_t dmat;
1541	struct bus_dmamap *map;
1542
1543	mtx_lock(&bounce_lock);
1544	while ((map = STAILQ_FIRST(&bounce_map_callbacklist)) != NULL) {
1545		STAILQ_REMOVE_HEAD(&bounce_map_callbacklist, links);
1546		mtx_unlock(&bounce_lock);
1547		dmat = map->dmat;
1548		(dmat->lockfunc)(dmat->lockfuncarg, BUS_DMA_LOCK);
1549		bus_dmamap_load(map->dmat, map, map->buf, map->buflen,
1550				map->callback, map->callback_arg, /*flags*/0);
1551		(dmat->lockfunc)(dmat->lockfuncarg, BUS_DMA_UNLOCK);
1552		mtx_lock(&bounce_lock);
1553	}
1554	mtx_unlock(&bounce_lock);
1555}
1556