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