xref: /freebsd/sys/arm64/arm64/busdma_machdep.c (revision 3933ff56)
11ca4eb3aSZbigniew Bodek /*-
21ca4eb3aSZbigniew Bodek  * Copyright (c) 1997, 1998 Justin T. Gibbs.
31ca4eb3aSZbigniew Bodek  * Copyright (c) 2013, 2015 The FreeBSD Foundation
41ca4eb3aSZbigniew Bodek  * All rights reserved.
51ca4eb3aSZbigniew Bodek  *
61ca4eb3aSZbigniew Bodek  * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
71ca4eb3aSZbigniew Bodek  * under sponsorship from the FreeBSD Foundation.
81ca4eb3aSZbigniew Bodek  *
91ca4eb3aSZbigniew Bodek  * Portions of this software were developed by Semihalf
101ca4eb3aSZbigniew Bodek  * under sponsorship of the FreeBSD Foundation.
111ca4eb3aSZbigniew Bodek  *
121ca4eb3aSZbigniew Bodek  * Redistribution and use in source and binary forms, with or without
131ca4eb3aSZbigniew Bodek  * modification, are permitted provided that the following conditions
141ca4eb3aSZbigniew Bodek  * are met:
151ca4eb3aSZbigniew Bodek  * 1. Redistributions of source code must retain the above copyright
161ca4eb3aSZbigniew Bodek  *    notice, this list of conditions, and the following disclaimer,
171ca4eb3aSZbigniew Bodek  *    without modification, immediately at the beginning of the file.
181ca4eb3aSZbigniew Bodek  * 2. The name of the author may not be used to endorse or promote products
191ca4eb3aSZbigniew Bodek  *    derived from this software without specific prior written permission.
201ca4eb3aSZbigniew Bodek  *
211ca4eb3aSZbigniew Bodek  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
221ca4eb3aSZbigniew Bodek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231ca4eb3aSZbigniew Bodek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241ca4eb3aSZbigniew Bodek  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
251ca4eb3aSZbigniew Bodek  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261ca4eb3aSZbigniew Bodek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271ca4eb3aSZbigniew Bodek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281ca4eb3aSZbigniew Bodek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291ca4eb3aSZbigniew Bodek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301ca4eb3aSZbigniew Bodek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311ca4eb3aSZbigniew Bodek  * SUCH DAMAGE.
321ca4eb3aSZbigniew Bodek  */
33e5acd89cSAndrew Turner 
34e5acd89cSAndrew Turner #include <sys/param.h>
35e5acd89cSAndrew Turner #include <sys/systm.h>
361ca4eb3aSZbigniew Bodek #include <sys/malloc.h>
371ca4eb3aSZbigniew Bodek #include <sys/bus.h>
381ca4eb3aSZbigniew Bodek #include <sys/kernel.h>
391ca4eb3aSZbigniew Bodek #include <sys/ktr.h>
401ca4eb3aSZbigniew Bodek #include <sys/lock.h>
411ca4eb3aSZbigniew Bodek #include <sys/memdesc.h>
421ca4eb3aSZbigniew Bodek #include <sys/mutex.h>
431ca4eb3aSZbigniew Bodek #include <sys/uio.h>
44e5acd89cSAndrew Turner #include <vm/vm.h>
451ca4eb3aSZbigniew Bodek #include <vm/vm_extern.h>
46271e669eSAndrew Turner #include <vm/vm_phys.h>
47e5acd89cSAndrew Turner #include <vm/pmap.h>
48e5acd89cSAndrew Turner 
49e5acd89cSAndrew Turner #include <machine/bus.h>
501ca4eb3aSZbigniew Bodek #include <arm64/include/bus_dma_impl.h>
511ca4eb3aSZbigniew Bodek 
521ca4eb3aSZbigniew Bodek int
common_bus_dma_tag_create(struct bus_dma_tag_common * 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,size_t sz,void ** dmat)531ca4eb3aSZbigniew Bodek common_bus_dma_tag_create(struct bus_dma_tag_common *parent,
541ca4eb3aSZbigniew Bodek     bus_size_t alignment, bus_addr_t boundary, bus_addr_t lowaddr,
55900907f4SMitchell Horne     bus_addr_t highaddr, bus_size_t maxsize, int nsegments,
56900907f4SMitchell Horne     bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc,
57900907f4SMitchell Horne     void *lockfuncarg, size_t sz, void **dmat)
581ca4eb3aSZbigniew Bodek {
591ca4eb3aSZbigniew Bodek 	void *newtag;
601ca4eb3aSZbigniew Bodek 	struct bus_dma_tag_common *common;
611ca4eb3aSZbigniew Bodek 
621ca4eb3aSZbigniew Bodek 	KASSERT(sz >= sizeof(struct bus_dma_tag_common), ("sz"));
631ca4eb3aSZbigniew Bodek 	/* Return a NULL tag on failure */
641ca4eb3aSZbigniew Bodek 	*dmat = NULL;
651ca4eb3aSZbigniew Bodek 	/* Basic sanity checking */
661ca4eb3aSZbigniew Bodek 	if (boundary != 0 && boundary < maxsegsz)
671ca4eb3aSZbigniew Bodek 		maxsegsz = boundary;
681ca4eb3aSZbigniew Bodek 	if (maxsegsz == 0)
691ca4eb3aSZbigniew Bodek 		return (EINVAL);
701ca4eb3aSZbigniew Bodek 
711ca4eb3aSZbigniew Bodek 	newtag = malloc(sz, M_DEVBUF, M_ZERO | M_NOWAIT);
721ca4eb3aSZbigniew Bodek 	if (newtag == NULL) {
731ca4eb3aSZbigniew Bodek 		CTR4(KTR_BUSDMA, "%s returned tag %p tag flags 0x%x error %d",
741ca4eb3aSZbigniew Bodek 		    __func__, newtag, 0, ENOMEM);
751ca4eb3aSZbigniew Bodek 		return (ENOMEM);
761ca4eb3aSZbigniew Bodek 	}
771ca4eb3aSZbigniew Bodek 
781ca4eb3aSZbigniew Bodek 	common = newtag;
791ca4eb3aSZbigniew Bodek 	common->impl = &bus_dma_bounce_impl;
801ca4eb3aSZbigniew Bodek 	common->alignment = alignment;
811ca4eb3aSZbigniew Bodek 	common->boundary = boundary;
821ca4eb3aSZbigniew Bodek 	common->lowaddr = trunc_page((vm_paddr_t)lowaddr) + (PAGE_SIZE - 1);
831ca4eb3aSZbigniew Bodek 	common->highaddr = trunc_page((vm_paddr_t)highaddr) + (PAGE_SIZE - 1);
841ca4eb3aSZbigniew Bodek 	common->maxsize = maxsize;
851ca4eb3aSZbigniew Bodek 	common->nsegments = nsegments;
861ca4eb3aSZbigniew Bodek 	common->maxsegsz = maxsegsz;
871ca4eb3aSZbigniew Bodek 	common->flags = flags;
881ca4eb3aSZbigniew Bodek 	if (lockfunc != NULL) {
891ca4eb3aSZbigniew Bodek 		common->lockfunc = lockfunc;
901ca4eb3aSZbigniew Bodek 		common->lockfuncarg = lockfuncarg;
911ca4eb3aSZbigniew Bodek 	} else {
927def1e10SJohn Baldwin 		common->lockfunc = _busdma_dflt_lock;
931ca4eb3aSZbigniew Bodek 		common->lockfuncarg = NULL;
941ca4eb3aSZbigniew Bodek 	}
951ca4eb3aSZbigniew Bodek 
961ca4eb3aSZbigniew Bodek 	/* Take into account any restrictions imposed by our parent tag */
971ca4eb3aSZbigniew Bodek 	if (parent != NULL) {
981ca4eb3aSZbigniew Bodek 		common->impl = parent->impl;
991ca4eb3aSZbigniew Bodek 		common->lowaddr = MIN(parent->lowaddr, common->lowaddr);
1001ca4eb3aSZbigniew Bodek 		common->highaddr = MAX(parent->highaddr, common->highaddr);
101ec9d0685SAndrew Turner 		common->alignment = MAX(parent->alignment, common->alignment);
1021ca4eb3aSZbigniew Bodek 		if (common->boundary == 0)
1031ca4eb3aSZbigniew Bodek 			common->boundary = parent->boundary;
1041ca4eb3aSZbigniew Bodek 		else if (parent->boundary != 0) {
1051ca4eb3aSZbigniew Bodek 			common->boundary = MIN(parent->boundary,
1061ca4eb3aSZbigniew Bodek 			    common->boundary);
1071ca4eb3aSZbigniew Bodek 		}
108900907f4SMitchell Horne 
109271e669eSAndrew Turner 		common->domain = parent->domain;
1101ca4eb3aSZbigniew Bodek 	}
111271e669eSAndrew Turner 	common->domain = vm_phys_domain_match(common->domain, 0ul,
112271e669eSAndrew Turner 	    common->lowaddr);
1131ca4eb3aSZbigniew Bodek 	*dmat = common;
1141ca4eb3aSZbigniew Bodek 	return (0);
1151ca4eb3aSZbigniew Bodek }
1161ca4eb3aSZbigniew Bodek 
1171ca4eb3aSZbigniew Bodek /*
1181ca4eb3aSZbigniew Bodek  * Allocate a device specific dma_tag.
1191ca4eb3aSZbigniew Bodek  */
1201ca4eb3aSZbigniew Bodek int
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_dma_filter_t * filter,void * filterarg,bus_size_t maxsize,int nsegments,bus_size_t maxsegsz,int flags,bus_dma_lock_t * lockfunc,void * lockfuncarg,bus_dma_tag_t * dmat)1211ca4eb3aSZbigniew Bodek bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment,
1221ca4eb3aSZbigniew Bodek     bus_addr_t boundary, bus_addr_t lowaddr, bus_addr_t highaddr,
1231ca4eb3aSZbigniew Bodek     bus_dma_filter_t *filter, void *filterarg, bus_size_t maxsize,
1241ca4eb3aSZbigniew Bodek     int nsegments, bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc,
1251ca4eb3aSZbigniew Bodek     void *lockfuncarg, bus_dma_tag_t *dmat)
1261ca4eb3aSZbigniew Bodek {
1271ca4eb3aSZbigniew Bodek 	struct bus_dma_tag_common *tc;
1281ca4eb3aSZbigniew Bodek 	int error;
1291ca4eb3aSZbigniew Bodek 
1307cb028deSMitchell Horne 	/* Filters are no longer supported. */
1317cb028deSMitchell Horne 	if (filter != NULL || filterarg != NULL)
1327cb028deSMitchell Horne 		return (EINVAL);
1337cb028deSMitchell Horne 
1341ca4eb3aSZbigniew Bodek 	if (parent == NULL) {
1351ca4eb3aSZbigniew Bodek 		error = bus_dma_bounce_impl.tag_create(parent, alignment,
136900907f4SMitchell Horne 		    boundary, lowaddr, highaddr, maxsize, nsegments, maxsegsz,
137900907f4SMitchell Horne 		    flags, lockfunc, lockfuncarg, dmat);
1381ca4eb3aSZbigniew Bodek 	} else {
1391ca4eb3aSZbigniew Bodek 		tc = (struct bus_dma_tag_common *)parent;
1401ca4eb3aSZbigniew Bodek 		error = tc->impl->tag_create(parent, alignment,
141900907f4SMitchell Horne 		    boundary, lowaddr, highaddr, maxsize, nsegments, maxsegsz,
142900907f4SMitchell Horne 		    flags, lockfunc, lockfuncarg, dmat);
1431ca4eb3aSZbigniew Bodek 	}
1441ca4eb3aSZbigniew Bodek 	return (error);
1451ca4eb3aSZbigniew Bodek }
1461ca4eb3aSZbigniew Bodek 
147757d4fbaSScott Long void
bus_dma_template_clone(bus_dma_template_t * t,bus_dma_tag_t dmat)14874c781edSScott Long bus_dma_template_clone(bus_dma_template_t *t, bus_dma_tag_t dmat)
149757d4fbaSScott Long {
150757d4fbaSScott Long 	struct bus_dma_tag_common *common;
151757d4fbaSScott Long 
152757d4fbaSScott Long 	if (t == NULL || dmat == NULL)
153757d4fbaSScott Long 		return;
154757d4fbaSScott Long 
155757d4fbaSScott Long 	common = (struct bus_dma_tag_common *)dmat;
156757d4fbaSScott Long 
157757d4fbaSScott Long 	t->alignment = common->alignment;
158757d4fbaSScott Long 	t->boundary = common->boundary;
159757d4fbaSScott Long 	t->lowaddr = common->lowaddr;
160757d4fbaSScott Long 	t->highaddr = common->highaddr;
161757d4fbaSScott Long 	t->maxsize = common->maxsize;
162757d4fbaSScott Long 	t->nsegments = common->nsegments;
163757d4fbaSScott Long 	t->maxsegsize = common->maxsegsz;
164757d4fbaSScott Long 	t->flags = common->flags;
165757d4fbaSScott Long 	t->lockfunc = common->lockfunc;
166757d4fbaSScott Long 	t->lockfuncarg = common->lockfuncarg;
167757d4fbaSScott Long }
168757d4fbaSScott Long 
1691ca4eb3aSZbigniew Bodek int
bus_dma_tag_destroy(bus_dma_tag_t dmat)1701ca4eb3aSZbigniew Bodek bus_dma_tag_destroy(bus_dma_tag_t dmat)
1711ca4eb3aSZbigniew Bodek {
1721ca4eb3aSZbigniew Bodek 	struct bus_dma_tag_common *tc;
1731ca4eb3aSZbigniew Bodek 
1741ca4eb3aSZbigniew Bodek 	tc = (struct bus_dma_tag_common *)dmat;
1751ca4eb3aSZbigniew Bodek 	return (tc->impl->tag_destroy(dmat));
1761ca4eb3aSZbigniew Bodek }
1771ca4eb3aSZbigniew Bodek 
1786f4acaf4SJeff Roberson int
bus_dma_tag_set_domain(bus_dma_tag_t dmat,int domain)1796f4acaf4SJeff Roberson bus_dma_tag_set_domain(bus_dma_tag_t dmat, int domain)
1806f4acaf4SJeff Roberson {
181271e669eSAndrew Turner 	struct bus_dma_tag_common *tc;
1826f4acaf4SJeff Roberson 
183271e669eSAndrew Turner 	tc = (struct bus_dma_tag_common *)dmat;
184271e669eSAndrew Turner 	domain = vm_phys_domain_match(domain, 0ul, tc->lowaddr);
185271e669eSAndrew Turner 	/* Only call the callback if it changes. */
186271e669eSAndrew Turner 	if (domain == tc->domain)
1876f4acaf4SJeff Roberson 		return (0);
188271e669eSAndrew Turner 	tc->domain = domain;
189271e669eSAndrew Turner 	return (tc->impl->tag_set_domain(dmat));
1906f4acaf4SJeff Roberson }
191