4 * Copyright (c) 1997, 1998, 2009 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
35 __KERNEL_RCSID(0, "$NetBSD$");
37 #include <sys/param.h>
38 #include <sys/systm.h>
44 #include <common/bus_dma/bus_dmamem_common.h>
47 * _bus_dmamem_alloc_range_common --
48 * Allocate physical memory from the specified physical address range.
51 _bus_dmamem_alloc_range_common(bus_dma_tag_t t
,
55 bus_dma_segment_t
*segs
,
62 paddr_t curaddr
, lastaddr
;
67 /* Always round the size. */
68 size
= round_page(size
);
70 /* Allocate pages from the VM system. */
71 error
= uvm_pglistalloc(size
, low
, high
, alignment
, boundary
,
72 &mlist
, nsegs
, (flags
& BUS_DMA_NOWAIT
) == 0);
73 if (__predict_false(error
!= 0))
77 * Compute the location, size, and number of segments actually
78 * returned by the VM system.
80 m
= TAILQ_FIRST(&mlist
);
82 lastaddr
= segs
[curseg
].ds_addr
= VM_PAGE_TO_PHYS(m
);
83 segs
[curseg
].ds_len
= PAGE_SIZE
;
84 m
= TAILQ_NEXT(m
, pageq
.queue
);
86 for (; m
!= NULL
; m
= TAILQ_NEXT(m
, pageq
.queue
)) {
87 curaddr
= VM_PAGE_TO_PHYS(m
);
88 KASSERT(curaddr
>= low
);
89 KASSERT(curaddr
< high
);
90 if (curaddr
== (lastaddr
+ PAGE_SIZE
))
91 segs
[curseg
].ds_len
+= PAGE_SIZE
;
94 segs
[curseg
].ds_addr
= curaddr
;
95 segs
[curseg
].ds_len
= PAGE_SIZE
;
106 * _bus_dmamem_free_common --
107 * Free memory allocated with _bus_dmamem_alloc_range_common()
108 * back to the VM system.
111 _bus_dmamem_free_common(bus_dma_tag_t t
,
112 bus_dma_segment_t
*segs
,
121 for (curseg
= 0; curseg
< nsegs
; curseg
++) {
122 for (addr
= segs
[curseg
].ds_addr
;
123 addr
< (segs
[curseg
].ds_addr
+ segs
[curseg
].ds_len
);
125 m
= PHYS_TO_VM_PAGE(addr
);
126 TAILQ_INSERT_TAIL(&mlist
, m
, pageq
.queue
);
130 uvm_pglistfree(&mlist
);
134 * _bus_dmamem_map_common --
135 * Map memory allocated with _bus_dmamem_alloc_range_common() into
136 * the kernel virtual address space.
139 _bus_dmamem_map_common(bus_dma_tag_t t
,
140 bus_dma_segment_t
*segs
,
150 const uvm_flag_t kmflags
=
151 (flags
& BUS_DMA_NOWAIT
) != 0 ? UVM_KMF_NOWAIT
: 0;
153 size
= round_page(size
);
155 va
= uvm_km_alloc(kernel_map
, size
, 0, UVM_KMF_VAONLY
| kmflags
);
156 if (__predict_false(va
== 0))
161 for (curseg
= 0; curseg
< nsegs
; curseg
++) {
162 for (addr
= segs
[curseg
].ds_addr
;
163 addr
< (segs
[curseg
].ds_addr
+ segs
[curseg
].ds_len
);
164 addr
+= PAGE_SIZE
, va
+= PAGE_SIZE
, size
-= PAGE_SIZE
) {
166 /* XXX pmap_kenter_pa()? */
167 pmap_enter(pmap_kernel(), va
, addr
,
168 VM_PROT_READ
| VM_PROT_WRITE
,
169 pmapflags
| PMAP_WIRED
|
170 VM_PROT_READ
| VM_PROT_WRITE
);
173 pmap_update(pmap_kernel());
179 * _bus_dmamem_unmap_common --
180 * Remove a mapping created with _bus_dmamem_map_common().
183 _bus_dmamem_unmap_common(bus_dma_tag_t t
,
188 KASSERT(((vaddr_t
)kva
& PAGE_MASK
) == 0);
190 size
= round_page(size
);
191 /* XXX pmap_kremove()? See above... */
192 pmap_remove(pmap_kernel(), (vaddr_t
)kva
, (vaddr_t
)kva
+ size
);
193 pmap_update(pmap_kernel());
194 uvm_km_free(kernel_map
, (vaddr_t
)kva
, size
, UVM_KMF_VAONLY
);
198 * _bus_dmamem_mmap_common --
199 * Mmap support for memory allocated with _bus_dmamem_alloc_range_common().
202 _bus_dmamem_mmap_common(bus_dma_tag_t t
,
203 bus_dma_segment_t
*segs
,
211 for (i
= 0; i
< nsegs
; i
++) {
212 KASSERT((off
& PAGE_MASK
) == 0);
213 KASSERT((segs
[i
].ds_addr
& PAGE_MASK
) == 0);
214 KASSERT((segs
[i
].ds_len
& PAGE_MASK
) == 0);
215 if (off
>= segs
[i
].ds_len
) {
216 off
-= segs
[i
].ds_len
;
220 /* XXX BUS_DMA_COHERENT */
222 return (segs
[i
].ds_addr
+ off
);
225 /* Page not found. */
226 return ((bus_addr_t
)-1);