fwdma.c revision 1.18 1 1.18 andvar /* $NetBSD: fwdma.c,v 1.18 2021/07/24 21:31:37 andvar Exp $ */
2 1.1 kiyohara /*-
3 1.1 kiyohara * Copyright (c) 2003
4 1.1 kiyohara * Hidetoshi Shimokawa. All rights reserved.
5 1.13 kiyohara *
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.13 kiyohara *
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.13 kiyohara *
35 1.1 kiyohara */
36 1.1 kiyohara
37 1.1 kiyohara #include <sys/cdefs.h>
38 1.18 andvar __KERNEL_RCSID(0, "$NetBSD: fwdma.c,v 1.18 2021/07/24 21:31:37 andvar 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.16 christos #include <sys/malloc.h>
50 1.17 jakllsch #include <sys/kmem.h>
51 1.13 kiyohara #include <sys/select.h>
52 1.1 kiyohara
53 1.13 kiyohara #include <machine/vmparam.h>
54 1.1 kiyohara
55 1.1 kiyohara #include <dev/ieee1394/firewire.h>
56 1.1 kiyohara #include <dev/ieee1394/firewirereg.h>
57 1.1 kiyohara #include <dev/ieee1394/fwdma.h>
58 1.1 kiyohara
59 1.13 kiyohara #define BUS_SPACE_MAXSIZE_32BIT 0xffffffff
60 1.1 kiyohara
61 1.1 kiyohara
62 1.1 kiyohara void *
63 1.13 kiyohara fwdma_malloc(device_t dev, bus_dma_tag_t dmat, bus_dmamap_t *dmamap,
64 1.13 kiyohara bus_size_t size, int alignment, int flags)
65 1.1 kiyohara {
66 1.13 kiyohara bus_dma_segment_t segs;
67 1.13 kiyohara int nsegs;
68 1.1 kiyohara int err;
69 1.13 kiyohara void *v_addr;
70 1.1 kiyohara
71 1.13 kiyohara err = bus_dmamem_alloc(dmat, size, alignment, 0, &segs, 1,
72 1.13 kiyohara &nsegs, flags);
73 1.1 kiyohara if (err) {
74 1.13 kiyohara aprint_error_dev(dev, "DMA memory allocation failed %d\n", err);
75 1.13 kiyohara return NULL;
76 1.1 kiyohara }
77 1.1 kiyohara
78 1.13 kiyohara err = bus_dmamem_map(dmat, &segs, nsegs, size, &v_addr, flags);
79 1.1 kiyohara if (err) {
80 1.13 kiyohara aprint_error_dev(dev, "DMA memory map failed %d\n", err);
81 1.13 kiyohara bus_dmamem_free(dmat, &segs, nsegs);
82 1.13 kiyohara return NULL;
83 1.13 kiyohara }
84 1.13 kiyohara
85 1.13 kiyohara if (*dmamap == NULL) {
86 1.13 kiyohara err = bus_dmamap_create(dmat, size, nsegs,
87 1.13 kiyohara BUS_SPACE_MAXSIZE_32BIT, 0, flags, dmamap);
88 1.13 kiyohara if (err) {
89 1.13 kiyohara aprint_error_dev(dev,
90 1.13 kiyohara "DMA map create failed %d\n", err);
91 1.13 kiyohara bus_dmamem_unmap(dmat, v_addr, size);
92 1.13 kiyohara bus_dmamem_free(dmat, &segs, nsegs);
93 1.13 kiyohara return NULL;
94 1.13 kiyohara }
95 1.1 kiyohara }
96 1.1 kiyohara
97 1.13 kiyohara err = bus_dmamap_load(dmat, *dmamap, v_addr, size, NULL, flags);
98 1.1 kiyohara if (err != 0) {
99 1.13 kiyohara aprint_error_dev(dev, "DMA map load failed %d\n", err);
100 1.13 kiyohara bus_dmamap_destroy(dmat, *dmamap);
101 1.13 kiyohara bus_dmamem_unmap(dmat, v_addr, size);
102 1.13 kiyohara bus_dmamem_free(dmat, &segs, nsegs);
103 1.13 kiyohara return NULL;
104 1.1 kiyohara }
105 1.1 kiyohara
106 1.13 kiyohara return v_addr;
107 1.1 kiyohara }
108 1.1 kiyohara
109 1.1 kiyohara void
110 1.13 kiyohara fwdma_free(bus_dma_tag_t dmat, bus_dmamap_t dmamap, void *vaddr)
111 1.1 kiyohara {
112 1.17 jakllsch bus_dma_segment_t *segs;
113 1.13 kiyohara
114 1.17 jakllsch /* XXX we shouldn't pass around the segs in the dmamap */
115 1.17 jakllsch const bus_size_t mapsize = dmamap->dm_mapsize;
116 1.17 jakllsch const int nsegs = dmamap->dm_nsegs;
117 1.17 jakllsch const size_t segssz = sizeof(bus_dma_segment_t) * nsegs;
118 1.17 jakllsch segs = kmem_alloc(segssz, KM_SLEEP);
119 1.17 jakllsch memcpy(segs, dmamap->dm_segs, segssz);
120 1.17 jakllsch
121 1.13 kiyohara bus_dmamap_unload(dmat, dmamap);
122 1.17 jakllsch bus_dmamem_unmap(dmat, vaddr, mapsize);
123 1.17 jakllsch bus_dmamem_free(dmat, segs, nsegs);
124 1.13 kiyohara bus_dmamap_destroy(dmat, dmamap);
125 1.17 jakllsch
126 1.17 jakllsch kmem_free(segs, segssz);
127 1.1 kiyohara }
128 1.1 kiyohara
129 1.1 kiyohara
130 1.1 kiyohara void *
131 1.13 kiyohara fwdma_alloc_setup(device_t dev, bus_dma_tag_t dmat, bus_size_t size,
132 1.13 kiyohara struct fwdma_alloc *dma, int alignment, int flags)
133 1.1 kiyohara {
134 1.1 kiyohara
135 1.13 kiyohara dma->v_addr =
136 1.13 kiyohara fwdma_malloc(dev, dmat, &dma->dma_map, size, alignment, flags);
137 1.13 kiyohara if (dma->v_addr != NULL) {
138 1.13 kiyohara dma->dma_tag = dmat;
139 1.13 kiyohara dma->bus_addr = dma->dma_map->dm_segs[0].ds_addr;
140 1.1 kiyohara }
141 1.13 kiyohara return dma->v_addr;
142 1.1 kiyohara }
143 1.1 kiyohara
144 1.1 kiyohara /*
145 1.1 kiyohara * Allocate multisegment dma buffers
146 1.18 andvar * each segment size is equal to ssize except last segment.
147 1.1 kiyohara */
148 1.1 kiyohara struct fwdma_alloc_multi *
149 1.13 kiyohara fwdma_malloc_multiseg(struct firewire_comm *fc, int alignment, int esize, int n,
150 1.13 kiyohara int flags)
151 1.1 kiyohara {
152 1.1 kiyohara struct fwdma_alloc_multi *am;
153 1.1 kiyohara struct fwdma_seg *seg;
154 1.1 kiyohara bus_size_t ssize;
155 1.14 kiyohara size_t size;
156 1.14 kiyohara int nseg;
157 1.1 kiyohara
158 1.1 kiyohara if (esize > PAGE_SIZE) {
159 1.1 kiyohara /* round up to PAGE_SIZE */
160 1.1 kiyohara esize = ssize = roundup2(esize, PAGE_SIZE);
161 1.1 kiyohara nseg = n;
162 1.1 kiyohara } else {
163 1.1 kiyohara /* allocate PAGE_SIZE segment for small elements */
164 1.1 kiyohara ssize = rounddown(PAGE_SIZE, esize);
165 1.1 kiyohara nseg = howmany(n, ssize / esize);
166 1.1 kiyohara }
167 1.13 kiyohara size = sizeof(struct fwdma_alloc_multi) +
168 1.13 kiyohara sizeof(struct fwdma_seg) * nseg;
169 1.16 christos am = (struct fwdma_alloc_multi *)malloc(size, M_FW, M_WAITOK | M_ZERO);
170 1.1 kiyohara if (am == NULL) {
171 1.16 christos aprint_error_dev(fc->dev, "malloc failed\n");
172 1.13 kiyohara return NULL;
173 1.1 kiyohara }
174 1.1 kiyohara am->ssize = ssize;
175 1.1 kiyohara am->esize = esize;
176 1.1 kiyohara am->nseg = 0;
177 1.13 kiyohara am->dma_tag = fc->dmat;
178 1.1 kiyohara
179 1.13 kiyohara for (seg = am->seg; nseg--; seg++) {
180 1.13 kiyohara seg->v_addr = fwdma_malloc(fc->dev, am->dma_tag, &seg->dma_map,
181 1.13 kiyohara ssize, alignment, flags);
182 1.1 kiyohara if (seg->v_addr == NULL) {
183 1.13 kiyohara aprint_error_dev(fc->dev, "malloc_size failed %d\n",
184 1.13 kiyohara am->nseg);
185 1.1 kiyohara fwdma_free_multiseg(am);
186 1.13 kiyohara return NULL;
187 1.1 kiyohara }
188 1.13 kiyohara seg->bus_addr = seg->dma_map->dm_segs[0].ds_addr;
189 1.1 kiyohara am->nseg++;
190 1.1 kiyohara }
191 1.13 kiyohara return am;
192 1.1 kiyohara }
193 1.1 kiyohara
194 1.1 kiyohara void
195 1.1 kiyohara fwdma_free_multiseg(struct fwdma_alloc_multi *am)
196 1.1 kiyohara {
197 1.1 kiyohara struct fwdma_seg *seg;
198 1.1 kiyohara
199 1.13 kiyohara for (seg = am->seg; am->nseg--; seg++)
200 1.13 kiyohara fwdma_free(am->dma_tag, seg->dma_map, seg->v_addr);
201 1.16 christos free(am, M_FW);
202 1.1 kiyohara }
203