static int fwdev_freebuf(struct fw_xferq *q) { if (q->flag & FWXFERQ_EXTBUF) { if (q->buf != NULL) fwdma_free_multiseg(q->buf); q->buf = NULL; free(q->bulkxfer, M_FW); q->bulkxfer = NULL; q->flag &= ~FWXFERQ_EXTBUF; q->psize = 0; q->maxq = FWMAXQUEUE; } return (0); }
/* * Allocate multisegment dma buffers * each segment size is eqaul to ssize except last segment. */ struct fwdma_alloc_multi * fwdma_malloc_multiseg(struct firewire_comm *fc, int alignment, int esize, int n, int flag) { struct fwdma_alloc_multi *am; struct fwdma_seg *seg; bus_size_t ssize; int nseg; if (esize > PAGE_SIZE) { /* round up to PAGE_SIZE */ esize = ssize = roundup2(esize, PAGE_SIZE); nseg = n; } else { /* allocate PAGE_SIZE segment for small elements */ ssize = rounddown(PAGE_SIZE, esize); nseg = howmany(n, ssize / esize); } am = (struct fwdma_alloc_multi *)malloc(sizeof(struct fwdma_alloc_multi) + sizeof(struct fwdma_seg)*nseg, M_FW, M_WAITOK); if (am == NULL) { printf("fwdma_malloc_multiseg: malloc failed\n"); return(NULL); } am->ssize = ssize; am->esize = esize; am->nseg = 0; if (bus_dma_tag_create( /*parent*/ fc->dmat, /*alignment*/ alignment, /*boundary*/ 0, /*lowaddr*/ BUS_SPACE_MAXADDR_32BIT, /*highaddr*/ BUS_SPACE_MAXADDR, /*filter*/NULL, /*filterarg*/NULL, /*maxsize*/ ssize, /*nsegments*/ 1, /*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT, /*flags*/ BUS_DMA_ALLOCNOW, #if __FreeBSD_version >= 501102 /*lockfunc*/busdma_lock_mutex, /*lockarg*/&Giant, #endif &am->dma_tag)) { printf("fwdma_malloc_multiseg: tag_create failed\n"); free(am, M_FW); return(NULL); } #if 0 #if __FreeBSD_version < 500000 printf("malloc_multi: ssize=%d nseg=%d\n", ssize, nseg); #else printf("malloc_multi: ssize=%td nseg=%d\n", ssize, nseg); #endif #endif for (seg = &am->seg[0]; nseg --; seg ++) { seg->v_addr = fwdma_malloc_size(am->dma_tag, &seg->dma_map, ssize, &seg->bus_addr, flag); if (seg->v_addr == NULL) { printf("fwdma_malloc_multi: malloc_size failed %d\n", am->nseg); fwdma_free_multiseg(am); return(NULL); } am->nseg++; } return(am); }