fwdma.c revision 117732
184053Sbrooks/* 284053Sbrooks * Copyright (c) 2003 3139823Simp * Hidetoshi Shimokawa. All rights reserved. 4139823Simp * 5139823Simp * Redistribution and use in source and binary forms, with or without 684053Sbrooks * modification, are permitted provided that the following conditions 784053Sbrooks * are met: 884053Sbrooks * 1. Redistributions of source code must retain the above copyright 984053Sbrooks * notice, this list of conditions and the following disclaimer. 1084053Sbrooks * 2. Redistributions in binary form must reproduce the above copyright 1184053Sbrooks * notice, this list of conditions and the following disclaimer in the 1284053Sbrooks * documentation and/or other materials provided with the distribution. 1384053Sbrooks * 3. All advertising materials mentioning features or use of this software 1484053Sbrooks * must display the following acknowledgement: 1584053Sbrooks * 1684053Sbrooks * This product includes software developed by Hidetoshi Shimokawa. 1784053Sbrooks * 1884053Sbrooks * 4. Neither the name of the author nor the names of its contributors 1984053Sbrooks * may be used to endorse or promote products derived from this software 2084053Sbrooks * without specific prior written permission. 2184053Sbrooks * 2284053Sbrooks * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2384053Sbrooks * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2484053Sbrooks * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2584053Sbrooks * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2684053Sbrooks * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2784053Sbrooks * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2884053Sbrooks * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2984053Sbrooks * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3084053Sbrooks * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3184053Sbrooks * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3284053Sbrooks * SUCH DAMAGE. 3384053Sbrooks * 3484053Sbrooks * $FreeBSD: head/sys/dev/firewire/fwdma.c 117732 2003-07-18 14:31:16Z simokawa $ 3584053Sbrooks */ 3684053Sbrooks#include <sys/param.h> 3784053Sbrooks#include <sys/systm.h> 3884053Sbrooks#include <sys/types.h> 3984053Sbrooks#include <sys/kernel.h> 4084053Sbrooks#include <sys/malloc.h> 4184053Sbrooks#if __FreeBSD_version >= 501102 4284053Sbrooks#include <sys/lock.h> 4384053Sbrooks#include <sys/mutex.h> 4484053Sbrooks#endif 4584053Sbrooks 4684053Sbrooks#include <sys/bus.h> 4784053Sbrooks#include <machine/bus.h> 4884053Sbrooks 4984053Sbrooks#include <dev/firewire/firewire.h> 5084053Sbrooks#include <dev/firewire/firewirereg.h> 5184053Sbrooks#include <dev/firewire/fwdma.h> 5284053Sbrooks 5384053Sbrooksstatic void 5484053Sbrooksfwdma_map_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 5584053Sbrooks{ 5684053Sbrooks bus_addr_t *baddr; 5784053Sbrooks 5884053Sbrooks if (error) 5984053Sbrooks printf("fwdma_map_cb: error=%d\n", error); 6084053Sbrooks baddr = (bus_addr_t *)arg; 6184053Sbrooks *baddr = segs->ds_addr; 6284053Sbrooks} 6384053Sbrooks 6484053Sbrooksvoid * 6584053Sbrooksfwdma_malloc(struct firewire_comm *fc, int alignment, bus_size_t size, 6684053Sbrooks struct fwdma_alloc *dma, int flag) 6784053Sbrooks{ 6884053Sbrooks int err; 6984053Sbrooks 7084053Sbrooks dma->v_addr = NULL; 7184053Sbrooks err = bus_dma_tag_create( 7284053Sbrooks /*parent*/ fc->dmat, 7384053Sbrooks /*alignment*/ alignment, 7484053Sbrooks /*boundary*/ 0, 7584053Sbrooks /*lowaddr*/ BUS_SPACE_MAXADDR_32BIT, 7684053Sbrooks /*highaddr*/ BUS_SPACE_MAXADDR, 7784053Sbrooks /*filter*/NULL, /*filterarg*/NULL, 7884053Sbrooks /*maxsize*/ size, 7984053Sbrooks /*nsegments*/ 1, 80194012Szec /*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT, 8184053Sbrooks /*flags*/ BUS_DMA_ALLOCNOW, 8284053Sbrooks#if __FreeBSD_version >= 501102 8384053Sbrooks /*lockfunc*/busdma_lock_mutex, 8484053Sbrooks /*lockarg*/&Giant, 8584053Sbrooks#endif 8684053Sbrooks &dma->dma_tag); 8784053Sbrooks if (err) { 8884053Sbrooks printf("fwdma_malloc: failed(1)\n"); 8984053Sbrooks return(NULL); 9084053Sbrooks } 9184053Sbrooks 9284053Sbrooks err = bus_dmamem_alloc(dma->dma_tag, &dma->v_addr, 9384053Sbrooks flag, &dma->dma_map); 9484053Sbrooks if (err) { 9584053Sbrooks printf("fwdma_malloc: failed(2)\n"); 9684053Sbrooks /* XXX destory tag */ 97129823Sjulian return(NULL); 98129823Sjulian } 99129823Sjulian 100129823Sjulian bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->v_addr, 101129823Sjulian size, fwdma_map_cb, &dma->bus_addr, /*flags*/0); 10284053Sbrooks 10384053Sbrooks return(dma->v_addr); 10484053Sbrooks} 10584053Sbrooks 10684053Sbrooksvoid 10784053Sbrooksfwdma_free(struct firewire_comm *fc, struct fwdma_alloc *dma) 10884053Sbrooks{ 10984053Sbrooks bus_dmamap_unload(dma->dma_tag, dma->dma_map); 11084053Sbrooks bus_dmamem_free(dma->dma_tag, dma->v_addr, dma->dma_map); 11184053Sbrooks bus_dma_tag_destroy(dma->dma_tag); 11284053Sbrooks} 11384053Sbrooks 11484053Sbrooks 11584053Sbrooksvoid * 11684053Sbrooksfwdma_malloc_size(bus_dma_tag_t dmat, bus_dmamap_t *dmamap, 11784053Sbrooks bus_size_t size, bus_addr_t *bus_addr, int flag) 11884053Sbrooks{ 11984053Sbrooks void *v_addr; 12084053Sbrooks 12184053Sbrooks if (bus_dmamem_alloc(dmat, &v_addr, flag, dmamap)) { 12284053Sbrooks printf("fwdma_malloc_size: failed(1)\n"); 12384053Sbrooks return(NULL); 124194012Szec } 125194012Szec bus_dmamap_load(dmat, *dmamap, v_addr, size, 126194012Szec fwdma_map_cb, bus_addr, /*flags*/0); 127194012Szec return(v_addr); 12884053Sbrooks} 12984053Sbrooks 13084053Sbrooksvoid 13184053Sbrooksfwdma_free_size(bus_dma_tag_t dmat, bus_dmamap_t dmamap, 13284053Sbrooks void *vaddr, bus_size_t size) 13384053Sbrooks{ 13484053Sbrooks bus_dmamap_unload(dmat, dmamap); 13584053Sbrooks bus_dmamem_free(dmat, vaddr, dmamap); 13684053Sbrooks} 13784053Sbrooks 13884053Sbrooks/* 13984053Sbrooks * Allocate multisegment dma buffers 14084053Sbrooks * each segment size is eqaul to ssize except last segment. 141 */ 142struct fwdma_alloc_multi * 143fwdma_malloc_multiseg(struct firewire_comm *fc, int alignment, 144 int esize, int n, int flag) 145{ 146 struct fwdma_alloc_multi *am; 147 struct fwdma_seg *seg; 148 bus_size_t ssize; 149 int nseg; 150 151 if (esize > PAGE_SIZE) { 152 /* round up to PAGE_SIZE */ 153 esize = ssize = roundup2(esize, PAGE_SIZE); 154 nseg = n; 155 } else { 156 /* allocate PAGE_SIZE segment for small elements */ 157 ssize = rounddown(PAGE_SIZE, esize); 158 nseg = howmany(n, ssize / esize); 159 } 160 am = (struct fwdma_alloc_multi *)malloc(sizeof(struct fwdma_alloc_multi) 161 + sizeof(struct fwdma_seg)*nseg, M_FW, M_WAITOK); 162 if (am == NULL) { 163 printf("fwdma_malloc_multiseg: malloc failed\n"); 164 return(NULL); 165 } 166 am->ssize = ssize; 167 am->esize = esize; 168 am->nseg = 0; 169 if (bus_dma_tag_create( 170 /*parent*/ fc->dmat, 171 /*alignment*/ alignment, 172 /*boundary*/ 0, 173 /*lowaddr*/ BUS_SPACE_MAXADDR_32BIT, 174 /*highaddr*/ BUS_SPACE_MAXADDR, 175 /*filter*/NULL, /*filterarg*/NULL, 176 /*maxsize*/ ssize, 177 /*nsegments*/ 1, 178 /*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT, 179 /*flags*/ BUS_DMA_ALLOCNOW, 180#if __FreeBSD_version >= 501102 181 /*lockfunc*/busdma_lock_mutex, 182 /*lockarg*/&Giant, 183#endif 184 &am->dma_tag)) { 185 printf("fwdma_malloc_multiseg: tag_create failed\n"); 186 free(am, M_FW); 187 return(NULL); 188 } 189 190#if 0 191#if __FreeBSD_version < 500000 192 printf("malloc_multi: ssize=%d nseg=%d\n", ssize, nseg); 193#else 194 printf("malloc_multi: ssize=%td nseg=%d\n", ssize, nseg); 195#endif 196#endif 197 for (seg = &am->seg[0]; nseg --; seg ++) { 198 seg->v_addr = fwdma_malloc_size(am->dma_tag, &seg->dma_map, 199 ssize, &seg->bus_addr, flag); 200 if (seg->v_addr == NULL) { 201 printf("fwdma_malloc_multi: malloc_size failed %d\n", 202 am->nseg); 203 fwdma_free_multiseg(am); 204 return(NULL); 205 } 206 am->nseg++; 207 } 208 return(am); 209} 210 211void 212fwdma_free_multiseg(struct fwdma_alloc_multi *am) 213{ 214 struct fwdma_seg *seg; 215 216 for (seg = &am->seg[0]; am->nseg --; seg ++) { 217 fwdma_free_size(am->dma_tag, seg->dma_map, 218 seg->v_addr, am->ssize); 219 } 220 bus_dma_tag_destroy(am->dma_tag); 221 free(am, M_FW); 222} 223