fwdma.c revision 117126
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: head/sys/dev/firewire/fwdma.c 117126 2003-07-01 15:52:06Z scottl $ 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#include <sys/lock.h> 42#include <sys/mutex.h> 43 44#include <sys/bus.h> 45#include <machine/bus.h> 46 47#include <dev/firewire/firewire.h> 48#include <dev/firewire/firewirereg.h> 49#include <dev/firewire/fwdma.h> 50 51static void 52fwdma_map_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 53{ 54 bus_addr_t *baddr; 55 56 if (error) 57 printf("fwdma_map_cb: error=%d\n", error); 58 baddr = (bus_addr_t *)arg; 59 *baddr = segs->ds_addr; 60} 61 62void * 63fwdma_malloc(struct firewire_comm *fc, int alignment, bus_size_t size, 64 struct fwdma_alloc *dma, int flag) 65{ 66 int err; 67 68 dma->v_addr = NULL; 69 err = bus_dma_tag_create( 70 /*parent*/ fc->dmat, 71 /*alignment*/ alignment, 72 /*boundary*/ 0, 73 /*lowaddr*/ BUS_SPACE_MAXADDR_32BIT, 74 /*highaddr*/ BUS_SPACE_MAXADDR, 75 /*filter*/NULL, /*filterarg*/NULL, 76 /*maxsize*/ size, 77 /*nsegments*/ 1, 78 /*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT, 79 /*flags*/ BUS_DMA_ALLOCNOW, 80 /*lockfunc*/busdma_lock_mutex,/*lockarg*/&Giant, &dma->dma_tag); 81 if (err) { 82 printf("fwdma_malloc: failed(1)\n"); 83 return(NULL); 84 } 85 86 err = bus_dmamem_alloc(dma->dma_tag, &dma->v_addr, 87 flag, &dma->dma_map); 88 if (err) { 89 printf("fwdma_malloc: failed(2)\n"); 90 /* XXX destory tag */ 91 return(NULL); 92 } 93 94 bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->v_addr, 95 size, fwdma_map_cb, &dma->bus_addr, /*flags*/0); 96 97 return(dma->v_addr); 98} 99 100void 101fwdma_free(struct firewire_comm *fc, struct fwdma_alloc *dma) 102{ 103 bus_dmamap_unload(dma->dma_tag, dma->dma_map); 104 bus_dmamem_free(dma->dma_tag, dma->v_addr, dma->dma_map); 105 bus_dma_tag_destroy(dma->dma_tag); 106} 107 108 109void * 110fwdma_malloc_size(bus_dma_tag_t dmat, bus_dmamap_t *dmamap, 111 bus_size_t size, bus_addr_t *bus_addr, int flag) 112{ 113 void *v_addr; 114 115 if (bus_dmamem_alloc(dmat, &v_addr, flag, dmamap)) { 116 printf("fwdma_malloc_size: failed(1)\n"); 117 return(NULL); 118 } 119 bus_dmamap_load(dmat, *dmamap, v_addr, size, 120 fwdma_map_cb, bus_addr, /*flags*/0); 121 return(v_addr); 122} 123 124void 125fwdma_free_size(bus_dma_tag_t dmat, bus_dmamap_t dmamap, 126 void *vaddr, bus_size_t size) 127{ 128 bus_dmamap_unload(dmat, dmamap); 129 bus_dmamem_free(dmat, vaddr, dmamap); 130} 131 132/* 133 * Allocate multisegment dma buffers 134 * each segment size is eqaul to ssize except last segment. 135 */ 136struct fwdma_alloc_multi * 137fwdma_malloc_multiseg(struct firewire_comm *fc, int alignment, 138 int esize, int n, int flag) 139{ 140 struct fwdma_alloc_multi *am; 141 struct fwdma_seg *seg; 142 bus_size_t ssize; 143 int nseg; 144 145 if (esize > PAGE_SIZE) { 146 /* round up to PAGE_SIZE */ 147 esize = ssize = roundup2(esize, PAGE_SIZE); 148 nseg = n; 149 } else { 150 /* allocate PAGE_SIZE segment for small elements */ 151 ssize = rounddown(PAGE_SIZE, esize); 152 nseg = howmany(n, ssize / esize); 153 } 154 am = (struct fwdma_alloc_multi *)malloc(sizeof(struct fwdma_alloc_multi) 155 + sizeof(struct fwdma_seg)*nseg, M_FW, M_WAITOK); 156 if (am == NULL) { 157 printf("fwdma_malloc_multiseg: malloc failed\n"); 158 return(NULL); 159 } 160 am->ssize = ssize; 161 am->esize = esize; 162 am->nseg = 0; 163 if (bus_dma_tag_create( 164 /*parent*/ fc->dmat, 165 /*alignment*/ alignment, 166 /*boundary*/ 0, 167 /*lowaddr*/ BUS_SPACE_MAXADDR_32BIT, 168 /*highaddr*/ BUS_SPACE_MAXADDR, 169 /*filter*/NULL, /*filterarg*/NULL, 170 /*maxsize*/ ssize, 171 /*nsegments*/ 1, 172 /*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT, 173 /*flags*/ BUS_DMA_ALLOCNOW, 174 /*lockfunc*/busdma_lock_mutex, 175 /*lockarg*/&Giant, &am->dma_tag)) { 176 printf("fwdma_malloc_multiseg: tag_create failed\n"); 177 free(am, M_FW); 178 return(NULL); 179 } 180 181#if 0 182#if __FreeBSD_version < 500000 183 printf("malloc_multi: ssize=%d nseg=%d\n", ssize, nseg); 184#else 185 printf("malloc_multi: ssize=%td nseg=%d\n", ssize, nseg); 186#endif 187#endif 188 for (seg = &am->seg[0]; nseg --; seg ++) { 189 seg->v_addr = fwdma_malloc_size(am->dma_tag, &seg->dma_map, 190 ssize, &seg->bus_addr, flag); 191 if (seg->v_addr == NULL) { 192 printf("fwdma_malloc_multi: malloc_size failed %d\n", 193 am->nseg); 194 fwdma_free_multiseg(am); 195 return(NULL); 196 } 197 am->nseg++; 198 } 199 return(am); 200} 201 202void 203fwdma_free_multiseg(struct fwdma_alloc_multi *am) 204{ 205 struct fwdma_seg *seg; 206 207 for (seg = &am->seg[0]; am->nseg --; seg ++) { 208 fwdma_free_size(am->dma_tag, seg->dma_map, 209 seg->v_addr, am->ssize); 210 } 211 bus_dma_tag_destroy(am->dma_tag); 212 free(am, M_FW); 213} 214