1139749Simp/*-
2113584Ssimokawa * Copyright (c) 2003
3113584Ssimokawa * 	Hidetoshi Shimokawa. All rights reserved.
4272214Skan *
5113584Ssimokawa * Redistribution and use in source and binary forms, with or without
6113584Ssimokawa * modification, are permitted provided that the following conditions
7113584Ssimokawa * are met:
8113584Ssimokawa * 1. Redistributions of source code must retain the above copyright
9113584Ssimokawa *    notice, this list of conditions and the following disclaimer.
10113584Ssimokawa * 2. Redistributions in binary form must reproduce the above copyright
11113584Ssimokawa *    notice, this list of conditions and the following disclaimer in the
12113584Ssimokawa *    documentation and/or other materials provided with the distribution.
13113584Ssimokawa * 3. All advertising materials mentioning features or use of this software
14113584Ssimokawa *    must display the following acknowledgement:
15113584Ssimokawa *
16113584Ssimokawa *	This product includes software developed by Hidetoshi Shimokawa.
17113584Ssimokawa *
18113584Ssimokawa * 4. Neither the name of the author nor the names of its contributors
19113584Ssimokawa *    may be used to endorse or promote products derived from this software
20113584Ssimokawa *    without specific prior written permission.
21272214Skan *
22113584Ssimokawa * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23113584Ssimokawa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24113584Ssimokawa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25113584Ssimokawa * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26113584Ssimokawa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27113584Ssimokawa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28113584Ssimokawa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29113584Ssimokawa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30113584Ssimokawa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31113584Ssimokawa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32113584Ssimokawa * SUCH DAMAGE.
33272214Skan *
34113584Ssimokawa */
35119418Sobrien
36127468Ssimokawa#ifdef __FreeBSD__
37119418Sobrien#include <sys/cdefs.h>
38119418Sobrien__FBSDID("$FreeBSD$");
39127468Ssimokawa#endif
40127468Ssimokawa
41113584Ssimokawa#include <sys/param.h>
42113584Ssimokawa#include <sys/systm.h>
43113584Ssimokawa#include <sys/types.h>
44113584Ssimokawa#include <sys/kernel.h>
45113584Ssimokawa#include <sys/malloc.h>
46117126Sscottl#include <sys/lock.h>
47117126Sscottl#include <sys/mutex.h>
48113584Ssimokawa
49113584Ssimokawa#include <sys/bus.h>
50113584Ssimokawa#include <machine/bus.h>
51113584Ssimokawa
52113584Ssimokawa#include <dev/firewire/firewire.h>
53113584Ssimokawa#include <dev/firewire/firewirereg.h>
54113584Ssimokawa#include <dev/firewire/fwdma.h>
55113584Ssimokawa
56113584Ssimokawastatic void
57113584Ssimokawafwdma_map_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
58113584Ssimokawa{
59113584Ssimokawa	bus_addr_t *baddr;
60113584Ssimokawa
61113584Ssimokawa	if (error)
62113584Ssimokawa		printf("fwdma_map_cb: error=%d\n", error);
63113584Ssimokawa	baddr = (bus_addr_t *)arg;
64113584Ssimokawa	*baddr = segs->ds_addr;
65113584Ssimokawa}
66113584Ssimokawa
67113584Ssimokawavoid *
68113584Ssimokawafwdma_malloc(struct firewire_comm *fc, int alignment, bus_size_t size,
69113584Ssimokawa	struct fwdma_alloc *dma, int flag)
70113584Ssimokawa{
71113584Ssimokawa	int err;
72113584Ssimokawa
73113584Ssimokawa	dma->v_addr = NULL;
74113584Ssimokawa	err = bus_dma_tag_create(
75113584Ssimokawa		/*parent*/ fc->dmat,
76113584Ssimokawa		/*alignment*/ alignment,
77113584Ssimokawa		/*boundary*/ 0,
78113584Ssimokawa		/*lowaddr*/ BUS_SPACE_MAXADDR_32BIT,
79113584Ssimokawa		/*highaddr*/ BUS_SPACE_MAXADDR,
80113584Ssimokawa		/*filter*/NULL, /*filterarg*/NULL,
81113584Ssimokawa		/*maxsize*/ size,
82113584Ssimokawa		/*nsegments*/ 1,
83113584Ssimokawa		/*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT,
84117126Sscottl		/*flags*/ BUS_DMA_ALLOCNOW,
85117228Ssimokawa		/*lockfunc*/busdma_lock_mutex,
86170374Ssimokawa		/*lockarg*/FW_GMTX(fc),
87117228Ssimokawa		&dma->dma_tag);
88113584Ssimokawa	if (err) {
89113584Ssimokawa		printf("fwdma_malloc: failed(1)\n");
90272214Skan		return (NULL);
91113584Ssimokawa	}
92113584Ssimokawa
93113584Ssimokawa	err = bus_dmamem_alloc(dma->dma_tag, &dma->v_addr,
94113584Ssimokawa		flag, &dma->dma_map);
95113584Ssimokawa	if (err) {
96113584Ssimokawa		printf("fwdma_malloc: failed(2)\n");
97168776Spjd		/* XXX destroy tag */
98272214Skan		return (NULL);
99113584Ssimokawa	}
100113584Ssimokawa
101113584Ssimokawa	bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->v_addr,
102113584Ssimokawa		size, fwdma_map_cb, &dma->bus_addr, /*flags*/0);
103113584Ssimokawa
104272214Skan	return (dma->v_addr);
105113584Ssimokawa}
106113584Ssimokawa
107113584Ssimokawavoid
108113584Ssimokawafwdma_free(struct firewire_comm *fc, struct fwdma_alloc *dma)
109113584Ssimokawa{
110113584Ssimokawa        bus_dmamap_unload(dma->dma_tag, dma->dma_map);
111113584Ssimokawa	bus_dmamem_free(dma->dma_tag, dma->v_addr, dma->dma_map);
112113584Ssimokawa	bus_dma_tag_destroy(dma->dma_tag);
113113584Ssimokawa}
114113584Ssimokawa
115113584Ssimokawa
116113584Ssimokawavoid *
117113584Ssimokawafwdma_malloc_size(bus_dma_tag_t dmat, bus_dmamap_t *dmamap,
118113584Ssimokawa	bus_size_t size, bus_addr_t *bus_addr, int flag)
119113584Ssimokawa{
120113584Ssimokawa	void *v_addr;
121113584Ssimokawa
122113584Ssimokawa	if (bus_dmamem_alloc(dmat, &v_addr, flag, dmamap)) {
123113584Ssimokawa		printf("fwdma_malloc_size: failed(1)\n");
124272214Skan		return (NULL);
125113584Ssimokawa	}
126113584Ssimokawa	bus_dmamap_load(dmat, *dmamap, v_addr, size,
127113584Ssimokawa			fwdma_map_cb, bus_addr, /*flags*/0);
128272214Skan	return (v_addr);
129113584Ssimokawa}
130113584Ssimokawa
131113584Ssimokawavoid
132113584Ssimokawafwdma_free_size(bus_dma_tag_t dmat, bus_dmamap_t dmamap,
133113584Ssimokawa		void *vaddr, bus_size_t size)
134113584Ssimokawa{
135113584Ssimokawa	bus_dmamap_unload(dmat, dmamap);
136113584Ssimokawa	bus_dmamem_free(dmat, vaddr, dmamap);
137272214Skan}
138113584Ssimokawa
139113584Ssimokawa/*
140113584Ssimokawa * Allocate multisegment dma buffers
141113584Ssimokawa * each segment size is eqaul to ssize except last segment.
142113584Ssimokawa */
143113584Ssimokawastruct fwdma_alloc_multi *
144113584Ssimokawafwdma_malloc_multiseg(struct firewire_comm *fc, int alignment,
145113584Ssimokawa		int esize, int n, int flag)
146113584Ssimokawa{
147113584Ssimokawa	struct fwdma_alloc_multi *am;
148113584Ssimokawa	struct fwdma_seg *seg;
149113584Ssimokawa	bus_size_t ssize;
150113584Ssimokawa	int nseg;
151113584Ssimokawa
152113584Ssimokawa	if (esize > PAGE_SIZE) {
153113584Ssimokawa		/* round up to PAGE_SIZE */
154113584Ssimokawa		esize = ssize = roundup2(esize, PAGE_SIZE);
155113584Ssimokawa		nseg = n;
156113584Ssimokawa	} else {
157113584Ssimokawa		/* allocate PAGE_SIZE segment for small elements */
158113584Ssimokawa		ssize = rounddown(PAGE_SIZE, esize);
159113584Ssimokawa		nseg = howmany(n, ssize / esize);
160113584Ssimokawa	}
161113584Ssimokawa	am = (struct fwdma_alloc_multi *)malloc(sizeof(struct fwdma_alloc_multi)
162113584Ssimokawa			+ sizeof(struct fwdma_seg)*nseg, M_FW, M_WAITOK);
163113584Ssimokawa	am->ssize = ssize;
164113584Ssimokawa	am->esize = esize;
165113584Ssimokawa	am->nseg = 0;
166113584Ssimokawa	if (bus_dma_tag_create(
167113584Ssimokawa			/*parent*/ fc->dmat,
168113584Ssimokawa			/*alignment*/ alignment,
169113584Ssimokawa			/*boundary*/ 0,
170113584Ssimokawa			/*lowaddr*/ BUS_SPACE_MAXADDR_32BIT,
171113584Ssimokawa			/*highaddr*/ BUS_SPACE_MAXADDR,
172113584Ssimokawa			/*filter*/NULL, /*filterarg*/NULL,
173113584Ssimokawa			/*maxsize*/ ssize,
174113584Ssimokawa			/*nsegments*/ 1,
175113584Ssimokawa			/*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT,
176117126Sscottl			/*flags*/ BUS_DMA_ALLOCNOW,
177117126Sscottl			/*lockfunc*/busdma_lock_mutex,
178170374Ssimokawa			/*lockarg*/FW_GMTX(fc),
179117228Ssimokawa			&am->dma_tag)) {
180113584Ssimokawa		printf("fwdma_malloc_multiseg: tag_create failed\n");
181113584Ssimokawa		free(am, M_FW);
182272214Skan		return (NULL);
183113584Ssimokawa	}
184113584Ssimokawa
185272214Skan	for (seg = &am->seg[0]; nseg--; seg++) {
186113584Ssimokawa		seg->v_addr = fwdma_malloc_size(am->dma_tag, &seg->dma_map,
187113584Ssimokawa			ssize, &seg->bus_addr, flag);
188113584Ssimokawa		if (seg->v_addr == NULL) {
189113584Ssimokawa			printf("fwdma_malloc_multi: malloc_size failed %d\n",
190113584Ssimokawa				am->nseg);
191113584Ssimokawa			fwdma_free_multiseg(am);
192272214Skan			return (NULL);
193113584Ssimokawa		}
194113584Ssimokawa		am->nseg++;
195113584Ssimokawa	}
196272214Skan	return (am);
197113584Ssimokawa}
198113584Ssimokawa
199113584Ssimokawavoid
200113584Ssimokawafwdma_free_multiseg(struct fwdma_alloc_multi *am)
201113584Ssimokawa{
202113584Ssimokawa	struct fwdma_seg *seg;
203113584Ssimokawa
204272214Skan	for (seg = &am->seg[0]; am->nseg--; seg++) {
205113584Ssimokawa		fwdma_free_size(am->dma_tag, seg->dma_map,
206113584Ssimokawa			seg->v_addr, am->ssize);
207113584Ssimokawa	}
208113584Ssimokawa	bus_dma_tag_destroy(am->dma_tag);
209113584Ssimokawa	free(am, M_FW);
210113584Ssimokawa}
211