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