xref: /freebsd-src/sys/dev/firewire/fwdma.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
1098ca2bdSWarner Losh /*-
2*df57947fSPedro F. Giffuni  * SPDX-License-Identifier: BSD-4-Clause
3*df57947fSPedro F. Giffuni  *
477ee030bSHidetoshi Shimokawa  * Copyright (c) 2003
577ee030bSHidetoshi Shimokawa  * 	Hidetoshi Shimokawa. All rights reserved.
677ee030bSHidetoshi Shimokawa  *
777ee030bSHidetoshi Shimokawa  * Redistribution and use in source and binary forms, with or without
877ee030bSHidetoshi Shimokawa  * modification, are permitted provided that the following conditions
977ee030bSHidetoshi Shimokawa  * are met:
1077ee030bSHidetoshi Shimokawa  * 1. Redistributions of source code must retain the above copyright
1177ee030bSHidetoshi Shimokawa  *    notice, this list of conditions and the following disclaimer.
1277ee030bSHidetoshi Shimokawa  * 2. Redistributions in binary form must reproduce the above copyright
1377ee030bSHidetoshi Shimokawa  *    notice, this list of conditions and the following disclaimer in the
1477ee030bSHidetoshi Shimokawa  *    documentation and/or other materials provided with the distribution.
1577ee030bSHidetoshi Shimokawa  * 3. All advertising materials mentioning features or use of this software
1677ee030bSHidetoshi Shimokawa  *    must display the following acknowledgement:
1777ee030bSHidetoshi Shimokawa  *
1877ee030bSHidetoshi Shimokawa  *	This product includes software developed by Hidetoshi Shimokawa.
1977ee030bSHidetoshi Shimokawa  *
2077ee030bSHidetoshi Shimokawa  * 4. Neither the name of the author nor the names of its contributors
2177ee030bSHidetoshi Shimokawa  *    may be used to endorse or promote products derived from this software
2277ee030bSHidetoshi Shimokawa  *    without specific prior written permission.
2377ee030bSHidetoshi Shimokawa  *
2477ee030bSHidetoshi Shimokawa  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2577ee030bSHidetoshi Shimokawa  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2677ee030bSHidetoshi Shimokawa  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2777ee030bSHidetoshi Shimokawa  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2877ee030bSHidetoshi Shimokawa  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2977ee030bSHidetoshi Shimokawa  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3077ee030bSHidetoshi Shimokawa  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3177ee030bSHidetoshi Shimokawa  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3277ee030bSHidetoshi Shimokawa  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3377ee030bSHidetoshi Shimokawa  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3477ee030bSHidetoshi Shimokawa  * SUCH DAMAGE.
3577ee030bSHidetoshi Shimokawa  *
3677ee030bSHidetoshi Shimokawa  */
37aad970f1SDavid E. O'Brien 
3810d3ed64SHidetoshi Shimokawa #ifdef __FreeBSD__
39aad970f1SDavid E. O'Brien #include <sys/cdefs.h>
4010d3ed64SHidetoshi Shimokawa #endif
4110d3ed64SHidetoshi Shimokawa 
4277ee030bSHidetoshi Shimokawa #include <sys/param.h>
4377ee030bSHidetoshi Shimokawa #include <sys/systm.h>
4477ee030bSHidetoshi Shimokawa #include <sys/types.h>
4577ee030bSHidetoshi Shimokawa #include <sys/kernel.h>
4677ee030bSHidetoshi Shimokawa #include <sys/malloc.h>
47f6b1c44dSScott Long #include <sys/lock.h>
48f6b1c44dSScott Long #include <sys/mutex.h>
4977ee030bSHidetoshi Shimokawa 
5077ee030bSHidetoshi Shimokawa #include <sys/bus.h>
5177ee030bSHidetoshi Shimokawa #include <machine/bus.h>
5277ee030bSHidetoshi Shimokawa 
5377ee030bSHidetoshi Shimokawa #include <dev/firewire/firewire.h>
5477ee030bSHidetoshi Shimokawa #include <dev/firewire/firewirereg.h>
5577ee030bSHidetoshi Shimokawa #include <dev/firewire/fwdma.h>
5677ee030bSHidetoshi Shimokawa 
5777ee030bSHidetoshi Shimokawa static void
fwdma_map_cb(void * arg,bus_dma_segment_t * segs,int nseg,int error)5877ee030bSHidetoshi Shimokawa fwdma_map_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
5977ee030bSHidetoshi Shimokawa {
6077ee030bSHidetoshi Shimokawa 	bus_addr_t *baddr;
6177ee030bSHidetoshi Shimokawa 
6277ee030bSHidetoshi Shimokawa 	if (error)
6377ee030bSHidetoshi Shimokawa 		printf("fwdma_map_cb: error=%d\n", error);
6477ee030bSHidetoshi Shimokawa 	baddr = (bus_addr_t *)arg;
6577ee030bSHidetoshi Shimokawa 	*baddr = segs->ds_addr;
6677ee030bSHidetoshi Shimokawa }
6777ee030bSHidetoshi Shimokawa 
6877ee030bSHidetoshi Shimokawa void *
fwdma_malloc(struct firewire_comm * fc,int alignment,bus_size_t size,struct fwdma_alloc * dma,int flag)6977ee030bSHidetoshi Shimokawa fwdma_malloc(struct firewire_comm *fc, int alignment, bus_size_t size,
7077ee030bSHidetoshi Shimokawa 	struct fwdma_alloc *dma, int flag)
7177ee030bSHidetoshi Shimokawa {
7277ee030bSHidetoshi Shimokawa 	int err;
7377ee030bSHidetoshi Shimokawa 
7477ee030bSHidetoshi Shimokawa 	dma->v_addr = NULL;
7577ee030bSHidetoshi Shimokawa 	err = bus_dma_tag_create(
7677ee030bSHidetoshi Shimokawa 		/*parent*/ fc->dmat,
7777ee030bSHidetoshi Shimokawa 		/*alignment*/ alignment,
7877ee030bSHidetoshi Shimokawa 		/*boundary*/ 0,
7977ee030bSHidetoshi Shimokawa 		/*lowaddr*/ BUS_SPACE_MAXADDR_32BIT,
8077ee030bSHidetoshi Shimokawa 		/*highaddr*/ BUS_SPACE_MAXADDR,
8177ee030bSHidetoshi Shimokawa 		/*filter*/NULL, /*filterarg*/NULL,
8277ee030bSHidetoshi Shimokawa 		/*maxsize*/ size,
8377ee030bSHidetoshi Shimokawa 		/*nsegments*/ 1,
8477ee030bSHidetoshi Shimokawa 		/*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT,
85f6b1c44dSScott Long 		/*flags*/ BUS_DMA_ALLOCNOW,
864f933468SHidetoshi Shimokawa 		/*lockfunc*/busdma_lock_mutex,
879950b741SHidetoshi Shimokawa 		/*lockarg*/FW_GMTX(fc),
884f933468SHidetoshi Shimokawa 		&dma->dma_tag);
8977ee030bSHidetoshi Shimokawa 	if (err) {
9077ee030bSHidetoshi Shimokawa 		printf("fwdma_malloc: failed(1)\n");
9177ee030bSHidetoshi Shimokawa 		return (NULL);
9277ee030bSHidetoshi Shimokawa 	}
9377ee030bSHidetoshi Shimokawa 
9477ee030bSHidetoshi Shimokawa 	err = bus_dmamem_alloc(dma->dma_tag, &dma->v_addr,
9577ee030bSHidetoshi Shimokawa 		flag, &dma->dma_map);
9677ee030bSHidetoshi Shimokawa 	if (err) {
9777ee030bSHidetoshi Shimokawa 		printf("fwdma_malloc: failed(2)\n");
986b3d6017SPawel Jakub Dawidek 		/* XXX destroy tag */
9977ee030bSHidetoshi Shimokawa 		return (NULL);
10077ee030bSHidetoshi Shimokawa 	}
10177ee030bSHidetoshi Shimokawa 
10277ee030bSHidetoshi Shimokawa 	bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->v_addr,
10377ee030bSHidetoshi Shimokawa 		size, fwdma_map_cb, &dma->bus_addr, /*flags*/0);
10477ee030bSHidetoshi Shimokawa 
10577ee030bSHidetoshi Shimokawa 	return (dma->v_addr);
10677ee030bSHidetoshi Shimokawa }
10777ee030bSHidetoshi Shimokawa 
10877ee030bSHidetoshi Shimokawa void
fwdma_free(struct firewire_comm * fc,struct fwdma_alloc * dma)10977ee030bSHidetoshi Shimokawa fwdma_free(struct firewire_comm *fc, struct fwdma_alloc *dma)
11077ee030bSHidetoshi Shimokawa {
11177ee030bSHidetoshi Shimokawa         bus_dmamap_unload(dma->dma_tag, dma->dma_map);
11277ee030bSHidetoshi Shimokawa 	bus_dmamem_free(dma->dma_tag, dma->v_addr, dma->dma_map);
11377ee030bSHidetoshi Shimokawa 	bus_dma_tag_destroy(dma->dma_tag);
11477ee030bSHidetoshi Shimokawa }
11577ee030bSHidetoshi Shimokawa 
11677ee030bSHidetoshi Shimokawa 
11777ee030bSHidetoshi Shimokawa void *
fwdma_malloc_size(bus_dma_tag_t dmat,bus_dmamap_t * dmamap,bus_size_t size,bus_addr_t * bus_addr,int flag)11877ee030bSHidetoshi Shimokawa fwdma_malloc_size(bus_dma_tag_t dmat, bus_dmamap_t *dmamap,
11977ee030bSHidetoshi Shimokawa 	bus_size_t size, bus_addr_t *bus_addr, int flag)
12077ee030bSHidetoshi Shimokawa {
12177ee030bSHidetoshi Shimokawa 	void *v_addr;
12277ee030bSHidetoshi Shimokawa 
12377ee030bSHidetoshi Shimokawa 	if (bus_dmamem_alloc(dmat, &v_addr, flag, dmamap)) {
12477ee030bSHidetoshi Shimokawa 		printf("fwdma_malloc_size: failed(1)\n");
12577ee030bSHidetoshi Shimokawa 		return (NULL);
12677ee030bSHidetoshi Shimokawa 	}
12777ee030bSHidetoshi Shimokawa 	bus_dmamap_load(dmat, *dmamap, v_addr, size,
12877ee030bSHidetoshi Shimokawa 			fwdma_map_cb, bus_addr, /*flags*/0);
12977ee030bSHidetoshi Shimokawa 	return (v_addr);
13077ee030bSHidetoshi Shimokawa }
13177ee030bSHidetoshi Shimokawa 
13277ee030bSHidetoshi Shimokawa void
fwdma_free_size(bus_dma_tag_t dmat,bus_dmamap_t dmamap,void * vaddr,bus_size_t size)13377ee030bSHidetoshi Shimokawa fwdma_free_size(bus_dma_tag_t dmat, bus_dmamap_t dmamap,
13477ee030bSHidetoshi Shimokawa 		void *vaddr, bus_size_t size)
13577ee030bSHidetoshi Shimokawa {
13677ee030bSHidetoshi Shimokawa 	bus_dmamap_unload(dmat, dmamap);
13777ee030bSHidetoshi Shimokawa 	bus_dmamem_free(dmat, vaddr, dmamap);
13877ee030bSHidetoshi Shimokawa }
13977ee030bSHidetoshi Shimokawa 
14077ee030bSHidetoshi Shimokawa /*
14177ee030bSHidetoshi Shimokawa  * Allocate multisegment dma buffers
14277ee030bSHidetoshi Shimokawa  * each segment size is eqaul to ssize except last segment.
14377ee030bSHidetoshi Shimokawa  */
14477ee030bSHidetoshi Shimokawa struct fwdma_alloc_multi *
fwdma_malloc_multiseg(struct firewire_comm * fc,int alignment,int esize,int n,int flag)14577ee030bSHidetoshi Shimokawa fwdma_malloc_multiseg(struct firewire_comm *fc, int alignment,
14677ee030bSHidetoshi Shimokawa 		int esize, int n, int flag)
14777ee030bSHidetoshi Shimokawa {
14877ee030bSHidetoshi Shimokawa 	struct fwdma_alloc_multi *am;
14977ee030bSHidetoshi Shimokawa 	struct fwdma_seg *seg;
15077ee030bSHidetoshi Shimokawa 	bus_size_t ssize;
15177ee030bSHidetoshi Shimokawa 	int nseg;
15277ee030bSHidetoshi Shimokawa 
15377ee030bSHidetoshi Shimokawa 	if (esize > PAGE_SIZE) {
15477ee030bSHidetoshi Shimokawa 		/* round up to PAGE_SIZE */
15577ee030bSHidetoshi Shimokawa 		esize = ssize = roundup2(esize, PAGE_SIZE);
15677ee030bSHidetoshi Shimokawa 		nseg = n;
15777ee030bSHidetoshi Shimokawa 	} else {
15877ee030bSHidetoshi Shimokawa 		/* allocate PAGE_SIZE segment for small elements */
15977ee030bSHidetoshi Shimokawa 		ssize = rounddown(PAGE_SIZE, esize);
16077ee030bSHidetoshi Shimokawa 		nseg = howmany(n, ssize / esize);
16177ee030bSHidetoshi Shimokawa 	}
16277ee030bSHidetoshi Shimokawa 	am = (struct fwdma_alloc_multi *)malloc(sizeof(struct fwdma_alloc_multi)
16377ee030bSHidetoshi Shimokawa 			+ sizeof(struct fwdma_seg)*nseg, M_FW, M_WAITOK);
16477ee030bSHidetoshi Shimokawa 	am->ssize = ssize;
16577ee030bSHidetoshi Shimokawa 	am->esize = esize;
16677ee030bSHidetoshi Shimokawa 	am->nseg = 0;
16777ee030bSHidetoshi Shimokawa 	if (bus_dma_tag_create(
16877ee030bSHidetoshi Shimokawa 			/*parent*/ fc->dmat,
16977ee030bSHidetoshi Shimokawa 			/*alignment*/ alignment,
17077ee030bSHidetoshi Shimokawa 			/*boundary*/ 0,
17177ee030bSHidetoshi Shimokawa 			/*lowaddr*/ BUS_SPACE_MAXADDR_32BIT,
17277ee030bSHidetoshi Shimokawa 			/*highaddr*/ BUS_SPACE_MAXADDR,
17377ee030bSHidetoshi Shimokawa 			/*filter*/NULL, /*filterarg*/NULL,
17477ee030bSHidetoshi Shimokawa 			/*maxsize*/ ssize,
17577ee030bSHidetoshi Shimokawa 			/*nsegments*/ 1,
17677ee030bSHidetoshi Shimokawa 			/*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT,
177f6b1c44dSScott Long 			/*flags*/ BUS_DMA_ALLOCNOW,
178f6b1c44dSScott Long 			/*lockfunc*/busdma_lock_mutex,
1799950b741SHidetoshi Shimokawa 			/*lockarg*/FW_GMTX(fc),
1804f933468SHidetoshi Shimokawa 			&am->dma_tag)) {
18177ee030bSHidetoshi Shimokawa 		printf("fwdma_malloc_multiseg: tag_create failed\n");
18277ee030bSHidetoshi Shimokawa 		free(am, M_FW);
18377ee030bSHidetoshi Shimokawa 		return (NULL);
18477ee030bSHidetoshi Shimokawa 	}
18577ee030bSHidetoshi Shimokawa 
18677ee030bSHidetoshi Shimokawa 	for (seg = &am->seg[0]; nseg--; seg++) {
18777ee030bSHidetoshi Shimokawa 		seg->v_addr = fwdma_malloc_size(am->dma_tag, &seg->dma_map,
18877ee030bSHidetoshi Shimokawa 			ssize, &seg->bus_addr, flag);
18977ee030bSHidetoshi Shimokawa 		if (seg->v_addr == NULL) {
19077ee030bSHidetoshi Shimokawa 			printf("fwdma_malloc_multi: malloc_size failed %d\n",
19177ee030bSHidetoshi Shimokawa 				am->nseg);
19277ee030bSHidetoshi Shimokawa 			fwdma_free_multiseg(am);
19377ee030bSHidetoshi Shimokawa 			return (NULL);
19477ee030bSHidetoshi Shimokawa 		}
19577ee030bSHidetoshi Shimokawa 		am->nseg++;
19677ee030bSHidetoshi Shimokawa 	}
19777ee030bSHidetoshi Shimokawa 	return (am);
19877ee030bSHidetoshi Shimokawa }
19977ee030bSHidetoshi Shimokawa 
20077ee030bSHidetoshi Shimokawa void
fwdma_free_multiseg(struct fwdma_alloc_multi * am)20177ee030bSHidetoshi Shimokawa fwdma_free_multiseg(struct fwdma_alloc_multi *am)
20277ee030bSHidetoshi Shimokawa {
20377ee030bSHidetoshi Shimokawa 	struct fwdma_seg *seg;
20477ee030bSHidetoshi Shimokawa 
20577ee030bSHidetoshi Shimokawa 	for (seg = &am->seg[0]; am->nseg--; seg++) {
20677ee030bSHidetoshi Shimokawa 		fwdma_free_size(am->dma_tag, seg->dma_map,
20777ee030bSHidetoshi Shimokawa 			seg->v_addr, am->ssize);
20877ee030bSHidetoshi Shimokawa 	}
20977ee030bSHidetoshi Shimokawa 	bus_dma_tag_destroy(am->dma_tag);
21077ee030bSHidetoshi Shimokawa 	free(am, M_FW);
21177ee030bSHidetoshi Shimokawa }
212