2 * Copyright (c) 1998 Doug Rabson
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <machine/bus.h>
33 #include <sys/malloc.h>
36 #include <machine/sgmap.h>
39 #include <vm/vm_map.h>
41 MALLOC_DEFINE(M_SGMAP, "sgmap", "Scatter Gather mapping");
44 struct rman rm; /* manage range of bus addresses */
45 sgmap_map_callback *map; /* map one page in the sgmap */
46 void *arg; /* argument to map function */
51 void *overflow_page = 0;
52 vm_offset_t overflow_page_pa;
55 sgmap_overflow_page(void)
58 * Allocate the overflow page if necessary.
61 overflow_page = malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT);
63 panic("sgmap_alloc_region: can't allocate overflow page");
64 overflow_page_pa = pmap_kextract((vm_offset_t) overflow_page);
67 return overflow_page_pa;
71 * Create an sgmap to manage a range of bus addresses which map
72 * physical memory using a scatter-gather map.
75 sgmap_map_create(bus_addr_t sba, bus_addr_t eba,
76 sgmap_map_callback *map, void *arg)
80 sgmap = malloc(sizeof *sgmap, M_SGMAP, M_NOWAIT);
85 sgmap->rm.rm_start = sba;
86 sgmap->rm.rm_end = eba;
87 sgmap->rm.rm_type = RMAN_ARRAY;
88 sgmap->rm.rm_descr = "Scatter Gather Bus Addresses";
89 rman_init(&sgmap->rm);
90 rman_manage_region(&sgmap->rm, sba, eba);
100 * Destroy an sgmap created with sgmap_map_create().
103 sgmap_map_destroy(struct sgmap *sgmap)
105 rman_fini(&sgmap->rm);
106 free(sgmap, M_SGMAP);
110 * Map a range of virtual addresses using the sgmap and return the bus
111 * address of the mapped region. An opaque handle for the mapped
112 * region is also returned in *mhp. This handle should be passed to
113 * sgmap_free_region() when the mapping is no longer required.
116 sgmap_alloc_region(struct sgmap *sgmap,
121 struct resource *res;
125 * This ensures allocations are on page boundaries. The extra
126 * page is used as a guard page since dma prefetching can
127 * generate accesses to addresses outside the transfer range.
129 size = round_page(size);
132 * Attempt to allocate within each boundary delimited region.
135 for (ba = sgmap->sba; ba < sgmap->eba; ba = nba) {
136 nba = (ba + boundary) & ~(boundary - 1);
137 res = rman_reserve_resource(&sgmap->rm,
138 ba, nba - 1, size + PAGE_SIZE,
148 return rman_get_start(res);
152 sgmap_load_region(struct sgmap *sgmap,
160 * Call the chipset to map each page in the mapped range to
161 * the correct physical page.
163 for (ba = sba, eba = sba + size; ba < eba;
164 ba += PAGE_SIZE, va += PAGE_SIZE) {
165 vm_offset_t pa = pmap_kextract(va);
166 sgmap->map(sgmap->arg, ba, pa);
168 sgmap->map(sgmap->arg, ba, overflow_page_pa);
172 sgmap_unload_region(struct sgmap *sgmap,
179 * Call the chipset to unmap each page.
181 for (ba = sba, eba = sba + size; ba < eba; ba += PAGE_SIZE) {
182 sgmap->map(sgmap->arg, ba, 0);
184 sgmap->map(sgmap->arg, ba, 0);
188 * Free a region allocated using sgmap_alloc_region().
191 sgmap_free_region(struct sgmap *sgmap, void *mh)
193 struct resource *res = mh;
194 rman_release_resource(res);