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