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