fwdma.c revision 1.12.32.1 1 1.12.32.1 rmind /* $NetBSD: fwdma.c,v 1.12.32.1 2010/05/30 05:17:27 rmind Exp $ */
2 1.1 kiyohara /*-
3 1.1 kiyohara * Copyright (c) 2003
4 1.1 kiyohara * Hidetoshi Shimokawa. All rights reserved.
5 1.12.32.1 rmind *
6 1.1 kiyohara * Redistribution and use in source and binary forms, with or without
7 1.1 kiyohara * modification, are permitted provided that the following conditions
8 1.1 kiyohara * are met:
9 1.1 kiyohara * 1. Redistributions of source code must retain the above copyright
10 1.1 kiyohara * notice, this list of conditions and the following disclaimer.
11 1.1 kiyohara * 2. Redistributions in binary form must reproduce the above copyright
12 1.1 kiyohara * notice, this list of conditions and the following disclaimer in the
13 1.1 kiyohara * documentation and/or other materials provided with the distribution.
14 1.1 kiyohara * 3. All advertising materials mentioning features or use of this software
15 1.1 kiyohara * must display the following acknowledgement:
16 1.1 kiyohara *
17 1.1 kiyohara * This product includes software developed by Hidetoshi Shimokawa.
18 1.1 kiyohara *
19 1.1 kiyohara * 4. Neither the name of the author nor the names of its contributors
20 1.1 kiyohara * may be used to endorse or promote products derived from this software
21 1.1 kiyohara * without specific prior written permission.
22 1.12.32.1 rmind *
23 1.1 kiyohara * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 1.1 kiyohara * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 1.1 kiyohara * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 1.1 kiyohara * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 1.1 kiyohara * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 1.1 kiyohara * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 1.1 kiyohara * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 1.1 kiyohara * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 1.1 kiyohara * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 1.1 kiyohara * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 1.1 kiyohara * SUCH DAMAGE.
34 1.12.32.1 rmind *
35 1.1 kiyohara */
36 1.1 kiyohara
37 1.1 kiyohara #include <sys/cdefs.h>
38 1.12.32.1 rmind __KERNEL_RCSID(0, "$NetBSD: fwdma.c,v 1.12.32.1 2010/05/30 05:17:27 rmind Exp $");
39 1.11 lukem #if defined(__FreeBSD__)
40 1.10 kiyohara __FBSDID("$FreeBSD: src/sys/dev/firewire/fwdma.c,v 1.9 2007/06/06 14:31:36 simokawa Exp $");
41 1.1 kiyohara #endif
42 1.1 kiyohara
43 1.1 kiyohara #include <sys/param.h>
44 1.1 kiyohara #include <sys/bus.h>
45 1.1 kiyohara #include <sys/device.h>
46 1.1 kiyohara #include <sys/systm.h>
47 1.1 kiyohara #include <sys/types.h>
48 1.1 kiyohara #include <sys/kernel.h>
49 1.1 kiyohara #include <sys/malloc.h>
50 1.12.32.1 rmind #include <sys/select.h>
51 1.1 kiyohara
52 1.12.32.1 rmind #include <machine/vmparam.h>
53 1.1 kiyohara
54 1.1 kiyohara #include <dev/ieee1394/firewire.h>
55 1.1 kiyohara #include <dev/ieee1394/firewirereg.h>
56 1.1 kiyohara #include <dev/ieee1394/fwdma.h>
57 1.1 kiyohara
58 1.12.32.1 rmind #define BUS_SPACE_MAXSIZE_32BIT 0xffffffff
59 1.1 kiyohara
60 1.1 kiyohara
61 1.1 kiyohara void *
62 1.12.32.1 rmind fwdma_malloc(device_t dev, bus_dma_tag_t dmat, bus_dmamap_t *dmamap,
63 1.12.32.1 rmind bus_size_t size, int alignment, int flags)
64 1.1 kiyohara {
65 1.12.32.1 rmind bus_dma_segment_t segs;
66 1.12.32.1 rmind int nsegs;
67 1.1 kiyohara int err;
68 1.12.32.1 rmind void *v_addr;
69 1.1 kiyohara
70 1.12.32.1 rmind err = bus_dmamem_alloc(dmat, size, alignment, 0, &segs, 1,
71 1.12.32.1 rmind &nsegs, flags);
72 1.1 kiyohara if (err) {
73 1.12.32.1 rmind aprint_error_dev(dev, "DMA memory allocation failed %d\n", err);
74 1.12.32.1 rmind return NULL;
75 1.1 kiyohara }
76 1.1 kiyohara
77 1.12.32.1 rmind err = bus_dmamem_map(dmat, &segs, nsegs, size, &v_addr, flags);
78 1.1 kiyohara if (err) {
79 1.12.32.1 rmind aprint_error_dev(dev, "DMA memory map failed %d\n", err);
80 1.12.32.1 rmind bus_dmamem_free(dmat, &segs, nsegs);
81 1.12.32.1 rmind return NULL;
82 1.12.32.1 rmind }
83 1.12.32.1 rmind
84 1.12.32.1 rmind if (*dmamap == NULL) {
85 1.12.32.1 rmind err = bus_dmamap_create(dmat, size, nsegs,
86 1.12.32.1 rmind BUS_SPACE_MAXSIZE_32BIT, 0, flags, dmamap);
87 1.12.32.1 rmind if (err) {
88 1.12.32.1 rmind aprint_error_dev(dev,
89 1.12.32.1 rmind "DMA map create failed %d\n", err);
90 1.12.32.1 rmind bus_dmamem_unmap(dmat, v_addr, size);
91 1.12.32.1 rmind bus_dmamem_free(dmat, &segs, nsegs);
92 1.12.32.1 rmind return NULL;
93 1.12.32.1 rmind }
94 1.1 kiyohara }
95 1.1 kiyohara
96 1.12.32.1 rmind err = bus_dmamap_load(dmat, *dmamap, v_addr, size, NULL, flags);
97 1.1 kiyohara if (err != 0) {
98 1.12.32.1 rmind aprint_error_dev(dev, "DMA map load failed %d\n", err);
99 1.12.32.1 rmind bus_dmamap_destroy(dmat, *dmamap);
100 1.12.32.1 rmind bus_dmamem_unmap(dmat, v_addr, size);
101 1.12.32.1 rmind bus_dmamem_free(dmat, &segs, nsegs);
102 1.12.32.1 rmind return NULL;
103 1.1 kiyohara }
104 1.1 kiyohara
105 1.12.32.1 rmind return v_addr;
106 1.1 kiyohara }
107 1.1 kiyohara
108 1.1 kiyohara void
109 1.12.32.1 rmind fwdma_free(bus_dma_tag_t dmat, bus_dmamap_t dmamap, void *vaddr)
110 1.1 kiyohara {
111 1.12.32.1 rmind
112 1.12.32.1 rmind bus_dmamap_unload(dmat, dmamap);
113 1.12.32.1 rmind bus_dmamem_unmap(dmat, vaddr, dmamap->dm_mapsize);
114 1.12.32.1 rmind bus_dmamem_free(dmat, dmamap->dm_segs, dmamap->dm_nsegs);
115 1.12.32.1 rmind bus_dmamap_destroy(dmat, dmamap);
116 1.1 kiyohara }
117 1.1 kiyohara
118 1.1 kiyohara
119 1.1 kiyohara void *
120 1.12.32.1 rmind fwdma_alloc_setup(device_t dev, bus_dma_tag_t dmat, bus_size_t size,
121 1.12.32.1 rmind struct fwdma_alloc *dma, int alignment, int flags)
122 1.1 kiyohara {
123 1.1 kiyohara
124 1.12.32.1 rmind dma->v_addr =
125 1.12.32.1 rmind fwdma_malloc(dev, dmat, &dma->dma_map, size, alignment, flags);
126 1.12.32.1 rmind if (dma->v_addr != NULL) {
127 1.12.32.1 rmind dma->dma_tag = dmat;
128 1.12.32.1 rmind dma->bus_addr = dma->dma_map->dm_segs[0].ds_addr;
129 1.1 kiyohara }
130 1.12.32.1 rmind return dma->v_addr;
131 1.1 kiyohara }
132 1.1 kiyohara
133 1.1 kiyohara /*
134 1.1 kiyohara * Allocate multisegment dma buffers
135 1.1 kiyohara * each segment size is eqaul to ssize except last segment.
136 1.1 kiyohara */
137 1.1 kiyohara struct fwdma_alloc_multi *
138 1.12.32.1 rmind fwdma_malloc_multiseg(struct firewire_comm *fc, int alignment, int esize, int n,
139 1.12.32.1 rmind int flags)
140 1.1 kiyohara {
141 1.1 kiyohara struct fwdma_alloc_multi *am;
142 1.1 kiyohara struct fwdma_seg *seg;
143 1.1 kiyohara bus_size_t ssize;
144 1.12.32.1 rmind size_t size;
145 1.12.32.1 rmind int nseg;
146 1.1 kiyohara
147 1.1 kiyohara if (esize > PAGE_SIZE) {
148 1.1 kiyohara /* round up to PAGE_SIZE */
149 1.1 kiyohara esize = ssize = roundup2(esize, PAGE_SIZE);
150 1.1 kiyohara nseg = n;
151 1.1 kiyohara } else {
152 1.1 kiyohara /* allocate PAGE_SIZE segment for small elements */
153 1.1 kiyohara ssize = rounddown(PAGE_SIZE, esize);
154 1.1 kiyohara nseg = howmany(n, ssize / esize);
155 1.1 kiyohara }
156 1.12.32.1 rmind size = sizeof(struct fwdma_alloc_multi) +
157 1.12.32.1 rmind sizeof(struct fwdma_seg) * nseg;
158 1.12.32.1 rmind am = (struct fwdma_alloc_multi *)malloc(size, M_FW, M_WAITOK | M_ZERO);
159 1.1 kiyohara if (am == NULL) {
160 1.12.32.1 rmind aprint_error_dev(fc->dev, "malloc failed\n");
161 1.12.32.1 rmind return NULL;
162 1.1 kiyohara }
163 1.1 kiyohara am->ssize = ssize;
164 1.1 kiyohara am->esize = esize;
165 1.1 kiyohara am->nseg = 0;
166 1.12.32.1 rmind am->dma_tag = fc->dmat;
167 1.1 kiyohara
168 1.12.32.1 rmind for (seg = am->seg; nseg--; seg++) {
169 1.12.32.1 rmind seg->v_addr = fwdma_malloc(fc->dev, am->dma_tag, &seg->dma_map,
170 1.12.32.1 rmind ssize, alignment, flags);
171 1.1 kiyohara if (seg->v_addr == NULL) {
172 1.12.32.1 rmind aprint_error_dev(fc->dev, "malloc_size failed %d\n",
173 1.12.32.1 rmind am->nseg);
174 1.1 kiyohara fwdma_free_multiseg(am);
175 1.12.32.1 rmind return NULL;
176 1.1 kiyohara }
177 1.12.32.1 rmind seg->bus_addr = seg->dma_map->dm_segs[0].ds_addr;
178 1.1 kiyohara am->nseg++;
179 1.1 kiyohara }
180 1.12.32.1 rmind return am;
181 1.1 kiyohara }
182 1.1 kiyohara
183 1.1 kiyohara void
184 1.1 kiyohara fwdma_free_multiseg(struct fwdma_alloc_multi *am)
185 1.1 kiyohara {
186 1.1 kiyohara struct fwdma_seg *seg;
187 1.1 kiyohara
188 1.12.32.1 rmind for (seg = am->seg; am->nseg--; seg++)
189 1.12.32.1 rmind fwdma_free(am->dma_tag, seg->dma_map, seg->v_addr);
190 1.1 kiyohara free(am, M_FW);
191 1.1 kiyohara }
192