rbus.c revision 1.8.6.1 1 1.8.6.1 lukem /* $NetBSD: rbus.c,v 1.8.6.1 2001/08/03 04:12:52 lukem 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.1 haya
33 1.1 haya
34 1.1 haya #include <sys/types.h>
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.1 haya #include <machine/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.1 haya static rbus_tag_t rbus_new_body __P((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.1 haya int flags));
61 1.1 haya
62 1.1 haya
63 1.1 haya int
64 1.1 haya rbus_space_alloc(rbt, addr, size, mask, align, flags, addrp, bshp)
65 1.7 haya rbus_tag_t rbt;
66 1.7 haya bus_addr_t addr;
67 1.7 haya bus_size_t size;
68 1.7 haya bus_addr_t mask, align;
69 1.7 haya int flags;
70 1.7 haya bus_addr_t *addrp;
71 1.7 haya bus_space_handle_t *bshp;
72 1.1 haya {
73 1.7 haya return rbus_space_alloc_subregion(rbt, rbt->rb_start, rbt->rb_end,
74 1.7 haya addr, size, mask, align, flags, addrp, bshp);
75 1.1 haya }
76 1.1 haya
77 1.1 haya
78 1.1 haya
79 1.1 haya
80 1.1 haya int
81 1.1 haya rbus_space_alloc_subregion(rbt, substart, subend, addr, size, mask, align, flags, addrp, bshp)
82 1.7 haya rbus_tag_t rbt;
83 1.7 haya bus_addr_t addr;
84 1.7 haya bus_addr_t substart;
85 1.7 haya bus_addr_t subend;
86 1.7 haya bus_size_t size;
87 1.7 haya bus_addr_t mask, align;
88 1.7 haya int flags;
89 1.7 haya bus_addr_t *addrp;
90 1.7 haya bus_space_handle_t *bshp;
91 1.1 haya {
92 1.7 haya bus_addr_t decodesize = mask + 1;
93 1.7 haya bus_addr_t boundary, search_addr;
94 1.7 haya int val;
95 1.7 haya bus_addr_t result;
96 1.8 haya int exflags = EX_FAST | EX_NOWAIT | EX_MALLOCOK;
97 1.7 haya
98 1.7 haya DPRINTF(("rbus_space_alloc: addr %lx, size %lx, mask %lx, align %lx\n",
99 1.7 haya addr, size, mask, align));
100 1.7 haya
101 1.7 haya addr += rbt->rb_offset;
102 1.7 haya
103 1.7 haya if (mask == 0) {
104 1.7 haya /* FULL Decode */
105 1.7 haya decodesize = 0;
106 1.7 haya }
107 1.7 haya
108 1.7 haya if (rbt->rb_flags == RBUS_SPACE_ASK_PARENT) {
109 1.7 haya return rbus_space_alloc(rbt->rb_parent, addr, size, mask,
110 1.7 haya align, flags, addrp, bshp);
111 1.7 haya } else if (rbt->rb_flags == RBUS_SPACE_SHARE ||
112 1.7 haya rbt->rb_flags == RBUS_SPACE_DEDICATE) {
113 1.7 haya /* rbt has its own sh_extent */
114 1.7 haya
115 1.7 haya /*
116 1.7 haya * sanity check: the subregion [substart, subend] should be
117 1.7 haya * smaller than the region included in sh_extent.
118 1.7 haya */
119 1.7 haya if (substart < rbt->rb_ext->ex_start
120 1.7 haya || subend > rbt->rb_ext->ex_end) {
121 1.8 haya DPRINTF(("rbus: out of range\n"));
122 1.7 haya return 1;
123 1.7 haya }
124 1.7 haya
125 1.7 haya if (decodesize == align) {
126 1.7 haya if(extent_alloc_subregion(rbt->rb_ext, substart,
127 1.7 haya subend, size, align, 0, exflags, (u_long *)&result)) {
128 1.7 haya return 1;
129 1.7 haya }
130 1.7 haya } else if (decodesize == 0) {
131 1.7 haya /* maybe, the resister is overflowed. */
132 1.5 augustss
133 1.7 haya if (extent_alloc_subregion(rbt->rb_ext, addr,
134 1.8.6.1 lukem addr + size, size, 1, 0, exflags, (u_long *)&result)) {
135 1.7 haya return 1;
136 1.7 haya }
137 1.7 haya } else {
138 1.7 haya
139 1.7 haya boundary = decodesize > align ? decodesize : align;
140 1.7 haya
141 1.7 haya search_addr = (substart & ~(boundary - 1)) + addr;
142 1.7 haya
143 1.7 haya if (search_addr < substart) {
144 1.7 haya search_addr += boundary;
145 1.7 haya }
146 1.7 haya
147 1.7 haya val = 1;
148 1.7 haya for (; search_addr + size <= subend;
149 1.7 haya search_addr += boundary) {
150 1.7 haya val = extent_alloc_subregion(rbt->rb_ext,
151 1.7 haya search_addr, search_addr + size, size,
152 1.7 haya align, 0, exflags, (u_long *)&result);
153 1.8 haya DPRINTF(("rbus: trying [%lx:%lx] %lx\n",
154 1.8 haya search_addr, search_addr + size, align));
155 1.7 haya if (val == 0) {
156 1.7 haya break;
157 1.7 haya }
158 1.7 haya }
159 1.7 haya if (val != 0) {
160 1.7 haya /* no space found */
161 1.8 haya DPRINTF(("rbus: no space found\n"));
162 1.7 haya return 1;
163 1.7 haya }
164 1.7 haya }
165 1.7 haya
166 1.7 haya if(md_space_map(rbt->rb_bt, result, size, flags, bshp)) {
167 1.7 haya /* map failed */
168 1.7 haya extent_free(rbt->rb_ext, result, size, exflags);
169 1.7 haya return 1;
170 1.7 haya }
171 1.7 haya
172 1.7 haya if (addrp != NULL) {
173 1.7 haya *addrp = result + rbt->rb_offset;
174 1.7 haya }
175 1.7 haya return 0;
176 1.7 haya
177 1.7 haya } else {
178 1.7 haya /* error!! */
179 1.8 haya DPRINTF(("rbus: no rbus type\n"));
180 1.7 haya return 1;
181 1.1 haya }
182 1.5 augustss return 1;
183 1.5 augustss }
184 1.5 augustss
185 1.1 haya
186 1.1 haya
187 1.1 haya
188 1.1 haya
189 1.1 haya int
190 1.1 haya rbus_space_free(rbt, bsh, size, addrp)
191 1.7 haya rbus_tag_t rbt;
192 1.7 haya bus_space_handle_t bsh;
193 1.7 haya bus_size_t size;
194 1.7 haya bus_addr_t *addrp;
195 1.1 haya {
196 1.7 haya int exflags = EX_FAST | EX_NOWAIT;
197 1.7 haya bus_addr_t addr;
198 1.7 haya int status = 1;
199 1.7 haya
200 1.7 haya if (rbt->rb_flags == RBUS_SPACE_ASK_PARENT) {
201 1.7 haya status = rbus_space_free(rbt->rb_parent, bsh, size, &addr);
202 1.7 haya } else if (rbt->rb_flags == RBUS_SPACE_SHARE ||
203 1.7 haya rbt->rb_flags == RBUS_SPACE_DEDICATE) {
204 1.7 haya md_space_unmap(rbt->rb_bt, bsh, size, &addr);
205 1.7 haya
206 1.7 haya extent_free(rbt->rb_ext, addr, size, exflags);
207 1.7 haya
208 1.7 haya status = 0;
209 1.7 haya } else {
210 1.7 haya /* error. INVALID rbustag */
211 1.7 haya status = 1;
212 1.7 haya }
213 1.7 haya if (addrp != NULL) {
214 1.7 haya *addrp = addr;
215 1.7 haya }
216 1.7 haya return status;
217 1.1 haya }
218 1.1 haya
219 1.1 haya
220 1.1 haya
221 1.1 haya /*
222 1.1 haya * static rbus_tag_t
223 1.1 haya * rbus_new_body(bus_space_tag_t bt, rbus_tag_t parent,
224 1.1 haya * struct extent *ex, bus_addr_t start, bus_size_t end,
225 1.1 haya * bus_addr_t offset, int flags)
226 1.1 haya *
227 1.1 haya */
228 1.1 haya static rbus_tag_t
229 1.1 haya rbus_new_body(bt, parent, ex, start, end, offset, flags)
230 1.7 haya bus_space_tag_t bt;
231 1.7 haya rbus_tag_t parent;
232 1.7 haya struct extent *ex;
233 1.7 haya bus_addr_t start, end, offset;
234 1.7 haya int flags;
235 1.1 haya {
236 1.7 haya rbus_tag_t rb;
237 1.7 haya
238 1.7 haya /* sanity check */
239 1.7 haya if (parent != NULL) {
240 1.7 haya if (start < parent->rb_start || end > parent->rb_end) {
241 1.7 haya /*
242 1.7 haya * out of range: [start, size] should be
243 1.7 haya * containd in parent space
244 1.7 haya */
245 1.7 haya return 0;
246 1.7 haya /* Should I invoke panic? */
247 1.7 haya }
248 1.7 haya }
249 1.1 haya
250 1.7 haya if (NULL == (rb = (rbus_tag_t)malloc(sizeof(struct rbustag), M_DEVBUF,
251 1.7 haya M_NOWAIT))) {
252 1.7 haya panic("no memory for rbus instance");
253 1.7 haya }
254 1.7 haya
255 1.7 haya rb->rb_bt = bt;
256 1.7 haya rb->rb_parent = parent;
257 1.7 haya rb->rb_start = start;
258 1.7 haya rb->rb_end = end;
259 1.7 haya rb->rb_offset = offset;
260 1.7 haya rb->rb_flags = flags;
261 1.7 haya rb->rb_ext = ex;
262 1.7 haya
263 1.7 haya DPRINTF(("rbus_new_body: [%lx, %lx] type %s name [%s]\n", start, end,
264 1.7 haya flags == RBUS_SPACE_SHARE ? "share" :
265 1.7 haya flags == RBUS_SPACE_DEDICATE ? "dedicated" :
266 1.7 haya flags == RBUS_SPACE_ASK_PARENT ? "parent" : "invalid",
267 1.7 haya ex != NULL ? ex->ex_name : "noname"));
268 1.1 haya
269 1.7 haya return rb;
270 1.1 haya }
271 1.1 haya
272 1.1 haya
273 1.1 haya
274 1.1 haya /*
275 1.1 haya * rbus_tag_t rbus_new(rbus_tag_t parent, bus_addr_t start, bus_size_t
276 1.1 haya * size, bus_addr_t offset, int flags)
277 1.1 haya *
278 1.1 haya * This function makes a new child rbus instance.
279 1.1 haya */
280 1.1 haya rbus_tag_t
281 1.1 haya rbus_new(parent, start, size, offset, flags)
282 1.7 haya rbus_tag_t parent;
283 1.7 haya bus_addr_t start;
284 1.7 haya bus_size_t size;
285 1.7 haya bus_addr_t offset;
286 1.7 haya int flags;
287 1.1 haya {
288 1.7 haya rbus_tag_t rb;
289 1.7 haya struct extent *ex = NULL;
290 1.7 haya bus_addr_t end = start + size;
291 1.7 haya
292 1.7 haya if (flags == RBUS_SPACE_SHARE) {
293 1.7 haya ex = parent->rb_ext;
294 1.7 haya } else if (flags == RBUS_SPACE_DEDICATE) {
295 1.7 haya if (NULL == (ex = extent_create("rbus", start, end, M_DEVBUF,
296 1.7 haya NULL, 0, EX_NOCOALESCE|EX_NOWAIT))) {
297 1.7 haya free(rb, M_DEVBUF);
298 1.7 haya return NULL;
299 1.7 haya }
300 1.7 haya } else if (flags == RBUS_SPACE_ASK_PARENT) {
301 1.7 haya ex = NULL;
302 1.7 haya } else {
303 1.7 haya /* Invalid flag */
304 1.7 haya return 0;
305 1.7 haya }
306 1.7 haya
307 1.7 haya rb = rbus_new_body(parent->rb_bt, parent, ex, start, start + size,
308 1.7 haya offset, flags);
309 1.7 haya
310 1.7 haya if ((rb == NULL) && (flags == RBUS_SPACE_DEDICATE)) {
311 1.7 haya extent_destroy(ex);
312 1.7 haya }
313 1.1 haya
314 1.7 haya return rb;
315 1.1 haya }
316 1.1 haya
317 1.1 haya
318 1.1 haya
319 1.1 haya
320 1.1 haya /*
321 1.1 haya * rbus_tag_t rbus_new_root_delegate(bus_space_tag, bus_addr_t,
322 1.1 haya * bus_size_t, bus_addr_t offset)
323 1.1 haya *
324 1.1 haya * This function makes a root rbus instance.
325 1.1 haya */
326 1.1 haya rbus_tag_t
327 1.1 haya rbus_new_root_delegate(bt, start, size, offset)
328 1.7 haya bus_space_tag_t bt;
329 1.7 haya bus_addr_t start;
330 1.7 haya bus_size_t size;
331 1.7 haya bus_addr_t offset;
332 1.1 haya {
333 1.7 haya rbus_tag_t rb;
334 1.7 haya struct extent *ex;
335 1.1 haya
336 1.7 haya if (NULL == (ex = extent_create("rbus root", start, start + size,
337 1.7 haya M_DEVBUF, NULL, 0, EX_NOCOALESCE|EX_NOWAIT))) {
338 1.7 haya return NULL;
339 1.7 haya }
340 1.7 haya
341 1.7 haya rb = rbus_new_body(bt, NULL, ex, start, start + size, offset,
342 1.7 haya RBUS_SPACE_DEDICATE);
343 1.7 haya
344 1.7 haya if (rb == NULL) {
345 1.7 haya extent_destroy(ex);
346 1.7 haya }
347 1.5 augustss
348 1.7 haya return rb;
349 1.1 haya }
350 1.1 haya
351 1.1 haya
352 1.1 haya
353 1.1 haya /*
354 1.1 haya * rbus_tag_t rbus_new_root_share(bus_space_tag, struct extent *,
355 1.1 haya * bus_addr_t, bus_size_t, bus_addr_t offset)
356 1.1 haya *
357 1.1 haya * This function makes a root rbus instance.
358 1.1 haya */
359 1.1 haya rbus_tag_t
360 1.1 haya rbus_new_root_share(bt, ex, start, size, offset)
361 1.7 haya bus_space_tag_t bt;
362 1.7 haya struct extent *ex;
363 1.7 haya bus_addr_t start;
364 1.7 haya bus_size_t size;
365 1.7 haya bus_addr_t offset;
366 1.1 haya {
367 1.7 haya /* sanity check */
368 1.7 haya if (start < ex->ex_start || start + size > ex->ex_end) {
369 1.7 haya /*
370 1.7 haya * out of range: [start, size] should be containd in
371 1.7 haya * parent space
372 1.7 haya */
373 1.7 haya return 0;
374 1.7 haya /* Should I invoke panic? */
375 1.7 haya }
376 1.1 haya
377 1.7 haya return rbus_new_body(bt, NULL, ex, start, start + size, offset,
378 1.7 haya RBUS_SPACE_SHARE);
379 1.1 haya }
380 1.1 haya
381 1.1 haya
382 1.1 haya
383 1.1 haya
384 1.1 haya
385 1.1 haya /*
386 1.1 haya * int rbus_delete (rbus_tag_t rb)
387 1.1 haya *
388 1.1 haya * This function deletes the rbus structure pointed in the argument.
389 1.1 haya */
390 1.1 haya int
391 1.1 haya rbus_delete(rb)
392 1.7 haya rbus_tag_t rb;
393 1.1 haya {
394 1.7 haya DPRINTF(("rbus_delete called [%s]\n",
395 1.7 haya rb->rb_ext != NULL ? rb->rb_ext->ex_name : "noname"));
396 1.7 haya if (rb->rb_flags == RBUS_SPACE_DEDICATE) {
397 1.7 haya extent_destroy(rb->rb_ext);
398 1.7 haya }
399 1.1 haya
400 1.7 haya free(rb, M_DEVBUF);
401 1.1 haya
402 1.7 haya return 0;
403 1.1 haya }
404