rbus.c revision 1.25 1 1.25 ad /* $NetBSD: rbus.c,v 1.25 2007/10/19 11:59:39 ad 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 ad __KERNEL_RCSID(0, "$NetBSD: rbus.c,v 1.25 2007/10/19 11:59:39 ad 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.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.13 christos bus_addr_t boundary, search_addr;
94 1.7 haya int val;
95 1.16 nakayama u_long 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.17 scw (u_long)addr, (u_long)size, (u_long)mask, (u_long)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.16 nakayama subend, size, align, 0, exflags, &result)) {
128 1.7 haya return 1;
129 1.7 haya }
130 1.7 haya } else if (decodesize == 0) {
131 1.20 skd /* maybe, the register is overflowed. */
132 1.22 perry
133 1.7 haya if (extent_alloc_subregion(rbt->rb_ext, addr,
134 1.16 nakayama addr + size, size, 1, 0, exflags, &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.13 christos
147 1.7 haya val = 1;
148 1.13 christos 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.16 nakayama align, 0, exflags, &result);
153 1.8 haya DPRINTF(("rbus: trying [%lx:%lx] %lx\n",
154 1.17 scw (u_long)search_addr,
155 1.17 scw (u_long)search_addr + size, (u_long)align));
156 1.7 haya if (val == 0) {
157 1.7 haya break;
158 1.7 haya }
159 1.7 haya }
160 1.7 haya if (val != 0) {
161 1.7 haya /* no space found */
162 1.8 haya DPRINTF(("rbus: no space found\n"));
163 1.7 haya return 1;
164 1.7 haya }
165 1.7 haya }
166 1.7 haya
167 1.7 haya if(md_space_map(rbt->rb_bt, result, size, flags, bshp)) {
168 1.7 haya /* map failed */
169 1.7 haya extent_free(rbt->rb_ext, result, size, exflags);
170 1.7 haya return 1;
171 1.7 haya }
172 1.7 haya
173 1.7 haya if (addrp != NULL) {
174 1.7 haya *addrp = result + rbt->rb_offset;
175 1.7 haya }
176 1.7 haya return 0;
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 }
183 1.5 augustss
184 1.1 haya
185 1.1 haya
186 1.1 haya
187 1.1 haya
188 1.1 haya int
189 1.1 haya rbus_space_free(rbt, bsh, size, addrp)
190 1.7 haya rbus_tag_t rbt;
191 1.7 haya bus_space_handle_t bsh;
192 1.7 haya bus_size_t size;
193 1.7 haya bus_addr_t *addrp;
194 1.1 haya {
195 1.7 haya int exflags = EX_FAST | EX_NOWAIT;
196 1.7 haya bus_addr_t addr;
197 1.7 haya int status = 1;
198 1.7 haya
199 1.7 haya if (rbt->rb_flags == RBUS_SPACE_ASK_PARENT) {
200 1.7 haya status = rbus_space_free(rbt->rb_parent, bsh, size, &addr);
201 1.7 haya } else if (rbt->rb_flags == RBUS_SPACE_SHARE ||
202 1.7 haya rbt->rb_flags == RBUS_SPACE_DEDICATE) {
203 1.7 haya md_space_unmap(rbt->rb_bt, bsh, size, &addr);
204 1.7 haya
205 1.7 haya extent_free(rbt->rb_ext, addr, size, exflags);
206 1.7 haya
207 1.7 haya status = 0;
208 1.7 haya } else {
209 1.7 haya /* error. INVALID rbustag */
210 1.7 haya status = 1;
211 1.7 haya }
212 1.24 christos if (status == 0 && addrp != NULL) {
213 1.7 haya *addrp = addr;
214 1.7 haya }
215 1.7 haya return status;
216 1.1 haya }
217 1.1 haya
218 1.1 haya
219 1.1 haya
220 1.1 haya /*
221 1.1 haya * static rbus_tag_t
222 1.1 haya * rbus_new_body(bus_space_tag_t bt, rbus_tag_t parent,
223 1.1 haya * struct extent *ex, bus_addr_t start, bus_size_t end,
224 1.1 haya * bus_addr_t offset, int flags)
225 1.1 haya *
226 1.1 haya */
227 1.1 haya static rbus_tag_t
228 1.1 haya rbus_new_body(bt, parent, ex, start, end, offset, flags)
229 1.7 haya bus_space_tag_t bt;
230 1.7 haya rbus_tag_t parent;
231 1.7 haya struct extent *ex;
232 1.7 haya bus_addr_t start, end, offset;
233 1.7 haya int flags;
234 1.1 haya {
235 1.7 haya rbus_tag_t rb;
236 1.7 haya
237 1.7 haya /* sanity check */
238 1.7 haya if (parent != NULL) {
239 1.7 haya if (start < parent->rb_start || end > parent->rb_end) {
240 1.7 haya /*
241 1.7 haya * out of range: [start, size] should be
242 1.19 wiz * contained in parent space
243 1.7 haya */
244 1.7 haya return 0;
245 1.7 haya /* Should I invoke panic? */
246 1.7 haya }
247 1.7 haya }
248 1.1 haya
249 1.7 haya if (NULL == (rb = (rbus_tag_t)malloc(sizeof(struct rbustag), M_DEVBUF,
250 1.7 haya M_NOWAIT))) {
251 1.7 haya panic("no memory for rbus instance");
252 1.7 haya }
253 1.7 haya
254 1.7 haya rb->rb_bt = bt;
255 1.7 haya rb->rb_parent = parent;
256 1.7 haya rb->rb_start = start;
257 1.7 haya rb->rb_end = end;
258 1.7 haya rb->rb_offset = offset;
259 1.7 haya rb->rb_flags = flags;
260 1.7 haya rb->rb_ext = ex;
261 1.7 haya
262 1.17 scw DPRINTF(("rbus_new_body: [%lx, %lx] type %s name [%s]\n",
263 1.17 scw (u_long)start, (u_long)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 return NULL;
298 1.7 haya }
299 1.7 haya } else if (flags == RBUS_SPACE_ASK_PARENT) {
300 1.7 haya ex = NULL;
301 1.7 haya } else {
302 1.7 haya /* Invalid flag */
303 1.7 haya return 0;
304 1.7 haya }
305 1.7 haya
306 1.7 haya rb = rbus_new_body(parent->rb_bt, parent, ex, start, start + size,
307 1.7 haya offset, flags);
308 1.7 haya
309 1.7 haya if ((rb == NULL) && (flags == RBUS_SPACE_DEDICATE)) {
310 1.7 haya extent_destroy(ex);
311 1.7 haya }
312 1.1 haya
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 /*
320 1.1 haya * rbus_tag_t rbus_new_root_delegate(bus_space_tag, bus_addr_t,
321 1.1 haya * bus_size_t, bus_addr_t offset)
322 1.1 haya *
323 1.1 haya * This function makes a root rbus instance.
324 1.1 haya */
325 1.1 haya rbus_tag_t
326 1.1 haya rbus_new_root_delegate(bt, start, size, offset)
327 1.7 haya bus_space_tag_t bt;
328 1.7 haya bus_addr_t start;
329 1.7 haya bus_size_t size;
330 1.7 haya bus_addr_t offset;
331 1.1 haya {
332 1.7 haya rbus_tag_t rb;
333 1.7 haya struct extent *ex;
334 1.1 haya
335 1.7 haya if (NULL == (ex = extent_create("rbus root", start, start + size,
336 1.7 haya M_DEVBUF, NULL, 0, EX_NOCOALESCE|EX_NOWAIT))) {
337 1.7 haya return NULL;
338 1.7 haya }
339 1.7 haya
340 1.7 haya rb = rbus_new_body(bt, NULL, ex, start, start + size, offset,
341 1.7 haya RBUS_SPACE_DEDICATE);
342 1.7 haya
343 1.7 haya if (rb == NULL) {
344 1.7 haya extent_destroy(ex);
345 1.7 haya }
346 1.5 augustss
347 1.7 haya return rb;
348 1.1 haya }
349 1.1 haya
350 1.1 haya
351 1.1 haya
352 1.1 haya /*
353 1.1 haya * rbus_tag_t rbus_new_root_share(bus_space_tag, struct extent *,
354 1.1 haya * bus_addr_t, bus_size_t, bus_addr_t offset)
355 1.1 haya *
356 1.1 haya * This function makes a root rbus instance.
357 1.1 haya */
358 1.1 haya rbus_tag_t
359 1.1 haya rbus_new_root_share(bt, ex, start, size, offset)
360 1.7 haya bus_space_tag_t bt;
361 1.7 haya struct extent *ex;
362 1.7 haya bus_addr_t start;
363 1.7 haya bus_size_t size;
364 1.7 haya bus_addr_t offset;
365 1.1 haya {
366 1.7 haya /* sanity check */
367 1.7 haya if (start < ex->ex_start || start + size > ex->ex_end) {
368 1.7 haya /*
369 1.19 wiz * out of range: [start, size] should be contained in
370 1.7 haya * parent space
371 1.7 haya */
372 1.7 haya return 0;
373 1.7 haya /* Should I invoke panic? */
374 1.7 haya }
375 1.1 haya
376 1.7 haya return rbus_new_body(bt, NULL, ex, start, start + size, offset,
377 1.7 haya RBUS_SPACE_SHARE);
378 1.1 haya }
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 * int rbus_delete (rbus_tag_t rb)
386 1.1 haya *
387 1.1 haya * This function deletes the rbus structure pointed in the argument.
388 1.1 haya */
389 1.1 haya int
390 1.1 haya rbus_delete(rb)
391 1.7 haya rbus_tag_t rb;
392 1.1 haya {
393 1.7 haya DPRINTF(("rbus_delete called [%s]\n",
394 1.7 haya rb->rb_ext != NULL ? rb->rb_ext->ex_name : "noname"));
395 1.7 haya if (rb->rb_flags == RBUS_SPACE_DEDICATE) {
396 1.7 haya extent_destroy(rb->rb_ext);
397 1.7 haya }
398 1.1 haya
399 1.7 haya free(rb, M_DEVBUF);
400 1.1 haya
401 1.7 haya return 0;
402 1.1 haya }
403