1098ca2bdSWarner Losh /*-
2*df57947fSPedro F. Giffuni * SPDX-License-Identifier: BSD-4-Clause
3*df57947fSPedro F. Giffuni *
477ee030bSHidetoshi Shimokawa * Copyright (c) 2003
577ee030bSHidetoshi Shimokawa * Hidetoshi Shimokawa. All rights reserved.
677ee030bSHidetoshi Shimokawa *
777ee030bSHidetoshi Shimokawa * Redistribution and use in source and binary forms, with or without
877ee030bSHidetoshi Shimokawa * modification, are permitted provided that the following conditions
977ee030bSHidetoshi Shimokawa * are met:
1077ee030bSHidetoshi Shimokawa * 1. Redistributions of source code must retain the above copyright
1177ee030bSHidetoshi Shimokawa * notice, this list of conditions and the following disclaimer.
1277ee030bSHidetoshi Shimokawa * 2. Redistributions in binary form must reproduce the above copyright
1377ee030bSHidetoshi Shimokawa * notice, this list of conditions and the following disclaimer in the
1477ee030bSHidetoshi Shimokawa * documentation and/or other materials provided with the distribution.
1577ee030bSHidetoshi Shimokawa * 3. All advertising materials mentioning features or use of this software
1677ee030bSHidetoshi Shimokawa * must display the following acknowledgement:
1777ee030bSHidetoshi Shimokawa *
1877ee030bSHidetoshi Shimokawa * This product includes software developed by Hidetoshi Shimokawa.
1977ee030bSHidetoshi Shimokawa *
2077ee030bSHidetoshi Shimokawa * 4. Neither the name of the author nor the names of its contributors
2177ee030bSHidetoshi Shimokawa * may be used to endorse or promote products derived from this software
2277ee030bSHidetoshi Shimokawa * without specific prior written permission.
2377ee030bSHidetoshi Shimokawa *
2477ee030bSHidetoshi Shimokawa * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2577ee030bSHidetoshi Shimokawa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2677ee030bSHidetoshi Shimokawa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2777ee030bSHidetoshi Shimokawa * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2877ee030bSHidetoshi Shimokawa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2977ee030bSHidetoshi Shimokawa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3077ee030bSHidetoshi Shimokawa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3177ee030bSHidetoshi Shimokawa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3277ee030bSHidetoshi Shimokawa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3377ee030bSHidetoshi Shimokawa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3477ee030bSHidetoshi Shimokawa * SUCH DAMAGE.
3577ee030bSHidetoshi Shimokawa *
3677ee030bSHidetoshi Shimokawa */
37aad970f1SDavid E. O'Brien
3810d3ed64SHidetoshi Shimokawa #ifdef __FreeBSD__
39aad970f1SDavid E. O'Brien #include <sys/cdefs.h>
4010d3ed64SHidetoshi Shimokawa #endif
4110d3ed64SHidetoshi Shimokawa
4277ee030bSHidetoshi Shimokawa #include <sys/param.h>
4377ee030bSHidetoshi Shimokawa #include <sys/systm.h>
4477ee030bSHidetoshi Shimokawa #include <sys/types.h>
4577ee030bSHidetoshi Shimokawa #include <sys/kernel.h>
4677ee030bSHidetoshi Shimokawa #include <sys/malloc.h>
47f6b1c44dSScott Long #include <sys/lock.h>
48f6b1c44dSScott Long #include <sys/mutex.h>
4977ee030bSHidetoshi Shimokawa
5077ee030bSHidetoshi Shimokawa #include <sys/bus.h>
5177ee030bSHidetoshi Shimokawa #include <machine/bus.h>
5277ee030bSHidetoshi Shimokawa
5377ee030bSHidetoshi Shimokawa #include <dev/firewire/firewire.h>
5477ee030bSHidetoshi Shimokawa #include <dev/firewire/firewirereg.h>
5577ee030bSHidetoshi Shimokawa #include <dev/firewire/fwdma.h>
5677ee030bSHidetoshi Shimokawa
5777ee030bSHidetoshi Shimokawa static void
fwdma_map_cb(void * arg,bus_dma_segment_t * segs,int nseg,int error)5877ee030bSHidetoshi Shimokawa fwdma_map_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
5977ee030bSHidetoshi Shimokawa {
6077ee030bSHidetoshi Shimokawa bus_addr_t *baddr;
6177ee030bSHidetoshi Shimokawa
6277ee030bSHidetoshi Shimokawa if (error)
6377ee030bSHidetoshi Shimokawa printf("fwdma_map_cb: error=%d\n", error);
6477ee030bSHidetoshi Shimokawa baddr = (bus_addr_t *)arg;
6577ee030bSHidetoshi Shimokawa *baddr = segs->ds_addr;
6677ee030bSHidetoshi Shimokawa }
6777ee030bSHidetoshi Shimokawa
6877ee030bSHidetoshi Shimokawa void *
fwdma_malloc(struct firewire_comm * fc,int alignment,bus_size_t size,struct fwdma_alloc * dma,int flag)6977ee030bSHidetoshi Shimokawa fwdma_malloc(struct firewire_comm *fc, int alignment, bus_size_t size,
7077ee030bSHidetoshi Shimokawa struct fwdma_alloc *dma, int flag)
7177ee030bSHidetoshi Shimokawa {
7277ee030bSHidetoshi Shimokawa int err;
7377ee030bSHidetoshi Shimokawa
7477ee030bSHidetoshi Shimokawa dma->v_addr = NULL;
7577ee030bSHidetoshi Shimokawa err = bus_dma_tag_create(
7677ee030bSHidetoshi Shimokawa /*parent*/ fc->dmat,
7777ee030bSHidetoshi Shimokawa /*alignment*/ alignment,
7877ee030bSHidetoshi Shimokawa /*boundary*/ 0,
7977ee030bSHidetoshi Shimokawa /*lowaddr*/ BUS_SPACE_MAXADDR_32BIT,
8077ee030bSHidetoshi Shimokawa /*highaddr*/ BUS_SPACE_MAXADDR,
8177ee030bSHidetoshi Shimokawa /*filter*/NULL, /*filterarg*/NULL,
8277ee030bSHidetoshi Shimokawa /*maxsize*/ size,
8377ee030bSHidetoshi Shimokawa /*nsegments*/ 1,
8477ee030bSHidetoshi Shimokawa /*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT,
85f6b1c44dSScott Long /*flags*/ BUS_DMA_ALLOCNOW,
864f933468SHidetoshi Shimokawa /*lockfunc*/busdma_lock_mutex,
879950b741SHidetoshi Shimokawa /*lockarg*/FW_GMTX(fc),
884f933468SHidetoshi Shimokawa &dma->dma_tag);
8977ee030bSHidetoshi Shimokawa if (err) {
9077ee030bSHidetoshi Shimokawa printf("fwdma_malloc: failed(1)\n");
9177ee030bSHidetoshi Shimokawa return (NULL);
9277ee030bSHidetoshi Shimokawa }
9377ee030bSHidetoshi Shimokawa
9477ee030bSHidetoshi Shimokawa err = bus_dmamem_alloc(dma->dma_tag, &dma->v_addr,
9577ee030bSHidetoshi Shimokawa flag, &dma->dma_map);
9677ee030bSHidetoshi Shimokawa if (err) {
9777ee030bSHidetoshi Shimokawa printf("fwdma_malloc: failed(2)\n");
986b3d6017SPawel Jakub Dawidek /* XXX destroy tag */
9977ee030bSHidetoshi Shimokawa return (NULL);
10077ee030bSHidetoshi Shimokawa }
10177ee030bSHidetoshi Shimokawa
10277ee030bSHidetoshi Shimokawa bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->v_addr,
10377ee030bSHidetoshi Shimokawa size, fwdma_map_cb, &dma->bus_addr, /*flags*/0);
10477ee030bSHidetoshi Shimokawa
10577ee030bSHidetoshi Shimokawa return (dma->v_addr);
10677ee030bSHidetoshi Shimokawa }
10777ee030bSHidetoshi Shimokawa
10877ee030bSHidetoshi Shimokawa void
fwdma_free(struct firewire_comm * fc,struct fwdma_alloc * dma)10977ee030bSHidetoshi Shimokawa fwdma_free(struct firewire_comm *fc, struct fwdma_alloc *dma)
11077ee030bSHidetoshi Shimokawa {
11177ee030bSHidetoshi Shimokawa bus_dmamap_unload(dma->dma_tag, dma->dma_map);
11277ee030bSHidetoshi Shimokawa bus_dmamem_free(dma->dma_tag, dma->v_addr, dma->dma_map);
11377ee030bSHidetoshi Shimokawa bus_dma_tag_destroy(dma->dma_tag);
11477ee030bSHidetoshi Shimokawa }
11577ee030bSHidetoshi Shimokawa
11677ee030bSHidetoshi Shimokawa
11777ee030bSHidetoshi Shimokawa void *
fwdma_malloc_size(bus_dma_tag_t dmat,bus_dmamap_t * dmamap,bus_size_t size,bus_addr_t * bus_addr,int flag)11877ee030bSHidetoshi Shimokawa fwdma_malloc_size(bus_dma_tag_t dmat, bus_dmamap_t *dmamap,
11977ee030bSHidetoshi Shimokawa bus_size_t size, bus_addr_t *bus_addr, int flag)
12077ee030bSHidetoshi Shimokawa {
12177ee030bSHidetoshi Shimokawa void *v_addr;
12277ee030bSHidetoshi Shimokawa
12377ee030bSHidetoshi Shimokawa if (bus_dmamem_alloc(dmat, &v_addr, flag, dmamap)) {
12477ee030bSHidetoshi Shimokawa printf("fwdma_malloc_size: failed(1)\n");
12577ee030bSHidetoshi Shimokawa return (NULL);
12677ee030bSHidetoshi Shimokawa }
12777ee030bSHidetoshi Shimokawa bus_dmamap_load(dmat, *dmamap, v_addr, size,
12877ee030bSHidetoshi Shimokawa fwdma_map_cb, bus_addr, /*flags*/0);
12977ee030bSHidetoshi Shimokawa return (v_addr);
13077ee030bSHidetoshi Shimokawa }
13177ee030bSHidetoshi Shimokawa
13277ee030bSHidetoshi Shimokawa void
fwdma_free_size(bus_dma_tag_t dmat,bus_dmamap_t dmamap,void * vaddr,bus_size_t size)13377ee030bSHidetoshi Shimokawa fwdma_free_size(bus_dma_tag_t dmat, bus_dmamap_t dmamap,
13477ee030bSHidetoshi Shimokawa void *vaddr, bus_size_t size)
13577ee030bSHidetoshi Shimokawa {
13677ee030bSHidetoshi Shimokawa bus_dmamap_unload(dmat, dmamap);
13777ee030bSHidetoshi Shimokawa bus_dmamem_free(dmat, vaddr, dmamap);
13877ee030bSHidetoshi Shimokawa }
13977ee030bSHidetoshi Shimokawa
14077ee030bSHidetoshi Shimokawa /*
14177ee030bSHidetoshi Shimokawa * Allocate multisegment dma buffers
14277ee030bSHidetoshi Shimokawa * each segment size is eqaul to ssize except last segment.
14377ee030bSHidetoshi Shimokawa */
14477ee030bSHidetoshi Shimokawa struct fwdma_alloc_multi *
fwdma_malloc_multiseg(struct firewire_comm * fc,int alignment,int esize,int n,int flag)14577ee030bSHidetoshi Shimokawa fwdma_malloc_multiseg(struct firewire_comm *fc, int alignment,
14677ee030bSHidetoshi Shimokawa int esize, int n, int flag)
14777ee030bSHidetoshi Shimokawa {
14877ee030bSHidetoshi Shimokawa struct fwdma_alloc_multi *am;
14977ee030bSHidetoshi Shimokawa struct fwdma_seg *seg;
15077ee030bSHidetoshi Shimokawa bus_size_t ssize;
15177ee030bSHidetoshi Shimokawa int nseg;
15277ee030bSHidetoshi Shimokawa
15377ee030bSHidetoshi Shimokawa if (esize > PAGE_SIZE) {
15477ee030bSHidetoshi Shimokawa /* round up to PAGE_SIZE */
15577ee030bSHidetoshi Shimokawa esize = ssize = roundup2(esize, PAGE_SIZE);
15677ee030bSHidetoshi Shimokawa nseg = n;
15777ee030bSHidetoshi Shimokawa } else {
15877ee030bSHidetoshi Shimokawa /* allocate PAGE_SIZE segment for small elements */
15977ee030bSHidetoshi Shimokawa ssize = rounddown(PAGE_SIZE, esize);
16077ee030bSHidetoshi Shimokawa nseg = howmany(n, ssize / esize);
16177ee030bSHidetoshi Shimokawa }
16277ee030bSHidetoshi Shimokawa am = (struct fwdma_alloc_multi *)malloc(sizeof(struct fwdma_alloc_multi)
16377ee030bSHidetoshi Shimokawa + sizeof(struct fwdma_seg)*nseg, M_FW, M_WAITOK);
16477ee030bSHidetoshi Shimokawa am->ssize = ssize;
16577ee030bSHidetoshi Shimokawa am->esize = esize;
16677ee030bSHidetoshi Shimokawa am->nseg = 0;
16777ee030bSHidetoshi Shimokawa if (bus_dma_tag_create(
16877ee030bSHidetoshi Shimokawa /*parent*/ fc->dmat,
16977ee030bSHidetoshi Shimokawa /*alignment*/ alignment,
17077ee030bSHidetoshi Shimokawa /*boundary*/ 0,
17177ee030bSHidetoshi Shimokawa /*lowaddr*/ BUS_SPACE_MAXADDR_32BIT,
17277ee030bSHidetoshi Shimokawa /*highaddr*/ BUS_SPACE_MAXADDR,
17377ee030bSHidetoshi Shimokawa /*filter*/NULL, /*filterarg*/NULL,
17477ee030bSHidetoshi Shimokawa /*maxsize*/ ssize,
17577ee030bSHidetoshi Shimokawa /*nsegments*/ 1,
17677ee030bSHidetoshi Shimokawa /*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT,
177f6b1c44dSScott Long /*flags*/ BUS_DMA_ALLOCNOW,
178f6b1c44dSScott Long /*lockfunc*/busdma_lock_mutex,
1799950b741SHidetoshi Shimokawa /*lockarg*/FW_GMTX(fc),
1804f933468SHidetoshi Shimokawa &am->dma_tag)) {
18177ee030bSHidetoshi Shimokawa printf("fwdma_malloc_multiseg: tag_create failed\n");
18277ee030bSHidetoshi Shimokawa free(am, M_FW);
18377ee030bSHidetoshi Shimokawa return (NULL);
18477ee030bSHidetoshi Shimokawa }
18577ee030bSHidetoshi Shimokawa
18677ee030bSHidetoshi Shimokawa for (seg = &am->seg[0]; nseg--; seg++) {
18777ee030bSHidetoshi Shimokawa seg->v_addr = fwdma_malloc_size(am->dma_tag, &seg->dma_map,
18877ee030bSHidetoshi Shimokawa ssize, &seg->bus_addr, flag);
18977ee030bSHidetoshi Shimokawa if (seg->v_addr == NULL) {
19077ee030bSHidetoshi Shimokawa printf("fwdma_malloc_multi: malloc_size failed %d\n",
19177ee030bSHidetoshi Shimokawa am->nseg);
19277ee030bSHidetoshi Shimokawa fwdma_free_multiseg(am);
19377ee030bSHidetoshi Shimokawa return (NULL);
19477ee030bSHidetoshi Shimokawa }
19577ee030bSHidetoshi Shimokawa am->nseg++;
19677ee030bSHidetoshi Shimokawa }
19777ee030bSHidetoshi Shimokawa return (am);
19877ee030bSHidetoshi Shimokawa }
19977ee030bSHidetoshi Shimokawa
20077ee030bSHidetoshi Shimokawa void
fwdma_free_multiseg(struct fwdma_alloc_multi * am)20177ee030bSHidetoshi Shimokawa fwdma_free_multiseg(struct fwdma_alloc_multi *am)
20277ee030bSHidetoshi Shimokawa {
20377ee030bSHidetoshi Shimokawa struct fwdma_seg *seg;
20477ee030bSHidetoshi Shimokawa
20577ee030bSHidetoshi Shimokawa for (seg = &am->seg[0]; am->nseg--; seg++) {
20677ee030bSHidetoshi Shimokawa fwdma_free_size(am->dma_tag, seg->dma_map,
20777ee030bSHidetoshi Shimokawa seg->v_addr, am->ssize);
20877ee030bSHidetoshi Shimokawa }
20977ee030bSHidetoshi Shimokawa bus_dma_tag_destroy(am->dma_tag);
21077ee030bSHidetoshi Shimokawa free(am, M_FW);
21177ee030bSHidetoshi Shimokawa }
212