rbus.c revision 1.25.20.1 1 1.25.20.1 yamt /* $NetBSD: rbus.c,v 1.25.20.1 2009/05/04 08:12:36 yamt Exp $ */
2 1.1 haya /*
3 1.7 haya * Copyright (c) 1999 and 2000
4 1.1 haya * HAYAKAWA Koichi. All rights reserved.
5 1.1 haya *
6 1.1 haya * Redistribution and use in source and binary forms, with or without
7 1.1 haya * modification, are permitted provided that the following conditions
8 1.1 haya * are met:
9 1.1 haya * 1. Redistributions of source code must retain the above copyright
10 1.1 haya * notice, this list of conditions and the following disclaimer.
11 1.1 haya * 2. Redistributions in binary form must reproduce the above copyright
12 1.1 haya * notice, this list of conditions and the following disclaimer in the
13 1.1 haya * documentation and/or other materials provided with the distribution.
14 1.1 haya * 3. All advertising materials mentioning features or use of this software
15 1.1 haya * must display the following acknowledgement:
16 1.1 haya * This product includes software developed by HAYAKAWA Koichi.
17 1.1 haya * 4. The name of the author may not be used to endorse or promote products
18 1.1 haya * derived from this software without specific prior written permission.
19 1.1 haya *
20 1.1 haya * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 1.1 haya * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 1.1 haya * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 1.1 haya * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 1.1 haya * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 1.1 haya * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 1.1 haya * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 1.1 haya * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 1.1 haya * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 1.1 haya * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 1.1 haya */
31 1.1 haya
32 1.10 lukem #include <sys/cdefs.h>
33 1.25.20.1 yamt __KERNEL_RCSID(0, "$NetBSD: rbus.c,v 1.25.20.1 2009/05/04 08:12:36 yamt Exp $");
34 1.1 haya
35 1.1 haya #include <sys/param.h>
36 1.1 haya #include <sys/systm.h>
37 1.1 haya #include <sys/device.h>
38 1.1 haya #include <sys/malloc.h>
39 1.1 haya #include <sys/extent.h>
40 1.1 haya
41 1.25 ad #include <sys/bus.h>
42 1.1 haya
43 1.1 haya #include <dev/cardbus/rbus.h>
44 1.1 haya
45 1.5 augustss /* #define RBUS_DEBUG */
46 1.1 haya
47 1.1 haya #if defined RBUS_DEBUG
48 1.1 haya #define STATIC
49 1.1 haya #define DPRINTF(a) printf a
50 1.1 haya #else
51 1.1 haya #define STATIC static
52 1.1 haya #define DPRINTF(a)
53 1.1 haya #endif
54 1.1 haya
55 1.1 haya
56 1.1 haya
57 1.21 perry static rbus_tag_t rbus_new_body(bus_space_tag_t bt, rbus_tag_t parent,
58 1.1 haya struct extent *ex, bus_addr_t start,
59 1.1 haya bus_addr_t end, bus_addr_t offset,
60 1.21 perry int flags);
61 1.1 haya
62 1.1 haya
63 1.1 haya int
64 1.25.20.1 yamt rbus_space_alloc(rbus_tag_t rbt, bus_addr_t addr, bus_size_t size, bus_addr_t mask, bus_addr_t align, int flags, bus_addr_t *addrp, bus_space_handle_t *bshp)
65 1.1 haya {
66 1.7 haya return rbus_space_alloc_subregion(rbt, rbt->rb_start, rbt->rb_end,
67 1.7 haya addr, size, mask, align, flags, addrp, bshp);
68 1.1 haya }
69 1.1 haya
70 1.1 haya
71 1.1 haya
72 1.1 haya
73 1.1 haya int
74 1.25.20.1 yamt rbus_space_alloc_subregion(rbus_tag_t rbt, bus_addr_t substart, bus_addr_t subend, bus_addr_t addr, bus_size_t size, bus_addr_t mask, bus_addr_t align, int flags, bus_addr_t *addrp, bus_space_handle_t *bshp)
75 1.1 haya {
76 1.7 haya bus_addr_t decodesize = mask + 1;
77 1.13 christos bus_addr_t boundary, search_addr;
78 1.7 haya int val;
79 1.16 nakayama u_long result;
80 1.8 haya int exflags = EX_FAST | EX_NOWAIT | EX_MALLOCOK;
81 1.7 haya
82 1.7 haya DPRINTF(("rbus_space_alloc: addr %lx, size %lx, mask %lx, align %lx\n",
83 1.17 scw (u_long)addr, (u_long)size, (u_long)mask, (u_long)align));
84 1.7 haya
85 1.7 haya addr += rbt->rb_offset;
86 1.7 haya
87 1.7 haya if (mask == 0) {
88 1.7 haya /* FULL Decode */
89 1.7 haya decodesize = 0;
90 1.7 haya }
91 1.7 haya
92 1.7 haya if (rbt->rb_flags == RBUS_SPACE_ASK_PARENT) {
93 1.7 haya return rbus_space_alloc(rbt->rb_parent, addr, size, mask,
94 1.7 haya align, flags, addrp, bshp);
95 1.7 haya } else if (rbt->rb_flags == RBUS_SPACE_SHARE ||
96 1.7 haya rbt->rb_flags == RBUS_SPACE_DEDICATE) {
97 1.7 haya /* rbt has its own sh_extent */
98 1.7 haya
99 1.7 haya /*
100 1.7 haya * sanity check: the subregion [substart, subend] should be
101 1.7 haya * smaller than the region included in sh_extent.
102 1.7 haya */
103 1.7 haya if (substart < rbt->rb_ext->ex_start
104 1.7 haya || subend > rbt->rb_ext->ex_end) {
105 1.8 haya DPRINTF(("rbus: out of range\n"));
106 1.7 haya return 1;
107 1.7 haya }
108 1.7 haya
109 1.7 haya if (decodesize == align) {
110 1.7 haya if(extent_alloc_subregion(rbt->rb_ext, substart,
111 1.16 nakayama subend, size, align, 0, exflags, &result)) {
112 1.7 haya return 1;
113 1.7 haya }
114 1.7 haya } else if (decodesize == 0) {
115 1.20 skd /* maybe, the register is overflowed. */
116 1.22 perry
117 1.7 haya if (extent_alloc_subregion(rbt->rb_ext, addr,
118 1.16 nakayama addr + size, size, 1, 0, exflags, &result)) {
119 1.7 haya return 1;
120 1.7 haya }
121 1.7 haya } else {
122 1.7 haya
123 1.7 haya boundary = decodesize > align ? decodesize : align;
124 1.7 haya
125 1.7 haya search_addr = (substart & ~(boundary - 1)) + addr;
126 1.7 haya
127 1.7 haya if (search_addr < substart) {
128 1.7 haya search_addr += boundary;
129 1.7 haya }
130 1.13 christos
131 1.7 haya val = 1;
132 1.13 christos for (; search_addr + size <= subend;
133 1.7 haya search_addr += boundary) {
134 1.7 haya val = extent_alloc_subregion(rbt->rb_ext,
135 1.7 haya search_addr, search_addr + size, size,
136 1.16 nakayama align, 0, exflags, &result);
137 1.8 haya DPRINTF(("rbus: trying [%lx:%lx] %lx\n",
138 1.17 scw (u_long)search_addr,
139 1.17 scw (u_long)search_addr + size, (u_long)align));
140 1.7 haya if (val == 0) {
141 1.7 haya break;
142 1.7 haya }
143 1.7 haya }
144 1.7 haya if (val != 0) {
145 1.7 haya /* no space found */
146 1.8 haya DPRINTF(("rbus: no space found\n"));
147 1.7 haya return 1;
148 1.7 haya }
149 1.7 haya }
150 1.7 haya
151 1.7 haya if(md_space_map(rbt->rb_bt, result, size, flags, bshp)) {
152 1.7 haya /* map failed */
153 1.7 haya extent_free(rbt->rb_ext, result, size, exflags);
154 1.7 haya return 1;
155 1.7 haya }
156 1.7 haya
157 1.7 haya if (addrp != NULL) {
158 1.7 haya *addrp = result + rbt->rb_offset;
159 1.7 haya }
160 1.7 haya return 0;
161 1.7 haya } else {
162 1.7 haya /* error!! */
163 1.8 haya DPRINTF(("rbus: no rbus type\n"));
164 1.7 haya return 1;
165 1.1 haya }
166 1.5 augustss }
167 1.5 augustss
168 1.1 haya
169 1.1 haya
170 1.1 haya
171 1.1 haya
172 1.1 haya int
173 1.25.20.1 yamt rbus_space_free(rbus_tag_t rbt, bus_space_handle_t bsh, bus_size_t size, bus_addr_t *addrp)
174 1.1 haya {
175 1.7 haya int exflags = EX_FAST | EX_NOWAIT;
176 1.7 haya bus_addr_t addr;
177 1.7 haya int status = 1;
178 1.7 haya
179 1.7 haya if (rbt->rb_flags == RBUS_SPACE_ASK_PARENT) {
180 1.7 haya status = rbus_space_free(rbt->rb_parent, bsh, size, &addr);
181 1.7 haya } else if (rbt->rb_flags == RBUS_SPACE_SHARE ||
182 1.7 haya rbt->rb_flags == RBUS_SPACE_DEDICATE) {
183 1.7 haya md_space_unmap(rbt->rb_bt, bsh, size, &addr);
184 1.7 haya
185 1.7 haya extent_free(rbt->rb_ext, addr, size, exflags);
186 1.7 haya
187 1.7 haya status = 0;
188 1.7 haya } else {
189 1.7 haya /* error. INVALID rbustag */
190 1.7 haya status = 1;
191 1.7 haya }
192 1.24 christos if (status == 0 && addrp != NULL) {
193 1.7 haya *addrp = addr;
194 1.7 haya }
195 1.7 haya return status;
196 1.1 haya }
197 1.1 haya
198 1.1 haya
199 1.1 haya
200 1.1 haya /*
201 1.1 haya * static rbus_tag_t
202 1.1 haya * rbus_new_body(bus_space_tag_t bt, rbus_tag_t parent,
203 1.1 haya * struct extent *ex, bus_addr_t start, bus_size_t end,
204 1.1 haya * bus_addr_t offset, int flags)
205 1.1 haya *
206 1.1 haya */
207 1.1 haya static rbus_tag_t
208 1.25.20.1 yamt rbus_new_body(bus_space_tag_t bt, rbus_tag_t parent, struct extent *ex, bus_addr_t start, bus_addr_t end, bus_addr_t offset, int flags)
209 1.1 haya {
210 1.7 haya rbus_tag_t rb;
211 1.7 haya
212 1.7 haya /* sanity check */
213 1.7 haya if (parent != NULL) {
214 1.7 haya if (start < parent->rb_start || end > parent->rb_end) {
215 1.7 haya /*
216 1.7 haya * out of range: [start, size] should be
217 1.19 wiz * contained in parent space
218 1.7 haya */
219 1.7 haya return 0;
220 1.7 haya /* Should I invoke panic? */
221 1.7 haya }
222 1.7 haya }
223 1.1 haya
224 1.7 haya if (NULL == (rb = (rbus_tag_t)malloc(sizeof(struct rbustag), M_DEVBUF,
225 1.7 haya M_NOWAIT))) {
226 1.7 haya panic("no memory for rbus instance");
227 1.7 haya }
228 1.7 haya
229 1.7 haya rb->rb_bt = bt;
230 1.7 haya rb->rb_parent = parent;
231 1.7 haya rb->rb_start = start;
232 1.7 haya rb->rb_end = end;
233 1.7 haya rb->rb_offset = offset;
234 1.7 haya rb->rb_flags = flags;
235 1.7 haya rb->rb_ext = ex;
236 1.7 haya
237 1.17 scw DPRINTF(("rbus_new_body: [%lx, %lx] type %s name [%s]\n",
238 1.17 scw (u_long)start, (u_long)end,
239 1.7 haya flags == RBUS_SPACE_SHARE ? "share" :
240 1.7 haya flags == RBUS_SPACE_DEDICATE ? "dedicated" :
241 1.7 haya flags == RBUS_SPACE_ASK_PARENT ? "parent" : "invalid",
242 1.7 haya ex != NULL ? ex->ex_name : "noname"));
243 1.1 haya
244 1.7 haya return rb;
245 1.1 haya }
246 1.1 haya
247 1.1 haya
248 1.1 haya
249 1.1 haya /*
250 1.1 haya * rbus_tag_t rbus_new(rbus_tag_t parent, bus_addr_t start, bus_size_t
251 1.1 haya * size, bus_addr_t offset, int flags)
252 1.1 haya *
253 1.1 haya * This function makes a new child rbus instance.
254 1.1 haya */
255 1.1 haya rbus_tag_t
256 1.25.20.1 yamt rbus_new(rbus_tag_t parent, bus_addr_t start, bus_size_t size, bus_addr_t offset, int flags)
257 1.1 haya {
258 1.7 haya rbus_tag_t rb;
259 1.7 haya struct extent *ex = NULL;
260 1.7 haya bus_addr_t end = start + size;
261 1.7 haya
262 1.7 haya if (flags == RBUS_SPACE_SHARE) {
263 1.7 haya ex = parent->rb_ext;
264 1.7 haya } else if (flags == RBUS_SPACE_DEDICATE) {
265 1.7 haya if (NULL == (ex = extent_create("rbus", start, end, M_DEVBUF,
266 1.7 haya NULL, 0, EX_NOCOALESCE|EX_NOWAIT))) {
267 1.7 haya return NULL;
268 1.7 haya }
269 1.7 haya } else if (flags == RBUS_SPACE_ASK_PARENT) {
270 1.7 haya ex = NULL;
271 1.7 haya } else {
272 1.7 haya /* Invalid flag */
273 1.7 haya return 0;
274 1.7 haya }
275 1.7 haya
276 1.7 haya rb = rbus_new_body(parent->rb_bt, parent, ex, start, start + size,
277 1.7 haya offset, flags);
278 1.7 haya
279 1.7 haya if ((rb == NULL) && (flags == RBUS_SPACE_DEDICATE)) {
280 1.7 haya extent_destroy(ex);
281 1.7 haya }
282 1.1 haya
283 1.7 haya return rb;
284 1.1 haya }
285 1.1 haya
286 1.1 haya
287 1.1 haya
288 1.1 haya
289 1.1 haya /*
290 1.1 haya * rbus_tag_t rbus_new_root_delegate(bus_space_tag, bus_addr_t,
291 1.1 haya * bus_size_t, bus_addr_t offset)
292 1.1 haya *
293 1.1 haya * This function makes a root rbus instance.
294 1.1 haya */
295 1.1 haya rbus_tag_t
296 1.25.20.1 yamt rbus_new_root_delegate(bus_space_tag_t bt, bus_addr_t start, bus_size_t size, bus_addr_t offset)
297 1.1 haya {
298 1.7 haya rbus_tag_t rb;
299 1.7 haya struct extent *ex;
300 1.1 haya
301 1.7 haya if (NULL == (ex = extent_create("rbus root", start, start + size,
302 1.7 haya M_DEVBUF, NULL, 0, EX_NOCOALESCE|EX_NOWAIT))) {
303 1.7 haya return NULL;
304 1.7 haya }
305 1.7 haya
306 1.7 haya rb = rbus_new_body(bt, NULL, ex, start, start + size, offset,
307 1.7 haya RBUS_SPACE_DEDICATE);
308 1.7 haya
309 1.7 haya if (rb == NULL) {
310 1.7 haya extent_destroy(ex);
311 1.7 haya }
312 1.5 augustss
313 1.7 haya return rb;
314 1.1 haya }
315 1.1 haya
316 1.1 haya
317 1.1 haya
318 1.1 haya /*
319 1.1 haya * rbus_tag_t rbus_new_root_share(bus_space_tag, struct extent *,
320 1.1 haya * bus_addr_t, bus_size_t, bus_addr_t offset)
321 1.1 haya *
322 1.1 haya * This function makes a root rbus instance.
323 1.1 haya */
324 1.1 haya rbus_tag_t
325 1.25.20.1 yamt rbus_new_root_share(bus_space_tag_t bt, struct extent *ex, bus_addr_t start, bus_size_t size, bus_addr_t offset)
326 1.1 haya {
327 1.7 haya /* sanity check */
328 1.7 haya if (start < ex->ex_start || start + size > ex->ex_end) {
329 1.7 haya /*
330 1.19 wiz * out of range: [start, size] should be contained in
331 1.7 haya * parent space
332 1.7 haya */
333 1.7 haya return 0;
334 1.7 haya /* Should I invoke panic? */
335 1.7 haya }
336 1.1 haya
337 1.7 haya return rbus_new_body(bt, NULL, ex, start, start + size, offset,
338 1.7 haya RBUS_SPACE_SHARE);
339 1.1 haya }
340 1.1 haya
341 1.1 haya
342 1.1 haya
343 1.1 haya
344 1.1 haya
345 1.1 haya /*
346 1.1 haya * int rbus_delete (rbus_tag_t rb)
347 1.1 haya *
348 1.1 haya * This function deletes the rbus structure pointed in the argument.
349 1.1 haya */
350 1.1 haya int
351 1.25.20.1 yamt rbus_delete(rbus_tag_t rb)
352 1.1 haya {
353 1.7 haya DPRINTF(("rbus_delete called [%s]\n",
354 1.7 haya rb->rb_ext != NULL ? rb->rb_ext->ex_name : "noname"));
355 1.7 haya if (rb->rb_flags == RBUS_SPACE_DEDICATE) {
356 1.7 haya extent_destroy(rb->rb_ext);
357 1.7 haya }
358 1.1 haya
359 1.7 haya free(rb, M_DEVBUF);
360 1.1 haya
361 1.7 haya return 0;
362 1.1 haya }
363