| File: | dev/cardbus/rbus.c |
| Warning: | line 171, column 10 Assigned value is garbage or undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: rbus.c,v 1.16 2010/09/22 02:28:37 jsg 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 | * | |||
| 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |||
| 17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
| 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |||
| 19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |||
| 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |||
| 21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||
| 22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||
| 23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
| 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |||
| 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| 26 | */ | |||
| 27 | ||||
| 28 | #include <sys/param.h> | |||
| 29 | #include <sys/systm.h> | |||
| 30 | #include <sys/device.h> | |||
| 31 | #include <sys/malloc.h> | |||
| 32 | #include <sys/extent.h> | |||
| 33 | ||||
| 34 | #include <machine/bus.h> | |||
| 35 | ||||
| 36 | #include <dev/cardbus/rbus.h> | |||
| 37 | ||||
| 38 | /* #define RBUS_DEBUG */ | |||
| 39 | ||||
| 40 | #if defined RBUS_DEBUG | |||
| 41 | #define STATIC | |||
| 42 | #define DPRINTF(a) printf a | |||
| 43 | #else | |||
| 44 | #ifdef DDB1 | |||
| 45 | #define STATIC | |||
| 46 | #else | |||
| 47 | #define STATIC static | |||
| 48 | #endif | |||
| 49 | #define DPRINTF(a) | |||
| 50 | #endif | |||
| 51 | ||||
| 52 | ||||
| 53 | int | |||
| 54 | rbus_space_alloc(rbus_tag_t rbt, bus_addr_t addr, bus_size_t size, | |||
| 55 | bus_addr_t mask, bus_addr_t align, int flags, bus_addr_t *addrp, | |||
| 56 | bus_space_handle_t *bshp) | |||
| 57 | { | |||
| 58 | return (rbus_space_alloc_subregion(rbt, rbt->rb_start, rbt->rb_end, | |||
| 59 | addr, size, mask, align, flags, addrp, bshp)); | |||
| 60 | } | |||
| 61 | ||||
| 62 | int | |||
| 63 | rbus_space_alloc_subregion(rbus_tag_t rbt, bus_addr_t substart, | |||
| 64 | bus_addr_t subend, bus_addr_t addr, bus_size_t size, | |||
| 65 | bus_addr_t mask, bus_addr_t align, int flags, bus_addr_t *addrp, | |||
| 66 | bus_space_handle_t *bshp) | |||
| 67 | { | |||
| 68 | bus_addr_t decodesize = mask + 1; | |||
| 69 | bus_addr_t boundary, search_addr; | |||
| 70 | int val; | |||
| 71 | u_long result; | |||
| 72 | int exflags = EX_FAST0x0002 | EX_NOWAIT0x0000 | EX_MALLOCOK0x0010; | |||
| 73 | ||||
| 74 | DPRINTF(("rbus_space_alloc: addr %lx, size %lx, mask %lx, align %lx\n", | |||
| 75 | (u_long)addr, (u_long)size, (u_long)mask, (u_long)align)); | |||
| 76 | ||||
| 77 | if (mask == 0) { | |||
| 78 | /* FULL Decode */ | |||
| 79 | decodesize = 0; | |||
| 80 | } | |||
| 81 | ||||
| 82 | if (rbt->rb_flags == RBUS_SPACE_SHARE0x01 || | |||
| 83 | rbt->rb_flags == RBUS_SPACE_DEDICATE0x02) { | |||
| 84 | /* rbt has its own sh_extent */ | |||
| 85 | ||||
| 86 | /* sanity check: the subregion [substart, subend] should be | |||
| 87 | smaller than the region included in sh_extent */ | |||
| 88 | if (substart < rbt->rb_ext->ex_start || | |||
| 89 | subend > rbt->rb_ext->ex_end) { | |||
| 90 | DPRINTF(("rbus: out of range\n")); | |||
| 91 | return (1); | |||
| 92 | } | |||
| 93 | ||||
| 94 | if (decodesize == align) { | |||
| 95 | if (extent_alloc_subregion(rbt->rb_ext, substart, | |||
| 96 | subend, size, align, 0, 0, exflags, &result)) | |||
| 97 | return (1); | |||
| 98 | } else if (decodesize == 0) { | |||
| 99 | /* maybe, the register is overflowed. */ | |||
| 100 | ||||
| 101 | if (extent_alloc_subregion(rbt->rb_ext, addr, | |||
| 102 | addr + size, size, 1, 0, 0, exflags, &result)) | |||
| 103 | return (1); | |||
| 104 | } else { | |||
| 105 | boundary = decodesize > align ? decodesize : align; | |||
| 106 | ||||
| 107 | search_addr = (substart & ~(boundary - 1)) + addr; | |||
| 108 | ||||
| 109 | if (search_addr < substart) | |||
| 110 | search_addr += boundary; | |||
| 111 | ||||
| 112 | val = 1; | |||
| 113 | for (; search_addr + size <= subend; | |||
| 114 | search_addr += boundary) { | |||
| 115 | val = extent_alloc_subregion( | |||
| 116 | rbt->rb_ext,search_addr, | |||
| 117 | search_addr + size, size, align, 0, 0, | |||
| 118 | exflags, &result); | |||
| 119 | DPRINTF(("rbus: trying [%lx:%lx] %lx\n", | |||
| 120 | (u_long)search_addr, | |||
| 121 | (u_long)search_addr + size, | |||
| 122 | (u_long)align)); | |||
| 123 | if (val == 0) | |||
| 124 | break; | |||
| 125 | } | |||
| 126 | ||||
| 127 | if (val != 0) { | |||
| 128 | /* no space found */ | |||
| 129 | DPRINTF(("rbus: no space found\n")); | |||
| 130 | return (1); | |||
| 131 | } | |||
| 132 | } | |||
| 133 | ||||
| 134 | if (md_space_map(rbt, result, size, flags, bshp)_bus_space_map((rbt)->rb_bt, (result), (size), (flags), (bshp ))) { | |||
| 135 | /* map failed */ | |||
| 136 | extent_free(rbt->rb_ext, result, size, exflags); | |||
| 137 | return (1); | |||
| 138 | } | |||
| 139 | ||||
| 140 | if (addrp != NULL((void *)0)) | |||
| 141 | *addrp = result; | |||
| 142 | return (0); | |||
| 143 | } else { | |||
| 144 | /* error!! */ | |||
| 145 | DPRINTF(("rbus: no rbus type\n")); | |||
| 146 | return (1); | |||
| 147 | } | |||
| 148 | } | |||
| 149 | ||||
| 150 | int | |||
| 151 | rbus_space_free(rbus_tag_t rbt, bus_space_handle_t bsh, bus_size_t size, | |||
| 152 | bus_addr_t *addrp) | |||
| 153 | { | |||
| 154 | int exflags = EX_FAST0x0002 | EX_NOWAIT0x0000; | |||
| 155 | bus_addr_t addr; | |||
| ||||
| 156 | int status = 1; | |||
| 157 | ||||
| 158 | if (rbt->rb_flags == RBUS_SPACE_SHARE0x01 || | |||
| 159 | rbt->rb_flags == RBUS_SPACE_DEDICATE0x02) { | |||
| 160 | md_space_unmap(rbt, bsh, size, &addr)_bus_space_unmap((rbt)->rb_bt, (bsh), (size), (&addr)); | |||
| 161 | ||||
| 162 | extent_free(rbt->rb_ext, addr, size, exflags); | |||
| 163 | ||||
| 164 | status = 0; | |||
| 165 | } else { | |||
| 166 | /* error. INVALID rbustag */ | |||
| 167 | status = 1; | |||
| 168 | } | |||
| 169 | ||||
| 170 | if (addrp != NULL((void *)0)) | |||
| 171 | *addrp = addr; | |||
| ||||
| 172 | ||||
| 173 | return (status); | |||
| 174 | } | |||
| 175 | ||||
| 176 | /* | |||
| 177 | * rbus_tag_t | |||
| 178 | * rbus_new_body(bus_space_tag_t bt, | |||
| 179 | * struct extent *ex, bus_addr_t start, bus_size_t end, | |||
| 180 | * int flags) | |||
| 181 | * | |||
| 182 | */ | |||
| 183 | rbus_tag_t | |||
| 184 | rbus_new_body(bus_space_tag_t bt, struct extent *ex, | |||
| 185 | bus_addr_t start, bus_addr_t end, int flags) | |||
| 186 | { | |||
| 187 | rbus_tag_t rb; | |||
| 188 | ||||
| 189 | if ((rb = (rbus_tag_t)malloc(sizeof(struct rbustag), M_DEVBUF2, | |||
| 190 | M_NOWAIT0x0002)) == NULL((void *)0)) { | |||
| 191 | panic("no memory for rbus instance"); | |||
| 192 | } | |||
| 193 | ||||
| 194 | rb->rb_bt = bt; | |||
| 195 | rb->rb_start = start; | |||
| 196 | rb->rb_end = end; | |||
| 197 | rb->rb_flags = flags; | |||
| 198 | rb->rb_ext = ex; | |||
| 199 | ||||
| 200 | DPRINTF(("rbus_new_body: [%lx, %lx] type %s name [%s]\n", | |||
| 201 | (u_long)start, (u_long)end, | |||
| 202 | flags == RBUS_SPACE_SHARE ? "share" : | |||
| 203 | flags == RBUS_SPACE_DEDICATE ? "dedicated" : "invalid", | |||
| 204 | ex != NULL ? ex->ex_name : "noname")); | |||
| 205 | ||||
| 206 | return (rb); | |||
| 207 | } | |||
| 208 | ||||
| 209 | /* | |||
| 210 | * rbus_tag_t rbus_new_root_delegate(bus_space_tag, bus_addr_t, | |||
| 211 | * bus_size_t) | |||
| 212 | * | |||
| 213 | * This function makes a root rbus instance. | |||
| 214 | */ | |||
| 215 | rbus_tag_t | |||
| 216 | rbus_new_root_delegate(bus_space_tag_t bt, bus_addr_t start, bus_size_t size) | |||
| 217 | { | |||
| 218 | rbus_tag_t rb; | |||
| 219 | struct extent *ex; | |||
| 220 | ||||
| 221 | if ((ex = extent_create("rbus root", start, start + size, M_DEVBUF2, | |||
| 222 | NULL((void *)0), 0, EX_NOCOALESCE0x0008|EX_NOWAIT0x0000)) == NULL((void *)0)) | |||
| 223 | return (NULL((void *)0)); | |||
| 224 | ||||
| 225 | rb = rbus_new_body(bt, ex, start, start + size, | |||
| 226 | RBUS_SPACE_DEDICATE0x02); | |||
| 227 | ||||
| 228 | if (rb == NULL((void *)0)) | |||
| 229 | extent_destroy(ex); | |||
| 230 | ||||
| 231 | return (rb); | |||
| 232 | } | |||
| 233 | ||||
| 234 | /* | |||
| 235 | * rbus_tag_t rbus_new_root_share(bus_space_tag, struct extent *, | |||
| 236 | * bus_addr_t, bus_size_t) | |||
| 237 | * | |||
| 238 | * This function makes a root rbus instance. | |||
| 239 | */ | |||
| 240 | rbus_tag_t | |||
| 241 | rbus_new_root_share(bus_space_tag_t bt, struct extent *ex, bus_addr_t start, | |||
| 242 | bus_size_t size) | |||
| 243 | { | |||
| 244 | /* sanity check */ | |||
| 245 | if (start < ex->ex_start || start + size > ex->ex_end) { | |||
| 246 | /* out of range: [start, size] should be contained in | |||
| 247 | * parent space | |||
| 248 | */ | |||
| 249 | return (0); | |||
| 250 | /* Should I invoke panic? */ | |||
| 251 | } | |||
| 252 | ||||
| 253 | return (rbus_new_body(bt, ex, start, start + size, | |||
| 254 | RBUS_SPACE_SHARE0x01)); | |||
| 255 | } |