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