]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/alpha/alpha/sgmap.c
This commit was generated by cvs2svn to compensate for changes in r57093,
[FreeBSD/FreeBSD.git] / sys / alpha / alpha / sgmap.c
1 /*-
2  * Copyright (c) 1998 Doug Rabson
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
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>
34 #include <sys/rman.h>
35 #include <sys/lock.h>
36 #include <machine/sgmap.h>
37 #include <vm/vm.h>
38 #include <vm/pmap.h>
39 #include <vm/vm_map.h>
40
41 MALLOC_DEFINE(M_SGMAP, "sgmap", "Scatter Gather mapping");
42
43 struct sgmap {
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 */
47         bus_addr_t      sba;
48         bus_addr_t      eba;
49 };
50
51 void *overflow_page = 0;
52 vm_offset_t overflow_page_pa;
53
54 vm_offset_t
55 sgmap_overflow_page(void)
56 {
57         /*
58          * Allocate the overflow page if necessary.
59          */
60         if (!overflow_page) {
61                 overflow_page = malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT);
62                 if (!overflow_page)
63                         panic("sgmap_alloc_region: can't allocate overflow page");
64                 overflow_page_pa = pmap_kextract((vm_offset_t) overflow_page);
65         }
66
67         return overflow_page_pa;
68 }
69
70 /*
71  * Create an sgmap to manage a range of bus addresses which map
72  * physical memory using a scatter-gather map.
73  */
74 struct sgmap *
75 sgmap_map_create(bus_addr_t sba, bus_addr_t eba,
76                  sgmap_map_callback *map, void *arg)
77 {
78         struct sgmap *sgmap;
79     
80         sgmap = malloc(sizeof *sgmap, M_SGMAP, M_NOWAIT);
81         if (!sgmap)
82                 return 0;
83
84
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);
91         sgmap->map = map;
92         sgmap->arg = arg;
93         sgmap->sba = sba;
94         sgmap->eba = eba;
95
96         return sgmap;
97 }
98
99 /*
100  * Destroy an sgmap created with sgmap_map_create().
101  */
102 void
103 sgmap_map_destroy(struct sgmap *sgmap)
104 {
105         rman_fini(&sgmap->rm);
106         free(sgmap, M_SGMAP);
107 }
108
109 /*
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.
114  */
115 bus_addr_t
116 sgmap_alloc_region(struct sgmap *sgmap,
117                    bus_size_t size,
118                    bus_size_t boundary,
119                    void **mhp)
120 {
121         struct resource *res;
122         bus_addr_t ba, nba;
123
124         /*
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.
128          */
129         size = round_page(size);
130
131         /*
132          * Attempt to allocate within each boundary delimited region.
133          */
134         res = 0;
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,
139                                             RF_ACTIVE, 0);
140                 if (res)
141                         break;
142         }
143
144         if (res == 0)
145                 return 0;
146
147         *mhp = (void *) res;
148         return rman_get_start(res);
149 }
150
151 void
152 sgmap_load_region(struct sgmap *sgmap,
153                   bus_addr_t sba,
154                   vm_offset_t va,
155                   bus_size_t size)
156 {
157         bus_addr_t ba, eba;
158
159         /*
160          * Call the chipset to map each page in the mapped range to
161          * the correct physical page.
162          */
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);
167         }
168         sgmap->map(sgmap->arg, ba, overflow_page_pa);
169 }
170
171 void
172 sgmap_unload_region(struct sgmap *sgmap,
173                     bus_addr_t sba,
174                     bus_size_t size)
175 {
176         bus_addr_t ba, eba;
177
178         /*
179          * Call the chipset to unmap each page.
180          */
181         for (ba = sba, eba = sba + size; ba < eba; ba += PAGE_SIZE) {
182                 sgmap->map(sgmap->arg, ba, 0);
183         }
184         sgmap->map(sgmap->arg, ba, 0);
185 }
186
187 /*
188  * Free a region allocated using sgmap_alloc_region().
189  */
190 void
191 sgmap_free_region(struct sgmap *sgmap, void *mh)
192 {
193         struct resource *res = mh;
194         rman_release_resource(res);
195 }