1 /* $NetBSD: bus_dma_jazz.c,v 1.14 2006/06/15 17:06:19 tsutsui Exp $ */
4 * Copyright (c) 2003 Izumi Tsutsui. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * Copyright (C) 2000 Shuichiro URATA. All rights reserved.
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in the
37 * documentation and/or other materials provided with the distribution.
38 * 3. The name of the author may not be used to endorse or promote products
39 * derived from this software without specific prior written permission.
41 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
42 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
43 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
44 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
45 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
47 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
48 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
50 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53 #include <sys/cdefs.h>
54 __KERNEL_RCSID(0, "$NetBSD: bus_dma_jazz.c,v 1.14 2006/06/15 17:06:19 tsutsui Exp $");
56 #include <sys/param.h>
57 #include <sys/systm.h>
59 #include <sys/device.h>
61 #include <uvm/uvm_extern.h>
63 #define _ARC_BUS_DMA_PRIVATE
64 #include <machine/bus.h>
66 #include <arc/jazz/jazzdmatlbreg.h>
67 #include <arc/jazz/jazzdmatlbvar.h>
69 typedef struct jazz_tlbmap
{
70 struct jazz_dma_pte
*ptebase
;
74 static int jazz_bus_dmamap_alloc_sgmap(bus_dma_tag_t
,
75 bus_dma_segment_t
*, int, bus_size_t
, int);
76 static void jazz_bus_dmamap_free_sgmap(bus_dma_tag_t
,
77 bus_dma_segment_t
*, int);
79 int jazz_bus_dmamap_create(bus_dma_tag_t
, bus_size_t
, int,
80 bus_size_t
, bus_size_t
, int, bus_dmamap_t
*);
81 void jazz_bus_dmamap_destroy(bus_dma_tag_t
, bus_dmamap_t
);
82 int jazz_bus_dmamap_load(bus_dma_tag_t
, bus_dmamap_t
, void *,
83 bus_size_t
, struct proc
*, int);
84 int jazz_bus_dmamap_load_mbuf(bus_dma_tag_t
, bus_dmamap_t
,
86 int jazz_bus_dmamap_load_uio(bus_dma_tag_t
, bus_dmamap_t
,
88 int jazz_bus_dmamap_load_raw(bus_dma_tag_t
, bus_dmamap_t
,
89 bus_dma_segment_t
*, int, bus_size_t
, int);
90 void jazz_bus_dmamap_unload(bus_dma_tag_t
, bus_dmamap_t
);
91 void jazz_bus_dmamap_sync(bus_dma_tag_t
, bus_dmamap_t
,
92 bus_addr_t
, bus_size_t
, int);
95 jazz_bus_dma_tag_init(bus_dma_tag_t t
)
100 t
->_dmamap_create
= jazz_bus_dmamap_create
;
101 t
->_dmamap_destroy
= jazz_bus_dmamap_destroy
;
102 t
->_dmamap_load
= jazz_bus_dmamap_load
;
103 t
->_dmamap_load_mbuf
= jazz_bus_dmamap_load_mbuf
;
104 t
->_dmamap_load_uio
= jazz_bus_dmamap_load_uio
;
105 t
->_dmamap_load_raw
= jazz_bus_dmamap_load_raw
;
106 t
->_dmamap_unload
= jazz_bus_dmamap_unload
;
107 t
->_dmamap_sync
= jazz_bus_dmamap_sync
;
108 t
->_dmamem_alloc
= _bus_dmamem_alloc
;
109 t
->_dmamem_free
= _bus_dmamem_free
;
113 jazz_bus_dmamap_alloc_sgmap(bus_dma_tag_t t
, bus_dma_segment_t
*segs
,
114 int nsegs
, bus_size_t boundary
, int flags
)
116 jazz_dma_pte_t
*dmapte
;
121 for (i
= 0; i
< nsegs
; i
++) {
122 off
= jazz_dma_page_offs(segs
[i
]._ds_paddr
);
123 npte
= jazz_dma_page_round(segs
[i
].ds_len
+ off
) /
125 dmapte
= jazz_dmatlb_alloc(npte
, boundary
, flags
, &addr
);
128 segs
[i
].ds_addr
= addr
+ off
;
130 jazz_dmatlb_map_pa(segs
[i
]._ds_paddr
, segs
[i
].ds_len
, dmapte
);
136 jazz_bus_dmamap_free_sgmap(bus_dma_tag_t t
, bus_dma_segment_t
*segs
, int nsegs
)
141 for (i
= 0; i
< nsegs
; i
++) {
142 addr
= (segs
[i
].ds_addr
- t
->dma_offset
) & JAZZ_DMA_PAGE_NUM
;
143 npte
= jazz_dma_page_round(segs
[i
].ds_len
+
144 jazz_dma_page_offs(segs
[i
].ds_addr
)) / JAZZ_DMA_PAGE_SIZE
;
145 jazz_dmatlb_free(addr
, npte
);
151 * function to create a DMA map. If BUS_DMA_ALLOCNOW is specified and
152 * nsegments is 1, allocate jazzdmatlb here, too.
155 jazz_bus_dmamap_create(bus_dma_tag_t t
, bus_size_t size
, int nsegments
,
156 bus_size_t maxsegsz
, bus_size_t boundary
, int flags
, bus_dmamap_t
*dmamp
)
158 struct arc_bus_dmamap
*map
;
159 jazz_tlbmap_t tlbmap
;
164 * BUS_DMA_ALLOCNOW is allowed only with one segment for now.
165 * XXX needs re-think.
167 flags
&= ~BUS_DMA_ALLOCNOW
;
169 if ((flags
& BUS_DMA_ALLOCNOW
) == 0)
170 return _bus_dmamap_create(t
, size
, nsegments
, maxsegsz
,
171 boundary
, flags
, dmamp
);
173 tlbmap
= malloc(sizeof(struct jazz_tlbmap
), M_DMAMAP
,
174 (flags
& BUS_DMA_NOWAIT
) ? M_NOWAIT
: M_WAITOK
);
178 npte
= jazz_dma_page_round(maxsegsz
) / JAZZ_DMA_PAGE_SIZE
+ 1;
180 jazz_dmatlb_alloc(npte
, boundary
, flags
, &tlbmap
->vaddr
);
181 if (tlbmap
->ptebase
== NULL
) {
182 free(tlbmap
, M_DMAMAP
);
186 error
= _bus_dmamap_create(t
, size
, 1, maxsegsz
, boundary
,
189 jazz_dmatlb_free(tlbmap
->vaddr
, npte
);
190 free(tlbmap
, M_DMAMAP
);
194 map
->_dm_cookie
= (void *)tlbmap
;
200 * function to destroy a DMA map. If BUS_DMA_ALLOCNOW is specified,
201 * free jazzdmatlb, too.
204 jazz_bus_dmamap_destroy(bus_dma_tag_t t
, bus_dmamap_t map
)
207 if ((map
->_dm_flags
& BUS_DMA_ALLOCNOW
) != 0) {
208 jazz_tlbmap_t tlbmap
;
211 tlbmap
= (jazz_tlbmap_t
)map
->_dm_cookie
;
212 npte
= jazz_dma_page_round(map
->dm_maxsegsz
) /
213 JAZZ_DMA_PAGE_SIZE
+ 1;
214 jazz_dmatlb_free(tlbmap
->vaddr
, npte
);
215 free(tlbmap
, M_DMAMAP
);
218 _bus_dmamap_destroy(t
, map
);
222 * function for loading a direct-mapped DMA map with a linear buffer.
225 jazz_bus_dmamap_load(bus_dma_tag_t t
, bus_dmamap_t map
, void *buf
,
226 bus_size_t buflen
, struct proc
*p
, int flags
)
230 if ((map
->_dm_flags
& BUS_DMA_ALLOCNOW
) != 0) {
231 /* just use pre-allocated DMA TLB for the buffer */
232 jazz_tlbmap_t tlbmap
;
239 vm
= vmspace_kernel();
242 tlbmap
= (jazz_tlbmap_t
)map
->_dm_cookie
;
243 off
= jazz_dma_page_offs(buf
);
244 jazz_dmatlb_map_va(vm
, (vaddr_t
)buf
, buflen
, tlbmap
->ptebase
);
246 map
->dm_segs
[0].ds_addr
= tlbmap
->vaddr
+ off
;
247 map
->dm_segs
[0].ds_len
= buflen
;
248 map
->dm_segs
[0]._ds_vaddr
= (vaddr_t
)buf
;
249 map
->dm_mapsize
= buflen
;
251 map
->_dm_vmspace
= vm
;
253 if (buf
>= (void *)MIPS_KSEG1_START
&&
254 buf
< (void *)MIPS_KSEG2_START
)
255 map
->_dm_flags
|= ARC_DMAMAP_COHERENT
;
260 error
= _bus_dmamap_load(t
, map
, buf
, buflen
, p
, flags
);
262 /* allocate DMA TLB for each dmamap segment */
263 error
= jazz_bus_dmamap_alloc_sgmap(t
, map
->dm_segs
,
264 map
->dm_nsegs
, map
->_dm_boundary
, flags
);
270 * Like jazz_bus_dmamap_load(), but for mbufs.
273 jazz_bus_dmamap_load_mbuf(bus_dma_tag_t t
, bus_dmamap_t map
, struct mbuf
*m0
,
278 if ((map
->_dm_flags
& BUS_DMA_ALLOCNOW
) != 0)
279 /* BUS_DMA_ALLOCNOW is valid only for linear buffer. */
280 return ENODEV
; /* XXX which errno is better? */
282 error
= _bus_dmamap_load_mbuf(t
, map
, m0
, flags
);
284 error
= jazz_bus_dmamap_alloc_sgmap(t
, map
->dm_segs
,
285 map
->dm_nsegs
, map
->_dm_boundary
, flags
);
291 * Like jazz_bus_dmamap_load(), but for uios.
294 jazz_bus_dmamap_load_uio(bus_dma_tag_t t
, bus_dmamap_t map
, struct uio
*uio
,
299 if ((map
->_dm_flags
& BUS_DMA_ALLOCNOW
) != 0)
300 /* BUS_DMA_ALLOCNOW is valid only for linear buffer. */
301 return ENODEV
; /* XXX which errno is better? */
303 error
= jazz_bus_dmamap_load_uio(t
, map
, uio
, flags
);
305 error
= jazz_bus_dmamap_alloc_sgmap(t
, map
->dm_segs
,
306 map
->dm_nsegs
, map
->_dm_boundary
, flags
);
312 * Like _bus_dmamap_load(), but for raw memory.
315 jazz_bus_dmamap_load_raw(bus_dma_tag_t t
, bus_dmamap_t map
,
316 bus_dma_segment_t
*segs
, int nsegs
, bus_size_t size
, int flags
)
320 if ((map
->_dm_flags
& BUS_DMA_ALLOCNOW
) != 0)
321 /* BUS_DMA_ALLOCNOW is valid only for linear buffer. */
322 return ENODEV
; /* XXX which errno is better? */
324 error
= _bus_dmamap_load_raw(t
, map
, segs
, nsegs
, size
, flags
);
326 error
= jazz_bus_dmamap_alloc_sgmap(t
, map
->dm_segs
,
327 map
->dm_nsegs
, map
->_dm_boundary
, flags
);
336 jazz_bus_dmamap_unload(bus_dma_tag_t t
, bus_dmamap_t map
)
339 if ((map
->_dm_flags
& BUS_DMA_ALLOCNOW
) != 0) {
340 /* DMA TLB should be preserved */
346 jazz_bus_dmamap_free_sgmap(t
, map
->dm_segs
, map
->dm_nsegs
);
347 _bus_dmamap_unload(t
, map
);
351 * Function for MIPS3 DMA map synchronization.
354 jazz_bus_dmamap_sync(bus_dma_tag_t t
, bus_dmamap_t map
, bus_addr_t offset
,
355 bus_size_t len
, int ops
)
359 if ((ops
& (BUS_DMASYNC_PREREAD
|BUS_DMASYNC_PREWRITE
)) != 0)
362 return _bus_dmamap_sync(t
, map
, offset
, len
, ops
);