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